@@ -309,14 +309,34 @@ bool SPIRVRegularizeLLVM::regularize() {
309309 }
310310 }
311311 if (auto Cmpxchg = dyn_cast<AtomicCmpXchgInst>(&II)) {
312- Value *Ptr = Cmpxchg->getPointerOperand ();
312+ // Transform:
313+ // %1 = cmpxchg i32* %ptr, i32 %comparator, i32 %0 seq_cst acquire
314+ // To:
315+ // %cmpxchg.res = call spir_func
316+ // i32 @_Z29__spirv_AtomicCompareExchangePiiiiii(
317+ // i32* %ptr, i32 1, i32 16, i32 2, i32 %0, i32 %comparator)
318+ // %cmpxchg.success = icmp eq i32 %cmpxchg.res, %comparator
319+ // %1 = insertvalue { i32, i1 } undef, i32 %cmpxchg.res, 0
320+ // %2 = insertvalue { i32, i1 } %1, i1 %cmpxchg.success, 1
321+
313322 // To get memory scope argument we might use Cmpxchg->getSyncScopeID()
314323 // but LLVM's cmpxchg instruction is not aware of OpenCL(or SPIR-V)
315324 // memory scope enumeration. And assuming the produced SPIR-V module
316325 // will be consumed in an OpenCL environment, we can use the same
317326 // memory scope as OpenCL atomic functions that do not have
318327 // memory_scope argument, i.e. memory_scope_device. See the OpenCL C
319328 // specification p6.13.11. Atomic Functions
329+
330+ // cmpxchg LLVM instruction returns a pair {i32, i1}: the original
331+ // value and a flag indicating success (true) or failure (false).
332+ // OpAtomicCompareExchange SPIR-V instruction returns only the
333+ // original value. To keep the return type({i32, i1}) we construct
334+ // a composite. The first element of the composite holds result of
335+ // OpAtomicCompareExchange, i.e. the original value. The second
336+ // element holds result of comparison of the returned value and the
337+ // comparator, which matches with semantics of the flag returned by
338+ // cmpxchg.
339+ Value *Ptr = Cmpxchg->getPointerOperand ();
320340 Value *MemoryScope = getInt32 (M, spv::ScopeDevice);
321341 auto SuccessOrder = static_cast <OCLMemOrderKind>(
322342 llvm::toCABI (Cmpxchg->getSuccessOrdering ()));
@@ -332,45 +352,13 @@ bool SPIRVRegularizeLLVM::regularize() {
332352 auto *Res = addCallInstSPIRV (M, " __spirv_AtomicCompareExchange" ,
333353 Cmpxchg->getCompareOperand ()->getType (),
334354 Args, nullptr , &II, " cmpxchg.res" );
335- // cmpxchg LLVM instruction returns a pair: the original value and
336- // a flag indicating success (true) or failure (false).
337- // OpAtomicCompareExchange SPIR-V instruction returns only the
338- // original value. So we replace all uses of the original value
339- // extracted from the pair with the result of OpAtomicCompareExchange
340- // instruction. And we replace all uses of the flag with result of an
341- // OpIEqual instruction. The OpIEqual instruction returns true if the
342- // original value equals to the comparator which matches with
343- // semantics of cmpxchg.
344- // In case the original value was stored as is without extraction, we
345- // create a composite type manually from OpAtomicCompareExchange and
346- // OpIEqual instructions, and replace the original value usage in
347- // Store insruction with the new composite type.
348- for (User *U : Cmpxchg->users ()) {
349- if (auto *Extract = dyn_cast<ExtractValueInst>(U)) {
350- if (Extract->getIndices ()[0 ] == 0 ) {
351- Extract->replaceAllUsesWith (Res);
352- } else if (Extract->getIndices ()[0 ] == 1 ) {
353- auto *Cmp = new ICmpInst (Extract, CmpInst::ICMP_EQ, Res,
354- Comparator, " cmpxchg.success" );
355- Extract->replaceAllUsesWith (Cmp);
356- } else {
357- llvm_unreachable (" Unxpected cmpxchg pattern" );
358- }
359- assert (Extract->user_empty ());
360- Extract->dropAllReferences ();
361- ToErase.push_back (Extract);
362- } else if (auto *Store = dyn_cast<StoreInst>(U)) {
363- auto *Cmp = new ICmpInst (Store, CmpInst::ICMP_EQ, Res, Comparator,
364- " cmpxchg.success" );
365- auto *Agg = InsertValueInst::Create (
366- UndefValue::get (Cmpxchg->getType ()), Res, 0 , " agg0" , Store);
367- auto *AggStruct =
368- InsertValueInst::Create (Agg, Cmp, 1 , " agg1" , Store);
369- Store->getValueOperand ()->replaceAllUsesWith (AggStruct);
370- }
371- }
372- if (Cmpxchg->user_empty ())
373- ToErase.push_back (Cmpxchg);
355+ IRBuilder<> Builder (Cmpxchg);
356+ auto *Cmp = Builder.CreateICmpEQ (Res, Comparator, " cmpxchg.success" );
357+ auto *V1 = Builder.CreateInsertValue (
358+ UndefValue::get (Cmpxchg->getType ()), Res, 0 );
359+ auto *V2 = Builder.CreateInsertValue (V1, Cmp, 1 , Cmpxchg->getName ());
360+ Cmpxchg->replaceAllUsesWith (V2);
361+ ToErase.push_back (Cmpxchg);
374362 }
375363 }
376364 }
0 commit comments