[tint][ir][ToProgram] Disable derivative_uniformity

If the module calls any builtins requiring uniform control flow.

Change-Id: I8ac3c6f571008d5824281003218e26d035f39988
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/140988
Reviewed-by: Dan Sinclair <dsinclair@chromium.org>
Auto-Submit: Ben Clayton <bclayton@google.com>
Kokoro: Kokoro <noreply+kokoro@google.com>
Reviewed-by: James Price <jrprice@google.com>
Commit-Queue: Ben Clayton <bclayton@google.com>
diff --git a/src/tint/ir/to_program.cc b/src/tint/ir/to_program.cc
index b552839..72050ac 100644
--- a/src/tint/ir/to_program.cc
+++ b/src/tint/ir/to_program.cc
@@ -165,6 +165,9 @@
     /// Map of struct to output program name.
     utils::Hashmap<const type::Struct*, Symbol, 8> structs_;
 
+    /// True if 'diagnostic(off, derivative_uniformity)' has been emitted
+    bool disabled_derivative_uniformity_ = false;
+
     void RootBlock(ir::Block* root) {
         for (auto* inst : *root) {
             tint::Switch(
@@ -564,6 +567,13 @@
                 Bind(c->Result(), expr, PtrKind::kPtr);
             },
             [&](ir::BuiltinCall* c) {
+                if (!disabled_derivative_uniformity_ && RequiresDerivativeUniformity(c->Func())) {
+                    // TODO(crbug.com/tint/1985): Be smarter about disabling derivative uniformity.
+                    b.DiagnosticDirective(builtin::DiagnosticSeverity::kOff,
+                                          builtin::CoreDiagnosticRule::kDerivativeUniformity);
+                    disabled_derivative_uniformity_ = true;
+                }
+
                 auto* expr = b.Call(c->Func(), std::move(args));
                 if (!call->HasResults() || call->Result()->Type()->Is<type::Void>()) {
                     Append(b.CallStmt(expr));
@@ -1081,6 +1091,26 @@
         }
         return b.IndexAccessor(expr, Expr(index));
     }
+
+    bool RequiresDerivativeUniformity(builtin::Function fn) {
+        switch (fn) {
+            case builtin::Function::kDpdxCoarse:
+            case builtin::Function::kDpdyCoarse:
+            case builtin::Function::kFwidthCoarse:
+            case builtin::Function::kDpdxFine:
+            case builtin::Function::kDpdyFine:
+            case builtin::Function::kFwidthFine:
+            case builtin::Function::kDpdx:
+            case builtin::Function::kDpdy:
+            case builtin::Function::kFwidth:
+            case builtin::Function::kTextureSample:
+            case builtin::Function::kTextureSampleBias:
+            case builtin::Function::kTextureSampleCompare:
+                return true;
+            default:
+                return false;
+        }
+    }
 };
 
 }  // namespace
diff --git a/src/tint/ir/to_program_roundtrip_test.cc b/src/tint/ir/to_program_roundtrip_test.cc
index 9ce0845..fe8eb02 100644
--- a/src/tint/ir/to_program_roundtrip_test.cc
+++ b/src/tint/ir/to_program_roundtrip_test.cc
@@ -212,6 +212,23 @@
 )");
 }
 
+TEST_F(IRToProgramRoundtripTest, BuiltinCall_DisableDerivativeUniformity) {
+    Test(R"(
+fn f(in : f32) {
+  let x = dpdx(in);
+  let y = dpdy(in);
+}
+)",
+         R"(
+diagnostic(off, derivative_uniformity);
+
+fn f(in : f32) {
+  let x = dpdx(in);
+  let y = dpdy(in);
+}
+)");
+}
+
 ////////////////////////////////////////////////////////////////////////////////
 // Type Construct
 ////////////////////////////////////////////////////////////////////////////////