Skip to content

Commit 62dcf74

Browse files
committed
[SPIRV] Cast operands to and and or to bool
The `and` and `or` intrinsics are impliemented with templates for the parameters. This means that the expansion of those intrinics for SPIR-V must add a cast to bool to make the OpLogicalAnd instruction valid. Fixes #6995
1 parent 070d0d5 commit 62dcf74

File tree

4 files changed

+113
-2
lines changed

4 files changed

+113
-2
lines changed

tools/clang/lib/SPIRV/SpirvEmitter.cpp

Lines changed: 27 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9383,6 +9383,20 @@ SpirvEmitter::processIntrinsicCallExpr(const CallExpr *callExpr) {
93839383
case hlsl::IntrinsicOp::IOP_EvaluateAttributeSnapped: {
93849384
retVal = processEvaluateAttributeAt(callExpr, hlslOpcode, srcLoc, srcRange);
93859385
break;
9386+
}
9387+
case hlsl::IntrinsicOp::IOP_and: {
9388+
retVal = createBinaryOpWithBoolOperands(
9389+
spv::Op::OpLogicalAnd, callExpr->getArg(0), callExpr->getArg(1),
9390+
callExpr->getType(), callExpr->getExprLoc(),
9391+
callExpr->getSourceRange());
9392+
break;
9393+
}
9394+
case hlsl::IntrinsicOp::IOP_or: {
9395+
retVal = createBinaryOpWithBoolOperands(
9396+
spv::Op::OpLogicalOr, callExpr->getArg(0), callExpr->getArg(1),
9397+
callExpr->getType(), callExpr->getExprLoc(),
9398+
callExpr->getSourceRange());
9399+
break;
93869400
}
93879401
INTRINSIC_SPIRV_OP_CASE(ddx, DPdx, true);
93889402
INTRINSIC_SPIRV_OP_CASE(ddx_coarse, DPdxCoarse, false);
@@ -9394,8 +9408,6 @@ SpirvEmitter::processIntrinsicCallExpr(const CallExpr *callExpr) {
93949408
INTRINSIC_SPIRV_OP_CASE(fmod, FRem, true);
93959409
INTRINSIC_SPIRV_OP_CASE(fwidth, Fwidth, true);
93969410
INTRINSIC_SPIRV_OP_CASE(reversebits, BitReverse, false);
9397-
INTRINSIC_SPIRV_OP_CASE(and, LogicalAnd, false);
9398-
INTRINSIC_SPIRV_OP_CASE(or, LogicalOr, false);
93999411
INTRINSIC_OP_CASE(round, RoundEven, true);
94009412
INTRINSIC_OP_CASE(uabs, SAbs, true);
94019413
INTRINSIC_OP_CASE_INT_FLOAT(abs, SAbs, FAbs, true);
@@ -9450,6 +9462,19 @@ SpirvEmitter::processIntrinsicCallExpr(const CallExpr *callExpr) {
94509462
return retVal;
94519463
}
94529464

9465+
SpirvInstruction *SpirvEmitter::createBinaryOpWithBoolOperands(
9466+
spv::Op opcode, const Expr *a0, const Expr *a1, QualType resultType,
9467+
SourceLocation loc, SourceRange range) {
9468+
SpirvInstruction *retVal;
9469+
SpirvInstruction *arg0 = castToBool(doExpr(a0), a0->getType(), resultType,
9470+
a0->getExprLoc(), a0->getSourceRange());
9471+
SpirvInstruction *arg1 = castToBool(doExpr(a1), a1->getType(), resultType,
9472+
a1->getExprLoc(), a1->getSourceRange());
9473+
retVal =
9474+
spvBuilder.createBinaryOp(opcode, resultType, arg0, arg1, loc, range);
9475+
return retVal;
9476+
}
9477+
94539478
SpirvInstruction *
94549479
SpirvEmitter::processIntrinsicFirstbit(const CallExpr *callExpr,
94559480
GLSLstd450 glslOpcode) {

tools/clang/lib/SPIRV/SpirvEmitter.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -767,6 +767,13 @@ class SpirvEmitter : public ASTConsumer {
767767
SpirvInstruction *processIntrinsicExecutionMode(const CallExpr *expr,
768768
bool useIdParams);
769769

770+
// Returns a spirv instruction with the given binary opcode with operands `a0`
771+
// and `a1`. The operands will be cast to bool if they are not already bools.
772+
SpirvInstruction *
773+
createBinaryOpWithBoolOperands(spv::Op opcode, const Expr *a0, const Expr *a1,
774+
QualType resultType, SourceLocation loc,
775+
SourceRange range);
776+
770777
/// Processes the 'firstbit{high|low}' intrinsic functions.
771778
SpirvInstruction *processIntrinsicFirstbit(const CallExpr *,
772779
GLSLstd450 glslOpcode);

tools/clang/test/CodeGenSPIRV/intrinsics.and.hlsl

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
11
// RUN: %dxc -T ps_6_0 -E main -HV 2021 -fcgl %s -spirv | FileCheck %s
22
// RUN: %dxc -T ps_6_0 -E main -HV 2018 -fcgl %s -spirv | FileCheck %s
33

4+
// CHECK-DAG: [[v3_0:%[0-9]+]] = OpConstantComposite %v3int %int_0 %int_0 %int_0
5+
// CHECK-DAG: [[v3_1:%[0-9]+]] = OpConstantComposite %v3int %int_1 %int_1 %int_1
6+
47
void main() {
58
// CHECK-LABEL: %bb_entry = OpLabel
69

@@ -33,4 +36,46 @@ void main() {
3336
// CHECK-NEXT: [[and3:%[0-9]+]] = OpLogicalAnd %bool [[a1]] [[b1]]
3437
// CHECK-NEXT: {{%[0-9]+}} = OpCompositeConstruct %v2bool [[and3]] %true
3538
bool2 t = bool2(and(a, b), true);
39+
40+
int a_0, b_0, c_0;
41+
// Plain assign (scalar)
42+
// CHECK: [[a0_int:%[0-9]+]] = OpLoad %int %a_0
43+
// CHECK-NEXT: [[a0:%[0-9]+]] = OpINotEqual %bool [[a0_int]] %int_0
44+
// CHECK-NEXT: [[b0_int:%[0-9]+]] = OpLoad %int %b_0
45+
// CHECK-NEXT: [[b0:%[0-9]+]] = OpINotEqual %bool [[b0_int]] %int_0
46+
// CHECK-NEXT: [[and0:%[0-9]+]] = OpLogicalAnd %bool [[a0]] [[b0]]
47+
// CHECK-NEXT: [[sel:%[0-9]+]] = OpSelect %int [[and0]] %int_1 %int_0
48+
// CHECK-NEXT: OpStore %c_0 [[sel]]
49+
c_0 = and(a_0, b_0);
50+
51+
int1 i_0, j_0, k_0;
52+
int3 o_0, p_0, q_0;
53+
// Plain assign (vector)
54+
// CHECK-NEXT: [[i0_int:%[0-9]+]] = OpLoad %int %i_0
55+
// CHECK-NEXT: [[i0:%[0-9]+]] = OpINotEqual %bool [[i0_int]] %int_0
56+
// CHECK-NEXT: [[j0_int:%[0-9]+]] = OpLoad %int %j_0
57+
// CHECK-NEXT: [[j0:%[0-9]+]] = OpINotEqual %bool [[j0_int]] %int_0
58+
// CHECK-NEXT: [[and1:%[0-9]+]] = OpLogicalAnd %bool [[i0]] [[j0]]
59+
// CHECK-NEXT: [[sel:%[0-9]+]] = OpSelect %int [[and1]] %int_1 %int_0
60+
// CHECK-NEXT: OpStore %k_0 [[sel]]
61+
k_0 = and(i_0, j_0);
62+
63+
// CHECK-NEXT: [[o0_int:%[0-9]+]] = OpLoad %v3int %o_0
64+
// CHECK-NEXT: [[o0:%[0-9]+]] = OpINotEqual %v3bool [[o0_int]] [[v3_0]]
65+
// CHECK-NEXT: [[p0_int:%[0-9]+]] = OpLoad %v3int %p_0
66+
// CHECK-NEXT: [[p0:%[0-9]+]] = OpINotEqual %v3bool [[p0_int]] [[v3_0]]
67+
// CHECK-NEXT: [[and2:%[0-9]+]] = OpLogicalAnd %v3bool [[o0]] [[p0]]
68+
// CHECK-NEXT: [[sel:%[0-9]+]] = OpSelect %v3int [[and2]] [[v3_1]] [[v3_0]]
69+
// CHECK-NEXT: OpStore %q_0 [[sel]]
70+
q_0 = and(o_0, p_0);
71+
72+
// The result of '&&' could be 'const bool'. In such cases, make sure
73+
// the result type is correct.
74+
// CHECK: [[a0_int:%[0-9]+]] = OpLoad %int %a_0
75+
// CHECK-NEXT: [[a0:%[0-9]+]] = OpINotEqual %bool [[a0_int]] %int_0
76+
// CHECK-NEXT: [[b0_int:%[0-9]+]] = OpLoad %int %b_0
77+
// CHECK-NEXT: [[b0:%[0-9]+]] = OpINotEqual %bool [[b0_int]] %int_0
78+
// CHECK-NEXT: [[and0:%[0-9]+]] = OpLogicalAnd %bool [[a0]] [[b0]]
79+
// CHECK-NEXT: {{%[0-9]+}} = OpCompositeConstruct %v2bool [[and0]] %true
80+
bool2 t = bool2(and(a_0, b_0), true);
3681
}

tools/clang/test/CodeGenSPIRV/intrinsics.or.hlsl

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
// RUN: %dxc -T ps_6_0 -E main -HV 2021 -fcgl %s -spirv | FileCheck %s
22
// RUN: %dxc -T ps_6_0 -E main -HV 2018 -fcgl %s -spirv | FileCheck %s
33

4+
// CHECK: [[v3_0:%[0-9]+]] = OpConstantComposite %v3int %int_0 %int_0 %int_0
5+
46
void main() {
57
// CHECK-LABEL: %bb_entry = OpLabel
68

@@ -25,4 +27,36 @@ void main() {
2527
// CHECK-NEXT: OpStore %q [[or2]]
2628
k = or(i, j);
2729
q = or(o, p);
30+
31+
int r, s;
32+
bool t;
33+
// Plain assign (scalar)
34+
// CHECK: [[r0_int:%[0-9]+]] = OpLoad %int %r
35+
// CHECK-NEXT: [[r0:%[0-9]+]] = OpINotEqual %bool [[r0_int]] %int_0
36+
// CHECK-NEXT: [[s0_int:%[0-9]+]] = OpLoad %int %s
37+
// CHECK-NEXT: [[s0:%[0-9]+]] = OpINotEqual %bool [[s0_int]] %int_0
38+
// CHECK-NEXT: [[or0:%[0-9]+]] = OpLogicalOr %bool [[r0]] [[s0]]
39+
// CHECK-NEXT: OpStore %t [[or0]]
40+
t = or(r, s);
41+
42+
int1 u, v;
43+
bool1 w;
44+
// Plain assign (vector)
45+
// CHECK-NEXT: [[u0_int:%[0-9]+]] = OpLoad %int %u
46+
// CHECK-NEXT: [[u0:%[0-9]+]] = OpINotEqual %bool [[u0_int]] %int_0
47+
// CHECK-NEXT: [[v0_int:%[0-9]+]] = OpLoad %int %v
48+
// CHECK-NEXT: [[v0:%[0-9]+]] = OpINotEqual %bool [[v0_int]] %int_0
49+
// CHECK-NEXT: [[or1:%[0-9]+]] = OpLogicalOr %bool [[u0]] [[v0]]
50+
// CHECK-NEXT: OpStore %w [[or1]]
51+
w = or(u, v);
52+
53+
int3 x, y;
54+
bool3 z;
55+
// CHECK-NEXT: [[x0_int:%[0-9]+]] = OpLoad %v3int %x
56+
// CHECK-NEXT: [[x0:%[0-9]+]] = OpINotEqual %v3bool [[x0_int]] [[v3_0]]
57+
// CHECK-NEXT: [[y0_int:%[0-9]+]] = OpLoad %v3int %y
58+
// CHECK-NEXT: [[y0:%[0-9]+]] = OpINotEqual %v3bool [[y0_int]] [[v3_0]]
59+
// CHECK-NEXT: [[or2:%[0-9]+]] = OpLogicalOr %v3bool [[x0]] [[y0]]
60+
// CHECK-NEXT: OpStore %z [[or2]]
61+
z = or(x, y);
2862
}

0 commit comments

Comments
 (0)