Import Tint changes from Dawn

Changes:
  - 8e2c3e14f9bc165d76ccf87772828a142203846d tint/resolver: Adjust diagnostic source for member access... by Ben Clayton <bclayton@google.com>
  - 8937ec4e72e2a4b0613c9635099c7c57782631ba spirv-reader: disable Clspv-related test by David Neto <dneto@google.com>
  - 011e95a2ff78a6f60e8728842126d903042e4c8a Add missing include of type_traits by Hans Wennborg <hans@chromium.org>
  - efdfc6bbcac307cab149759504ef4b37a22913a0 tint/gn: Use Unix diagnostic printer on macOS by James Price <jrprice@google.com>
  - cf1f4658aed655ae032cd69878873b5ca5225cb7 tint/resolver: Fix ICE on short-name type used as identif... by Ben Clayton <bclayton@google.com>
  - 0fa5fb16bd4d54a7d8b3c26e76f9f03c55c8cfd2 tint: fix clang-cl compilation by Ángel Eduardo García Hernández <egarcia@reversedgames.com>
  - f3f813eb0c1fe6a3dd87fd048a1f352dee448a05 tint: fix const eval short-circuiting with mixed runtime ... by Ben Clayton <bclayton@google.com>
  - be367b73ae9c5d043fd9934c87636b09a9da9099 Reduce shader complexity for external textures by Ben Clayton <bclayton@google.com>
GitOrigin-RevId: 8e2c3e14f9bc165d76ccf87772828a142203846d
Change-Id: I2e1a30b3f13df6352d768763c14ded4ee9c9959a
Reviewed-on: https://dawn-review.googlesource.com/c/tint/+/116135
Reviewed-by: Ben Clayton <bclayton@google.com>
Commit-Queue: Ben Clayton <bclayton@google.com>
Kokoro: Kokoro <noreply+kokoro@google.com>
diff --git a/src/tint/BUILD.gn b/src/tint/BUILD.gn
index d942b86..2167eaf 100644
--- a/src/tint/BUILD.gn
+++ b/src/tint/BUILD.gn
@@ -628,8 +628,8 @@
     "writer/writer.h",
   ]
 
-  if (is_linux) {
-    sources += [ "diagnostic/printer_linux.cc" ]
+  if (is_linux || is_mac) {
+    sources += [ "diagnostic/printer_posix.cc" ]
   } else if (is_win) {
     sources += [ "diagnostic/printer_windows.cc" ]
   } else {
diff --git a/src/tint/CMakeLists.txt b/src/tint/CMakeLists.txt
index 7988364..b30227a 100644
--- a/src/tint/CMakeLists.txt
+++ b/src/tint/CMakeLists.txt
@@ -572,7 +572,7 @@
 tint_generated(type/short_name BENCH TEST)
 
 if(UNIX)
-  list(APPEND TINT_LIB_SRCS diagnostic/printer_linux.cc)
+  list(APPEND TINT_LIB_SRCS diagnostic/printer_posix.cc)
 elseif(WIN32)
   list(APPEND TINT_LIB_SRCS diagnostic/printer_windows.cc)
 else()
diff --git a/src/tint/diagnostic/printer_linux.cc b/src/tint/diagnostic/printer_posix.cc
similarity index 94%
rename from src/tint/diagnostic/printer_linux.cc
rename to src/tint/diagnostic/printer_posix.cc
index 56d77b9..b854640 100644
--- a/src/tint/diagnostic/printer_linux.cc
+++ b/src/tint/diagnostic/printer_posix.cc
@@ -42,9 +42,9 @@
     return true;
 }
 
-class PrinterLinux : public Printer {
+class PrinterPosix : public Printer {
   public:
-    PrinterLinux(FILE* f, bool colors) : file(f), use_colors(colors && supports_colors(f)) {}
+    PrinterPosix(FILE* f, bool colors) : file(f), use_colors(colors && supports_colors(f)) {}
 
     void write(const std::string& str, const Style& style) override {
         write_color(style.color, style.bold);
@@ -91,7 +91,7 @@
 }  // namespace
 
 std::unique_ptr<Printer> Printer::create(FILE* out, bool use_colors) {
-    return std::make_unique<PrinterLinux>(out, use_colors);
+    return std::make_unique<PrinterPosix>(out, use_colors);
 }
 
 }  // namespace tint::diag
diff --git a/src/tint/ir/builder_impl_test.cc b/src/tint/ir/builder_impl_test.cc
index 41a3f4c..ced23f6 100644
--- a/src/tint/ir/builder_impl_test.cc
+++ b/src/tint/ir/builder_impl_test.cc
@@ -1697,8 +1697,8 @@
 }
 
 TEST_F(IR_BuilderImplTest, EmitExpression_Binary_Compound) {
-    auto* expr = LogicalOr(LessThan(1_u, Add(Shr(3_u, 4_u), 9_u)),
-                           GreaterThan(2.5_f, Div(6.7_f, Mul(2.3_f, 5.5_f))));
+    auto* expr = LogicalAnd(LessThan(1_u, Add(Shr(3_u, 4_u), 9_u)),
+                            GreaterThan(2.5_f, Div(6.7_f, Mul(2.3_f, 5.5_f))));
     WrapInFunction(expr);
 
     auto& b = CreateBuilder();
@@ -1714,7 +1714,7 @@
 %4 (f32) = 2.3 * 5.5
 %5 (f32) = 6.7 / %4 (f32)
 %6 (bool) = 2.5 > %5 (f32)
-%7 (bool) = %3 (bool) || %6 (bool)
+%7 (bool) = %3 (bool) && %6 (bool)
 )");
 }
 
diff --git a/src/tint/reader/spirv/parser_impl_import_test.cc b/src/tint/reader/spirv/parser_impl_import_test.cc
index b25db07..7748acc 100644
--- a/src/tint/reader/spirv/parser_impl_import_test.cc
+++ b/src/tint/reader/spirv/parser_impl_import_test.cc
@@ -54,7 +54,15 @@
     p->DeliberatelyInvalidSpirv();
 }
 
-TEST_F(SpvParserImportTest, Import_NonSemantic_IgnoredExtInsts) {
+TEST_F(SpvParserImportTest, DISABLED_Import_NonSemantic_IgnoredExtInsts) {
+    // TODO(crbug.com/tint/1789): The NonSemantic.ClspvReflection.1 instruction
+    // set grammar has changed
+    // but the corresponding feature in Clspv has not yet landed.
+    // See:
+    //   https://github.com/KhronosGroup/SPIRV-Headers/pull/308
+    //   https://github.com/google/clspv/pull/925
+    // Disable this test until upstream has settled.
+
     // This is the clspv-compiled output of this OpenCL C:
     //    kernel void foo(global int*A) { A=A; }
     // It emits NonSemantic.ClspvReflection.1 extended instructions.
diff --git a/src/tint/reader/wgsl/lexer.cc b/src/tint/reader/wgsl/lexer.cc
index 16712ca..9ebe5d8 100644
--- a/src/tint/reader/wgsl/lexer.cc
+++ b/src/tint/reader/wgsl/lexer.cc
@@ -405,11 +405,13 @@
         }
     }
 
+    TINT_BEGIN_DISABLE_WARNING(FLOAT_EQUAL);
     if (value == HUGE_VAL || -value == HUGE_VAL) {
         return {Token::Type::kError, source, "value cannot be represented as 'abstract-float'"};
     } else {
         return {Token::Type::kFloatLiteral, source, value};
     }
+    TINT_END_DISABLE_WARNING(FLOAT_EQUAL);
 }
 
 Token Lexer::try_hex_float() {
diff --git a/src/tint/resolver/const_eval_binary_op_test.cc b/src/tint/resolver/const_eval_binary_op_test.cc
index 7ea998a..55d22ba 100644
--- a/src/tint/resolver/const_eval_binary_op_test.cc
+++ b/src/tint/resolver/const_eval_binary_op_test.cc
@@ -2209,6 +2209,32 @@
 }
 
 ////////////////////////////////////////////////
+// Short-Circuit Mixed Constant and Runtime
+////////////////////////////////////////////////
+
+TEST_F(ResolverConstEvalTest, ShortCircuit_And_MixedConstantAndRuntime) {
+    // var j : i32;
+    // let result = false && j < (0 - 8);
+    auto* j = Decl(Var("j", ty.i32()));
+    auto* binary = LogicalAnd(Expr(false), LessThan("j", Sub(0_a, 8_a)));
+    auto* result = Let("result", binary);
+    WrapInFunction(j, result);
+    EXPECT_TRUE(r()->Resolve()) << r()->error();
+    ValidateAnd(Sem(), binary);
+}
+
+TEST_F(ResolverConstEvalTest, ShortCircuit_Or_MixedConstantAndRuntime) {
+    // var j : i32;
+    // let result = true || j < (0 - 8);
+    auto* j = Decl(Var("j", ty.i32()));
+    auto* binary = LogicalOr(Expr(true), LessThan("j", Sub(0_a, 8_a)));
+    auto* result = Let("result", binary);
+    WrapInFunction(j, result);
+    EXPECT_TRUE(r()->Resolve()) << r()->error();
+    ValidateOr(Sem(), binary);
+}
+
+////////////////////////////////////////////////
 // Short-Circuit Nested
 ////////////////////////////////////////////////
 
diff --git a/src/tint/resolver/intrinsic_table.cc b/src/tint/resolver/intrinsic_table.cc
index 54c851d..0b1a6d8 100644
--- a/src/tint/resolver/intrinsic_table.cc
+++ b/src/tint/resolver/intrinsic_table.cc
@@ -356,7 +356,7 @@
 }
 
 bool match_fa(MatchState& state, const type::Type* ty) {
-    return (state.earliest_eval_stage == sem::EvaluationStage::kConstant) &&
+    return (state.earliest_eval_stage <= sem::EvaluationStage::kConstant) &&
            ty->IsAnyOf<Any, type::AbstractNumeric>();
 }
 
@@ -365,7 +365,7 @@
 }
 
 bool match_ia(MatchState& state, const type::Type* ty) {
-    return (state.earliest_eval_stage == sem::EvaluationStage::kConstant) &&
+    return (state.earliest_eval_stage <= sem::EvaluationStage::kConstant) &&
            ty->IsAnyOf<Any, type::AbstractInt>();
 }
 
diff --git a/src/tint/resolver/resolver.cc b/src/tint/resolver/resolver.cc
index cec6e5a..cecac6e 100644
--- a/src/tint/resolver/resolver.cc
+++ b/src/tint/resolver/resolver.cc
@@ -2620,13 +2620,18 @@
     }
 
     const constant::Value* val = nullptr;
-    if (auto r = const_eval_.Literal(ty, literal)) {
-        val = r.Get();
-    } else {
-        return nullptr;
+    auto stage = sem::EvaluationStage::kConstant;
+    if (skip_const_eval_.Contains(literal)) {
+        stage = sem::EvaluationStage::kNotEvaluated;
     }
-    return builder_->create<sem::Expression>(literal, ty, sem::EvaluationStage::kConstant,
-                                             current_statement_, std::move(val),
+    if (stage == sem::EvaluationStage::kConstant) {
+        if (auto r = const_eval_.Literal(ty, literal)) {
+            val = r.Get();
+        } else {
+            return nullptr;
+        }
+    }
+    return builder_->create<sem::Expression>(literal, ty, stage, current_statement_, std::move(val),
                                              /* has_side_effects */ false);
 }
 
@@ -2711,11 +2716,13 @@
         return nullptr;
     }
 
-    if (sem_.ResolvedSymbol<type::Type>(expr)) {
+    if (sem_.ResolvedSymbol<type::Type>(expr) ||
+        type::ParseShortName(builder_->Symbols().NameFor(symbol)) != type::ShortName::kUndefined) {
         AddError("missing '(' for type initializer or cast", expr->source.End());
         return nullptr;
     }
 
+    // The dependency graph should have errored on this unresolved identifier before reaching here.
     TINT_ICE(Resolver, diagnostics_)
         << expr->source << " unresolved identifier:\n"
         << "resolved: " << (sem_resolved ? sem_resolved->TypeInfo().name : "<null>") << "\n"
@@ -2859,7 +2866,7 @@
         [&](Default) {
             AddError("invalid member accessor expression. Expected vector or struct, got '" +
                          sem_.TypeNameOf(storage_ty) + "'",
-                     expr->structure->source);
+                     expr->member->source);
             return nullptr;
         });
 }
@@ -2899,29 +2906,36 @@
     }
 
     const constant::Value* value = nullptr;
-    if (stage == sem::EvaluationStage::kConstant) {
-        if (op.const_eval_fn) {
-            if (skip_const_eval_.Contains(expr)) {
-                stage = sem::EvaluationStage::kNotEvaluated;
-            } else if (skip_const_eval_.Contains(expr->rhs)) {
-                // Only the rhs should be short-circuited, use the lhs value
-                value = lhs->ConstantValue();
+    if (skip_const_eval_.Contains(expr)) {
+        // This expression is short-circuited by an ancestor expression.
+        // Do not const-eval.
+        stage = sem::EvaluationStage::kNotEvaluated;
+    } else if (lhs->Stage() == sem::EvaluationStage::kConstant &&
+               rhs->Stage() == sem::EvaluationStage::kNotEvaluated) {
+        // Short-circuiting binary expression. Use the LHS value and stage.
+        value = lhs->ConstantValue();
+        stage = sem::EvaluationStage::kConstant;
+    } else if (stage == sem::EvaluationStage::kConstant) {
+        // Both LHS and RHS have expressions that are constant evaluation stage.
+        if (op.const_eval_fn) {  // Do we have a @const operator?
+            // Yes. Perform any required abstract argument values implicit conversions to the
+            // overload parameter types, and const-eval.
+            utils::Vector const_args{lhs->ConstantValue(), rhs->ConstantValue()};
+            // Implicit conversion (e.g. AInt -> AFloat)
+            if (!Convert(const_args[0], op.lhs, lhs->Declaration()->source)) {
+                return nullptr;
+            }
+            if (!Convert(const_args[1], op.rhs, rhs->Declaration()->source)) {
+                return nullptr;
+            }
+            if (auto r = (const_eval_.*op.const_eval_fn)(op.result, const_args, expr->source)) {
+                value = r.Get();
             } else {
-                auto const_args = utils::Vector{lhs->ConstantValue(), rhs->ConstantValue()};
-                // Implicit conversion (e.g. AInt -> AFloat)
-                if (!Convert(const_args[0], op.lhs, lhs->Declaration()->source)) {
-                    return nullptr;
-                }
-                if (!Convert(const_args[1], op.rhs, rhs->Declaration()->source)) {
-                    return nullptr;
-                }
-                if (auto r = (const_eval_.*op.const_eval_fn)(op.result, const_args, expr->source)) {
-                    value = r.Get();
-                } else {
-                    return nullptr;
-                }
+                return nullptr;
             }
         } else {
+            // The arguments have constant values, but the operator cannot be const-evaluated. This
+            // can only be evaluated at runtime.
             stage = sem::EvaluationStage::kRuntime;
         }
     }
diff --git a/src/tint/resolver/validation_test.cc b/src/tint/resolver/validation_test.cc
index 6ccdc7c..b476602 100644
--- a/src/tint/resolver/validation_test.cc
+++ b/src/tint/resolver/validation_test.cc
@@ -159,25 +159,32 @@
 
 TEST_F(ResolverValidationTest, Expr_DontCall_Function) {
     Func("func", utils::Empty, ty.void_(), utils::Empty, {});
-    WrapInFunction(Expr(Source{{{3, 3}, {3, 8}}}, "func"));
+    WrapInFunction(Expr(Source{{12, 34}}, "func"));
 
     EXPECT_FALSE(r()->Resolve());
-    EXPECT_EQ(r()->error(), "3:8 error: missing '(' for function call");
+    EXPECT_EQ(r()->error(), "12:34 error: missing '(' for function call");
 }
 
 TEST_F(ResolverValidationTest, Expr_DontCall_Builtin) {
-    WrapInFunction(Expr(Source{{{3, 3}, {3, 8}}}, "round"));
+    WrapInFunction(Expr(Source{{12, 34}}, "round"));
 
     EXPECT_FALSE(r()->Resolve());
-    EXPECT_EQ(r()->error(), "3:8 error: missing '(' for builtin call");
+    EXPECT_EQ(r()->error(), "12:34 error: missing '(' for builtin call");
 }
 
 TEST_F(ResolverValidationTest, Expr_DontCall_Type) {
     Alias("T", ty.u32());
-    WrapInFunction(Expr(Source{{{3, 3}, {3, 8}}}, "T"));
+    WrapInFunction(Expr(Source{{12, 34}}, "T"));
 
     EXPECT_FALSE(r()->Resolve());
-    EXPECT_EQ(r()->error(), "3:8 error: missing '(' for type initializer or cast");
+    EXPECT_EQ(r()->error(), "12:34 error: missing '(' for type initializer or cast");
+}
+
+TEST_F(ResolverValidationTest, Expr_DontCall_ShortName) {
+    WrapInFunction(Expr(Source{{12, 34}}, "vec3f"));
+
+    EXPECT_FALSE(r()->Resolve());
+    EXPECT_EQ(r()->error(), "12:34 error: missing '(' for type initializer or cast");
 }
 
 TEST_F(ResolverValidationTest, AssignmentStmt_InvalidLHS_BuiltinFunctionName) {
@@ -398,9 +405,9 @@
     // var param: vec4<f32>
     // let ret: f32 = *(&param).x;
     auto* param = Var("param", ty.vec4<f32>());
-    auto* x = Expr(Source{{{3, 3}, {3, 8}}}, "x");
+    auto* x = Expr(Source{{12, 34}}, "x");
 
-    auto* addressOf_expr = AddressOf(Source{{12, 34}}, param);
+    auto* addressOf_expr = AddressOf(param);
     auto* accessor_expr = MemberAccessor(addressOf_expr, x);
     auto* star_p = Deref(accessor_expr);
     auto* ret = Var("r", ty.f32(), star_p);
@@ -408,8 +415,8 @@
 
     EXPECT_FALSE(r()->Resolve());
     EXPECT_EQ(r()->error(),
-              "12:34 error: invalid member accessor expression. Expected vector "
-              "or struct, got 'ptr<function, vec4<f32>, read_write>'");
+              "12:34 error: invalid member accessor expression. Expected vector or struct, got "
+              "'ptr<function, vec4<f32>, read_write>'");
 }
 
 TEST_F(ResolverValidationTest, EXpr_MemberAccessor_FuncGoodParent) {
@@ -419,7 +426,7 @@
     // }
     auto* p = Param("p", ty.pointer(ty.vec4<f32>(), ast::AddressSpace::kFunction));
     auto* star_p = Deref(p);
-    auto* z = Expr(Source{{{3, 3}, {3, 8}}}, "z");
+    auto* z = Expr("z");
     auto* accessor_expr = MemberAccessor(star_p, z);
     auto* x = Var("x", ty.f32(), accessor_expr);
     Func("func", utils::Vector{p}, ty.f32(),
@@ -436,7 +443,7 @@
     //     return x;
     // }
     auto* p = Param("p", ty.pointer(ty.vec4<f32>(), ast::AddressSpace::kFunction));
-    auto* z = Expr(Source{{{3, 3}, {3, 8}}}, "z");
+    auto* z = Expr(Source{{12, 34}}, "z");
     auto* accessor_expr = MemberAccessor(p, z);
     auto* star_p = Deref(accessor_expr);
     auto* x = Var("x", ty.f32(), star_p);
@@ -448,8 +455,8 @@
 
     EXPECT_FALSE(r()->Resolve());
     EXPECT_EQ(r()->error(),
-              "error: invalid member accessor expression. "
-              "Expected vector or struct, got 'ptr<function, vec4<f32>, read_write>'");
+              "12:34 error: invalid member accessor expression. Expected vector or struct, got "
+              "'ptr<function, vec4<f32>, read_write>'");
 }
 
 TEST_F(ResolverValidationTest,
diff --git a/src/tint/sem/expression.cc b/src/tint/sem/expression.cc
index cf338c4..ebea34c 100644
--- a/src/tint/sem/expression.cc
+++ b/src/tint/sem/expression.cc
@@ -39,6 +39,9 @@
       has_side_effects_(has_side_effects) {
     TINT_ASSERT(Semantic, type_);
     TINT_ASSERT(Semantic, (constant != nullptr) == (stage == EvaluationStage::kConstant));
+    if (constant != nullptr) {
+        TINT_ASSERT(Semantic, type_ == constant->Type());
+    }
 }
 
 Expression::~Expression() = default;
diff --git a/src/tint/traits.h b/src/tint/traits.h
index 441067e..f6dac27 100644
--- a/src/tint/traits.h
+++ b/src/tint/traits.h
@@ -16,6 +16,7 @@
 #define SRC_TINT_TRAITS_H_
 
 #include <tuple>
+#include <type_traits>
 #include <utility>
 
 namespace tint::traits {
diff --git a/src/tint/transform/multiplanar_external_texture.cc b/src/tint/transform/multiplanar_external_texture.cc
index f8c927b..f5770fb 100644
--- a/src/tint/transform/multiplanar_external_texture.cc
+++ b/src/tint/transform/multiplanar_external_texture.cc
@@ -263,7 +263,7 @@
             b.Member("gammaDecodeParams", b.ty.type_name("GammaTransferParams")),
             b.Member("gammaEncodeParams", b.ty.type_name("GammaTransferParams")),
             b.Member("gamutConversionMatrix", b.ty.mat3x3<f32>()),
-            b.Member("coordTransformationMatrix", b.ty.mat2x3<f32>())};
+            b.Member("coordTransformationMatrix", b.ty.mat3x2<f32>())};
 
         params_struct_sym = b.Symbols().New("ExternalTextureParams");
 
@@ -316,12 +316,9 @@
         const ast::CallExpression* plane_1_call = nullptr;
         switch (call_type) {
             case sem::BuiltinType::kTextureSampleBaseClampToEdge:
-                // TODO(dawn:1614): Change this statement to incorporate the "- 0.5" into the
-                // matrix.
-                stmts.Push(
-                    b.Decl(b.Let("modifiedCoords",
-                                 b.Mul(b.vec3<f32>(b.Sub("coord", f32(0.5)), f32(1.0f)),
-                                       b.MemberAccessor("params", "coordTransformationMatrix")))));
+                stmts.Push(b.Decl(b.Let(
+                    "modifiedCoords", b.Mul(b.MemberAccessor("params", "coordTransformationMatrix"),
+                                            b.vec3<f32>("coord", 1_a)))));
 
                 stmts.Push(b.Decl(b.Let(
                     "plane0_dims",
diff --git a/src/tint/transform/multiplanar_external_texture_test.cc b/src/tint/transform/multiplanar_external_texture_test.cc
index 15fa48e..c76e3e3 100644
--- a/src/tint/transform/multiplanar_external_texture_test.cc
+++ b/src/tint/transform/multiplanar_external_texture_test.cc
@@ -138,7 +138,7 @@
   gammaDecodeParams : GammaTransferParams,
   gammaEncodeParams : GammaTransferParams,
   gamutConversionMatrix : mat3x3<f32>,
-  coordTransformationMatrix : mat2x3<f32>,
+  coordTransformationMatrix : mat3x2<f32>,
 }
 
 @group(0) @binding(1) var ext_tex_plane_1 : texture_2d<f32>;
@@ -194,7 +194,7 @@
   gammaDecodeParams : GammaTransferParams,
   gammaEncodeParams : GammaTransferParams,
   gamutConversionMatrix : mat3x3<f32>,
-  coordTransformationMatrix : mat2x3<f32>,
+  coordTransformationMatrix : mat3x2<f32>,
 }
 
 @group(0) @binding(1) var ext_tex_plane_1 : texture_2d<f32>;
@@ -249,7 +249,7 @@
   gammaDecodeParams : GammaTransferParams,
   gammaEncodeParams : GammaTransferParams,
   gamutConversionMatrix : mat3x3<f32>,
-  coordTransformationMatrix : mat2x3<f32>,
+  coordTransformationMatrix : mat3x2<f32>,
 }
 
 @group(0) @binding(2) var ext_tex_plane_1 : texture_2d<f32>;
@@ -268,7 +268,7 @@
 }
 
 fn textureSampleExternal(plane0 : texture_2d<f32>, plane1 : texture_2d<f32>, smp : sampler, coord : vec2<f32>, params : ExternalTextureParams) -> vec4<f32> {
-  let modifiedCoords = (vec3<f32>((coord - 0.5f), 1.0f) * params.coordTransformationMatrix);
+  let modifiedCoords = (params.coordTransformationMatrix * vec3<f32>(coord, 1));
   let plane0_dims = vec2<f32>(textureDimensions(plane0, 0));
   let plane0_half_texel = (vec2<f32>(0.5) / plane0_dims);
   let plane0_clamped = clamp(modifiedCoords, plane0_half_texel, (1 - plane0_half_texel));
@@ -333,7 +333,7 @@
   gammaDecodeParams : GammaTransferParams,
   gammaEncodeParams : GammaTransferParams,
   gamutConversionMatrix : mat3x3<f32>,
-  coordTransformationMatrix : mat2x3<f32>,
+  coordTransformationMatrix : mat3x2<f32>,
 }
 
 @group(0) @binding(2) var ext_tex_plane_1 : texture_2d<f32>;
@@ -348,7 +348,7 @@
 }
 
 fn textureSampleExternal(plane0 : texture_2d<f32>, plane1 : texture_2d<f32>, smp : sampler, coord : vec2<f32>, params : ExternalTextureParams) -> vec4<f32> {
-  let modifiedCoords = (vec3<f32>((coord - 0.5f), 1.0f) * params.coordTransformationMatrix);
+  let modifiedCoords = (params.coordTransformationMatrix * vec3<f32>(coord, 1));
   let plane0_dims = vec2<f32>(textureDimensions(plane0, 0));
   let plane0_half_texel = (vec2<f32>(0.5) / plane0_dims);
   let plane0_clamped = clamp(modifiedCoords, plane0_half_texel, (1 - plane0_half_texel));
@@ -418,7 +418,7 @@
   gammaDecodeParams : GammaTransferParams,
   gammaEncodeParams : GammaTransferParams,
   gamutConversionMatrix : mat3x3<f32>,
-  coordTransformationMatrix : mat2x3<f32>,
+  coordTransformationMatrix : mat3x2<f32>,
 }
 
 @group(0) @binding(1) var ext_tex_plane_1 : texture_2d<f32>;
@@ -511,7 +511,7 @@
   gammaDecodeParams : GammaTransferParams,
   gammaEncodeParams : GammaTransferParams,
   gamutConversionMatrix : mat3x3<f32>,
-  coordTransformationMatrix : mat2x3<f32>,
+  coordTransformationMatrix : mat3x2<f32>,
 }
 
 @group(0) @binding(1) var ext_tex_plane_1 : texture_2d<f32>;
@@ -603,7 +603,7 @@
   gammaDecodeParams : GammaTransferParams,
   gammaEncodeParams : GammaTransferParams,
   gamutConversionMatrix : mat3x3<f32>,
-  coordTransformationMatrix : mat2x3<f32>,
+  coordTransformationMatrix : mat3x2<f32>,
 }
 
 @group(0) @binding(2) var ext_tex_plane_1 : texture_2d<f32>;
@@ -622,7 +622,7 @@
 }
 
 fn textureSampleExternal(plane0 : texture_2d<f32>, plane1 : texture_2d<f32>, smp : sampler, coord : vec2<f32>, params : ExternalTextureParams) -> vec4<f32> {
-  let modifiedCoords = (vec3<f32>((coord - 0.5f), 1.0f) * params.coordTransformationMatrix);
+  let modifiedCoords = (params.coordTransformationMatrix * vec3<f32>(coord, 1));
   let plane0_dims = vec2<f32>(textureDimensions(plane0, 0));
   let plane0_half_texel = (vec2<f32>(0.5) / plane0_dims);
   let plane0_clamped = clamp(modifiedCoords, plane0_half_texel, (1 - plane0_half_texel));
@@ -702,7 +702,7 @@
   gammaDecodeParams : GammaTransferParams,
   gammaEncodeParams : GammaTransferParams,
   gamutConversionMatrix : mat3x3<f32>,
-  coordTransformationMatrix : mat2x3<f32>,
+  coordTransformationMatrix : mat3x2<f32>,
 }
 
 @group(0) @binding(2) var ext_tex_plane_1 : texture_2d<f32>;
@@ -717,7 +717,7 @@
 }
 
 fn textureSampleExternal(plane0 : texture_2d<f32>, plane1 : texture_2d<f32>, smp : sampler, coord : vec2<f32>, params : ExternalTextureParams) -> vec4<f32> {
-  let modifiedCoords = (vec3<f32>((coord - 0.5f), 1.0f) * params.coordTransformationMatrix);
+  let modifiedCoords = (params.coordTransformationMatrix * vec3<f32>(coord, 1));
   let plane0_dims = vec2<f32>(textureDimensions(plane0, 0));
   let plane0_half_texel = (vec2<f32>(0.5) / plane0_dims);
   let plane0_clamped = clamp(modifiedCoords, plane0_half_texel, (1 - plane0_half_texel));
@@ -807,7 +807,7 @@
   gammaDecodeParams : GammaTransferParams,
   gammaEncodeParams : GammaTransferParams,
   gamutConversionMatrix : mat3x3<f32>,
-  coordTransformationMatrix : mat2x3<f32>,
+  coordTransformationMatrix : mat3x2<f32>,
 }
 
 @group(0) @binding(4) var ext_tex_plane_1 : texture_2d<f32>;
@@ -844,7 +844,7 @@
 }
 
 fn textureSampleExternal(plane0 : texture_2d<f32>, plane1 : texture_2d<f32>, smp : sampler, coord : vec2<f32>, params : ExternalTextureParams) -> vec4<f32> {
-  let modifiedCoords = (vec3<f32>((coord - 0.5f), 1.0f) * params.coordTransformationMatrix);
+  let modifiedCoords = (params.coordTransformationMatrix * vec3<f32>(coord, 1));
   let plane0_dims = vec2<f32>(textureDimensions(plane0, 0));
   let plane0_half_texel = (vec2<f32>(0.5) / plane0_dims);
   let plane0_clamped = clamp(modifiedCoords, plane0_half_texel, (1 - plane0_half_texel));
@@ -918,7 +918,7 @@
   gammaDecodeParams : GammaTransferParams,
   gammaEncodeParams : GammaTransferParams,
   gamutConversionMatrix : mat3x3<f32>,
-  coordTransformationMatrix : mat2x3<f32>,
+  coordTransformationMatrix : mat3x2<f32>,
 }
 
 @group(0) @binding(2) var ext_tex_plane_1 : texture_2d<f32>;
@@ -933,7 +933,7 @@
 }
 
 fn textureSampleExternal(plane0 : texture_2d<f32>, plane1 : texture_2d<f32>, smp : sampler, coord : vec2<f32>, params : ExternalTextureParams) -> vec4<f32> {
-  let modifiedCoords = (vec3<f32>((coord - 0.5f), 1.0f) * params.coordTransformationMatrix);
+  let modifiedCoords = (params.coordTransformationMatrix * vec3<f32>(coord, 1));
   let plane0_dims = vec2<f32>(textureDimensions(plane0, 0));
   let plane0_half_texel = (vec2<f32>(0.5) / plane0_dims);
   let plane0_clamped = clamp(modifiedCoords, plane0_half_texel, (1 - plane0_half_texel));
@@ -1011,7 +1011,7 @@
   gammaDecodeParams : GammaTransferParams,
   gammaEncodeParams : GammaTransferParams,
   gamutConversionMatrix : mat3x3<f32>,
-  coordTransformationMatrix : mat2x3<f32>,
+  coordTransformationMatrix : mat3x2<f32>,
 }
 
 @group(0) @binding(2) var ext_tex_plane_1 : texture_2d<f32>;
@@ -1031,7 +1031,7 @@
 }
 
 fn textureSampleExternal(plane0 : texture_2d<f32>, plane1 : texture_2d<f32>, smp : sampler, coord : vec2<f32>, params : ExternalTextureParams) -> vec4<f32> {
-  let modifiedCoords = (vec3<f32>((coord - 0.5f), 1.0f) * params.coordTransformationMatrix);
+  let modifiedCoords = (params.coordTransformationMatrix * vec3<f32>(coord, 1));
   let plane0_dims = vec2<f32>(textureDimensions(plane0, 0));
   let plane0_half_texel = (vec2<f32>(0.5) / plane0_dims);
   let plane0_clamped = clamp(modifiedCoords, plane0_half_texel, (1 - plane0_half_texel));
@@ -1104,7 +1104,7 @@
   gammaDecodeParams : GammaTransferParams,
   gammaEncodeParams : GammaTransferParams,
   gamutConversionMatrix : mat3x3<f32>,
-  coordTransformationMatrix : mat2x3<f32>,
+  coordTransformationMatrix : mat3x2<f32>,
 }
 
 @group(0) @binding(2) var ext_tex_plane_1 : texture_2d<f32>;
@@ -1119,7 +1119,7 @@
 }
 
 fn textureSampleExternal(plane0 : texture_2d<f32>, plane1 : texture_2d<f32>, smp : sampler, coord : vec2<f32>, params : ExternalTextureParams) -> vec4<f32> {
-  let modifiedCoords = (vec3<f32>((coord - 0.5f), 1.0f) * params.coordTransformationMatrix);
+  let modifiedCoords = (params.coordTransformationMatrix * vec3<f32>(coord, 1));
   let plane0_dims = vec2<f32>(textureDimensions(plane0, 0));
   let plane0_half_texel = (vec2<f32>(0.5) / plane0_dims);
   let plane0_clamped = clamp(modifiedCoords, plane0_half_texel, (1 - plane0_half_texel));
@@ -1199,7 +1199,7 @@
   gammaDecodeParams : GammaTransferParams,
   gammaEncodeParams : GammaTransferParams,
   gamutConversionMatrix : mat3x3<f32>,
-  coordTransformationMatrix : mat2x3<f32>,
+  coordTransformationMatrix : mat3x2<f32>,
 }
 
 @group(0) @binding(3) var ext_tex_plane_1 : texture_2d<f32>;
@@ -1218,7 +1218,7 @@
 }
 
 fn textureSampleExternal(plane0 : texture_2d<f32>, plane1 : texture_2d<f32>, smp : sampler, coord : vec2<f32>, params : ExternalTextureParams) -> vec4<f32> {
-  let modifiedCoords = (vec3<f32>((coord - 0.5f), 1.0f) * params.coordTransformationMatrix);
+  let modifiedCoords = (params.coordTransformationMatrix * vec3<f32>(coord, 1));
   let plane0_dims = vec2<f32>(textureDimensions(plane0, 0));
   let plane0_half_texel = (vec2<f32>(0.5) / plane0_dims);
   let plane0_clamped = clamp(modifiedCoords, plane0_half_texel, (1 - plane0_half_texel));
@@ -1303,7 +1303,7 @@
   gammaDecodeParams : GammaTransferParams,
   gammaEncodeParams : GammaTransferParams,
   gamutConversionMatrix : mat3x3<f32>,
-  coordTransformationMatrix : mat2x3<f32>,
+  coordTransformationMatrix : mat3x2<f32>,
 }
 
 @group(0) @binding(3) var ext_tex_plane_1 : texture_2d<f32>;
@@ -1327,7 +1327,7 @@
 }
 
 fn textureSampleExternal(plane0 : texture_2d<f32>, plane1 : texture_2d<f32>, smp : sampler, coord : vec2<f32>, params : ExternalTextureParams) -> vec4<f32> {
-  let modifiedCoords = (vec3<f32>((coord - 0.5f), 1.0f) * params.coordTransformationMatrix);
+  let modifiedCoords = (params.coordTransformationMatrix * vec3<f32>(coord, 1));
   let plane0_dims = vec2<f32>(textureDimensions(plane0, 0));
   let plane0_half_texel = (vec2<f32>(0.5) / plane0_dims);
   let plane0_clamped = clamp(modifiedCoords, plane0_half_texel, (1 - plane0_half_texel));
@@ -1408,7 +1408,7 @@
   gammaDecodeParams : GammaTransferParams,
   gammaEncodeParams : GammaTransferParams,
   gamutConversionMatrix : mat3x3<f32>,
-  coordTransformationMatrix : mat2x3<f32>,
+  coordTransformationMatrix : mat3x2<f32>,
 }
 
 @group(0) @binding(2) var ext_tex_plane_1 : texture_2d<f32>;
@@ -1423,7 +1423,7 @@
 }
 
 fn textureSampleExternal(plane0 : texture_2d<f32>, plane1 : texture_2d<f32>, smp : sampler, coord : vec2<f32>, params : ExternalTextureParams) -> vec4<f32> {
-  let modifiedCoords = (vec3<f32>((coord - 0.5f), 1.0f) * params.coordTransformationMatrix);
+  let modifiedCoords = (params.coordTransformationMatrix * vec3<f32>(coord, 1));
   let plane0_dims = vec2<f32>(textureDimensions(plane0, 0));
   let plane0_half_texel = (vec2<f32>(0.5) / plane0_dims);
   let plane0_clamped = clamp(modifiedCoords, plane0_half_texel, (1 - plane0_half_texel));
@@ -1509,7 +1509,7 @@
   gammaDecodeParams : GammaTransferParams,
   gammaEncodeParams : GammaTransferParams,
   gamutConversionMatrix : mat3x3<f32>,
-  coordTransformationMatrix : mat2x3<f32>,
+  coordTransformationMatrix : mat3x2<f32>,
 }
 
 @group(0) @binding(2) var ext_tex_plane_1 : texture_2d<f32>;
@@ -1524,7 +1524,7 @@
 }
 
 fn textureSampleExternal(plane0 : texture_2d<f32>, plane1 : texture_2d<f32>, smp : sampler, coord : vec2<f32>, params : ExternalTextureParams) -> vec4<f32> {
-  let modifiedCoords = (vec3<f32>((coord - 0.5f), 1.0f) * params.coordTransformationMatrix);
+  let modifiedCoords = (params.coordTransformationMatrix * vec3<f32>(coord, 1));
   let plane0_dims = vec2<f32>(textureDimensions(plane0, 0));
   let plane0_half_texel = (vec2<f32>(0.5) / plane0_dims);
   let plane0_clamped = clamp(modifiedCoords, plane0_half_texel, (1 - plane0_half_texel));
@@ -1598,7 +1598,7 @@
   gammaDecodeParams : GammaTransferParams,
   gammaEncodeParams : GammaTransferParams,
   gamutConversionMatrix : mat3x3<f32>,
-  coordTransformationMatrix : mat2x3<f32>,
+  coordTransformationMatrix : mat3x2<f32>,
 }
 
 fn f(ext_tex : texture_2d<f32>, ext_tex_plane_1 : texture_2d<f32>, ext_tex_params : ExternalTextureParams) -> vec2<u32> {
@@ -1650,7 +1650,7 @@
   gammaDecodeParams : GammaTransferParams,
   gammaEncodeParams : GammaTransferParams,
   gamutConversionMatrix : mat3x3<f32>,
-  coordTransformationMatrix : mat2x3<f32>,
+  coordTransformationMatrix : mat3x2<f32>,
 }
 
 @group(0) @binding(2) var ext_tex_plane_1 : texture_2d<f32>;
@@ -1667,7 +1667,7 @@
 }
 
 fn textureSampleExternal(plane0 : texture_2d<f32>, plane1 : texture_2d<f32>, smp : sampler, coord : vec2<f32>, params : ExternalTextureParams) -> vec4<f32> {
-  let modifiedCoords = (vec3<f32>((coord - 0.5f), 1.0f) * params.coordTransformationMatrix);
+  let modifiedCoords = (params.coordTransformationMatrix * vec3<f32>(coord, 1));
   let plane0_dims = vec2<f32>(textureDimensions(plane0, 0));
   let plane0_half_texel = (vec2<f32>(0.5) / plane0_dims);
   let plane0_clamped = clamp(modifiedCoords, plane0_half_texel, (1 - plane0_half_texel));
@@ -1746,7 +1746,7 @@
   gammaDecodeParams : GammaTransferParams,
   gammaEncodeParams : GammaTransferParams,
   gamutConversionMatrix : mat3x3<f32>,
-  coordTransformationMatrix : mat2x3<f32>,
+  coordTransformationMatrix : mat3x2<f32>,
 }
 
 @group(0) @binding(2) var ext_tex_plane_1 : texture_2d<f32>;
@@ -1766,7 +1766,7 @@
 }
 
 fn textureSampleExternal(plane0 : texture_2d<f32>, plane1 : texture_2d<f32>, smp : sampler, coord : vec2<f32>, params : ExternalTextureParams) -> vec4<f32> {
-  let modifiedCoords = (vec3<f32>((coord - 0.5f), 1.0f) * params.coordTransformationMatrix);
+  let modifiedCoords = (params.coordTransformationMatrix * vec3<f32>(coord, 1));
   let plane0_dims = vec2<f32>(textureDimensions(plane0, 0));
   let plane0_half_texel = (vec2<f32>(0.5) / plane0_dims);
   let plane0_clamped = clamp(modifiedCoords, plane0_half_texel, (1 - plane0_half_texel));
diff --git a/src/tint/utils/compiler_macros.h b/src/tint/utils/compiler_macros.h
index b0df241..1a04042 100644
--- a/src/tint/utils/compiler_macros.h
+++ b/src/tint/utils/compiler_macros.h
@@ -19,7 +19,7 @@
 
 #define TINT_REQUIRE_SEMICOLON static_assert(true)
 
-#if defined(_MSC_VER)
+#if defined(_MSC_VER) && !defined(__clang__)
 ////////////////////////////////////////////////////////////////////////////////
 // MSVC
 ////////////////////////////////////////////////////////////////////////////////
@@ -30,6 +30,7 @@
 #define TINT_DISABLE_WARNING_SIGN_CONVERSION     /* currently no-op */
 #define TINT_DISABLE_WARNING_UNREACHABLE_CODE __pragma(warning(disable : 4702))
 #define TINT_DISABLE_WARNING_WEAK_VTABLES /* currently no-op */
+#define TINT_DISABLE_WARNING_FLOAT_EQUAL  /* currently no-op */
 
 // clang-format off
 #define TINT_BEGIN_DISABLE_WARNING(name)     \
@@ -52,6 +53,7 @@
     _Pragma("clang diagnostic ignored \"-Wsign-conversion\"")
 #define TINT_DISABLE_WARNING_UNREACHABLE_CODE /* currently no-op */
 #define TINT_DISABLE_WARNING_WEAK_VTABLES _Pragma("clang diagnostic ignored \"-Wweak-vtables\"")
+#define TINT_DISABLE_WARNING_FLOAT_EQUAL _Pragma("clang diagnostic ignored \"-Wfloat-equal\"")
 
 // clang-format off
 #define TINT_BEGIN_DISABLE_WARNING(name)     \
@@ -74,6 +76,7 @@
 #define TINT_DISABLE_WARNING_SIGN_CONVERSION  /* currently no-op */
 #define TINT_DISABLE_WARNING_UNREACHABLE_CODE /* currently no-op */
 #define TINT_DISABLE_WARNING_WEAK_VTABLES     /* currently no-op */
+#define TINT_DISABLE_WARNING_FLOAT_EQUAL      /* currently no-op */
 
 // clang-format off
 #define TINT_BEGIN_DISABLE_WARNING(name)     \