Skip to content

Commit f3cd6b7

Browse files
llvm-beanzfarzonlerichkeane
authored
[HLSL] Convert vectors to bool for unary ! (#163857)
HLSL extends C++'s requirement that unary `!` apply to boolean arguments and produces boolean results to apply to vectors. This change implements implicit conversion for non-boolean vector operands to boolean vectors. I've noted this behavior in the issue tracking writing the HLSL specification section on unary operators (microsoft/hlsl-specs#686). Fixes #162913 --------- Co-authored-by: Farzon Lotfi <[email protected]> Co-authored-by: Erich Keane <[email protected]>
1 parent f404517 commit f3cd6b7

File tree

3 files changed

+100
-0
lines changed

3 files changed

+100
-0
lines changed

clang/lib/Sema/SemaExpr.cpp

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15944,6 +15944,20 @@ ExprResult Sema::CreateBuiltinUnaryOp(SourceLocation OpLoc,
1594415944
return ExprError(Diag(OpLoc, diag::err_typecheck_unary_expr)
1594515945
<< resultType << Input.get()->getSourceRange());
1594615946
}
15947+
} else if (Context.getLangOpts().HLSL && resultType->isVectorType() &&
15948+
!resultType->hasBooleanRepresentation()) {
15949+
// HLSL unary logical 'not' behaves like C++, which states that the
15950+
// operand is converted to bool and the result is bool, however HLSL
15951+
// extends this property to vectors.
15952+
const VectorType *VTy = resultType->castAs<VectorType>();
15953+
resultType =
15954+
Context.getExtVectorType(Context.BoolTy, VTy->getNumElements());
15955+
15956+
Input = ImpCastExprToType(
15957+
Input.get(), resultType,
15958+
ScalarTypeToBooleanCastKind(VTy->getElementType()))
15959+
.get();
15960+
break;
1594715961
} else if (resultType->isExtVectorType()) {
1594815962
if (Context.getLangOpts().OpenCL &&
1594915963
Context.getLangOpts().getOpenCLCompatibleVersion() < 120) {
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.6-library -disable-llvm-passes -emit-llvm -finclude-default-header -fnative-half-type -o - %s | FileCheck %s
2+
3+
// CHECK-LABEL: case1
4+
// CHECK: [[ToBool:%.*]] = icmp ne <2 x i32> {{.*}}, zeroinitializer
5+
// CHECK-NEXT: [[BoolCmp:%.*]] = icmp eq <2 x i1> [[ToBool]], zeroinitializer
6+
// CHECK-NEXT: {{.*}} = zext <2 x i1> [[BoolCmp]] to <2 x i32>
7+
export uint32_t2 case1(uint32_t2 b) {
8+
return !b;
9+
}
10+
11+
// CHECK-LABEL: case2
12+
// CHECK: [[ToBool:%.*]] = icmp ne <3 x i32> {{.*}}, zeroinitializer
13+
// CHECK-NEXT: [[BoolCmp:%.*]] = icmp eq <3 x i1> [[ToBool]], zeroinitializer
14+
// CHECK-NEXT: {{.*}} = zext <3 x i1> [[BoolCmp]] to <3 x i32>
15+
export int32_t3 case2(int32_t3 b) {
16+
return !b;
17+
}
18+
19+
// CHECK-LABEL: case3
20+
// CHECK: [[ToBool:%.*]] = fcmp reassoc nnan ninf nsz arcp afn une half {{.*}}, 0xH0000
21+
// CHECK-NEXT: [[BoolCmp:%.*]] = xor i1 [[ToBool]], true
22+
// CHECK-NEXT: {{.*}} = uitofp i1 [[BoolCmp]] to half
23+
export float16_t case3(float16_t b) {
24+
return !b;
25+
}
26+
27+
// CHECK-LABEL: case4
28+
// CHECK: [[ToBool:%.*]] = fcmp reassoc nnan ninf nsz arcp afn une <4 x float> {{.*}}, zeroinitializer
29+
// CHECK-NEXT: [[BoolCmp:%.*]] = icmp eq <4 x i1> [[ToBool]], zeroinitializer
30+
// CHECK-NEXT: {{.*}} = uitofp <4 x i1> [[BoolCmp]] to <4 x float>
31+
export float4 case4(float4 b) {
32+
return !b;
33+
}
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
// RUN: %clang_cc1 -finclude-default-header -triple dxil-pc-shadermodel6.6-library %s -fnative-half-type -ast-dump -ast-dump-filter=case | FileCheck %s
2+
3+
// CHECK-LABEL: FunctionDecl {{.*}} used case1 'uint32_t2 (uint32_t2)'
4+
// CHECK-NEXT: ParmVarDecl {{.*}} used b 'uint32_t2':'vector<uint32_t, 2>'
5+
// CHECK-NEXT: CompoundStmt
6+
// CHECK-NEXT: ReturnStmt
7+
// CHECK-NEXT: ImplicitCastExpr {{.*}} 'vector<uint32_t, 2>' <IntegralCast>
8+
// CHECK-NEXT: UnaryOperator {{.*}} 'vector<bool, 2>' prefix '!' cannot overflow
9+
// CHECK-NEXT: ImplicitCastExpr {{.*}} 'vector<bool, 2>' <IntegralToBoolean>
10+
// CHECK-NEXT: ImplicitCastExpr {{.*}} 'uint32_t2':'vector<uint32_t, 2>' <LValueToRValue>
11+
// CHECK-NEXT: DeclRefExpr {{.*}} 'uint32_t2':'vector<uint32_t, 2>' lvalue ParmVar {{.*}} 'b' 'uint32_t2':'vector<uint32_t, 2>'
12+
export uint32_t2 case1(uint32_t2 b) {
13+
return !b;
14+
}
15+
16+
// CHECK-LABEL: FunctionDecl {{.*}} used case2 'int32_t3 (int32_t3)'
17+
// CHECK-NEXT: ParmVarDecl {{.*}} used b 'int32_t3':'vector<int32_t, 3>'
18+
// CHECK-NEXT: CompoundStmt
19+
// CHECK-NEXT: ReturnStmt
20+
// CHECK-NEXT: ImplicitCastExpr {{.*}} 'vector<int32_t, 3>' <IntegralCast>
21+
// CHECK-NEXT: UnaryOperator {{.*}} 'vector<bool, 3>' prefix '!' cannot overflow
22+
// CHECK-NEXT: ImplicitCastExpr {{.*}} 'vector<bool, 3>' <IntegralToBoolean>
23+
// CHECK-NEXT: ImplicitCastExpr {{.*}} 'int32_t3':'vector<int32_t, 3>' <LValueToRValue>
24+
// CHECK-NEXT: DeclRefExpr {{.*}} 'int32_t3':'vector<int32_t, 3>' lvalue ParmVar {{.*}} 'b' 'int32_t3':'vector<int32_t, 3>'
25+
export int32_t3 case2(int32_t3 b) {
26+
return !b;
27+
}
28+
29+
// CHECK-LABEL: FunctionDecl {{.*}} used case3 'float16_t (float16_t)'
30+
// CHECK-NEXT: ParmVarDecl {{.*}} used b 'float16_t':'half'
31+
// CHECK-NEXT: CompoundStmt
32+
// CHECK-NEXT: ReturnStmt
33+
// CHECK-NEXT: ImplicitCastExpr {{.*}} 'float16_t':'half' <IntegralToFloating>
34+
// CHECK-NEXT: UnaryOperator {{.*}} 'bool' prefix '!' cannot overflow
35+
// CHECK-NEXT: ImplicitCastExpr {{.*}} 'bool' <FloatingToBoolean>
36+
// CHECK-NEXT: ImplicitCastExpr {{.*}} 'float16_t':'half' <LValueToRValue>
37+
// CHECK-NEXT: DeclRefExpr {{.*}} 'float16_t':'half' lvalue ParmVar {{.*}} 'b' 'float16_t':'half'
38+
export float16_t case3(float16_t b) {
39+
return !b;
40+
}
41+
42+
// CHECK-LABEL: FunctionDecl {{.*}} used case4 'float4 (float4)'
43+
// CHECK-NEXT: ParmVarDecl {{.*}} used b 'float4':'vector<float, 4>'
44+
// CHECK-NEXT: CompoundStmt
45+
// CHECK-NEXT: ReturnStmt
46+
// CHECK-NEXT: ImplicitCastExpr {{.*}} 'vector<float, 4>' <IntegralToFloating>
47+
// CHECK-NEXT: UnaryOperator {{.*}} 'vector<bool, 4>' prefix '!' cannot overflow
48+
// CHECK-NEXT: ImplicitCastExpr {{.*}} 'vector<bool, 4>' <FloatingToBoolean>
49+
// CHECK-NEXT: ImplicitCastExpr {{.*}} 'float4':'vector<float, 4>' <LValueToRValue>
50+
// CHECK-NEXT: DeclRefExpr {{.*}} 'float4':'vector<float, 4>' lvalue ParmVar {{.*}} 'b' 'float4':'vector<float, 4>'
51+
export float4 case4(float4 b) {
52+
return !b;
53+
}

0 commit comments

Comments
 (0)