[clang] [Clang][HLSL] Emit constant matrix values in column-major order (PR #227356)

Farzon Lotfi via cfe-commits cfe-commits at lists.llvm.org
Tue Sep 29 16:52:05 PDT 2026


https://github.com/farzonl updated https://github.com/llvm/llvm-project/pull/227356

>From 3df3c47023e53f62ee7f92415eef8e2c4a46f14f Mon Sep 17 00:00:00 2001
From: Farzon Lotfi <farzonlotfi at microsoft.com>
Date: Tue, 29 Sep 2026 11:48:59 -0400
Subject: [PATCH 1/4] Clang][HLSL] Emit constant matrix values in column-major
 order

Emit matrix APValues in the canonical column-major register layout,
independent of the selected matrix memory layout.

When a constant is used as a row-major memory initializer, reorder its
elements at the register-to-memory boundary. This preserves the physical
layout of global and static row-major matrices while ensuring constexpr
matrix expressions produce canonical register values.

Assisted by Cop-pilot GPT 5.6-Sol
---
 clang/lib/CodeGen/CGExprConstant.cpp              | 15 ++++++++++++---
 .../BasicFeatures/MatrixInitializerListOrder.hlsl | 11 +++++++++++
 2 files changed, 23 insertions(+), 3 deletions(-)

diff --git a/clang/lib/CodeGen/CGExprConstant.cpp b/clang/lib/CodeGen/CGExprConstant.cpp
index 3d8fefb4988b79..917be246b7346c 100644
--- a/clang/lib/CodeGen/CGExprConstant.cpp
+++ b/clang/lib/CodeGen/CGExprConstant.cpp
@@ -2087,6 +2087,17 @@ llvm::Constant *ConstantEmitter::emitForMemory(CodeGenModule &CGM,
     }
   }
 
+  if (destType->isConstantMatrixType() &&
+      isMatrixRowMajor(CGM.getLangOpts(), destType)) {
+    const auto *MT = destType->castAs<ConstantMatrixType>();
+    SmallVector<llvm::Constant *, 16> Inits(MT->getNumElementsFlattened());
+    for (unsigned Row = 0; Row != MT->getNumRows(); ++Row)
+      for (unsigned Col = 0; Col != MT->getNumColumns(); ++Col)
+        Inits[MT->getRowMajorFlattenedIndex(Row, Col)] =
+            C->getAggregateElement(MT->getColumnMajorFlattenedIndex(Row, Col));
+    return llvm::ConstantVector::get(Inits);
+  }
+
   return C;
 }
 
@@ -2667,12 +2678,10 @@ ConstantEmitter::tryEmitPrivate(const APValue &Value, QualType DestType,
     unsigned NumElts = NumRows * NumCols;
     SmallVector<llvm::Constant *, 16> Inits(NumElts);
 
-    bool IsRowMajor = isMatrixRowMajor(CGM.getLangOpts(), DestType);
-
     for (unsigned Row = 0; Row != NumRows; ++Row) {
       for (unsigned Col = 0; Col != NumCols; ++Col) {
         const APValue &Elt = Value.getMatrixElt(Row, Col);
-        unsigned Idx = MT->getFlattenedIndex(Row, Col, IsRowMajor);
+        unsigned Idx = MT->getColumnMajorFlattenedIndex(Row, Col);
         if (Elt.isInt())
           Inits[Idx] =
               llvm::ConstantInt::get(CGM.getLLVMContext(), Elt.getInt());
diff --git a/clang/test/CodeGenHLSL/BasicFeatures/MatrixInitializerListOrder.hlsl b/clang/test/CodeGenHLSL/BasicFeatures/MatrixInitializerListOrder.hlsl
index 97ebe1712e9c76..d5879d7cdd5b49 100644
--- a/clang/test/CodeGenHLSL/BasicFeatures/MatrixInitializerListOrder.hlsl
+++ b/clang/test/CodeGenHLSL/BasicFeatures/MatrixInitializerListOrder.hlsl
@@ -11,6 +11,17 @@
 // The register value is reordered to col0=[1,4], col1=[2,5], col2=[3,6] =
 // <1,4,2,5,3,6>. Row-major memory layout transposes that value at the store.
 
+constexpr float2x3 make_matrix() {
+  return float2x3(1, 2, 3, 4, 5, 6);
+}
+
+export float2x3 return_constexpr_matrix() {
+// CHECK-LABEL: define {{.*}} <6 x float> @_Z23return_constexpr_matrixv
+// CHECK: ret <6 x float> <float 1.000000e+00, float 4.000000e+00, float 2.000000e+00, float 5.000000e+00, float 3.000000e+00, float 6.000000e+00>
+  constexpr float2x3 value = make_matrix();
+  return value;
+}
+
 export float test_row0_col2() {
 // CHECK-LABEL: define {{.*}} float @_Z14test_row0_col2v
 // COL-CHECK: store <6 x float> <float 1.000000e+00, float 4.000000e+00, float 2.000000e+00, float 5.000000e+00, float 3.000000e+00, float 6.000000e+00>

>From e9b2055ab815f78e77b76194ff7942a98d23e45e Mon Sep 17 00:00:00 2001
From: Farzon Lotfi <farzonlotfi at microsoft.com>
Date: Tue, 29 Sep 2026 17:22:51 -0400
Subject: [PATCH 2/4] add suport for hlsl bool matrix types mem layout
 loads\stores

---
 clang/lib/CodeGen/CGExprConstant.cpp                |  6 +++++-
 clang/lib/CodeGen/CodeGenTypes.cpp                  |  2 +-
 .../BasicFeatures/MatrixInitializerListOrder.hlsl   | 13 +++++++++++++
 3 files changed, 19 insertions(+), 2 deletions(-)

diff --git a/clang/lib/CodeGen/CGExprConstant.cpp b/clang/lib/CodeGen/CGExprConstant.cpp
index 917be246b7346c..312c6282978d87 100644
--- a/clang/lib/CodeGen/CGExprConstant.cpp
+++ b/clang/lib/CodeGen/CGExprConstant.cpp
@@ -2095,7 +2095,11 @@ llvm::Constant *ConstantEmitter::emitForMemory(CodeGenModule &CGM,
       for (unsigned Col = 0; Col != MT->getNumColumns(); ++Col)
         Inits[MT->getRowMajorFlattenedIndex(Row, Col)] =
             C->getAggregateElement(MT->getColumnMajorFlattenedIndex(Row, Col));
-    return llvm::ConstantVector::get(Inits);
+    llvm::Constant *MemoryValue = llvm::ConstantVector::get(Inits);
+    if (CGM.getLangOpts().HLSL && destType->isConstantMatrixBoolType())
+      return llvm::ConstantExpr::getZExt(
+          MemoryValue, CGM.getTypes().convertTypeForLoadStore(destType));
+    return MemoryValue;
   }
 
   return C;
diff --git a/clang/lib/CodeGen/CodeGenTypes.cpp b/clang/lib/CodeGen/CodeGenTypes.cpp
index 999867e5e40cec..4430f2885c5482 100644
--- a/clang/lib/CodeGen/CodeGenTypes.cpp
+++ b/clang/lib/CodeGen/CodeGenTypes.cpp
@@ -195,7 +195,7 @@ llvm::Type *CodeGenTypes::convertTypeForLoadStore(QualType T,
     return llvm::IntegerType::get(getLLVMContext(),
                                   (unsigned)Context.getTypeSize(T));
 
-  if (T->isConstantMatrixBoolType()) {
+  if (Context.getLangOpts().HLSL && T->isConstantMatrixBoolType()) {
     // Matrices are loaded and stored atomically as vectors. Therefore we
     // construct a FixedVectorType here instead of returning
     // ConvertTypeForMem(T) which would return an ArrayType instead.
diff --git a/clang/test/CodeGenHLSL/BasicFeatures/MatrixInitializerListOrder.hlsl b/clang/test/CodeGenHLSL/BasicFeatures/MatrixInitializerListOrder.hlsl
index d5879d7cdd5b49..b659cb43be975e 100644
--- a/clang/test/CodeGenHLSL/BasicFeatures/MatrixInitializerListOrder.hlsl
+++ b/clang/test/CodeGenHLSL/BasicFeatures/MatrixInitializerListOrder.hlsl
@@ -15,6 +15,19 @@ constexpr float2x3 make_matrix() {
   return float2x3(1, 2, 3, 4, 5, 6);
 }
 
+// Bool matrices use i1 elements in registers and i32 elements in memory.
+// CHECK: @_ZL1B = internal global <6 x i32> <i32 1, i32 0, i32 1, i32 0, i32 1, i32 0>
+static row_major bool2x3 B =
+    bool2x3(true, false, true, false, true, false);
+
+export bool read_bool_matrix() {
+// CHECK-LABEL: define {{.*}} i1 @_Z16read_bool_matrixv
+// CHECK: [[FROM_MEMORY:%.*]] = load <6 x i32>, ptr @_ZL1B
+// CHECK: [[IN_REGISTER:%.*]] = call <6 x i32> @llvm.matrix.transpose.v6i32(<6 x i32> [[FROM_MEMORY]], i32 3, i32 2)
+// CHECK: extractelement <6 x i32> [[IN_REGISTER]], i32 3
+  return B[1][1];
+}
+
 export float2x3 return_constexpr_matrix() {
 // CHECK-LABEL: define {{.*}} <6 x float> @_Z23return_constexpr_matrixv
 // CHECK: ret <6 x float> <float 1.000000e+00, float 4.000000e+00, float 2.000000e+00, float 5.000000e+00, float 3.000000e+00, float 6.000000e+00>

>From d9f29fe3ef9e4b17d512973e86cec6867df1483e Mon Sep 17 00:00:00 2001
From: Farzon Lotfi <farzonlotfi at microsoft.com>
Date: Tue, 29 Sep 2026 17:29:37 -0400
Subject: [PATCH 3/4] ConvertTypeForMem already does the hlsl lang opt check
 fix test run issue

---
 clang/lib/CodeGen/CGExprConstant.cpp                  | 11 ++++++++---
 clang/lib/CodeGen/CodeGenTypes.cpp                    |  2 +-
 .../BasicFeatures/MatrixInitializerListOrder.hlsl     |  4 ++--
 3 files changed, 11 insertions(+), 6 deletions(-)

diff --git a/clang/lib/CodeGen/CGExprConstant.cpp b/clang/lib/CodeGen/CGExprConstant.cpp
index 312c6282978d87..4d8bd7ab382040 100644
--- a/clang/lib/CodeGen/CGExprConstant.cpp
+++ b/clang/lib/CodeGen/CGExprConstant.cpp
@@ -2096,9 +2096,14 @@ llvm::Constant *ConstantEmitter::emitForMemory(CodeGenModule &CGM,
         Inits[MT->getRowMajorFlattenedIndex(Row, Col)] =
             C->getAggregateElement(MT->getColumnMajorFlattenedIndex(Row, Col));
     llvm::Constant *MemoryValue = llvm::ConstantVector::get(Inits);
-    if (CGM.getLangOpts().HLSL && destType->isConstantMatrixBoolType())
-      return llvm::ConstantExpr::getZExt(
-          MemoryValue, CGM.getTypes().convertTypeForLoadStore(destType));
+    if (destType->isConstantMatrixBoolType()) {
+      llvm::Constant *Res = llvm::ConstantFoldCastOperand(
+          llvm::Instruction::ZExt, MemoryValue,
+          CGM.getTypes().convertTypeForLoadStore(destType),
+          CGM.getDataLayout());
+      assert(Res && "Constant folding must succeed");
+      return Res;
+    }
     return MemoryValue;
   }
 
diff --git a/clang/lib/CodeGen/CodeGenTypes.cpp b/clang/lib/CodeGen/CodeGenTypes.cpp
index 4430f2885c5482..999867e5e40cec 100644
--- a/clang/lib/CodeGen/CodeGenTypes.cpp
+++ b/clang/lib/CodeGen/CodeGenTypes.cpp
@@ -195,7 +195,7 @@ llvm::Type *CodeGenTypes::convertTypeForLoadStore(QualType T,
     return llvm::IntegerType::get(getLLVMContext(),
                                   (unsigned)Context.getTypeSize(T));
 
-  if (Context.getLangOpts().HLSL && T->isConstantMatrixBoolType()) {
+  if (T->isConstantMatrixBoolType()) {
     // Matrices are loaded and stored atomically as vectors. Therefore we
     // construct a FixedVectorType here instead of returning
     // ConvertTypeForMem(T) which would return an ArrayType instead.
diff --git a/clang/test/CodeGenHLSL/BasicFeatures/MatrixInitializerListOrder.hlsl b/clang/test/CodeGenHLSL/BasicFeatures/MatrixInitializerListOrder.hlsl
index b659cb43be975e..5f7384fb5e4976 100644
--- a/clang/test/CodeGenHLSL/BasicFeatures/MatrixInitializerListOrder.hlsl
+++ b/clang/test/CodeGenHLSL/BasicFeatures/MatrixInitializerListOrder.hlsl
@@ -1,8 +1,8 @@
 // RUN: %clang_cc1 -triple dxil-pc-shadermodel6.0-library -disable-llvm-passes \
-// RUN:   -emit-llvm -finclude-default-header -o - %s | FileCheck %s --check-prefix=CHECK,COL-CHECK
+// RUN:   -emit-llvm -finclude-default-header -o - %s | FileCheck %s --check-prefixes=CHECK,COL-CHECK
 // RUN: %clang_cc1 -triple dxil-pc-shadermodel6.0-library -disable-llvm-passes \
 // RUN:   -emit-llvm -finclude-default-header -fmatrix-memory-layout=row-major -o - %s \
-// RUN:   | FileCheck %s --check-prefix=CHECK,ROW-CHECK
+// RUN:   | FileCheck %s --check-prefixes=CHECK,ROW-CHECK
 
 // Verify that matrix initializer lists produce values in canonical column-major
 // register layout. The initializer list {1,2,3,4,5,6} for a float2x3 (2 rows,

>From 5e669de19e49ef1e8189d0a1cbce6d63bf74a87c Mon Sep 17 00:00:00 2001
From: Farzon Lotfi <farzonlotfi at microsoft.com>
Date: Tue, 29 Sep 2026 19:51:35 -0400
Subject: [PATCH 4/4] fix tests pst bool mat changes

---
 .../BasicFeatures/MatrixInitializerListOrder.hlsl            | 5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)

diff --git a/clang/test/CodeGenHLSL/BasicFeatures/MatrixInitializerListOrder.hlsl b/clang/test/CodeGenHLSL/BasicFeatures/MatrixInitializerListOrder.hlsl
index 5f7384fb5e4976..0e972ff83ae8fd 100644
--- a/clang/test/CodeGenHLSL/BasicFeatures/MatrixInitializerListOrder.hlsl
+++ b/clang/test/CodeGenHLSL/BasicFeatures/MatrixInitializerListOrder.hlsl
@@ -23,8 +23,9 @@ static row_major bool2x3 B =
 export bool read_bool_matrix() {
 // CHECK-LABEL: define {{.*}} i1 @_Z16read_bool_matrixv
 // CHECK: [[FROM_MEMORY:%.*]] = load <6 x i32>, ptr @_ZL1B
-// CHECK: [[IN_REGISTER:%.*]] = call <6 x i32> @llvm.matrix.transpose.v6i32(<6 x i32> [[FROM_MEMORY]], i32 3, i32 2)
-// CHECK: extractelement <6 x i32> [[IN_REGISTER]], i32 3
+// CHECK: [[AS_BOOL:%.*]] = icmp ne <6 x i32> [[FROM_MEMORY]], zeroinitializer
+// CHECK: [[IN_REGISTER:%.*]] = call <6 x i1> @llvm.matrix.transpose.v6i1(<6 x i1> [[AS_BOOL]], i32 3, i32 2)
+// CHECK: extractelement <6 x i1> [[IN_REGISTER]], i32 3
   return B[1][1];
 }
 



More information about the cfe-commits mailing list