Skip to content

Commit b226eb5

Browse files
committed
Fix mistranslation of OpAtomicCompareExchangeWeak
The semantics of OpAtomicCompareExchangeWeak are the same as those of OpAtomicCompareExchange. Each of the ops should be translated to atomic_compare_exchange_strong_explicit() when using OpenCL 2.0 builtins, and not atomic_compare_exchange_weak_explicit(), as use of the latter may result in unreported spurious failures which are not detectable when using OpAtomicCompareExchangeWeak, which does not give a direct indication of its success.
1 parent 336248f commit b226eb5

File tree

6 files changed

+40
-29
lines changed

6 files changed

+40
-29
lines changed

lib/SPIRV/SPIRVToOCL.h

+9-7
Original file line numberDiff line numberDiff line change
@@ -187,7 +187,7 @@ class SPIRVToOCLBase : public InstVisitor<SPIRVToOCLBase> {
187187

188188
/// Transform __spirv_OpAtomicCompareExchange and
189189
/// __spirv_OpAtomicCompareExchangeWeak
190-
virtual Instruction *visitCallSPIRVAtomicCmpExchg(CallInst *CI, Op OC) = 0;
190+
virtual Instruction *visitCallSPIRVAtomicCmpExchg(CallInst *CI) = 0;
191191

192192
/// Transform __spirv_OpAtomicIIncrement/OpAtomicIDecrement to:
193193
/// - OCL2.0: atomic_fetch_add_explicit/atomic_fetch_sub_explicit
@@ -293,10 +293,10 @@ class SPIRVToOCL12Base : public SPIRVToOCLBase {
293293
/// (bool)atomic_xchg(*ptr, 1)
294294
Instruction *visitCallSPIRVAtomicFlagTestAndSet(CallInst *CI);
295295

296-
/// Transform __spirv_OpAtomicCompareExchange and
297-
/// __spirv_OpAtomicCompareExchangeWeak into atomic_cmpxchg. There is no
298-
/// weak version of function in OpenCL 1.2
299-
Instruction *visitCallSPIRVAtomicCmpExchg(CallInst *CI, Op OC) override;
296+
/// Transform __spirv_OpAtomicCompareExchange/Weak into atomic_cmpxchg
297+
/// OpAtomicCompareExchangeWeak is not "weak" at all, but instead has
298+
/// the same semantics as OpAtomicCompareExchange.
299+
Instruction *visitCallSPIRVAtomicCmpExchg(CallInst *CI) override;
300300

301301
/// Conduct generic mutations for all atomic builtins
302302
CallInst *mutateCommonAtomicArguments(CallInst *CI, Op OC) override;
@@ -371,8 +371,10 @@ class SPIRVToOCL20Base : public SPIRVToOCLBase {
371371
std::string mapFPAtomicName(Op OC) override;
372372

373373
/// Transform __spirv_OpAtomicCompareExchange/Weak into
374-
/// compare_exchange_strong/weak_explicit
375-
Instruction *visitCallSPIRVAtomicCmpExchg(CallInst *CI, Op OC) override;
374+
/// atomic_compare_exchange_strong_explicit
375+
/// OpAtomicCompareExchangeWeak is not "weak" at all, but instead has
376+
/// the same semantics as OpAtomicCompareExchange.
377+
Instruction *visitCallSPIRVAtomicCmpExchg(CallInst *CI) override;
376378
};
377379

378380
class SPIRVToOCL20Pass : public llvm::PassInfoMixin<SPIRVToOCL20Pass>,

lib/SPIRV/SPIRVToOCL12.cpp

+2-3
Original file line numberDiff line numberDiff line change
@@ -205,8 +205,7 @@ SPIRVToOCL12Base::visitCallSPIRVAtomicFlagTestAndSet(CallInst *CI) {
205205
&Attrs);
206206
}
207207

208-
Instruction *SPIRVToOCL12Base::visitCallSPIRVAtomicCmpExchg(CallInst *CI,
209-
Op OC) {
208+
Instruction *SPIRVToOCL12Base::visitCallSPIRVAtomicCmpExchg(CallInst *CI) {
210209
AttributeList Attrs = CI->getCalledFunction()->getAttributes();
211210
return mutateCallInstOCL(
212211
M, CI,
@@ -247,7 +246,7 @@ Instruction *SPIRVToOCL12Base::visitCallSPIRVAtomicBuiltin(CallInst *CI,
247246
break;
248247
case OpAtomicCompareExchange:
249248
case OpAtomicCompareExchangeWeak:
250-
NewCI = visitCallSPIRVAtomicCmpExchg(CI, OC);
249+
NewCI = visitCallSPIRVAtomicCmpExchg(CI);
251250
break;
252251
default:
253252
NewCI = mutateCommonAtomicArguments(CI, OC);

lib/SPIRV/SPIRVToOCL20.cpp

+6-5
Original file line numberDiff line numberDiff line change
@@ -159,7 +159,7 @@ Instruction *SPIRVToOCL20Base::visitCallSPIRVAtomicBuiltin(CallInst *CI,
159159
break;
160160
case OpAtomicCompareExchange:
161161
case OpAtomicCompareExchangeWeak:
162-
NewCI = visitCallSPIRVAtomicCmpExchg(CIG, OC);
162+
NewCI = visitCallSPIRVAtomicCmpExchg(CIG);
163163
break;
164164
default:
165165
NewCI = mutateAtomicName(CIG, OC);
@@ -232,8 +232,7 @@ CallInst *SPIRVToOCL20Base::mutateCommonAtomicArguments(CallInst *CI, Op OC) {
232232
&Attrs);
233233
}
234234

235-
Instruction *SPIRVToOCL20Base::visitCallSPIRVAtomicCmpExchg(CallInst *CI,
236-
Op OC) {
235+
Instruction *SPIRVToOCL20Base::visitCallSPIRVAtomicCmpExchg(CallInst *CI) {
237236
assert(CI->getCalledFunction() && "Unexpected indirect call");
238237
AttributeList Attrs = CI->getCalledFunction()->getAttributes();
239238
Instruction *PInsertBefore = CI;
@@ -242,7 +241,7 @@ Instruction *SPIRVToOCL20Base::visitCallSPIRVAtomicCmpExchg(CallInst *CI,
242241
M, CI,
243242
[=](CallInst *, std::vector<Value *> &Args, Type *&RetTy) {
244243
// OpAtomicCompareExchange[Weak] semantics is different from
245-
// atomic_compare_exchange_[strong|weak] semantics as well as
244+
// atomic_compare_exchange_strong semantics as well as
246245
// arguments order.
247246
// OCL built-ins returns boolean value and stores a new/original
248247
// value by pointer passed as 2nd argument (aka expected) while SPIR-V
@@ -263,7 +262,9 @@ Instruction *SPIRVToOCL20Base::visitCallSPIRVAtomicCmpExchg(CallInst *CI,
263262
std::swap(Args[3], Args[4]);
264263
std::swap(Args[2], Args[3]);
265264
RetTy = Type::getInt1Ty(*Ctx);
266-
return OCLSPIRVBuiltinMap::rmap(OC);
265+
// OpAtomicCompareExchangeWeak is not "weak" at all, but instead has
266+
// the same semantics as OpAtomicCompareExchange.
267+
return "atomic_compare_exchange_strong_explicit";
267268
},
268269
[=](CallInst *CI) -> Instruction * {
269270
// OCL built-ins atomic_compare_exchange_[strong|weak] return boolean

test/transcoding/AtomicCompareExchangeExplicit_cl20.cl

+2-2
Original file line numberDiff line numberDiff line change
@@ -47,5 +47,5 @@ __kernel void testAtomicCompareExchangeExplicit_cl20(
4747

4848
//CHECK-LLVM: call spir_func i1 @_Z39atomic_compare_exchange_strong_explicitPU3AS4VU7_AtomiciPU3AS4ii12memory_orderS4_12memory_scope(i32 addrspace(4)* %0, i32 addrspace(4)* %expected1.as, i32 %desired, i32 3, i32 0, i32 2)
4949
//CHECK-LLVM: call spir_func i1 @_Z39atomic_compare_exchange_strong_explicitPU3AS4VU7_AtomiciPU3AS4ii12memory_orderS4_12memory_scope(i32 addrspace(4)* %0, i32 addrspace(4)* %expected3.as, i32 %desired, i32 4, i32 0, i32 1)
50-
//CHECK-LLVM: call spir_func i1 @_Z37atomic_compare_exchange_weak_explicitPU3AS4VU7_AtomiciPU3AS4ii12memory_orderS4_12memory_scope(i32 addrspace(4)* %0, i32 addrspace(4)* %expected5.as, i32 %desired, i32 3, i32 0, i32 2)
51-
//CHECK-LLVM: call spir_func i1 @_Z37atomic_compare_exchange_weak_explicitPU3AS4VU7_AtomiciPU3AS4ii12memory_orderS4_12memory_scope(i32 addrspace(4)* %0, i32 addrspace(4)* %expected7.as, i32 %desired, i32 4, i32 0, i32 1)
50+
//CHECK-LLVM: call spir_func i1 @_Z39atomic_compare_exchange_strong_explicitPU3AS4VU7_AtomiciPU3AS4ii12memory_orderS4_12memory_scope(i32 addrspace(4)* %0, i32 addrspace(4)* %expected5.as, i32 %desired, i32 3, i32 0, i32 2)
51+
//CHECK-LLVM: call spir_func i1 @_Z39atomic_compare_exchange_strong_explicitPU3AS4VU7_AtomiciPU3AS4ii12memory_orderS4_12memory_scope(i32 addrspace(4)* %0, i32 addrspace(4)* %expected7.as, i32 %desired, i32 4, i32 0, i32 1)

test/transcoding/AtomicCompareExchange_cl20.ll

+8-1
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,13 @@ target triple = "spir-unknown-unknown"
99

1010
; Check 'LLVM ==> SPIR-V ==> LLVM' conversion of atomic_compare_exchange_strong and atomic_compare_exchange_weak.
1111

12+
; SPIR-V does not include an equivalent of atomic_compare_exchange_weak
13+
; (OpAtomicCompareExchangeWeak is identical to OpAtomicCompareExchange and
14+
; is deprecated, and removed in SPIR-V 1.4.)
15+
; This breaks the round trip for atomic_compare_exchange_weak, which must be
16+
; translated back to LLVM IR as atomic_compare_exchange_strong, regardless
17+
; of whether OpAtomicCompareExchange or OpAtomicCompareExchangeWeak is used.
18+
1219
; Function Attrs: nounwind
1320

1421
; CHECK-LABEL: define spir_func void @test_strong
@@ -24,7 +31,7 @@ target triple = "spir-unknown-unknown"
2431
; CHECK: [[PTR_WEAK:%expected[0-9]*]] = alloca i32, align 4
2532
; CHECK: store i32 {{.*}}, i32* [[PTR_WEAK]]
2633
; CHECK: [[PTR_WEAK]].as = addrspacecast i32* [[PTR_WEAK]] to i32 addrspace(4)*
27-
; CHECK: call spir_func i1 @_Z37atomic_compare_exchange_weak_explicitPU3AS4VU7_AtomiciPU3AS4ii12memory_orderS4_12memory_scope{{.*}}(i32 {{.*}}* %object, i32 {{.*}}* [[PTR_WEAK]].as, i32 %desired, i32 5, i32 5, i32 2)
34+
; CHECK: call spir_func i1 @_Z39atomic_compare_exchange_strong_explicitPU3AS4VU7_AtomiciPU3AS4ii12memory_orderS4_12memory_scope{{.*}}(i32 {{.*}}* %object, i32 {{.*}}* [[PTR_WEAK]].as, i32 %desired, i32 5, i32 5, i32 2)
2835
; CHECK: load i32, i32 addrspace(4)* [[PTR_WEAK]].as
2936

3037
; Check that alloca for atomic_compare_exchange is being created in the entry block.

test/transcoding/atomics.spt

+13-11
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
1-
119734787 65536 393230 32 0
1+
119734787 65536 393230 33 0
22
2 Capability Addresses
33
2 Capability Kernel
44
5 ExtInstImport 1 "OpenCL.std"
55
3 MemoryModel 2 2
66
8 EntryPoint 6 6 "test_atomic_global"
7-
13 String 31 "kernel_arg_type.test_atomic_global.int*,"
7+
13 String 32 "kernel_arg_type.test_atomic_global.int*,"
88
3 Source 3 102000
99
3 Name 7 "dst"
1010
4 Name 8 "object"
@@ -18,7 +18,7 @@
1818
2 TypeVoid 2
1919
4 TypePointer 4 5 3
2020
7 TypeFunction 5 2 4 4 4 3
21-
2 TypeBool 29
21+
2 TypeBool 30
2222

2323

2424
5 Function 2 6 0 5
@@ -40,10 +40,11 @@
4040
7 AtomicXor 3 24 7 13 14 13
4141
7 AtomicAnd 3 25 7 13 14 13
4242
9 AtomicCompareExchange 3 26 7 13 14 14 13 17
43-
7 AtomicExchange 3 27 7 13 14 13
44-
6 AtomicLoad 3 28 8 13 14
43+
9 AtomicCompareExchangeWeak 3 27 7 13 14 14 13 17
44+
7 AtomicExchange 3 28 7 13 14 13
45+
6 AtomicLoad 3 29 8 13 14
4546
5 AtomicStore 8 13 14 10
46-
6 AtomicFlagTestAndSet 29 30 8 13 14
47+
6 AtomicFlagTestAndSet 30 31 8 13 14
4748
4 AtomicFlagClear 8 13 14
4849
1 Return
4950

@@ -66,7 +67,7 @@
6667
; CHECK-LLVM-12: call spir_func i32 @_Z9atomic_orPU3AS1Vii(i32 addrspace(1)* %dst, i32 1) [[attr]]
6768
; CHECK-LLVM-12: call spir_func i32 @_Z10atomic_xorPU3AS1Vii(i32 addrspace(1)* %dst, i32 1) [[attr]]
6869
; CHECK-LLVM-12: call spir_func i32 @_Z10atomic_andPU3AS1Vii(i32 addrspace(1)* %dst, i32 1) [[attr]]
69-
; CHECK-LLVM-12: call spir_func i32 @_Z14atomic_cmpxchgPU3AS1Viii(i32 addrspace(1)* %dst, i32 0, i32 1) [[attr]]
70+
; CHECK-LLVM-12-COUNT-2: call spir_func i32 @_Z14atomic_cmpxchgPU3AS1Viii(i32 addrspace(1)* %dst, i32 0, i32 1) [[attr]]
7071
; CHECK-LLVM-12: call spir_func i32 @_Z11atomic_xchgPU3AS1Vii(i32 addrspace(1)* %dst, i32 1) [[attr]]
7172
; CHECK-LLVM-12: call spir_func i32 @_Z10atomic_addPU3AS1Vii(i32 addrspace(1)* %object, i32 0) [[attr]]
7273
; CHECK-LLVM-12: call spir_func i32 @_Z11atomic_xchgPU3AS1Vii(i32 addrspace(1)* %object, i32 %desired) [[attr]]
@@ -89,11 +90,12 @@
8990
; CHECK-LLVM-20: call spir_func i32 @_Z25atomic_fetch_xor_explicitPU3AS4VU7_Atomicii12memory_order12memory_scope(i32 addrspace(4)* %dst.as9, i32 1, i32 5, i32 2) [[attr]]
9091
; CHECK-LLVM-20: call spir_func i32 @_Z25atomic_fetch_and_explicitPU3AS4VU7_Atomicii12memory_order12memory_scope(i32 addrspace(4)* %dst.as10, i32 1, i32 5, i32 2) [[attr]]
9192
; CHECK-LLVM-20: call spir_func i1 @_Z39atomic_compare_exchange_strong_explicitPU3AS4VU7_AtomiciPU3AS4ii12memory_orderS4_12memory_scope(i32 addrspace(4)* %dst.as11, i32 addrspace(4)* %expected12.as, i32 1, i32 5, i32 5, i32 2) [[attr]]
92-
; CHECK-LLVM-20: call spir_func i32 @_Z24atomic_exchange_explicitPU3AS4VU7_Atomicii12memory_order12memory_scope(i32 addrspace(4)* %dst.as13, i32 1, i32 5, i32 2) [[attr]]
93+
; CHECK-LLVM-20: call spir_func i1 @_Z39atomic_compare_exchange_strong_explicitPU3AS4VU7_AtomiciPU3AS4ii12memory_orderS4_12memory_scope(i32 addrspace(4)* %dst.as13, i32 addrspace(4)* %expected14.as, i32 1, i32 5, i32 5, i32 2) [[attr]]
94+
; CHECK-LLVM-20: call spir_func i32 @_Z24atomic_exchange_explicitPU3AS4VU7_Atomicii12memory_order12memory_scope(i32 addrspace(4)* %dst.as15, i32 1, i32 5, i32 2) [[attr]]
9395
; CHECK-LLVM-20: call spir_func i32 @_Z20atomic_load_explicitPU3AS4VU7_Atomici12memory_order12memory_scope(i32 addrspace(4)* %object.as, i32 5, i32 2) [[attr]]
94-
; CHECK-LLVM-20: call spir_func void @_Z21atomic_store_explicitPU3AS4VU7_Atomicii12memory_order12memory_scope(i32 addrspace(4)* %object.as14, i32 %desired, i32 5, i32 2) [[attr]]
95-
; CHECK-LLVM-20: call spir_func i1 @_Z33atomic_flag_test_and_set_explicitPU3AS4VU7_Atomici12memory_order12memory_scope(i32 addrspace(4)* %object.as15, i32 5, i32 2) [[attr]]
96-
; CHECK-LLVM-20: call spir_func void @_Z26atomic_flag_clear_explicitPU3AS4VU7_Atomici12memory_order12memory_scope(i32 addrspace(4)* %object.as16, i32 5, i32 2) [[attr]]
96+
; CHECK-LLVM-20: call spir_func void @_Z21atomic_store_explicitPU3AS4VU7_Atomicii12memory_order12memory_scope(i32 addrspace(4)* %object.as16, i32 %desired, i32 5, i32 2) [[attr]]
97+
; CHECK-LLVM-20: call spir_func i1 @_Z33atomic_flag_test_and_set_explicitPU3AS4VU7_Atomici12memory_order12memory_scope(i32 addrspace(4)* %object.as17, i32 5, i32 2) [[attr]]
98+
; CHECK-LLVM-20: call spir_func void @_Z26atomic_flag_clear_explicitPU3AS4VU7_Atomici12memory_order12memory_scope(i32 addrspace(4)* %object.as18, i32 5, i32 2) [[attr]]
9799

98100
; RUN: llvm-spirv -r %t1.spv -o %t2.bc --spirv-target-env="SPV-IR"
99101
; RUN: llvm-dis < %t2.bc | FileCheck %s --check-prefix=CHECK-LLVM-SPV-IR

0 commit comments

Comments
 (0)