[llvm] [SPIRV] Translate {uinc/udec}_wrap as opaque intrinsics for AMD (PR #215507)

Arseniy Obolenskiy via llvm-commits llvm-commits at lists.llvm.org
Tue Aug 11 03:30:12 PDT 2026


================
@@ -2624,6 +2621,61 @@ SPIRVEmitIntrinsicsImpl::visitAtomicCmpXchgInst(AtomicCmpXchgInst &I) {
   return NewI;
 }
 
+Instruction *SPIRVEmitIntrinsicsImpl::visitAtomicRMWInst(AtomicRMWInst &I) {
+  auto Op = I.getOperation();
+  if (Op != AtomicRMWInst::UIncWrap && Op != AtomicRMWInst::UDecWrap)
+    return &I;
+
+  // Carrying these across the SPIR-V boundary as a call to an imported helper
+  // is an AMD extension: there is no SPIR-V opcode for them, so a consumer has
+  // to recognize the helper by name to make sense of the module. Restrict it to
+  // AMD targets and let everyone else keep the generic expansion.
+  if (!isAMDTarget(TM.getTargetTriple()))
+    return &I;
+
+  Module *M = I.getModule();
+  IRBuilder<> B(I.getParent());
+  B.SetInsertPoint(&I);
+
+  const SPIRVSubtarget &ST = TM.getSubtarget<SPIRVSubtarget>(*I.getFunction());
+  unsigned AS = I.getPointerOperand()->getType()->getPointerAddressSpace();
+
+  uint32_t Scope = static_cast<uint32_t>(
+      getMemScope(TM.getTargetTriple(), I.getContext(), I.getSyncScopeID()));
+  uint32_t ScSem = static_cast<uint32_t>(
+      getMemSemanticsForStorageClass(addressSpaceToStorageClass(AS, ST)));
+  uint32_t MemSem =
+      static_cast<uint32_t>(getMemSemantics(I.getOrdering())) | ScSem;
+
+  std::string FuncName = (Op == AtomicRMWInst::UIncWrap)
+                             ? "__translate_spirv_atomic_uinc_wrap"
+                             : "__translate_spirv_atomic_udec_wrap";
+
+  Type *ValTy = I.getValOperand()->getType();
+  Type *PtrTy = I.getPointerOperand()->getType();
+  // Encode the address space and the value type in the name, the same way
+  // lowerLLVMIntrinsicName() does for spirv.llvm_memset_p1_i64. A module may
+  // need several mutually incompatible signatures, while SPIR-V resolves an
+  // imported function by its linkage name alone.
+  FuncName += "_p" + std::to_string(AS) + "_i" +
+              std::to_string(ValTy->getIntegerBitWidth());
+
+  Type *Int32Ty = B.getInt32Ty();
+  SmallVector<Type *, 4> ArgTys = {PtrTy, Int32Ty, Int32Ty, ValTy};
+  FunctionType *FT = FunctionType::get(ValTy, ArgTys, false);
+  FunctionCallee FC = M->getOrInsertFunction(FuncName, FT);
+  if (auto *F = dyn_cast<Function>(FC.getCallee()))
+    F->setCallingConv(CallingConv::SPIR_FUNC);
+
+  SmallVector<Value *, 4> Args = {I.getPointerOperand(), B.getInt32(Scope),
+                                  B.getInt32(MemSem), I.getValOperand()};
+  CallInst *CI = B.CreateCall(FC, Args);
+  CI->setCallingConv(CallingConv::SPIR_FUNC);
+
+  replaceAllUsesWithAndErase(B, &I, CI);
----------------
aobolensk wrote:

Before the actual instruction drop, do we have any useful metadata that is supposed to be copied explicitly or not?

https://github.com/llvm/llvm-project/pull/215507


More information about the llvm-commits mailing list