tint: Fix emitting identity matrix ctor in HLSL

This patch fix the issue of identity matrix constructors in HLSL. This
patch also fix dawn e2e tests for identity matrix constructors and zero
matrix constructors.

Bug: tint:1596, tint:1545
Change-Id: I6c41eb299c1d5f89cf18720611f450abae26d3f4
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/94042
Reviewed-by: Ben Clayton <bclayton@google.com>
Kokoro: Kokoro <noreply+kokoro@google.com>
Commit-Queue: Zhaoming Jiang <zhaoming.jiang@intel.com>
diff --git a/src/tint/writer/hlsl/generator_impl.cc b/src/tint/writer/hlsl/generator_impl.cc
index b9a6675..72e02f0 100644
--- a/src/tint/writer/hlsl/generator_impl.cc
+++ b/src/tint/writer/hlsl/generator_impl.cc
@@ -1110,52 +1110,13 @@
         return EmitZeroValue(out, type);
     }
 
-    if (auto* mat = call->Type()->As<sem::Matrix>()) {
-        if (ctor->Parameters().size() == 1) {
-            // Matrix constructor with single scalar.
-            auto fn = utils::GetOrCreate(matrix_scalar_ctors_, mat, [&]() -> std::string {
-                TextBuffer b;
-                TINT_DEFER(helpers_.Append(b));
-
-                auto name = UniqueIdentifier("build_mat" + std::to_string(mat->columns()) + "x" +
-                                             std::to_string(mat->rows()));
-                {
-                    auto l = line(&b);
-                    if (!EmitType(l, mat, ast::StorageClass::kNone, ast::Access::kUndefined, "")) {
-                        return "";
-                    }
-                    l << " " << name << "(";
-                    if (!EmitType(l, mat->type(), ast::StorageClass::kNone, ast::Access::kUndefined,
-                                  "")) {
-                        return "";
-                    }
-                    l << " value) {";
-                }
-                {
-                    ScopedIndent si(&b);
-                    auto l = line(&b);
-                    l << "return ";
-                    if (!EmitType(l, mat, ast::StorageClass::kNone, ast::Access::kUndefined, "")) {
-                        return "";
-                    }
-                    l << "(";
-                    for (uint32_t i = 0; i < mat->columns() * mat->rows(); i++) {
-                        l << ((i > 0) ? ", value" : "value");
-                    }
-                    l << ");";
-                }
-                line(&b) << "}";
-                return name;
-            });
-            if (fn.empty()) {
-                return false;
-            }
-            out << fn << "(";
-            if (!EmitExpression(out, call->Arguments()[0]->Declaration())) {
-                return false;
-            }
-            out << ")";
-            return true;
+    // Single parameter matrix initializers must be identity constructor.
+    // It could also be conversions between f16 and f32 matrix when f16 is properly supported.
+    if (type->Is<sem::Matrix>() && call->Arguments().size() == 1) {
+        if (!ctor->Parameters()[0]->Type()->UnwrapRef()->is_float_matrix()) {
+            TINT_UNREACHABLE(Writer, diagnostics_)
+                << "found a single-parameter matrix constructor that is not identity constructor";
+            return false;
         }
     }
 
diff --git a/src/tint/writer/hlsl/generator_impl_constructor_test.cc b/src/tint/writer/hlsl/generator_impl_constructor_test.cc
index 700d94b..6a1d696 100644
--- a/src/tint/writer/hlsl/generator_impl_constructor_test.cc
+++ b/src/tint/writer/hlsl/generator_impl_constructor_test.cc
@@ -223,6 +223,24 @@
     EXPECT_THAT(gen.result(), HasSubstr("float2x3 tint_symbol = float2x3((0.0f).xxx, (0.0f).xxx)"));
 }
 
+TEST_F(HlslGeneratorImplTest_Constructor, EmitConstructor_Type_Mat_Identity) {
+    // fn f() {
+    //     var m_1: mat4x4<f32> = mat4x4<f32>();
+    //     var m_2: mat4x4<f32> = mat4x4<f32>(m_1);
+    // }
+
+    auto* m_1 = Var("m_1", ty.mat4x4(ty.f32()), mat4x4<f32>());
+    auto* m_2 = Var("m_2", ty.mat4x4(ty.f32()), mat4x4<f32>(m_1));
+
+    WrapInFunction(m_1, m_2);
+
+    GeneratorImpl& gen = Build();
+
+    ASSERT_TRUE(gen.Generate()) << gen.error();
+
+    EXPECT_THAT(gen.result(), HasSubstr("float4x4 m_2 = float4x4(m_1);"));
+}
+
 TEST_F(HlslGeneratorImplTest_Constructor, EmitConstructor_Type_Array) {
     WrapInFunction(Construct(ty.array(ty.vec3<f32>(), 3_u), vec3<f32>(1_f, 2_f, 3_f),
                              vec3<f32>(4_f, 5_f, 6_f), vec3<f32>(7_f, 8_f, 9_f)));
diff --git a/test/tint/expressions/type_ctor/mat2x2/explicit/identity/f32.wgsl b/test/tint/expressions/type_ctor/mat2x2/explicit/identity/f32.wgsl
index 7d23bcf..3249340 100644
--- a/test/tint/expressions/type_ctor/mat2x2/explicit/identity/f32.wgsl
+++ b/test/tint/expressions/type_ctor/mat2x2/explicit/identity/f32.wgsl
@@ -1 +1,7 @@
-let m = mat2x2<f32>();
+let m = mat2x2(mat2x2<f32>(0.0f, 1.0f,
+                           2.0f, 3.0f));
+
+fn f() -> mat2x2<f32> {
+    let m_1 = mat2x2(m);
+    return m_1;
+}
diff --git a/test/tint/expressions/type_ctor/mat2x2/explicit/identity/f32.wgsl.expected.glsl b/test/tint/expressions/type_ctor/mat2x2/explicit/identity/f32.wgsl.expected.glsl
index a496f95..98b5a53 100644
--- a/test/tint/expressions/type_ctor/mat2x2/explicit/identity/f32.wgsl.expected.glsl
+++ b/test/tint/expressions/type_ctor/mat2x2/explicit/identity/f32.wgsl.expected.glsl
@@ -4,4 +4,9 @@
 void unused_entry_point() {
   return;
 }
-const mat2 m = mat2(vec2(0.0f), vec2(0.0f));
+const mat2 m = mat2(vec2(0.0f, 1.0f), vec2(2.0f, 3.0f));
+mat2 f() {
+  mat2 m_1 = mat2(vec2(0.0f, 1.0f), vec2(2.0f, 3.0f));
+  return mat2(vec2(0.0f, 1.0f), vec2(2.0f, 3.0f));
+}
+
diff --git a/test/tint/expressions/type_ctor/mat2x2/explicit/identity/f32.wgsl.expected.hlsl b/test/tint/expressions/type_ctor/mat2x2/explicit/identity/f32.wgsl.expected.hlsl
index a38b32b..884de04 100644
--- a/test/tint/expressions/type_ctor/mat2x2/explicit/identity/f32.wgsl.expected.hlsl
+++ b/test/tint/expressions/type_ctor/mat2x2/explicit/identity/f32.wgsl.expected.hlsl
@@ -3,4 +3,9 @@
   return;
 }
 
-static const float2x2 m = float2x2((0.0f).xx, (0.0f).xx);
+static const float2x2 m = float2x2(float2(0.0f, 1.0f), float2(2.0f, 3.0f));
+
+float2x2 f() {
+  const float2x2 m_1 = float2x2(float2(0.0f, 1.0f), float2(2.0f, 3.0f));
+  return float2x2(float2(0.0f, 1.0f), float2(2.0f, 3.0f));
+}
diff --git a/test/tint/expressions/type_ctor/mat2x2/explicit/identity/f32.wgsl.expected.msl b/test/tint/expressions/type_ctor/mat2x2/explicit/identity/f32.wgsl.expected.msl
index 9076107..2397b00 100644
--- a/test/tint/expressions/type_ctor/mat2x2/explicit/identity/f32.wgsl.expected.msl
+++ b/test/tint/expressions/type_ctor/mat2x2/explicit/identity/f32.wgsl.expected.msl
@@ -1,5 +1,10 @@
 #include <metal_stdlib>
 
 using namespace metal;
-constant float2x2 m = float2x2(float2(0.0f), float2(0.0f));
+constant float2x2 m = float2x2(float2(0.0f, 1.0f), float2(2.0f, 3.0f));
+
+float2x2 f() {
+  float2x2 const m_1 = float2x2(float2(0.0f, 1.0f), float2(2.0f, 3.0f));
+  return float2x2(float2(0.0f, 1.0f), float2(2.0f, 3.0f));
+}
 
diff --git a/test/tint/expressions/type_ctor/mat2x2/explicit/identity/f32.wgsl.expected.spvasm b/test/tint/expressions/type_ctor/mat2x2/explicit/identity/f32.wgsl.expected.spvasm
index 849d656..8b08148 100644
--- a/test/tint/expressions/type_ctor/mat2x2/explicit/identity/f32.wgsl.expected.spvasm
+++ b/test/tint/expressions/type_ctor/mat2x2/explicit/identity/f32.wgsl.expected.spvasm
@@ -1,7 +1,7 @@
 ; SPIR-V
 ; Version: 1.3
 ; Generator: Google Tint Compiler; 0
-; Bound: 9
+; Bound: 18
 ; Schema: 0
                OpCapability Shader
                OpMemoryModel Logical GLSL450
@@ -9,13 +9,25 @@
                OpExecutionMode %unused_entry_point LocalSize 1 1 1
                OpName %m "m"
                OpName %unused_entry_point "unused_entry_point"
+               OpName %f "f"
       %float = OpTypeFloat 32
     %v2float = OpTypeVector %float 2
 %mat2v2float = OpTypeMatrix %v2float 2
-          %m = OpConstantNull %mat2v2float
+    %float_0 = OpConstant %float 0
+    %float_1 = OpConstant %float 1
+          %6 = OpConstantComposite %v2float %float_0 %float_1
+    %float_2 = OpConstant %float 2
+    %float_3 = OpConstant %float 3
+          %9 = OpConstantComposite %v2float %float_2 %float_3
+          %m = OpConstantComposite %mat2v2float %6 %9
        %void = OpTypeVoid
-          %5 = OpTypeFunction %void
-%unused_entry_point = OpFunction %void None %5
-          %8 = OpLabel
+         %11 = OpTypeFunction %void
+         %15 = OpTypeFunction %mat2v2float
+%unused_entry_point = OpFunction %void None %11
+         %14 = OpLabel
                OpReturn
                OpFunctionEnd
+          %f = OpFunction %mat2v2float None %15
+         %17 = OpLabel
+               OpReturnValue %m
+               OpFunctionEnd
diff --git a/test/tint/expressions/type_ctor/mat2x2/explicit/identity/f32.wgsl.expected.wgsl b/test/tint/expressions/type_ctor/mat2x2/explicit/identity/f32.wgsl.expected.wgsl
index 7d23bcf..27431a6 100644
--- a/test/tint/expressions/type_ctor/mat2x2/explicit/identity/f32.wgsl.expected.wgsl
+++ b/test/tint/expressions/type_ctor/mat2x2/explicit/identity/f32.wgsl.expected.wgsl
@@ -1 +1,6 @@
-let m = mat2x2<f32>();
+let m = mat2x2(mat2x2<f32>(0.0f, 1.0f, 2.0f, 3.0f));
+
+fn f() -> mat2x2<f32> {
+  let m_1 = mat2x2(m);
+  return m_1;
+}
diff --git a/test/tint/expressions/type_ctor/mat2x2/inferred/identity/f32.wgsl b/test/tint/expressions/type_ctor/mat2x2/inferred/identity/f32.wgsl
new file mode 100644
index 0000000..3b4c5e2
--- /dev/null
+++ b/test/tint/expressions/type_ctor/mat2x2/inferred/identity/f32.wgsl
@@ -0,0 +1,7 @@
+let m = mat2x2(mat2x2(0.0f, 1.0f,
+                      2.0f, 3.0f));
+
+fn f() -> mat2x2<f32> {
+    let m_1 = mat2x2(m);
+    return m_1;
+}
diff --git a/test/tint/expressions/type_ctor/mat2x2/inferred/identity/f32.wgsl.expected.glsl b/test/tint/expressions/type_ctor/mat2x2/inferred/identity/f32.wgsl.expected.glsl
new file mode 100644
index 0000000..98b5a53
--- /dev/null
+++ b/test/tint/expressions/type_ctor/mat2x2/inferred/identity/f32.wgsl.expected.glsl
@@ -0,0 +1,12 @@
+#version 310 es
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void unused_entry_point() {
+  return;
+}
+const mat2 m = mat2(vec2(0.0f, 1.0f), vec2(2.0f, 3.0f));
+mat2 f() {
+  mat2 m_1 = mat2(vec2(0.0f, 1.0f), vec2(2.0f, 3.0f));
+  return mat2(vec2(0.0f, 1.0f), vec2(2.0f, 3.0f));
+}
+
diff --git a/test/tint/expressions/type_ctor/mat2x2/inferred/identity/f32.wgsl.expected.hlsl b/test/tint/expressions/type_ctor/mat2x2/inferred/identity/f32.wgsl.expected.hlsl
new file mode 100644
index 0000000..884de04
--- /dev/null
+++ b/test/tint/expressions/type_ctor/mat2x2/inferred/identity/f32.wgsl.expected.hlsl
@@ -0,0 +1,11 @@
+[numthreads(1, 1, 1)]
+void unused_entry_point() {
+  return;
+}
+
+static const float2x2 m = float2x2(float2(0.0f, 1.0f), float2(2.0f, 3.0f));
+
+float2x2 f() {
+  const float2x2 m_1 = float2x2(float2(0.0f, 1.0f), float2(2.0f, 3.0f));
+  return float2x2(float2(0.0f, 1.0f), float2(2.0f, 3.0f));
+}
diff --git a/test/tint/expressions/type_ctor/mat2x2/inferred/identity/f32.wgsl.expected.msl b/test/tint/expressions/type_ctor/mat2x2/inferred/identity/f32.wgsl.expected.msl
new file mode 100644
index 0000000..2397b00
--- /dev/null
+++ b/test/tint/expressions/type_ctor/mat2x2/inferred/identity/f32.wgsl.expected.msl
@@ -0,0 +1,10 @@
+#include <metal_stdlib>
+
+using namespace metal;
+constant float2x2 m = float2x2(float2(0.0f, 1.0f), float2(2.0f, 3.0f));
+
+float2x2 f() {
+  float2x2 const m_1 = float2x2(float2(0.0f, 1.0f), float2(2.0f, 3.0f));
+  return float2x2(float2(0.0f, 1.0f), float2(2.0f, 3.0f));
+}
+
diff --git a/test/tint/expressions/type_ctor/mat2x2/inferred/identity/f32.wgsl.expected.spvasm b/test/tint/expressions/type_ctor/mat2x2/inferred/identity/f32.wgsl.expected.spvasm
new file mode 100644
index 0000000..8b08148
--- /dev/null
+++ b/test/tint/expressions/type_ctor/mat2x2/inferred/identity/f32.wgsl.expected.spvasm
@@ -0,0 +1,33 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 18
+; Schema: 0
+               OpCapability Shader
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %unused_entry_point "unused_entry_point"
+               OpExecutionMode %unused_entry_point LocalSize 1 1 1
+               OpName %m "m"
+               OpName %unused_entry_point "unused_entry_point"
+               OpName %f "f"
+      %float = OpTypeFloat 32
+    %v2float = OpTypeVector %float 2
+%mat2v2float = OpTypeMatrix %v2float 2
+    %float_0 = OpConstant %float 0
+    %float_1 = OpConstant %float 1
+          %6 = OpConstantComposite %v2float %float_0 %float_1
+    %float_2 = OpConstant %float 2
+    %float_3 = OpConstant %float 3
+          %9 = OpConstantComposite %v2float %float_2 %float_3
+          %m = OpConstantComposite %mat2v2float %6 %9
+       %void = OpTypeVoid
+         %11 = OpTypeFunction %void
+         %15 = OpTypeFunction %mat2v2float
+%unused_entry_point = OpFunction %void None %11
+         %14 = OpLabel
+               OpReturn
+               OpFunctionEnd
+          %f = OpFunction %mat2v2float None %15
+         %17 = OpLabel
+               OpReturnValue %m
+               OpFunctionEnd
diff --git a/test/tint/expressions/type_ctor/mat2x2/inferred/identity/f32.wgsl.expected.wgsl b/test/tint/expressions/type_ctor/mat2x2/inferred/identity/f32.wgsl.expected.wgsl
new file mode 100644
index 0000000..cd44a0f
--- /dev/null
+++ b/test/tint/expressions/type_ctor/mat2x2/inferred/identity/f32.wgsl.expected.wgsl
@@ -0,0 +1,6 @@
+let m = mat2x2(mat2x2(0.0f, 1.0f, 2.0f, 3.0f));
+
+fn f() -> mat2x2<f32> {
+  let m_1 = mat2x2(m);
+  return m_1;
+}
diff --git a/test/tint/expressions/type_ctor/mat2x2/zero/f32.wgsl b/test/tint/expressions/type_ctor/mat2x2/zero/f32.wgsl
new file mode 100644
index 0000000..7d23bcf
--- /dev/null
+++ b/test/tint/expressions/type_ctor/mat2x2/zero/f32.wgsl
@@ -0,0 +1 @@
+let m = mat2x2<f32>();
diff --git a/test/tint/expressions/type_ctor/mat2x2/zero/f32.wgsl.expected.glsl b/test/tint/expressions/type_ctor/mat2x2/zero/f32.wgsl.expected.glsl
new file mode 100644
index 0000000..a496f95
--- /dev/null
+++ b/test/tint/expressions/type_ctor/mat2x2/zero/f32.wgsl.expected.glsl
@@ -0,0 +1,7 @@
+#version 310 es
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void unused_entry_point() {
+  return;
+}
+const mat2 m = mat2(vec2(0.0f), vec2(0.0f));
diff --git a/test/tint/expressions/type_ctor/mat2x2/zero/f32.wgsl.expected.hlsl b/test/tint/expressions/type_ctor/mat2x2/zero/f32.wgsl.expected.hlsl
new file mode 100644
index 0000000..a38b32b
--- /dev/null
+++ b/test/tint/expressions/type_ctor/mat2x2/zero/f32.wgsl.expected.hlsl
@@ -0,0 +1,6 @@
+[numthreads(1, 1, 1)]
+void unused_entry_point() {
+  return;
+}
+
+static const float2x2 m = float2x2((0.0f).xx, (0.0f).xx);
diff --git a/test/tint/expressions/type_ctor/mat2x2/zero/f32.wgsl.expected.msl b/test/tint/expressions/type_ctor/mat2x2/zero/f32.wgsl.expected.msl
new file mode 100644
index 0000000..9076107
--- /dev/null
+++ b/test/tint/expressions/type_ctor/mat2x2/zero/f32.wgsl.expected.msl
@@ -0,0 +1,5 @@
+#include <metal_stdlib>
+
+using namespace metal;
+constant float2x2 m = float2x2(float2(0.0f), float2(0.0f));
+
diff --git a/test/tint/expressions/type_ctor/mat2x2/zero/f32.wgsl.expected.spvasm b/test/tint/expressions/type_ctor/mat2x2/zero/f32.wgsl.expected.spvasm
new file mode 100644
index 0000000..849d656
--- /dev/null
+++ b/test/tint/expressions/type_ctor/mat2x2/zero/f32.wgsl.expected.spvasm
@@ -0,0 +1,21 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 9
+; Schema: 0
+               OpCapability Shader
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %unused_entry_point "unused_entry_point"
+               OpExecutionMode %unused_entry_point LocalSize 1 1 1
+               OpName %m "m"
+               OpName %unused_entry_point "unused_entry_point"
+      %float = OpTypeFloat 32
+    %v2float = OpTypeVector %float 2
+%mat2v2float = OpTypeMatrix %v2float 2
+          %m = OpConstantNull %mat2v2float
+       %void = OpTypeVoid
+          %5 = OpTypeFunction %void
+%unused_entry_point = OpFunction %void None %5
+          %8 = OpLabel
+               OpReturn
+               OpFunctionEnd
diff --git a/test/tint/expressions/type_ctor/mat2x2/zero/f32.wgsl.expected.wgsl b/test/tint/expressions/type_ctor/mat2x2/zero/f32.wgsl.expected.wgsl
new file mode 100644
index 0000000..7d23bcf
--- /dev/null
+++ b/test/tint/expressions/type_ctor/mat2x2/zero/f32.wgsl.expected.wgsl
@@ -0,0 +1 @@
+let m = mat2x2<f32>();
diff --git a/test/tint/expressions/type_ctor/mat2x3/explicit/identity/f32.wgsl b/test/tint/expressions/type_ctor/mat2x3/explicit/identity/f32.wgsl
new file mode 100644
index 0000000..dff89c8
--- /dev/null
+++ b/test/tint/expressions/type_ctor/mat2x3/explicit/identity/f32.wgsl
@@ -0,0 +1,7 @@
+let m = mat2x3(mat2x3<f32>(0.0f, 1.0f, 2.0f,
+                           3.0f, 4.0f, 5.0f));
+
+fn f() -> mat2x3<f32> {
+    let m_1 = mat2x3(m);
+    return m_1;
+}
diff --git a/test/tint/expressions/type_ctor/mat2x3/explicit/identity/f32.wgsl.expected.glsl b/test/tint/expressions/type_ctor/mat2x3/explicit/identity/f32.wgsl.expected.glsl
new file mode 100644
index 0000000..b191a03
--- /dev/null
+++ b/test/tint/expressions/type_ctor/mat2x3/explicit/identity/f32.wgsl.expected.glsl
@@ -0,0 +1,12 @@
+#version 310 es
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void unused_entry_point() {
+  return;
+}
+const mat2x3 m = mat2x3(vec3(0.0f, 1.0f, 2.0f), vec3(3.0f, 4.0f, 5.0f));
+mat2x3 f() {
+  mat2x3 m_1 = mat2x3(vec3(0.0f, 1.0f, 2.0f), vec3(3.0f, 4.0f, 5.0f));
+  return mat2x3(vec3(0.0f, 1.0f, 2.0f), vec3(3.0f, 4.0f, 5.0f));
+}
+
diff --git a/test/tint/expressions/type_ctor/mat2x3/explicit/identity/f32.wgsl.expected.hlsl b/test/tint/expressions/type_ctor/mat2x3/explicit/identity/f32.wgsl.expected.hlsl
new file mode 100644
index 0000000..4a428a2
--- /dev/null
+++ b/test/tint/expressions/type_ctor/mat2x3/explicit/identity/f32.wgsl.expected.hlsl
@@ -0,0 +1,11 @@
+[numthreads(1, 1, 1)]
+void unused_entry_point() {
+  return;
+}
+
+static const float2x3 m = float2x3(float3(0.0f, 1.0f, 2.0f), float3(3.0f, 4.0f, 5.0f));
+
+float2x3 f() {
+  const float2x3 m_1 = float2x3(float3(0.0f, 1.0f, 2.0f), float3(3.0f, 4.0f, 5.0f));
+  return float2x3(float3(0.0f, 1.0f, 2.0f), float3(3.0f, 4.0f, 5.0f));
+}
diff --git a/test/tint/expressions/type_ctor/mat2x3/explicit/identity/f32.wgsl.expected.msl b/test/tint/expressions/type_ctor/mat2x3/explicit/identity/f32.wgsl.expected.msl
new file mode 100644
index 0000000..6e9320e
--- /dev/null
+++ b/test/tint/expressions/type_ctor/mat2x3/explicit/identity/f32.wgsl.expected.msl
@@ -0,0 +1,10 @@
+#include <metal_stdlib>
+
+using namespace metal;
+constant float2x3 m = float2x3(float3(0.0f, 1.0f, 2.0f), float3(3.0f, 4.0f, 5.0f));
+
+float2x3 f() {
+  float2x3 const m_1 = float2x3(float3(0.0f, 1.0f, 2.0f), float3(3.0f, 4.0f, 5.0f));
+  return float2x3(float3(0.0f, 1.0f, 2.0f), float3(3.0f, 4.0f, 5.0f));
+}
+
diff --git a/test/tint/expressions/type_ctor/mat2x3/explicit/identity/f32.wgsl.expected.spvasm b/test/tint/expressions/type_ctor/mat2x3/explicit/identity/f32.wgsl.expected.spvasm
new file mode 100644
index 0000000..0cecb54
--- /dev/null
+++ b/test/tint/expressions/type_ctor/mat2x3/explicit/identity/f32.wgsl.expected.spvasm
@@ -0,0 +1,35 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 20
+; Schema: 0
+               OpCapability Shader
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %unused_entry_point "unused_entry_point"
+               OpExecutionMode %unused_entry_point LocalSize 1 1 1
+               OpName %m "m"
+               OpName %unused_entry_point "unused_entry_point"
+               OpName %f "f"
+      %float = OpTypeFloat 32
+    %v3float = OpTypeVector %float 3
+%mat2v3float = OpTypeMatrix %v3float 2
+    %float_0 = OpConstant %float 0
+    %float_1 = OpConstant %float 1
+    %float_2 = OpConstant %float 2
+          %7 = OpConstantComposite %v3float %float_0 %float_1 %float_2
+    %float_3 = OpConstant %float 3
+    %float_4 = OpConstant %float 4
+    %float_5 = OpConstant %float 5
+         %11 = OpConstantComposite %v3float %float_3 %float_4 %float_5
+          %m = OpConstantComposite %mat2v3float %7 %11
+       %void = OpTypeVoid
+         %13 = OpTypeFunction %void
+         %17 = OpTypeFunction %mat2v3float
+%unused_entry_point = OpFunction %void None %13
+         %16 = OpLabel
+               OpReturn
+               OpFunctionEnd
+          %f = OpFunction %mat2v3float None %17
+         %19 = OpLabel
+               OpReturnValue %m
+               OpFunctionEnd
diff --git a/test/tint/expressions/type_ctor/mat2x3/explicit/identity/f32.wgsl.expected.wgsl b/test/tint/expressions/type_ctor/mat2x3/explicit/identity/f32.wgsl.expected.wgsl
new file mode 100644
index 0000000..5c9282f
--- /dev/null
+++ b/test/tint/expressions/type_ctor/mat2x3/explicit/identity/f32.wgsl.expected.wgsl
@@ -0,0 +1,6 @@
+let m = mat2x3(mat2x3<f32>(0.0f, 1.0f, 2.0f, 3.0f, 4.0f, 5.0f));
+
+fn f() -> mat2x3<f32> {
+  let m_1 = mat2x3(m);
+  return m_1;
+}
diff --git a/test/tint/expressions/type_ctor/mat2x3/inferred/identity/f32.wgsl b/test/tint/expressions/type_ctor/mat2x3/inferred/identity/f32.wgsl
new file mode 100644
index 0000000..93c90e7
--- /dev/null
+++ b/test/tint/expressions/type_ctor/mat2x3/inferred/identity/f32.wgsl
@@ -0,0 +1,7 @@
+let m = mat2x3(mat2x3(0.0f, 1.0f, 2.0f,
+                      3.0f, 4.0f, 5.0f));
+
+fn f() -> mat2x3<f32> {
+    let m_1 = mat2x3(m);
+    return m_1;
+}
diff --git a/test/tint/expressions/type_ctor/mat2x3/inferred/identity/f32.wgsl.expected.glsl b/test/tint/expressions/type_ctor/mat2x3/inferred/identity/f32.wgsl.expected.glsl
new file mode 100644
index 0000000..b191a03
--- /dev/null
+++ b/test/tint/expressions/type_ctor/mat2x3/inferred/identity/f32.wgsl.expected.glsl
@@ -0,0 +1,12 @@
+#version 310 es
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void unused_entry_point() {
+  return;
+}
+const mat2x3 m = mat2x3(vec3(0.0f, 1.0f, 2.0f), vec3(3.0f, 4.0f, 5.0f));
+mat2x3 f() {
+  mat2x3 m_1 = mat2x3(vec3(0.0f, 1.0f, 2.0f), vec3(3.0f, 4.0f, 5.0f));
+  return mat2x3(vec3(0.0f, 1.0f, 2.0f), vec3(3.0f, 4.0f, 5.0f));
+}
+
diff --git a/test/tint/expressions/type_ctor/mat2x3/inferred/identity/f32.wgsl.expected.hlsl b/test/tint/expressions/type_ctor/mat2x3/inferred/identity/f32.wgsl.expected.hlsl
new file mode 100644
index 0000000..4a428a2
--- /dev/null
+++ b/test/tint/expressions/type_ctor/mat2x3/inferred/identity/f32.wgsl.expected.hlsl
@@ -0,0 +1,11 @@
+[numthreads(1, 1, 1)]
+void unused_entry_point() {
+  return;
+}
+
+static const float2x3 m = float2x3(float3(0.0f, 1.0f, 2.0f), float3(3.0f, 4.0f, 5.0f));
+
+float2x3 f() {
+  const float2x3 m_1 = float2x3(float3(0.0f, 1.0f, 2.0f), float3(3.0f, 4.0f, 5.0f));
+  return float2x3(float3(0.0f, 1.0f, 2.0f), float3(3.0f, 4.0f, 5.0f));
+}
diff --git a/test/tint/expressions/type_ctor/mat2x3/inferred/identity/f32.wgsl.expected.msl b/test/tint/expressions/type_ctor/mat2x3/inferred/identity/f32.wgsl.expected.msl
new file mode 100644
index 0000000..6e9320e
--- /dev/null
+++ b/test/tint/expressions/type_ctor/mat2x3/inferred/identity/f32.wgsl.expected.msl
@@ -0,0 +1,10 @@
+#include <metal_stdlib>
+
+using namespace metal;
+constant float2x3 m = float2x3(float3(0.0f, 1.0f, 2.0f), float3(3.0f, 4.0f, 5.0f));
+
+float2x3 f() {
+  float2x3 const m_1 = float2x3(float3(0.0f, 1.0f, 2.0f), float3(3.0f, 4.0f, 5.0f));
+  return float2x3(float3(0.0f, 1.0f, 2.0f), float3(3.0f, 4.0f, 5.0f));
+}
+
diff --git a/test/tint/expressions/type_ctor/mat2x3/inferred/identity/f32.wgsl.expected.spvasm b/test/tint/expressions/type_ctor/mat2x3/inferred/identity/f32.wgsl.expected.spvasm
new file mode 100644
index 0000000..0cecb54
--- /dev/null
+++ b/test/tint/expressions/type_ctor/mat2x3/inferred/identity/f32.wgsl.expected.spvasm
@@ -0,0 +1,35 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 20
+; Schema: 0
+               OpCapability Shader
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %unused_entry_point "unused_entry_point"
+               OpExecutionMode %unused_entry_point LocalSize 1 1 1
+               OpName %m "m"
+               OpName %unused_entry_point "unused_entry_point"
+               OpName %f "f"
+      %float = OpTypeFloat 32
+    %v3float = OpTypeVector %float 3
+%mat2v3float = OpTypeMatrix %v3float 2
+    %float_0 = OpConstant %float 0
+    %float_1 = OpConstant %float 1
+    %float_2 = OpConstant %float 2
+          %7 = OpConstantComposite %v3float %float_0 %float_1 %float_2
+    %float_3 = OpConstant %float 3
+    %float_4 = OpConstant %float 4
+    %float_5 = OpConstant %float 5
+         %11 = OpConstantComposite %v3float %float_3 %float_4 %float_5
+          %m = OpConstantComposite %mat2v3float %7 %11
+       %void = OpTypeVoid
+         %13 = OpTypeFunction %void
+         %17 = OpTypeFunction %mat2v3float
+%unused_entry_point = OpFunction %void None %13
+         %16 = OpLabel
+               OpReturn
+               OpFunctionEnd
+          %f = OpFunction %mat2v3float None %17
+         %19 = OpLabel
+               OpReturnValue %m
+               OpFunctionEnd
diff --git a/test/tint/expressions/type_ctor/mat2x3/inferred/identity/f32.wgsl.expected.wgsl b/test/tint/expressions/type_ctor/mat2x3/inferred/identity/f32.wgsl.expected.wgsl
new file mode 100644
index 0000000..f0a3182
--- /dev/null
+++ b/test/tint/expressions/type_ctor/mat2x3/inferred/identity/f32.wgsl.expected.wgsl
@@ -0,0 +1,6 @@
+let m = mat2x3(mat2x3(0.0f, 1.0f, 2.0f, 3.0f, 4.0f, 5.0f));
+
+fn f() -> mat2x3<f32> {
+  let m_1 = mat2x3(m);
+  return m_1;
+}
diff --git a/test/tint/expressions/type_ctor/mat2x3/identity/f32.wgsl b/test/tint/expressions/type_ctor/mat2x3/zero/f32.wgsl
similarity index 100%
rename from test/tint/expressions/type_ctor/mat2x3/identity/f32.wgsl
rename to test/tint/expressions/type_ctor/mat2x3/zero/f32.wgsl
diff --git a/test/tint/expressions/type_ctor/mat2x3/identity/f32.wgsl.expected.glsl b/test/tint/expressions/type_ctor/mat2x3/zero/f32.wgsl.expected.glsl
similarity index 100%
rename from test/tint/expressions/type_ctor/mat2x3/identity/f32.wgsl.expected.glsl
rename to test/tint/expressions/type_ctor/mat2x3/zero/f32.wgsl.expected.glsl
diff --git a/test/tint/expressions/type_ctor/mat2x3/identity/f32.wgsl.expected.hlsl b/test/tint/expressions/type_ctor/mat2x3/zero/f32.wgsl.expected.hlsl
similarity index 100%
rename from test/tint/expressions/type_ctor/mat2x3/identity/f32.wgsl.expected.hlsl
rename to test/tint/expressions/type_ctor/mat2x3/zero/f32.wgsl.expected.hlsl
diff --git a/test/tint/expressions/type_ctor/mat2x3/identity/f32.wgsl.expected.msl b/test/tint/expressions/type_ctor/mat2x3/zero/f32.wgsl.expected.msl
similarity index 100%
rename from test/tint/expressions/type_ctor/mat2x3/identity/f32.wgsl.expected.msl
rename to test/tint/expressions/type_ctor/mat2x3/zero/f32.wgsl.expected.msl
diff --git a/test/tint/expressions/type_ctor/mat2x3/identity/f32.wgsl.expected.spvasm b/test/tint/expressions/type_ctor/mat2x3/zero/f32.wgsl.expected.spvasm
similarity index 100%
rename from test/tint/expressions/type_ctor/mat2x3/identity/f32.wgsl.expected.spvasm
rename to test/tint/expressions/type_ctor/mat2x3/zero/f32.wgsl.expected.spvasm
diff --git a/test/tint/expressions/type_ctor/mat2x3/identity/f32.wgsl.expected.wgsl b/test/tint/expressions/type_ctor/mat2x3/zero/f32.wgsl.expected.wgsl
similarity index 100%
rename from test/tint/expressions/type_ctor/mat2x3/identity/f32.wgsl.expected.wgsl
rename to test/tint/expressions/type_ctor/mat2x3/zero/f32.wgsl.expected.wgsl
diff --git a/test/tint/expressions/type_ctor/mat2x4/explicit/identity/f32.wgsl b/test/tint/expressions/type_ctor/mat2x4/explicit/identity/f32.wgsl
new file mode 100644
index 0000000..3d3f9c2
--- /dev/null
+++ b/test/tint/expressions/type_ctor/mat2x4/explicit/identity/f32.wgsl
@@ -0,0 +1,7 @@
+let m = mat2x4(mat2x4<f32>(0.0f, 1.0f, 2.0f, 3.0f,
+                           4.0f, 5.0f, 6.0f, 7.0f));
+
+fn f() -> mat2x4<f32> {
+    let m_1 = mat2x4(m);
+    return m_1;
+}
diff --git a/test/tint/expressions/type_ctor/mat2x4/explicit/identity/f32.wgsl.expected.glsl b/test/tint/expressions/type_ctor/mat2x4/explicit/identity/f32.wgsl.expected.glsl
new file mode 100644
index 0000000..41253c4
--- /dev/null
+++ b/test/tint/expressions/type_ctor/mat2x4/explicit/identity/f32.wgsl.expected.glsl
@@ -0,0 +1,12 @@
+#version 310 es
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void unused_entry_point() {
+  return;
+}
+const mat2x4 m = mat2x4(vec4(0.0f, 1.0f, 2.0f, 3.0f), vec4(4.0f, 5.0f, 6.0f, 7.0f));
+mat2x4 f() {
+  mat2x4 m_1 = mat2x4(vec4(0.0f, 1.0f, 2.0f, 3.0f), vec4(4.0f, 5.0f, 6.0f, 7.0f));
+  return mat2x4(vec4(0.0f, 1.0f, 2.0f, 3.0f), vec4(4.0f, 5.0f, 6.0f, 7.0f));
+}
+
diff --git a/test/tint/expressions/type_ctor/mat2x4/explicit/identity/f32.wgsl.expected.hlsl b/test/tint/expressions/type_ctor/mat2x4/explicit/identity/f32.wgsl.expected.hlsl
new file mode 100644
index 0000000..32b40f8
--- /dev/null
+++ b/test/tint/expressions/type_ctor/mat2x4/explicit/identity/f32.wgsl.expected.hlsl
@@ -0,0 +1,11 @@
+[numthreads(1, 1, 1)]
+void unused_entry_point() {
+  return;
+}
+
+static const float2x4 m = float2x4(float4(0.0f, 1.0f, 2.0f, 3.0f), float4(4.0f, 5.0f, 6.0f, 7.0f));
+
+float2x4 f() {
+  const float2x4 m_1 = float2x4(float4(0.0f, 1.0f, 2.0f, 3.0f), float4(4.0f, 5.0f, 6.0f, 7.0f));
+  return float2x4(float4(0.0f, 1.0f, 2.0f, 3.0f), float4(4.0f, 5.0f, 6.0f, 7.0f));
+}
diff --git a/test/tint/expressions/type_ctor/mat2x4/explicit/identity/f32.wgsl.expected.msl b/test/tint/expressions/type_ctor/mat2x4/explicit/identity/f32.wgsl.expected.msl
new file mode 100644
index 0000000..d4bd7df
--- /dev/null
+++ b/test/tint/expressions/type_ctor/mat2x4/explicit/identity/f32.wgsl.expected.msl
@@ -0,0 +1,10 @@
+#include <metal_stdlib>
+
+using namespace metal;
+constant float2x4 m = float2x4(float4(0.0f, 1.0f, 2.0f, 3.0f), float4(4.0f, 5.0f, 6.0f, 7.0f));
+
+float2x4 f() {
+  float2x4 const m_1 = float2x4(float4(0.0f, 1.0f, 2.0f, 3.0f), float4(4.0f, 5.0f, 6.0f, 7.0f));
+  return float2x4(float4(0.0f, 1.0f, 2.0f, 3.0f), float4(4.0f, 5.0f, 6.0f, 7.0f));
+}
+
diff --git a/test/tint/expressions/type_ctor/mat2x4/explicit/identity/f32.wgsl.expected.spvasm b/test/tint/expressions/type_ctor/mat2x4/explicit/identity/f32.wgsl.expected.spvasm
new file mode 100644
index 0000000..6766c86
--- /dev/null
+++ b/test/tint/expressions/type_ctor/mat2x4/explicit/identity/f32.wgsl.expected.spvasm
@@ -0,0 +1,37 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 22
+; Schema: 0
+               OpCapability Shader
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %unused_entry_point "unused_entry_point"
+               OpExecutionMode %unused_entry_point LocalSize 1 1 1
+               OpName %m "m"
+               OpName %unused_entry_point "unused_entry_point"
+               OpName %f "f"
+      %float = OpTypeFloat 32
+    %v4float = OpTypeVector %float 4
+%mat2v4float = OpTypeMatrix %v4float 2
+    %float_0 = OpConstant %float 0
+    %float_1 = OpConstant %float 1
+    %float_2 = OpConstant %float 2
+    %float_3 = OpConstant %float 3
+          %8 = OpConstantComposite %v4float %float_0 %float_1 %float_2 %float_3
+    %float_4 = OpConstant %float 4
+    %float_5 = OpConstant %float 5
+    %float_6 = OpConstant %float 6
+    %float_7 = OpConstant %float 7
+         %13 = OpConstantComposite %v4float %float_4 %float_5 %float_6 %float_7
+          %m = OpConstantComposite %mat2v4float %8 %13
+       %void = OpTypeVoid
+         %15 = OpTypeFunction %void
+         %19 = OpTypeFunction %mat2v4float
+%unused_entry_point = OpFunction %void None %15
+         %18 = OpLabel
+               OpReturn
+               OpFunctionEnd
+          %f = OpFunction %mat2v4float None %19
+         %21 = OpLabel
+               OpReturnValue %m
+               OpFunctionEnd
diff --git a/test/tint/expressions/type_ctor/mat2x4/explicit/identity/f32.wgsl.expected.wgsl b/test/tint/expressions/type_ctor/mat2x4/explicit/identity/f32.wgsl.expected.wgsl
new file mode 100644
index 0000000..f31ac21
--- /dev/null
+++ b/test/tint/expressions/type_ctor/mat2x4/explicit/identity/f32.wgsl.expected.wgsl
@@ -0,0 +1,6 @@
+let m = mat2x4(mat2x4<f32>(0.0f, 1.0f, 2.0f, 3.0f, 4.0f, 5.0f, 6.0f, 7.0f));
+
+fn f() -> mat2x4<f32> {
+  let m_1 = mat2x4(m);
+  return m_1;
+}
diff --git a/test/tint/expressions/type_ctor/mat2x4/inferred/identity/f32.wgsl b/test/tint/expressions/type_ctor/mat2x4/inferred/identity/f32.wgsl
new file mode 100644
index 0000000..cc6f3fd
--- /dev/null
+++ b/test/tint/expressions/type_ctor/mat2x4/inferred/identity/f32.wgsl
@@ -0,0 +1,7 @@
+let m = mat2x4(mat2x4(0.0f, 1.0f, 2.0f, 3.0f,
+                      4.0f, 5.0f, 6.0f, 7.0f));
+
+fn f() -> mat2x4<f32> {
+    let m_1 = mat2x4(m);
+    return m_1;
+}
diff --git a/test/tint/expressions/type_ctor/mat2x4/inferred/identity/f32.wgsl.expected.glsl b/test/tint/expressions/type_ctor/mat2x4/inferred/identity/f32.wgsl.expected.glsl
new file mode 100644
index 0000000..41253c4
--- /dev/null
+++ b/test/tint/expressions/type_ctor/mat2x4/inferred/identity/f32.wgsl.expected.glsl
@@ -0,0 +1,12 @@
+#version 310 es
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void unused_entry_point() {
+  return;
+}
+const mat2x4 m = mat2x4(vec4(0.0f, 1.0f, 2.0f, 3.0f), vec4(4.0f, 5.0f, 6.0f, 7.0f));
+mat2x4 f() {
+  mat2x4 m_1 = mat2x4(vec4(0.0f, 1.0f, 2.0f, 3.0f), vec4(4.0f, 5.0f, 6.0f, 7.0f));
+  return mat2x4(vec4(0.0f, 1.0f, 2.0f, 3.0f), vec4(4.0f, 5.0f, 6.0f, 7.0f));
+}
+
diff --git a/test/tint/expressions/type_ctor/mat2x4/inferred/identity/f32.wgsl.expected.hlsl b/test/tint/expressions/type_ctor/mat2x4/inferred/identity/f32.wgsl.expected.hlsl
new file mode 100644
index 0000000..32b40f8
--- /dev/null
+++ b/test/tint/expressions/type_ctor/mat2x4/inferred/identity/f32.wgsl.expected.hlsl
@@ -0,0 +1,11 @@
+[numthreads(1, 1, 1)]
+void unused_entry_point() {
+  return;
+}
+
+static const float2x4 m = float2x4(float4(0.0f, 1.0f, 2.0f, 3.0f), float4(4.0f, 5.0f, 6.0f, 7.0f));
+
+float2x4 f() {
+  const float2x4 m_1 = float2x4(float4(0.0f, 1.0f, 2.0f, 3.0f), float4(4.0f, 5.0f, 6.0f, 7.0f));
+  return float2x4(float4(0.0f, 1.0f, 2.0f, 3.0f), float4(4.0f, 5.0f, 6.0f, 7.0f));
+}
diff --git a/test/tint/expressions/type_ctor/mat2x4/inferred/identity/f32.wgsl.expected.msl b/test/tint/expressions/type_ctor/mat2x4/inferred/identity/f32.wgsl.expected.msl
new file mode 100644
index 0000000..d4bd7df
--- /dev/null
+++ b/test/tint/expressions/type_ctor/mat2x4/inferred/identity/f32.wgsl.expected.msl
@@ -0,0 +1,10 @@
+#include <metal_stdlib>
+
+using namespace metal;
+constant float2x4 m = float2x4(float4(0.0f, 1.0f, 2.0f, 3.0f), float4(4.0f, 5.0f, 6.0f, 7.0f));
+
+float2x4 f() {
+  float2x4 const m_1 = float2x4(float4(0.0f, 1.0f, 2.0f, 3.0f), float4(4.0f, 5.0f, 6.0f, 7.0f));
+  return float2x4(float4(0.0f, 1.0f, 2.0f, 3.0f), float4(4.0f, 5.0f, 6.0f, 7.0f));
+}
+
diff --git a/test/tint/expressions/type_ctor/mat2x4/inferred/identity/f32.wgsl.expected.spvasm b/test/tint/expressions/type_ctor/mat2x4/inferred/identity/f32.wgsl.expected.spvasm
new file mode 100644
index 0000000..6766c86
--- /dev/null
+++ b/test/tint/expressions/type_ctor/mat2x4/inferred/identity/f32.wgsl.expected.spvasm
@@ -0,0 +1,37 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 22
+; Schema: 0
+               OpCapability Shader
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %unused_entry_point "unused_entry_point"
+               OpExecutionMode %unused_entry_point LocalSize 1 1 1
+               OpName %m "m"
+               OpName %unused_entry_point "unused_entry_point"
+               OpName %f "f"
+      %float = OpTypeFloat 32
+    %v4float = OpTypeVector %float 4
+%mat2v4float = OpTypeMatrix %v4float 2
+    %float_0 = OpConstant %float 0
+    %float_1 = OpConstant %float 1
+    %float_2 = OpConstant %float 2
+    %float_3 = OpConstant %float 3
+          %8 = OpConstantComposite %v4float %float_0 %float_1 %float_2 %float_3
+    %float_4 = OpConstant %float 4
+    %float_5 = OpConstant %float 5
+    %float_6 = OpConstant %float 6
+    %float_7 = OpConstant %float 7
+         %13 = OpConstantComposite %v4float %float_4 %float_5 %float_6 %float_7
+          %m = OpConstantComposite %mat2v4float %8 %13
+       %void = OpTypeVoid
+         %15 = OpTypeFunction %void
+         %19 = OpTypeFunction %mat2v4float
+%unused_entry_point = OpFunction %void None %15
+         %18 = OpLabel
+               OpReturn
+               OpFunctionEnd
+          %f = OpFunction %mat2v4float None %19
+         %21 = OpLabel
+               OpReturnValue %m
+               OpFunctionEnd
diff --git a/test/tint/expressions/type_ctor/mat2x4/inferred/identity/f32.wgsl.expected.wgsl b/test/tint/expressions/type_ctor/mat2x4/inferred/identity/f32.wgsl.expected.wgsl
new file mode 100644
index 0000000..644d882
--- /dev/null
+++ b/test/tint/expressions/type_ctor/mat2x4/inferred/identity/f32.wgsl.expected.wgsl
@@ -0,0 +1,6 @@
+let m = mat2x4(mat2x4(0.0f, 1.0f, 2.0f, 3.0f, 4.0f, 5.0f, 6.0f, 7.0f));
+
+fn f() -> mat2x4<f32> {
+  let m_1 = mat2x4(m);
+  return m_1;
+}
diff --git a/test/tint/expressions/type_ctor/mat2x4/identity/f32.wgsl b/test/tint/expressions/type_ctor/mat2x4/zero/f32.wgsl
similarity index 100%
rename from test/tint/expressions/type_ctor/mat2x4/identity/f32.wgsl
rename to test/tint/expressions/type_ctor/mat2x4/zero/f32.wgsl
diff --git a/test/tint/expressions/type_ctor/mat2x4/identity/f32.wgsl.expected.glsl b/test/tint/expressions/type_ctor/mat2x4/zero/f32.wgsl.expected.glsl
similarity index 100%
rename from test/tint/expressions/type_ctor/mat2x4/identity/f32.wgsl.expected.glsl
rename to test/tint/expressions/type_ctor/mat2x4/zero/f32.wgsl.expected.glsl
diff --git a/test/tint/expressions/type_ctor/mat2x4/identity/f32.wgsl.expected.hlsl b/test/tint/expressions/type_ctor/mat2x4/zero/f32.wgsl.expected.hlsl
similarity index 100%
rename from test/tint/expressions/type_ctor/mat2x4/identity/f32.wgsl.expected.hlsl
rename to test/tint/expressions/type_ctor/mat2x4/zero/f32.wgsl.expected.hlsl
diff --git a/test/tint/expressions/type_ctor/mat2x4/identity/f32.wgsl.expected.msl b/test/tint/expressions/type_ctor/mat2x4/zero/f32.wgsl.expected.msl
similarity index 100%
rename from test/tint/expressions/type_ctor/mat2x4/identity/f32.wgsl.expected.msl
rename to test/tint/expressions/type_ctor/mat2x4/zero/f32.wgsl.expected.msl
diff --git a/test/tint/expressions/type_ctor/mat2x4/identity/f32.wgsl.expected.spvasm b/test/tint/expressions/type_ctor/mat2x4/zero/f32.wgsl.expected.spvasm
similarity index 100%
rename from test/tint/expressions/type_ctor/mat2x4/identity/f32.wgsl.expected.spvasm
rename to test/tint/expressions/type_ctor/mat2x4/zero/f32.wgsl.expected.spvasm
diff --git a/test/tint/expressions/type_ctor/mat2x4/identity/f32.wgsl.expected.wgsl b/test/tint/expressions/type_ctor/mat2x4/zero/f32.wgsl.expected.wgsl
similarity index 100%
rename from test/tint/expressions/type_ctor/mat2x4/identity/f32.wgsl.expected.wgsl
rename to test/tint/expressions/type_ctor/mat2x4/zero/f32.wgsl.expected.wgsl
diff --git a/test/tint/expressions/type_ctor/mat3x2/explicit/identity/f32.wgsl b/test/tint/expressions/type_ctor/mat3x2/explicit/identity/f32.wgsl
new file mode 100644
index 0000000..7a14231
--- /dev/null
+++ b/test/tint/expressions/type_ctor/mat3x2/explicit/identity/f32.wgsl
@@ -0,0 +1,8 @@
+let m = mat3x2(mat3x2<f32>(0.0f, 1.0f,
+                           2.0f, 3.0f,
+                           4.0f, 5.0f));
+
+fn f() -> mat3x2<f32> {
+    let m_1 = mat3x2(m);
+    return m_1;
+}
diff --git a/test/tint/expressions/type_ctor/mat3x2/explicit/identity/f32.wgsl.expected.glsl b/test/tint/expressions/type_ctor/mat3x2/explicit/identity/f32.wgsl.expected.glsl
new file mode 100644
index 0000000..49056fe
--- /dev/null
+++ b/test/tint/expressions/type_ctor/mat3x2/explicit/identity/f32.wgsl.expected.glsl
@@ -0,0 +1,12 @@
+#version 310 es
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void unused_entry_point() {
+  return;
+}
+const mat3x2 m = mat3x2(vec2(0.0f, 1.0f), vec2(2.0f, 3.0f), vec2(4.0f, 5.0f));
+mat3x2 f() {
+  mat3x2 m_1 = mat3x2(vec2(0.0f, 1.0f), vec2(2.0f, 3.0f), vec2(4.0f, 5.0f));
+  return mat3x2(vec2(0.0f, 1.0f), vec2(2.0f, 3.0f), vec2(4.0f, 5.0f));
+}
+
diff --git a/test/tint/expressions/type_ctor/mat3x2/explicit/identity/f32.wgsl.expected.hlsl b/test/tint/expressions/type_ctor/mat3x2/explicit/identity/f32.wgsl.expected.hlsl
new file mode 100644
index 0000000..049a998
--- /dev/null
+++ b/test/tint/expressions/type_ctor/mat3x2/explicit/identity/f32.wgsl.expected.hlsl
@@ -0,0 +1,11 @@
+[numthreads(1, 1, 1)]
+void unused_entry_point() {
+  return;
+}
+
+static const float3x2 m = float3x2(float2(0.0f, 1.0f), float2(2.0f, 3.0f), float2(4.0f, 5.0f));
+
+float3x2 f() {
+  const float3x2 m_1 = float3x2(float2(0.0f, 1.0f), float2(2.0f, 3.0f), float2(4.0f, 5.0f));
+  return float3x2(float2(0.0f, 1.0f), float2(2.0f, 3.0f), float2(4.0f, 5.0f));
+}
diff --git a/test/tint/expressions/type_ctor/mat3x2/explicit/identity/f32.wgsl.expected.msl b/test/tint/expressions/type_ctor/mat3x2/explicit/identity/f32.wgsl.expected.msl
new file mode 100644
index 0000000..9e216c8
--- /dev/null
+++ b/test/tint/expressions/type_ctor/mat3x2/explicit/identity/f32.wgsl.expected.msl
@@ -0,0 +1,10 @@
+#include <metal_stdlib>
+
+using namespace metal;
+constant float3x2 m = float3x2(float2(0.0f, 1.0f), float2(2.0f, 3.0f), float2(4.0f, 5.0f));
+
+float3x2 f() {
+  float3x2 const m_1 = float3x2(float2(0.0f, 1.0f), float2(2.0f, 3.0f), float2(4.0f, 5.0f));
+  return float3x2(float2(0.0f, 1.0f), float2(2.0f, 3.0f), float2(4.0f, 5.0f));
+}
+
diff --git a/test/tint/expressions/type_ctor/mat3x2/explicit/identity/f32.wgsl.expected.spvasm b/test/tint/expressions/type_ctor/mat3x2/explicit/identity/f32.wgsl.expected.spvasm
new file mode 100644
index 0000000..6679e29
--- /dev/null
+++ b/test/tint/expressions/type_ctor/mat3x2/explicit/identity/f32.wgsl.expected.spvasm
@@ -0,0 +1,36 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 21
+; Schema: 0
+               OpCapability Shader
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %unused_entry_point "unused_entry_point"
+               OpExecutionMode %unused_entry_point LocalSize 1 1 1
+               OpName %m "m"
+               OpName %unused_entry_point "unused_entry_point"
+               OpName %f "f"
+      %float = OpTypeFloat 32
+    %v2float = OpTypeVector %float 2
+%mat3v2float = OpTypeMatrix %v2float 3
+    %float_0 = OpConstant %float 0
+    %float_1 = OpConstant %float 1
+          %6 = OpConstantComposite %v2float %float_0 %float_1
+    %float_2 = OpConstant %float 2
+    %float_3 = OpConstant %float 3
+          %9 = OpConstantComposite %v2float %float_2 %float_3
+    %float_4 = OpConstant %float 4
+    %float_5 = OpConstant %float 5
+         %12 = OpConstantComposite %v2float %float_4 %float_5
+          %m = OpConstantComposite %mat3v2float %6 %9 %12
+       %void = OpTypeVoid
+         %14 = OpTypeFunction %void
+         %18 = OpTypeFunction %mat3v2float
+%unused_entry_point = OpFunction %void None %14
+         %17 = OpLabel
+               OpReturn
+               OpFunctionEnd
+          %f = OpFunction %mat3v2float None %18
+         %20 = OpLabel
+               OpReturnValue %m
+               OpFunctionEnd
diff --git a/test/tint/expressions/type_ctor/mat3x2/explicit/identity/f32.wgsl.expected.wgsl b/test/tint/expressions/type_ctor/mat3x2/explicit/identity/f32.wgsl.expected.wgsl
new file mode 100644
index 0000000..06f3edf
--- /dev/null
+++ b/test/tint/expressions/type_ctor/mat3x2/explicit/identity/f32.wgsl.expected.wgsl
@@ -0,0 +1,6 @@
+let m = mat3x2(mat3x2<f32>(0.0f, 1.0f, 2.0f, 3.0f, 4.0f, 5.0f));
+
+fn f() -> mat3x2<f32> {
+  let m_1 = mat3x2(m);
+  return m_1;
+}
diff --git a/test/tint/expressions/type_ctor/mat3x2/inferred/identity/f32.wgsl b/test/tint/expressions/type_ctor/mat3x2/inferred/identity/f32.wgsl
new file mode 100644
index 0000000..d77e83b
--- /dev/null
+++ b/test/tint/expressions/type_ctor/mat3x2/inferred/identity/f32.wgsl
@@ -0,0 +1,8 @@
+let m = mat3x2(mat3x2(0.0f, 1.0f,
+                      2.0f, 3.0f,
+                      4.0f, 5.0f));
+
+fn f() -> mat3x2<f32> {
+    let m_1 = mat3x2(m);
+    return m_1;
+}
diff --git a/test/tint/expressions/type_ctor/mat3x2/inferred/identity/f32.wgsl.expected.glsl b/test/tint/expressions/type_ctor/mat3x2/inferred/identity/f32.wgsl.expected.glsl
new file mode 100644
index 0000000..49056fe
--- /dev/null
+++ b/test/tint/expressions/type_ctor/mat3x2/inferred/identity/f32.wgsl.expected.glsl
@@ -0,0 +1,12 @@
+#version 310 es
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void unused_entry_point() {
+  return;
+}
+const mat3x2 m = mat3x2(vec2(0.0f, 1.0f), vec2(2.0f, 3.0f), vec2(4.0f, 5.0f));
+mat3x2 f() {
+  mat3x2 m_1 = mat3x2(vec2(0.0f, 1.0f), vec2(2.0f, 3.0f), vec2(4.0f, 5.0f));
+  return mat3x2(vec2(0.0f, 1.0f), vec2(2.0f, 3.0f), vec2(4.0f, 5.0f));
+}
+
diff --git a/test/tint/expressions/type_ctor/mat3x2/inferred/identity/f32.wgsl.expected.hlsl b/test/tint/expressions/type_ctor/mat3x2/inferred/identity/f32.wgsl.expected.hlsl
new file mode 100644
index 0000000..049a998
--- /dev/null
+++ b/test/tint/expressions/type_ctor/mat3x2/inferred/identity/f32.wgsl.expected.hlsl
@@ -0,0 +1,11 @@
+[numthreads(1, 1, 1)]
+void unused_entry_point() {
+  return;
+}
+
+static const float3x2 m = float3x2(float2(0.0f, 1.0f), float2(2.0f, 3.0f), float2(4.0f, 5.0f));
+
+float3x2 f() {
+  const float3x2 m_1 = float3x2(float2(0.0f, 1.0f), float2(2.0f, 3.0f), float2(4.0f, 5.0f));
+  return float3x2(float2(0.0f, 1.0f), float2(2.0f, 3.0f), float2(4.0f, 5.0f));
+}
diff --git a/test/tint/expressions/type_ctor/mat3x2/inferred/identity/f32.wgsl.expected.msl b/test/tint/expressions/type_ctor/mat3x2/inferred/identity/f32.wgsl.expected.msl
new file mode 100644
index 0000000..9e216c8
--- /dev/null
+++ b/test/tint/expressions/type_ctor/mat3x2/inferred/identity/f32.wgsl.expected.msl
@@ -0,0 +1,10 @@
+#include <metal_stdlib>
+
+using namespace metal;
+constant float3x2 m = float3x2(float2(0.0f, 1.0f), float2(2.0f, 3.0f), float2(4.0f, 5.0f));
+
+float3x2 f() {
+  float3x2 const m_1 = float3x2(float2(0.0f, 1.0f), float2(2.0f, 3.0f), float2(4.0f, 5.0f));
+  return float3x2(float2(0.0f, 1.0f), float2(2.0f, 3.0f), float2(4.0f, 5.0f));
+}
+
diff --git a/test/tint/expressions/type_ctor/mat3x2/inferred/identity/f32.wgsl.expected.spvasm b/test/tint/expressions/type_ctor/mat3x2/inferred/identity/f32.wgsl.expected.spvasm
new file mode 100644
index 0000000..6679e29
--- /dev/null
+++ b/test/tint/expressions/type_ctor/mat3x2/inferred/identity/f32.wgsl.expected.spvasm
@@ -0,0 +1,36 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 21
+; Schema: 0
+               OpCapability Shader
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %unused_entry_point "unused_entry_point"
+               OpExecutionMode %unused_entry_point LocalSize 1 1 1
+               OpName %m "m"
+               OpName %unused_entry_point "unused_entry_point"
+               OpName %f "f"
+      %float = OpTypeFloat 32
+    %v2float = OpTypeVector %float 2
+%mat3v2float = OpTypeMatrix %v2float 3
+    %float_0 = OpConstant %float 0
+    %float_1 = OpConstant %float 1
+          %6 = OpConstantComposite %v2float %float_0 %float_1
+    %float_2 = OpConstant %float 2
+    %float_3 = OpConstant %float 3
+          %9 = OpConstantComposite %v2float %float_2 %float_3
+    %float_4 = OpConstant %float 4
+    %float_5 = OpConstant %float 5
+         %12 = OpConstantComposite %v2float %float_4 %float_5
+          %m = OpConstantComposite %mat3v2float %6 %9 %12
+       %void = OpTypeVoid
+         %14 = OpTypeFunction %void
+         %18 = OpTypeFunction %mat3v2float
+%unused_entry_point = OpFunction %void None %14
+         %17 = OpLabel
+               OpReturn
+               OpFunctionEnd
+          %f = OpFunction %mat3v2float None %18
+         %20 = OpLabel
+               OpReturnValue %m
+               OpFunctionEnd
diff --git a/test/tint/expressions/type_ctor/mat3x2/inferred/identity/f32.wgsl.expected.wgsl b/test/tint/expressions/type_ctor/mat3x2/inferred/identity/f32.wgsl.expected.wgsl
new file mode 100644
index 0000000..e16eab4
--- /dev/null
+++ b/test/tint/expressions/type_ctor/mat3x2/inferred/identity/f32.wgsl.expected.wgsl
@@ -0,0 +1,6 @@
+let m = mat3x2(mat3x2(0.0f, 1.0f, 2.0f, 3.0f, 4.0f, 5.0f));
+
+fn f() -> mat3x2<f32> {
+  let m_1 = mat3x2(m);
+  return m_1;
+}
diff --git a/test/tint/expressions/type_ctor/mat3x2/identity/f32.wgsl b/test/tint/expressions/type_ctor/mat3x2/zero/f32.wgsl
similarity index 100%
rename from test/tint/expressions/type_ctor/mat3x2/identity/f32.wgsl
rename to test/tint/expressions/type_ctor/mat3x2/zero/f32.wgsl
diff --git a/test/tint/expressions/type_ctor/mat3x2/identity/f32.wgsl.expected.glsl b/test/tint/expressions/type_ctor/mat3x2/zero/f32.wgsl.expected.glsl
similarity index 100%
rename from test/tint/expressions/type_ctor/mat3x2/identity/f32.wgsl.expected.glsl
rename to test/tint/expressions/type_ctor/mat3x2/zero/f32.wgsl.expected.glsl
diff --git a/test/tint/expressions/type_ctor/mat3x2/identity/f32.wgsl.expected.hlsl b/test/tint/expressions/type_ctor/mat3x2/zero/f32.wgsl.expected.hlsl
similarity index 100%
rename from test/tint/expressions/type_ctor/mat3x2/identity/f32.wgsl.expected.hlsl
rename to test/tint/expressions/type_ctor/mat3x2/zero/f32.wgsl.expected.hlsl
diff --git a/test/tint/expressions/type_ctor/mat3x2/identity/f32.wgsl.expected.msl b/test/tint/expressions/type_ctor/mat3x2/zero/f32.wgsl.expected.msl
similarity index 100%
rename from test/tint/expressions/type_ctor/mat3x2/identity/f32.wgsl.expected.msl
rename to test/tint/expressions/type_ctor/mat3x2/zero/f32.wgsl.expected.msl
diff --git a/test/tint/expressions/type_ctor/mat3x2/identity/f32.wgsl.expected.spvasm b/test/tint/expressions/type_ctor/mat3x2/zero/f32.wgsl.expected.spvasm
similarity index 100%
rename from test/tint/expressions/type_ctor/mat3x2/identity/f32.wgsl.expected.spvasm
rename to test/tint/expressions/type_ctor/mat3x2/zero/f32.wgsl.expected.spvasm
diff --git a/test/tint/expressions/type_ctor/mat3x2/identity/f32.wgsl.expected.wgsl b/test/tint/expressions/type_ctor/mat3x2/zero/f32.wgsl.expected.wgsl
similarity index 100%
rename from test/tint/expressions/type_ctor/mat3x2/identity/f32.wgsl.expected.wgsl
rename to test/tint/expressions/type_ctor/mat3x2/zero/f32.wgsl.expected.wgsl
diff --git a/test/tint/expressions/type_ctor/mat3x3/explicit/identity/f32.wgsl b/test/tint/expressions/type_ctor/mat3x3/explicit/identity/f32.wgsl
new file mode 100644
index 0000000..9f57499
--- /dev/null
+++ b/test/tint/expressions/type_ctor/mat3x3/explicit/identity/f32.wgsl
@@ -0,0 +1,8 @@
+let m = mat3x3(mat3x3<f32>(0.0f, 1.0f, 2.0f,
+                           3.0f, 4.0f, 5.0f,
+                           6.0f, 7.0f, 8.0f));
+
+fn f() -> mat3x3<f32> {
+    let m_1 = mat3x3(m);
+    return m_1;
+}
diff --git a/test/tint/expressions/type_ctor/mat3x3/explicit/identity/f32.wgsl.expected.glsl b/test/tint/expressions/type_ctor/mat3x3/explicit/identity/f32.wgsl.expected.glsl
new file mode 100644
index 0000000..e99ac3c
--- /dev/null
+++ b/test/tint/expressions/type_ctor/mat3x3/explicit/identity/f32.wgsl.expected.glsl
@@ -0,0 +1,12 @@
+#version 310 es
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void unused_entry_point() {
+  return;
+}
+const mat3 m = mat3(vec3(0.0f, 1.0f, 2.0f), vec3(3.0f, 4.0f, 5.0f), vec3(6.0f, 7.0f, 8.0f));
+mat3 f() {
+  mat3 m_1 = mat3(vec3(0.0f, 1.0f, 2.0f), vec3(3.0f, 4.0f, 5.0f), vec3(6.0f, 7.0f, 8.0f));
+  return mat3(vec3(0.0f, 1.0f, 2.0f), vec3(3.0f, 4.0f, 5.0f), vec3(6.0f, 7.0f, 8.0f));
+}
+
diff --git a/test/tint/expressions/type_ctor/mat3x3/explicit/identity/f32.wgsl.expected.hlsl b/test/tint/expressions/type_ctor/mat3x3/explicit/identity/f32.wgsl.expected.hlsl
new file mode 100644
index 0000000..63eef11
--- /dev/null
+++ b/test/tint/expressions/type_ctor/mat3x3/explicit/identity/f32.wgsl.expected.hlsl
@@ -0,0 +1,11 @@
+[numthreads(1, 1, 1)]
+void unused_entry_point() {
+  return;
+}
+
+static const float3x3 m = float3x3(float3(0.0f, 1.0f, 2.0f), float3(3.0f, 4.0f, 5.0f), float3(6.0f, 7.0f, 8.0f));
+
+float3x3 f() {
+  const float3x3 m_1 = float3x3(float3(0.0f, 1.0f, 2.0f), float3(3.0f, 4.0f, 5.0f), float3(6.0f, 7.0f, 8.0f));
+  return float3x3(float3(0.0f, 1.0f, 2.0f), float3(3.0f, 4.0f, 5.0f), float3(6.0f, 7.0f, 8.0f));
+}
diff --git a/test/tint/expressions/type_ctor/mat3x3/explicit/identity/f32.wgsl.expected.msl b/test/tint/expressions/type_ctor/mat3x3/explicit/identity/f32.wgsl.expected.msl
new file mode 100644
index 0000000..d2eac15
--- /dev/null
+++ b/test/tint/expressions/type_ctor/mat3x3/explicit/identity/f32.wgsl.expected.msl
@@ -0,0 +1,10 @@
+#include <metal_stdlib>
+
+using namespace metal;
+constant float3x3 m = float3x3(float3(0.0f, 1.0f, 2.0f), float3(3.0f, 4.0f, 5.0f), float3(6.0f, 7.0f, 8.0f));
+
+float3x3 f() {
+  float3x3 const m_1 = float3x3(float3(0.0f, 1.0f, 2.0f), float3(3.0f, 4.0f, 5.0f), float3(6.0f, 7.0f, 8.0f));
+  return float3x3(float3(0.0f, 1.0f, 2.0f), float3(3.0f, 4.0f, 5.0f), float3(6.0f, 7.0f, 8.0f));
+}
+
diff --git a/test/tint/expressions/type_ctor/mat3x3/explicit/identity/f32.wgsl.expected.spvasm b/test/tint/expressions/type_ctor/mat3x3/explicit/identity/f32.wgsl.expected.spvasm
new file mode 100644
index 0000000..0386f4e
--- /dev/null
+++ b/test/tint/expressions/type_ctor/mat3x3/explicit/identity/f32.wgsl.expected.spvasm
@@ -0,0 +1,39 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 24
+; Schema: 0
+               OpCapability Shader
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %unused_entry_point "unused_entry_point"
+               OpExecutionMode %unused_entry_point LocalSize 1 1 1
+               OpName %m "m"
+               OpName %unused_entry_point "unused_entry_point"
+               OpName %f "f"
+      %float = OpTypeFloat 32
+    %v3float = OpTypeVector %float 3
+%mat3v3float = OpTypeMatrix %v3float 3
+    %float_0 = OpConstant %float 0
+    %float_1 = OpConstant %float 1
+    %float_2 = OpConstant %float 2
+          %7 = OpConstantComposite %v3float %float_0 %float_1 %float_2
+    %float_3 = OpConstant %float 3
+    %float_4 = OpConstant %float 4
+    %float_5 = OpConstant %float 5
+         %11 = OpConstantComposite %v3float %float_3 %float_4 %float_5
+    %float_6 = OpConstant %float 6
+    %float_7 = OpConstant %float 7
+    %float_8 = OpConstant %float 8
+         %15 = OpConstantComposite %v3float %float_6 %float_7 %float_8
+          %m = OpConstantComposite %mat3v3float %7 %11 %15
+       %void = OpTypeVoid
+         %17 = OpTypeFunction %void
+         %21 = OpTypeFunction %mat3v3float
+%unused_entry_point = OpFunction %void None %17
+         %20 = OpLabel
+               OpReturn
+               OpFunctionEnd
+          %f = OpFunction %mat3v3float None %21
+         %23 = OpLabel
+               OpReturnValue %m
+               OpFunctionEnd
diff --git a/test/tint/expressions/type_ctor/mat3x3/explicit/identity/f32.wgsl.expected.wgsl b/test/tint/expressions/type_ctor/mat3x3/explicit/identity/f32.wgsl.expected.wgsl
new file mode 100644
index 0000000..4ed58da
--- /dev/null
+++ b/test/tint/expressions/type_ctor/mat3x3/explicit/identity/f32.wgsl.expected.wgsl
@@ -0,0 +1,6 @@
+let m = mat3x3(mat3x3<f32>(0.0f, 1.0f, 2.0f, 3.0f, 4.0f, 5.0f, 6.0f, 7.0f, 8.0f));
+
+fn f() -> mat3x3<f32> {
+  let m_1 = mat3x3(m);
+  return m_1;
+}
diff --git a/test/tint/expressions/type_ctor/mat3x3/inferred/identity/f32.wgsl b/test/tint/expressions/type_ctor/mat3x3/inferred/identity/f32.wgsl
new file mode 100644
index 0000000..d1792d1
--- /dev/null
+++ b/test/tint/expressions/type_ctor/mat3x3/inferred/identity/f32.wgsl
@@ -0,0 +1,8 @@
+let m = mat3x3(mat3x3(0.0f, 1.0f, 2.0f,
+                      3.0f, 4.0f, 5.0f,
+                      6.0f, 7.0f, 8.0f));
+
+fn f() -> mat3x3<f32> {
+    let m_1 = mat3x3(m);
+    return m_1;
+}
diff --git a/test/tint/expressions/type_ctor/mat3x3/inferred/identity/f32.wgsl.expected.glsl b/test/tint/expressions/type_ctor/mat3x3/inferred/identity/f32.wgsl.expected.glsl
new file mode 100644
index 0000000..e99ac3c
--- /dev/null
+++ b/test/tint/expressions/type_ctor/mat3x3/inferred/identity/f32.wgsl.expected.glsl
@@ -0,0 +1,12 @@
+#version 310 es
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void unused_entry_point() {
+  return;
+}
+const mat3 m = mat3(vec3(0.0f, 1.0f, 2.0f), vec3(3.0f, 4.0f, 5.0f), vec3(6.0f, 7.0f, 8.0f));
+mat3 f() {
+  mat3 m_1 = mat3(vec3(0.0f, 1.0f, 2.0f), vec3(3.0f, 4.0f, 5.0f), vec3(6.0f, 7.0f, 8.0f));
+  return mat3(vec3(0.0f, 1.0f, 2.0f), vec3(3.0f, 4.0f, 5.0f), vec3(6.0f, 7.0f, 8.0f));
+}
+
diff --git a/test/tint/expressions/type_ctor/mat3x3/inferred/identity/f32.wgsl.expected.hlsl b/test/tint/expressions/type_ctor/mat3x3/inferred/identity/f32.wgsl.expected.hlsl
new file mode 100644
index 0000000..63eef11
--- /dev/null
+++ b/test/tint/expressions/type_ctor/mat3x3/inferred/identity/f32.wgsl.expected.hlsl
@@ -0,0 +1,11 @@
+[numthreads(1, 1, 1)]
+void unused_entry_point() {
+  return;
+}
+
+static const float3x3 m = float3x3(float3(0.0f, 1.0f, 2.0f), float3(3.0f, 4.0f, 5.0f), float3(6.0f, 7.0f, 8.0f));
+
+float3x3 f() {
+  const float3x3 m_1 = float3x3(float3(0.0f, 1.0f, 2.0f), float3(3.0f, 4.0f, 5.0f), float3(6.0f, 7.0f, 8.0f));
+  return float3x3(float3(0.0f, 1.0f, 2.0f), float3(3.0f, 4.0f, 5.0f), float3(6.0f, 7.0f, 8.0f));
+}
diff --git a/test/tint/expressions/type_ctor/mat3x3/inferred/identity/f32.wgsl.expected.msl b/test/tint/expressions/type_ctor/mat3x3/inferred/identity/f32.wgsl.expected.msl
new file mode 100644
index 0000000..d2eac15
--- /dev/null
+++ b/test/tint/expressions/type_ctor/mat3x3/inferred/identity/f32.wgsl.expected.msl
@@ -0,0 +1,10 @@
+#include <metal_stdlib>
+
+using namespace metal;
+constant float3x3 m = float3x3(float3(0.0f, 1.0f, 2.0f), float3(3.0f, 4.0f, 5.0f), float3(6.0f, 7.0f, 8.0f));
+
+float3x3 f() {
+  float3x3 const m_1 = float3x3(float3(0.0f, 1.0f, 2.0f), float3(3.0f, 4.0f, 5.0f), float3(6.0f, 7.0f, 8.0f));
+  return float3x3(float3(0.0f, 1.0f, 2.0f), float3(3.0f, 4.0f, 5.0f), float3(6.0f, 7.0f, 8.0f));
+}
+
diff --git a/test/tint/expressions/type_ctor/mat3x3/inferred/identity/f32.wgsl.expected.spvasm b/test/tint/expressions/type_ctor/mat3x3/inferred/identity/f32.wgsl.expected.spvasm
new file mode 100644
index 0000000..0386f4e
--- /dev/null
+++ b/test/tint/expressions/type_ctor/mat3x3/inferred/identity/f32.wgsl.expected.spvasm
@@ -0,0 +1,39 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 24
+; Schema: 0
+               OpCapability Shader
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %unused_entry_point "unused_entry_point"
+               OpExecutionMode %unused_entry_point LocalSize 1 1 1
+               OpName %m "m"
+               OpName %unused_entry_point "unused_entry_point"
+               OpName %f "f"
+      %float = OpTypeFloat 32
+    %v3float = OpTypeVector %float 3
+%mat3v3float = OpTypeMatrix %v3float 3
+    %float_0 = OpConstant %float 0
+    %float_1 = OpConstant %float 1
+    %float_2 = OpConstant %float 2
+          %7 = OpConstantComposite %v3float %float_0 %float_1 %float_2
+    %float_3 = OpConstant %float 3
+    %float_4 = OpConstant %float 4
+    %float_5 = OpConstant %float 5
+         %11 = OpConstantComposite %v3float %float_3 %float_4 %float_5
+    %float_6 = OpConstant %float 6
+    %float_7 = OpConstant %float 7
+    %float_8 = OpConstant %float 8
+         %15 = OpConstantComposite %v3float %float_6 %float_7 %float_8
+          %m = OpConstantComposite %mat3v3float %7 %11 %15
+       %void = OpTypeVoid
+         %17 = OpTypeFunction %void
+         %21 = OpTypeFunction %mat3v3float
+%unused_entry_point = OpFunction %void None %17
+         %20 = OpLabel
+               OpReturn
+               OpFunctionEnd
+          %f = OpFunction %mat3v3float None %21
+         %23 = OpLabel
+               OpReturnValue %m
+               OpFunctionEnd
diff --git a/test/tint/expressions/type_ctor/mat3x3/inferred/identity/f32.wgsl.expected.wgsl b/test/tint/expressions/type_ctor/mat3x3/inferred/identity/f32.wgsl.expected.wgsl
new file mode 100644
index 0000000..6bf1918
--- /dev/null
+++ b/test/tint/expressions/type_ctor/mat3x3/inferred/identity/f32.wgsl.expected.wgsl
@@ -0,0 +1,6 @@
+let m = mat3x3(mat3x3(0.0f, 1.0f, 2.0f, 3.0f, 4.0f, 5.0f, 6.0f, 7.0f, 8.0f));
+
+fn f() -> mat3x3<f32> {
+  let m_1 = mat3x3(m);
+  return m_1;
+}
diff --git a/test/tint/expressions/type_ctor/mat3x3/identity/f32.wgsl b/test/tint/expressions/type_ctor/mat3x3/zero/f32.wgsl
similarity index 100%
rename from test/tint/expressions/type_ctor/mat3x3/identity/f32.wgsl
rename to test/tint/expressions/type_ctor/mat3x3/zero/f32.wgsl
diff --git a/test/tint/expressions/type_ctor/mat3x3/identity/f32.wgsl.expected.glsl b/test/tint/expressions/type_ctor/mat3x3/zero/f32.wgsl.expected.glsl
similarity index 100%
rename from test/tint/expressions/type_ctor/mat3x3/identity/f32.wgsl.expected.glsl
rename to test/tint/expressions/type_ctor/mat3x3/zero/f32.wgsl.expected.glsl
diff --git a/test/tint/expressions/type_ctor/mat3x3/identity/f32.wgsl.expected.hlsl b/test/tint/expressions/type_ctor/mat3x3/zero/f32.wgsl.expected.hlsl
similarity index 100%
rename from test/tint/expressions/type_ctor/mat3x3/identity/f32.wgsl.expected.hlsl
rename to test/tint/expressions/type_ctor/mat3x3/zero/f32.wgsl.expected.hlsl
diff --git a/test/tint/expressions/type_ctor/mat3x3/identity/f32.wgsl.expected.msl b/test/tint/expressions/type_ctor/mat3x3/zero/f32.wgsl.expected.msl
similarity index 100%
rename from test/tint/expressions/type_ctor/mat3x3/identity/f32.wgsl.expected.msl
rename to test/tint/expressions/type_ctor/mat3x3/zero/f32.wgsl.expected.msl
diff --git a/test/tint/expressions/type_ctor/mat3x3/identity/f32.wgsl.expected.spvasm b/test/tint/expressions/type_ctor/mat3x3/zero/f32.wgsl.expected.spvasm
similarity index 100%
rename from test/tint/expressions/type_ctor/mat3x3/identity/f32.wgsl.expected.spvasm
rename to test/tint/expressions/type_ctor/mat3x3/zero/f32.wgsl.expected.spvasm
diff --git a/test/tint/expressions/type_ctor/mat3x3/identity/f32.wgsl.expected.wgsl b/test/tint/expressions/type_ctor/mat3x3/zero/f32.wgsl.expected.wgsl
similarity index 100%
rename from test/tint/expressions/type_ctor/mat3x3/identity/f32.wgsl.expected.wgsl
rename to test/tint/expressions/type_ctor/mat3x3/zero/f32.wgsl.expected.wgsl
diff --git a/test/tint/expressions/type_ctor/mat3x4/explicit/identity/f32.wgsl b/test/tint/expressions/type_ctor/mat3x4/explicit/identity/f32.wgsl
new file mode 100644
index 0000000..823be66
--- /dev/null
+++ b/test/tint/expressions/type_ctor/mat3x4/explicit/identity/f32.wgsl
@@ -0,0 +1,8 @@
+let m = mat3x4(mat3x4<f32>(0.0f, 1.0f, 2.0f, 3.0f,
+                           4.0f, 5.0f, 6.0f, 7.0f,
+                           8.0f, 9.0f, 10.0f, 11.0f));
+
+fn f() -> mat3x4<f32> {
+    let m_1 = mat3x4(m);
+    return m_1;
+}
diff --git a/test/tint/expressions/type_ctor/mat3x4/explicit/identity/f32.wgsl.expected.glsl b/test/tint/expressions/type_ctor/mat3x4/explicit/identity/f32.wgsl.expected.glsl
new file mode 100644
index 0000000..075d29b
--- /dev/null
+++ b/test/tint/expressions/type_ctor/mat3x4/explicit/identity/f32.wgsl.expected.glsl
@@ -0,0 +1,12 @@
+#version 310 es
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void unused_entry_point() {
+  return;
+}
+const mat3x4 m = mat3x4(vec4(0.0f, 1.0f, 2.0f, 3.0f), vec4(4.0f, 5.0f, 6.0f, 7.0f), vec4(8.0f, 9.0f, 10.0f, 11.0f));
+mat3x4 f() {
+  mat3x4 m_1 = mat3x4(vec4(0.0f, 1.0f, 2.0f, 3.0f), vec4(4.0f, 5.0f, 6.0f, 7.0f), vec4(8.0f, 9.0f, 10.0f, 11.0f));
+  return mat3x4(vec4(0.0f, 1.0f, 2.0f, 3.0f), vec4(4.0f, 5.0f, 6.0f, 7.0f), vec4(8.0f, 9.0f, 10.0f, 11.0f));
+}
+
diff --git a/test/tint/expressions/type_ctor/mat3x4/explicit/identity/f32.wgsl.expected.hlsl b/test/tint/expressions/type_ctor/mat3x4/explicit/identity/f32.wgsl.expected.hlsl
new file mode 100644
index 0000000..de62d39
--- /dev/null
+++ b/test/tint/expressions/type_ctor/mat3x4/explicit/identity/f32.wgsl.expected.hlsl
@@ -0,0 +1,11 @@
+[numthreads(1, 1, 1)]
+void unused_entry_point() {
+  return;
+}
+
+static const float3x4 m = float3x4(float4(0.0f, 1.0f, 2.0f, 3.0f), float4(4.0f, 5.0f, 6.0f, 7.0f), float4(8.0f, 9.0f, 10.0f, 11.0f));
+
+float3x4 f() {
+  const float3x4 m_1 = float3x4(float4(0.0f, 1.0f, 2.0f, 3.0f), float4(4.0f, 5.0f, 6.0f, 7.0f), float4(8.0f, 9.0f, 10.0f, 11.0f));
+  return float3x4(float4(0.0f, 1.0f, 2.0f, 3.0f), float4(4.0f, 5.0f, 6.0f, 7.0f), float4(8.0f, 9.0f, 10.0f, 11.0f));
+}
diff --git a/test/tint/expressions/type_ctor/mat3x4/explicit/identity/f32.wgsl.expected.msl b/test/tint/expressions/type_ctor/mat3x4/explicit/identity/f32.wgsl.expected.msl
new file mode 100644
index 0000000..86e4c2e
--- /dev/null
+++ b/test/tint/expressions/type_ctor/mat3x4/explicit/identity/f32.wgsl.expected.msl
@@ -0,0 +1,10 @@
+#include <metal_stdlib>
+
+using namespace metal;
+constant float3x4 m = float3x4(float4(0.0f, 1.0f, 2.0f, 3.0f), float4(4.0f, 5.0f, 6.0f, 7.0f), float4(8.0f, 9.0f, 10.0f, 11.0f));
+
+float3x4 f() {
+  float3x4 const m_1 = float3x4(float4(0.0f, 1.0f, 2.0f, 3.0f), float4(4.0f, 5.0f, 6.0f, 7.0f), float4(8.0f, 9.0f, 10.0f, 11.0f));
+  return float3x4(float4(0.0f, 1.0f, 2.0f, 3.0f), float4(4.0f, 5.0f, 6.0f, 7.0f), float4(8.0f, 9.0f, 10.0f, 11.0f));
+}
+
diff --git a/test/tint/expressions/type_ctor/mat3x4/explicit/identity/f32.wgsl.expected.spvasm b/test/tint/expressions/type_ctor/mat3x4/explicit/identity/f32.wgsl.expected.spvasm
new file mode 100644
index 0000000..8770c7b
--- /dev/null
+++ b/test/tint/expressions/type_ctor/mat3x4/explicit/identity/f32.wgsl.expected.spvasm
@@ -0,0 +1,42 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 27
+; Schema: 0
+               OpCapability Shader
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %unused_entry_point "unused_entry_point"
+               OpExecutionMode %unused_entry_point LocalSize 1 1 1
+               OpName %m "m"
+               OpName %unused_entry_point "unused_entry_point"
+               OpName %f "f"
+      %float = OpTypeFloat 32
+    %v4float = OpTypeVector %float 4
+%mat3v4float = OpTypeMatrix %v4float 3
+    %float_0 = OpConstant %float 0
+    %float_1 = OpConstant %float 1
+    %float_2 = OpConstant %float 2
+    %float_3 = OpConstant %float 3
+          %8 = OpConstantComposite %v4float %float_0 %float_1 %float_2 %float_3
+    %float_4 = OpConstant %float 4
+    %float_5 = OpConstant %float 5
+    %float_6 = OpConstant %float 6
+    %float_7 = OpConstant %float 7
+         %13 = OpConstantComposite %v4float %float_4 %float_5 %float_6 %float_7
+    %float_8 = OpConstant %float 8
+    %float_9 = OpConstant %float 9
+   %float_10 = OpConstant %float 10
+   %float_11 = OpConstant %float 11
+         %18 = OpConstantComposite %v4float %float_8 %float_9 %float_10 %float_11
+          %m = OpConstantComposite %mat3v4float %8 %13 %18
+       %void = OpTypeVoid
+         %20 = OpTypeFunction %void
+         %24 = OpTypeFunction %mat3v4float
+%unused_entry_point = OpFunction %void None %20
+         %23 = OpLabel
+               OpReturn
+               OpFunctionEnd
+          %f = OpFunction %mat3v4float None %24
+         %26 = OpLabel
+               OpReturnValue %m
+               OpFunctionEnd
diff --git a/test/tint/expressions/type_ctor/mat3x4/explicit/identity/f32.wgsl.expected.wgsl b/test/tint/expressions/type_ctor/mat3x4/explicit/identity/f32.wgsl.expected.wgsl
new file mode 100644
index 0000000..4c6c2d0
--- /dev/null
+++ b/test/tint/expressions/type_ctor/mat3x4/explicit/identity/f32.wgsl.expected.wgsl
@@ -0,0 +1,6 @@
+let m = mat3x4(mat3x4<f32>(0.0f, 1.0f, 2.0f, 3.0f, 4.0f, 5.0f, 6.0f, 7.0f, 8.0f, 9.0f, 10.0f, 11.0f));
+
+fn f() -> mat3x4<f32> {
+  let m_1 = mat3x4(m);
+  return m_1;
+}
diff --git a/test/tint/expressions/type_ctor/mat3x4/inferred/identity/f32.wgsl b/test/tint/expressions/type_ctor/mat3x4/inferred/identity/f32.wgsl
new file mode 100644
index 0000000..b80dbc5
--- /dev/null
+++ b/test/tint/expressions/type_ctor/mat3x4/inferred/identity/f32.wgsl
@@ -0,0 +1,8 @@
+let m = mat3x4(mat3x4(0.0f, 1.0f, 2.0f, 3.0f,
+                      4.0f, 5.0f, 6.0f, 7.0f,
+                      8.0f, 9.0f, 10.0f, 11.0f));
+
+fn f() -> mat3x4<f32> {
+    let m_1 = mat3x4(m);
+    return m_1;
+}
diff --git a/test/tint/expressions/type_ctor/mat3x4/inferred/identity/f32.wgsl.expected.glsl b/test/tint/expressions/type_ctor/mat3x4/inferred/identity/f32.wgsl.expected.glsl
new file mode 100644
index 0000000..075d29b
--- /dev/null
+++ b/test/tint/expressions/type_ctor/mat3x4/inferred/identity/f32.wgsl.expected.glsl
@@ -0,0 +1,12 @@
+#version 310 es
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void unused_entry_point() {
+  return;
+}
+const mat3x4 m = mat3x4(vec4(0.0f, 1.0f, 2.0f, 3.0f), vec4(4.0f, 5.0f, 6.0f, 7.0f), vec4(8.0f, 9.0f, 10.0f, 11.0f));
+mat3x4 f() {
+  mat3x4 m_1 = mat3x4(vec4(0.0f, 1.0f, 2.0f, 3.0f), vec4(4.0f, 5.0f, 6.0f, 7.0f), vec4(8.0f, 9.0f, 10.0f, 11.0f));
+  return mat3x4(vec4(0.0f, 1.0f, 2.0f, 3.0f), vec4(4.0f, 5.0f, 6.0f, 7.0f), vec4(8.0f, 9.0f, 10.0f, 11.0f));
+}
+
diff --git a/test/tint/expressions/type_ctor/mat3x4/inferred/identity/f32.wgsl.expected.hlsl b/test/tint/expressions/type_ctor/mat3x4/inferred/identity/f32.wgsl.expected.hlsl
new file mode 100644
index 0000000..de62d39
--- /dev/null
+++ b/test/tint/expressions/type_ctor/mat3x4/inferred/identity/f32.wgsl.expected.hlsl
@@ -0,0 +1,11 @@
+[numthreads(1, 1, 1)]
+void unused_entry_point() {
+  return;
+}
+
+static const float3x4 m = float3x4(float4(0.0f, 1.0f, 2.0f, 3.0f), float4(4.0f, 5.0f, 6.0f, 7.0f), float4(8.0f, 9.0f, 10.0f, 11.0f));
+
+float3x4 f() {
+  const float3x4 m_1 = float3x4(float4(0.0f, 1.0f, 2.0f, 3.0f), float4(4.0f, 5.0f, 6.0f, 7.0f), float4(8.0f, 9.0f, 10.0f, 11.0f));
+  return float3x4(float4(0.0f, 1.0f, 2.0f, 3.0f), float4(4.0f, 5.0f, 6.0f, 7.0f), float4(8.0f, 9.0f, 10.0f, 11.0f));
+}
diff --git a/test/tint/expressions/type_ctor/mat3x4/inferred/identity/f32.wgsl.expected.msl b/test/tint/expressions/type_ctor/mat3x4/inferred/identity/f32.wgsl.expected.msl
new file mode 100644
index 0000000..86e4c2e
--- /dev/null
+++ b/test/tint/expressions/type_ctor/mat3x4/inferred/identity/f32.wgsl.expected.msl
@@ -0,0 +1,10 @@
+#include <metal_stdlib>
+
+using namespace metal;
+constant float3x4 m = float3x4(float4(0.0f, 1.0f, 2.0f, 3.0f), float4(4.0f, 5.0f, 6.0f, 7.0f), float4(8.0f, 9.0f, 10.0f, 11.0f));
+
+float3x4 f() {
+  float3x4 const m_1 = float3x4(float4(0.0f, 1.0f, 2.0f, 3.0f), float4(4.0f, 5.0f, 6.0f, 7.0f), float4(8.0f, 9.0f, 10.0f, 11.0f));
+  return float3x4(float4(0.0f, 1.0f, 2.0f, 3.0f), float4(4.0f, 5.0f, 6.0f, 7.0f), float4(8.0f, 9.0f, 10.0f, 11.0f));
+}
+
diff --git a/test/tint/expressions/type_ctor/mat3x4/inferred/identity/f32.wgsl.expected.spvasm b/test/tint/expressions/type_ctor/mat3x4/inferred/identity/f32.wgsl.expected.spvasm
new file mode 100644
index 0000000..8770c7b
--- /dev/null
+++ b/test/tint/expressions/type_ctor/mat3x4/inferred/identity/f32.wgsl.expected.spvasm
@@ -0,0 +1,42 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 27
+; Schema: 0
+               OpCapability Shader
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %unused_entry_point "unused_entry_point"
+               OpExecutionMode %unused_entry_point LocalSize 1 1 1
+               OpName %m "m"
+               OpName %unused_entry_point "unused_entry_point"
+               OpName %f "f"
+      %float = OpTypeFloat 32
+    %v4float = OpTypeVector %float 4
+%mat3v4float = OpTypeMatrix %v4float 3
+    %float_0 = OpConstant %float 0
+    %float_1 = OpConstant %float 1
+    %float_2 = OpConstant %float 2
+    %float_3 = OpConstant %float 3
+          %8 = OpConstantComposite %v4float %float_0 %float_1 %float_2 %float_3
+    %float_4 = OpConstant %float 4
+    %float_5 = OpConstant %float 5
+    %float_6 = OpConstant %float 6
+    %float_7 = OpConstant %float 7
+         %13 = OpConstantComposite %v4float %float_4 %float_5 %float_6 %float_7
+    %float_8 = OpConstant %float 8
+    %float_9 = OpConstant %float 9
+   %float_10 = OpConstant %float 10
+   %float_11 = OpConstant %float 11
+         %18 = OpConstantComposite %v4float %float_8 %float_9 %float_10 %float_11
+          %m = OpConstantComposite %mat3v4float %8 %13 %18
+       %void = OpTypeVoid
+         %20 = OpTypeFunction %void
+         %24 = OpTypeFunction %mat3v4float
+%unused_entry_point = OpFunction %void None %20
+         %23 = OpLabel
+               OpReturn
+               OpFunctionEnd
+          %f = OpFunction %mat3v4float None %24
+         %26 = OpLabel
+               OpReturnValue %m
+               OpFunctionEnd
diff --git a/test/tint/expressions/type_ctor/mat3x4/inferred/identity/f32.wgsl.expected.wgsl b/test/tint/expressions/type_ctor/mat3x4/inferred/identity/f32.wgsl.expected.wgsl
new file mode 100644
index 0000000..46be1d3
--- /dev/null
+++ b/test/tint/expressions/type_ctor/mat3x4/inferred/identity/f32.wgsl.expected.wgsl
@@ -0,0 +1,6 @@
+let m = mat3x4(mat3x4(0.0f, 1.0f, 2.0f, 3.0f, 4.0f, 5.0f, 6.0f, 7.0f, 8.0f, 9.0f, 10.0f, 11.0f));
+
+fn f() -> mat3x4<f32> {
+  let m_1 = mat3x4(m);
+  return m_1;
+}
diff --git a/test/tint/expressions/type_ctor/mat3x4/identity/f32.wgsl b/test/tint/expressions/type_ctor/mat3x4/zero/f32.wgsl
similarity index 100%
rename from test/tint/expressions/type_ctor/mat3x4/identity/f32.wgsl
rename to test/tint/expressions/type_ctor/mat3x4/zero/f32.wgsl
diff --git a/test/tint/expressions/type_ctor/mat3x4/identity/f32.wgsl.expected.glsl b/test/tint/expressions/type_ctor/mat3x4/zero/f32.wgsl.expected.glsl
similarity index 100%
rename from test/tint/expressions/type_ctor/mat3x4/identity/f32.wgsl.expected.glsl
rename to test/tint/expressions/type_ctor/mat3x4/zero/f32.wgsl.expected.glsl
diff --git a/test/tint/expressions/type_ctor/mat3x4/identity/f32.wgsl.expected.hlsl b/test/tint/expressions/type_ctor/mat3x4/zero/f32.wgsl.expected.hlsl
similarity index 100%
rename from test/tint/expressions/type_ctor/mat3x4/identity/f32.wgsl.expected.hlsl
rename to test/tint/expressions/type_ctor/mat3x4/zero/f32.wgsl.expected.hlsl
diff --git a/test/tint/expressions/type_ctor/mat3x4/identity/f32.wgsl.expected.msl b/test/tint/expressions/type_ctor/mat3x4/zero/f32.wgsl.expected.msl
similarity index 100%
rename from test/tint/expressions/type_ctor/mat3x4/identity/f32.wgsl.expected.msl
rename to test/tint/expressions/type_ctor/mat3x4/zero/f32.wgsl.expected.msl
diff --git a/test/tint/expressions/type_ctor/mat3x4/identity/f32.wgsl.expected.spvasm b/test/tint/expressions/type_ctor/mat3x4/zero/f32.wgsl.expected.spvasm
similarity index 100%
rename from test/tint/expressions/type_ctor/mat3x4/identity/f32.wgsl.expected.spvasm
rename to test/tint/expressions/type_ctor/mat3x4/zero/f32.wgsl.expected.spvasm
diff --git a/test/tint/expressions/type_ctor/mat3x4/identity/f32.wgsl.expected.wgsl b/test/tint/expressions/type_ctor/mat3x4/zero/f32.wgsl.expected.wgsl
similarity index 100%
rename from test/tint/expressions/type_ctor/mat3x4/identity/f32.wgsl.expected.wgsl
rename to test/tint/expressions/type_ctor/mat3x4/zero/f32.wgsl.expected.wgsl
diff --git a/test/tint/expressions/type_ctor/mat4x2/explicit/identity/f32.wgsl b/test/tint/expressions/type_ctor/mat4x2/explicit/identity/f32.wgsl
new file mode 100644
index 0000000..44099e2
--- /dev/null
+++ b/test/tint/expressions/type_ctor/mat4x2/explicit/identity/f32.wgsl
@@ -0,0 +1,9 @@
+let m = mat4x2(mat4x2<f32>(0.0f, 1.0f,
+                           2.0f, 3.0f,
+                           4.0f, 5.0f,
+                           6.0f, 7.0f));
+
+fn f() -> mat4x2<f32> {
+    let m_1 = mat4x2(m);
+    return m_1;
+}
diff --git a/test/tint/expressions/type_ctor/mat4x2/explicit/identity/f32.wgsl.expected.glsl b/test/tint/expressions/type_ctor/mat4x2/explicit/identity/f32.wgsl.expected.glsl
new file mode 100644
index 0000000..899a25f
--- /dev/null
+++ b/test/tint/expressions/type_ctor/mat4x2/explicit/identity/f32.wgsl.expected.glsl
@@ -0,0 +1,12 @@
+#version 310 es
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void unused_entry_point() {
+  return;
+}
+const mat4x2 m = mat4x2(vec2(0.0f, 1.0f), vec2(2.0f, 3.0f), vec2(4.0f, 5.0f), vec2(6.0f, 7.0f));
+mat4x2 f() {
+  mat4x2 m_1 = mat4x2(vec2(0.0f, 1.0f), vec2(2.0f, 3.0f), vec2(4.0f, 5.0f), vec2(6.0f, 7.0f));
+  return mat4x2(vec2(0.0f, 1.0f), vec2(2.0f, 3.0f), vec2(4.0f, 5.0f), vec2(6.0f, 7.0f));
+}
+
diff --git a/test/tint/expressions/type_ctor/mat4x2/explicit/identity/f32.wgsl.expected.hlsl b/test/tint/expressions/type_ctor/mat4x2/explicit/identity/f32.wgsl.expected.hlsl
new file mode 100644
index 0000000..de0cb92
--- /dev/null
+++ b/test/tint/expressions/type_ctor/mat4x2/explicit/identity/f32.wgsl.expected.hlsl
@@ -0,0 +1,11 @@
+[numthreads(1, 1, 1)]
+void unused_entry_point() {
+  return;
+}
+
+static const float4x2 m = float4x2(float2(0.0f, 1.0f), float2(2.0f, 3.0f), float2(4.0f, 5.0f), float2(6.0f, 7.0f));
+
+float4x2 f() {
+  const float4x2 m_1 = float4x2(float2(0.0f, 1.0f), float2(2.0f, 3.0f), float2(4.0f, 5.0f), float2(6.0f, 7.0f));
+  return float4x2(float2(0.0f, 1.0f), float2(2.0f, 3.0f), float2(4.0f, 5.0f), float2(6.0f, 7.0f));
+}
diff --git a/test/tint/expressions/type_ctor/mat4x2/explicit/identity/f32.wgsl.expected.msl b/test/tint/expressions/type_ctor/mat4x2/explicit/identity/f32.wgsl.expected.msl
new file mode 100644
index 0000000..19ae099
--- /dev/null
+++ b/test/tint/expressions/type_ctor/mat4x2/explicit/identity/f32.wgsl.expected.msl
@@ -0,0 +1,10 @@
+#include <metal_stdlib>
+
+using namespace metal;
+constant float4x2 m = float4x2(float2(0.0f, 1.0f), float2(2.0f, 3.0f), float2(4.0f, 5.0f), float2(6.0f, 7.0f));
+
+float4x2 f() {
+  float4x2 const m_1 = float4x2(float2(0.0f, 1.0f), float2(2.0f, 3.0f), float2(4.0f, 5.0f), float2(6.0f, 7.0f));
+  return float4x2(float2(0.0f, 1.0f), float2(2.0f, 3.0f), float2(4.0f, 5.0f), float2(6.0f, 7.0f));
+}
+
diff --git a/test/tint/expressions/type_ctor/mat4x2/explicit/identity/f32.wgsl.expected.spvasm b/test/tint/expressions/type_ctor/mat4x2/explicit/identity/f32.wgsl.expected.spvasm
new file mode 100644
index 0000000..045b57c
--- /dev/null
+++ b/test/tint/expressions/type_ctor/mat4x2/explicit/identity/f32.wgsl.expected.spvasm
@@ -0,0 +1,39 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 24
+; Schema: 0
+               OpCapability Shader
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %unused_entry_point "unused_entry_point"
+               OpExecutionMode %unused_entry_point LocalSize 1 1 1
+               OpName %m "m"
+               OpName %unused_entry_point "unused_entry_point"
+               OpName %f "f"
+      %float = OpTypeFloat 32
+    %v2float = OpTypeVector %float 2
+%mat4v2float = OpTypeMatrix %v2float 4
+    %float_0 = OpConstant %float 0
+    %float_1 = OpConstant %float 1
+          %6 = OpConstantComposite %v2float %float_0 %float_1
+    %float_2 = OpConstant %float 2
+    %float_3 = OpConstant %float 3
+          %9 = OpConstantComposite %v2float %float_2 %float_3
+    %float_4 = OpConstant %float 4
+    %float_5 = OpConstant %float 5
+         %12 = OpConstantComposite %v2float %float_4 %float_5
+    %float_6 = OpConstant %float 6
+    %float_7 = OpConstant %float 7
+         %15 = OpConstantComposite %v2float %float_6 %float_7
+          %m = OpConstantComposite %mat4v2float %6 %9 %12 %15
+       %void = OpTypeVoid
+         %17 = OpTypeFunction %void
+         %21 = OpTypeFunction %mat4v2float
+%unused_entry_point = OpFunction %void None %17
+         %20 = OpLabel
+               OpReturn
+               OpFunctionEnd
+          %f = OpFunction %mat4v2float None %21
+         %23 = OpLabel
+               OpReturnValue %m
+               OpFunctionEnd
diff --git a/test/tint/expressions/type_ctor/mat4x2/explicit/identity/f32.wgsl.expected.wgsl b/test/tint/expressions/type_ctor/mat4x2/explicit/identity/f32.wgsl.expected.wgsl
new file mode 100644
index 0000000..6ae1b50
--- /dev/null
+++ b/test/tint/expressions/type_ctor/mat4x2/explicit/identity/f32.wgsl.expected.wgsl
@@ -0,0 +1,6 @@
+let m = mat4x2(mat4x2<f32>(0.0f, 1.0f, 2.0f, 3.0f, 4.0f, 5.0f, 6.0f, 7.0f));
+
+fn f() -> mat4x2<f32> {
+  let m_1 = mat4x2(m);
+  return m_1;
+}
diff --git a/test/tint/expressions/type_ctor/mat4x2/inferred/identity/f32.wgsl b/test/tint/expressions/type_ctor/mat4x2/inferred/identity/f32.wgsl
new file mode 100644
index 0000000..45b9ed0
--- /dev/null
+++ b/test/tint/expressions/type_ctor/mat4x2/inferred/identity/f32.wgsl
@@ -0,0 +1,9 @@
+let m = mat4x2(mat4x2(0.0f, 1.0f,
+                      2.0f, 3.0f,
+                      4.0f, 5.0f,
+                      6.0f, 7.0f));
+
+fn f() -> mat4x2<f32> {
+    let m_1 = mat4x2(m);
+    return m_1;
+}
diff --git a/test/tint/expressions/type_ctor/mat4x2/inferred/identity/f32.wgsl.expected.glsl b/test/tint/expressions/type_ctor/mat4x2/inferred/identity/f32.wgsl.expected.glsl
new file mode 100644
index 0000000..899a25f
--- /dev/null
+++ b/test/tint/expressions/type_ctor/mat4x2/inferred/identity/f32.wgsl.expected.glsl
@@ -0,0 +1,12 @@
+#version 310 es
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void unused_entry_point() {
+  return;
+}
+const mat4x2 m = mat4x2(vec2(0.0f, 1.0f), vec2(2.0f, 3.0f), vec2(4.0f, 5.0f), vec2(6.0f, 7.0f));
+mat4x2 f() {
+  mat4x2 m_1 = mat4x2(vec2(0.0f, 1.0f), vec2(2.0f, 3.0f), vec2(4.0f, 5.0f), vec2(6.0f, 7.0f));
+  return mat4x2(vec2(0.0f, 1.0f), vec2(2.0f, 3.0f), vec2(4.0f, 5.0f), vec2(6.0f, 7.0f));
+}
+
diff --git a/test/tint/expressions/type_ctor/mat4x2/inferred/identity/f32.wgsl.expected.hlsl b/test/tint/expressions/type_ctor/mat4x2/inferred/identity/f32.wgsl.expected.hlsl
new file mode 100644
index 0000000..de0cb92
--- /dev/null
+++ b/test/tint/expressions/type_ctor/mat4x2/inferred/identity/f32.wgsl.expected.hlsl
@@ -0,0 +1,11 @@
+[numthreads(1, 1, 1)]
+void unused_entry_point() {
+  return;
+}
+
+static const float4x2 m = float4x2(float2(0.0f, 1.0f), float2(2.0f, 3.0f), float2(4.0f, 5.0f), float2(6.0f, 7.0f));
+
+float4x2 f() {
+  const float4x2 m_1 = float4x2(float2(0.0f, 1.0f), float2(2.0f, 3.0f), float2(4.0f, 5.0f), float2(6.0f, 7.0f));
+  return float4x2(float2(0.0f, 1.0f), float2(2.0f, 3.0f), float2(4.0f, 5.0f), float2(6.0f, 7.0f));
+}
diff --git a/test/tint/expressions/type_ctor/mat4x2/inferred/identity/f32.wgsl.expected.msl b/test/tint/expressions/type_ctor/mat4x2/inferred/identity/f32.wgsl.expected.msl
new file mode 100644
index 0000000..19ae099
--- /dev/null
+++ b/test/tint/expressions/type_ctor/mat4x2/inferred/identity/f32.wgsl.expected.msl
@@ -0,0 +1,10 @@
+#include <metal_stdlib>
+
+using namespace metal;
+constant float4x2 m = float4x2(float2(0.0f, 1.0f), float2(2.0f, 3.0f), float2(4.0f, 5.0f), float2(6.0f, 7.0f));
+
+float4x2 f() {
+  float4x2 const m_1 = float4x2(float2(0.0f, 1.0f), float2(2.0f, 3.0f), float2(4.0f, 5.0f), float2(6.0f, 7.0f));
+  return float4x2(float2(0.0f, 1.0f), float2(2.0f, 3.0f), float2(4.0f, 5.0f), float2(6.0f, 7.0f));
+}
+
diff --git a/test/tint/expressions/type_ctor/mat4x2/inferred/identity/f32.wgsl.expected.spvasm b/test/tint/expressions/type_ctor/mat4x2/inferred/identity/f32.wgsl.expected.spvasm
new file mode 100644
index 0000000..045b57c
--- /dev/null
+++ b/test/tint/expressions/type_ctor/mat4x2/inferred/identity/f32.wgsl.expected.spvasm
@@ -0,0 +1,39 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 24
+; Schema: 0
+               OpCapability Shader
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %unused_entry_point "unused_entry_point"
+               OpExecutionMode %unused_entry_point LocalSize 1 1 1
+               OpName %m "m"
+               OpName %unused_entry_point "unused_entry_point"
+               OpName %f "f"
+      %float = OpTypeFloat 32
+    %v2float = OpTypeVector %float 2
+%mat4v2float = OpTypeMatrix %v2float 4
+    %float_0 = OpConstant %float 0
+    %float_1 = OpConstant %float 1
+          %6 = OpConstantComposite %v2float %float_0 %float_1
+    %float_2 = OpConstant %float 2
+    %float_3 = OpConstant %float 3
+          %9 = OpConstantComposite %v2float %float_2 %float_3
+    %float_4 = OpConstant %float 4
+    %float_5 = OpConstant %float 5
+         %12 = OpConstantComposite %v2float %float_4 %float_5
+    %float_6 = OpConstant %float 6
+    %float_7 = OpConstant %float 7
+         %15 = OpConstantComposite %v2float %float_6 %float_7
+          %m = OpConstantComposite %mat4v2float %6 %9 %12 %15
+       %void = OpTypeVoid
+         %17 = OpTypeFunction %void
+         %21 = OpTypeFunction %mat4v2float
+%unused_entry_point = OpFunction %void None %17
+         %20 = OpLabel
+               OpReturn
+               OpFunctionEnd
+          %f = OpFunction %mat4v2float None %21
+         %23 = OpLabel
+               OpReturnValue %m
+               OpFunctionEnd
diff --git a/test/tint/expressions/type_ctor/mat4x2/inferred/identity/f32.wgsl.expected.wgsl b/test/tint/expressions/type_ctor/mat4x2/inferred/identity/f32.wgsl.expected.wgsl
new file mode 100644
index 0000000..ace9fa2
--- /dev/null
+++ b/test/tint/expressions/type_ctor/mat4x2/inferred/identity/f32.wgsl.expected.wgsl
@@ -0,0 +1,6 @@
+let m = mat4x2(mat4x2(0.0f, 1.0f, 2.0f, 3.0f, 4.0f, 5.0f, 6.0f, 7.0f));
+
+fn f() -> mat4x2<f32> {
+  let m_1 = mat4x2(m);
+  return m_1;
+}
diff --git a/test/tint/expressions/type_ctor/mat4x2/identity/f32.wgsl b/test/tint/expressions/type_ctor/mat4x2/zero/f32.wgsl
similarity index 100%
rename from test/tint/expressions/type_ctor/mat4x2/identity/f32.wgsl
rename to test/tint/expressions/type_ctor/mat4x2/zero/f32.wgsl
diff --git a/test/tint/expressions/type_ctor/mat4x2/identity/f32.wgsl.expected.glsl b/test/tint/expressions/type_ctor/mat4x2/zero/f32.wgsl.expected.glsl
similarity index 100%
rename from test/tint/expressions/type_ctor/mat4x2/identity/f32.wgsl.expected.glsl
rename to test/tint/expressions/type_ctor/mat4x2/zero/f32.wgsl.expected.glsl
diff --git a/test/tint/expressions/type_ctor/mat4x2/identity/f32.wgsl.expected.hlsl b/test/tint/expressions/type_ctor/mat4x2/zero/f32.wgsl.expected.hlsl
similarity index 100%
rename from test/tint/expressions/type_ctor/mat4x2/identity/f32.wgsl.expected.hlsl
rename to test/tint/expressions/type_ctor/mat4x2/zero/f32.wgsl.expected.hlsl
diff --git a/test/tint/expressions/type_ctor/mat4x2/identity/f32.wgsl.expected.msl b/test/tint/expressions/type_ctor/mat4x2/zero/f32.wgsl.expected.msl
similarity index 100%
rename from test/tint/expressions/type_ctor/mat4x2/identity/f32.wgsl.expected.msl
rename to test/tint/expressions/type_ctor/mat4x2/zero/f32.wgsl.expected.msl
diff --git a/test/tint/expressions/type_ctor/mat4x2/identity/f32.wgsl.expected.spvasm b/test/tint/expressions/type_ctor/mat4x2/zero/f32.wgsl.expected.spvasm
similarity index 100%
rename from test/tint/expressions/type_ctor/mat4x2/identity/f32.wgsl.expected.spvasm
rename to test/tint/expressions/type_ctor/mat4x2/zero/f32.wgsl.expected.spvasm
diff --git a/test/tint/expressions/type_ctor/mat4x2/identity/f32.wgsl.expected.wgsl b/test/tint/expressions/type_ctor/mat4x2/zero/f32.wgsl.expected.wgsl
similarity index 100%
rename from test/tint/expressions/type_ctor/mat4x2/identity/f32.wgsl.expected.wgsl
rename to test/tint/expressions/type_ctor/mat4x2/zero/f32.wgsl.expected.wgsl
diff --git a/test/tint/expressions/type_ctor/mat4x3/explicit/identity/f32.wgsl b/test/tint/expressions/type_ctor/mat4x3/explicit/identity/f32.wgsl
new file mode 100644
index 0000000..f940087
--- /dev/null
+++ b/test/tint/expressions/type_ctor/mat4x3/explicit/identity/f32.wgsl
@@ -0,0 +1,9 @@
+let m = mat4x3(mat4x3<f32>(0.0f, 1.0f, 2.0f,
+                           3.0f, 4.0f, 5.0f,
+                           6.0f, 7.0f, 8.0f,
+                           9.0f, 10.0f, 11.0f));
+
+fn f() -> mat4x3<f32> {
+    let m_1 = mat4x3(m);
+    return m_1;
+}
diff --git a/test/tint/expressions/type_ctor/mat4x3/explicit/identity/f32.wgsl.expected.glsl b/test/tint/expressions/type_ctor/mat4x3/explicit/identity/f32.wgsl.expected.glsl
new file mode 100644
index 0000000..87a80c9
--- /dev/null
+++ b/test/tint/expressions/type_ctor/mat4x3/explicit/identity/f32.wgsl.expected.glsl
@@ -0,0 +1,12 @@
+#version 310 es
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void unused_entry_point() {
+  return;
+}
+const mat4x3 m = mat4x3(vec3(0.0f, 1.0f, 2.0f), vec3(3.0f, 4.0f, 5.0f), vec3(6.0f, 7.0f, 8.0f), vec3(9.0f, 10.0f, 11.0f));
+mat4x3 f() {
+  mat4x3 m_1 = mat4x3(vec3(0.0f, 1.0f, 2.0f), vec3(3.0f, 4.0f, 5.0f), vec3(6.0f, 7.0f, 8.0f), vec3(9.0f, 10.0f, 11.0f));
+  return mat4x3(vec3(0.0f, 1.0f, 2.0f), vec3(3.0f, 4.0f, 5.0f), vec3(6.0f, 7.0f, 8.0f), vec3(9.0f, 10.0f, 11.0f));
+}
+
diff --git a/test/tint/expressions/type_ctor/mat4x3/explicit/identity/f32.wgsl.expected.hlsl b/test/tint/expressions/type_ctor/mat4x3/explicit/identity/f32.wgsl.expected.hlsl
new file mode 100644
index 0000000..30ebfbf
--- /dev/null
+++ b/test/tint/expressions/type_ctor/mat4x3/explicit/identity/f32.wgsl.expected.hlsl
@@ -0,0 +1,11 @@
+[numthreads(1, 1, 1)]
+void unused_entry_point() {
+  return;
+}
+
+static const float4x3 m = float4x3(float3(0.0f, 1.0f, 2.0f), float3(3.0f, 4.0f, 5.0f), float3(6.0f, 7.0f, 8.0f), float3(9.0f, 10.0f, 11.0f));
+
+float4x3 f() {
+  const float4x3 m_1 = float4x3(float3(0.0f, 1.0f, 2.0f), float3(3.0f, 4.0f, 5.0f), float3(6.0f, 7.0f, 8.0f), float3(9.0f, 10.0f, 11.0f));
+  return float4x3(float3(0.0f, 1.0f, 2.0f), float3(3.0f, 4.0f, 5.0f), float3(6.0f, 7.0f, 8.0f), float3(9.0f, 10.0f, 11.0f));
+}
diff --git a/test/tint/expressions/type_ctor/mat4x3/explicit/identity/f32.wgsl.expected.msl b/test/tint/expressions/type_ctor/mat4x3/explicit/identity/f32.wgsl.expected.msl
new file mode 100644
index 0000000..d7238cd
--- /dev/null
+++ b/test/tint/expressions/type_ctor/mat4x3/explicit/identity/f32.wgsl.expected.msl
@@ -0,0 +1,10 @@
+#include <metal_stdlib>
+
+using namespace metal;
+constant float4x3 m = float4x3(float3(0.0f, 1.0f, 2.0f), float3(3.0f, 4.0f, 5.0f), float3(6.0f, 7.0f, 8.0f), float3(9.0f, 10.0f, 11.0f));
+
+float4x3 f() {
+  float4x3 const m_1 = float4x3(float3(0.0f, 1.0f, 2.0f), float3(3.0f, 4.0f, 5.0f), float3(6.0f, 7.0f, 8.0f), float3(9.0f, 10.0f, 11.0f));
+  return float4x3(float3(0.0f, 1.0f, 2.0f), float3(3.0f, 4.0f, 5.0f), float3(6.0f, 7.0f, 8.0f), float3(9.0f, 10.0f, 11.0f));
+}
+
diff --git a/test/tint/expressions/type_ctor/mat4x3/explicit/identity/f32.wgsl.expected.spvasm b/test/tint/expressions/type_ctor/mat4x3/explicit/identity/f32.wgsl.expected.spvasm
new file mode 100644
index 0000000..16d9efb
--- /dev/null
+++ b/test/tint/expressions/type_ctor/mat4x3/explicit/identity/f32.wgsl.expected.spvasm
@@ -0,0 +1,43 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 28
+; Schema: 0
+               OpCapability Shader
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %unused_entry_point "unused_entry_point"
+               OpExecutionMode %unused_entry_point LocalSize 1 1 1
+               OpName %m "m"
+               OpName %unused_entry_point "unused_entry_point"
+               OpName %f "f"
+      %float = OpTypeFloat 32
+    %v3float = OpTypeVector %float 3
+%mat4v3float = OpTypeMatrix %v3float 4
+    %float_0 = OpConstant %float 0
+    %float_1 = OpConstant %float 1
+    %float_2 = OpConstant %float 2
+          %7 = OpConstantComposite %v3float %float_0 %float_1 %float_2
+    %float_3 = OpConstant %float 3
+    %float_4 = OpConstant %float 4
+    %float_5 = OpConstant %float 5
+         %11 = OpConstantComposite %v3float %float_3 %float_4 %float_5
+    %float_6 = OpConstant %float 6
+    %float_7 = OpConstant %float 7
+    %float_8 = OpConstant %float 8
+         %15 = OpConstantComposite %v3float %float_6 %float_7 %float_8
+    %float_9 = OpConstant %float 9
+   %float_10 = OpConstant %float 10
+   %float_11 = OpConstant %float 11
+         %19 = OpConstantComposite %v3float %float_9 %float_10 %float_11
+          %m = OpConstantComposite %mat4v3float %7 %11 %15 %19
+       %void = OpTypeVoid
+         %21 = OpTypeFunction %void
+         %25 = OpTypeFunction %mat4v3float
+%unused_entry_point = OpFunction %void None %21
+         %24 = OpLabel
+               OpReturn
+               OpFunctionEnd
+          %f = OpFunction %mat4v3float None %25
+         %27 = OpLabel
+               OpReturnValue %m
+               OpFunctionEnd
diff --git a/test/tint/expressions/type_ctor/mat4x3/explicit/identity/f32.wgsl.expected.wgsl b/test/tint/expressions/type_ctor/mat4x3/explicit/identity/f32.wgsl.expected.wgsl
new file mode 100644
index 0000000..4daec06
--- /dev/null
+++ b/test/tint/expressions/type_ctor/mat4x3/explicit/identity/f32.wgsl.expected.wgsl
@@ -0,0 +1,6 @@
+let m = mat4x3(mat4x3<f32>(0.0f, 1.0f, 2.0f, 3.0f, 4.0f, 5.0f, 6.0f, 7.0f, 8.0f, 9.0f, 10.0f, 11.0f));
+
+fn f() -> mat4x3<f32> {
+  let m_1 = mat4x3(m);
+  return m_1;
+}
diff --git a/test/tint/expressions/type_ctor/mat4x3/inferred/identity/f32.wgsl b/test/tint/expressions/type_ctor/mat4x3/inferred/identity/f32.wgsl
new file mode 100644
index 0000000..aba260d
--- /dev/null
+++ b/test/tint/expressions/type_ctor/mat4x3/inferred/identity/f32.wgsl
@@ -0,0 +1,9 @@
+let m = mat4x3(mat4x3(0.0f, 1.0f, 2.0f,
+                      3.0f, 4.0f, 5.0f,
+                      6.0f, 7.0f, 8.0f,
+                      9.0f, 10.0f, 11.0f));
+
+fn f() -> mat4x3<f32> {
+    let m_1 = mat4x3(m);
+    return m_1;
+}
diff --git a/test/tint/expressions/type_ctor/mat4x3/inferred/identity/f32.wgsl.expected.glsl b/test/tint/expressions/type_ctor/mat4x3/inferred/identity/f32.wgsl.expected.glsl
new file mode 100644
index 0000000..87a80c9
--- /dev/null
+++ b/test/tint/expressions/type_ctor/mat4x3/inferred/identity/f32.wgsl.expected.glsl
@@ -0,0 +1,12 @@
+#version 310 es
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void unused_entry_point() {
+  return;
+}
+const mat4x3 m = mat4x3(vec3(0.0f, 1.0f, 2.0f), vec3(3.0f, 4.0f, 5.0f), vec3(6.0f, 7.0f, 8.0f), vec3(9.0f, 10.0f, 11.0f));
+mat4x3 f() {
+  mat4x3 m_1 = mat4x3(vec3(0.0f, 1.0f, 2.0f), vec3(3.0f, 4.0f, 5.0f), vec3(6.0f, 7.0f, 8.0f), vec3(9.0f, 10.0f, 11.0f));
+  return mat4x3(vec3(0.0f, 1.0f, 2.0f), vec3(3.0f, 4.0f, 5.0f), vec3(6.0f, 7.0f, 8.0f), vec3(9.0f, 10.0f, 11.0f));
+}
+
diff --git a/test/tint/expressions/type_ctor/mat4x3/inferred/identity/f32.wgsl.expected.hlsl b/test/tint/expressions/type_ctor/mat4x3/inferred/identity/f32.wgsl.expected.hlsl
new file mode 100644
index 0000000..30ebfbf
--- /dev/null
+++ b/test/tint/expressions/type_ctor/mat4x3/inferred/identity/f32.wgsl.expected.hlsl
@@ -0,0 +1,11 @@
+[numthreads(1, 1, 1)]
+void unused_entry_point() {
+  return;
+}
+
+static const float4x3 m = float4x3(float3(0.0f, 1.0f, 2.0f), float3(3.0f, 4.0f, 5.0f), float3(6.0f, 7.0f, 8.0f), float3(9.0f, 10.0f, 11.0f));
+
+float4x3 f() {
+  const float4x3 m_1 = float4x3(float3(0.0f, 1.0f, 2.0f), float3(3.0f, 4.0f, 5.0f), float3(6.0f, 7.0f, 8.0f), float3(9.0f, 10.0f, 11.0f));
+  return float4x3(float3(0.0f, 1.0f, 2.0f), float3(3.0f, 4.0f, 5.0f), float3(6.0f, 7.0f, 8.0f), float3(9.0f, 10.0f, 11.0f));
+}
diff --git a/test/tint/expressions/type_ctor/mat4x3/inferred/identity/f32.wgsl.expected.msl b/test/tint/expressions/type_ctor/mat4x3/inferred/identity/f32.wgsl.expected.msl
new file mode 100644
index 0000000..d7238cd
--- /dev/null
+++ b/test/tint/expressions/type_ctor/mat4x3/inferred/identity/f32.wgsl.expected.msl
@@ -0,0 +1,10 @@
+#include <metal_stdlib>
+
+using namespace metal;
+constant float4x3 m = float4x3(float3(0.0f, 1.0f, 2.0f), float3(3.0f, 4.0f, 5.0f), float3(6.0f, 7.0f, 8.0f), float3(9.0f, 10.0f, 11.0f));
+
+float4x3 f() {
+  float4x3 const m_1 = float4x3(float3(0.0f, 1.0f, 2.0f), float3(3.0f, 4.0f, 5.0f), float3(6.0f, 7.0f, 8.0f), float3(9.0f, 10.0f, 11.0f));
+  return float4x3(float3(0.0f, 1.0f, 2.0f), float3(3.0f, 4.0f, 5.0f), float3(6.0f, 7.0f, 8.0f), float3(9.0f, 10.0f, 11.0f));
+}
+
diff --git a/test/tint/expressions/type_ctor/mat4x3/inferred/identity/f32.wgsl.expected.spvasm b/test/tint/expressions/type_ctor/mat4x3/inferred/identity/f32.wgsl.expected.spvasm
new file mode 100644
index 0000000..16d9efb
--- /dev/null
+++ b/test/tint/expressions/type_ctor/mat4x3/inferred/identity/f32.wgsl.expected.spvasm
@@ -0,0 +1,43 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 28
+; Schema: 0
+               OpCapability Shader
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %unused_entry_point "unused_entry_point"
+               OpExecutionMode %unused_entry_point LocalSize 1 1 1
+               OpName %m "m"
+               OpName %unused_entry_point "unused_entry_point"
+               OpName %f "f"
+      %float = OpTypeFloat 32
+    %v3float = OpTypeVector %float 3
+%mat4v3float = OpTypeMatrix %v3float 4
+    %float_0 = OpConstant %float 0
+    %float_1 = OpConstant %float 1
+    %float_2 = OpConstant %float 2
+          %7 = OpConstantComposite %v3float %float_0 %float_1 %float_2
+    %float_3 = OpConstant %float 3
+    %float_4 = OpConstant %float 4
+    %float_5 = OpConstant %float 5
+         %11 = OpConstantComposite %v3float %float_3 %float_4 %float_5
+    %float_6 = OpConstant %float 6
+    %float_7 = OpConstant %float 7
+    %float_8 = OpConstant %float 8
+         %15 = OpConstantComposite %v3float %float_6 %float_7 %float_8
+    %float_9 = OpConstant %float 9
+   %float_10 = OpConstant %float 10
+   %float_11 = OpConstant %float 11
+         %19 = OpConstantComposite %v3float %float_9 %float_10 %float_11
+          %m = OpConstantComposite %mat4v3float %7 %11 %15 %19
+       %void = OpTypeVoid
+         %21 = OpTypeFunction %void
+         %25 = OpTypeFunction %mat4v3float
+%unused_entry_point = OpFunction %void None %21
+         %24 = OpLabel
+               OpReturn
+               OpFunctionEnd
+          %f = OpFunction %mat4v3float None %25
+         %27 = OpLabel
+               OpReturnValue %m
+               OpFunctionEnd
diff --git a/test/tint/expressions/type_ctor/mat4x3/inferred/identity/f32.wgsl.expected.wgsl b/test/tint/expressions/type_ctor/mat4x3/inferred/identity/f32.wgsl.expected.wgsl
new file mode 100644
index 0000000..d7e3f24
--- /dev/null
+++ b/test/tint/expressions/type_ctor/mat4x3/inferred/identity/f32.wgsl.expected.wgsl
@@ -0,0 +1,6 @@
+let m = mat4x3(mat4x3(0.0f, 1.0f, 2.0f, 3.0f, 4.0f, 5.0f, 6.0f, 7.0f, 8.0f, 9.0f, 10.0f, 11.0f));
+
+fn f() -> mat4x3<f32> {
+  let m_1 = mat4x3(m);
+  return m_1;
+}
diff --git a/test/tint/expressions/type_ctor/mat4x3/identity/f32.wgsl b/test/tint/expressions/type_ctor/mat4x3/zero/f32.wgsl
similarity index 100%
rename from test/tint/expressions/type_ctor/mat4x3/identity/f32.wgsl
rename to test/tint/expressions/type_ctor/mat4x3/zero/f32.wgsl
diff --git a/test/tint/expressions/type_ctor/mat4x3/identity/f32.wgsl.expected.glsl b/test/tint/expressions/type_ctor/mat4x3/zero/f32.wgsl.expected.glsl
similarity index 100%
rename from test/tint/expressions/type_ctor/mat4x3/identity/f32.wgsl.expected.glsl
rename to test/tint/expressions/type_ctor/mat4x3/zero/f32.wgsl.expected.glsl
diff --git a/test/tint/expressions/type_ctor/mat4x3/identity/f32.wgsl.expected.hlsl b/test/tint/expressions/type_ctor/mat4x3/zero/f32.wgsl.expected.hlsl
similarity index 100%
rename from test/tint/expressions/type_ctor/mat4x3/identity/f32.wgsl.expected.hlsl
rename to test/tint/expressions/type_ctor/mat4x3/zero/f32.wgsl.expected.hlsl
diff --git a/test/tint/expressions/type_ctor/mat4x3/identity/f32.wgsl.expected.msl b/test/tint/expressions/type_ctor/mat4x3/zero/f32.wgsl.expected.msl
similarity index 100%
rename from test/tint/expressions/type_ctor/mat4x3/identity/f32.wgsl.expected.msl
rename to test/tint/expressions/type_ctor/mat4x3/zero/f32.wgsl.expected.msl
diff --git a/test/tint/expressions/type_ctor/mat4x3/identity/f32.wgsl.expected.spvasm b/test/tint/expressions/type_ctor/mat4x3/zero/f32.wgsl.expected.spvasm
similarity index 100%
rename from test/tint/expressions/type_ctor/mat4x3/identity/f32.wgsl.expected.spvasm
rename to test/tint/expressions/type_ctor/mat4x3/zero/f32.wgsl.expected.spvasm
diff --git a/test/tint/expressions/type_ctor/mat4x3/identity/f32.wgsl.expected.wgsl b/test/tint/expressions/type_ctor/mat4x3/zero/f32.wgsl.expected.wgsl
similarity index 100%
rename from test/tint/expressions/type_ctor/mat4x3/identity/f32.wgsl.expected.wgsl
rename to test/tint/expressions/type_ctor/mat4x3/zero/f32.wgsl.expected.wgsl
diff --git a/test/tint/expressions/type_ctor/mat4x4/explicit/identity/f32.wgsl b/test/tint/expressions/type_ctor/mat4x4/explicit/identity/f32.wgsl
new file mode 100644
index 0000000..bc5556d
--- /dev/null
+++ b/test/tint/expressions/type_ctor/mat4x4/explicit/identity/f32.wgsl
@@ -0,0 +1,9 @@
+let m = mat4x4(mat4x4<f32>(0.0f, 1.0f, 2.0f, 3.0f,
+                           4.0f, 5.0f, 6.0f, 7.0f,
+                           8.0f, 9.0f, 10.0f, 11.0f,
+                           12.0f, 13.0f, 14.0f, 15.0f));
+
+fn f() -> mat4x4<f32> {
+    let m_1 = mat4x4(m);
+    return m_1;
+}
diff --git a/test/tint/expressions/type_ctor/mat4x4/explicit/identity/f32.wgsl.expected.glsl b/test/tint/expressions/type_ctor/mat4x4/explicit/identity/f32.wgsl.expected.glsl
new file mode 100644
index 0000000..3c5cf24
--- /dev/null
+++ b/test/tint/expressions/type_ctor/mat4x4/explicit/identity/f32.wgsl.expected.glsl
@@ -0,0 +1,12 @@
+#version 310 es
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void unused_entry_point() {
+  return;
+}
+const mat4 m = mat4(vec4(0.0f, 1.0f, 2.0f, 3.0f), vec4(4.0f, 5.0f, 6.0f, 7.0f), vec4(8.0f, 9.0f, 10.0f, 11.0f), vec4(12.0f, 13.0f, 14.0f, 15.0f));
+mat4 f() {
+  mat4 m_1 = mat4(vec4(0.0f, 1.0f, 2.0f, 3.0f), vec4(4.0f, 5.0f, 6.0f, 7.0f), vec4(8.0f, 9.0f, 10.0f, 11.0f), vec4(12.0f, 13.0f, 14.0f, 15.0f));
+  return mat4(vec4(0.0f, 1.0f, 2.0f, 3.0f), vec4(4.0f, 5.0f, 6.0f, 7.0f), vec4(8.0f, 9.0f, 10.0f, 11.0f), vec4(12.0f, 13.0f, 14.0f, 15.0f));
+}
+
diff --git a/test/tint/expressions/type_ctor/mat4x4/explicit/identity/f32.wgsl.expected.hlsl b/test/tint/expressions/type_ctor/mat4x4/explicit/identity/f32.wgsl.expected.hlsl
new file mode 100644
index 0000000..1f3e190
--- /dev/null
+++ b/test/tint/expressions/type_ctor/mat4x4/explicit/identity/f32.wgsl.expected.hlsl
@@ -0,0 +1,11 @@
+[numthreads(1, 1, 1)]
+void unused_entry_point() {
+  return;
+}
+
+static const float4x4 m = float4x4(float4(0.0f, 1.0f, 2.0f, 3.0f), float4(4.0f, 5.0f, 6.0f, 7.0f), float4(8.0f, 9.0f, 10.0f, 11.0f), float4(12.0f, 13.0f, 14.0f, 15.0f));
+
+float4x4 f() {
+  const float4x4 m_1 = float4x4(float4(0.0f, 1.0f, 2.0f, 3.0f), float4(4.0f, 5.0f, 6.0f, 7.0f), float4(8.0f, 9.0f, 10.0f, 11.0f), float4(12.0f, 13.0f, 14.0f, 15.0f));
+  return float4x4(float4(0.0f, 1.0f, 2.0f, 3.0f), float4(4.0f, 5.0f, 6.0f, 7.0f), float4(8.0f, 9.0f, 10.0f, 11.0f), float4(12.0f, 13.0f, 14.0f, 15.0f));
+}
diff --git a/test/tint/expressions/type_ctor/mat4x4/explicit/identity/f32.wgsl.expected.msl b/test/tint/expressions/type_ctor/mat4x4/explicit/identity/f32.wgsl.expected.msl
new file mode 100644
index 0000000..ffac88e
--- /dev/null
+++ b/test/tint/expressions/type_ctor/mat4x4/explicit/identity/f32.wgsl.expected.msl
@@ -0,0 +1,10 @@
+#include <metal_stdlib>
+
+using namespace metal;
+constant float4x4 m = float4x4(float4(0.0f, 1.0f, 2.0f, 3.0f), float4(4.0f, 5.0f, 6.0f, 7.0f), float4(8.0f, 9.0f, 10.0f, 11.0f), float4(12.0f, 13.0f, 14.0f, 15.0f));
+
+float4x4 f() {
+  float4x4 const m_1 = float4x4(float4(0.0f, 1.0f, 2.0f, 3.0f), float4(4.0f, 5.0f, 6.0f, 7.0f), float4(8.0f, 9.0f, 10.0f, 11.0f), float4(12.0f, 13.0f, 14.0f, 15.0f));
+  return float4x4(float4(0.0f, 1.0f, 2.0f, 3.0f), float4(4.0f, 5.0f, 6.0f, 7.0f), float4(8.0f, 9.0f, 10.0f, 11.0f), float4(12.0f, 13.0f, 14.0f, 15.0f));
+}
+
diff --git a/test/tint/expressions/type_ctor/mat4x4/explicit/identity/f32.wgsl.expected.spvasm b/test/tint/expressions/type_ctor/mat4x4/explicit/identity/f32.wgsl.expected.spvasm
new file mode 100644
index 0000000..a4fc367
--- /dev/null
+++ b/test/tint/expressions/type_ctor/mat4x4/explicit/identity/f32.wgsl.expected.spvasm
@@ -0,0 +1,47 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 32
+; Schema: 0
+               OpCapability Shader
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %unused_entry_point "unused_entry_point"
+               OpExecutionMode %unused_entry_point LocalSize 1 1 1
+               OpName %m "m"
+               OpName %unused_entry_point "unused_entry_point"
+               OpName %f "f"
+      %float = OpTypeFloat 32
+    %v4float = OpTypeVector %float 4
+%mat4v4float = OpTypeMatrix %v4float 4
+    %float_0 = OpConstant %float 0
+    %float_1 = OpConstant %float 1
+    %float_2 = OpConstant %float 2
+    %float_3 = OpConstant %float 3
+          %8 = OpConstantComposite %v4float %float_0 %float_1 %float_2 %float_3
+    %float_4 = OpConstant %float 4
+    %float_5 = OpConstant %float 5
+    %float_6 = OpConstant %float 6
+    %float_7 = OpConstant %float 7
+         %13 = OpConstantComposite %v4float %float_4 %float_5 %float_6 %float_7
+    %float_8 = OpConstant %float 8
+    %float_9 = OpConstant %float 9
+   %float_10 = OpConstant %float 10
+   %float_11 = OpConstant %float 11
+         %18 = OpConstantComposite %v4float %float_8 %float_9 %float_10 %float_11
+   %float_12 = OpConstant %float 12
+   %float_13 = OpConstant %float 13
+   %float_14 = OpConstant %float 14
+   %float_15 = OpConstant %float 15
+         %23 = OpConstantComposite %v4float %float_12 %float_13 %float_14 %float_15
+          %m = OpConstantComposite %mat4v4float %8 %13 %18 %23
+       %void = OpTypeVoid
+         %25 = OpTypeFunction %void
+         %29 = OpTypeFunction %mat4v4float
+%unused_entry_point = OpFunction %void None %25
+         %28 = OpLabel
+               OpReturn
+               OpFunctionEnd
+          %f = OpFunction %mat4v4float None %29
+         %31 = OpLabel
+               OpReturnValue %m
+               OpFunctionEnd
diff --git a/test/tint/expressions/type_ctor/mat4x4/explicit/identity/f32.wgsl.expected.wgsl b/test/tint/expressions/type_ctor/mat4x4/explicit/identity/f32.wgsl.expected.wgsl
new file mode 100644
index 0000000..908d9b9
--- /dev/null
+++ b/test/tint/expressions/type_ctor/mat4x4/explicit/identity/f32.wgsl.expected.wgsl
@@ -0,0 +1,6 @@
+let m = mat4x4(mat4x4<f32>(0.0f, 1.0f, 2.0f, 3.0f, 4.0f, 5.0f, 6.0f, 7.0f, 8.0f, 9.0f, 10.0f, 11.0f, 12.0f, 13.0f, 14.0f, 15.0f));
+
+fn f() -> mat4x4<f32> {
+  let m_1 = mat4x4(m);
+  return m_1;
+}
diff --git a/test/tint/expressions/type_ctor/mat4x4/inferred/identity/f32.wgsl b/test/tint/expressions/type_ctor/mat4x4/inferred/identity/f32.wgsl
new file mode 100644
index 0000000..2b9f7e9
--- /dev/null
+++ b/test/tint/expressions/type_ctor/mat4x4/inferred/identity/f32.wgsl
@@ -0,0 +1,9 @@
+let m = mat4x4(mat4x4(0.0f, 1.0f, 2.0f, 3.0f,
+                      4.0f, 5.0f, 6.0f, 7.0f,
+                      8.0f, 9.0f, 10.0f, 11.0f,
+                      12.0f, 13.0f, 14.0f, 15.0f));
+
+fn f() -> mat4x4<f32> {
+    let m_1 = mat4x4(m);
+    return m_1;
+}
diff --git a/test/tint/expressions/type_ctor/mat4x4/inferred/identity/f32.wgsl.expected.glsl b/test/tint/expressions/type_ctor/mat4x4/inferred/identity/f32.wgsl.expected.glsl
new file mode 100644
index 0000000..3c5cf24
--- /dev/null
+++ b/test/tint/expressions/type_ctor/mat4x4/inferred/identity/f32.wgsl.expected.glsl
@@ -0,0 +1,12 @@
+#version 310 es
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void unused_entry_point() {
+  return;
+}
+const mat4 m = mat4(vec4(0.0f, 1.0f, 2.0f, 3.0f), vec4(4.0f, 5.0f, 6.0f, 7.0f), vec4(8.0f, 9.0f, 10.0f, 11.0f), vec4(12.0f, 13.0f, 14.0f, 15.0f));
+mat4 f() {
+  mat4 m_1 = mat4(vec4(0.0f, 1.0f, 2.0f, 3.0f), vec4(4.0f, 5.0f, 6.0f, 7.0f), vec4(8.0f, 9.0f, 10.0f, 11.0f), vec4(12.0f, 13.0f, 14.0f, 15.0f));
+  return mat4(vec4(0.0f, 1.0f, 2.0f, 3.0f), vec4(4.0f, 5.0f, 6.0f, 7.0f), vec4(8.0f, 9.0f, 10.0f, 11.0f), vec4(12.0f, 13.0f, 14.0f, 15.0f));
+}
+
diff --git a/test/tint/expressions/type_ctor/mat4x4/inferred/identity/f32.wgsl.expected.hlsl b/test/tint/expressions/type_ctor/mat4x4/inferred/identity/f32.wgsl.expected.hlsl
new file mode 100644
index 0000000..1f3e190
--- /dev/null
+++ b/test/tint/expressions/type_ctor/mat4x4/inferred/identity/f32.wgsl.expected.hlsl
@@ -0,0 +1,11 @@
+[numthreads(1, 1, 1)]
+void unused_entry_point() {
+  return;
+}
+
+static const float4x4 m = float4x4(float4(0.0f, 1.0f, 2.0f, 3.0f), float4(4.0f, 5.0f, 6.0f, 7.0f), float4(8.0f, 9.0f, 10.0f, 11.0f), float4(12.0f, 13.0f, 14.0f, 15.0f));
+
+float4x4 f() {
+  const float4x4 m_1 = float4x4(float4(0.0f, 1.0f, 2.0f, 3.0f), float4(4.0f, 5.0f, 6.0f, 7.0f), float4(8.0f, 9.0f, 10.0f, 11.0f), float4(12.0f, 13.0f, 14.0f, 15.0f));
+  return float4x4(float4(0.0f, 1.0f, 2.0f, 3.0f), float4(4.0f, 5.0f, 6.0f, 7.0f), float4(8.0f, 9.0f, 10.0f, 11.0f), float4(12.0f, 13.0f, 14.0f, 15.0f));
+}
diff --git a/test/tint/expressions/type_ctor/mat4x4/inferred/identity/f32.wgsl.expected.msl b/test/tint/expressions/type_ctor/mat4x4/inferred/identity/f32.wgsl.expected.msl
new file mode 100644
index 0000000..ffac88e
--- /dev/null
+++ b/test/tint/expressions/type_ctor/mat4x4/inferred/identity/f32.wgsl.expected.msl
@@ -0,0 +1,10 @@
+#include <metal_stdlib>
+
+using namespace metal;
+constant float4x4 m = float4x4(float4(0.0f, 1.0f, 2.0f, 3.0f), float4(4.0f, 5.0f, 6.0f, 7.0f), float4(8.0f, 9.0f, 10.0f, 11.0f), float4(12.0f, 13.0f, 14.0f, 15.0f));
+
+float4x4 f() {
+  float4x4 const m_1 = float4x4(float4(0.0f, 1.0f, 2.0f, 3.0f), float4(4.0f, 5.0f, 6.0f, 7.0f), float4(8.0f, 9.0f, 10.0f, 11.0f), float4(12.0f, 13.0f, 14.0f, 15.0f));
+  return float4x4(float4(0.0f, 1.0f, 2.0f, 3.0f), float4(4.0f, 5.0f, 6.0f, 7.0f), float4(8.0f, 9.0f, 10.0f, 11.0f), float4(12.0f, 13.0f, 14.0f, 15.0f));
+}
+
diff --git a/test/tint/expressions/type_ctor/mat4x4/inferred/identity/f32.wgsl.expected.spvasm b/test/tint/expressions/type_ctor/mat4x4/inferred/identity/f32.wgsl.expected.spvasm
new file mode 100644
index 0000000..a4fc367
--- /dev/null
+++ b/test/tint/expressions/type_ctor/mat4x4/inferred/identity/f32.wgsl.expected.spvasm
@@ -0,0 +1,47 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 32
+; Schema: 0
+               OpCapability Shader
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %unused_entry_point "unused_entry_point"
+               OpExecutionMode %unused_entry_point LocalSize 1 1 1
+               OpName %m "m"
+               OpName %unused_entry_point "unused_entry_point"
+               OpName %f "f"
+      %float = OpTypeFloat 32
+    %v4float = OpTypeVector %float 4
+%mat4v4float = OpTypeMatrix %v4float 4
+    %float_0 = OpConstant %float 0
+    %float_1 = OpConstant %float 1
+    %float_2 = OpConstant %float 2
+    %float_3 = OpConstant %float 3
+          %8 = OpConstantComposite %v4float %float_0 %float_1 %float_2 %float_3
+    %float_4 = OpConstant %float 4
+    %float_5 = OpConstant %float 5
+    %float_6 = OpConstant %float 6
+    %float_7 = OpConstant %float 7
+         %13 = OpConstantComposite %v4float %float_4 %float_5 %float_6 %float_7
+    %float_8 = OpConstant %float 8
+    %float_9 = OpConstant %float 9
+   %float_10 = OpConstant %float 10
+   %float_11 = OpConstant %float 11
+         %18 = OpConstantComposite %v4float %float_8 %float_9 %float_10 %float_11
+   %float_12 = OpConstant %float 12
+   %float_13 = OpConstant %float 13
+   %float_14 = OpConstant %float 14
+   %float_15 = OpConstant %float 15
+         %23 = OpConstantComposite %v4float %float_12 %float_13 %float_14 %float_15
+          %m = OpConstantComposite %mat4v4float %8 %13 %18 %23
+       %void = OpTypeVoid
+         %25 = OpTypeFunction %void
+         %29 = OpTypeFunction %mat4v4float
+%unused_entry_point = OpFunction %void None %25
+         %28 = OpLabel
+               OpReturn
+               OpFunctionEnd
+          %f = OpFunction %mat4v4float None %29
+         %31 = OpLabel
+               OpReturnValue %m
+               OpFunctionEnd
diff --git a/test/tint/expressions/type_ctor/mat4x4/inferred/identity/f32.wgsl.expected.wgsl b/test/tint/expressions/type_ctor/mat4x4/inferred/identity/f32.wgsl.expected.wgsl
new file mode 100644
index 0000000..b9e9f8f
--- /dev/null
+++ b/test/tint/expressions/type_ctor/mat4x4/inferred/identity/f32.wgsl.expected.wgsl
@@ -0,0 +1,6 @@
+let m = mat4x4(mat4x4(0.0f, 1.0f, 2.0f, 3.0f, 4.0f, 5.0f, 6.0f, 7.0f, 8.0f, 9.0f, 10.0f, 11.0f, 12.0f, 13.0f, 14.0f, 15.0f));
+
+fn f() -> mat4x4<f32> {
+  let m_1 = mat4x4(m);
+  return m_1;
+}
diff --git a/test/tint/expressions/type_ctor/mat4x4/identity/f32.wgsl b/test/tint/expressions/type_ctor/mat4x4/zero/f32.wgsl
similarity index 100%
rename from test/tint/expressions/type_ctor/mat4x4/identity/f32.wgsl
rename to test/tint/expressions/type_ctor/mat4x4/zero/f32.wgsl
diff --git a/test/tint/expressions/type_ctor/mat4x4/identity/f32.wgsl.expected.glsl b/test/tint/expressions/type_ctor/mat4x4/zero/f32.wgsl.expected.glsl
similarity index 100%
rename from test/tint/expressions/type_ctor/mat4x4/identity/f32.wgsl.expected.glsl
rename to test/tint/expressions/type_ctor/mat4x4/zero/f32.wgsl.expected.glsl
diff --git a/test/tint/expressions/type_ctor/mat4x4/identity/f32.wgsl.expected.hlsl b/test/tint/expressions/type_ctor/mat4x4/zero/f32.wgsl.expected.hlsl
similarity index 100%
rename from test/tint/expressions/type_ctor/mat4x4/identity/f32.wgsl.expected.hlsl
rename to test/tint/expressions/type_ctor/mat4x4/zero/f32.wgsl.expected.hlsl
diff --git a/test/tint/expressions/type_ctor/mat4x4/identity/f32.wgsl.expected.msl b/test/tint/expressions/type_ctor/mat4x4/zero/f32.wgsl.expected.msl
similarity index 100%
rename from test/tint/expressions/type_ctor/mat4x4/identity/f32.wgsl.expected.msl
rename to test/tint/expressions/type_ctor/mat4x4/zero/f32.wgsl.expected.msl
diff --git a/test/tint/expressions/type_ctor/mat4x4/identity/f32.wgsl.expected.spvasm b/test/tint/expressions/type_ctor/mat4x4/zero/f32.wgsl.expected.spvasm
similarity index 100%
rename from test/tint/expressions/type_ctor/mat4x4/identity/f32.wgsl.expected.spvasm
rename to test/tint/expressions/type_ctor/mat4x4/zero/f32.wgsl.expected.spvasm
diff --git a/test/tint/expressions/type_ctor/mat4x4/identity/f32.wgsl.expected.wgsl b/test/tint/expressions/type_ctor/mat4x4/zero/f32.wgsl.expected.wgsl
similarity index 100%
rename from test/tint/expressions/type_ctor/mat4x4/identity/f32.wgsl.expected.wgsl
rename to test/tint/expressions/type_ctor/mat4x4/zero/f32.wgsl.expected.wgsl