From ca10e73b530376e191fbaa4920b5dde02d8b5930 Mon Sep 17 00:00:00 2001 From: OCHyams Date: Wed, 19 Apr 2023 11:59:37 +0100 Subject: [PATCH] [NFC] Rename isPointerOffset to getPointerOffsetFrom and move to Value.h Linking LLVMCore failed when building D148536 with shared libs enabled: https://lab.llvm.org/buildbot/#/builders/121/builds/29766 Make isPointerOffset a Value method and rename it to getPointerOffsetFrom. Reviewed By: jmorse Differential Revision: https://reviews.llvm.org/D148698 --- llvm/include/llvm/Analysis/ValueTracking.h | 6 -- llvm/include/llvm/IR/Value.h | 5 ++ llvm/lib/Analysis/ValueTracking.cpp | 71 ------------------------ llvm/lib/IR/Value.cpp | 73 +++++++++++++++++++++++++ llvm/lib/Target/AArch64/AArch64StackTagging.cpp | 4 +- llvm/lib/Transforms/Scalar/MemCpyOptimizer.cpp | 4 +- 6 files changed, 82 insertions(+), 81 deletions(-) diff --git a/llvm/include/llvm/Analysis/ValueTracking.h b/llvm/include/llvm/Analysis/ValueTracking.h index 1891dcb..1daef70 100644 --- a/llvm/include/llvm/Analysis/ValueTracking.h +++ b/llvm/include/llvm/Analysis/ValueTracking.h @@ -1017,12 +1017,6 @@ std::optional isImpliedByDomCondition(CmpInst::Predicate Pred, const Value *LHS, const Value *RHS, const Instruction *ContextI, const DataLayout &DL); - -/// If Ptr1 is provably equal to Ptr2 plus a constant offset, return that -/// offset. For example, Ptr1 might be &A[42], and Ptr2 might be &A[40]. In -/// this case offset would be -8. -std::optional isPointerOffset(const Value *Ptr1, const Value *Ptr2, - const DataLayout &DL); } // end namespace llvm #endif // LLVM_ANALYSIS_VALUETRACKING_H diff --git a/llvm/include/llvm/IR/Value.h b/llvm/include/llvm/IR/Value.h index d0cd83b..16ae451 100644 --- a/llvm/include/llvm/IR/Value.h +++ b/llvm/include/llvm/IR/Value.h @@ -744,6 +744,11 @@ public: static_cast(this)->stripInBoundsOffsets(Func)); } + /// If this ptr is provably equal to \p Other plus a constant offset, return + /// that offset in bytes. Essentially `ptr this` subtract `ptr Other`. + std::optional getPointerOffsetFrom(const Value *Other, + const DataLayout &DL) const; + /// Return true if the memory object referred to by V can by freed in the /// scope for which the SSA value defining the allocation is statically /// defined. E.g. deallocation after the static scope of a value does not diff --git a/llvm/lib/Analysis/ValueTracking.cpp b/llvm/lib/Analysis/ValueTracking.cpp index 3f2ee99..c25f02b 100644 --- a/llvm/lib/Analysis/ValueTracking.cpp +++ b/llvm/lib/Analysis/ValueTracking.cpp @@ -8224,74 +8224,3 @@ ConstantRange llvm::computeConstantRange(const Value *V, bool ForSigned, return CR; } - -static std::optional -getOffsetFromIndex(const GEPOperator *GEP, unsigned Idx, const DataLayout &DL) { - // Skip over the first indices. - gep_type_iterator GTI = gep_type_begin(GEP); - for (unsigned i = 1; i != Idx; ++i, ++GTI) - /*skip along*/; - - // Compute the offset implied by the rest of the indices. - int64_t Offset = 0; - for (unsigned i = Idx, e = GEP->getNumOperands(); i != e; ++i, ++GTI) { - ConstantInt *OpC = dyn_cast(GEP->getOperand(i)); - if (!OpC) - return std::nullopt; - if (OpC->isZero()) - continue; // No offset. - - // Handle struct indices, which add their field offset to the pointer. - if (StructType *STy = GTI.getStructTypeOrNull()) { - Offset += DL.getStructLayout(STy)->getElementOffset(OpC->getZExtValue()); - continue; - } - - // Otherwise, we have a sequential type like an array or fixed-length - // vector. Multiply the index by the ElementSize. - TypeSize Size = DL.getTypeAllocSize(GTI.getIndexedType()); - if (Size.isScalable()) - return std::nullopt; - Offset += Size.getFixedValue() * OpC->getSExtValue(); - } - - return Offset; -} - -std::optional llvm::isPointerOffset(const Value *Ptr1, - const Value *Ptr2, - const DataLayout &DL) { - APInt Offset1(DL.getIndexTypeSizeInBits(Ptr1->getType()), 0); - APInt Offset2(DL.getIndexTypeSizeInBits(Ptr2->getType()), 0); - Ptr1 = Ptr1->stripAndAccumulateConstantOffsets(DL, Offset1, true); - Ptr2 = Ptr2->stripAndAccumulateConstantOffsets(DL, Offset2, true); - - // Handle the trivial case first. - if (Ptr1 == Ptr2) - return Offset2.getSExtValue() - Offset1.getSExtValue(); - - const GEPOperator *GEP1 = dyn_cast(Ptr1); - const GEPOperator *GEP2 = dyn_cast(Ptr2); - - // Right now we handle the case when Ptr1/Ptr2 are both GEPs with an identical - // base. After that base, they may have some number of common (and - // potentially variable) indices. After that they handle some constant - // offset, which determines their offset from each other. At this point, we - // handle no other case. - if (!GEP1 || !GEP2 || GEP1->getOperand(0) != GEP2->getOperand(0) || - GEP1->getSourceElementType() != GEP2->getSourceElementType()) - return std::nullopt; - - // Skip any common indices and track the GEP types. - unsigned Idx = 1; - for (; Idx != GEP1->getNumOperands() && Idx != GEP2->getNumOperands(); ++Idx) - if (GEP1->getOperand(Idx) != GEP2->getOperand(Idx)) - break; - - auto IOffset1 = getOffsetFromIndex(GEP1, Idx, DL); - auto IOffset2 = getOffsetFromIndex(GEP2, Idx, DL); - if (!IOffset1 || !IOffset2) - return std::nullopt; - return *IOffset2 - *IOffset1 + Offset2.getSExtValue() - - Offset1.getSExtValue(); -} diff --git a/llvm/lib/IR/Value.cpp b/llvm/lib/IR/Value.cpp index 11dc5060e..41260a9 100644 --- a/llvm/lib/IR/Value.cpp +++ b/llvm/lib/IR/Value.cpp @@ -20,6 +20,7 @@ #include "llvm/IR/DebugInfo.h" #include "llvm/IR/DerivedTypes.h" #include "llvm/IR/DerivedUser.h" +#include "llvm/IR/GetElementPtrTypeIterator.h" #include "llvm/IR/InstrTypes.h" #include "llvm/IR/Instructions.h" #include "llvm/IR/IntrinsicInst.h" @@ -985,6 +986,78 @@ Align Value::getPointerAlignment(const DataLayout &DL) const { return Align(1); } +static std::optional +getOffsetFromIndex(const GEPOperator *GEP, unsigned Idx, const DataLayout &DL) { + // Skip over the first indices. + gep_type_iterator GTI = gep_type_begin(GEP); + for (unsigned i = 1; i != Idx; ++i, ++GTI) + /*skip along*/; + + // Compute the offset implied by the rest of the indices. + int64_t Offset = 0; + for (unsigned i = Idx, e = GEP->getNumOperands(); i != e; ++i, ++GTI) { + ConstantInt *OpC = dyn_cast(GEP->getOperand(i)); + if (!OpC) + return std::nullopt; + if (OpC->isZero()) + continue; // No offset. + + // Handle struct indices, which add their field offset to the pointer. + if (StructType *STy = GTI.getStructTypeOrNull()) { + Offset += DL.getStructLayout(STy)->getElementOffset(OpC->getZExtValue()); + continue; + } + + // Otherwise, we have a sequential type like an array or fixed-length + // vector. Multiply the index by the ElementSize. + TypeSize Size = DL.getTypeAllocSize(GTI.getIndexedType()); + if (Size.isScalable()) + return std::nullopt; + Offset += Size.getFixedValue() * OpC->getSExtValue(); + } + + return Offset; +} + +std::optional Value::getPointerOffsetFrom(const Value *Other, + const DataLayout &DL) const { + const Value *Ptr1 = Other; + const Value *Ptr2 = this; + APInt Offset1(DL.getIndexTypeSizeInBits(Ptr1->getType()), 0); + APInt Offset2(DL.getIndexTypeSizeInBits(Ptr2->getType()), 0); + Ptr1 = Ptr1->stripAndAccumulateConstantOffsets(DL, Offset1, true); + Ptr2 = Ptr2->stripAndAccumulateConstantOffsets(DL, Offset2, true); + + // Handle the trivial case first. + if (Ptr1 == Ptr2) + return Offset2.getSExtValue() - Offset1.getSExtValue(); + + const GEPOperator *GEP1 = dyn_cast(Ptr1); + const GEPOperator *GEP2 = dyn_cast(Ptr2); + + // Right now we handle the case when Ptr1/Ptr2 are both GEPs with an identical + // base. After that base, they may have some number of common (and + // potentially variable) indices. After that they handle some constant + // offset, which determines their offset from each other. At this point, we + // handle no other case. + if (!GEP1 || !GEP2 || GEP1->getOperand(0) != GEP2->getOperand(0) || + GEP1->getSourceElementType() != GEP2->getSourceElementType()) + return std::nullopt; + + // Skip any common indices and track the GEP types. + unsigned Idx = 1; + for (; Idx != GEP1->getNumOperands() && Idx != GEP2->getNumOperands(); ++Idx) + if (GEP1->getOperand(Idx) != GEP2->getOperand(Idx)) + break; + + auto IOffset1 = getOffsetFromIndex(GEP1, Idx, DL); + auto IOffset2 = getOffsetFromIndex(GEP2, Idx, DL); + if (!IOffset1 || !IOffset2) + return std::nullopt; + return *IOffset2 - *IOffset1 + Offset2.getSExtValue() - + Offset1.getSExtValue(); +} + const Value *Value::DoPHITranslation(const BasicBlock *CurBB, const BasicBlock *PredBB) const { auto *PN = dyn_cast(this); diff --git a/llvm/lib/Target/AArch64/AArch64StackTagging.cpp b/llvm/lib/Target/AArch64/AArch64StackTagging.cpp index 97afb66..3ac86b3 100644 --- a/llvm/lib/Target/AArch64/AArch64StackTagging.cpp +++ b/llvm/lib/Target/AArch64/AArch64StackTagging.cpp @@ -380,7 +380,7 @@ Instruction *AArch64StackTagging::collectInitializers(Instruction *StartInst, // Check to see if this store is to a constant offset from the start ptr. std::optional Offset = - isPointerOffset(StartPtr, NextStore->getPointerOperand(), *DL); + NextStore->getPointerOperand()->getPointerOffsetFrom(StartPtr, *DL); if (!Offset) break; @@ -398,7 +398,7 @@ Instruction *AArch64StackTagging::collectInitializers(Instruction *StartInst, // Check to see if this store is to a constant offset from the start ptr. std::optional Offset = - isPointerOffset(StartPtr, MSI->getDest(), *DL); + MSI->getDest()->getPointerOffsetFrom(StartPtr, *DL); if (!Offset) break; diff --git a/llvm/lib/Transforms/Scalar/MemCpyOptimizer.cpp b/llvm/lib/Transforms/Scalar/MemCpyOptimizer.cpp index 95f7370..bf54c42 100644 --- a/llvm/lib/Transforms/Scalar/MemCpyOptimizer.cpp +++ b/llvm/lib/Transforms/Scalar/MemCpyOptimizer.cpp @@ -412,7 +412,7 @@ Instruction *MemCpyOptPass::tryMergingIntoMemset(Instruction *StartInst, // Check to see if this store is to a constant offset from the start ptr. std::optional Offset = - isPointerOffset(StartPtr, NextStore->getPointerOperand(), DL); + NextStore->getPointerOperand()->getPointerOffsetFrom(StartPtr, DL); if (!Offset) break; @@ -426,7 +426,7 @@ Instruction *MemCpyOptPass::tryMergingIntoMemset(Instruction *StartInst, // Check to see if this store is to a constant offset from the start ptr. std::optional Offset = - isPointerOffset(StartPtr, MSI->getDest(), DL); + MSI->getDest()->getPointerOffsetFrom(StartPtr, DL); if (!Offset) break; -- 2.7.4