Skip to content

Commit 1c762c2

Browse files
authored
[HLSL] Implement the 'and' HLSL function (#127098)
Addresses #125604 - Implements `and` as an HLSL builtin function - The `and` HLSL builtin function gets lowered to the the LLVM `and` instruction
1 parent 85e23fe commit 1c762c2

File tree

6 files changed

+138
-0
lines changed

6 files changed

+138
-0
lines changed

clang/include/clang/Basic/Builtins.td

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4771,6 +4771,12 @@ def HLSLAll : LangBuiltin<"HLSL_LANG"> {
47714771
let Prototype = "bool(...)";
47724772
}
47734773

4774+
def HLSLAnd : LangBuiltin<"HLSL_LANG"> {
4775+
let Spellings = ["__builtin_hlsl_and"];
4776+
let Attributes = [NoThrow, Const];
4777+
let Prototype = "void(...)";
4778+
}
4779+
47744780
def HLSLAny : LangBuiltin<"HLSL_LANG"> {
47754781
let Spellings = ["__builtin_hlsl_any"];
47764782
let Attributes = [NoThrow, Const];

clang/lib/CodeGen/CGBuiltin.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19506,6 +19506,11 @@ Value *CodeGenFunction::EmitHLSLBuiltinExpr(unsigned BuiltinID,
1950619506
CGM.getHLSLRuntime().getAllIntrinsic(), ArrayRef<Value *>{Op0}, nullptr,
1950719507
"hlsl.all");
1950819508
}
19509+
case Builtin::BI__builtin_hlsl_and: {
19510+
Value *Op0 = EmitScalarExpr(E->getArg(0));
19511+
Value *Op1 = EmitScalarExpr(E->getArg(1));
19512+
return Builder.CreateAnd(Op0, Op1, "hlsl.and");
19513+
}
1950919514
case Builtin::BI__builtin_hlsl_any: {
1951019515
Value *Op0 = EmitScalarExpr(E->getArg(0));
1951119516
return Builder.CreateIntrinsic(

clang/lib/Headers/hlsl/hlsl_intrinsics.h

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -249,6 +249,28 @@ bool all(double3);
249249
_HLSL_BUILTIN_ALIAS(__builtin_hlsl_all)
250250
bool all(double4);
251251

252+
//===----------------------------------------------------------------------===//
253+
// and builtins
254+
//===----------------------------------------------------------------------===//
255+
256+
/// \fn bool and(bool x, bool y)
257+
/// \brief Logically ands two boolean vectors elementwise and produces a bool
258+
/// vector output.
259+
260+
// TODO: Clean up clang-format marker once we've resolved
261+
// https://github.com/llvm/llvm-project/issues/127851
262+
//
263+
// clang-format off
264+
_HLSL_BUILTIN_ALIAS(__builtin_hlsl_and)
265+
bool and(bool x, bool y);
266+
_HLSL_BUILTIN_ALIAS(__builtin_hlsl_and)
267+
bool2 and(bool2 x, bool2 y);
268+
_HLSL_BUILTIN_ALIAS(__builtin_hlsl_and)
269+
bool3 and(bool3 x, bool3 y);
270+
_HLSL_BUILTIN_ALIAS(__builtin_hlsl_and)
271+
bool4 and(bool4 x, bool4 y);
272+
// clang-format on
273+
252274
//===----------------------------------------------------------------------===//
253275
// any builtins
254276
//===----------------------------------------------------------------------===//

clang/lib/Sema/SemaHLSL.cpp

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2245,6 +2245,20 @@ bool SemaHLSL::CheckBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) {
22452245

22462246
break;
22472247
}
2248+
case Builtin::BI__builtin_hlsl_and: {
2249+
if (SemaRef.checkArgCount(TheCall, 2))
2250+
return true;
2251+
if (CheckVectorElementCallArgs(&SemaRef, TheCall))
2252+
return true;
2253+
if (CheckScalarOrVector(&SemaRef, TheCall, getASTContext().BoolTy, 0))
2254+
return true;
2255+
2256+
ExprResult A = TheCall->getArg(0);
2257+
QualType ArgTyA = A.get()->getType();
2258+
// return type is the same as the input type
2259+
TheCall->setType(ArgTyA);
2260+
break;
2261+
}
22482262
case Builtin::BI__builtin_hlsl_all:
22492263
case Builtin::BI__builtin_hlsl_any: {
22502264
if (SemaRef.checkArgCount(TheCall, 1))
Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
// NOTE: Assertions have been autogenerated by utils/update_cc_test_checks.py UTC_ARGS: --version 5
2+
// RUN: %clang_cc1 -finclude-default-header -triple \
3+
// RUN: dxil-pc-shadermodel6.3-library %s \
4+
// RUN: -emit-llvm -O1 -o - | FileCheck %s
5+
6+
// CHECK-LABEL: define noundef i1 @_Z15test_and_scalarbb(
7+
// CHECK-SAME: i1 noundef [[X:%.*]], i1 noundef [[Y:%.*]]) local_unnamed_addr #[[ATTR0:[0-9]+]] {
8+
// CHECK-NEXT: [[ENTRY:.*:]]
9+
// CHECK-NEXT: [[HLSL_AND:%.*]] = and i1 [[X]], [[Y]]
10+
// CHECK-NEXT: ret i1 [[HLSL_AND]]
11+
//
12+
bool test_and_scalar(bool x, bool y) {
13+
return and(x, y);
14+
}
15+
16+
// CHECK-LABEL: define noundef <2 x i1> @_Z14test_and_bool2Dv2_bS_(
17+
// CHECK-SAME: <2 x i1> noundef [[X:%.*]], <2 x i1> noundef [[Y:%.*]]) local_unnamed_addr #[[ATTR0]] {
18+
// CHECK-NEXT: [[ENTRY:.*:]]
19+
// CHECK-NEXT: [[HLSL_AND:%.*]] = and <2 x i1> [[X]], [[Y]]
20+
// CHECK-NEXT: ret <2 x i1> [[HLSL_AND]]
21+
//
22+
bool2 test_and_bool2(bool2 x, bool2 y) {
23+
return and(x, y);
24+
}
25+
26+
// CHECK-LABEL: define noundef <3 x i1> @_Z14test_and_bool3Dv3_bS_(
27+
// CHECK-SAME: <3 x i1> noundef [[X:%.*]], <3 x i1> noundef [[Y:%.*]]) local_unnamed_addr #[[ATTR0]] {
28+
// CHECK-NEXT: [[ENTRY:.*:]]
29+
// CHECK-NEXT: [[HLSL_AND:%.*]] = and <3 x i1> [[X]], [[Y]]
30+
// CHECK-NEXT: ret <3 x i1> [[HLSL_AND]]
31+
//
32+
bool3 test_and_bool3(bool3 x, bool3 y) {
33+
return and(x, y);
34+
}
35+
36+
// CHECK-LABEL: define noundef <4 x i1> @_Z14test_and_bool4Dv4_bS_(
37+
// CHECK-SAME: <4 x i1> noundef [[X:%.*]], <4 x i1> noundef [[Y:%.*]]) local_unnamed_addr #[[ATTR0]] {
38+
// CHECK-NEXT: [[ENTRY:.*:]]
39+
// CHECK-NEXT: [[HLSL_AND:%.*]] = and <4 x i1> [[X]], [[Y]]
40+
// CHECK-NEXT: ret <4 x i1> [[HLSL_AND]]
41+
//
42+
bool4 test_and_bool4(bool4 x, bool4 y) {
43+
return and(x, y);
44+
}
45+
46+
// CHECK-LABEL: define noundef <4 x i1> @_Z13test_and_int4Dv4_iS_(
47+
// CHECK-SAME: <4 x i32> noundef [[X:%.*]], <4 x i32> noundef [[Y:%.*]]) local_unnamed_addr #[[ATTR0]] {
48+
// CHECK-NEXT: [[ENTRY:.*:]]
49+
// CHECK-NEXT: [[TOBOOL:%.*]] = icmp ne <4 x i32> [[X]], zeroinitializer
50+
// CHECK-NEXT: [[TOBOOL1:%.*]] = icmp ne <4 x i32> [[Y]], zeroinitializer
51+
// CHECK-NEXT: [[HLSL_AND:%.*]] = and <4 x i1> [[TOBOOL]], [[TOBOOL1]]
52+
// CHECK-NEXT: ret <4 x i1> [[HLSL_AND]]
53+
//
54+
bool4 test_and_int4(int4 x, int4 y) {
55+
return and(x, y);
56+
}
57+
58+
// CHECK-LABEL: define noundef <4 x i1> @_Z15test_and_float4Dv4_fS_(
59+
// CHECK-SAME: <4 x float> noundef nofpclass(nan inf) [[X:%.*]], <4 x float> noundef nofpclass(nan inf) [[Y:%.*]]) local_unnamed_addr #[[ATTR0]] {
60+
// CHECK-NEXT: [[ENTRY:.*:]]
61+
// CHECK-NEXT: [[TOBOOL:%.*]] = fcmp reassoc nnan ninf nsz arcp afn une <4 x float> [[X]], zeroinitializer
62+
// CHECK-NEXT: [[TOBOOL1:%.*]] = fcmp reassoc nnan ninf nsz arcp afn une <4 x float> [[Y]], zeroinitializer
63+
// CHECK-NEXT: [[HLSL_AND:%.*]] = and <4 x i1> [[TOBOOL]], [[TOBOOL1]]
64+
// CHECK-NEXT: ret <4 x i1> [[HLSL_AND]]
65+
//
66+
bool4 test_and_float4(float4 x, float4 y) {
67+
return and(x, y);
68+
}
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
// RUN: %clang_cc1 -finclude-default-header -triple \
2+
// RUN: dxil-pc-shadermodel6.3-library %s \
3+
// RUN: -emit-llvm -O1 -verify
4+
5+
bool test_too_few_arg(bool a) {
6+
return __builtin_hlsl_and(a);
7+
// expected-error@-1 {{too few arguments to function call, expected 2, have 1}}
8+
}
9+
10+
bool test_too_many_arg(bool a) {
11+
return __builtin_hlsl_and(a, a, a);
12+
// expected-error@-1 {{too many arguments to function call, expected 2, have 3}}
13+
}
14+
15+
bool2 test_mismatched_args(bool2 a, bool3 b) {
16+
return __builtin_hlsl_and(a, b);
17+
// expected-error@-1 {{all arguments to '__builtin_hlsl_and' must have the same type}}
18+
}
19+
20+
bool test_incorrect_type(int a) {
21+
return __builtin_hlsl_and(a, a);
22+
// expected-error@-1{{invalid operand of type 'int' where 'bool' or a vector of such type is required}}
23+
}

0 commit comments

Comments
 (0)