[clang] [Sema][HLSL][Matrix] Make matrices initializable by a single vector and vice-versa (PR #177486)
Deric C. via cfe-commits
cfe-commits at lists.llvm.org
Tue Feb 17 14:47:23 PST 2026
https://github.com/Icohedron updated https://github.com/llvm/llvm-project/pull/177486
>From d20c1a92d4df29f7cc4de826dc6a6408c93dcb1b Mon Sep 17 00:00:00 2001
From: Deric Cheung <cheung.deric at gmail.com>
Date: Thu, 22 Jan 2026 14:41:09 -0800
Subject: [PATCH 1/9] Make matrices initializable by a single vector and
vice-versa
---
clang/lib/Sema/SemaInit.cpp | 6 +-
.../MatrixToAndFromVectorConstructors.hlsl | 91 +++++++++++++++++++
.../BuiltinMatrix/MatrixSplatErrors.hlsl | 5 -
3 files changed, 96 insertions(+), 6 deletions(-)
create mode 100644 clang/test/CodeGenHLSL/MatrixToAndFromVectorConstructors.hlsl
diff --git a/clang/lib/Sema/SemaInit.cpp b/clang/lib/Sema/SemaInit.cpp
index ff278bc7471bd..58dba9b3ffe30 100644
--- a/clang/lib/Sema/SemaInit.cpp
+++ b/clang/lib/Sema/SemaInit.cpp
@@ -6938,7 +6938,11 @@ void InitializationSequence::InitializeFrom(Sema &S,
// For HLSL ext vector types we allow list initialization behavior for C++
// functional cast expressions which look like constructor syntax. This is
// accomplished by converting initialization arguments to InitListExpr.
- if (S.getLangOpts().HLSL && Args.size() > 1 &&
+ bool IsMatToVecOrVecToMatInit =
+ Args.size() == 1 &&
+ ((SourceType->isExtVectorType() && DestType->isConstantMatrixType()) ||
+ (SourceType->isConstantMatrixType() && DestType->isExtVectorType()));
+ if (S.getLangOpts().HLSL && (IsMatToVecOrVecToMatInit || Args.size() > 1) &&
(DestType->isExtVectorType() || DestType->isConstantMatrixType()) &&
(SourceType.isNull() ||
!Context.hasSameUnqualifiedType(SourceType, DestType))) {
diff --git a/clang/test/CodeGenHLSL/MatrixToAndFromVectorConstructors.hlsl b/clang/test/CodeGenHLSL/MatrixToAndFromVectorConstructors.hlsl
new file mode 100644
index 0000000000000..f7a5cae6a22ff
--- /dev/null
+++ b/clang/test/CodeGenHLSL/MatrixToAndFromVectorConstructors.hlsl
@@ -0,0 +1,91 @@
+// NOTE: Assertions have been autogenerated by utils/update_cc_test_checks.py UTC_ARGS: --version 6
+// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.0-library -disable-llvm-passes -emit-llvm -finclude-default-header -o - %s | FileCheck %s
+
+// CHECK-LABEL: define hidden noundef nofpclass(nan inf) <4 x float> @_Z2fnu11matrix_typeILm2ELm2EfE(
+// CHECK-SAME: <4 x float> noundef nofpclass(nan inf) [[M:%.*]]) #[[ATTR0:[0-9]+]] {
+// CHECK-NEXT: [[ENTRY:.*:]]
+// CHECK-NEXT: [[M_ADDR:%.*]] = alloca [4 x float], align 4
+// CHECK-NEXT: [[V:%.*]] = alloca <4 x float>, align 16
+// CHECK-NEXT: store <4 x float> [[M]], ptr [[M_ADDR]], align 4
+// CHECK-NEXT: [[TMP0:%.*]] = load <4 x float>, ptr [[M_ADDR]], align 4
+// CHECK-NEXT: [[MATRIXEXT:%.*]] = extractelement <4 x float> [[TMP0]], i32 0
+// CHECK-NEXT: [[VECINIT:%.*]] = insertelement <4 x float> poison, float [[MATRIXEXT]], i32 0
+// CHECK-NEXT: [[TMP1:%.*]] = load <4 x float>, ptr [[M_ADDR]], align 4
+// CHECK-NEXT: [[MATRIXEXT1:%.*]] = extractelement <4 x float> [[TMP1]], i32 1
+// CHECK-NEXT: [[VECINIT2:%.*]] = insertelement <4 x float> [[VECINIT]], float [[MATRIXEXT1]], i32 1
+// CHECK-NEXT: [[TMP2:%.*]] = load <4 x float>, ptr [[M_ADDR]], align 4
+// CHECK-NEXT: [[MATRIXEXT3:%.*]] = extractelement <4 x float> [[TMP2]], i32 2
+// CHECK-NEXT: [[VECINIT4:%.*]] = insertelement <4 x float> [[VECINIT2]], float [[MATRIXEXT3]], i32 2
+// CHECK-NEXT: [[TMP3:%.*]] = load <4 x float>, ptr [[M_ADDR]], align 4
+// CHECK-NEXT: [[MATRIXEXT5:%.*]] = extractelement <4 x float> [[TMP3]], i32 3
+// CHECK-NEXT: [[VECINIT6:%.*]] = insertelement <4 x float> [[VECINIT4]], float [[MATRIXEXT5]], i32 3
+// CHECK-NEXT: store <4 x float> [[VECINIT6]], ptr [[V]], align 16
+// CHECK-NEXT: [[TMP4:%.*]] = load <4 x float>, ptr [[V]], align 16
+// CHECK-NEXT: ret <4 x float> [[TMP4]]
+//
+float4 fn(float2x2 m) {
+ float4 v = m;
+ return v;
+m
+
+// CHECK-LABEL: define hidden noundef <2 x i32> @_Z3fn1Dv2_i(
+// CHECK-SAME: <2 x i32> noundef [[V:%.*]]) #[[ATTR0]] {
+// CHECK-NEXT: [[ENTRY:.*:]]
+// CHECK-NEXT: [[V_ADDR:%.*]] = alloca <2 x i32>, align 8
+// CHECK-NEXT: store <2 x i32> [[V]], ptr [[V_ADDR]], align 8
+// CHECK-NEXT: [[TMP0:%.*]] = load <2 x i32>, ptr [[V_ADDR]], align 8
+// CHECK-NEXT: [[VECEXT:%.*]] = extractelement <2 x i32> [[TMP0]], i64 0
+// CHECK-NEXT: [[VECINIT:%.*]] = insertelement <2 x i32> poison, i32 [[VECEXT]], i32 0
+// CHECK-NEXT: [[TMP1:%.*]] = load <2 x i32>, ptr [[V_ADDR]], align 8
+// CHECK-NEXT: [[VECEXT1:%.*]] = extractelement <2 x i32> [[TMP1]], i64 1
+// CHECK-NEXT: [[VECINIT2:%.*]] = insertelement <2 x i32> [[VECINIT]], i32 [[VECEXT1]], i32 1
+// CHECK-NEXT: ret <2 x i32> [[VECINIT2]]
+//
+int1x2 fn1(int2 v) {
+ return v;
+}
+
+// CHECK-LABEL: define hidden noundef <3 x i1> @_Z3fn2Dv3_b(
+// CHECK-SAME: <3 x i1> noundef [[B:%.*]]) #[[ATTR0]] {
+// CHECK-NEXT: [[ENTRY:.*:]]
+// CHECK-NEXT: [[B_ADDR:%.*]] = alloca <3 x i32>, align 16
+// CHECK-NEXT: [[TMP0:%.*]] = zext <3 x i1> [[B]] to <3 x i32>
+// CHECK-NEXT: store <3 x i32> [[TMP0]], ptr [[B_ADDR]], align 16
+// CHECK-NEXT: [[TMP1:%.*]] = load <3 x i32>, ptr [[B_ADDR]], align 16
+// CHECK-NEXT: [[LOADEDV:%.*]] = trunc <3 x i32> [[TMP1]] to <3 x i1>
+// CHECK-NEXT: [[VECEXT:%.*]] = extractelement <3 x i1> [[LOADEDV]], i64 0
+// CHECK-NEXT: [[VECINIT:%.*]] = insertelement <3 x i1> poison, i1 [[VECEXT]], i32 0
+// CHECK-NEXT: [[TMP2:%.*]] = load <3 x i32>, ptr [[B_ADDR]], align 16
+// CHECK-NEXT: [[LOADEDV1:%.*]] = trunc <3 x i32> [[TMP2]] to <3 x i1>
+// CHECK-NEXT: [[VECEXT2:%.*]] = extractelement <3 x i1> [[LOADEDV1]], i64 1
+// CHECK-NEXT: [[VECINIT3:%.*]] = insertelement <3 x i1> [[VECINIT]], i1 [[VECEXT2]], i32 1
+// CHECK-NEXT: [[TMP3:%.*]] = load <3 x i32>, ptr [[B_ADDR]], align 16
+// CHECK-NEXT: [[LOADEDV4:%.*]] = trunc <3 x i32> [[TMP3]] to <3 x i1>
+// CHECK-NEXT: [[VECEXT5:%.*]] = extractelement <3 x i1> [[LOADEDV4]], i64 2
+// CHECK-NEXT: [[VECINIT6:%.*]] = insertelement <3 x i1> [[VECINIT3]], i1 [[VECEXT5]], i32 2
+// CHECK-NEXT: ret <3 x i1> [[VECINIT6]]
+//
+bool3x1 fn2(bool3 b) {
+ return b;
+}
+
+// CHECK-LABEL: define hidden noundef <3 x i32> @_Z3fn3u11matrix_typeILm1ELm3EbE(
+// CHECK-SAME: <3 x i1> noundef [[B:%.*]]) #[[ATTR0]] {
+// CHECK-NEXT: [[ENTRY:.*:]]
+// CHECK-NEXT: [[B_ADDR:%.*]] = alloca [3 x i32], align 4
+// CHECK-NEXT: [[TMP0:%.*]] = zext <3 x i1> [[B]] to <3 x i32>
+// CHECK-NEXT: store <3 x i32> [[TMP0]], ptr [[B_ADDR]], align 4
+// CHECK-NEXT: [[TMP1:%.*]] = load <3 x i32>, ptr [[B_ADDR]], align 4
+// CHECK-NEXT: [[MATRIXEXT:%.*]] = extractelement <3 x i32> [[TMP1]], i32 0
+// CHECK-NEXT: [[VECINIT:%.*]] = insertelement <3 x i32> poison, i32 [[MATRIXEXT]], i32 0
+// CHECK-NEXT: [[TMP2:%.*]] = load <3 x i32>, ptr [[B_ADDR]], align 4
+// CHECK-NEXT: [[MATRIXEXT1:%.*]] = extractelement <3 x i32> [[TMP2]], i32 1
+// CHECK-NEXT: [[VECINIT2:%.*]] = insertelement <3 x i32> [[VECINIT]], i32 [[MATRIXEXT1]], i32 1
+// CHECK-NEXT: [[TMP3:%.*]] = load <3 x i32>, ptr [[B_ADDR]], align 4
+// CHECK-NEXT: [[MATRIXEXT3:%.*]] = extractelement <3 x i32> [[TMP3]], i32 2
+// CHECK-NEXT: [[VECINIT4:%.*]] = insertelement <3 x i32> [[VECINIT2]], i32 [[MATRIXEXT3]], i32 2
+// CHECK-NEXT: ret <3 x i32> [[VECINIT4]]
+//
+int3 fn3(bool1x3 b) {
+ return b;
+}
diff --git a/clang/test/SemaHLSL/Types/BuiltinMatrix/MatrixSplatErrors.hlsl b/clang/test/SemaHLSL/Types/BuiltinMatrix/MatrixSplatErrors.hlsl
index 0c2e53d382180..5a726bb324b60 100644
--- a/clang/test/SemaHLSL/Types/BuiltinMatrix/MatrixSplatErrors.hlsl
+++ b/clang/test/SemaHLSL/Types/BuiltinMatrix/MatrixSplatErrors.hlsl
@@ -1,10 +1,5 @@
// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.6-library -finclude-default-header -std=hlsl202x -verify %s
-void SplatOfVectortoMat(int4 V){
- int2x2 M = V;
- // expected-error at -1 {{cannot initialize a variable of type 'int2x2' (aka 'matrix<int, 2, 2>') with an lvalue of type 'int4' (aka 'vector<int, 4>')}}
-}
-
void SplatOfMattoMat(int4x3 N){
int4x4 M = N;
// expected-error at -1 {{cannot initialize a variable of type 'matrix<[2 * ...], 4>' with an lvalue of type 'matrix<[2 * ...], 3>'}}
>From d63e41724c526143e49f83689663a90414a69b84 Mon Sep 17 00:00:00 2001
From: Deric Cheung <cheung.deric at gmail.com>
Date: Thu, 22 Jan 2026 16:03:52 -0800
Subject: [PATCH 2/9] Check HLSL lang opt in HLSL-specific bool
---
clang/lib/Sema/SemaInit.cpp | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/clang/lib/Sema/SemaInit.cpp b/clang/lib/Sema/SemaInit.cpp
index 58dba9b3ffe30..b2bdf8e3e9d60 100644
--- a/clang/lib/Sema/SemaInit.cpp
+++ b/clang/lib/Sema/SemaInit.cpp
@@ -6938,11 +6938,11 @@ void InitializationSequence::InitializeFrom(Sema &S,
// For HLSL ext vector types we allow list initialization behavior for C++
// functional cast expressions which look like constructor syntax. This is
// accomplished by converting initialization arguments to InitListExpr.
- bool IsMatToVecOrVecToMatInit =
- Args.size() == 1 &&
+ bool IsHLSLMatToVecOrVecToMatInit =
+ S.getLangOpts().HLSL && Args.size() == 1 &&
((SourceType->isExtVectorType() && DestType->isConstantMatrixType()) ||
(SourceType->isConstantMatrixType() && DestType->isExtVectorType()));
- if (S.getLangOpts().HLSL && (IsMatToVecOrVecToMatInit || Args.size() > 1) &&
+ if (S.getLangOpts().HLSL && (IsHLSLMatToVecOrVecToMatInit || Args.size() > 1) &&
(DestType->isExtVectorType() || DestType->isConstantMatrixType()) &&
(SourceType.isNull() ||
!Context.hasSameUnqualifiedType(SourceType, DestType))) {
>From debf088fa6ed2935369af7c8f0485e23bc9e9c91 Mon Sep 17 00:00:00 2001
From: Deric Cheung <cheung.deric at gmail.com>
Date: Thu, 22 Jan 2026 16:06:36 -0800
Subject: [PATCH 3/9] Fix typo in test
---
clang/test/CodeGenHLSL/MatrixToAndFromVectorConstructors.hlsl | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/clang/test/CodeGenHLSL/MatrixToAndFromVectorConstructors.hlsl b/clang/test/CodeGenHLSL/MatrixToAndFromVectorConstructors.hlsl
index f7a5cae6a22ff..63db8ec9d7763 100644
--- a/clang/test/CodeGenHLSL/MatrixToAndFromVectorConstructors.hlsl
+++ b/clang/test/CodeGenHLSL/MatrixToAndFromVectorConstructors.hlsl
@@ -26,7 +26,7 @@
float4 fn(float2x2 m) {
float4 v = m;
return v;
-m
+}
// CHECK-LABEL: define hidden noundef <2 x i32> @_Z3fn1Dv2_i(
// CHECK-SAME: <2 x i32> noundef [[V:%.*]]) #[[ATTR0]] {
>From cf27db9dc1e116bbdcf12286527772b863dcc366 Mon Sep 17 00:00:00 2001
From: Deric Cheung <cheung.deric at gmail.com>
Date: Thu, 22 Jan 2026 16:07:13 -0800
Subject: [PATCH 4/9] Apply clang-format
---
clang/lib/Sema/SemaInit.cpp | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/clang/lib/Sema/SemaInit.cpp b/clang/lib/Sema/SemaInit.cpp
index b2bdf8e3e9d60..930da8783ab3b 100644
--- a/clang/lib/Sema/SemaInit.cpp
+++ b/clang/lib/Sema/SemaInit.cpp
@@ -6942,7 +6942,8 @@ void InitializationSequence::InitializeFrom(Sema &S,
S.getLangOpts().HLSL && Args.size() == 1 &&
((SourceType->isExtVectorType() && DestType->isConstantMatrixType()) ||
(SourceType->isConstantMatrixType() && DestType->isExtVectorType()));
- if (S.getLangOpts().HLSL && (IsHLSLMatToVecOrVecToMatInit || Args.size() > 1) &&
+ if (S.getLangOpts().HLSL &&
+ (IsHLSLMatToVecOrVecToMatInit || Args.size() > 1) &&
(DestType->isExtVectorType() || DestType->isConstantMatrixType()) &&
(SourceType.isNull() ||
!Context.hasSameUnqualifiedType(SourceType, DestType))) {
>From a9b3464bbeca0f00e1fa4632882da6c270983915 Mon Sep 17 00:00:00 2001
From: Deric Cheung <cheung.deric at gmail.com>
Date: Fri, 23 Jan 2026 14:43:12 -0800
Subject: [PATCH 5/9] Make test try both row and column major order matrices
---
.../MatrixToAndFromVectorConstructors.hlsl | 37 +++++++++++++++++--
1 file changed, 33 insertions(+), 4 deletions(-)
diff --git a/clang/test/CodeGenHLSL/MatrixToAndFromVectorConstructors.hlsl b/clang/test/CodeGenHLSL/MatrixToAndFromVectorConstructors.hlsl
index 63db8ec9d7763..8438d50725a93 100644
--- a/clang/test/CodeGenHLSL/MatrixToAndFromVectorConstructors.hlsl
+++ b/clang/test/CodeGenHLSL/MatrixToAndFromVectorConstructors.hlsl
@@ -1,5 +1,5 @@
-// NOTE: Assertions have been autogenerated by utils/update_cc_test_checks.py UTC_ARGS: --version 6
-// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.0-library -disable-llvm-passes -emit-llvm -finclude-default-header -o - %s | FileCheck %s
+// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.0-library -disable-llvm-passes -emit-llvm -finclude-default-header -o - -fmatrix-memory-layout=column-major %s | FileCheck %s --check-prefixes=CHECK,COL-CHECK
+// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.0-library -disable-llvm-passes -emit-llvm -finclude-default-header -o - -fmatrix-memory-layout=row-major %s | FileCheck %s --check-prefixes=CHECK,ROW-CHECK
// CHECK-LABEL: define hidden noundef nofpclass(nan inf) <4 x float> @_Z2fnu11matrix_typeILm2ELm2EfE(
// CHECK-SAME: <4 x float> noundef nofpclass(nan inf) [[M:%.*]]) #[[ATTR0:[0-9]+]] {
@@ -11,10 +11,12 @@
// CHECK-NEXT: [[MATRIXEXT:%.*]] = extractelement <4 x float> [[TMP0]], i32 0
// CHECK-NEXT: [[VECINIT:%.*]] = insertelement <4 x float> poison, float [[MATRIXEXT]], i32 0
// CHECK-NEXT: [[TMP1:%.*]] = load <4 x float>, ptr [[M_ADDR]], align 4
-// CHECK-NEXT: [[MATRIXEXT1:%.*]] = extractelement <4 x float> [[TMP1]], i32 1
+// COL-CHECK-NEXT: [[MATRIXEXT1:%.*]] = extractelement <4 x float> [[TMP1]], i32 1
+// ROW-CHECK-NEXT: [[MATRIXEXT1:%.*]] = extractelement <4 x float> [[TMP1]], i32 2
// CHECK-NEXT: [[VECINIT2:%.*]] = insertelement <4 x float> [[VECINIT]], float [[MATRIXEXT1]], i32 1
// CHECK-NEXT: [[TMP2:%.*]] = load <4 x float>, ptr [[M_ADDR]], align 4
-// CHECK-NEXT: [[MATRIXEXT3:%.*]] = extractelement <4 x float> [[TMP2]], i32 2
+// COL-CHECK-NEXT: [[MATRIXEXT3:%.*]] = extractelement <4 x float> [[TMP2]], i32 2
+// ROW-CHECK-NEXT: [[MATRIXEXT3:%.*]] = extractelement <4 x float> [[TMP2]], i32 1
// CHECK-NEXT: [[VECINIT4:%.*]] = insertelement <4 x float> [[VECINIT2]], float [[MATRIXEXT3]], i32 2
// CHECK-NEXT: [[TMP3:%.*]] = load <4 x float>, ptr [[M_ADDR]], align 4
// CHECK-NEXT: [[MATRIXEXT5:%.*]] = extractelement <4 x float> [[TMP3]], i32 3
@@ -28,6 +30,33 @@ float4 fn(float2x2 m) {
return v;
}
+// CHECK-LABEL: define hidden noundef <4 x i32> @_Z2fnDv4_i(
+// CHECK-SAME: <4 x i32> noundef [[V:%.*]]) #[[ATTR0:[0-9]+]] {
+// CHECK-NEXT: [[ENTRY:.*:]]
+// CHECK-NEXT: [[V_ADDR:%.*]] = alloca <4 x i32>, align 16
+// CHECK-NEXT: [[M:%.*]] = alloca [4 x i32], align 4
+// CHECK-NEXT: store <4 x i32> [[V]], ptr [[V_ADDR]], align 16
+// CHECK-NEXT: [[TMP0:%.*]] = load <4 x i32>, ptr [[V_ADDR]], align 16
+// CHECK-NEXT: [[VECEXT:%.*]] = extractelement <4 x i32> [[TMP0]], i64 0
+// CHECK-NEXT: [[VECINIT:%.*]] = insertelement <4 x i32> poison, i32 [[VECEXT]], i32 0
+// CHECK-NEXT: [[TMP1:%.*]] = load <4 x i32>, ptr [[V_ADDR]], align 16
+// CHECK-NEXT: [[VECEXT1:%.*]] = extractelement <4 x i32> [[TMP1]], i64 2
+// CHECK-NEXT: [[VECINIT2:%.*]] = insertelement <4 x i32> [[VECINIT]], i32 [[VECEXT1]], i32 1
+// CHECK-NEXT: [[TMP2:%.*]] = load <4 x i32>, ptr [[V_ADDR]], align 16
+// CHECK-NEXT: [[VECEXT3:%.*]] = extractelement <4 x i32> [[TMP2]], i64 1
+// CHECK-NEXT: [[VECINIT4:%.*]] = insertelement <4 x i32> [[VECINIT2]], i32 [[VECEXT3]], i32 2
+// CHECK-NEXT: [[TMP3:%.*]] = load <4 x i32>, ptr [[V_ADDR]], align 16
+// CHECK-NEXT: [[VECEXT5:%.*]] = extractelement <4 x i32> [[TMP3]], i64 3
+// CHECK-NEXT: [[VECINIT6:%.*]] = insertelement <4 x i32> [[VECINIT4]], i32 [[VECEXT5]], i32 3
+// CHECK-NEXT: store <4 x i32> [[VECINIT6]], ptr [[M]], align 4
+// CHECK-NEXT: [[TMP4:%.*]] = load <4 x i32>, ptr [[M]], align 4
+// CHECK-NEXT: ret <4 x i32> [[TMP4]]
+//
+int2x2 fn(int4 v) {
+ int2x2 m = v;
+ return m;
+}
+
// CHECK-LABEL: define hidden noundef <2 x i32> @_Z3fn1Dv2_i(
// CHECK-SAME: <2 x i32> noundef [[V:%.*]]) #[[ATTR0]] {
// CHECK-NEXT: [[ENTRY:.*:]]
>From 74ae3b6f88c832a39a16991222875352d32a192e Mon Sep 17 00:00:00 2001
From: Deric Cheung <cheung.deric at gmail.com>
Date: Mon, 26 Jan 2026 10:24:18 -0800
Subject: [PATCH 6/9] Move test into BasicFeatures folder
---
.../{ => BasicFeatures}/MatrixToAndFromVectorConstructors.hlsl | 0
1 file changed, 0 insertions(+), 0 deletions(-)
rename clang/test/CodeGenHLSL/{ => BasicFeatures}/MatrixToAndFromVectorConstructors.hlsl (100%)
diff --git a/clang/test/CodeGenHLSL/MatrixToAndFromVectorConstructors.hlsl b/clang/test/CodeGenHLSL/BasicFeatures/MatrixToAndFromVectorConstructors.hlsl
similarity index 100%
rename from clang/test/CodeGenHLSL/MatrixToAndFromVectorConstructors.hlsl
rename to clang/test/CodeGenHLSL/BasicFeatures/MatrixToAndFromVectorConstructors.hlsl
>From 6bb3508ab12f65cbff36a3bcea7b22dda7df2008 Mon Sep 17 00:00:00 2001
From: Deric Cheung <cheung.deric at gmail.com>
Date: Mon, 26 Jan 2026 11:08:16 -0800
Subject: [PATCH 7/9] Add new vector-to-matrix sema error tests
---
.../Types/BuiltinMatrix/MatrixSplatErrors.hlsl | 10 ++++++++++
1 file changed, 10 insertions(+)
diff --git a/clang/test/SemaHLSL/Types/BuiltinMatrix/MatrixSplatErrors.hlsl b/clang/test/SemaHLSL/Types/BuiltinMatrix/MatrixSplatErrors.hlsl
index 5a726bb324b60..fc3f8e7adc050 100644
--- a/clang/test/SemaHLSL/Types/BuiltinMatrix/MatrixSplatErrors.hlsl
+++ b/clang/test/SemaHLSL/Types/BuiltinMatrix/MatrixSplatErrors.hlsl
@@ -1,5 +1,15 @@
// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.6-library -finclude-default-header -std=hlsl202x -verify %s
+void SplatOfUndersizedVectortoMat(int3 V){
+ int2x2 M = V;
+ // expected-error at -1 {{too few initializers in list for type 'int2x2' (aka 'matrix<int, 2, 2>') (expected 4 but found 3)}}
+}
+
+void SplatOfOversizedVectortoMat(int3 V){
+ int1x2 M = V;
+ // expected-error at -1 {{too many initializers in list for type 'int1x2' (aka 'matrix<int, 1, 2>') (expected 2 but found 3)}}
+}
+
void SplatOfMattoMat(int4x3 N){
int4x4 M = N;
// expected-error at -1 {{cannot initialize a variable of type 'matrix<[2 * ...], 4>' with an lvalue of type 'matrix<[2 * ...], 3>'}}
>From 8ea17833229b740383a4f65bad724fc72ccad936 Mon Sep 17 00:00:00 2001
From: Deric Cheung <cheung.deric at gmail.com>
Date: Mon, 2 Feb 2026 11:22:04 -0800
Subject: [PATCH 8/9] Fix test after change to matrix initialization list order
in upstream
---
.../BasicFeatures/MatrixToAndFromVectorConstructors.hlsl | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/clang/test/CodeGenHLSL/BasicFeatures/MatrixToAndFromVectorConstructors.hlsl b/clang/test/CodeGenHLSL/BasicFeatures/MatrixToAndFromVectorConstructors.hlsl
index 8438d50725a93..5b1cc2f4bd5c4 100644
--- a/clang/test/CodeGenHLSL/BasicFeatures/MatrixToAndFromVectorConstructors.hlsl
+++ b/clang/test/CodeGenHLSL/BasicFeatures/MatrixToAndFromVectorConstructors.hlsl
@@ -11,12 +11,12 @@
// CHECK-NEXT: [[MATRIXEXT:%.*]] = extractelement <4 x float> [[TMP0]], i32 0
// CHECK-NEXT: [[VECINIT:%.*]] = insertelement <4 x float> poison, float [[MATRIXEXT]], i32 0
// CHECK-NEXT: [[TMP1:%.*]] = load <4 x float>, ptr [[M_ADDR]], align 4
-// COL-CHECK-NEXT: [[MATRIXEXT1:%.*]] = extractelement <4 x float> [[TMP1]], i32 1
-// ROW-CHECK-NEXT: [[MATRIXEXT1:%.*]] = extractelement <4 x float> [[TMP1]], i32 2
+// COL-CHECK-NEXT: [[MATRIXEXT1:%.*]] = extractelement <4 x float> [[TMP1]], i32 2
+// ROW-CHECK-NEXT: [[MATRIXEXT1:%.*]] = extractelement <4 x float> [[TMP1]], i32 1
// CHECK-NEXT: [[VECINIT2:%.*]] = insertelement <4 x float> [[VECINIT]], float [[MATRIXEXT1]], i32 1
// CHECK-NEXT: [[TMP2:%.*]] = load <4 x float>, ptr [[M_ADDR]], align 4
-// COL-CHECK-NEXT: [[MATRIXEXT3:%.*]] = extractelement <4 x float> [[TMP2]], i32 2
-// ROW-CHECK-NEXT: [[MATRIXEXT3:%.*]] = extractelement <4 x float> [[TMP2]], i32 1
+// COL-CHECK-NEXT: [[MATRIXEXT3:%.*]] = extractelement <4 x float> [[TMP2]], i32 1
+// ROW-CHECK-NEXT: [[MATRIXEXT3:%.*]] = extractelement <4 x float> [[TMP2]], i32 2
// CHECK-NEXT: [[VECINIT4:%.*]] = insertelement <4 x float> [[VECINIT2]], float [[MATRIXEXT3]], i32 2
// CHECK-NEXT: [[TMP3:%.*]] = load <4 x float>, ptr [[M_ADDR]], align 4
// CHECK-NEXT: [[MATRIXEXT5:%.*]] = extractelement <4 x float> [[TMP3]], i32 3
>From cf4ee3f42ffeeee928a782e4d0ab77dafb61505a Mon Sep 17 00:00:00 2001
From: Deric Cheung <cheung.deric at gmail.com>
Date: Tue, 17 Feb 2026 14:47:02 -0800
Subject: [PATCH 9/9] Replace complex boolean expression with a boolean lambda
expression with early returns
---
clang/lib/Sema/SemaInit.cpp | 42 +++++++++++++++++++++++++++++--------
1 file changed, 33 insertions(+), 9 deletions(-)
diff --git a/clang/lib/Sema/SemaInit.cpp b/clang/lib/Sema/SemaInit.cpp
index 930da8783ab3b..2e705a6c50be7 100644
--- a/clang/lib/Sema/SemaInit.cpp
+++ b/clang/lib/Sema/SemaInit.cpp
@@ -6938,15 +6938,39 @@ void InitializationSequence::InitializeFrom(Sema &S,
// For HLSL ext vector types we allow list initialization behavior for C++
// functional cast expressions which look like constructor syntax. This is
// accomplished by converting initialization arguments to InitListExpr.
- bool IsHLSLMatToVecOrVecToMatInit =
- S.getLangOpts().HLSL && Args.size() == 1 &&
- ((SourceType->isExtVectorType() && DestType->isConstantMatrixType()) ||
- (SourceType->isConstantMatrixType() && DestType->isExtVectorType()));
- if (S.getLangOpts().HLSL &&
- (IsHLSLMatToVecOrVecToMatInit || Args.size() > 1) &&
- (DestType->isExtVectorType() || DestType->isConstantMatrixType()) &&
- (SourceType.isNull() ||
- !Context.hasSameUnqualifiedType(SourceType, DestType))) {
+ auto ShouldTryListInitialization = [&]() -> bool {
+ // Only try list initialization for HLSL.
+ if (!S.getLangOpts().HLSL)
+ return false;
+
+ bool DestIsVec = DestType->isExtVectorType();
+ bool DestIsMat = DestType->isConstantMatrixType();
+
+ // If the destination type is neither a vector nor a matrix, then don't try
+ // list initialization.
+ if (!DestIsVec && !DestIsMat)
+ return false;
+
+ // If there is only a single source argument, then only try list
+ // initialization if initializing a matrix with a vector or vice versa.
+ if (Args.size() == 1) {
+ assert(!SourceType.isNull() &&
+ "Source QualType should not be null when arg size is exactly 1");
+ bool SourceIsVec = SourceType->isExtVectorType();
+ bool SourceIsMat = SourceType->isConstantMatrixType();
+
+ if (DestIsMat && !SourceIsVec)
+ return false;
+ if (DestIsVec && !SourceIsMat)
+ return false;
+ }
+
+ // Try list initialization if the source type is null or if the
+ // destination and source types differ.
+ return SourceType.isNull() ||
+ !Context.hasSameUnqualifiedType(SourceType, DestType);
+ };
+ if (ShouldTryListInitialization()) {
InitListExpr *ILE = new (Context)
InitListExpr(S.getASTContext(), Args.front()->getBeginLoc(), Args,
Args.back()->getEndLoc());
More information about the cfe-commits
mailing list