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.de...@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@-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@-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@-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@-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.de...@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.de...@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.de...@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@-1{{no viable conversion from returned value of type 'S' to function return type 'bool'}} + // expected-error@-1{{passing 'S' to parameter of incompatible type 'bool'}} } >From 82bf99855bbf49d57d3d3e53a87b501f688926cd Mon Sep 17 00:00:00 2001 From: Icohedron <cheung.de...@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.de...@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(); _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits