diff options
author | Antonio Frighetto <me@antoniofrighetto.com> | 2025-09-24 15:59:32 +0200 |
---|---|---|
committer | Antonio Frighetto <me@antoniofrighetto.com> | 2025-09-24 15:59:32 +0200 |
commit | 32c6e162462bbca3beb2259b90cc922a7419ba2c (patch) | |
tree | 9f0267bbb5519da8472272dfd6ea6b8249100d8c /llvm/lib/IR/Verifier.cpp | |
parent | 03742c5dacef177a990f0fa3a3d11ba720fc0ac5 (diff) | |
download | llvm-32c6e162462bbca3beb2259b90cc922a7419ba2c.zip llvm-32c6e162462bbca3beb2259b90cc922a7419ba2c.tar.gz llvm-32c6e162462bbca3beb2259b90cc922a7419ba2c.tar.bz2 |
[IR] Introduce `llvm.errno.tbaa` metadata for errno alias disambiguation
Add a new named module-level frontend-annotated metadata that
specifies the TBAA node for an integer access, for which, C/C++
`errno` accesses are guaranteed to use (under strict aliasing).
This should allow LLVM to prove the involved memory location/
accesses may not alias `errno`; thus, to perform optimizations
around errno-writing libcalls (store-to-load forwarding amongst
others).
Previous discussion: https://discourse.llvm.org/t/rfc-modelling-errno-memory-effects/82972.
Diffstat (limited to 'llvm/lib/IR/Verifier.cpp')
-rw-r--r-- | llvm/lib/IR/Verifier.cpp | 69 |
1 files changed, 42 insertions, 27 deletions
diff --git a/llvm/lib/IR/Verifier.cpp b/llvm/lib/IR/Verifier.cpp index 0c6175b1..6ff9693 100644 --- a/llvm/lib/IR/Verifier.cpp +++ b/llvm/lib/IR/Verifier.cpp @@ -480,6 +480,7 @@ public: visitModuleFlags(); visitModuleIdents(); visitModuleCommandLines(); + visitModuleErrnoTBAA(); verifyCompileUnits(); @@ -516,6 +517,7 @@ private: void visitComdat(const Comdat &C); void visitModuleIdents(); void visitModuleCommandLines(); + void visitModuleErrnoTBAA(); void visitModuleFlags(); void visitModuleFlag(const MDNode *Op, DenseMap<const MDString *, const MDNode *> &SeenIDs, @@ -1815,6 +1817,18 @@ void Verifier::visitModuleCommandLines() { } } +void Verifier::visitModuleErrnoTBAA() { + const NamedMDNode *ErrnoTBAA = M.getNamedMetadata("llvm.errno.tbaa"); + if (!ErrnoTBAA) + return; + + Check(ErrnoTBAA->getNumOperands() >= 1, + "llvm.errno.tbaa must have at least one operand", ErrnoTBAA); + + for (const MDNode *N : ErrnoTBAA->operands()) + TBAAVerifyHelper.visitTBAAMetadata(nullptr, N); +} + void Verifier::visitModuleFlags() { const NamedMDNode *Flags = M.getModuleFlagsMetadata(); if (!Flags) return; @@ -5537,7 +5551,7 @@ void Verifier::visitInstruction(Instruction &I) { visitNofreeMetadata(I, MD); if (MDNode *TBAA = I.getMetadata(LLVMContext::MD_tbaa)) - TBAAVerifyHelper.visitTBAAMetadata(I, TBAA); + TBAAVerifyHelper.visitTBAAMetadata(&I, TBAA); if (MDNode *MD = I.getMetadata(LLVMContext::MD_noalias)) visitAliasScopeListMetadata(MD); @@ -7879,21 +7893,22 @@ static bool isNewFormatTBAATypeNode(llvm::MDNode *Type) { return isa_and_nonnull<MDNode>(Type->getOperand(0)); } -bool TBAAVerifier::visitTBAAMetadata(Instruction &I, const MDNode *MD) { - CheckTBAA(MD->getNumOperands() > 0, "TBAA metadata cannot have 0 operands", - &I, MD); +bool TBAAVerifier::visitTBAAMetadata(Instruction *I, const MDNode *MD) { + CheckTBAA(MD->getNumOperands() > 0, "TBAA metadata cannot have 0 operands", I, + MD); - CheckTBAA(isa<LoadInst>(I) || isa<StoreInst>(I) || isa<CallInst>(I) || - isa<VAArgInst>(I) || isa<AtomicRMWInst>(I) || - isa<AtomicCmpXchgInst>(I), - "This instruction shall not have a TBAA access tag!", &I); + if (I) + CheckTBAA(isa<LoadInst>(I) || isa<StoreInst>(I) || isa<CallInst>(I) || + isa<VAArgInst>(I) || isa<AtomicRMWInst>(I) || + isa<AtomicCmpXchgInst>(I), + "This instruction shall not have a TBAA access tag!", I); bool IsStructPathTBAA = isa<MDNode>(MD->getOperand(0)) && MD->getNumOperands() >= 3; CheckTBAA(IsStructPathTBAA, "Old-style TBAA is no longer allowed, use struct-path TBAA instead", - &I); + I); MDNode *BaseNode = dyn_cast_or_null<MDNode>(MD->getOperand(0)); MDNode *AccessType = dyn_cast_or_null<MDNode>(MD->getOperand(1)); @@ -7902,17 +7917,17 @@ bool TBAAVerifier::visitTBAAMetadata(Instruction &I, const MDNode *MD) { if (IsNewFormat) { CheckTBAA(MD->getNumOperands() == 4 || MD->getNumOperands() == 5, - "Access tag metadata must have either 4 or 5 operands", &I, MD); + "Access tag metadata must have either 4 or 5 operands", I, MD); } else { CheckTBAA(MD->getNumOperands() < 5, - "Struct tag metadata must have either 3 or 4 operands", &I, MD); + "Struct tag metadata must have either 3 or 4 operands", I, MD); } // Check the access size field. if (IsNewFormat) { auto *AccessSizeNode = mdconst::dyn_extract_or_null<ConstantInt>( MD->getOperand(3)); - CheckTBAA(AccessSizeNode, "Access size field must be a constant", &I, MD); + CheckTBAA(AccessSizeNode, "Access size field must be a constant", I, MD); } // Check the immutability flag. @@ -7921,27 +7936,27 @@ bool TBAAVerifier::visitTBAAMetadata(Instruction &I, const MDNode *MD) { auto *IsImmutableCI = mdconst::dyn_extract_or_null<ConstantInt>( MD->getOperand(ImmutabilityFlagOpNo)); CheckTBAA(IsImmutableCI, - "Immutability tag on struct tag metadata must be a constant", &I, + "Immutability tag on struct tag metadata must be a constant", I, MD); CheckTBAA( IsImmutableCI->isZero() || IsImmutableCI->isOne(), - "Immutability part of the struct tag metadata must be either 0 or 1", - &I, MD); + "Immutability part of the struct tag metadata must be either 0 or 1", I, + MD); } CheckTBAA(BaseNode && AccessType, "Malformed struct tag metadata: base and access-type " "should be non-null and point to Metadata nodes", - &I, MD, BaseNode, AccessType); + I, MD, BaseNode, AccessType); if (!IsNewFormat) { CheckTBAA(isValidScalarTBAANode(AccessType), - "Access type node must be a valid scalar type", &I, MD, + "Access type node must be a valid scalar type", I, MD, AccessType); } auto *OffsetCI = mdconst::dyn_extract_or_null<ConstantInt>(MD->getOperand(2)); - CheckTBAA(OffsetCI, "Offset must be constant integer", &I, MD); + CheckTBAA(OffsetCI, "Offset must be constant integer", I, MD); APInt Offset = OffsetCI->getValue(); bool SeenAccessTypeInPath = false; @@ -7949,17 +7964,17 @@ bool TBAAVerifier::visitTBAAMetadata(Instruction &I, const MDNode *MD) { SmallPtrSet<MDNode *, 4> StructPath; for (/* empty */; BaseNode && !IsRootTBAANode(BaseNode); - BaseNode = getFieldNodeFromTBAABaseNode(I, BaseNode, Offset, - IsNewFormat)) { + BaseNode = + getFieldNodeFromTBAABaseNode(*I, BaseNode, Offset, IsNewFormat)) { if (!StructPath.insert(BaseNode).second) { - CheckFailed("Cycle detected in struct path", &I, MD); + CheckFailed("Cycle detected in struct path", I, MD); return false; } bool Invalid; unsigned BaseNodeBitWidth; - std::tie(Invalid, BaseNodeBitWidth) = verifyTBAABaseNode(I, BaseNode, - IsNewFormat); + std::tie(Invalid, BaseNodeBitWidth) = + verifyTBAABaseNode(*I, BaseNode, IsNewFormat); // If the base node is invalid in itself, then we've already printed all the // errors we wanted to print. @@ -7969,20 +7984,20 @@ bool TBAAVerifier::visitTBAAMetadata(Instruction &I, const MDNode *MD) { SeenAccessTypeInPath |= BaseNode == AccessType; if (isValidScalarTBAANode(BaseNode) || BaseNode == AccessType) - CheckTBAA(Offset == 0, "Offset not zero at the point of scalar access", - &I, MD, &Offset); + CheckTBAA(Offset == 0, "Offset not zero at the point of scalar access", I, + MD, &Offset); CheckTBAA(BaseNodeBitWidth == Offset.getBitWidth() || (BaseNodeBitWidth == 0 && Offset == 0) || (IsNewFormat && BaseNodeBitWidth == ~0u), - "Access bit-width not the same as description bit-width", &I, MD, + "Access bit-width not the same as description bit-width", I, MD, BaseNodeBitWidth, Offset.getBitWidth()); if (IsNewFormat && SeenAccessTypeInPath) break; } - CheckTBAA(SeenAccessTypeInPath, "Did not see access type in access path!", &I, + CheckTBAA(SeenAccessTypeInPath, "Did not see access type in access path!", I, MD); return true; } |