Skip to content

Conversation

@farzonl
Copy link
Member

@farzonl farzonl commented Dec 15, 2025

fixes #172341

This change adds the or and and HLSL builtins with overloads for the matrix types.

It also disables the logical operators from being used for HLSL 2021. To keep this code from getting too complicated HLSL 2018 and lower logical operator support was not added.

fixes llvm#172341

This change adds the `or` and `and` HLSL builtins with overloads
for the matrix types.

It also disables the logical operators from being used for HLSL 2021.
To keep this code from getting too complicated HLSL 2018 and lower
logical operator support was not added.
@llvmbot llvmbot added clang Clang issues not falling into any other category backend:X86 clang:frontend Language frontend issues, e.g. anything involving "Sema" clang:headers Headers provided by Clang, e.g. for intrinsics HLSL HLSL Language Support labels Dec 15, 2025
@llvmbot
Copy link
Member

llvmbot commented Dec 15, 2025

@llvm/pr-subscribers-backend-x86

@llvm/pr-subscribers-hlsl

Author: Farzon Lotfi (farzonl)

Changes

fixes #172341

This change adds the or and and HLSL builtins with overloads for the matrix types.

It also disables the logical operators from being used for HLSL 2021. To keep this code from getting too complicated HLSL 2018 and lower logical operator support was not added.


Patch is 21.22 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/172384.diff

8 Files Affected:

  • (modified) clang/include/clang/Basic/DiagnosticSemaKinds.td (+4)
  • (modified) clang/include/clang/Sema/Sema.h (+3-1)
  • (modified) clang/lib/Headers/hlsl/hlsl_alias_intrinsics.h (+54-4)
  • (modified) clang/lib/Sema/SemaExpr.cpp (+23)
  • (modified) clang/lib/Sema/SemaHLSL.cpp (+32-1)
  • (added) clang/test/CodeGenHLSL/builtins/and_mat.hlsl (+125)
  • (modified) clang/test/CodeGenHLSL/builtins/or.hlsl (+121)
  • (modified) clang/test/SemaHLSL/Language/UsualArithmeticConversions.hlsl (+22)
diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index 381d1fb063eba..4ab2f1e422a46 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -9766,6 +9766,9 @@ def err_typecheck_cond_incompatible_operands : Error<
 def err_typecheck_expect_scalar_or_vector : Error<
   "invalid operand of type %0 where %1 or "
   "a vector of such type is required">;
+def err_typecheck_expect_scalar_or_vector_or_matrix : Error<
+  "invalid operand of type %0 where %1 or "
+  "a vector or matrix of such type is required">;
 def err_typecheck_expect_any_scalar_or_vector : Error<
   "invalid operand of type %0%select{| where a scalar or vector is required}1">;
 def err_typecheck_expect_flt_or_vector : Error<
@@ -13277,6 +13280,7 @@ def err_std_initializer_list_malformed : Error<
   "%0 layout not recognized. Must be a non-polymorphic class type with no bases and two fields: a 'const E *' and either another 'const E *' or a 'std::size_t'">;
 
 // HLSL Diagnostics
+def err_hlsl_langstd_unimplemented : Error<"support for HLSL language version %0 is incomplete">;
 def err_hlsl_attr_unsupported_in_stage : Error<"attribute %0 is unsupported in '%1' shaders, requires %select{|one of the following: }2%3">;
 def err_hlsl_attr_invalid_type : Error<
    "attribute %0 only applies to a field or parameter of type '%1'">;
diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h
index 42f130c3a700d..94d4bce29d9ba 100644
--- a/clang/include/clang/Sema/Sema.h
+++ b/clang/include/clang/Sema/Sema.h
@@ -7866,7 +7866,9 @@ class Sema final : public SemaBase {
   QualType CheckVectorLogicalOperands(ExprResult &LHS, ExprResult &RHS,
                                       SourceLocation Loc,
                                       BinaryOperatorKind Opc);
-
+  QualType CheckMatrixLogicalOperands(ExprResult &LHS, ExprResult &RHS,
+                                      SourceLocation Loc,
+                                      BinaryOperatorKind Opc);
   // type checking for sizeless vector binary operators.
   QualType CheckSizelessVectorOperands(ExprResult &LHS, ExprResult &RHS,
                                        SourceLocation Loc, bool IsCompAssign,
diff --git a/clang/lib/Headers/hlsl/hlsl_alias_intrinsics.h b/clang/lib/Headers/hlsl/hlsl_alias_intrinsics.h
index f58150ed61106..c4c2b99167692 100644
--- a/clang/lib/Headers/hlsl/hlsl_alias_intrinsics.h
+++ b/clang/lib/Headers/hlsl/hlsl_alias_intrinsics.h
@@ -294,8 +294,8 @@ bool all(double4);
 //===----------------------------------------------------------------------===//
 
 /// \fn bool and(bool x, bool y)
-/// \brief Logically ands two boolean vectors elementwise and produces a bool
-/// vector output.
+/// \brief Logically ands two boolean vectors or matrices elementwise and
+// produces a bool vector or matrix output.
 
 // TODO: Clean up clang-format marker once we've resolved
 //       https://github.com/llvm/llvm-project/issues/127851
@@ -309,6 +309,31 @@ _HLSL_BUILTIN_ALIAS(__builtin_hlsl_and)
 bool3 and(bool3 x, bool3 y);
 _HLSL_BUILTIN_ALIAS(__builtin_hlsl_and)
 bool4 and(bool4 x, bool4 y);
+
+_HLSL_BUILTIN_ALIAS(__builtin_hlsl_and)
+bool2x1 and(bool2x1 x, bool2x1 y);
+_HLSL_BUILTIN_ALIAS(__builtin_hlsl_and)
+bool2x2 and(bool2x2 x, bool2x2 y);
+_HLSL_BUILTIN_ALIAS(__builtin_hlsl_and)
+bool2x3 and(bool2x3 x, bool2x3 y);
+_HLSL_BUILTIN_ALIAS(__builtin_hlsl_and)
+bool2x4 and(bool2x4 x, bool2x4 y);
+_HLSL_BUILTIN_ALIAS(__builtin_hlsl_and)
+bool3x1 and(bool3x1 x, bool3x1 y);
+_HLSL_BUILTIN_ALIAS(__builtin_hlsl_and)
+bool3x2 and(bool3x2 x, bool3x2 y);
+_HLSL_BUILTIN_ALIAS(__builtin_hlsl_and)
+bool3x3 and(bool3x3 x, bool3x3 y);
+_HLSL_BUILTIN_ALIAS(__builtin_hlsl_and)
+bool3x4 and(bool3x4 x, bool3x4 y);
+_HLSL_BUILTIN_ALIAS(__builtin_hlsl_and)
+bool4x1 and(bool4x1 x, bool4x1 y);
+_HLSL_BUILTIN_ALIAS(__builtin_hlsl_and)
+bool4x2 and(bool4x2 x, bool4x2 y);
+_HLSL_BUILTIN_ALIAS(__builtin_hlsl_and)
+bool4x3 and(bool4x3 x, bool4x3 y);
+_HLSL_BUILTIN_ALIAS(__builtin_hlsl_and)
+bool4x4 and(bool4x4 x, bool4x4 y);
 // clang-format on
 
 //===----------------------------------------------------------------------===//
@@ -1759,8 +1784,8 @@ float4 normalize(float4);
 //===----------------------------------------------------------------------===//
 
 /// \fn bool or(bool x, bool y)
-/// \brief Logically ors two boolean vectors elementwise and produces a bool
-/// vector output.
+/// \brief Logically ors two boolean vectors or matrices elementwise and
+///  produces a bool vector or matrix output.
 
 // TODO: Clean up clang-format marker once we've resolved
 //       https://github.com/llvm/llvm-project/issues/127851
@@ -1774,6 +1799,31 @@ _HLSL_BUILTIN_ALIAS(__builtin_hlsl_or)
 bool3 or(bool3, bool3);
 _HLSL_BUILTIN_ALIAS(__builtin_hlsl_or)
 bool4 or(bool4, bool4);
+
+_HLSL_BUILTIN_ALIAS(__builtin_hlsl_or)
+bool2x1 or(bool2x1 x, bool2x1 y);
+_HLSL_BUILTIN_ALIAS(__builtin_hlsl_or)
+bool2x2 or(bool2x2 x, bool2x2 y);
+_HLSL_BUILTIN_ALIAS(__builtin_hlsl_or)
+bool2x3 or(bool2x3 x, bool2x3 y);
+_HLSL_BUILTIN_ALIAS(__builtin_hlsl_or)
+bool2x4 or(bool2x4 x, bool2x4 y);
+_HLSL_BUILTIN_ALIAS(__builtin_hlsl_or)
+bool3x1 or(bool3x1 x, bool3x1 y);
+_HLSL_BUILTIN_ALIAS(__builtin_hlsl_or)
+bool3x2 or(bool3x2 x, bool3x2 y);
+_HLSL_BUILTIN_ALIAS(__builtin_hlsl_or)
+bool3x3 or(bool3x3 x, bool3x3 y);
+_HLSL_BUILTIN_ALIAS(__builtin_hlsl_or)
+bool3x4 or(bool3x4 x, bool3x4 y);
+_HLSL_BUILTIN_ALIAS(__builtin_hlsl_or)
+bool4x1 or(bool4x1 x, bool4x1 y);
+_HLSL_BUILTIN_ALIAS(__builtin_hlsl_or)
+bool4x2 or(bool4x2 x, bool4x2 y);
+_HLSL_BUILTIN_ALIAS(__builtin_hlsl_or)
+bool4x3 or(bool4x3 x, bool4x3 y);
+_HLSL_BUILTIN_ALIAS(__builtin_hlsl_or)
+bool4x4 or(bool4x4 x, bool4x4 y);
 // clang-format on
 
 //===----------------------------------------------------------------------===//
diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp
index e01bf9c1a50e3..553129f27c3d2 100644
--- a/clang/lib/Sema/SemaExpr.cpp
+++ b/clang/lib/Sema/SemaExpr.cpp
@@ -13389,6 +13389,25 @@ QualType Sema::CheckVectorLogicalOperands(ExprResult &LHS, ExprResult &RHS,
   return GetSignedVectorType(LHS.get()->getType());
 }
 
+QualType Sema::CheckMatrixLogicalOperands(ExprResult &LHS, ExprResult &RHS,
+                                          SourceLocation Loc,
+                                          BinaryOperatorKind Opc) {
+
+  if (!getLangOpts().HLSL) {
+    assert(false && "Logical operands are not support in C\\C++");
+    return QualType();
+  }
+
+  if (getLangOpts().getHLSLVersion() >= LangOptionsBase::HLSL_2021) {
+    (void)InvalidOperands(Loc, LHS, RHS);
+    HLSL().emitLogicalOperatorFixIt(LHS.get(), RHS.get(), Opc);
+    return QualType();
+  }
+  SemaRef.Diag(LHS.get()->getBeginLoc(), diag::err_hlsl_langstd_unimplemented)
+      << getLangOpts().getHLSLVersion();
+  return QualType();
+}
+
 QualType Sema::CheckMatrixElementwiseOperands(ExprResult &LHS, ExprResult &RHS,
                                               SourceLocation Loc,
                                               bool IsCompAssign) {
@@ -13561,6 +13580,10 @@ inline QualType Sema::CheckLogicalOperands(ExprResult &LHS, ExprResult &RHS,
       RHS.get()->getType()->isVectorType())
     return CheckVectorLogicalOperands(LHS, RHS, Loc, Opc);
 
+  if (LHS.get()->getType()->isConstantMatrixType() ||
+      RHS.get()->getType()->isConstantMatrixType())
+    return CheckMatrixLogicalOperands(LHS, RHS, Loc, Opc);
+
   bool EnumConstantInBoolContext = false;
   for (const ExprResult &HS : {LHS, RHS}) {
     if (const auto *DREHS = dyn_cast<DeclRefExpr>(HS.get())) {
diff --git a/clang/lib/Sema/SemaHLSL.cpp b/clang/lib/Sema/SemaHLSL.cpp
index 28744ff0ff42e..c6b989ffffef0 100644
--- a/clang/lib/Sema/SemaHLSL.cpp
+++ b/clang/lib/Sema/SemaHLSL.cpp
@@ -2993,6 +2993,36 @@ static bool CheckScalarOrVector(Sema *S, CallExpr *TheCall, QualType Scalar,
   return false;
 }
 
+static bool CheckScalarOrVectorOrMatrix(Sema *S, CallExpr *TheCall,
+                                        QualType Scalar, unsigned ArgIndex) {
+  assert(TheCall->getNumArgs() > ArgIndex);
+
+  Expr *Arg = TheCall->getArg(ArgIndex);
+  QualType ArgType = Arg->getType();
+
+  // Scalar: T
+  if (S->Context.hasSameUnqualifiedType(ArgType, Scalar))
+    return false;
+
+  // Vector: vector<T>
+  if (const auto *VTy = ArgType->getAs<VectorType>()) {
+    if (S->Context.hasSameUnqualifiedType(VTy->getElementType(), Scalar))
+      return false;
+  }
+
+  // Matrix: ConstantMatrixType with element type T
+  if (const auto *MTy = ArgType->getAs<ConstantMatrixType>()) {
+    if (S->Context.hasSameUnqualifiedType(MTy->getElementType(), Scalar))
+      return false;
+  }
+
+  // Not a scalar/vector/matrix-of-scalar
+  S->Diag(Arg->getBeginLoc(),
+          diag::err_typecheck_expect_scalar_or_vector_or_matrix)
+      << ArgType << Scalar;
+  return true;
+}
+
 static bool CheckAnyScalarOrVector(Sema *S, CallExpr *TheCall,
                                    unsigned ArgIndex) {
   assert(TheCall->getNumArgs() >= ArgIndex);
@@ -3225,7 +3255,8 @@ bool SemaHLSL::CheckBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) {
   case Builtin::BI__builtin_hlsl_or: {
     if (SemaRef.checkArgCount(TheCall, 2))
       return true;
-    if (CheckScalarOrVector(&SemaRef, TheCall, getASTContext().BoolTy, 0))
+    if (CheckScalarOrVectorOrMatrix(&SemaRef, TheCall, getASTContext().BoolTy,
+                                    0))
       return true;
     if (CheckAllArgsHaveSameType(&SemaRef, TheCall))
       return true;
diff --git a/clang/test/CodeGenHLSL/builtins/and_mat.hlsl b/clang/test/CodeGenHLSL/builtins/and_mat.hlsl
new file mode 100644
index 0000000000000..4f9e5da304fd1
--- /dev/null
+++ b/clang/test/CodeGenHLSL/builtins/and_mat.hlsl
@@ -0,0 +1,125 @@
+// RUN: %clang_cc1 -finclude-default-header -triple \
+// RUN:   dxil-pc-shadermodel6.3-library %s \
+// RUN:   -emit-llvm -disable-llvm-passes -o - | FileCheck %s
+
+//CHECK-LABEL: define hidden noundef <2 x i1> @_Z16test_and_bool2x1u11matrix_typeILm2ELm1EbES_(
+//CHECK-SAME: <2 x i1> noundef [[X:%.*]], <2 x i1> noundef [[Y:%.*]])  #[[ATTR0:[0-9]+]] {
+//CHECK-NEXT:  entry:
+//CHECK:         [[HLSL_AND:%.*]] = and <2 x i32> [[A:%.*]], [[B:%.*]]
+//CHECK:         ret <2 x i1> [[HLSL_AND_CAST:%.*]]
+bool2x1 test_and_bool2x1(bool2x1 x, bool2x1 y)
+{
+    return and(x, y);
+}
+
+
+//CHECK-LABEL: define hidden noundef <4 x i1> @_Z16test_and_bool2x2u11matrix_typeILm2ELm2EbES_(
+//CHECK-SAME: <4 x i1> noundef [[X:%.*]], <4 x i1> noundef [[Y:%.*]]) #[[ATTR0]] {
+//CHECK-NEXT:  entry:
+//CHECK:         [[HLSL_AND:%.*]] = and <4 x i32> [[A:%.*]], [[B:%.*]]
+//CHECK:         ret <4 x i1> [[HLSL_AND_CAST:%.*]]
+bool2x2 test_and_bool2x2(bool2x2 x, bool2x2 y)
+{
+    return and(x, y);
+}
+
+//CHECK-LABEL: define hidden noundef <6 x i1> @_Z16test_and_bool2x3u11matrix_typeILm2ELm3EbES_(
+//CHECK-SAME: <6 x i1> noundef [[X:%.*]], <6 x i1> noundef [[Y:%.*]]) #[[ATTR0]] {
+//CHECK-NEXT:  entry:
+//CHECK:         [[HLSL_AND:%.*]] = and <6 x i32> [[A:%.*]], [[B:%.*]]
+//CHECK:         ret <6 x i1> [[HLSL_AND_CAST:%.*]]
+bool2x3 test_and_bool2x3(bool2x3 x, bool2x3 y)
+{
+    return and(x, y);
+}
+
+//CHECK-LABEL: define hidden noundef <8 x i1> @_Z16test_and_bool2x4u11matrix_typeILm2ELm4EbES_(
+//CHECK-SAME: <8 x i1> noundef [[X:%.*]], <8 x i1> noundef [[Y:%.*]]) #[[ATTR0]] {
+//CHECK-NEXT:  entry:
+//CHECK:         [[HLSL_AND:%.*]] = and <8 x i32> [[A:%.*]], [[B:%.*]]
+//CHECK:         ret <8 x i1> [[HLSL_AND_CAST:%.*]]
+bool2x4 test_and_bool2x4(bool2x4 x, bool2x4 y)
+{
+    return and(x, y);
+}
+
+//CHECK-LABEL: define hidden noundef <3 x i1> @_Z16test_and_bool3x1u11matrix_typeILm3ELm1EbES_(
+//CHECK-SAME: <3 x i1> noundef [[X:%.*]], <3 x i1> noundef [[Y:%.*]]) #[[ATTR0]] {
+//CHECK-NEXT:  entry:
+//CHECK:         [[HLSL_AND:%.*]] = and <3 x i32> [[A:%.*]], [[B:%.*]]
+//CHECK:         ret <3 x i1> [[HLSL_AND_CAST:%.*]]
+bool3x1 test_and_bool3x1(bool3x1 x, bool3x1 y)
+{
+    return and(x, y);
+}
+
+//CHECK-LABEL: define hidden noundef <6 x i1> @_Z16test_and_bool3x2u11matrix_typeILm3ELm2EbES_(
+//CHECK-SAME: <6 x i1> noundef [[X:%.*]], <6 x i1> noundef [[Y:%.*]]) #[[ATTR0]] {
+//CHECK-NEXT:  entry:
+//CHECK:         [[HLSL_AND:%.*]] = and <6 x i32> [[A:%.*]], [[B:%.*]]
+//CHECK:         ret <6 x i1> [[HLSL_AND_CAST:%.*]]
+bool3x2 test_and_bool3x2(bool3x2 x, bool3x2 y)
+{
+    return and(x, y);
+}
+
+
+//CHECK-LABEL: define hidden noundef <9 x i1> @_Z16test_and_bool3x3u11matrix_typeILm3ELm3EbES_(
+//CHECK-SAME: <9 x i1> noundef [[X:%.*]], <9 x i1> noundef [[Y:%.*]]) #[[ATTR0]] {
+//CHECK-NEXT:  entry:
+//CHECK:         [[HLSL_AND:%.*]] = and <9 x i32> [[A:%.*]], [[B:%.*]]
+//CHECK:         ret <9 x i1> [[HLSL_AND_CAST:%.*]]
+bool3x3 test_and_bool3x3(bool3x3 x, bool3x3 y)
+{
+    return and(x, y);
+}
+
+//CHECK-LABEL: define hidden noundef <12 x i1> @_Z16test_and_bool3x4u11matrix_typeILm3ELm4EbES_(
+//CHECK-SAME: <12 x i1> noundef [[X:%.*]], <12 x i1> noundef [[Y:%.*]]) #[[ATTR0]] {
+//CHECK-NEXT:  entry:
+//CHECK:         [[HLSL_AND:%.*]] = and <12 x i32> [[A:%.*]], [[B:%.*]]
+//CHECK:         ret <12 x i1> [[HLSL_AND_CAST:%.*]]
+bool3x4 test_and_bool3x4(bool3x4 x, bool3x4 y)
+{
+    return and(x, y);
+}
+
+//CHECK-LABEL: define hidden noundef <4 x i1> @_Z16test_and_bool4x1u11matrix_typeILm4ELm1EbES_(
+//CHECK-SAME: <4 x i1> noundef [[X:%.*]], <4 x i1> noundef [[Y:%.*]]) #[[ATTR0]] {
+//CHECK-NEXT:  entry:
+//CHECK:         [[HLSL_AND:%.*]] = and <4 x i32> [[A:%.*]], [[B:%.*]]
+//CHECK:         ret <4 x i1> [[HLSL_AND_CAST:%.*]]
+bool4x1 test_and_bool4x1(bool4x1 x, bool4x1 y)
+{
+    return and(x, y);
+}
+
+//CHECK-LABEL: define hidden noundef <8 x i1> @_Z16test_and_bool4x2u11matrix_typeILm4ELm2EbES_(
+//CHECK-SAME: <8 x i1> noundef [[X:%.*]], <8 x i1> noundef [[Y:%.*]]) #[[ATTR0]] {
+//CHECK-NEXT:  entry:
+//CHECK:         [[HLSL_AND:%.*]] = and <8 x i32> [[A:%.*]], [[B:%.*]]
+//CHECK:         ret <8 x i1> [[HLSL_AND_CAST:%.*]]
+bool4x2 test_and_bool4x2(bool4x2 x, bool4x2 y)
+{
+    return and(x, y);
+}
+
+//CHECK-LABEL: define hidden noundef <12 x i1> @_Z16test_and_bool4x3u11matrix_typeILm4ELm3EbES_(
+//CHECK-SAME: <12 x i1> noundef [[X:%.*]], <12 x i1> noundef [[Y:%.*]]) #[[ATTR0]] {
+//CHECK-NEXT:  entry:
+//CHECK:         [[HLSL_AND:%.*]] = and <12 x i32> [[A:%.*]], [[B:%.*]]
+//CHECK:         ret <12 x i1> [[HLSL_AND_CAST:%.*]]
+bool4x3 test_and_bool4x3(bool4x3 x, bool4x3 y)
+{
+    return and(x, y);
+}
+
+//CHECK-LABEL: define hidden noundef <16 x i1> @_Z16test_and_bool4x4u11matrix_typeILm4ELm4EbES_(
+//CHECK-SAME: <16 x i1> noundef [[X:%.*]], <16 x i1> noundef [[Y:%.*]]) #[[ATTR0]] {
+//CHECK-NEXT:  entry:
+//CHECK:         [[HLSL_AND:%.*]] = and <16 x i32> [[A:%.*]], [[B:%.*]]
+//CHECK:         ret <16 x i1> [[HLSL_AND_CAST:%.*]]
+bool4x4 test_and_bool4x4(bool4x4 x, bool4x4 y)
+{
+    return and(x, y);
+}
diff --git a/clang/test/CodeGenHLSL/builtins/or.hlsl b/clang/test/CodeGenHLSL/builtins/or.hlsl
index 0a09cd2459fff..53240ec14c202 100644
--- a/clang/test/CodeGenHLSL/builtins/or.hlsl
+++ b/clang/test/CodeGenHLSL/builtins/or.hlsl
@@ -78,3 +78,124 @@ bool4 test_or_float4(float4 x, float4 y)
     return or(x, y);
 }
 
+//CHECK-LABEL: define hidden noundef <2 x i1> @_Z15test_or_bool2x1u11matrix_typeILm2ELm1EbES_(
+//CHECK-SAME: <2 x i1> noundef [[X:%.*]], <2 x i1> noundef [[Y:%.*]]) #[[ATTR0]] {
+//CHECK-NEXT:  entry:
+//CHECK:         [[HLSL_OR:%.*]] = or <2 x i32> [[A:%.*]], [[B:%.*]]
+//CHECK:         ret <2 x i1> [[HLSL_OR_CAST:%.*]]
+bool2x1 test_or_bool2x1(bool2x1 x, bool2x1 y)
+{
+    return or(x, y);
+}
+
+
+//CHECK-LABEL: define hidden noundef <4 x i1> @_Z15test_or_bool2x2u11matrix_typeILm2ELm2EbES_(
+//CHECK-SAME: <4 x i1> noundef [[X:%.*]], <4 x i1> noundef [[Y:%.*]]) #[[ATTR0]] {
+//CHECK-NEXT:  entry:
+//CHECK:         [[HLSL_OR:%.*]] = or <4 x i32> [[A:%.*]], [[B:%.*]]
+//CHECK:         ret <4 x i1> [[HLSL_OR_CAST:%.*]]
+bool2x2 test_or_bool2x2(bool2x2 x, bool2x2 y)
+{
+    return or(x, y);
+}
+
+//CHECK-LABEL: define hidden noundef <6 x i1> @_Z15test_or_bool2x3u11matrix_typeILm2ELm3EbES_(
+//CHECK-SAME: <6 x i1> noundef [[X:%.*]], <6 x i1> noundef [[Y:%.*]]) #[[ATTR0]] {
+//CHECK-NEXT:  entry:
+//CHECK:         [[HLSL_OR:%.*]] = or <6 x i32> [[A:%.*]], [[B:%.*]]
+//CHECK:         ret <6 x i1> [[HLSL_OR_CAST:%.*]]
+bool2x3 test_or_bool2x3(bool2x3 x, bool2x3 y)
+{
+    return or(x, y);
+}
+
+//CHECK-LABEL: define hidden noundef <8 x i1> @_Z15test_or_bool2x4u11matrix_typeILm2ELm4EbES_(
+//CHECK-SAME: <8 x i1> noundef [[X:%.*]], <8 x i1> noundef [[Y:%.*]]) #[[ATTR0]] {
+//CHECK-NEXT:  entry:
+//CHECK:         [[HLSL_OR:%.*]] = or <8 x i32> [[A:%.*]], [[B:%.*]]
+//CHECK:         ret <8 x i1> [[HLSL_OR_CAST:%.*]]
+bool2x4 test_or_bool2x4(bool2x4 x, bool2x4 y)
+{
+    return or(x, y);
+}
+
+//CHECK-LABEL: define hidden noundef <3 x i1> @_Z15test_or_bool3x1u11matrix_typeILm3ELm1EbES_(
+//CHECK-SAME: <3 x i1> noundef [[X:%.*]], <3 x i1> noundef [[Y:%.*]]) #[[ATTR0]] {
+//CHECK-NEXT:  entry:
+//CHECK:         [[HLSL_OR:%.*]] = or <3 x i32> [[A:%.*]], [[B:%.*]]
+//CHECK:         ret <3 x i1> [[HLSL_OR_CAST:%.*]]
+bool3x1 test_or_bool3x1(bool3x1 x, bool3x1 y)
+{
+    return or(x, y);
+}
+
+//CHECK-LABEL: define hidden noundef <6 x i1> @_Z15test_or_bool3x2u11matrix_typeILm3ELm2EbES_(
+//CHECK-SAME: <6 x i1> noundef [[X:%.*]], <6 x i1> noundef [[Y:%.*]]) #[[ATTR0]] {
+//CHECK-NEXT:  entry:
+//CHECK:         [[HLSL_OR:%.*]] = or <6 x i32> [[A:%.*]], [[B:%.*]]
+//CHECK:         ret <6 x i1> [[HLSL_OR_CAST:%.*]]
+bool3x2 test_or_bool3x2(bool3x2 x, bool3x2 y)
+{
+    return or(x, y);
+}
+
+
+//CHECK-LABEL: define hidden noundef <9 x i1> @_Z15test_or_bool3x3u11matrix_typeILm3ELm3EbES_(
+//CHECK-SAME: <9 x i1> noundef [[X:%.*]], <9 x i1> noundef [[Y:%.*]]) #[[ATTR0]] {
+//CHECK-NEXT:  entry:
+//CHECK:         [[HLSL_OR:%.*]] = or <9 x i32> [[A:%.*]], [[B:%.*]]
+//CHECK:         ret <9 x i1> [[HLSL_OR_CAST:%.*]]
+bool3x3 test_or_bool3x3(bool3x3 x, bool3x3 y)
+{
+    return or(x, y);
+}
+
+//CHECK-LABEL: define hidden noundef <12 x i1> @_Z15test_or_bool3x4u11matrix_typeILm3ELm4EbES_(
+//CHECK-SAME: <12 x i1> noundef [[X:%.*]], <12 x i1> noundef [[Y:%.*]]) #[[ATTR0]] {
+//CHECK-NEXT:  entry:
+//CHECK:         [[HLSL_OR:%.*]] = or <12 x i32> [[A:%.*]], [[B:%.*]]
+//CHECK:         ret <12 x i1> [[HLSL_OR_CAST:%.*]]
+bool3x4 test_or_bool3x4(bool3x4 x, bool3x4 y)
+{
+    return or(x, y);
+}
+
+//CHECK-LABEL: define hidden noundef <4 x i1> @_Z15test_or_bool4x1u11matrix_typeILm4ELm1EbES_(
+//CHECK-SAME: <4 x i1> noundef [[X:%.*]], <4 x i1> noundef [[Y:%.*]]) #[[ATTR0]] {
+//CHECK-NEXT:  entry:
+//CHECK:         [[HLSL_OR:%.*]] = or <4 x i32> [[A:%.*]], [[B:%.*]]
+//CHECK:         ret <4 x i1> [[HLSL_OR_CAST:%.*]]
+bool4x1 test_or_bool4x1(bool4x1 x, bool4x1 y)
+{
+    return or(x, y);
+}
+
+//CHECK-LABEL: define hidden noundef <8 x i1> @_Z15test_or_bool4x2u11matrix_typeILm4ELm2EbES_(
+//CHECK-SAME: <8 x i1> noundef [[X:%.*]], <8 x i1> noundef [[Y:%.*]]) #[[ATTR0]] {
+//CHECK-NEXT:  entry:
+//CHECK:         [[HLSL_OR:%.*]] = or <8 x i32> [[A:%.*]], [[B:%.*]]
+//CHECK:         ret <8 x i1> [[HLSL_OR_CAST:%.*]]
+bool4x2 test_or_bool4x2(bool4x2 x, bool4x2 y)
+{
+    return or(x, y);
+}
+
+//CHECK-LABEL: define hidden noundef <12 x i1> @_Z15test_or_bool4x3u11matrix_typeILm4ELm3EbES_(
+//CHECK-SAME: <12 x i1> noundef [[X:%.*]], <12 x i1> noundef [[Y:%.*]]) #[[ATTR0]] {
+//CHECK-NEXT:  entry:
+//CHECK:         [[HLSL_OR:%.*]] = or <12 x i32> [[A:%.*]], [[B:%.*]]
+//CHECK:         ret <12 x i1> [[HLSL_OR_CAST:%.*]]
+bool4x3 test_or_bool4x3(bool4x3 x, bool4x3 y)
+{
+    return or(x, y);
+}
+
+//CHECK-LABEL: define hidden noundef <16 x i1> @_Z15test_or_bool4x4u11matrix_typeILm4ELm4EbES_(
+//CHECK-SAME: <16 x i1> noundef [[X:%.*]], <16 x i1> noundef [[Y:%.*]]) #[[ATTR0]] {
+//CHECK-NEXT:  entry:
+//CHECK:         [[HLSL_OR:%.*]] = or <16 x i32> [[A:%.*]], [[B:%.*]]
+//CHECK:         ret <16 x i1> [[HLSL_OR_CAST:%.*]]
+bool4x4 test_or_bool4x4(bool4x4 x, bool4x4 y)
+{
+    return or(x, y);
+}
diff --git a/clang/test/SemaHLSL/Language/UsualArithmeticConversions.hlsl b/clang/test/SemaHLSL/Language/UsualArithmeticConversions.hlsl
index d9f20a4cb79ec..3c6710a50270c 100644
--- a/clang/test/SemaHLSL/Language/UsualArithmeticConversions.hlsl
+++ b/clang/test/SemaHLSL/Language/UsualArithmeticConversions.hlsl
@@ -359,6 +359,28 @@ export bool4 b4f4i4Logical(f...
[truncated]

@llvmbot
Copy link
Member

llvmbot commented Dec 15, 2025

@llvm/pr-subscribers-clang

Author: Farzon Lotfi (farzonl)

Changes

fixes #172341

This change adds the or and and HLSL builtins with overloads for the matrix types.

It also disables the logical operators from being used for HLSL 2021. To keep this code from getting too complicated HLSL 2018 and lower logical operator support was not added.


Patch is 21.22 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/172384.diff

8 Files Affected:

  • (modified) clang/include/clang/Basic/DiagnosticSemaKinds.td (+4)
  • (modified) clang/include/clang/Sema/Sema.h (+3-1)
  • (modified) clang/lib/Headers/hlsl/hlsl_alias_intrinsics.h (+54-4)
  • (modified) clang/lib/Sema/SemaExpr.cpp (+23)
  • (modified) clang/lib/Sema/SemaHLSL.cpp (+32-1)
  • (added) clang/test/CodeGenHLSL/builtins/and_mat.hlsl (+125)
  • (modified) clang/test/CodeGenHLSL/builtins/or.hlsl (+121)
  • (modified) clang/test/SemaHLSL/Language/UsualArithmeticConversions.hlsl (+22)
diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index 381d1fb063eba..4ab2f1e422a46 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -9766,6 +9766,9 @@ def err_typecheck_cond_incompatible_operands : Error<
 def err_typecheck_expect_scalar_or_vector : Error<
   "invalid operand of type %0 where %1 or "
   "a vector of such type is required">;
+def err_typecheck_expect_scalar_or_vector_or_matrix : Error<
+  "invalid operand of type %0 where %1 or "
+  "a vector or matrix of such type is required">;
 def err_typecheck_expect_any_scalar_or_vector : Error<
   "invalid operand of type %0%select{| where a scalar or vector is required}1">;
 def err_typecheck_expect_flt_or_vector : Error<
@@ -13277,6 +13280,7 @@ def err_std_initializer_list_malformed : Error<
   "%0 layout not recognized. Must be a non-polymorphic class type with no bases and two fields: a 'const E *' and either another 'const E *' or a 'std::size_t'">;
 
 // HLSL Diagnostics
+def err_hlsl_langstd_unimplemented : Error<"support for HLSL language version %0 is incomplete">;
 def err_hlsl_attr_unsupported_in_stage : Error<"attribute %0 is unsupported in '%1' shaders, requires %select{|one of the following: }2%3">;
 def err_hlsl_attr_invalid_type : Error<
    "attribute %0 only applies to a field or parameter of type '%1'">;
diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h
index 42f130c3a700d..94d4bce29d9ba 100644
--- a/clang/include/clang/Sema/Sema.h
+++ b/clang/include/clang/Sema/Sema.h
@@ -7866,7 +7866,9 @@ class Sema final : public SemaBase {
   QualType CheckVectorLogicalOperands(ExprResult &LHS, ExprResult &RHS,
                                       SourceLocation Loc,
                                       BinaryOperatorKind Opc);
-
+  QualType CheckMatrixLogicalOperands(ExprResult &LHS, ExprResult &RHS,
+                                      SourceLocation Loc,
+                                      BinaryOperatorKind Opc);
   // type checking for sizeless vector binary operators.
   QualType CheckSizelessVectorOperands(ExprResult &LHS, ExprResult &RHS,
                                        SourceLocation Loc, bool IsCompAssign,
diff --git a/clang/lib/Headers/hlsl/hlsl_alias_intrinsics.h b/clang/lib/Headers/hlsl/hlsl_alias_intrinsics.h
index f58150ed61106..c4c2b99167692 100644
--- a/clang/lib/Headers/hlsl/hlsl_alias_intrinsics.h
+++ b/clang/lib/Headers/hlsl/hlsl_alias_intrinsics.h
@@ -294,8 +294,8 @@ bool all(double4);
 //===----------------------------------------------------------------------===//
 
 /// \fn bool and(bool x, bool y)
-/// \brief Logically ands two boolean vectors elementwise and produces a bool
-/// vector output.
+/// \brief Logically ands two boolean vectors or matrices elementwise and
+// produces a bool vector or matrix output.
 
 // TODO: Clean up clang-format marker once we've resolved
 //       https://github.com/llvm/llvm-project/issues/127851
@@ -309,6 +309,31 @@ _HLSL_BUILTIN_ALIAS(__builtin_hlsl_and)
 bool3 and(bool3 x, bool3 y);
 _HLSL_BUILTIN_ALIAS(__builtin_hlsl_and)
 bool4 and(bool4 x, bool4 y);
+
+_HLSL_BUILTIN_ALIAS(__builtin_hlsl_and)
+bool2x1 and(bool2x1 x, bool2x1 y);
+_HLSL_BUILTIN_ALIAS(__builtin_hlsl_and)
+bool2x2 and(bool2x2 x, bool2x2 y);
+_HLSL_BUILTIN_ALIAS(__builtin_hlsl_and)
+bool2x3 and(bool2x3 x, bool2x3 y);
+_HLSL_BUILTIN_ALIAS(__builtin_hlsl_and)
+bool2x4 and(bool2x4 x, bool2x4 y);
+_HLSL_BUILTIN_ALIAS(__builtin_hlsl_and)
+bool3x1 and(bool3x1 x, bool3x1 y);
+_HLSL_BUILTIN_ALIAS(__builtin_hlsl_and)
+bool3x2 and(bool3x2 x, bool3x2 y);
+_HLSL_BUILTIN_ALIAS(__builtin_hlsl_and)
+bool3x3 and(bool3x3 x, bool3x3 y);
+_HLSL_BUILTIN_ALIAS(__builtin_hlsl_and)
+bool3x4 and(bool3x4 x, bool3x4 y);
+_HLSL_BUILTIN_ALIAS(__builtin_hlsl_and)
+bool4x1 and(bool4x1 x, bool4x1 y);
+_HLSL_BUILTIN_ALIAS(__builtin_hlsl_and)
+bool4x2 and(bool4x2 x, bool4x2 y);
+_HLSL_BUILTIN_ALIAS(__builtin_hlsl_and)
+bool4x3 and(bool4x3 x, bool4x3 y);
+_HLSL_BUILTIN_ALIAS(__builtin_hlsl_and)
+bool4x4 and(bool4x4 x, bool4x4 y);
 // clang-format on
 
 //===----------------------------------------------------------------------===//
@@ -1759,8 +1784,8 @@ float4 normalize(float4);
 //===----------------------------------------------------------------------===//
 
 /// \fn bool or(bool x, bool y)
-/// \brief Logically ors two boolean vectors elementwise and produces a bool
-/// vector output.
+/// \brief Logically ors two boolean vectors or matrices elementwise and
+///  produces a bool vector or matrix output.
 
 // TODO: Clean up clang-format marker once we've resolved
 //       https://github.com/llvm/llvm-project/issues/127851
@@ -1774,6 +1799,31 @@ _HLSL_BUILTIN_ALIAS(__builtin_hlsl_or)
 bool3 or(bool3, bool3);
 _HLSL_BUILTIN_ALIAS(__builtin_hlsl_or)
 bool4 or(bool4, bool4);
+
+_HLSL_BUILTIN_ALIAS(__builtin_hlsl_or)
+bool2x1 or(bool2x1 x, bool2x1 y);
+_HLSL_BUILTIN_ALIAS(__builtin_hlsl_or)
+bool2x2 or(bool2x2 x, bool2x2 y);
+_HLSL_BUILTIN_ALIAS(__builtin_hlsl_or)
+bool2x3 or(bool2x3 x, bool2x3 y);
+_HLSL_BUILTIN_ALIAS(__builtin_hlsl_or)
+bool2x4 or(bool2x4 x, bool2x4 y);
+_HLSL_BUILTIN_ALIAS(__builtin_hlsl_or)
+bool3x1 or(bool3x1 x, bool3x1 y);
+_HLSL_BUILTIN_ALIAS(__builtin_hlsl_or)
+bool3x2 or(bool3x2 x, bool3x2 y);
+_HLSL_BUILTIN_ALIAS(__builtin_hlsl_or)
+bool3x3 or(bool3x3 x, bool3x3 y);
+_HLSL_BUILTIN_ALIAS(__builtin_hlsl_or)
+bool3x4 or(bool3x4 x, bool3x4 y);
+_HLSL_BUILTIN_ALIAS(__builtin_hlsl_or)
+bool4x1 or(bool4x1 x, bool4x1 y);
+_HLSL_BUILTIN_ALIAS(__builtin_hlsl_or)
+bool4x2 or(bool4x2 x, bool4x2 y);
+_HLSL_BUILTIN_ALIAS(__builtin_hlsl_or)
+bool4x3 or(bool4x3 x, bool4x3 y);
+_HLSL_BUILTIN_ALIAS(__builtin_hlsl_or)
+bool4x4 or(bool4x4 x, bool4x4 y);
 // clang-format on
 
 //===----------------------------------------------------------------------===//
diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp
index e01bf9c1a50e3..553129f27c3d2 100644
--- a/clang/lib/Sema/SemaExpr.cpp
+++ b/clang/lib/Sema/SemaExpr.cpp
@@ -13389,6 +13389,25 @@ QualType Sema::CheckVectorLogicalOperands(ExprResult &LHS, ExprResult &RHS,
   return GetSignedVectorType(LHS.get()->getType());
 }
 
+QualType Sema::CheckMatrixLogicalOperands(ExprResult &LHS, ExprResult &RHS,
+                                          SourceLocation Loc,
+                                          BinaryOperatorKind Opc) {
+
+  if (!getLangOpts().HLSL) {
+    assert(false && "Logical operands are not support in C\\C++");
+    return QualType();
+  }
+
+  if (getLangOpts().getHLSLVersion() >= LangOptionsBase::HLSL_2021) {
+    (void)InvalidOperands(Loc, LHS, RHS);
+    HLSL().emitLogicalOperatorFixIt(LHS.get(), RHS.get(), Opc);
+    return QualType();
+  }
+  SemaRef.Diag(LHS.get()->getBeginLoc(), diag::err_hlsl_langstd_unimplemented)
+      << getLangOpts().getHLSLVersion();
+  return QualType();
+}
+
 QualType Sema::CheckMatrixElementwiseOperands(ExprResult &LHS, ExprResult &RHS,
                                               SourceLocation Loc,
                                               bool IsCompAssign) {
@@ -13561,6 +13580,10 @@ inline QualType Sema::CheckLogicalOperands(ExprResult &LHS, ExprResult &RHS,
       RHS.get()->getType()->isVectorType())
     return CheckVectorLogicalOperands(LHS, RHS, Loc, Opc);
 
+  if (LHS.get()->getType()->isConstantMatrixType() ||
+      RHS.get()->getType()->isConstantMatrixType())
+    return CheckMatrixLogicalOperands(LHS, RHS, Loc, Opc);
+
   bool EnumConstantInBoolContext = false;
   for (const ExprResult &HS : {LHS, RHS}) {
     if (const auto *DREHS = dyn_cast<DeclRefExpr>(HS.get())) {
diff --git a/clang/lib/Sema/SemaHLSL.cpp b/clang/lib/Sema/SemaHLSL.cpp
index 28744ff0ff42e..c6b989ffffef0 100644
--- a/clang/lib/Sema/SemaHLSL.cpp
+++ b/clang/lib/Sema/SemaHLSL.cpp
@@ -2993,6 +2993,36 @@ static bool CheckScalarOrVector(Sema *S, CallExpr *TheCall, QualType Scalar,
   return false;
 }
 
+static bool CheckScalarOrVectorOrMatrix(Sema *S, CallExpr *TheCall,
+                                        QualType Scalar, unsigned ArgIndex) {
+  assert(TheCall->getNumArgs() > ArgIndex);
+
+  Expr *Arg = TheCall->getArg(ArgIndex);
+  QualType ArgType = Arg->getType();
+
+  // Scalar: T
+  if (S->Context.hasSameUnqualifiedType(ArgType, Scalar))
+    return false;
+
+  // Vector: vector<T>
+  if (const auto *VTy = ArgType->getAs<VectorType>()) {
+    if (S->Context.hasSameUnqualifiedType(VTy->getElementType(), Scalar))
+      return false;
+  }
+
+  // Matrix: ConstantMatrixType with element type T
+  if (const auto *MTy = ArgType->getAs<ConstantMatrixType>()) {
+    if (S->Context.hasSameUnqualifiedType(MTy->getElementType(), Scalar))
+      return false;
+  }
+
+  // Not a scalar/vector/matrix-of-scalar
+  S->Diag(Arg->getBeginLoc(),
+          diag::err_typecheck_expect_scalar_or_vector_or_matrix)
+      << ArgType << Scalar;
+  return true;
+}
+
 static bool CheckAnyScalarOrVector(Sema *S, CallExpr *TheCall,
                                    unsigned ArgIndex) {
   assert(TheCall->getNumArgs() >= ArgIndex);
@@ -3225,7 +3255,8 @@ bool SemaHLSL::CheckBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) {
   case Builtin::BI__builtin_hlsl_or: {
     if (SemaRef.checkArgCount(TheCall, 2))
       return true;
-    if (CheckScalarOrVector(&SemaRef, TheCall, getASTContext().BoolTy, 0))
+    if (CheckScalarOrVectorOrMatrix(&SemaRef, TheCall, getASTContext().BoolTy,
+                                    0))
       return true;
     if (CheckAllArgsHaveSameType(&SemaRef, TheCall))
       return true;
diff --git a/clang/test/CodeGenHLSL/builtins/and_mat.hlsl b/clang/test/CodeGenHLSL/builtins/and_mat.hlsl
new file mode 100644
index 0000000000000..4f9e5da304fd1
--- /dev/null
+++ b/clang/test/CodeGenHLSL/builtins/and_mat.hlsl
@@ -0,0 +1,125 @@
+// RUN: %clang_cc1 -finclude-default-header -triple \
+// RUN:   dxil-pc-shadermodel6.3-library %s \
+// RUN:   -emit-llvm -disable-llvm-passes -o - | FileCheck %s
+
+//CHECK-LABEL: define hidden noundef <2 x i1> @_Z16test_and_bool2x1u11matrix_typeILm2ELm1EbES_(
+//CHECK-SAME: <2 x i1> noundef [[X:%.*]], <2 x i1> noundef [[Y:%.*]])  #[[ATTR0:[0-9]+]] {
+//CHECK-NEXT:  entry:
+//CHECK:         [[HLSL_AND:%.*]] = and <2 x i32> [[A:%.*]], [[B:%.*]]
+//CHECK:         ret <2 x i1> [[HLSL_AND_CAST:%.*]]
+bool2x1 test_and_bool2x1(bool2x1 x, bool2x1 y)
+{
+    return and(x, y);
+}
+
+
+//CHECK-LABEL: define hidden noundef <4 x i1> @_Z16test_and_bool2x2u11matrix_typeILm2ELm2EbES_(
+//CHECK-SAME: <4 x i1> noundef [[X:%.*]], <4 x i1> noundef [[Y:%.*]]) #[[ATTR0]] {
+//CHECK-NEXT:  entry:
+//CHECK:         [[HLSL_AND:%.*]] = and <4 x i32> [[A:%.*]], [[B:%.*]]
+//CHECK:         ret <4 x i1> [[HLSL_AND_CAST:%.*]]
+bool2x2 test_and_bool2x2(bool2x2 x, bool2x2 y)
+{
+    return and(x, y);
+}
+
+//CHECK-LABEL: define hidden noundef <6 x i1> @_Z16test_and_bool2x3u11matrix_typeILm2ELm3EbES_(
+//CHECK-SAME: <6 x i1> noundef [[X:%.*]], <6 x i1> noundef [[Y:%.*]]) #[[ATTR0]] {
+//CHECK-NEXT:  entry:
+//CHECK:         [[HLSL_AND:%.*]] = and <6 x i32> [[A:%.*]], [[B:%.*]]
+//CHECK:         ret <6 x i1> [[HLSL_AND_CAST:%.*]]
+bool2x3 test_and_bool2x3(bool2x3 x, bool2x3 y)
+{
+    return and(x, y);
+}
+
+//CHECK-LABEL: define hidden noundef <8 x i1> @_Z16test_and_bool2x4u11matrix_typeILm2ELm4EbES_(
+//CHECK-SAME: <8 x i1> noundef [[X:%.*]], <8 x i1> noundef [[Y:%.*]]) #[[ATTR0]] {
+//CHECK-NEXT:  entry:
+//CHECK:         [[HLSL_AND:%.*]] = and <8 x i32> [[A:%.*]], [[B:%.*]]
+//CHECK:         ret <8 x i1> [[HLSL_AND_CAST:%.*]]
+bool2x4 test_and_bool2x4(bool2x4 x, bool2x4 y)
+{
+    return and(x, y);
+}
+
+//CHECK-LABEL: define hidden noundef <3 x i1> @_Z16test_and_bool3x1u11matrix_typeILm3ELm1EbES_(
+//CHECK-SAME: <3 x i1> noundef [[X:%.*]], <3 x i1> noundef [[Y:%.*]]) #[[ATTR0]] {
+//CHECK-NEXT:  entry:
+//CHECK:         [[HLSL_AND:%.*]] = and <3 x i32> [[A:%.*]], [[B:%.*]]
+//CHECK:         ret <3 x i1> [[HLSL_AND_CAST:%.*]]
+bool3x1 test_and_bool3x1(bool3x1 x, bool3x1 y)
+{
+    return and(x, y);
+}
+
+//CHECK-LABEL: define hidden noundef <6 x i1> @_Z16test_and_bool3x2u11matrix_typeILm3ELm2EbES_(
+//CHECK-SAME: <6 x i1> noundef [[X:%.*]], <6 x i1> noundef [[Y:%.*]]) #[[ATTR0]] {
+//CHECK-NEXT:  entry:
+//CHECK:         [[HLSL_AND:%.*]] = and <6 x i32> [[A:%.*]], [[B:%.*]]
+//CHECK:         ret <6 x i1> [[HLSL_AND_CAST:%.*]]
+bool3x2 test_and_bool3x2(bool3x2 x, bool3x2 y)
+{
+    return and(x, y);
+}
+
+
+//CHECK-LABEL: define hidden noundef <9 x i1> @_Z16test_and_bool3x3u11matrix_typeILm3ELm3EbES_(
+//CHECK-SAME: <9 x i1> noundef [[X:%.*]], <9 x i1> noundef [[Y:%.*]]) #[[ATTR0]] {
+//CHECK-NEXT:  entry:
+//CHECK:         [[HLSL_AND:%.*]] = and <9 x i32> [[A:%.*]], [[B:%.*]]
+//CHECK:         ret <9 x i1> [[HLSL_AND_CAST:%.*]]
+bool3x3 test_and_bool3x3(bool3x3 x, bool3x3 y)
+{
+    return and(x, y);
+}
+
+//CHECK-LABEL: define hidden noundef <12 x i1> @_Z16test_and_bool3x4u11matrix_typeILm3ELm4EbES_(
+//CHECK-SAME: <12 x i1> noundef [[X:%.*]], <12 x i1> noundef [[Y:%.*]]) #[[ATTR0]] {
+//CHECK-NEXT:  entry:
+//CHECK:         [[HLSL_AND:%.*]] = and <12 x i32> [[A:%.*]], [[B:%.*]]
+//CHECK:         ret <12 x i1> [[HLSL_AND_CAST:%.*]]
+bool3x4 test_and_bool3x4(bool3x4 x, bool3x4 y)
+{
+    return and(x, y);
+}
+
+//CHECK-LABEL: define hidden noundef <4 x i1> @_Z16test_and_bool4x1u11matrix_typeILm4ELm1EbES_(
+//CHECK-SAME: <4 x i1> noundef [[X:%.*]], <4 x i1> noundef [[Y:%.*]]) #[[ATTR0]] {
+//CHECK-NEXT:  entry:
+//CHECK:         [[HLSL_AND:%.*]] = and <4 x i32> [[A:%.*]], [[B:%.*]]
+//CHECK:         ret <4 x i1> [[HLSL_AND_CAST:%.*]]
+bool4x1 test_and_bool4x1(bool4x1 x, bool4x1 y)
+{
+    return and(x, y);
+}
+
+//CHECK-LABEL: define hidden noundef <8 x i1> @_Z16test_and_bool4x2u11matrix_typeILm4ELm2EbES_(
+//CHECK-SAME: <8 x i1> noundef [[X:%.*]], <8 x i1> noundef [[Y:%.*]]) #[[ATTR0]] {
+//CHECK-NEXT:  entry:
+//CHECK:         [[HLSL_AND:%.*]] = and <8 x i32> [[A:%.*]], [[B:%.*]]
+//CHECK:         ret <8 x i1> [[HLSL_AND_CAST:%.*]]
+bool4x2 test_and_bool4x2(bool4x2 x, bool4x2 y)
+{
+    return and(x, y);
+}
+
+//CHECK-LABEL: define hidden noundef <12 x i1> @_Z16test_and_bool4x3u11matrix_typeILm4ELm3EbES_(
+//CHECK-SAME: <12 x i1> noundef [[X:%.*]], <12 x i1> noundef [[Y:%.*]]) #[[ATTR0]] {
+//CHECK-NEXT:  entry:
+//CHECK:         [[HLSL_AND:%.*]] = and <12 x i32> [[A:%.*]], [[B:%.*]]
+//CHECK:         ret <12 x i1> [[HLSL_AND_CAST:%.*]]
+bool4x3 test_and_bool4x3(bool4x3 x, bool4x3 y)
+{
+    return and(x, y);
+}
+
+//CHECK-LABEL: define hidden noundef <16 x i1> @_Z16test_and_bool4x4u11matrix_typeILm4ELm4EbES_(
+//CHECK-SAME: <16 x i1> noundef [[X:%.*]], <16 x i1> noundef [[Y:%.*]]) #[[ATTR0]] {
+//CHECK-NEXT:  entry:
+//CHECK:         [[HLSL_AND:%.*]] = and <16 x i32> [[A:%.*]], [[B:%.*]]
+//CHECK:         ret <16 x i1> [[HLSL_AND_CAST:%.*]]
+bool4x4 test_and_bool4x4(bool4x4 x, bool4x4 y)
+{
+    return and(x, y);
+}
diff --git a/clang/test/CodeGenHLSL/builtins/or.hlsl b/clang/test/CodeGenHLSL/builtins/or.hlsl
index 0a09cd2459fff..53240ec14c202 100644
--- a/clang/test/CodeGenHLSL/builtins/or.hlsl
+++ b/clang/test/CodeGenHLSL/builtins/or.hlsl
@@ -78,3 +78,124 @@ bool4 test_or_float4(float4 x, float4 y)
     return or(x, y);
 }
 
+//CHECK-LABEL: define hidden noundef <2 x i1> @_Z15test_or_bool2x1u11matrix_typeILm2ELm1EbES_(
+//CHECK-SAME: <2 x i1> noundef [[X:%.*]], <2 x i1> noundef [[Y:%.*]]) #[[ATTR0]] {
+//CHECK-NEXT:  entry:
+//CHECK:         [[HLSL_OR:%.*]] = or <2 x i32> [[A:%.*]], [[B:%.*]]
+//CHECK:         ret <2 x i1> [[HLSL_OR_CAST:%.*]]
+bool2x1 test_or_bool2x1(bool2x1 x, bool2x1 y)
+{
+    return or(x, y);
+}
+
+
+//CHECK-LABEL: define hidden noundef <4 x i1> @_Z15test_or_bool2x2u11matrix_typeILm2ELm2EbES_(
+//CHECK-SAME: <4 x i1> noundef [[X:%.*]], <4 x i1> noundef [[Y:%.*]]) #[[ATTR0]] {
+//CHECK-NEXT:  entry:
+//CHECK:         [[HLSL_OR:%.*]] = or <4 x i32> [[A:%.*]], [[B:%.*]]
+//CHECK:         ret <4 x i1> [[HLSL_OR_CAST:%.*]]
+bool2x2 test_or_bool2x2(bool2x2 x, bool2x2 y)
+{
+    return or(x, y);
+}
+
+//CHECK-LABEL: define hidden noundef <6 x i1> @_Z15test_or_bool2x3u11matrix_typeILm2ELm3EbES_(
+//CHECK-SAME: <6 x i1> noundef [[X:%.*]], <6 x i1> noundef [[Y:%.*]]) #[[ATTR0]] {
+//CHECK-NEXT:  entry:
+//CHECK:         [[HLSL_OR:%.*]] = or <6 x i32> [[A:%.*]], [[B:%.*]]
+//CHECK:         ret <6 x i1> [[HLSL_OR_CAST:%.*]]
+bool2x3 test_or_bool2x3(bool2x3 x, bool2x3 y)
+{
+    return or(x, y);
+}
+
+//CHECK-LABEL: define hidden noundef <8 x i1> @_Z15test_or_bool2x4u11matrix_typeILm2ELm4EbES_(
+//CHECK-SAME: <8 x i1> noundef [[X:%.*]], <8 x i1> noundef [[Y:%.*]]) #[[ATTR0]] {
+//CHECK-NEXT:  entry:
+//CHECK:         [[HLSL_OR:%.*]] = or <8 x i32> [[A:%.*]], [[B:%.*]]
+//CHECK:         ret <8 x i1> [[HLSL_OR_CAST:%.*]]
+bool2x4 test_or_bool2x4(bool2x4 x, bool2x4 y)
+{
+    return or(x, y);
+}
+
+//CHECK-LABEL: define hidden noundef <3 x i1> @_Z15test_or_bool3x1u11matrix_typeILm3ELm1EbES_(
+//CHECK-SAME: <3 x i1> noundef [[X:%.*]], <3 x i1> noundef [[Y:%.*]]) #[[ATTR0]] {
+//CHECK-NEXT:  entry:
+//CHECK:         [[HLSL_OR:%.*]] = or <3 x i32> [[A:%.*]], [[B:%.*]]
+//CHECK:         ret <3 x i1> [[HLSL_OR_CAST:%.*]]
+bool3x1 test_or_bool3x1(bool3x1 x, bool3x1 y)
+{
+    return or(x, y);
+}
+
+//CHECK-LABEL: define hidden noundef <6 x i1> @_Z15test_or_bool3x2u11matrix_typeILm3ELm2EbES_(
+//CHECK-SAME: <6 x i1> noundef [[X:%.*]], <6 x i1> noundef [[Y:%.*]]) #[[ATTR0]] {
+//CHECK-NEXT:  entry:
+//CHECK:         [[HLSL_OR:%.*]] = or <6 x i32> [[A:%.*]], [[B:%.*]]
+//CHECK:         ret <6 x i1> [[HLSL_OR_CAST:%.*]]
+bool3x2 test_or_bool3x2(bool3x2 x, bool3x2 y)
+{
+    return or(x, y);
+}
+
+
+//CHECK-LABEL: define hidden noundef <9 x i1> @_Z15test_or_bool3x3u11matrix_typeILm3ELm3EbES_(
+//CHECK-SAME: <9 x i1> noundef [[X:%.*]], <9 x i1> noundef [[Y:%.*]]) #[[ATTR0]] {
+//CHECK-NEXT:  entry:
+//CHECK:         [[HLSL_OR:%.*]] = or <9 x i32> [[A:%.*]], [[B:%.*]]
+//CHECK:         ret <9 x i1> [[HLSL_OR_CAST:%.*]]
+bool3x3 test_or_bool3x3(bool3x3 x, bool3x3 y)
+{
+    return or(x, y);
+}
+
+//CHECK-LABEL: define hidden noundef <12 x i1> @_Z15test_or_bool3x4u11matrix_typeILm3ELm4EbES_(
+//CHECK-SAME: <12 x i1> noundef [[X:%.*]], <12 x i1> noundef [[Y:%.*]]) #[[ATTR0]] {
+//CHECK-NEXT:  entry:
+//CHECK:         [[HLSL_OR:%.*]] = or <12 x i32> [[A:%.*]], [[B:%.*]]
+//CHECK:         ret <12 x i1> [[HLSL_OR_CAST:%.*]]
+bool3x4 test_or_bool3x4(bool3x4 x, bool3x4 y)
+{
+    return or(x, y);
+}
+
+//CHECK-LABEL: define hidden noundef <4 x i1> @_Z15test_or_bool4x1u11matrix_typeILm4ELm1EbES_(
+//CHECK-SAME: <4 x i1> noundef [[X:%.*]], <4 x i1> noundef [[Y:%.*]]) #[[ATTR0]] {
+//CHECK-NEXT:  entry:
+//CHECK:         [[HLSL_OR:%.*]] = or <4 x i32> [[A:%.*]], [[B:%.*]]
+//CHECK:         ret <4 x i1> [[HLSL_OR_CAST:%.*]]
+bool4x1 test_or_bool4x1(bool4x1 x, bool4x1 y)
+{
+    return or(x, y);
+}
+
+//CHECK-LABEL: define hidden noundef <8 x i1> @_Z15test_or_bool4x2u11matrix_typeILm4ELm2EbES_(
+//CHECK-SAME: <8 x i1> noundef [[X:%.*]], <8 x i1> noundef [[Y:%.*]]) #[[ATTR0]] {
+//CHECK-NEXT:  entry:
+//CHECK:         [[HLSL_OR:%.*]] = or <8 x i32> [[A:%.*]], [[B:%.*]]
+//CHECK:         ret <8 x i1> [[HLSL_OR_CAST:%.*]]
+bool4x2 test_or_bool4x2(bool4x2 x, bool4x2 y)
+{
+    return or(x, y);
+}
+
+//CHECK-LABEL: define hidden noundef <12 x i1> @_Z15test_or_bool4x3u11matrix_typeILm4ELm3EbES_(
+//CHECK-SAME: <12 x i1> noundef [[X:%.*]], <12 x i1> noundef [[Y:%.*]]) #[[ATTR0]] {
+//CHECK-NEXT:  entry:
+//CHECK:         [[HLSL_OR:%.*]] = or <12 x i32> [[A:%.*]], [[B:%.*]]
+//CHECK:         ret <12 x i1> [[HLSL_OR_CAST:%.*]]
+bool4x3 test_or_bool4x3(bool4x3 x, bool4x3 y)
+{
+    return or(x, y);
+}
+
+//CHECK-LABEL: define hidden noundef <16 x i1> @_Z15test_or_bool4x4u11matrix_typeILm4ELm4EbES_(
+//CHECK-SAME: <16 x i1> noundef [[X:%.*]], <16 x i1> noundef [[Y:%.*]]) #[[ATTR0]] {
+//CHECK-NEXT:  entry:
+//CHECK:         [[HLSL_OR:%.*]] = or <16 x i32> [[A:%.*]], [[B:%.*]]
+//CHECK:         ret <16 x i1> [[HLSL_OR_CAST:%.*]]
+bool4x4 test_or_bool4x4(bool4x4 x, bool4x4 y)
+{
+    return or(x, y);
+}
diff --git a/clang/test/SemaHLSL/Language/UsualArithmeticConversions.hlsl b/clang/test/SemaHLSL/Language/UsualArithmeticConversions.hlsl
index d9f20a4cb79ec..3c6710a50270c 100644
--- a/clang/test/SemaHLSL/Language/UsualArithmeticConversions.hlsl
+++ b/clang/test/SemaHLSL/Language/UsualArithmeticConversions.hlsl
@@ -359,6 +359,28 @@ export bool4 b4f4i4Logical(f...
[truncated]

Comment on lines +13396 to +13399
if (!getLangOpts().HLSL) {
assert(false && "Logical operands are not support in C\\C++");
return QualType();
}
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This case is an assert where as the 2018 HLSL case is a Sema diagnostic error because its impossible today for C\C++ code to get into this function without explicit support for logical operators. The HLSL code really only exists to disable logical operators for the 2021 language mode. The 2018 language mode is suppose to support them but thats not our default language mode right now so that work will be punted on for now.

@github-actions
Copy link

github-actions bot commented Dec 16, 2025

🪟 Windows x64 Test Results

  • 53043 tests passed
  • 2080 tests skipped

✅ The build succeeded and all tests passed.

@github-actions
Copy link

github-actions bot commented Dec 16, 2025

🐧 Linux x64 Test Results

  • 112075 tests passed
  • 4520 tests skipped

✅ The build succeeded and all tests passed.

Copy link
Contributor

@Icohedron Icohedron left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks fine to me. Just some whitespace nits.

Comment on lines +5 to +9
//CHECK-LABEL: define hidden noundef <2 x i1> @_Z16test_and_bool2x1u11matrix_typeILm2ELm1EbES_(
//CHECK-SAME: <2 x i1> noundef [[X:%.*]], <2 x i1> noundef [[Y:%.*]]) #[[ATTR0:[0-9]+]] {
//CHECK-NEXT: entry:
//CHECK: [[HLSL_AND:%.*]] = and <2 x i32> [[A:%.*]], [[B:%.*]]
//CHECK: ret <2 x i1> [[HLSL_AND_CAST:%.*]]
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: there is no space between the // and CHECK for all occurrences in this file.

Suggested change
//CHECK-LABEL: define hidden noundef <2 x i1> @_Z16test_and_bool2x1u11matrix_typeILm2ELm1EbES_(
//CHECK-SAME: <2 x i1> noundef [[X:%.*]], <2 x i1> noundef [[Y:%.*]]) #[[ATTR0:[0-9]+]] {
//CHECK-NEXT: entry:
//CHECK: [[HLSL_AND:%.*]] = and <2 x i32> [[A:%.*]], [[B:%.*]]
//CHECK: ret <2 x i1> [[HLSL_AND_CAST:%.*]]
// CHECK-LABEL: define hidden noundef <2 x i1> @_Z16test_and_bool2x1u11matrix_typeILm2ELm1EbES_(
// CHECK-SAME: <2 x i1> noundef [[X:%.*]], <2 x i1> noundef [[Y:%.*]]) #[[ATTR0:[0-9]+]] {
// CHECK-NEXT: entry:
// CHECK: [[HLSL_AND:%.*]] = and <2 x i32> [[A:%.*]], [[B:%.*]]
// CHECK: ret <2 x i1> [[HLSL_AND_CAST:%.*]]

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same goes for the or_mat.hlsl test

Comment on lines +1 to +2

// RUN: %clang_cc1 -finclude-default-header -triple dxil-pc-shadermodel6.6-library %s -verify -DTEST_FUNC=or
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: there is an empty line at the start of this file

Suggested change
// RUN: %clang_cc1 -finclude-default-header -triple dxil-pc-shadermodel6.6-library %s -verify -DTEST_FUNC=or
// RUN: %clang_cc1 -finclude-default-header -triple dxil-pc-shadermodel6.6-library %s -verify -DTEST_FUNC=or

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

backend:X86 clang:frontend Language frontend issues, e.g. anything involving "Sema" clang:headers Headers provided by Clang, e.g. for intrinsics clang Clang issues not falling into any other category HLSL HLSL Language Support

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Add boolean comparison operator support for HLSL Matrix

3 participants