diff options
author | Matt Arsenault <Matthew.Arsenault@amd.com> | 2024-10-07 23:21:42 +0400 |
---|---|---|
committer | GitHub <noreply@github.com> | 2024-10-07 23:21:42 +0400 |
commit | a8e1311a1c4f7f67d8d8d7575f595da4f0a5873c (patch) | |
tree | b7c8040940ae3229b85d1d12a13c9cd07633440e /llvm/lib/IR/Verifier.cpp | |
parent | 90a5744bebffafb88abf2343a1a70a37e12abef4 (diff) | |
download | llvm-a8e1311a1c4f7f67d8d8d7575f595da4f0a5873c.zip llvm-a8e1311a1c4f7f67d8d8d7575f595da4f0a5873c.tar.gz llvm-a8e1311a1c4f7f67d8d8d7575f595da4f0a5873c.tar.bz2 |
[RFC] IR: Define noalias.addrspace metadata (#102461)
This is intended to solve a problem with lowering atomics in
OpenMP and C++ common to AMDGPU and NVPTX.
In OpenCL and CUDA, it is undefined behavior for an atomic instruction
to modify an object in thread private memory. In OpenMP, it is defined.
Correspondingly, the hardware does not handle this correctly. For
AMDGPU,
32-bit atomics work and 64-bit atomics are silently dropped. We
therefore
need to codegen this by inserting a runtime address space check,
performing
the private case without atomics, and fallback to issuing the real
atomic
otherwise. This metadata allows us to avoid this extra check and branch.
Handle this by introducing metadata intended to be applied to atomicrmw,
indicating they cannot access the forbidden address space.
Diffstat (limited to 'llvm/lib/IR/Verifier.cpp')
-rw-r--r-- | llvm/lib/IR/Verifier.cpp | 53 |
1 files changed, 43 insertions, 10 deletions
diff --git a/llvm/lib/IR/Verifier.cpp b/llvm/lib/IR/Verifier.cpp index 1cd5eb3..b89c9ce 100644 --- a/llvm/lib/IR/Verifier.cpp +++ b/llvm/lib/IR/Verifier.cpp @@ -492,6 +492,14 @@ private: /// Whether a metadata node is allowed to be, or contain, a DILocation. enum class AreDebugLocsAllowed { No, Yes }; + /// Metadata that should be treated as a range, with slightly different + /// requirements. + enum class RangeLikeMetadataKind { + Range, // MD_range + AbsoluteSymbol, // MD_absolute_symbol + NoaliasAddrspace // MD_noalias_addrspace + }; + // Verification methods... void visitGlobalValue(const GlobalValue &GV); void visitGlobalVariable(const GlobalVariable &GV); @@ -515,9 +523,10 @@ private: void visitModuleFlagCGProfileEntry(const MDOperand &MDO); void visitFunction(const Function &F); void visitBasicBlock(BasicBlock &BB); - void verifyRangeMetadata(const Value &V, const MDNode *Range, Type *Ty, - bool IsAbsoluteSymbol); + void verifyRangeLikeMetadata(const Value &V, const MDNode *Range, Type *Ty, + RangeLikeMetadataKind Kind); void visitRangeMetadata(Instruction &I, MDNode *Range, Type *Ty); + void visitNoaliasAddrspaceMetadata(Instruction &I, MDNode *Range, Type *Ty); void visitDereferenceableMetadata(Instruction &I, MDNode *MD); void visitProfMetadata(Instruction &I, MDNode *MD); void visitCallStackMetadata(MDNode *MD); @@ -760,8 +769,9 @@ void Verifier::visitGlobalValue(const GlobalValue &GV) { // FIXME: Why is getMetadata on GlobalValue protected? if (const MDNode *AbsoluteSymbol = GO->getMetadata(LLVMContext::MD_absolute_symbol)) { - verifyRangeMetadata(*GO, AbsoluteSymbol, DL.getIntPtrType(GO->getType()), - true); + verifyRangeLikeMetadata(*GO, AbsoluteSymbol, + DL.getIntPtrType(GO->getType()), + RangeLikeMetadataKind::AbsoluteSymbol); } } @@ -4136,8 +4146,8 @@ static bool isContiguous(const ConstantRange &A, const ConstantRange &B) { /// Verify !range and !absolute_symbol metadata. These have the same /// restrictions, except !absolute_symbol allows the full set. -void Verifier::verifyRangeMetadata(const Value &I, const MDNode *Range, - Type *Ty, bool IsAbsoluteSymbol) { +void Verifier::verifyRangeLikeMetadata(const Value &I, const MDNode *Range, + Type *Ty, RangeLikeMetadataKind Kind) { unsigned NumOperands = Range->getNumOperands(); Check(NumOperands % 2 == 0, "Unfinished range!", Range); unsigned NumRanges = NumOperands / 2; @@ -4154,8 +4164,14 @@ void Verifier::verifyRangeMetadata(const Value &I, const MDNode *Range, Check(High->getType() == Low->getType(), "Range pair types must match!", &I); - Check(High->getType() == Ty->getScalarType(), - "Range types must match instruction type!", &I); + + if (Kind == RangeLikeMetadataKind::NoaliasAddrspace) { + Check(High->getType()->isIntegerTy(32), + "noalias.addrspace type must be i32!", &I); + } else { + Check(High->getType() == Ty->getScalarType(), + "Range types must match instruction type!", &I); + } APInt HighV = High->getValue(); APInt LowV = Low->getValue(); @@ -4166,7 +4182,9 @@ void Verifier::verifyRangeMetadata(const Value &I, const MDNode *Range, "The upper and lower limits cannot be the same value", &I); ConstantRange CurRange(LowV, HighV); - Check(!CurRange.isEmptySet() && (IsAbsoluteSymbol || !CurRange.isFullSet()), + Check(!CurRange.isEmptySet() && + (Kind == RangeLikeMetadataKind::AbsoluteSymbol || + !CurRange.isFullSet()), "Range must not be empty!", Range); if (i != 0) { Check(CurRange.intersectWith(LastRange).isEmptySet(), @@ -4194,7 +4212,15 @@ void Verifier::verifyRangeMetadata(const Value &I, const MDNode *Range, void Verifier::visitRangeMetadata(Instruction &I, MDNode *Range, Type *Ty) { assert(Range && Range == I.getMetadata(LLVMContext::MD_range) && "precondition violation"); - verifyRangeMetadata(I, Range, Ty, false); + verifyRangeLikeMetadata(I, Range, Ty, RangeLikeMetadataKind::Range); +} + +void Verifier::visitNoaliasAddrspaceMetadata(Instruction &I, MDNode *Range, + Type *Ty) { + assert(Range && Range == I.getMetadata(LLVMContext::MD_noalias_addrspace) && + "precondition violation"); + verifyRangeLikeMetadata(I, Range, Ty, + RangeLikeMetadataKind::NoaliasAddrspace); } void Verifier::checkAtomicMemAccessSize(Type *Ty, const Instruction *I) { @@ -5187,6 +5213,13 @@ void Verifier::visitInstruction(Instruction &I) { visitRangeMetadata(I, Range, I.getType()); } + if (MDNode *Range = I.getMetadata(LLVMContext::MD_noalias_addrspace)) { + Check(isa<LoadInst>(I) || isa<StoreInst>(I) || isa<AtomicRMWInst>(I) || + isa<AtomicCmpXchgInst>(I) || isa<CallInst>(I), + "noalias.addrspace are only for memory operations!", &I); + visitNoaliasAddrspaceMetadata(I, Range, I.getType()); + } + if (I.hasMetadata(LLVMContext::MD_invariant_group)) { Check(isa<LoadInst>(I) || isa<StoreInst>(I), "invariant.group metadata is only for loads and stores", &I); |