Skip to content

Commit 9cd1f68

Browse files
authored
Correct const check for atomic methods (microsoft#4472)
The check for a const destination param for atomic functions mistakenly encompassed the first param of atomic methods, which is an offset and can very well be const. This changes the check to account for methods when relevant. Adds a test for this and a few other aspects of atomic methods
1 parent 227bd31 commit 9cd1f68

File tree

2 files changed

+101
-4
lines changed

2 files changed

+101
-4
lines changed

tools/clang/lib/Sema/SemaHLSL.cpp

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1862,7 +1862,10 @@ static bool IsBuiltinTable(LPCSTR tableName) {
18621862
return tableName == kBuiltinIntrinsicTableName;
18631863
}
18641864

1865-
static bool IsAtomicOperation(LPCSTR tableName, IntrinsicOp op) {
1865+
// Return true if the give <op> within the <tableName> namespace
1866+
// maps to an atomic operation.
1867+
// <acceptMethods> determines if atomic method operations will return true
1868+
static bool IsAtomicOperation(LPCSTR tableName, IntrinsicOp op, bool acceptMethods=true) {
18661869
if (!IsBuiltinTable(tableName))
18671870
return false;
18681871
switch (op) {
@@ -1877,6 +1880,7 @@ static bool IsAtomicOperation(LPCSTR tableName, IntrinsicOp op) {
18771880
case IntrinsicOp::IOP_InterlockedMin:
18781881
case IntrinsicOp::IOP_InterlockedOr:
18791882
case IntrinsicOp::IOP_InterlockedXor:
1883+
return true;
18801884
case IntrinsicOp::MOP_InterlockedAdd:
18811885
case IntrinsicOp::MOP_InterlockedAnd:
18821886
case IntrinsicOp::MOP_InterlockedCompareExchange:
@@ -1898,7 +1902,7 @@ static bool IsAtomicOperation(LPCSTR tableName, IntrinsicOp op) {
18981902
case IntrinsicOp::MOP_InterlockedExchangeFloat:
18991903
case IntrinsicOp::MOP_InterlockedCompareExchangeFloatBitwise:
19001904
case IntrinsicOp::MOP_InterlockedCompareStoreFloatBitwise:
1901-
return true;
1905+
return acceptMethods;
19021906
default:
19031907
return false;
19041908
}
@@ -6180,8 +6184,9 @@ bool HLSLExternalSource::MatchArguments(
61806184

61816185
// Catch invalid atomic dest parameters
61826186
if (iArg == kAtomicDstOperandIdx &&
6183-
IsAtomicOperation(tableName, builtinOp)) {
6184-
// This produces an error for bitfields that is a bit confusing because it says uint can't cast to uint
6187+
IsAtomicOperation(tableName, builtinOp, false /*acceptMethods*/)) {
6188+
// This produces an error for bitfields that is a bit confusing
6189+
// because it says uint can't cast to uint
61856190
if (pType.isConstant(actx) || pCallArg->getObjectKind() == OK_BitField) {
61866191
badArgIdx = std::min(badArgIdx, iArg);
61876192
}
Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
// RUN: %dxc -T cs_6_0 -DDEST=ro_babuf -DIDX=0 %s | %FileCheck %s -check-prefixes=CHKERR
2+
// RUN: %dxc -T cs_6_0 -DDEST=rw_babuf -DIDX=0 %s | %FileCheck %s
3+
// RUN: %dxc -T cs_6_0 -DDEST=rw_babuf -DIDX=SC_IDX %s | %FileCheck %s
4+
// RUN: %dxc -T cs_6_0 -DDEST=rw_babuf -DIDX=C_IDX %s | %FileCheck %s
5+
// RUN: %dxc -T cs_6_0 -DDEST=rw_babuf -DIDX=ix %s | %FileCheck %s
6+
7+
8+
// Test various Interlocked ops using read-only byteaddressbuffers and const params
9+
// The way the dest param of atomic ops is lowered is unique and missed a lot of
10+
// these invalid uses.
11+
12+
RWByteAddressBuffer rw_babuf;
13+
ByteAddressBuffer ro_babuf;
14+
15+
RWStructuredBuffer<float4> output; // just something to keep the variables live
16+
17+
static const uint SC_IDX = 6;
18+
19+
uint C_IDX;
20+
21+
[numthreads(1,1,1)]
22+
void main(uint ix : SV_GroupIndex) {
23+
24+
int val = 1;
25+
uint comp = 1;
26+
uint orig;
27+
28+
// add
29+
// CHKERR: error: no member named 'InterlockedAdd' in 'ByteAddressBuffer'
30+
// CHKERR: error: no member named 'InterlockedAdd' in 'ByteAddressBuffer'
31+
// CHECK: call i32 @dx.op.atomicBinOp.i32(i32 78,
32+
// CHECK: call i32 @dx.op.atomicBinOp.i32(i32 78,
33+
DEST.InterlockedAdd(IDX, val);
34+
DEST.InterlockedAdd(IDX, val, orig);
35+
36+
// min
37+
// CHKERR: error: no member named 'InterlockedMin' in 'ByteAddressBuffer'
38+
// CHKERR: error: no member named 'InterlockedMin' in 'ByteAddressBuffer'
39+
// CHECK: call i32 @dx.op.atomicBinOp.i32(i32 78,
40+
// CHECK: call i32 @dx.op.atomicBinOp.i32(i32 78,
41+
DEST.InterlockedMin(IDX, val);
42+
DEST.InterlockedMin(IDX, val, orig);
43+
44+
// max
45+
// CHKERR: error: no member named 'InterlockedMax' in 'ByteAddressBuffer'
46+
// CHKERR: error: no member named 'InterlockedMax' in 'ByteAddressBuffer'
47+
// CHECK: call i32 @dx.op.atomicBinOp.i32(i32 78,
48+
// CHECK: call i32 @dx.op.atomicBinOp.i32(i32 78,
49+
DEST.InterlockedMax(IDX, val);
50+
DEST.InterlockedMax(IDX, val, orig);
51+
52+
// and
53+
// CHKERR: error: no member named 'InterlockedAnd' in 'ByteAddressBuffer'
54+
// CHKERR: error: no member named 'InterlockedAnd' in 'ByteAddressBuffer'
55+
// CHECK: call i32 @dx.op.atomicBinOp.i32(i32 78,
56+
// CHECK: call i32 @dx.op.atomicBinOp.i32(i32 78,
57+
DEST.InterlockedAnd(IDX, val);
58+
DEST.InterlockedAnd(IDX, val, orig);
59+
60+
// or
61+
// CHKERR: error: no member named 'InterlockedOr' in 'ByteAddressBuffer'
62+
// CHKERR: error: no member named 'InterlockedOr' in 'ByteAddressBuffer'
63+
// CHECK: call i32 @dx.op.atomicBinOp.i32(i32 78,
64+
// CHECK: call i32 @dx.op.atomicBinOp.i32(i32 78,
65+
DEST.InterlockedOr(IDX, val);
66+
DEST.InterlockedOr(IDX, val, orig);
67+
68+
// xor
69+
// CHKERR: error: no member named 'InterlockedXor' in 'ByteAddressBuffer'
70+
// CHKERR: error: no member named 'InterlockedXor' in 'ByteAddressBuffer'
71+
// CHECK: call i32 @dx.op.atomicBinOp.i32(i32 78,
72+
// CHECK: call i32 @dx.op.atomicBinOp.i32(i32 78,
73+
DEST.InterlockedXor(IDX, val);
74+
DEST.InterlockedXor(IDX, val, orig);
75+
76+
// compareStore
77+
// CHKERR: error: no member named 'InterlockedCompareStore' in 'ByteAddressBuffer'
78+
// CHECK: call i32 @dx.op.atomicCompareExchange.i32(i32 79,
79+
DEST.InterlockedCompareStore(IDX, comp, val);
80+
81+
// exchange
82+
// CHKERR: error: no member named 'InterlockedExchange' in 'ByteAddressBuffer'
83+
// CHECK: call i32 @dx.op.atomicBinOp.i32(i32 78,
84+
DEST.InterlockedExchange(IDX, val, orig);
85+
86+
// compareExchange
87+
// CHKERR: error: no member named 'InterlockedCompareExchange' in 'ByteAddressBuffer'
88+
// CHECK: call i32 @dx.op.atomicCompareExchange.i32(i32 79,
89+
DEST.InterlockedCompareExchange(IDX, comp, val, orig);
90+
91+
output[ix] = (float)DEST.Load<float4>(IDX);
92+
}

0 commit comments

Comments
 (0)