Import Tint changes from Dawn

Changes:
  - 6ab02659de463f93a0e723845455bf06d00bb683 tint/spirv-reader: add support for GLSLstd450MatrixInverse by Antonio Maiorano <amaiorano@google.com>
GitOrigin-RevId: 6ab02659de463f93a0e723845455bf06d00bb683
Change-Id: Ib06eb42479d4d863fb9d6e8f546d65f0edca4eeb
Reviewed-on: https://dawn-review.googlesource.com/c/tint/+/102520
Kokoro: Kokoro <noreply+kokoro@google.com>
Commit-Queue: Ben Clayton <bclayton@google.com>
Reviewed-by: Ben Clayton <bclayton@google.com>
diff --git a/src/tint/reader/spirv/function.cc b/src/tint/reader/spirv/function.cc
index 773ba46..b16d08d 100644
--- a/src/tint/reader/spirv/function.cc
+++ b/src/tint/reader/spirv/function.cc
@@ -415,8 +415,6 @@
         case GLSLstd450Acosh:
         case GLSLstd450Atanh:
 
-        case GLSLstd450MatrixInverse:
-
         case GLSLstd450Modf:
         case GLSLstd450ModfStruct:
         case GLSLstd450IMix:
@@ -4043,6 +4041,11 @@
             default:
                 break;
         }
+    } else {
+        switch (ext_opcode) {
+            case GLSLstd450MatrixInverse:
+                return EmitGlslStd450MatrixInverse(inst);
+        }
     }
 
     const auto name = GetGlslStd450FuncName(ext_opcode);
@@ -4067,6 +4070,196 @@
     return parser_impl_.RectifyForcedResultType(call_expr, inst, first_operand_type);
 }
 
+TypedExpression FunctionEmitter::EmitGlslStd450MatrixInverse(
+    const spvtools::opt::Instruction& inst) {
+    auto mat = MakeOperand(inst, 2);
+    auto* mat_ty = mat.type->As<Matrix>();
+    TINT_ASSERT(Reader, mat_ty);
+    TINT_ASSERT(Reader, mat_ty->columns == mat_ty->rows);
+    auto& pb = builder_;
+
+    auto idx = [&](size_t row, size_t col) {
+        return pb.IndexAccessor(pb.IndexAccessor(mat.expr, u32(row)), u32(col));
+    };
+
+    // Compute and save determinant to a let
+    auto* det = pb.Div(1.0_f, pb.Call(Source{}, "determinant", mat.expr));
+    auto s = pb.Symbols().New("s");
+    AddStatement(pb.Decl(pb.Let(s, det)));
+
+    // Returns (a * b) - (c * d)
+    auto sub_mul2 = [&](auto* a, auto* b, auto* c, auto* d) {
+        return pb.Sub(pb.Mul(a, b), pb.Mul(c, d));
+    };
+
+    // Returns (a * b) - (c * d) + (e * f)
+    auto sub_add_mul3 = [&](auto* a, auto* b, auto* c, auto* d, auto* e, auto* f) {
+        return pb.Add(pb.Sub(pb.Mul(a, b), pb.Mul(c, d)), pb.Mul(e, f));
+    };
+
+    // Returns (a * b) + (c * d) - (e * f)
+    auto add_sub_mul3 = [&](auto* a, auto* b, auto* c, auto* d, auto* e, auto* f) {
+        return pb.Sub(pb.Add(pb.Mul(a, b), pb.Mul(c, d)), pb.Mul(e, f));
+    };
+
+    // Returns -a
+    auto neg = [&](auto&& a) { return pb.Negation(a); };
+
+    switch (mat_ty->columns) {
+        case 2: {
+            // a, b
+            // c, d
+            auto* a = idx(0, 0);
+            auto* b = idx(0, 1);
+            auto* c = idx(1, 0);
+            auto* d = idx(1, 1);
+
+            // s * d, -s * b, -s * c, s * a
+            auto* r = pb.mat2x2<f32>(  //
+                pb.vec2<f32>(pb.Mul(s, d), pb.Mul(neg(s), b)),
+                pb.vec2<f32>(pb.Mul(neg(s), c), pb.Mul(s, a)));
+            return {mat.type, r};
+        }
+
+        case 3: {
+            // a, b, c,
+            // d, e, f,
+            // g, h, i
+            auto* a = idx(0, 0);
+            auto* b = idx(0, 1);
+            auto* c = idx(0, 2);
+            auto* d = idx(1, 0);
+            auto* e = idx(1, 1);
+            auto* f = idx(1, 2);
+            auto* g = idx(2, 0);
+            auto* h = idx(2, 1);
+            auto* i = idx(2, 2);
+
+            auto r = pb.Mul(s,               //
+                            pb.mat3x3<f32>(  //
+                                pb.vec3<f32>(
+                                    // e * i - f * h
+                                    sub_mul2(e, i, f, h),
+                                    // c * h - b * i
+                                    sub_mul2(c, h, b, i),
+                                    // b * f - c * e
+                                    sub_mul2(b, f, c, e)),
+                                pb.vec3<f32>(
+                                    // f * g - d * i
+                                    sub_mul2(f, g, d, i),
+                                    // a * i - c * g
+                                    sub_mul2(a, i, c, g),
+                                    // c * d - a * f
+                                    sub_mul2(c, d, a, f)),
+                                pb.vec3<f32>(
+                                    // d * h - e * g
+                                    sub_mul2(d, h, e, g),
+                                    // b * g - a * h
+                                    sub_mul2(b, g, a, h),
+                                    // a * e - b * d
+                                    sub_mul2(a, e, b, d))));
+            return {mat.type, r};
+        }
+
+        case 4: {
+            // a, b, c, d,
+            // e, f, g, h,
+            // i, j, k, l,
+            // m, n, o, p
+            auto* a = idx(0, 0);
+            auto* b = idx(0, 1);
+            auto* c = idx(0, 2);
+            auto* d = idx(0, 3);
+            auto* e = idx(1, 0);
+            auto* f = idx(1, 1);
+            auto* g = idx(1, 2);
+            auto* h = idx(1, 3);
+            auto* i = idx(2, 0);
+            auto* j = idx(2, 1);
+            auto* k = idx(2, 2);
+            auto* l = idx(2, 3);
+            auto* m = idx(3, 0);
+            auto* n = idx(3, 1);
+            auto* o = idx(3, 2);
+            auto* p = idx(3, 3);
+
+            // kplo = k * p - l * o, jpln = j * p - l * n, jokn = j * o - k * n;
+            auto* kplo = sub_mul2(k, p, l, o);
+            auto* jpln = sub_mul2(j, p, l, n);
+            auto* jokn = sub_mul2(j, o, k, n);
+
+            // gpho = g * p - h * o, fphn = f * p - h * n, fogn = f * o - g * n;
+            auto* gpho = sub_mul2(g, p, h, o);
+            auto* fphn = sub_mul2(f, p, h, n);
+            auto* fogn = sub_mul2(f, o, g, n);
+
+            // glhk = g * l - h * k, flhj = f * l - h * j, fkgj = f * k - g * j;
+            auto* glhk = sub_mul2(g, l, h, k);
+            auto* flhj = sub_mul2(f, l, h, j);
+            auto* fkgj = sub_mul2(f, k, g, j);
+
+            // iplm = i * p - l * m, iokm = i * o - k * m, ephm = e * p - h * m;
+            auto* iplm = sub_mul2(i, p, l, m);
+            auto* iokm = sub_mul2(i, o, k, m);
+            auto* ephm = sub_mul2(e, p, h, m);
+
+            // eogm = e * o - g * m, elhi = e * l - h * i, ekgi = e * k - g * i;
+            auto* eogm = sub_mul2(e, o, g, m);
+            auto* elhi = sub_mul2(e, l, h, i);
+            auto* ekgi = sub_mul2(e, k, g, i);
+
+            // injm = i * n - j * m, enfm = e * n - f * m, ejfi = e * j - f * i;
+            auto* injm = sub_mul2(i, n, j, m);
+            auto* enfm = sub_mul2(e, n, f, m);
+            auto* ejfi = sub_mul2(e, j, f, i);
+
+            auto r = pb.Mul(s,               //
+                            pb.mat4x4<f32>(  //
+                                pb.vec4<f32>(
+                                    // f * kplo - g * jpln + h * jokn
+                                    sub_add_mul3(f, kplo, g, jpln, h, jokn),
+                                    // -b * kplo + c * jpln - d * jokn
+                                    add_sub_mul3(neg(b), kplo, c, jpln, d, jokn),
+                                    // b * gpho - c * fphn + d * fogn
+                                    sub_add_mul3(b, gpho, c, fphn, d, fogn),
+                                    // -b * glhk + c * flhj - d * fkgj
+                                    add_sub_mul3(neg(b), glhk, c, flhj, d, fkgj)),
+                                pb.vec4<f32>(
+                                    // -e * kplo + g * iplm - h * iokm
+                                    add_sub_mul3(neg(e), kplo, g, iplm, h, iokm),
+                                    // a * kplo - c * iplm + d * iokm
+                                    sub_add_mul3(a, kplo, c, iplm, d, iokm),
+                                    // -a * gpho + c * ephm - d * eogm
+                                    add_sub_mul3(neg(a), gpho, c, ephm, d, eogm),
+                                    // a * glhk - c * elhi + d * ekgi
+                                    sub_add_mul3(a, glhk, c, elhi, d, ekgi)),
+                                pb.vec4<f32>(
+                                    // e * jpln - f * iplm + h * injm
+                                    sub_add_mul3(e, jpln, f, iplm, h, injm),
+                                    // -a * jpln + b * iplm - d * injm
+                                    add_sub_mul3(neg(a), jpln, b, iplm, d, injm),
+                                    // a * fphn - b * ephm + d * enfm
+                                    sub_add_mul3(a, fphn, b, ephm, d, enfm),
+                                    // -a * flhj + b * elhi - d * ejfi
+                                    add_sub_mul3(neg(a), flhj, b, elhi, d, ejfi)),
+                                pb.vec4<f32>(
+                                    // -e * jokn + f * iokm - g * injm
+                                    add_sub_mul3(neg(e), jokn, f, iokm, g, injm),
+                                    // a * jokn - b * iokm + c * injm
+                                    sub_add_mul3(a, jokn, b, iokm, c, injm),
+                                    // -a * fogn + b * eogm - c * enfm
+                                    add_sub_mul3(neg(a), fogn, b, eogm, c, enfm),
+                                    // a * fkgj - b * ekgi + c * ejfi
+                                    sub_add_mul3(a, fkgj, b, ekgi, c, ejfi))));
+            return {mat.type, r};
+        }
+    }
+
+    const auto ext_opcode = inst.GetSingleWordInOperand(1);
+    Fail() << "invalid matrix size for " << GetGlslStd450FuncName(ext_opcode);
+    return {};
+}
+
 ast::IdentifierExpression* FunctionEmitter::Swizzle(uint32_t i) {
     if (i >= kMaxVectorLen) {
         Fail() << "vector component index is larger than " << kMaxVectorLen - 1 << ": " << i;
diff --git a/src/tint/reader/spirv/function.h b/src/tint/reader/spirv/function.h
index 7a2a86b..d779c93 100644
--- a/src/tint/reader/spirv/function.h
+++ b/src/tint/reader/spirv/function.h
@@ -804,6 +804,11 @@
     /// @returns an AST expression for the instruction, or nullptr.
     TypedExpression EmitGlslStd450ExtInst(const spvtools::opt::Instruction& inst);
 
+    /// Creates an expression for the GLSL.std.450 matrix `inverse` extended instruction.
+    /// @param inst a SPIR-V OpExtInst instruction from GLSL.std.450
+    /// @returns an AST expression for the instruction, or nullptr.
+    TypedExpression EmitGlslStd450MatrixInverse(const spvtools::opt::Instruction& inst);
+
     /// Creates an expression for OpCompositeExtract
     /// @param inst an OpCompositeExtract instruction.
     /// @returns an AST expression for the instruction, or nullptr.
diff --git a/src/tint/reader/spirv/function_glsl_std_450_test.cc b/src/tint/reader/spirv/function_glsl_std_450_test.cc
index f97f3e9..c5131e9 100644
--- a/src/tint/reader/spirv/function_glsl_std_450_test.cc
+++ b/src/tint/reader/spirv/function_glsl_std_450_test.cc
@@ -98,8 +98,8 @@
   %v4float_50_50_50_50 = OpConstantComposite %v4float %float_50 %float_50 %float_50 %float_50
 
   %mat2v2float_50_60 = OpConstantComposite %mat2v2float %v2float_50_60 %v2float_50_60
-  %mat3v3float_50_60_70 = OpConstantComposite %mat2v2float %v3float_50_60_70 %v3float_50_60_70 %v3float_50_60_70
-  %mat4v4float_50_50_50_50 = OpConstantComposite %mat2v2float %v4float_50_50_50_50 %v4float_50_50_50_50 %v4float_50_50_50_50 %v4float_50_50_50_50
+  %mat3v3float_50_60_70 = OpConstantComposite %mat3v3float %v3float_50_60_70 %v3float_50_60_70 %v3float_50_60_70
+  %mat4v4float_50_50_50_50 = OpConstantComposite %mat4v4float %v4float_50_50_50_50 %v4float_50_50_50_50 %v4float_50_50_50_50 %v4float_50_50_50_50
 
   %100 = OpFunction %void None %voidfn
   %entry = OpLabel
@@ -1158,5 +1158,159 @@
                          GlslStd450_Determinant,
                          ::testing::Values("m2x2f1", "m3x3f1", "m4x4f1"));
 
+TEST_F(SpvParserTest, GlslStd450_MatrixInverse_mat2x2) {
+    const auto assembly = Preamble() + R"(
+     %1 = OpExtInst %mat2v2float %glsl MatrixInverse %m2x2f1
+     OpReturn
+     OpFunctionEnd
+  )";
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions());
+    auto fe = p->function_emitter(100);
+    EXPECT_TRUE(fe.EmitBody()) << p->error();
+    auto ast_body = fe.ast_body();
+    const auto body = test::ToString(p->program(), ast_body);
+
+    std::string expected =
+        "let s = (1.0f / determinant(m2x2f1));\n"
+        "let x_1 : mat2x2<f32> = mat2x2<f32>(vec2<f32>((s * m2x2f1[1u][1u]), (-(s) * "
+        "m2x2f1[0u][1u])), vec2<f32>((-(s) * m2x2f1[1u][0u]), (s * m2x2f1[0u][0u])));";
+
+    EXPECT_THAT(body, HasSubstr(expected)) << body;
+}
+
+TEST_F(SpvParserTest, GlslStd450_MatrixInverse_mat3x3) {
+    const auto assembly = Preamble() + R"(
+     %1 = OpExtInst %mat3v3float %glsl MatrixInverse %m3x3f1
+     OpReturn
+     OpFunctionEnd
+  )";
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions());
+    auto fe = p->function_emitter(100);
+    EXPECT_TRUE(fe.EmitBody()) << p->error();
+    auto ast_body = fe.ast_body();
+    const auto body = test::ToString(p->program(), ast_body);
+
+    std::string expected =
+        "let s = (1.0f / determinant(m3x3f1));\n"
+        "let x_1 : mat3x3<f32> = (s * mat3x3<f32>(vec3<f32>(((m3x3f1[1u][1u] * m3x3f1[2u][2u]) - "
+        "(m3x3f1[1u][2u] * m3x3f1[2u][1u])), ((m3x3f1[0u][2u] * m3x3f1[2u][1u]) - (m3x3f1[0u][1u] "
+        "* m3x3f1[2u][2u])), ((m3x3f1[0u][1u] * m3x3f1[1u][2u]) - (m3x3f1[0u][2u] * "
+        "m3x3f1[1u][1u]))), vec3<f32>(((m3x3f1[1u][2u] * m3x3f1[2u][0u]) - (m3x3f1[1u][0u] * "
+        "m3x3f1[2u][2u])), ((m3x3f1[0u][0u] * m3x3f1[2u][2u]) - (m3x3f1[0u][2u] * "
+        "m3x3f1[2u][0u])), ((m3x3f1[0u][2u] * m3x3f1[1u][0u]) - (m3x3f1[0u][0u] * "
+        "m3x3f1[1u][2u]))), vec3<f32>(((m3x3f1[1u][0u] * m3x3f1[2u][1u]) - (m3x3f1[1u][1u] * "
+        "m3x3f1[2u][0u])), ((m3x3f1[0u][1u] * m3x3f1[2u][0u]) - (m3x3f1[0u][0u] * "
+        "m3x3f1[2u][1u])), ((m3x3f1[0u][0u] * m3x3f1[1u][1u]) - (m3x3f1[0u][1u] * "
+        "m3x3f1[1u][0u])))));";
+
+    EXPECT_THAT(body, HasSubstr(expected)) << body;
+}
+
+TEST_F(SpvParserTest, GlslStd450_MatrixInverse_mat4x4) {
+    const auto assembly = Preamble() + R"(
+     %1 = OpExtInst %mat4v4float %glsl MatrixInverse %m4x4f1
+     OpReturn
+     OpFunctionEnd
+  )";
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions());
+    auto fe = p->function_emitter(100);
+    EXPECT_TRUE(fe.EmitBody()) << p->error();
+    auto ast_body = fe.ast_body();
+    const auto body = test::ToString(p->program(), ast_body);
+
+    std::string expected =
+        "let s = (1.0f / determinant(m4x4f1));\n"
+        "let x_1 : mat4x4<f32> = (s * mat4x4<f32>(vec4<f32>((((m4x4f1[1u][1u] * ((m4x4f1[2u][2u] * "
+        "m4x4f1[3u][3u]) - (m4x4f1[2u][3u] * m4x4f1[3u][2u]))) - (m4x4f1[1u][2u] * "
+        "((m4x4f1[2u][1u] * m4x4f1[3u][3u]) - (m4x4f1[2u][3u] * m4x4f1[3u][1u])))) + "
+        "(m4x4f1[1u][3u] * ((m4x4f1[2u][1u] * m4x4f1[3u][2u]) - (m4x4f1[2u][2u] * "
+        "m4x4f1[3u][1u])))), (((-(m4x4f1[0u][1u]) * ((m4x4f1[2u][2u] * m4x4f1[3u][3u]) - "
+        "(m4x4f1[2u][3u] * m4x4f1[3u][2u]))) + (m4x4f1[0u][2u] * ((m4x4f1[2u][1u] * "
+        "m4x4f1[3u][3u]) - (m4x4f1[2u][3u] * m4x4f1[3u][1u])))) - (m4x4f1[0u][3u] * "
+        "((m4x4f1[2u][1u] * m4x4f1[3u][2u]) - (m4x4f1[2u][2u] * m4x4f1[3u][1u])))), "
+        "(((m4x4f1[0u][1u] * ((m4x4f1[1u][2u] * m4x4f1[3u][3u]) - (m4x4f1[1u][3u] * "
+        "m4x4f1[3u][2u]))) - (m4x4f1[0u][2u] * ((m4x4f1[1u][1u] * m4x4f1[3u][3u]) - "
+        "(m4x4f1[1u][3u] * m4x4f1[3u][1u])))) + (m4x4f1[0u][3u] * ((m4x4f1[1u][1u] * "
+        "m4x4f1[3u][2u]) - (m4x4f1[1u][2u] * m4x4f1[3u][1u])))), (((-(m4x4f1[0u][1u]) * "
+        "((m4x4f1[1u][2u] * m4x4f1[2u][3u]) - (m4x4f1[1u][3u] * m4x4f1[2u][2u]))) + "
+        "(m4x4f1[0u][2u] * ((m4x4f1[1u][1u] * m4x4f1[2u][3u]) - (m4x4f1[1u][3u] * "
+        "m4x4f1[2u][1u])))) - (m4x4f1[0u][3u] * ((m4x4f1[1u][1u] * m4x4f1[2u][2u]) - "
+        "(m4x4f1[1u][2u] * m4x4f1[2u][1u]))))), vec4<f32>((((-(m4x4f1[1u][0u]) * ((m4x4f1[2u][2u] "
+        "* m4x4f1[3u][3u]) - (m4x4f1[2u][3u] * m4x4f1[3u][2u]))) + (m4x4f1[1u][2u] * "
+        "((m4x4f1[2u][0u] * m4x4f1[3u][3u]) - (m4x4f1[2u][3u] * m4x4f1[3u][0u])))) - "
+        "(m4x4f1[1u][3u] * ((m4x4f1[2u][0u] * m4x4f1[3u][2u]) - (m4x4f1[2u][2u] * "
+        "m4x4f1[3u][0u])))), (((m4x4f1[0u][0u] * ((m4x4f1[2u][2u] * m4x4f1[3u][3u]) - "
+        "(m4x4f1[2u][3u] * m4x4f1[3u][2u]))) - (m4x4f1[0u][2u] * ((m4x4f1[2u][0u] * "
+        "m4x4f1[3u][3u]) - (m4x4f1[2u][3u] * m4x4f1[3u][0u])))) + (m4x4f1[0u][3u] * "
+        "((m4x4f1[2u][0u] * m4x4f1[3u][2u]) - (m4x4f1[2u][2u] * m4x4f1[3u][0u])))), "
+        "(((-(m4x4f1[0u][0u]) * ((m4x4f1[1u][2u] * m4x4f1[3u][3u]) - (m4x4f1[1u][3u] * "
+        "m4x4f1[3u][2u]))) + (m4x4f1[0u][2u] * ((m4x4f1[1u][0u] * m4x4f1[3u][3u]) - "
+        "(m4x4f1[1u][3u] * m4x4f1[3u][0u])))) - (m4x4f1[0u][3u] * ((m4x4f1[1u][0u] * "
+        "m4x4f1[3u][2u]) - (m4x4f1[1u][2u] * m4x4f1[3u][0u])))), (((m4x4f1[0u][0u] * "
+        "((m4x4f1[1u][2u] * m4x4f1[2u][3u]) - (m4x4f1[1u][3u] * m4x4f1[2u][2u]))) - "
+        "(m4x4f1[0u][2u] * ((m4x4f1[1u][0u] * m4x4f1[2u][3u]) - (m4x4f1[1u][3u] * "
+        "m4x4f1[2u][0u])))) + (m4x4f1[0u][3u] * ((m4x4f1[1u][0u] * m4x4f1[2u][2u]) - "
+        "(m4x4f1[1u][2u] * m4x4f1[2u][0u]))))), vec4<f32>((((m4x4f1[1u][0u] * ((m4x4f1[2u][1u] * "
+        "m4x4f1[3u][3u]) - (m4x4f1[2u][3u] * m4x4f1[3u][1u]))) - (m4x4f1[1u][1u] * "
+        "((m4x4f1[2u][0u] * m4x4f1[3u][3u]) - (m4x4f1[2u][3u] * m4x4f1[3u][0u])))) + "
+        "(m4x4f1[1u][3u] * ((m4x4f1[2u][0u] * m4x4f1[3u][1u]) - (m4x4f1[2u][1u] * "
+        "m4x4f1[3u][0u])))), (((-(m4x4f1[0u][0u]) * ((m4x4f1[2u][1u] * m4x4f1[3u][3u]) - "
+        "(m4x4f1[2u][3u] * m4x4f1[3u][1u]))) + (m4x4f1[0u][1u] * ((m4x4f1[2u][0u] * "
+        "m4x4f1[3u][3u]) - (m4x4f1[2u][3u] * m4x4f1[3u][0u])))) - (m4x4f1[0u][3u] * "
+        "((m4x4f1[2u][0u] * m4x4f1[3u][1u]) - (m4x4f1[2u][1u] * m4x4f1[3u][0u])))), "
+        "(((m4x4f1[0u][0u] * ((m4x4f1[1u][1u] * m4x4f1[3u][3u]) - (m4x4f1[1u][3u] * "
+        "m4x4f1[3u][1u]))) - (m4x4f1[0u][1u] * ((m4x4f1[1u][0u] * m4x4f1[3u][3u]) - "
+        "(m4x4f1[1u][3u] * m4x4f1[3u][0u])))) + (m4x4f1[0u][3u] * ((m4x4f1[1u][0u] * "
+        "m4x4f1[3u][1u]) - (m4x4f1[1u][1u] * m4x4f1[3u][0u])))), (((-(m4x4f1[0u][0u]) * "
+        "((m4x4f1[1u][1u] * m4x4f1[2u][3u]) - (m4x4f1[1u][3u] * m4x4f1[2u][1u]))) + "
+        "(m4x4f1[0u][1u] * ((m4x4f1[1u][0u] * m4x4f1[2u][3u]) - (m4x4f1[1u][3u] * "
+        "m4x4f1[2u][0u])))) - (m4x4f1[0u][3u] * ((m4x4f1[1u][0u] * m4x4f1[2u][1u]) - "
+        "(m4x4f1[1u][1u] * m4x4f1[2u][0u]))))), vec4<f32>((((-(m4x4f1[1u][0u]) * ((m4x4f1[2u][1u] "
+        "* m4x4f1[3u][2u]) - (m4x4f1[2u][2u] * m4x4f1[3u][1u]))) + (m4x4f1[1u][1u] * "
+        "((m4x4f1[2u][0u] * m4x4f1[3u][2u]) - (m4x4f1[2u][2u] * m4x4f1[3u][0u])))) - "
+        "(m4x4f1[1u][2u] * ((m4x4f1[2u][0u] * m4x4f1[3u][1u]) - (m4x4f1[2u][1u] * "
+        "m4x4f1[3u][0u])))), (((m4x4f1[0u][0u] * ((m4x4f1[2u][1u] * m4x4f1[3u][2u]) - "
+        "(m4x4f1[2u][2u] * m4x4f1[3u][1u]))) - (m4x4f1[0u][1u] * ((m4x4f1[2u][0u] * "
+        "m4x4f1[3u][2u]) - (m4x4f1[2u][2u] * m4x4f1[3u][0u])))) + (m4x4f1[0u][2u] * "
+        "((m4x4f1[2u][0u] * m4x4f1[3u][1u]) - (m4x4f1[2u][1u] * m4x4f1[3u][0u])))), "
+        "(((-(m4x4f1[0u][0u]) * ((m4x4f1[1u][1u] * m4x4f1[3u][2u]) - (m4x4f1[1u][2u] * "
+        "m4x4f1[3u][1u]))) + (m4x4f1[0u][1u] * ((m4x4f1[1u][0u] * m4x4f1[3u][2u]) - "
+        "(m4x4f1[1u][2u] * m4x4f1[3u][0u])))) - (m4x4f1[0u][2u] * ((m4x4f1[1u][0u] * "
+        "m4x4f1[3u][1u]) - (m4x4f1[1u][1u] * m4x4f1[3u][0u])))), (((m4x4f1[0u][0u] * "
+        "((m4x4f1[1u][1u] * m4x4f1[2u][2u]) - (m4x4f1[1u][2u] * m4x4f1[2u][1u]))) - "
+        "(m4x4f1[0u][1u] * ((m4x4f1[1u][0u] * m4x4f1[2u][2u]) - (m4x4f1[1u][2u] * "
+        "m4x4f1[2u][0u])))) + (m4x4f1[0u][2u] * ((m4x4f1[1u][0u] * m4x4f1[2u][1u]) - "
+        "(m4x4f1[1u][1u] * m4x4f1[2u][0u])))))));";
+
+    EXPECT_THAT(body, HasSubstr(expected)) << body;
+}
+
+TEST_F(SpvParserTest, GlslStd450_MatrixInverse_MultipleInScope) {
+    const auto assembly = Preamble() + R"(
+     %1 = OpExtInst %mat2v2float %glsl MatrixInverse %m2x2f1
+     %2 = OpExtInst %mat2v2float %glsl MatrixInverse %m2x2f1
+     OpReturn
+     OpFunctionEnd
+  )";
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions());
+    auto fe = p->function_emitter(100);
+    EXPECT_TRUE(fe.EmitBody()) << p->error();
+    auto ast_body = fe.ast_body();
+    const auto body = test::ToString(p->program(), ast_body);
+
+    std::string expected =
+        "let s = (1.0f / determinant(m2x2f1));\n"
+        "let x_1 : mat2x2<f32> = mat2x2<f32>(vec2<f32>((s * m2x2f1[1u][1u]), (-(s) * "
+        "m2x2f1[0u][1u])), vec2<f32>((-(s) * m2x2f1[1u][0u]), (s * m2x2f1[0u][0u])));\n"
+        "let s_1 = (1.0f / determinant(m2x2f1));\n"
+        "let x_2 : mat2x2<f32> = mat2x2<f32>(vec2<f32>((s_1 * m2x2f1[1u][1u]), (-(s_1) * "
+        "m2x2f1[0u][1u])), vec2<f32>((-(s_1) * m2x2f1[1u][0u]), (s_1 * m2x2f1[0u][0u])));";
+
+    EXPECT_THAT(body, HasSubstr(expected)) << body;
+}
 }  // namespace
 }  // namespace tint::reader::spirv