[spirv] Fail for functions with >255 parameters

Some IR transforms add new parameters to existing functions, which can
cause a valid input shader to exceed SPIR-V limit of 255
parameters. We can't easily fix this, so just fail gracefully and
class it as a spurious failure as per the WGSL spec.

Fixed: 354748060
Change-Id: I31b1d1eddc2b75e237e3f01f967f4bb3e3488cee
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/200014
Reviewed-by: David Neto <dneto@google.com>
Auto-Submit: James Price <jrprice@google.com>
Commit-Queue: David Neto <dneto@google.com>
diff --git a/src/tint/lang/spirv/writer/printer/printer.cc b/src/tint/lang/spirv/writer/printer/printer.cc
index aedc7d5..e403d0f 100644
--- a/src/tint/lang/spirv/writer/printer/printer.cc
+++ b/src/tint/lang/spirv/writer/printer/printer.cc
@@ -307,7 +307,10 @@
 
         // Emit functions.
         for (core::ir::Function* func : ir_.functions) {
-            EmitFunction(func);
+            auto res = EmitFunction(func);
+            if (res != Success) {
+                return res;
+            }
         }
 
         return Success;
@@ -694,7 +697,17 @@
 
     /// Emit a function.
     /// @param func the function to emit
-    void EmitFunction(core::ir::Function* func) {
+    Result<SuccessType> EmitFunction(core::ir::Function* func) {
+        if (func->Params().Length() > 255) {
+            // Tint transforms may add additional function parameters which can cause a valid input
+            // shader to exceed SPIR-V's function parameter limit. There isn't much we can do about
+            // this, so just fail gracefully instead of a generating invalid SPIR-V.
+            StringStream ss;
+            ss << "Function '" << ir_.NameOf(func).Name()
+               << "' has more than 255 parameters after running Tint transforms";
+            return Failure{ss.str()};
+        }
+
         auto id = Value(func);
 
         // Emit the function name.
@@ -748,6 +761,8 @@
 
         // Add the function to the module.
         module_.PushFunction(current_function_);
+
+        return Success;
     }
 
     /// Emit entry point declarations for a function.
diff --git a/src/tint/lang/spirv/writer/writer_test.cc b/src/tint/lang/spirv/writer/writer_test.cc
index b64c0ef..c00563f 100644
--- a/src/tint/lang/spirv/writer/writer_test.cc
+++ b/src/tint/lang/spirv/writer/writer_test.cc
@@ -86,5 +86,24 @@
 )");
 }
 
+// Test that we fail gracefully when a function has too many parameters.
+// See crbug.com/354748060.
+TEST_F(SpirvWriterTest, TooManyFunctionParameters) {
+    Vector<core::ir::FunctionParam*, 256> params;
+    for (uint32_t i = 0; i < 256; i++) {
+        params.Push(b.FunctionParam(ty.i32()));
+    }
+    auto* func = b.Function("foo", ty.void_());
+    func->SetParams(std::move(params));
+    b.Append(func->Block(), [&] {  //
+        b.Return(func);
+    });
+
+    EXPECT_FALSE(Generate());
+    EXPECT_THAT(Error(),
+                testing::HasSubstr(
+                    "Function 'foo' has more than 255 parameters after running Tint transforms"));
+}
+
 }  // namespace
 }  // namespace tint::spirv::writer