[clang] [HLSL][Matrix] Add Matrix Bool and represent them as i32 elements (PR #171051)
Farzon Lotfi via cfe-commits
cfe-commits at lists.llvm.org
Wed Dec 10 20:45:55 PST 2025
https://github.com/farzonl updated https://github.com/llvm/llvm-project/pull/171051
>From b36e6944e0d50bb2fc2c9019338eb1765e8848ff Mon Sep 17 00:00:00 2001
From: Farzon Lotfi <farzonlotfi at microsoft.com>
Date: Sun, 7 Dec 2025 13:31:16 -0500
Subject: [PATCH 1/3] [HLSL][Matrix] Add Matrix Bool and represent them as i32
elements
fixes #171049
fixes #171050
- Allow Bools for matrix type when in HLSL mode
- use ConvertTypeForMem to figure out the bool size
- Add Bool matrix types to hlsl_basic_types.h
---
clang/include/clang/AST/TypeBase.h | 31 ++++-
clang/lib/AST/ASTContext.cpp | 2 +-
clang/lib/CodeGen/CGExpr.cpp | 7 +-
clang/lib/CodeGen/CodeGenTypes.cpp | 5 +-
clang/lib/Headers/hlsl/hlsl_basic_types.h | 17 +++
clang/lib/Sema/SemaChecking.cpp | 4 +-
clang/lib/Sema/SemaType.cpp | 2 +-
clang/test/CodeGenHLSL/BoolMatrix.hlsl | 151 ++++++++++++++++++++++
clang/test/CodeGenHLSL/basic_types.hlsl | 33 +++++
9 files changed, 242 insertions(+), 10 deletions(-)
create mode 100644 clang/test/CodeGenHLSL/BoolMatrix.hlsl
diff --git a/clang/include/clang/AST/TypeBase.h b/clang/include/clang/AST/TypeBase.h
index 30b9efe5a31b7..cf6897b6e515c 100644
--- a/clang/include/clang/AST/TypeBase.h
+++ b/clang/include/clang/AST/TypeBase.h
@@ -2637,6 +2637,7 @@ class alignas(TypeAlignment) Type : public ExtQualsTypeCommonBase {
bool isVectorType() const; // GCC vector type.
bool isExtVectorType() const; // Extended vector type.
bool isExtVectorBoolType() const; // Extended vector type with bool element.
+ bool isConstantMatrixBoolType() const; // Matrix type with bool element.
// Extended vector type with bool element that is packed. HLSL doesn't pack
// its bool vectors.
bool isPackedVectorBoolType(const ASTContext &ctx) const;
@@ -4352,12 +4353,26 @@ class MatrixType : public Type, public llvm::FoldingSetNode {
/// Valid elements types are the following:
/// * an integer type (as in C23 6.2.5p22), but excluding enumerated types
- /// and _Bool
+ /// and _Bool (except that in HLSL, bool is allowed)
/// * the standard floating types float or double
/// * a half-precision floating point type, if one is supported on the target
- static bool isValidElementType(QualType T) {
- return T->isDependentType() ||
- (T->isRealType() && !T->isBooleanType() && !T->isEnumeralType());
+ static bool isValidElementType(QualType T, const LangOptions &LangOpts) {
+ // Dependent is always okay
+ if (T->isDependentType())
+ return true;
+
+ // Enums are never okay
+ if (T->isEnumeralType())
+ return false;
+
+ // In HLSL, bool is allowed as a matrix element type.
+ // Note: isRealType includes bool so don't need to check
+ if (LangOpts.HLSL)
+ return T->isRealType();
+
+ // In non-HLSL modes, follow the existing rule:
+ // real type, but not _Bool.
+ return T->isRealType() && !T->isBooleanType();
}
bool isSugared() const { return false; }
@@ -8665,6 +8680,14 @@ inline bool Type::isExtVectorBoolType() const {
return cast<ExtVectorType>(CanonicalType)->getElementType()->isBooleanType();
}
+inline bool Type::isConstantMatrixBoolType() const {
+ if (!isConstantMatrixType())
+ return false;
+ return cast<ConstantMatrixType>(CanonicalType)
+ ->getElementType()
+ ->isBooleanType();
+}
+
inline bool Type::isSubscriptableVectorType() const {
return isVectorType() || isSveVLSBuiltinType();
}
diff --git a/clang/lib/AST/ASTContext.cpp b/clang/lib/AST/ASTContext.cpp
index 404ce3ffd77c7..5ca76c79df7c6 100644
--- a/clang/lib/AST/ASTContext.cpp
+++ b/clang/lib/AST/ASTContext.cpp
@@ -4712,7 +4712,7 @@ QualType ASTContext::getConstantMatrixType(QualType ElementTy, unsigned NumRows,
ConstantMatrixType::Profile(ID, ElementTy, NumRows, NumColumns,
Type::ConstantMatrix);
- assert(MatrixType::isValidElementType(ElementTy) &&
+ assert(MatrixType::isValidElementType(ElementTy, getLangOpts()) &&
"need a valid element type");
assert(NumRows > 0 && NumRows <= LangOpts.MaxMatrixDimension &&
NumColumns > 0 && NumColumns <= LangOpts.MaxMatrixDimension &&
diff --git a/clang/lib/CodeGen/CGExpr.cpp b/clang/lib/CodeGen/CGExpr.cpp
index 3bde8e1fa2ac3..b44c1a7d18120 100644
--- a/clang/lib/CodeGen/CGExpr.cpp
+++ b/clang/lib/CodeGen/CGExpr.cpp
@@ -2655,8 +2655,13 @@ void CodeGenFunction::EmitStoreThroughLValue(RValue Src, LValue Dst,
MB.CreateIndexAssumption(Idx, MatTy->getNumElementsFlattened());
}
llvm::Instruction *Load = Builder.CreateLoad(Dst.getMatrixAddress());
+ llvm::Value *InsertVal = Src.getScalarVal();
+ if (getLangOpts().HLSL && InsertVal->getType()->isIntegerTy(1)) {
+ llvm::Type *StorageElmTy = Load->getType()->getScalarType();
+ InsertVal = Builder.CreateZExt(InsertVal, StorageElmTy);
+ }
llvm::Value *Vec =
- Builder.CreateInsertElement(Load, Src.getScalarVal(), Idx, "matins");
+ Builder.CreateInsertElement(Load, InsertVal, Idx, "matins");
auto *I = Builder.CreateStore(Vec, Dst.getMatrixAddress(),
Dst.isVolatileQualified());
addInstToCurrentSourceAtom(I, Vec);
diff --git a/clang/lib/CodeGen/CodeGenTypes.cpp b/clang/lib/CodeGen/CodeGenTypes.cpp
index be862cf07f177..a41bf86d6f95c 100644
--- a/clang/lib/CodeGen/CodeGenTypes.cpp
+++ b/clang/lib/CodeGen/CodeGenTypes.cpp
@@ -104,7 +104,10 @@ llvm::Type *CodeGenTypes::ConvertTypeForMem(QualType T) {
if (T->isConstantMatrixType()) {
const Type *Ty = Context.getCanonicalType(T).getTypePtr();
const ConstantMatrixType *MT = cast<ConstantMatrixType>(Ty);
- return llvm::ArrayType::get(ConvertType(MT->getElementType()),
+ llvm::Type *IRElemTy = ConvertType(MT->getElementType());
+ if (T->isConstantMatrixBoolType() && Context.getLangOpts().HLSL)
+ IRElemTy = ConvertTypeForMem(Context.BoolTy);
+ return llvm::ArrayType::get(IRElemTy,
MT->getNumRows() * MT->getNumColumns());
}
diff --git a/clang/lib/Headers/hlsl/hlsl_basic_types.h b/clang/lib/Headers/hlsl/hlsl_basic_types.h
index fc1e265067714..b1d87c51de9bb 100644
--- a/clang/lib/Headers/hlsl/hlsl_basic_types.h
+++ b/clang/lib/Headers/hlsl/hlsl_basic_types.h
@@ -150,6 +150,23 @@ typedef matrix<uint16_t, 4, 3> uint16_t4x3;
typedef matrix<uint16_t, 4, 4> uint16_t4x4;
#endif
+typedef matrix<bool, 1, 1> bool1x1;
+typedef matrix<bool, 1, 2> bool1x2;
+typedef matrix<bool, 1, 3> bool1x3;
+typedef matrix<bool, 1, 4> bool1x4;
+typedef matrix<bool, 2, 1> bool2x1;
+typedef matrix<bool, 2, 2> bool2x2;
+typedef matrix<bool, 2, 3> bool2x3;
+typedef matrix<bool, 2, 4> bool2x4;
+typedef matrix<bool, 3, 1> bool3x1;
+typedef matrix<bool, 3, 2> bool3x2;
+typedef matrix<bool, 3, 3> bool3x3;
+typedef matrix<bool, 3, 4> bool3x4;
+typedef matrix<bool, 4, 1> bool4x1;
+typedef matrix<bool, 4, 2> bool4x2;
+typedef matrix<bool, 4, 3> bool4x3;
+typedef matrix<bool, 4, 4> bool4x4;
+
typedef matrix<int, 1, 1> int1x1;
typedef matrix<int, 1, 2> int1x2;
typedef matrix<int, 1, 3> int1x3;
diff --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp
index 02c838bc4a862..bdf2e08400801 100644
--- a/clang/lib/Sema/SemaChecking.cpp
+++ b/clang/lib/Sema/SemaChecking.cpp
@@ -2145,7 +2145,7 @@ checkMathBuiltinElementType(Sema &S, SourceLocation Loc, QualType ArgTy,
switch (ArgTyRestr) {
case Sema::EltwiseBuiltinArgTyRestriction::None:
if (!ArgTy->getAs<VectorType>() &&
- !ConstantMatrixType::isValidElementType(ArgTy)) {
+ !ConstantMatrixType::isValidElementType(ArgTy, S.getLangOpts())) {
return S.Diag(Loc, diag::err_builtin_invalid_arg_type)
<< ArgOrdinal << /* vector */ 2 << /* integer */ 1 << /* fp */ 1
<< ArgTy;
@@ -16545,7 +16545,7 @@ ExprResult Sema::BuiltinMatrixColumnMajorLoad(CallExpr *TheCall,
} else {
ElementTy = PtrTy->getPointeeType().getUnqualifiedType();
- if (!ConstantMatrixType::isValidElementType(ElementTy)) {
+ if (!ConstantMatrixType::isValidElementType(ElementTy, getLangOpts())) {
Diag(PtrExpr->getBeginLoc(), diag::err_builtin_invalid_arg_type)
<< PtrArgIdx + 1 << 0 << /* pointer to element ty */ 5
<< /* no fp */ 0 << PtrExpr->getType();
diff --git a/clang/lib/Sema/SemaType.cpp b/clang/lib/Sema/SemaType.cpp
index fd64d4456cbfa..7ef83433326ed 100644
--- a/clang/lib/Sema/SemaType.cpp
+++ b/clang/lib/Sema/SemaType.cpp
@@ -2467,7 +2467,7 @@ QualType Sema::BuildMatrixType(QualType ElementTy, Expr *NumRows, Expr *NumCols,
// Check element type, if it is not dependent.
if (!ElementTy->isDependentType() &&
- !MatrixType::isValidElementType(ElementTy)) {
+ !MatrixType::isValidElementType(ElementTy, getLangOpts())) {
Diag(AttrLoc, diag::err_attribute_invalid_matrix_type) << ElementTy;
return QualType();
}
diff --git a/clang/test/CodeGenHLSL/BoolMatrix.hlsl b/clang/test/CodeGenHLSL/BoolMatrix.hlsl
new file mode 100644
index 0000000000000..da90738b68b96
--- /dev/null
+++ b/clang/test/CodeGenHLSL/BoolMatrix.hlsl
@@ -0,0 +1,151 @@
+// NOTE: Assertions have been autogenerated by utils/update_cc_test_checks.py UTC_ARGS: --version 6
+// RUN: %clang_cc1 -finclude-default-header -triple dxil-pc-shadermodel6.3-library -emit-llvm -disable-llvm-passes -o - %s | FileCheck %s
+
+
+struct S {
+ bool2x2 bM;
+ float f;
+};
+
+// CHECK-LABEL: define hidden noundef i1 @_Z3fn1v(
+// CHECK-SAME: ) #[[ATTR0:[0-9]+]] {
+// CHECK-NEXT: [[ENTRY:.*:]]
+// CHECK-NEXT: [[RETVAL:%.*]] = alloca i1, align 4
+// CHECK-NEXT: [[B:%.*]] = alloca [4 x i32], align 4
+// CHECK-NEXT: store <4 x i1> splat (i1 true), ptr [[B]], align 4
+// CHECK-NEXT: [[TMP0:%.*]] = load <4 x i32>, ptr [[B]], align 4
+// CHECK-NEXT: [[MATRIXEXT:%.*]] = extractelement <4 x i32> [[TMP0]], i32 0
+// CHECK-NEXT: store i32 [[MATRIXEXT]], ptr [[RETVAL]], align 4
+// CHECK-NEXT: [[TMP1:%.*]] = load i1, ptr [[RETVAL]], align 4
+// CHECK-NEXT: ret i1 [[TMP1]]
+//
+bool fn1() {
+ bool2x2 B = {true,true,true,true};
+ return B[0][0];
+}
+
+// CHECK-LABEL: define hidden noundef <4 x i1> @_Z3fn2b(
+// CHECK-SAME: i1 noundef [[V:%.*]]) #[[ATTR0]] {
+// CHECK-NEXT: [[ENTRY:.*:]]
+// CHECK-NEXT: [[RETVAL:%.*]] = alloca <4 x i1>, align 4
+// CHECK-NEXT: [[V_ADDR:%.*]] = alloca i32, align 4
+// CHECK-NEXT: [[A:%.*]] = alloca [4 x i32], align 4
+// CHECK-NEXT: [[STOREDV:%.*]] = zext i1 [[V]] to i32
+// CHECK-NEXT: store i32 [[STOREDV]], ptr [[V_ADDR]], align 4
+// CHECK-NEXT: [[TMP0:%.*]] = load i32, ptr [[V_ADDR]], align 4
+// CHECK-NEXT: [[LOADEDV:%.*]] = trunc i32 [[TMP0]] to i1
+// CHECK-NEXT: [[VECINIT:%.*]] = insertelement <4 x i1> poison, i1 [[LOADEDV]], i32 0
+// CHECK-NEXT: [[TMP1:%.*]] = load i32, ptr [[V_ADDR]], align 4
+// CHECK-NEXT: [[LOADEDV1:%.*]] = trunc i32 [[TMP1]] to i1
+// CHECK-NEXT: [[VECINIT2:%.*]] = insertelement <4 x i1> [[VECINIT]], i1 [[LOADEDV1]], i32 1
+// CHECK-NEXT: [[VECINIT3:%.*]] = insertelement <4 x i1> [[VECINIT2]], i1 true, i32 2
+// CHECK-NEXT: [[VECINIT4:%.*]] = insertelement <4 x i1> [[VECINIT3]], i1 false, i32 3
+// CHECK-NEXT: store <4 x i1> [[VECINIT4]], ptr [[A]], align 4
+// CHECK-NEXT: [[TMP2:%.*]] = load <4 x i32>, ptr [[A]], align 4
+// CHECK-NEXT: store <4 x i32> [[TMP2]], ptr [[RETVAL]], align 4
+// CHECK-NEXT: [[TMP3:%.*]] = load <4 x i1>, ptr [[RETVAL]], align 4
+// CHECK-NEXT: ret <4 x i1> [[TMP3]]
+//
+bool2x2 fn2(bool V) {
+ bool2x2 A = {V, true, V, false};
+ return A;
+}
+
+// CHECK-LABEL: define hidden noundef i1 @_Z3fn3v(
+// CHECK-SAME: ) #[[ATTR0]] {
+// CHECK-NEXT: [[ENTRY:.*:]]
+// CHECK-NEXT: [[RETVAL:%.*]] = alloca i1, align 4
+// CHECK-NEXT: [[S:%.*]] = alloca [[STRUCT_S:%.*]], align 1
+// CHECK-NEXT: [[BM:%.*]] = getelementptr inbounds nuw [[STRUCT_S]], ptr [[S]], i32 0, i32 0
+// CHECK-NEXT: store <4 x i1> <i1 true, i1 false, i1 true, i1 false>, ptr [[BM]], align 1
+// CHECK-NEXT: [[F:%.*]] = getelementptr inbounds nuw [[STRUCT_S]], ptr [[S]], i32 0, i32 1
+// CHECK-NEXT: store float 1.000000e+00, ptr [[F]], align 1
+// CHECK-NEXT: [[BM1:%.*]] = getelementptr inbounds nuw [[STRUCT_S]], ptr [[S]], i32 0, i32 0
+// CHECK-NEXT: [[TMP0:%.*]] = load <4 x i32>, ptr [[BM1]], align 1
+// CHECK-NEXT: [[MATRIXEXT:%.*]] = extractelement <4 x i32> [[TMP0]], i32 0
+// CHECK-NEXT: store i32 [[MATRIXEXT]], ptr [[RETVAL]], align 4
+// CHECK-NEXT: [[TMP1:%.*]] = load i1, ptr [[RETVAL]], align 4
+// CHECK-NEXT: ret i1 [[TMP1]]
+//
+bool fn3() {
+ S s = {{true,true, false, false}, 1.0};
+ return s.bM[0][0];
+}
+
+// CHECK-LABEL: define hidden noundef i1 @_Z3fn4v(
+// CHECK-SAME: ) #[[ATTR0]] {
+// CHECK-NEXT: [[ENTRY:.*:]]
+// CHECK-NEXT: [[RETVAL:%.*]] = alloca i1, align 4
+// CHECK-NEXT: [[ARR:%.*]] = alloca [2 x [4 x i32]], align 4
+// CHECK-NEXT: store <4 x i1> splat (i1 true), ptr [[ARR]], align 4
+// CHECK-NEXT: [[ARRAYINIT_ELEMENT:%.*]] = getelementptr inbounds [4 x i32], ptr [[ARR]], i32 1
+// CHECK-NEXT: store <4 x i1> zeroinitializer, ptr [[ARRAYINIT_ELEMENT]], align 4
+// CHECK-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds [2 x [4 x i32]], ptr [[ARR]], i32 0, i32 0
+// CHECK-NEXT: [[TMP0:%.*]] = load <4 x i32>, ptr [[ARRAYIDX]], align 4
+// CHECK-NEXT: [[MATRIXEXT:%.*]] = extractelement <4 x i32> [[TMP0]], i32 1
+// CHECK-NEXT: store i32 [[MATRIXEXT]], ptr [[RETVAL]], align 4
+// CHECK-NEXT: [[TMP1:%.*]] = load i1, ptr [[RETVAL]], align 4
+// CHECK-NEXT: ret i1 [[TMP1]]
+//
+bool fn4() {
+ bool2x2 Arr[2] = {{true,true,true,true}, {false,false,false,false}};
+ return Arr[0][1][0];
+}
+
+// CHECK-LABEL: define hidden void @_Z3fn5v(
+// CHECK-SAME: ) #[[ATTR0]] {
+// CHECK-NEXT: [[ENTRY:.*:]]
+// CHECK-NEXT: [[M:%.*]] = alloca [4 x i32], align 4
+// CHECK-NEXT: store <4 x i1> splat (i1 true), ptr [[M]], align 4
+// CHECK-NEXT: [[TMP0:%.*]] = load <4 x i32>, ptr [[M]], align 4
+// CHECK-NEXT: [[MATINS:%.*]] = insertelement <4 x i32> [[TMP0]], i32 0, i32 3
+// CHECK-NEXT: store <4 x i32> [[MATINS]], ptr [[M]], align 4
+// CHECK-NEXT: ret void
+//
+void fn5() {
+ bool2x2 M = {true,true,true,true};
+ M[1][1] = false;
+}
+
+// CHECK-LABEL: define hidden void @_Z3fn6v(
+// CHECK-SAME: ) #[[ATTR0]] {
+// CHECK-NEXT: [[ENTRY:.*:]]
+// CHECK-NEXT: [[V:%.*]] = alloca i32, align 4
+// CHECK-NEXT: [[S:%.*]] = alloca [[STRUCT_S:%.*]], align 1
+// CHECK-NEXT: store i32 0, ptr [[V]], align 4
+// CHECK-NEXT: [[BM:%.*]] = getelementptr inbounds nuw [[STRUCT_S]], ptr [[S]], i32 0, i32 0
+// CHECK-NEXT: store <4 x i1> <i1 true, i1 false, i1 true, i1 false>, ptr [[BM]], align 1
+// CHECK-NEXT: [[F:%.*]] = getelementptr inbounds nuw [[STRUCT_S]], ptr [[S]], i32 0, i32 1
+// CHECK-NEXT: store float 1.000000e+00, ptr [[F]], align 1
+// CHECK-NEXT: [[TMP0:%.*]] = load i32, ptr [[V]], align 4
+// CHECK-NEXT: [[LOADEDV:%.*]] = trunc i32 [[TMP0]] to i1
+// CHECK-NEXT: [[BM1:%.*]] = getelementptr inbounds nuw [[STRUCT_S]], ptr [[S]], i32 0, i32 0
+// CHECK-NEXT: [[TMP1:%.*]] = load <4 x i32>, ptr [[BM1]], align 1
+// CHECK-NEXT: [[TMP2:%.*]] = zext i1 [[LOADEDV]] to i32
+// CHECK-NEXT: [[MATINS:%.*]] = insertelement <4 x i32> [[TMP1]], i32 [[TMP2]], i32 1
+// CHECK-NEXT: store <4 x i32> [[MATINS]], ptr [[BM1]], align 1
+// CHECK-NEXT: ret void
+//
+void fn6() {
+ bool V = false;
+ S s = {{true,true,false,false}, 1.0};
+ s.bM[1][0] = V;
+}
+
+// CHECK-LABEL: define hidden void @_Z3fn7v(
+// CHECK-SAME: ) #[[ATTR0]] {
+// CHECK-NEXT: [[ENTRY:.*:]]
+// CHECK-NEXT: [[ARR:%.*]] = alloca [2 x [4 x i32]], align 4
+// CHECK-NEXT: store <4 x i1> splat (i1 true), ptr [[ARR]], align 4
+// CHECK-NEXT: [[ARRAYINIT_ELEMENT:%.*]] = getelementptr inbounds [4 x i32], ptr [[ARR]], i32 1
+// CHECK-NEXT: store <4 x i1> zeroinitializer, ptr [[ARRAYINIT_ELEMENT]], align 4
+// CHECK-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds [2 x [4 x i32]], ptr [[ARR]], i32 0, i32 0
+// CHECK-NEXT: [[TMP0:%.*]] = load <4 x i32>, ptr [[ARRAYIDX]], align 4
+// CHECK-NEXT: [[MATINS:%.*]] = insertelement <4 x i32> [[TMP0]], i32 0, i32 1
+// CHECK-NEXT: store <4 x i32> [[MATINS]], ptr [[ARRAYIDX]], align 4
+// CHECK-NEXT: ret void
+//
+void fn7() {
+ bool2x2 Arr[2] = {{true,true,true,true}, {false,false,false,false}};
+ Arr[0][1][0] = false;
+}
diff --git a/clang/test/CodeGenHLSL/basic_types.hlsl b/clang/test/CodeGenHLSL/basic_types.hlsl
index 8836126934957..677a9a8f5d1de 100644
--- a/clang/test/CodeGenHLSL/basic_types.hlsl
+++ b/clang/test/CodeGenHLSL/basic_types.hlsl
@@ -38,6 +38,22 @@
// CHECK: @double2_Val = external hidden addrspace(2) global <2 x double>, align 16
// CHECK: @double3_Val = external hidden addrspace(2) global <3 x double>, align 32
// CHECK: @double4_Val = external hidden addrspace(2) global <4 x double>, align 32
+// CHECK: @bool1x1_Val = external hidden addrspace(2) global [1 x i32], align 4
+// CHECK: @bool1x2_Val = external hidden addrspace(2) global [2 x i32], align 4
+// CHECK: @bool1x3_Val = external hidden addrspace(2) global [3 x i32], align 4
+// CHECK: @bool1x4_Val = external hidden addrspace(2) global [4 x i32], align 4
+// CHECK: @bool2x1_Val = external hidden addrspace(2) global [2 x i32], align 4
+// CHECK: @bool2x2_Val = external hidden addrspace(2) global [4 x i32], align 4
+// CHECK: @bool2x3_Val = external hidden addrspace(2) global [6 x i32], align 4
+// CHECK: @bool2x4_Val = external hidden addrspace(2) global [8 x i32], align 4
+// CHECK: @bool3x1_Val = external hidden addrspace(2) global [3 x i32], align 4
+// CHECK: @bool3x2_Val = external hidden addrspace(2) global [6 x i32], align 4
+// CHECK: @bool3x3_Val = external hidden addrspace(2) global [9 x i32], align 4
+// CHECK: @bool3x4_Val = external hidden addrspace(2) global [12 x i32], align 4
+// CHECK: @bool4x1_Val = external hidden addrspace(2) global [4 x i32], align 4
+// CHECK: @bool4x2_Val = external hidden addrspace(2) global [8 x i32], align 4
+// CHECK: @bool4x3_Val = external hidden addrspace(2) global [12 x i32], align 4
+// CHECK: @bool4x4_Val = external hidden addrspace(2) global [16 x i32], align 4
#ifdef NAMESPACED
#define TYPE_DECL(T) hlsl::T T##_Val
@@ -93,3 +109,20 @@ TYPE_DECL( float4 );
TYPE_DECL( double2 );
TYPE_DECL( double3 );
TYPE_DECL( double4 );
+
+TYPE_DECL( bool1x1 );
+TYPE_DECL( bool1x2 );
+TYPE_DECL( bool1x3 );
+TYPE_DECL( bool1x4 );
+TYPE_DECL( bool2x1 );
+TYPE_DECL( bool2x2 );
+TYPE_DECL( bool2x3 );
+TYPE_DECL( bool2x4 );
+TYPE_DECL( bool3x1 );
+TYPE_DECL( bool3x2 );
+TYPE_DECL( bool3x3 );
+TYPE_DECL( bool3x4 );
+TYPE_DECL( bool4x1 );
+TYPE_DECL( bool4x2 );
+TYPE_DECL( bool4x3 );
+TYPE_DECL( bool4x4 );
>From 9c9fd5390b35ca693734c11562d7ae66050b418b Mon Sep 17 00:00:00 2001
From: Farzon Lotfi <farzonlotfi at microsoft.com>
Date: Sun, 7 Dec 2025 16:00:32 -0500
Subject: [PATCH 2/3] these tests were errroneously dependent on
MatrixType::isValidElementType
---
clang/test/SemaHLSL/BuiltIns/clamp-errors.hlsl | 7 +++----
clang/test/SemaHLSL/BuiltIns/dot-errors.hlsl | 2 +-
clang/test/SemaHLSL/BuiltIns/mad-errors.hlsl | 4 ++--
3 files changed, 6 insertions(+), 7 deletions(-)
diff --git a/clang/test/SemaHLSL/BuiltIns/clamp-errors.hlsl b/clang/test/SemaHLSL/BuiltIns/clamp-errors.hlsl
index bbe567b6d6ac1..5f86e281eeca5 100644
--- a/clang/test/SemaHLSL/BuiltIns/clamp-errors.hlsl
+++ b/clang/test/SemaHLSL/BuiltIns/clamp-errors.hlsl
@@ -99,18 +99,17 @@ float2 test_builtin_clamp_int_vect_to_float_vec_promotion(int2 p0, float p1) {
}
float test_builtin_clamp_bool_type_promotion(bool p0) {
- return __builtin_hlsl_elementwise_clamp(p0, p0, p0);
- // expected-error at -1 {{1st argument must be a vector, integer or floating-point type (was 'bool')}}
+ return __builtin_hlsl_elementwise_clamp(p0, p0, p0); // note: should not error
}
float builtin_bool_to_float_type_promotion(float p0, bool p1) {
return __builtin_hlsl_elementwise_clamp(p0, p0, p1);
- // expected-error at -1 {{3rd argument must be a vector, integer or floating-point type (was 'bool')}}
+ // expected-error at -1 {{arguments are of different types ('float' vs 'bool')}}
}
float builtin_bool_to_float_type_promotion2(bool p0, float p1) {
return __builtin_hlsl_elementwise_clamp(p1, p0, p1);
- // expected-error at -1 {{2nd argument must be a vector, integer or floating-point type (was 'bool')}}
+ // expected-error at -1 {{arguments are of different types ('float' vs 'bool')}}
}
float builtin_clamp_int_to_float_promotion(float p0, int p1) {
diff --git a/clang/test/SemaHLSL/BuiltIns/dot-errors.hlsl b/clang/test/SemaHLSL/BuiltIns/dot-errors.hlsl
index f514a04eb9f49..3751f53ef40fd 100644
--- a/clang/test/SemaHLSL/BuiltIns/dot-errors.hlsl
+++ b/clang/test/SemaHLSL/BuiltIns/dot-errors.hlsl
@@ -106,7 +106,7 @@ float test_builtin_dot_int_vect_to_float_vec_promotion(int2 p0, float p1) {
int test_builtin_dot_bool_type_promotion(bool p0, float p1) {
return __builtin_hlsl_dot(p0, p1);
- // expected-error at -1 {{1st argument must be a vector, integer or floating-point type (was 'bool')}}
+ // expected-error at -1 {{arguments are of different types ('bool' vs 'float')}}
}
double test_dot_double(double2 p0, double2 p1) {
diff --git a/clang/test/SemaHLSL/BuiltIns/mad-errors.hlsl b/clang/test/SemaHLSL/BuiltIns/mad-errors.hlsl
index 0e9dda7055f98..a993fd9c26899 100644
--- a/clang/test/SemaHLSL/BuiltIns/mad-errors.hlsl
+++ b/clang/test/SemaHLSL/BuiltIns/mad-errors.hlsl
@@ -72,12 +72,12 @@ float2 test_builtin_mad_int_vect_to_float_vec_promotion(int2 p0, float p1) {
float builtin_bool_to_float_type_promotion(float p0, bool p1) {
return __builtin_hlsl_mad(p0, p0, p1);
- // expected-error at -1 {{3rd argument must be a vector, integer or floating-point type (was 'bool')}}
+ // expected-error at -1 {{arguments are of different types ('float' vs 'bool')}}
}
float builtin_bool_to_float_type_promotion2(bool p0, float p1) {
return __builtin_hlsl_mad(p1, p0, p1);
- // expected-error at -1 {{2nd argument must be a vector, integer or floating-point type (was 'bool')}}
+ // expected-error at -1 {{arguments are of different types ('float' vs 'bool')}}
}
float builtin_mad_int_to_float_promotion(float p0, int p1) {
>From 37d82e2cf13ac5b9cf521b47bf443ea4257fa561 Mon Sep 17 00:00:00 2001
From: Farzon Lotfi <farzonlotfi at microsoft.com>
Date: Wed, 10 Dec 2025 23:45:47 -0500
Subject: [PATCH 3/3] Apply suggestions from code review
Co-authored-by: Helena Kotas <hekotas at microsoft.com>
---
clang/include/clang/AST/TypeBase.h | 8 +++-----
clang/lib/CodeGen/CodeGenTypes.cpp | 2 +-
clang/test/CodeGenHLSL/BoolMatrix.hlsl | 2 +-
3 files changed, 5 insertions(+), 7 deletions(-)
diff --git a/clang/include/clang/AST/TypeBase.h b/clang/include/clang/AST/TypeBase.h
index cf6897b6e515c..f546393f6d8c3 100644
--- a/clang/include/clang/AST/TypeBase.h
+++ b/clang/include/clang/AST/TypeBase.h
@@ -8681,11 +8681,9 @@ inline bool Type::isExtVectorBoolType() const {
}
inline bool Type::isConstantMatrixBoolType() const {
- if (!isConstantMatrixType())
- return false;
- return cast<ConstantMatrixType>(CanonicalType)
- ->getElementType()
- ->isBooleanType();
+ if (auto *CMT = dyn_cast<ConstantMatrixType>(CanonicalType))
+ return CMT->getElementType()->isBooleanType();
+ return false;
}
inline bool Type::isSubscriptableVectorType() const {
diff --git a/clang/lib/CodeGen/CodeGenTypes.cpp b/clang/lib/CodeGen/CodeGenTypes.cpp
index a41bf86d6f95c..4239552d1299e 100644
--- a/clang/lib/CodeGen/CodeGenTypes.cpp
+++ b/clang/lib/CodeGen/CodeGenTypes.cpp
@@ -105,7 +105,7 @@ llvm::Type *CodeGenTypes::ConvertTypeForMem(QualType T) {
const Type *Ty = Context.getCanonicalType(T).getTypePtr();
const ConstantMatrixType *MT = cast<ConstantMatrixType>(Ty);
llvm::Type *IRElemTy = ConvertType(MT->getElementType());
- if (T->isConstantMatrixBoolType() && Context.getLangOpts().HLSL)
+ if (Context.getLangOpts().HLSL && T->isConstantMatrixBoolType())
IRElemTy = ConvertTypeForMem(Context.BoolTy);
return llvm::ArrayType::get(IRElemTy,
MT->getNumRows() * MT->getNumColumns());
diff --git a/clang/test/CodeGenHLSL/BoolMatrix.hlsl b/clang/test/CodeGenHLSL/BoolMatrix.hlsl
index da90738b68b96..71186f775b241 100644
--- a/clang/test/CodeGenHLSL/BoolMatrix.hlsl
+++ b/clang/test/CodeGenHLSL/BoolMatrix.hlsl
@@ -68,7 +68,7 @@ bool2x2 fn2(bool V) {
// CHECK-NEXT: ret i1 [[TMP1]]
//
bool fn3() {
- S s = {{true,true, false, false}, 1.0};
+ S s = {{true,true,false,false}, 1.0};
return s.bM[0][0];
}
More information about the cfe-commits
mailing list