[clang] [HLSL] Implement the 'and' HLSL function (PR #127098)
Deric Cheung via cfe-commits
cfe-commits at lists.llvm.org
Fri Feb 14 19:21:27 PST 2025
https://github.com/Icohedron updated https://github.com/llvm/llvm-project/pull/127098
>From 5b093ca42fdc24f89bfccac25e6f2e17155432f6 Mon Sep 17 00:00:00 2001
From: Icohedron <cheung.deric at gmail.com>
Date: Wed, 12 Feb 2025 21:24:00 +0000
Subject: [PATCH 1/6] Implement the 'and' HLSL function
---
clang/include/clang/Basic/Builtins.td | 6 +++
clang/lib/CodeGen/CGBuiltin.cpp | 5 +++
clang/lib/Headers/hlsl/hlsl_intrinsics.h | 16 +++++++
clang/lib/Sema/SemaHLSL.cpp | 11 +++++
clang/test/CodeGenHLSL/builtins/and.hlsl | 45 ++++++++++++++++++++
clang/test/SemaHLSL/BuiltIns/and-errors.hlsl | 27 ++++++++++++
6 files changed, 110 insertions(+)
create mode 100644 clang/test/CodeGenHLSL/builtins/and.hlsl
create mode 100644 clang/test/SemaHLSL/BuiltIns/and-errors.hlsl
diff --git a/clang/include/clang/Basic/Builtins.td b/clang/include/clang/Basic/Builtins.td
index 29939242596ba..de758d88f8f92 100644
--- a/clang/include/clang/Basic/Builtins.td
+++ b/clang/include/clang/Basic/Builtins.td
@@ -4765,6 +4765,12 @@ def HLSLAll : LangBuiltin<"HLSL_LANG"> {
let Prototype = "bool(...)";
}
+def HLSLAnd : LangBuiltin<"HLSL_LANG"> {
+ let Spellings = ["__builtin_hlsl_and"];
+ let Attributes = [NoThrow, Const];
+ let Prototype = "void(...)";
+}
+
def HLSLAny : LangBuiltin<"HLSL_LANG"> {
let Spellings = ["__builtin_hlsl_any"];
let Attributes = [NoThrow, Const];
diff --git a/clang/lib/CodeGen/CGBuiltin.cpp b/clang/lib/CodeGen/CGBuiltin.cpp
index 361e4c4bf2e2e..82527cb5e1f7a 100644
--- a/clang/lib/CodeGen/CGBuiltin.cpp
+++ b/clang/lib/CodeGen/CGBuiltin.cpp
@@ -19463,6 +19463,11 @@ Value *CodeGenFunction::EmitHLSLBuiltinExpr(unsigned BuiltinID,
CGM.getHLSLRuntime().getAllIntrinsic(), ArrayRef<Value *>{Op0}, nullptr,
"hlsl.all");
}
+ case Builtin::BI__builtin_hlsl_and: {
+ Value *Op0 = EmitScalarExpr(E->getArg(0));
+ Value *Op1 = EmitScalarExpr(E->getArg(1));
+ return Builder.CreateAnd(Op0, Op1, "hlsl.and");
+ }
case Builtin::BI__builtin_hlsl_any: {
Value *Op0 = EmitScalarExpr(E->getArg(0));
return Builder.CreateIntrinsic(
diff --git a/clang/lib/Headers/hlsl/hlsl_intrinsics.h b/clang/lib/Headers/hlsl/hlsl_intrinsics.h
index d1f5fdff8b600..7016b45d1c641 100644
--- a/clang/lib/Headers/hlsl/hlsl_intrinsics.h
+++ b/clang/lib/Headers/hlsl/hlsl_intrinsics.h
@@ -249,6 +249,22 @@ bool all(double3);
_HLSL_BUILTIN_ALIAS(__builtin_hlsl_all)
bool all(double4);
+//===----------------------------------------------------------------------===//
+// and builtins
+//===----------------------------------------------------------------------===//
+
+// \fn bool and(bool x, bool y)
+// \brief Logically ands two boolean vectors elementwise and produces a bool vector output.
+
+_HLSL_BUILTIN_ALIAS(__builtin_hlsl_and)
+bool and(bool x, bool y);
+_HLSL_BUILTIN_ALIAS(__builtin_hlsl_and)
+bool2 and(bool2 x, bool2 y);
+_HLSL_BUILTIN_ALIAS(__builtin_hlsl_and)
+bool3 and(bool3 x, bool3 y);
+_HLSL_BUILTIN_ALIAS(__builtin_hlsl_and)
+bool4 and(bool4 x, bool4 y);
+
//===----------------------------------------------------------------------===//
// any builtins
//===----------------------------------------------------------------------===//
diff --git a/clang/lib/Sema/SemaHLSL.cpp b/clang/lib/Sema/SemaHLSL.cpp
index 4abd870ad6aaa..7297fb3a9e4d0 100644
--- a/clang/lib/Sema/SemaHLSL.cpp
+++ b/clang/lib/Sema/SemaHLSL.cpp
@@ -2245,6 +2245,17 @@ bool SemaHLSL::CheckBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) {
break;
}
+ case Builtin::BI__builtin_hlsl_and: {
+ if (SemaRef.checkArgCount(TheCall, 2))
+ return true;
+ if (CheckVectorElementCallArgs(&SemaRef, TheCall))
+ return true;
+ ExprResult A = TheCall->getArg(0);
+ QualType ArgTyA = A.get()->getType();
+ // return type is the same as the input type
+ TheCall->setType(ArgTyA);
+ break;
+ }
case Builtin::BI__builtin_hlsl_all:
case Builtin::BI__builtin_hlsl_any: {
if (SemaRef.checkArgCount(TheCall, 1))
diff --git a/clang/test/CodeGenHLSL/builtins/and.hlsl b/clang/test/CodeGenHLSL/builtins/and.hlsl
new file mode 100644
index 0000000000000..60295f192f5cc
--- /dev/null
+++ b/clang/test/CodeGenHLSL/builtins/and.hlsl
@@ -0,0 +1,45 @@
+// NOTE: Assertions have been autogenerated by utils/update_cc_test_checks.py UTC_ARGS: --version 5
+// RUN: %clang_cc1 -finclude-default-header -triple \
+// RUN: dxil-pc-shadermodel6.3-library %s \
+// RUN: -emit-llvm -O1 -o - | FileCheck %s
+
+// CHECK-LABEL: define noundef i1 @_Z15test_and_scalarbb(
+// CHECK-SAME: i1 noundef [[X:%.*]], i1 noundef [[Y:%.*]]) local_unnamed_addr #[[ATTR0:[0-9]+]] {
+// CHECK-NEXT: [[ENTRY:.*:]]
+// CHECK-NEXT: [[HLSL_AND:%.*]] = and i1 [[X]], [[Y]]
+// CHECK-NEXT: ret i1 [[HLSL_AND]]
+//
+bool test_and_scalar(bool x, bool y) {
+ return and(x, y);
+}
+
+// CHECK-LABEL: define noundef <2 x i1> @_Z14test_and_bool2Dv2_bS_(
+// CHECK-SAME: <2 x i1> noundef [[X:%.*]], <2 x i1> noundef [[Y:%.*]]) local_unnamed_addr #[[ATTR0]] {
+// CHECK-NEXT: [[ENTRY:.*:]]
+// CHECK-NEXT: [[HLSL_AND:%.*]] = and <2 x i1> [[X]], [[Y]]
+// CHECK-NEXT: ret <2 x i1> [[HLSL_AND]]
+//
+bool2 test_and_bool2(bool2 x, bool2 y) {
+ return and(x, y);
+}
+
+// CHECK-LABEL: define noundef <3 x i1> @_Z14test_and_bool3Dv3_bS_(
+// CHECK-SAME: <3 x i1> noundef [[X:%.*]], <3 x i1> noundef [[Y:%.*]]) local_unnamed_addr #[[ATTR0]] {
+// CHECK-NEXT: [[ENTRY:.*:]]
+// CHECK-NEXT: [[HLSL_AND:%.*]] = and <3 x i1> [[X]], [[Y]]
+// CHECK-NEXT: ret <3 x i1> [[HLSL_AND]]
+//
+bool3 test_and_bool3(bool3 x, bool3 y) {
+ return and(x, y);
+}
+
+// CHECK-LABEL: define noundef <4 x i1> @_Z14test_and_bool4Dv4_bS_(
+// CHECK-SAME: <4 x i1> noundef [[X:%.*]], <4 x i1> noundef [[Y:%.*]]) local_unnamed_addr #[[ATTR0]] {
+// CHECK-NEXT: [[ENTRY:.*:]]
+// CHECK-NEXT: [[HLSL_AND:%.*]] = and <4 x i1> [[X]], [[Y]]
+// CHECK-NEXT: ret <4 x i1> [[HLSL_AND]]
+//
+bool4 test_and_bool4(bool4 x, bool4 y) {
+ return and(x, y);
+}
+
diff --git a/clang/test/SemaHLSL/BuiltIns/and-errors.hlsl b/clang/test/SemaHLSL/BuiltIns/and-errors.hlsl
new file mode 100644
index 0000000000000..0fbf172d46ccd
--- /dev/null
+++ b/clang/test/SemaHLSL/BuiltIns/and-errors.hlsl
@@ -0,0 +1,27 @@
+// RUN: %clang_cc1 -finclude-default-header -triple \
+// RUN: dxil-pc-shadermodel6.3-library %s \
+// RUN: -emit-llvm -O1 -verify
+
+bool test_too_few_arg(bool a) {
+ return __builtin_hlsl_and(a);
+ // expected-error at -1 {{too few arguments to function call, expected 2, have 1}}
+}
+
+bool test_too_many_arg(bool a) {
+ return __builtin_hlsl_and(a, a, a);
+ // expected-error at -1 {{too many arguments to function call, expected 2, have 3}}
+}
+
+bool2 test_mismatched_args(bool2 a, bool3 b) {
+ return __builtin_hlsl_and(a, b);
+ // expected-error at -1 {{all arguments to '__builtin_hlsl_and' must have the same type}}
+}
+
+struct S {
+ bool a;
+};
+
+bool test_invalid_type_conversion(S s) {
+ return __builtin_hlsl_and(s, s);
+ // expected-error at -1{{no viable conversion from returned value of type 'S' to function return type 'bool'}}
+}
>From ce311652dfb30b1e7c484c2d998b43dd9283d463 Mon Sep 17 00:00:00 2001
From: Icohedron <cheung.deric at gmail.com>
Date: Thu, 13 Feb 2025 17:43:48 +0000
Subject: [PATCH 2/6] Apply clang-format
---
clang/lib/Headers/hlsl/hlsl_intrinsics.h | 11 ++++++-----
1 file changed, 6 insertions(+), 5 deletions(-)
diff --git a/clang/lib/Headers/hlsl/hlsl_intrinsics.h b/clang/lib/Headers/hlsl/hlsl_intrinsics.h
index 7016b45d1c641..c3f5bb28d5838 100644
--- a/clang/lib/Headers/hlsl/hlsl_intrinsics.h
+++ b/clang/lib/Headers/hlsl/hlsl_intrinsics.h
@@ -254,16 +254,17 @@ 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 elementwise and produces a bool
+// vector output.
_HLSL_BUILTIN_ALIAS(__builtin_hlsl_and)
-bool and(bool x, bool y);
+bool and (bool x, bool y);
_HLSL_BUILTIN_ALIAS(__builtin_hlsl_and)
-bool2 and(bool2 x, bool2 y);
+bool2 and (bool2 x, bool2 y);
_HLSL_BUILTIN_ALIAS(__builtin_hlsl_and)
-bool3 and(bool3 x, bool3 y);
+bool3 and (bool3 x, bool3 y);
_HLSL_BUILTIN_ALIAS(__builtin_hlsl_and)
-bool4 and(bool4 x, bool4 y);
+bool4 and (bool4 x, bool4 y);
//===----------------------------------------------------------------------===//
// any builtins
>From 1f2e8d745d246ae3497e3b7edd20d78898a53ac3 Mon Sep 17 00:00:00 2001
From: Icohedron <cheung.deric at gmail.com>
Date: Thu, 13 Feb 2025 18:18:50 +0000
Subject: [PATCH 3/6] Add additional forward slash to and builtin docs
---
clang/lib/Headers/hlsl/hlsl_intrinsics.h | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/clang/lib/Headers/hlsl/hlsl_intrinsics.h b/clang/lib/Headers/hlsl/hlsl_intrinsics.h
index c3f5bb28d5838..abac41f34e8ac 100644
--- a/clang/lib/Headers/hlsl/hlsl_intrinsics.h
+++ b/clang/lib/Headers/hlsl/hlsl_intrinsics.h
@@ -253,9 +253,9 @@ bool all(double4);
// and builtins
//===----------------------------------------------------------------------===//
-// \fn bool and(bool x, bool y)
-// \brief Logically ands two boolean vectors elementwise and produces a bool
-// vector output.
+/// \fn bool and(bool x, bool y)
+/// \brief Logically ands two boolean vectors elementwise and produces a bool
+/// vector output.
_HLSL_BUILTIN_ALIAS(__builtin_hlsl_and)
bool and (bool x, bool y);
>From ba50dda30d2b5f6670baef869983b3a104aa19b9 Mon Sep 17 00:00:00 2001
From: Icohedron <cheung.deric at gmail.com>
Date: Sat, 15 Feb 2025 00:43:27 +0000
Subject: [PATCH 4/6] Add check for args to match bool type
---
clang/lib/Sema/SemaHLSL.cpp | 10 +++++++++
clang/test/CodeGenHLSL/builtins/and.hlsl | 23 ++++++++++++++++++++
clang/test/SemaHLSL/BuiltIns/and-errors.hlsl | 2 +-
3 files changed, 34 insertions(+), 1 deletion(-)
diff --git a/clang/lib/Sema/SemaHLSL.cpp b/clang/lib/Sema/SemaHLSL.cpp
index 7297fb3a9e4d0..12f79374af068 100644
--- a/clang/lib/Sema/SemaHLSL.cpp
+++ b/clang/lib/Sema/SemaHLSL.cpp
@@ -2079,6 +2079,14 @@ static bool CheckFloatingOrIntRepresentation(Sema *S, CallExpr *TheCall) {
checkAllSignedTypes);
}
+static bool CheckBoolRepresentation(Sema *S, CallExpr *TheCall) {
+ auto checkAllBoolTypes = [](clang::QualType PassedType) -> bool {
+ return !PassedType->hasIntegerRepresentation();
+ };
+ return CheckAllArgTypesAreCorrect(S, TheCall, S->Context.BoolTy,
+ checkAllBoolTypes);
+}
+
static bool CheckUnsignedIntRepresentation(Sema *S, CallExpr *TheCall) {
auto checkAllUnsignedTypes = [](clang::QualType PassedType) -> bool {
return !PassedType->hasUnsignedIntegerRepresentation();
@@ -2250,6 +2258,8 @@ bool SemaHLSL::CheckBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) {
return true;
if (CheckVectorElementCallArgs(&SemaRef, TheCall))
return true;
+ if (CheckBoolRepresentation(&SemaRef, TheCall))
+ return true;
ExprResult A = TheCall->getArg(0);
QualType ArgTyA = A.get()->getType();
// return type is the same as the input type
diff --git a/clang/test/CodeGenHLSL/builtins/and.hlsl b/clang/test/CodeGenHLSL/builtins/and.hlsl
index 60295f192f5cc..b77889cd9ae70 100644
--- a/clang/test/CodeGenHLSL/builtins/and.hlsl
+++ b/clang/test/CodeGenHLSL/builtins/and.hlsl
@@ -43,3 +43,26 @@ bool4 test_and_bool4(bool4 x, bool4 y) {
return and(x, y);
}
+// CHECK-LABEL: define noundef <4 x i1> @_Z13test_and_int4Dv4_iS_(
+// CHECK-SAME: <4 x i32> noundef [[X:%.*]], <4 x i32> noundef [[Y:%.*]]) local_unnamed_addr #[[ATTR0]] {
+// CHECK-NEXT: [[ENTRY:.*:]]
+// CHECK-NEXT: [[TOBOOL:%.*]] = icmp ne <4 x i32> [[X]], zeroinitializer
+// CHECK-NEXT: [[TOBOOL1:%.*]] = icmp ne <4 x i32> [[Y]], zeroinitializer
+// CHECK-NEXT: [[HLSL_AND:%.*]] = and <4 x i1> [[TOBOOL]], [[TOBOOL1]]
+// CHECK-NEXT: ret <4 x i1> [[HLSL_AND]]
+//
+bool4 test_and_int4(int4 x, int4 y) {
+ return and(x, y);
+}
+
+// CHECK-LABEL: define noundef <4 x i1> @_Z15test_and_float4Dv4_fS_(
+// CHECK-SAME: <4 x float> noundef nofpclass(nan inf) [[X:%.*]], <4 x float> noundef nofpclass(nan inf) [[Y:%.*]]) local_unnamed_addr #[[ATTR0]] {
+// CHECK-NEXT: [[ENTRY:.*:]]
+// CHECK-NEXT: [[TOBOOL:%.*]] = fcmp reassoc nnan ninf nsz arcp afn une <4 x float> [[X]], zeroinitializer
+// CHECK-NEXT: [[TOBOOL1:%.*]] = fcmp reassoc nnan ninf nsz arcp afn une <4 x float> [[Y]], zeroinitializer
+// CHECK-NEXT: [[HLSL_AND:%.*]] = and <4 x i1> [[TOBOOL]], [[TOBOOL1]]
+// CHECK-NEXT: ret <4 x i1> [[HLSL_AND]]
+//
+bool4 test_and_float4(float4 x, float4 y) {
+ return and(x, y);
+}
diff --git a/clang/test/SemaHLSL/BuiltIns/and-errors.hlsl b/clang/test/SemaHLSL/BuiltIns/and-errors.hlsl
index 0fbf172d46ccd..c256003317a65 100644
--- a/clang/test/SemaHLSL/BuiltIns/and-errors.hlsl
+++ b/clang/test/SemaHLSL/BuiltIns/and-errors.hlsl
@@ -23,5 +23,5 @@ struct S {
bool test_invalid_type_conversion(S s) {
return __builtin_hlsl_and(s, s);
- // expected-error at -1{{no viable conversion from returned value of type 'S' to function return type 'bool'}}
+ // expected-error at -1{{passing 'S' to parameter of incompatible type 'bool'}}
}
>From 82bf99855bbf49d57d3d3e53a87b501f688926cd Mon Sep 17 00:00:00 2001
From: Icohedron <cheung.deric at gmail.com>
Date: Sat, 15 Feb 2025 03:08:38 +0000
Subject: [PATCH 5/6] Revise type check for bool parameters
---
clang/lib/Sema/SemaHLSL.cpp | 23 ++++++++++++++---------
1 file changed, 14 insertions(+), 9 deletions(-)
diff --git a/clang/lib/Sema/SemaHLSL.cpp b/clang/lib/Sema/SemaHLSL.cpp
index 12f79374af068..04ba998e3e5d2 100644
--- a/clang/lib/Sema/SemaHLSL.cpp
+++ b/clang/lib/Sema/SemaHLSL.cpp
@@ -2079,14 +2079,6 @@ static bool CheckFloatingOrIntRepresentation(Sema *S, CallExpr *TheCall) {
checkAllSignedTypes);
}
-static bool CheckBoolRepresentation(Sema *S, CallExpr *TheCall) {
- auto checkAllBoolTypes = [](clang::QualType PassedType) -> bool {
- return !PassedType->hasIntegerRepresentation();
- };
- return CheckAllArgTypesAreCorrect(S, TheCall, S->Context.BoolTy,
- checkAllBoolTypes);
-}
-
static bool CheckUnsignedIntRepresentation(Sema *S, CallExpr *TheCall) {
auto checkAllUnsignedTypes = [](clang::QualType PassedType) -> bool {
return !PassedType->hasUnsignedIntegerRepresentation();
@@ -2258,8 +2250,21 @@ bool SemaHLSL::CheckBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) {
return true;
if (CheckVectorElementCallArgs(&SemaRef, TheCall))
return true;
- if (CheckBoolRepresentation(&SemaRef, TheCall))
+
+ // check that the arguments are bools or, if vectors,
+ // vectors of bools
+ QualType ArgTy = TheCall->getArg(0)->getType();
+ if (const auto *VecTy = ArgTy->getAs<VectorType>()) {
+ ArgTy = VecTy->getElementType();
+ }
+ if (!getASTContext().hasSameUnqualifiedType(ArgTy,
+ getASTContext().BoolTy)) {
+ SemaRef.Diag(TheCall->getBeginLoc(),
+ diag::err_typecheck_convert_incompatible)
+ << ArgTy << getASTContext().BoolTy << 1 << 0 << 0;
return true;
+ }
+
ExprResult A = TheCall->getArg(0);
QualType ArgTyA = A.get()->getType();
// return type is the same as the input type
>From 70133ee28c2e92f45f86248596e85d280e9a9314 Mon Sep 17 00:00:00 2001
From: Icohedron <cheung.deric at gmail.com>
Date: Sat, 15 Feb 2025 03:20:50 +0000
Subject: [PATCH 6/6] Add assertion for clarity when checking arg types
---
clang/lib/Sema/SemaHLSL.cpp | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/clang/lib/Sema/SemaHLSL.cpp b/clang/lib/Sema/SemaHLSL.cpp
index 04ba998e3e5d2..9b7306f9e444e 100644
--- a/clang/lib/Sema/SemaHLSL.cpp
+++ b/clang/lib/Sema/SemaHLSL.cpp
@@ -2251,6 +2251,10 @@ bool SemaHLSL::CheckBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) {
if (CheckVectorElementCallArgs(&SemaRef, TheCall))
return true;
+ // CheckVectorElementCallArgs(...) guarantees both args are the same type.
+ assert(TheCall->getArg(0)->getType() == TheCall->getArg(1)->getType() &&
+ "Both args must be of the same type");
+
// check that the arguments are bools or, if vectors,
// vectors of bools
QualType ArgTy = TheCall->getArg(0)->getType();
More information about the cfe-commits
mailing list