aboutsummaryrefslogtreecommitdiff
path: root/llvm/lib/IR/Verifier.cpp
diff options
context:
space:
mode:
authorMatt Arsenault <Matthew.Arsenault@amd.com>2024-10-07 23:21:42 +0400
committerGitHub <noreply@github.com>2024-10-07 23:21:42 +0400
commita8e1311a1c4f7f67d8d8d7575f595da4f0a5873c (patch)
treeb7c8040940ae3229b85d1d12a13c9cd07633440e /llvm/lib/IR/Verifier.cpp
parent90a5744bebffafb88abf2343a1a70a37e12abef4 (diff)
downloadllvm-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.cpp53
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);