[llvm] [SPIRV] Translate {uinc/udec}_wrap as opaque intrinsics and preserve AMDGPU metadata through NonSemantic.AuxData (PR #213685)
via llvm-commits
llvm-commits at lists.llvm.org
Mon Aug 3 07:38:57 PDT 2026
llvmorg-github-actions[bot] wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-backend-spir-v
Author: Marcos Maronas (maarquitos14)
<details>
<summary>Changes</summary>
The PR implements an extension to `NonSemantic.AuxData` spec to add `NonSemanticAuxDataInstructionMetadata`, which enables preservation of metadata for instructions other than `GlobalVariable` and `Function` objects for some AMDGPU metadata. Also, it includes the translation of `uinc_wrap` and `udec_wrap` as if they were opaque llvm intrinsics, so that they can be restored in the reverse translation to the exact original code.
---
Patch is 31.00 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/213685.diff
13 Files Affected:
- (modified) llvm/lib/Target/SPIRV/SPIRVAuxDataHandler.cpp (+23-1)
- (modified) llvm/lib/Target/SPIRV/SPIRVAuxDataHandler.h (+3-1)
- (modified) llvm/lib/Target/SPIRV/SPIRVEmitIntrinsics.cpp (+56-10)
- (modified) llvm/lib/Target/SPIRV/SPIRVISelLowering.cpp (+1-1)
- (modified) llvm/lib/Target/SPIRV/SPIRVModuleAnalysis.cpp (+22)
- (modified) llvm/lib/Target/SPIRV/SPIRVModuleAnalysis.h (+24)
- (modified) llvm/lib/Target/SPIRV/SPIRVSymbolicOperands.td (+2)
- (modified) llvm/test/CodeGen/SPIRV/amdgcnspirv-atomic-metadata-decoration.ll (+12-9)
- (added) llvm/test/CodeGen/SPIRV/atomicrmw-uinc-udec-wrap-orderings.ll (+66)
- (added) llvm/test/CodeGen/SPIRV/atomicrmw-uinc-udec-wrap-scopes.ll (+59)
- (modified) llvm/test/CodeGen/SPIRV/atomicrmw-uinc-udec-wrap.ll (+11-36)
- (added) llvm/test/CodeGen/SPIRV/extensions/SPV_KHR_non_semantic_info/preserve-auxdata-amdgpu-atomic-metadata.ll (+57)
- (added) llvm/test/CodeGen/SPIRV/extensions/SPV_KHR_non_semantic_info/preserve-auxdata-uinc-udec-wrap-metadata.ll (+49)
``````````diff
diff --git a/llvm/lib/Target/SPIRV/SPIRVAuxDataHandler.cpp b/llvm/lib/Target/SPIRV/SPIRVAuxDataHandler.cpp
index 469c261ac433e..c5a10db9685b3 100644
--- a/llvm/lib/Target/SPIRV/SPIRVAuxDataHandler.cpp
+++ b/llvm/lib/Target/SPIRV/SPIRVAuxDataHandler.cpp
@@ -65,6 +65,8 @@ SPIRVAuxDataHandler::SPIRVAuxDataHandler(AsmPrinter &AP, const Module &M)
bool SPIRVAuxDataHandler::hasWork() const { return SPVPreserveAuxData; }
+bool llvm::spirvPreserveAuxData() { return SPVPreserveAuxData; }
+
void SPIRVAuxDataHandler::prepareModuleOutput(const SPIRVSubtarget &ST,
SPIRV::ModuleAnalysisInfo &MAI) {
if (!hasWork())
@@ -76,7 +78,7 @@ void SPIRVAuxDataHandler::prepareModuleOutput(const SPIRVSubtarget &ST,
return;
}
MAI.Reqs.addExtension(SPIRV::Extension::SPV_KHR_non_semantic_info);
- if (!MAI.ExtInstSetMap.count(NonSemanticAuxDataSet))
+ if (!MAI.ExtInstSetMap.contains(NonSemanticAuxDataSet))
MAI.ExtInstSetMap[NonSemanticAuxDataSet] = MAI.getNextIDRegister();
}
@@ -181,6 +183,16 @@ void SPIRVAuxDataHandler::emitAuxDataStrings(SPIRV::ModuleAnalysisInfo &MAI) {
collectAttributesFor(&GO, MAI);
collectMetadataFor(&GO, MDNames, MAI);
}
+ // There are only 3 possible metadata names (AMDGPUAtomicMDKind has 3
+ // enumerators). Track which we've seen so we can stop early instead of
+ // scanning potentially thousands of records with redundant hash lookups.
+ unsigned SeenMask = 0;
+ for (const auto &Rec : MAI.InstrAuxDataRecords) {
+ SeenMask |= 1u << static_cast<unsigned>(Rec.Kind);
+ getOrEmitString(MAI.getAMDGPUAtomicMDName(Rec.Kind), MAI);
+ if (SeenMask == 0x7)
+ break;
+ }
}
void SPIRVAuxDataHandler::emitAuxData(SPIRV::ModuleAnalysisInfo &MAI) {
@@ -201,6 +213,16 @@ void SPIRVAuxDataHandler::emitAuxData(SPIRV::ModuleAnalysisInfo &MAI) {
emitAuxDataExtInst(Rec.Opcode, VoidTypeReg, ExtSetReg, Operands, MAI);
}
+ for (const auto &Rec : MAI.InstrAuxDataRecords) {
+ MCRegister TargetReg = MAI.getRegisterAlias(Rec.MF, Rec.TargetReg);
+ if (!TargetReg.isValid())
+ continue;
+ MCRegister MDNameReg =
+ getOrEmitString(MAI.getAMDGPUAtomicMDName(Rec.Kind), MAI);
+ emitAuxDataExtInst(InstructionMetadataOpcode, VoidTypeReg, ExtSetReg,
+ {TargetReg, MDNameReg}, MAI);
+ }
+
if (LinkagePreservedGOs.empty())
return;
diff --git a/llvm/lib/Target/SPIRV/SPIRVAuxDataHandler.h b/llvm/lib/Target/SPIRV/SPIRVAuxDataHandler.h
index 1d6ba998e6c2e..cae753bd05f0a 100644
--- a/llvm/lib/Target/SPIRV/SPIRVAuxDataHandler.h
+++ b/llvm/lib/Target/SPIRV/SPIRVAuxDataHandler.h
@@ -29,7 +29,6 @@ namespace llvm {
class AsmPrinter;
class Constant;
-class Function;
class GlobalObject;
class Module;
class SPIRVSubtarget;
@@ -42,6 +41,7 @@ enum AuxDataOpcode : int64_t {
GlobalVariableMetadataOpcode = 2,
GlobalVariableAttributeOpcode = 3,
LinkageOpcode = 4,
+ InstructionMetadataOpcode = 5,
};
class SPIRVAuxDataHandler {
@@ -111,6 +111,8 @@ class SPIRVAuxDataHandler {
SPIRV::ModuleAnalysisInfo &MAI);
};
+bool spirvPreserveAuxData();
+
} // namespace llvm
#endif // LLVM_LIB_TARGET_SPIRV_SPIRVAUXDATAHANDLER_H
diff --git a/llvm/lib/Target/SPIRV/SPIRVEmitIntrinsics.cpp b/llvm/lib/Target/SPIRV/SPIRVEmitIntrinsics.cpp
index 513b3149dd28f..a71485b2d1932 100644
--- a/llvm/lib/Target/SPIRV/SPIRVEmitIntrinsics.cpp
+++ b/llvm/lib/Target/SPIRV/SPIRVEmitIntrinsics.cpp
@@ -13,6 +13,7 @@
#include "SPIRVEmitIntrinsics.h"
#include "SPIRV.h"
+#include "SPIRVAuxDataHandler.h"
#include "SPIRVBuiltins.h"
#include "SPIRVSubtarget.h"
#include "SPIRVTargetMachine.h"
@@ -394,6 +395,7 @@ class SPIRVEmitIntrinsicsImpl
Instruction *visitStoreInst(StoreInst &I);
Instruction *visitAllocaInst(AllocaInst &I);
Instruction *visitAtomicCmpXchgInst(AtomicCmpXchgInst &I);
+ Instruction *visitAtomicRMWInst(AtomicRMWInst &I);
Instruction *visitUnreachableInst(UnreachableInst &I);
Instruction *visitCallInst(CallInst &I);
@@ -2609,6 +2611,48 @@ SPIRVEmitIntrinsicsImpl::visitAtomicCmpXchgInst(AtomicCmpXchgInst &I) {
return NewI;
}
+Instruction *SPIRVEmitIntrinsicsImpl::visitAtomicRMWInst(AtomicRMWInst &I) {
+ auto Op = I.getOperation();
+ if (Op != AtomicRMWInst::UIncWrap && Op != AtomicRMWInst::UDecWrap)
+ 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(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;
+
+ StringRef FuncName = (Op == AtomicRMWInst::UIncWrap)
+ ? "__spirv_AtomicUIncWrap"
+ : "__spirv_AtomicUDecWrap";
+
+ Type *ValTy = I.getValOperand()->getType();
+ Type *PtrTy = I.getPointerOperand()->getType();
+ 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);
+
+ I.replaceAllUsesWith(CI);
+ I.eraseFromParent();
+ return CI;
+}
+
static bool isAbortCall(const Instruction &I, const SPIRVSubtarget &ST) {
auto *CI = dyn_cast<CallInst>(&I);
if (!CI)
@@ -3004,27 +3048,29 @@ void SPIRVEmitIntrinsicsImpl::insertSpirvDecorations(Instruction *I,
{I->getType()},
{I, MetadataAsValue::get(I->getContext(), MD)});
}
- if (I->getModule()->getTargetTriple().getVendor() == Triple::AMD &&
+ if (spirvPreserveAuxData() &&
+ I->getModule()->getTargetTriple().getVendor() == Triple::AMD &&
isa<AtomicRMWInst>(I)) {
- // If present, we encode AMDGPU atomic metadata as UserSemantic string
- // decorations, which will be parsed during reverse translation.
- auto &Ctx = B.getContext();
- auto *US = ConstantAsMetadata::get(
- ConstantInt::get(B.getInt32Ty(), SPIRV::Decoration::UserSemantic));
+ LLVMContext &Ctx = B.getContext();
+ auto *AuxMD = ConstantAsMetadata::get(ConstantInt::get(
+ B.getInt32Ty(), SPIRV::Decoration::AuxDataInstructionMetadata));
SmallVector<Metadata *> MDs;
if (I->hasMetadata("amdgpu.no.fine.grained.memory"))
MDs.push_back(MDNode::get(
- Ctx, {US, MDString::get(Ctx, "amdgpu.no.fine.grained.memory")}));
+ Ctx,
+ {AuxMD, MDString::get(Ctx, "amdgpu.no.fine.grained.memory")}));
if (I->hasMetadata("amdgpu.no.remote.memory"))
MDs.push_back(MDNode::get(
- Ctx, {US, MDString::get(Ctx, "amdgpu.no.remote.memory")}));
+ Ctx, {AuxMD, MDString::get(Ctx, "amdgpu.no.remote.memory")}));
if (I->hasMetadata("amdgpu.ignore.denormal.mode"))
MDs.push_back(MDNode::get(
- Ctx, {US, MDString::get(Ctx, "amdgpu.ignore.denormal.mode")}));
- if (!MDs.empty())
+ Ctx, {AuxMD, MDString::get(Ctx, "amdgpu.ignore.denormal.mode")}));
+ if (!MDs.empty()) {
+ setInsertPointAfterDef(B, I);
B.CreateIntrinsic(Intrinsic::spv_assign_decoration, {I->getType()},
{I, MetadataAsValue::get(Ctx, MDNode::get(Ctx, MDs))});
+ }
}
}
diff --git a/llvm/lib/Target/SPIRV/SPIRVISelLowering.cpp b/llvm/lib/Target/SPIRV/SPIRVISelLowering.cpp
index 64c61d9f6a0c8..3289f724d9313 100644
--- a/llvm/lib/Target/SPIRV/SPIRVISelLowering.cpp
+++ b/llvm/lib/Target/SPIRV/SPIRVISelLowering.cpp
@@ -679,7 +679,7 @@ SPIRVTargetLowering::shouldExpandAtomicRMWInIR(const AtomicRMWInst *RMW) const {
return AtomicExpansionKind::None;
case AtomicRMWInst::UIncWrap:
case AtomicRMWInst::UDecWrap:
- return AtomicExpansionKind::CmpXChg;
+ return AtomicExpansionKind::None;
default:
return TargetLowering::shouldExpandAtomicRMWInIR(RMW);
}
diff --git a/llvm/lib/Target/SPIRV/SPIRVModuleAnalysis.cpp b/llvm/lib/Target/SPIRV/SPIRVModuleAnalysis.cpp
index 2836a2cc43ef0..c30e29651e99e 100644
--- a/llvm/lib/Target/SPIRV/SPIRVModuleAnalysis.cpp
+++ b/llvm/lib/Target/SPIRV/SPIRVModuleAnalysis.cpp
@@ -26,6 +26,7 @@
#include "SPIRVTargetMachine.h"
#include "SPIRVUtils.h"
#include "llvm/ADT/STLExtras.h"
+#include "llvm/ADT/StringSwitch.h"
#include "llvm/CodeGen/MachineModuleInfo.h"
#include "llvm/CodeGen/TargetPassConfig.h"
@@ -747,6 +748,27 @@ void SPIRVModuleAnalysis::processOtherInstrs(const Module &M) {
} else if (TII->isAliasingInstr(MI)) {
collectOtherInstr(MI, MAI, SPIRV::MB_AliasingInsts, IS);
} else if (TII->isDecorationInstr(MI)) {
+ if (MI.getOpcode() == SPIRV::OpDecorate &&
+ MI.getOperand(1).getImm() ==
+ static_cast<unsigned>(
+ SPIRV::Decoration::AuxDataInstructionMetadata)) {
+ MAI.setSkipEmission(&MI);
+ std::string Str = getStringImm(MI, 2);
+ using AMDMD = SPIRV::ModuleAnalysisInfo::AMDGPUAtomicMDKind;
+ auto MaybeKind =
+ StringSwitch<std::optional<AMDMD>>(Str)
+ .Case("amdgpu.no.fine.grained.memory",
+ AMDMD::NoFineGrainedMemory)
+ .Case("amdgpu.no.remote.memory",
+ AMDMD::NoRemoteMemory)
+ .Case("amdgpu.ignore.denormal.mode",
+ AMDMD::IgnoreDenormalMode)
+ .Default(std::nullopt);
+ if (MaybeKind)
+ MAI.InstrAuxDataRecords.push_back(
+ {MF, MI.getOperand(0).getReg(), *MaybeKind});
+ continue;
+ }
collectOtherInstr(MI, MAI, SPIRV::MB_Annotations, IS);
collectFuncNames(MI, &F);
} else if (TII->isConstantInstr(MI)) {
diff --git a/llvm/lib/Target/SPIRV/SPIRVModuleAnalysis.h b/llvm/lib/Target/SPIRV/SPIRVModuleAnalysis.h
index 6559b5cfc7457..a41349805fe8c 100644
--- a/llvm/lib/Target/SPIRV/SPIRVModuleAnalysis.h
+++ b/llvm/lib/Target/SPIRV/SPIRVModuleAnalysis.h
@@ -167,6 +167,18 @@ struct ModuleAnalysisInfo {
DenseMap<const Function *, SPIRV::FPFastMathDefaultInfoVector>
FPFastMathDefaultInfoMap;
+ enum class AMDGPUAtomicMDKind : uint8_t {
+ NoFineGrainedMemory,
+ NoRemoteMemory,
+ IgnoreDenormalMode,
+ };
+ struct InstrAuxDataRecord {
+ const MachineFunction *MF;
+ Register TargetReg;
+ AMDGPUAtomicMDKind Kind;
+ };
+ SmallVector<InstrAuxDataRecord> InstrAuxDataRecords;
+
MCRegister getGlobalObjReg(const GlobalObject *GO) {
assert(GO && "GlobalObject is null");
return GlobalObjMap.lookup(GO);
@@ -211,6 +223,18 @@ struct ModuleAnalysisInfo {
It->second = getNextIDRegister();
return It->second;
}
+ static StringRef getAMDGPUAtomicMDName(AMDGPUAtomicMDKind Kind) {
+ switch (Kind) {
+ case AMDGPUAtomicMDKind::NoFineGrainedMemory:
+ return "amdgpu.no.fine.grained.memory";
+ case AMDGPUAtomicMDKind::NoRemoteMemory:
+ return "amdgpu.no.remote.memory";
+ case AMDGPUAtomicMDKind::IgnoreDenormalMode:
+ return "amdgpu.ignore.denormal.mode";
+ default:
+ llvm_unreachable("unknown AMDGPUAtomicMDKind");
+ }
+ }
};
} // namespace SPIRV
diff --git a/llvm/lib/Target/SPIRV/SPIRVSymbolicOperands.td b/llvm/lib/Target/SPIRV/SPIRVSymbolicOperands.td
index 7da57bc1b2d47..cf4393c4bb884 100644
--- a/llvm/lib/Target/SPIRV/SPIRVSymbolicOperands.td
+++ b/llvm/lib/Target/SPIRV/SPIRVSymbolicOperands.td
@@ -1435,6 +1435,8 @@ defm FunctionFloatingPointModeINTEL : DecorationOperand<6080, 0, 0, [], [Functio
defm AliasScopeINTEL : DecorationOperand<5914, 0, 0, [], [MemoryAccessAliasingINTEL]>;
defm NoAliasINTEL : DecorationOperand<5915, 0, 0, [], [MemoryAccessAliasingINTEL]>;
defm FPMaxErrorDecorationINTEL : DecorationOperand<6170, 0, 0, [], [FPMaxErrorINTEL]>;
+// Internal-only sentinel; intercepted by SPIRVModuleAnalysis, never emitted.
+defm AuxDataInstructionMetadata : DecorationOperand<0xFFFF, 0, 0, [], []>;
//===----------------------------------------------------------------------===//
// Multiclass used to define BuiltIn enum values and at the same time
diff --git a/llvm/test/CodeGen/SPIRV/amdgcnspirv-atomic-metadata-decoration.ll b/llvm/test/CodeGen/SPIRV/amdgcnspirv-atomic-metadata-decoration.ll
index 9c6300f374261..3d679fe7e2281 100644
--- a/llvm/test/CodeGen/SPIRV/amdgcnspirv-atomic-metadata-decoration.ll
+++ b/llvm/test/CodeGen/SPIRV/amdgcnspirv-atomic-metadata-decoration.ll
@@ -1,18 +1,21 @@
-; RUN: llc -O0 -mtriple=spirv64-amd-amdhsa %s -o - | FileCheck %s
-; RUN: %if spirv-tools %{ llc -O0 -mtriple=spirv64-amd-amdhsa %s -o - -filetype=obj | spirv-val %}
+; Without -spirv-preserve-auxdata, AMDGPU atomic metadata must not appear
+; as UserSemantic decorations or any other form in the SPIR-V output.
-; CHECK: OpDecorate %[[#Add:]] UserSemantic "amdgpu.no.fine.grained.memory"
-; CHECK-NEXT: OpDecorate %[[#Add]] UserSemantic "amdgpu.no.remote.memory"
-; CHECK-NEXT: OpDecorate %[[#FAdd:]] UserSemantic "amdgpu.no.fine.grained.memory"
-; CHECK-NEXT: OpDecorate %[[#FAdd]] UserSemantic "amdgpu.no.remote.memory"
-; CHECK-NEXT: OpDecorate %[[#FAdd]] UserSemantic "amdgpu.ignore.denormal.mode"
-; CHECK: %[[#Add]] = OpAtomicIAdd
-; CHECK: %[[#FAdd]] = OpAtomicFAddEXT
+; RUN: llc -verify-machineinstrs -O0 -mtriple=spirv64-amd-amdhsa %s -o - | FileCheck %s
+; RUN: %if spirv-tools %{ llc -verify-machineinstrs -O0 -mtriple=spirv64-amd-amdhsa %s -o - -filetype=obj | spirv-val %}
+
+; CHECK-NOT: amdgpu.no.fine.grained.memory
+; CHECK-NOT: amdgpu.no.remote.memory
+; CHECK-NOT: amdgpu.ignore.denormal.mode
+; CHECK: %[[#Add:]] = OpAtomicIAdd
+; CHECK: %[[#FAdd:]] = OpAtomicFAddEXT
+; CHECK: %[[#Xchg:]] = OpAtomicExchange
define spir_func void @foo(ptr addrspace(1) %p) {
entry:
%atomic.add = atomicrmw add ptr addrspace(1) %p, i32 1 seq_cst, !amdgpu.no.fine.grained.memory !0, !amdgpu.no.remote.memory !0
%atomic.fadd = atomicrmw fadd ptr addrspace(1) %p, float 1.0 seq_cst, !amdgpu.no.fine.grained.memory !0, !amdgpu.no.remote.memory !0, !amdgpu.ignore.denormal.mode !0
+ %atomic.xchg = atomicrmw xchg ptr addrspace(1) %p, i32 1 seq_cst, !amdgpu.no.fine.grained.memory !0
ret void
}
diff --git a/llvm/test/CodeGen/SPIRV/atomicrmw-uinc-udec-wrap-orderings.ll b/llvm/test/CodeGen/SPIRV/atomicrmw-uinc-udec-wrap-orderings.ll
new file mode 100644
index 0000000000000..fb075e9021628
--- /dev/null
+++ b/llvm/test/CodeGen/SPIRV/atomicrmw-uinc-udec-wrap-orderings.ll
@@ -0,0 +1,66 @@
+; RUN: llc -verify-machineinstrs -O0 -mtriple=spirv64-unknown-unknown %s -o - | FileCheck %s
+; RUN: %if spirv-tools %{ llc -O0 -mtriple=spirv64-unknown-unknown %s -o - -filetype=obj | spirv-val %}
+; RUN: llc -verify-machineinstrs -O0 -mtriple=spirv32-unknown-unknown %s -o - | FileCheck %s
+; RUN: %if spirv-tools %{ llc -O0 -mtriple=spirv32-unknown-unknown %s -o - -filetype=obj | spirv-val %}
+
+; Check that atomicrmw uinc_wrap/udec_wrap correctly encode memory
+; orderings in the function call arguments.
+; CrossWorkgroupMemory = 0x200 = 512
+; Monotonic (Relaxed) = 0x000 -> with CrossWorkgroup: 512
+; Acquire = 0x002 -> with CrossWorkgroup: 514
+; Release = 0x004 -> with CrossWorkgroup: 516
+; AcquireRelease = 0x008 -> with CrossWorkgroup: 520
+; SequentiallyConsistent = 0x010 -> with CrossWorkgroup: 528
+
+; CHECK-DAG: %[[#Int:]] = OpTypeInt 32 0
+; CHECK-DAG: %[[#Scope:]] = OpConstantNull %[[#Int]]
+; CHECK-DAG: %[[#MemSem_Monotonic:]] = OpConstant %[[#Int]] 512
+; CHECK-DAG: %[[#MemSem_Acquire:]] = OpConstant %[[#Int]] 514
+; CHECK-DAG: %[[#MemSem_Release:]] = OpConstant %[[#Int]] 516
+; CHECK-DAG: %[[#MemSem_AcqRel:]] = OpConstant %[[#Int]] 520
+; CHECK-DAG: %[[#MemSem_SeqCst:]] = OpConstant %[[#Int]] 528
+
+; CHECK-DAG: OpDecorate %[[#UIncFn:]] LinkageAttributes "__spirv_AtomicUIncWrap" Import
+; CHECK-DAG: OpDecorate %[[#UDecFn:]] LinkageAttributes "__spirv_AtomicUDecWrap" Import
+
+ at ui = common dso_local addrspace(1) global i32 0, align 4
+
+define dso_local spir_func void @uinc_wrap_orderings() {
+entry:
+ ; CHECK: OpFunctionCall %[[#Int]] %[[#UIncFn]] %[[#]] %[[#Scope]] %[[#MemSem_Monotonic]]
+ %0 = atomicrmw uinc_wrap ptr addrspace(1) @ui, i32 42 monotonic
+
+ ; CHECK: OpFunctionCall %[[#Int]] %[[#UIncFn]] %[[#]] %[[#Scope]] %[[#MemSem_Acquire]]
+ %1 = atomicrmw uinc_wrap ptr addrspace(1) @ui, i32 42 acquire
+
+ ; CHECK: OpFunctionCall %[[#Int]] %[[#UIncFn]] %[[#]] %[[#Scope]] %[[#MemSem_Release]]
+ %2 = atomicrmw uinc_wrap ptr addrspace(1) @ui, i32 42 release
+
+ ; CHECK: OpFunctionCall %[[#Int]] %[[#UIncFn]] %[[#]] %[[#Scope]] %[[#MemSem_AcqRel]]
+ %3 = atomicrmw uinc_wrap ptr addrspace(1) @ui, i32 42 acq_rel
+
+ ; CHECK: OpFunctionCall %[[#Int]] %[[#UIncFn]] %[[#]] %[[#Scope]] %[[#MemSem_SeqCst]]
+ %4 = atomicrmw uinc_wrap ptr addrspace(1) @ui, i32 42 seq_cst
+
+ ret void
+}
+
+define dso_local spir_func void @udec_wrap_orderings() {
+entry:
+ ; CHECK: OpFunctionCall %[[#Int]] %[[#UDecFn]] %[[#]] %[[#Scope]] %[[#MemSem_Monotonic]]
+ %0 = atomicrmw udec_wrap ptr addrspace(1) @ui, i32 42 monotonic
+
+ ; CHECK: OpFunctionCall %[[#Int]] %[[#UDecFn]] %[[#]] %[[#Scope]] %[[#MemSem_Acquire]]
+ %1 = atomicrmw udec_wrap ptr addrspace(1) @ui, i32 42 acquire
+
+ ; CHECK: OpFunctionCall %[[#Int]] %[[#UDecFn]] %[[#]] %[[#Scope]] %[[#MemSem_Release]]
+ %2 = atomicrmw udec_wrap ptr addrspace(1) @ui, i32 42 release
+
+ ; CHECK: OpFunctionCall %[[#Int]] %[[#UDecFn]] %[[#]] %[[#Scope]] %[[#MemSem_AcqRel]]
+ %3 = atomicrmw udec_wrap ptr addrspace(1) @ui, i32 42 acq_rel
+
+ ; CHECK: OpFunctionCall %[[#Int]] %[[#UDecFn]] %[[#]] %[[#Scope]] %[[#MemSem_SeqCst]]
+ %4 = atomicrmw udec_wrap ptr addrspace(1) @ui, i32 42 seq_cst
+
+ ret void
+}
diff --git a/llvm/test/CodeGen/SPIRV/atomicrmw-uinc-udec-wrap-scopes.ll b/llvm/test/CodeGen/SPIRV/atomicrmw-uinc-udec-wrap-scopes.ll
new file mode 100644
index 0000000000000..b9385d6a4441c
--- /dev/null
+++ b/llvm/test/CodeGen/SPIRV/atomicrmw-uinc-udec-wrap-scopes.ll
@@ -0,0 +1,59 @@
+; RUN: llc -verify-machineinstrs -O0 -mtriple=spirv64-unknown-unknown %s -o - | FileCheck %s
+; RUN: %if spirv-tools %{ llc -O0 -mtriple=spirv64-unknown-unknown %s -o - -filetype=obj | spirv-val %}
+; RUN: llc -verify-machineinstrs -O0 -mtriple=spirv32-unknown-unknown %s -o - | FileCheck %s
+; RUN: %if spirv-tools %{ llc -O0 -mtriple=spirv32-unknown-unknown %s -o - -filetype=obj | spirv-val %}
+
+; Check that atomicrmw uinc_wrap/udec_wrap correctly encode scopes.
+
+; CHECK-DAG: %[[#Int:]] = OpTypeInt 32 0
+; CHECK-DAG: %[[#Scope_CrossDevice:]] = OpConstantNull %[[#Int]]
+; CHECK-DAG: %[[#Scope_Device:]] = OpConstant %[[#Int]] 1{{$}}
+; CHECK-DAG: %[[#Scope_Workgroup:]] = OpConstant %[[#Int]] 2{{$}}
+; CHECK-DAG: %[[#Scope_Subgroup:]] = OpConstant %[[#Int]] 3{{$}}
+; CHECK-DAG: %[[#Scope_Invocation:]] = OpConstant %[[#Int]] 4{{$}}
+; CHECK-DAG: %[[#MemSem_SeqCst:]] = OpConstant %[[#Int]] 528{{$}}
+
+; CHECK-DAG: OpDecorate %[[#UIncFn:]] LinkageAttributes "__spirv_AtomicUIncWrap" Import
+; CHECK-DAG: OpDecorate %[[#UDecFn:]] LinkageAttributes "__spirv_AtomicUDecWrap" Import
+
+ at ui = common dso_local addrspace(1) global i32 0, align 4
+
+define dso_local spir_func void @uinc_wrap_scopes() {
+entry:
+ ; CHECK: OpFunctionCall %[[#Int]] %[[#UIncFn]] %[[#]] %[[#Scope_CrossDevice]] %[[#MemSem_SeqCst]]
+ %0 = atomicrmw uinc_wrap ptr addrspace(1) @ui, i32 42 seq_cst
+
+ ; CHECK: OpFunctionCall %[[#Int]] %[[#UIncFn]] %[[#]] %[[#Scope_Device]] %[[#MemSem_SeqCst]]
+ %1 = atomicrmw uinc_wrap ptr addrspace(1) @ui, i32 42 syncscope("device") seq_cst
+
+ ; CHECK: OpFunctionCall %[[#Int]] %[[#UIncFn]] %[[#]] %[[#Scope_Workgroup]] %[[#MemSem_SeqCst]]
+ %2 = atomicrmw uinc_wrap ptr addrspace(1) @ui, i32 42 syncscope("workgroup") seq_cst
+
+ ; CHECK: OpFunctionCall %[[#Int]] %[[#UIncFn]] %[[#]] %[[#Scope_...
[truncated]
``````````
</details>
https://github.com/llvm/llvm-project/pull/213685
More information about the llvm-commits
mailing list