diff options
author | Dimitry Andric <dim@FreeBSD.org> | 2022-03-20 11:40:34 +0000 |
---|---|---|
committer | Dimitry Andric <dim@FreeBSD.org> | 2022-05-14 11:43:05 +0000 |
commit | 349cc55c9796c4596a5b9904cd3281af295f878f (patch) | |
tree | 410c5a785075730a35f1272ca6a7adf72222ad03 /contrib/llvm-project/llvm/lib/Analysis/BasicAliasAnalysis.cpp | |
parent | cb2ae6163174b90e999326ecec3699ee093a5d43 (diff) | |
parent | c0981da47d5696fe36474fcf86b4ce03ae3ff818 (diff) |
Diffstat (limited to 'contrib/llvm-project/llvm/lib/Analysis/BasicAliasAnalysis.cpp')
-rw-r--r-- | contrib/llvm-project/llvm/lib/Analysis/BasicAliasAnalysis.cpp | 622 |
1 files changed, 345 insertions, 277 deletions
diff --git a/contrib/llvm-project/llvm/lib/Analysis/BasicAliasAnalysis.cpp b/contrib/llvm-project/llvm/lib/Analysis/BasicAliasAnalysis.cpp index 357772c9c4f2..88b0f37b1d48 100644 --- a/contrib/llvm-project/llvm/lib/Analysis/BasicAliasAnalysis.cpp +++ b/contrib/llvm-project/llvm/lib/Analysis/BasicAliasAnalysis.cpp @@ -31,6 +31,7 @@ #include "llvm/IR/Argument.h" #include "llvm/IR/Attributes.h" #include "llvm/IR/Constant.h" +#include "llvm/IR/ConstantRange.h" #include "llvm/IR/Constants.h" #include "llvm/IR/DataLayout.h" #include "llvm/IR/DerivedTypes.h" @@ -68,15 +69,6 @@ using namespace llvm; static cl::opt<bool> EnableRecPhiAnalysis("basic-aa-recphi", cl::Hidden, cl::init(true)); -/// By default, even on 32-bit architectures we use 64-bit integers for -/// calculations. This will allow us to more-aggressively decompose indexing -/// expressions calculated using i64 values (e.g., long long in C) which is -/// common enough to worry about. -static cl::opt<bool> ForceAtLeast64Bits("basic-aa-force-at-least-64b", - cl::Hidden, cl::init(true)); -static cl::opt<bool> DoubleCalcBits("basic-aa-double-calc-bits", - cl::Hidden, cl::init(false)); - /// SearchLimitReached / SearchTimes shows how often the limit of /// to decompose GEPs is reached. It will affect the precision /// of basic alias analysis. @@ -91,8 +83,7 @@ STATISTIC(SearchTimes, "Number of times a GEP is decomposed"); const unsigned MaxNumPhiBBsValueReachabilityCheck = 20; // The max limit of the search depth in DecomposeGEPExpression() and -// getUnderlyingObject(), both functions need to use the same search -// depth otherwise the algorithm in aliasGEP will assert. +// getUnderlyingObject(). static const unsigned MaxLookupSearchDepth = 6; bool BasicAAResult::invalidate(Function &Fn, const PreservedAnalyses &PA, @@ -120,9 +111,6 @@ static bool isEscapeSource(const Value *V) { if (isa<CallBase>(V)) return true; - if (isa<Argument>(V)) - return true; - // The load case works because isNonEscapingLocalObject considers all // stores to be escapes (it passes true for the StoreCaptures argument // to PointerMayBeCaptured). @@ -206,12 +194,12 @@ static uint64_t getMinimalExtentFrom(const Value &V, bool NullIsValidLoc) { // If we have dereferenceability information we know a lower bound for the // extent as accesses for a lower offset would be valid. We need to exclude - // the "or null" part if null is a valid pointer. + // the "or null" part if null is a valid pointer. We can ignore frees, as an + // access after free would be undefined behavior. bool CanBeNull, CanBeFreed; uint64_t DerefBytes = V.getPointerDereferenceableBytes(DL, CanBeNull, CanBeFreed); DerefBytes = (CanBeNull && NullIsValidLoc) ? 0 : DerefBytes; - DerefBytes = CanBeFreed ? 0 : DerefBytes; // If queried with a precise location size, we assume that location size to be // accessed, thus valid. if (LocSize.isPrecise()) @@ -227,82 +215,163 @@ static bool isObjectSize(const Value *V, uint64_t Size, const DataLayout &DL, } //===----------------------------------------------------------------------===// +// CaptureInfo implementations +//===----------------------------------------------------------------------===// + +CaptureInfo::~CaptureInfo() = default; + +bool SimpleCaptureInfo::isNotCapturedBeforeOrAt(const Value *Object, + const Instruction *I) { + return isNonEscapingLocalObject(Object, &IsCapturedCache); +} + +bool EarliestEscapeInfo::isNotCapturedBeforeOrAt(const Value *Object, + const Instruction *I) { + if (!isIdentifiedFunctionLocal(Object)) + return false; + + auto Iter = EarliestEscapes.insert({Object, nullptr}); + if (Iter.second) { + Instruction *EarliestCapture = FindEarliestCapture( + Object, *const_cast<Function *>(I->getFunction()), + /*ReturnCaptures=*/false, /*StoreCaptures=*/true, DT); + if (EarliestCapture) { + auto Ins = Inst2Obj.insert({EarliestCapture, {}}); + Ins.first->second.push_back(Object); + } + Iter.first->second = EarliestCapture; + } + + // No capturing instruction. + if (!Iter.first->second) + return true; + + return I != Iter.first->second && + !isPotentiallyReachable(Iter.first->second, I, nullptr, &DT, &LI); +} + +void EarliestEscapeInfo::removeInstruction(Instruction *I) { + auto Iter = Inst2Obj.find(I); + if (Iter != Inst2Obj.end()) { + for (const Value *Obj : Iter->second) + EarliestEscapes.erase(Obj); + Inst2Obj.erase(I); + } +} + +//===----------------------------------------------------------------------===// // GetElementPtr Instruction Decomposition and Analysis //===----------------------------------------------------------------------===// namespace { -/// Represents zext(sext(V)). -struct ExtendedValue { +/// Represents zext(sext(trunc(V))). +struct CastedValue { const Value *V; - unsigned ZExtBits; - unsigned SExtBits; + unsigned ZExtBits = 0; + unsigned SExtBits = 0; + unsigned TruncBits = 0; - explicit ExtendedValue(const Value *V, unsigned ZExtBits = 0, - unsigned SExtBits = 0) - : V(V), ZExtBits(ZExtBits), SExtBits(SExtBits) {} + explicit CastedValue(const Value *V) : V(V) {} + explicit CastedValue(const Value *V, unsigned ZExtBits, unsigned SExtBits, + unsigned TruncBits) + : V(V), ZExtBits(ZExtBits), SExtBits(SExtBits), TruncBits(TruncBits) {} unsigned getBitWidth() const { - return V->getType()->getPrimitiveSizeInBits() + ZExtBits + SExtBits; + return V->getType()->getPrimitiveSizeInBits() - TruncBits + ZExtBits + + SExtBits; } - ExtendedValue withValue(const Value *NewV) const { - return ExtendedValue(NewV, ZExtBits, SExtBits); + CastedValue withValue(const Value *NewV) const { + return CastedValue(NewV, ZExtBits, SExtBits, TruncBits); } - ExtendedValue withZExtOfValue(const Value *NewV) const { + /// Replace V with zext(NewV) + CastedValue withZExtOfValue(const Value *NewV) const { unsigned ExtendBy = V->getType()->getPrimitiveSizeInBits() - NewV->getType()->getPrimitiveSizeInBits(); + if (ExtendBy <= TruncBits) + return CastedValue(NewV, ZExtBits, SExtBits, TruncBits - ExtendBy); + // zext(sext(zext(NewV))) == zext(zext(zext(NewV))) - return ExtendedValue(NewV, ZExtBits + SExtBits + ExtendBy, 0); + ExtendBy -= TruncBits; + return CastedValue(NewV, ZExtBits + SExtBits + ExtendBy, 0, 0); } - ExtendedValue withSExtOfValue(const Value *NewV) const { + /// Replace V with sext(NewV) + CastedValue withSExtOfValue(const Value *NewV) const { unsigned ExtendBy = V->getType()->getPrimitiveSizeInBits() - NewV->getType()->getPrimitiveSizeInBits(); + if (ExtendBy <= TruncBits) + return CastedValue(NewV, ZExtBits, SExtBits, TruncBits - ExtendBy); + // zext(sext(sext(NewV))) - return ExtendedValue(NewV, ZExtBits, SExtBits + ExtendBy); + ExtendBy -= TruncBits; + return CastedValue(NewV, ZExtBits, SExtBits + ExtendBy, 0); } APInt evaluateWith(APInt N) const { assert(N.getBitWidth() == V->getType()->getPrimitiveSizeInBits() && "Incompatible bit width"); + if (TruncBits) N = N.trunc(N.getBitWidth() - TruncBits); if (SExtBits) N = N.sext(N.getBitWidth() + SExtBits); if (ZExtBits) N = N.zext(N.getBitWidth() + ZExtBits); return N; } + ConstantRange evaluateWith(ConstantRange N) const { + assert(N.getBitWidth() == V->getType()->getPrimitiveSizeInBits() && + "Incompatible bit width"); + if (TruncBits) N = N.truncate(N.getBitWidth() - TruncBits); + if (SExtBits) N = N.signExtend(N.getBitWidth() + SExtBits); + if (ZExtBits) N = N.zeroExtend(N.getBitWidth() + ZExtBits); + return N; + } + bool canDistributeOver(bool NUW, bool NSW) const { // zext(x op<nuw> y) == zext(x) op<nuw> zext(y) // sext(x op<nsw> y) == sext(x) op<nsw> sext(y) + // trunc(x op y) == trunc(x) op trunc(y) return (!ZExtBits || NUW) && (!SExtBits || NSW); } + + bool hasSameCastsAs(const CastedValue &Other) const { + return ZExtBits == Other.ZExtBits && SExtBits == Other.SExtBits && + TruncBits == Other.TruncBits; + } }; -/// Represents zext(sext(V)) * Scale + Offset. +/// Represents zext(sext(trunc(V))) * Scale + Offset. struct LinearExpression { - ExtendedValue Val; + CastedValue Val; APInt Scale; APInt Offset; /// True if all operations in this expression are NSW. bool IsNSW; - LinearExpression(const ExtendedValue &Val, const APInt &Scale, + LinearExpression(const CastedValue &Val, const APInt &Scale, const APInt &Offset, bool IsNSW) : Val(Val), Scale(Scale), Offset(Offset), IsNSW(IsNSW) {} - LinearExpression(const ExtendedValue &Val) : Val(Val), IsNSW(true) { + LinearExpression(const CastedValue &Val) : Val(Val), IsNSW(true) { unsigned BitWidth = Val.getBitWidth(); Scale = APInt(BitWidth, 1); Offset = APInt(BitWidth, 0); } + + LinearExpression mul(const APInt &Other, bool MulIsNSW) const { + // The check for zero offset is necessary, because generally + // (X +nsw Y) *nsw Z does not imply (X *nsw Z) +nsw (Y *nsw Z). + bool NSW = IsNSW && (Other.isOne() || (MulIsNSW && Offset.isZero())); + return LinearExpression(Val, Scale * Other, Offset * Other, NSW); + } }; } /// Analyzes the specified value as a linear expression: "A*V + B", where A and /// B are constant integers. static LinearExpression GetLinearExpression( - const ExtendedValue &Val, const DataLayout &DL, unsigned Depth, + const CastedValue &Val, const DataLayout &DL, unsigned Depth, AssumptionCache *AC, DominatorTree *DT) { // Limit our recursion depth. if (Depth == 6) @@ -325,6 +394,11 @@ static LinearExpression GetLinearExpression( if (!Val.canDistributeOver(NUW, NSW)) return Val; + // While we can distribute over trunc, we cannot preserve nowrap flags + // in that case. + if (Val.TruncBits) + NUW = NSW = false; + LinearExpression E(Val); switch (BOp->getOpcode()) { default: @@ -353,14 +427,11 @@ static LinearExpression GetLinearExpression( E.IsNSW &= NSW; break; } - case Instruction::Mul: { + case Instruction::Mul: E = GetLinearExpression(Val.withValue(BOp->getOperand(0)), DL, - Depth + 1, AC, DT); - E.Offset *= RHS; - E.Scale *= RHS; - E.IsNSW &= NSW; + Depth + 1, AC, DT) + .mul(RHS, NSW); break; - } case Instruction::Shl: // We're trying to linearize an expression of the kind: // shl i8 -128, 36 @@ -394,25 +465,75 @@ static LinearExpression GetLinearExpression( return Val; } -/// To ensure a pointer offset fits in an integer of size PointerSize -/// (in bits) when that size is smaller than the maximum pointer size. This is +/// To ensure a pointer offset fits in an integer of size IndexSize +/// (in bits) when that size is smaller than the maximum index size. This is /// an issue, for example, in particular for 32b pointers with negative indices /// that rely on two's complement wrap-arounds for precise alias information -/// where the maximum pointer size is 64b. -static APInt adjustToPointerSize(const APInt &Offset, unsigned PointerSize) { - assert(PointerSize <= Offset.getBitWidth() && "Invalid PointerSize!"); - unsigned ShiftBits = Offset.getBitWidth() - PointerSize; +/// where the maximum index size is 64b. +static APInt adjustToIndexSize(const APInt &Offset, unsigned IndexSize) { + assert(IndexSize <= Offset.getBitWidth() && "Invalid IndexSize!"); + unsigned ShiftBits = Offset.getBitWidth() - IndexSize; return (Offset << ShiftBits).ashr(ShiftBits); } -static unsigned getMaxPointerSize(const DataLayout &DL) { - unsigned MaxPointerSize = DL.getMaxPointerSizeInBits(); - if (MaxPointerSize < 64 && ForceAtLeast64Bits) MaxPointerSize = 64; - if (DoubleCalcBits) MaxPointerSize *= 2; +namespace { +// A linear transformation of a Value; this class represents +// ZExt(SExt(Trunc(V, TruncBits), SExtBits), ZExtBits) * Scale. +struct VariableGEPIndex { + CastedValue Val; + APInt Scale; + + // Context instruction to use when querying information about this index. + const Instruction *CxtI; + + /// True if all operations in this expression are NSW. + bool IsNSW; - return MaxPointerSize; + void dump() const { + print(dbgs()); + dbgs() << "\n"; + } + void print(raw_ostream &OS) const { + OS << "(V=" << Val.V->getName() + << ", zextbits=" << Val.ZExtBits + << ", sextbits=" << Val.SExtBits + << ", truncbits=" << Val.TruncBits + << ", scale=" << Scale << ")"; + } +}; } +// Represents the internal structure of a GEP, decomposed into a base pointer, +// constant offsets, and variable scaled indices. +struct BasicAAResult::DecomposedGEP { + // Base pointer of the GEP + const Value *Base; + // Total constant offset from base. + APInt Offset; + // Scaled variable (non-constant) indices. + SmallVector<VariableGEPIndex, 4> VarIndices; + // Are all operations inbounds GEPs or non-indexing operations? + // (None iff expression doesn't involve any geps) + Optional<bool> InBounds; + + void dump() const { + print(dbgs()); + dbgs() << "\n"; + } + void print(raw_ostream &OS) const { + OS << "(DecomposedGEP Base=" << Base->getName() + << ", Offset=" << Offset + << ", VarIndices=["; + for (size_t i = 0; i < VarIndices.size(); i++) { + if (i != 0) + OS << ", "; + VarIndices[i].print(OS); + } + OS << "])"; + } +}; + + /// If V is a symbolic pointer expression, decompose it into a base pointer /// with a constant offset and a number of scaled symbolic offsets. /// @@ -420,11 +541,6 @@ static unsigned getMaxPointerSize(const DataLayout &DL) { /// in the VarIndices vector) are Value*'s that are known to be scaled by the /// specified amount, but which may have other unrepresented high bits. As /// such, the gep cannot necessarily be reconstructed from its decomposed form. -/// -/// This function is capable of analyzing everything that getUnderlyingObject -/// can look through. To be able to do that getUnderlyingObject and -/// DecomposeGEPExpression must use the same search depth -/// (MaxLookupSearchDepth). BasicAAResult::DecomposedGEP BasicAAResult::DecomposeGEPExpression(const Value *V, const DataLayout &DL, AssumptionCache *AC, DominatorTree *DT) { @@ -433,10 +549,9 @@ BasicAAResult::DecomposeGEPExpression(const Value *V, const DataLayout &DL, SearchTimes++; const Instruction *CxtI = dyn_cast<Instruction>(V); - unsigned MaxPointerSize = getMaxPointerSize(DL); + unsigned MaxIndexSize = DL.getMaxIndexSizeInBits(); DecomposedGEP Decomposed; - Decomposed.Offset = APInt(MaxPointerSize, 0); - Decomposed.HasCompileTimeConstantScale = true; + Decomposed.Offset = APInt(MaxIndexSize, 0); do { // See if this is a bitcast or GEP. const Operator *Op = dyn_cast<Operator>(V); @@ -493,24 +608,19 @@ BasicAAResult::DecomposeGEPExpression(const Value *V, const DataLayout &DL, else if (!GEPOp->isInBounds()) Decomposed.InBounds = false; - // Don't attempt to analyze GEPs over unsized objects. - if (!GEPOp->getSourceElementType()->isSized()) { - Decomposed.Base = V; - return Decomposed; - } + assert(GEPOp->getSourceElementType()->isSized() && "GEP must be sized"); // Don't attempt to analyze GEPs if index scale is not a compile-time // constant. if (isa<ScalableVectorType>(GEPOp->getSourceElementType())) { Decomposed.Base = V; - Decomposed.HasCompileTimeConstantScale = false; return Decomposed; } unsigned AS = GEPOp->getPointerAddressSpace(); // Walk the indices of the GEP, accumulating them into BaseOff/VarIndices. gep_type_iterator GTI = gep_type_begin(GEPOp); - unsigned PointerSize = DL.getPointerSizeInBits(AS); + unsigned IndexSize = DL.getIndexSizeInBits(AS); // Assume all GEP operands are constants until proven otherwise. bool GepHasConstantOffset = true; for (User::const_op_iterator I = GEPOp->op_begin() + 1, E = GEPOp->op_end(); @@ -533,49 +643,34 @@ BasicAAResult::DecomposeGEPExpression(const Value *V, const DataLayout &DL, continue; Decomposed.Offset += DL.getTypeAllocSize(GTI.getIndexedType()).getFixedSize() * - CIdx->getValue().sextOrTrunc(MaxPointerSize); + CIdx->getValue().sextOrTrunc(MaxIndexSize); continue; } GepHasConstantOffset = false; - APInt Scale(MaxPointerSize, - DL.getTypeAllocSize(GTI.getIndexedType()).getFixedSize()); - // If the integer type is smaller than the pointer size, it is implicitly - // sign extended to pointer size. + // If the integer type is smaller than the index size, it is implicitly + // sign extended or truncated to index size. unsigned Width = Index->getType()->getIntegerBitWidth(); - unsigned SExtBits = PointerSize > Width ? PointerSize - Width : 0; + unsigned SExtBits = IndexSize > Width ? IndexSize - Width : 0; + unsigned TruncBits = IndexSize < Width ? Width - IndexSize : 0; LinearExpression LE = GetLinearExpression( - ExtendedValue(Index, 0, SExtBits), DL, 0, AC, DT); - - // The GEP index scale ("Scale") scales C1*V+C2, yielding (C1*V+C2)*Scale. - // This gives us an aggregate computation of (C1*Scale)*V + C2*Scale. - - // It can be the case that, even through C1*V+C2 does not overflow for - // relevant values of V, (C2*Scale) can overflow. In that case, we cannot - // decompose the expression in this way. - // - // FIXME: C1*Scale and the other operations in the decomposed - // (C1*Scale)*V+C2*Scale can also overflow. We should check for this - // possibility. - bool Overflow; - APInt ScaledOffset = LE.Offset.sextOrTrunc(MaxPointerSize) - .smul_ov(Scale, Overflow); - if (Overflow) { - LE = LinearExpression(ExtendedValue(Index, 0, SExtBits)); - } else { - Decomposed.Offset += ScaledOffset; - Scale *= LE.Scale.sextOrTrunc(MaxPointerSize); - } + CastedValue(Index, 0, SExtBits, TruncBits), DL, 0, AC, DT); + + // Scale by the type size. + unsigned TypeSize = + DL.getTypeAllocSize(GTI.getIndexedType()).getFixedSize(); + LE = LE.mul(APInt(IndexSize, TypeSize), GEPOp->isInBounds()); + Decomposed.Offset += LE.Offset.sextOrSelf(MaxIndexSize); + APInt Scale = LE.Scale.sextOrSelf(MaxIndexSize); // If we already had an occurrence of this index variable, merge this // scale into it. For example, we want to handle: // A[x][x] -> x*16 + x*4 -> x*20 // This also ensures that 'x' only appears in the index list once. for (unsigned i = 0, e = Decomposed.VarIndices.size(); i != e; ++i) { - if (Decomposed.VarIndices[i].V == LE.Val.V && - Decomposed.VarIndices[i].ZExtBits == LE.Val.ZExtBits && - Decomposed.VarIndices[i].SExtBits == LE.Val.SExtBits) { + if (Decomposed.VarIndices[i].Val.V == LE.Val.V && + Decomposed.VarIndices[i].Val.hasSameCastsAs(LE.Val)) { Scale += Decomposed.VarIndices[i].Scale; Decomposed.VarIndices.erase(Decomposed.VarIndices.begin() + i); break; @@ -583,19 +678,18 @@ BasicAAResult::DecomposeGEPExpression(const Value *V, const DataLayout &DL, } // Make sure that we have a scale that makes sense for this target's - // pointer size. - Scale = adjustToPointerSize(Scale, PointerSize); + // index size. + Scale = adjustToIndexSize(Scale, IndexSize); if (!!Scale) { - VariableGEPIndex Entry = { - LE.Val.V, LE.Val.ZExtBits, LE.Val.SExtBits, Scale, CxtI, LE.IsNSW}; + VariableGEPIndex Entry = {LE.Val, Scale, CxtI, LE.IsNSW}; Decomposed.VarIndices.push_back(Entry); } } // Take care of wrap-arounds if (GepHasConstantOffset) - Decomposed.Offset = adjustToPointerSize(Decomposed.Offset, PointerSize); + Decomposed.Offset = adjustToIndexSize(Decomposed.Offset, IndexSize); // Analyze the base pointer next. V = GEPOp->getOperand(0); @@ -838,7 +932,7 @@ ModRefInfo BasicAAResult::getModRefInfo(const CallBase *Call, // then the call can not mod/ref the pointer unless the call takes the pointer // as an argument, and itself doesn't capture it. if (!isa<Constant>(Object) && Call != Object && - isNonEscapingLocalObject(Object, &AAQI.IsCapturedCache)) { + AAQI.CI->isNotCapturedBeforeOrAt(Object, Call)) { // Optimistically assume that call doesn't touch Object and check this // assumption in the following loop. @@ -852,8 +946,7 @@ ModRefInfo BasicAAResult::getModRefInfo(const CallBase *Call, // pointer were passed to arguments that were neither of these, then it // couldn't be no-capture. if (!(*CI)->getType()->isPointerTy() || - (!Call->doesNotCapture(OperandNo) && - OperandNo < Call->getNumArgOperands() && + (!Call->doesNotCapture(OperandNo) && OperandNo < Call->arg_size() && !Call->isByValArgument(OperandNo))) continue; @@ -1046,20 +1139,13 @@ AliasResult BasicAAResult::aliasGEP( DecomposedGEP DecompGEP1 = DecomposeGEPExpression(GEP1, DL, &AC, DT); DecomposedGEP DecompGEP2 = DecomposeGEPExpression(V2, DL, &AC, DT); - // Don't attempt to analyze the decomposed GEP if index scale is not a - // compile-time constant. - if (!DecompGEP1.HasCompileTimeConstantScale || - !DecompGEP2.HasCompileTimeConstantScale) + // Bail if we were not able to decompose anything. + if (DecompGEP1.Base == GEP1 && DecompGEP2.Base == V2) return AliasResult::MayAlias; - assert(DecompGEP1.Base == UnderlyingV1 && DecompGEP2.Base == UnderlyingV2 && - "DecomposeGEPExpression returned a result different from " - "getUnderlyingObject"); - // Subtract the GEP2 pointer from the GEP1 pointer to find out their // symbolic difference. - DecompGEP1.Offset -= DecompGEP2.Offset; - GetIndexDifference(DecompGEP1.VarIndices, DecompGEP2.VarIndices); + subtractDecomposedGEPs(DecompGEP1, DecompGEP2); // If an inbounds GEP would have to start from an out of bounds address // for the two to alias, then we can assume noalias. @@ -1079,14 +1165,14 @@ AliasResult BasicAAResult::aliasGEP( // For GEPs with identical offsets, we can preserve the size and AAInfo // when performing the alias check on the underlying objects. if (DecompGEP1.Offset == 0 && DecompGEP1.VarIndices.empty()) - return getBestAAResults().alias( - MemoryLocation(UnderlyingV1, V1Size), - MemoryLocation(UnderlyingV2, V2Size), AAQI); + return getBestAAResults().alias(MemoryLocation(DecompGEP1.Base, V1Size), + MemoryLocation(DecompGEP2.Base, V2Size), + AAQI); // Do the base pointers alias? AliasResult BaseAlias = getBestAAResults().alias( - MemoryLocation::getBeforeOrAfter(UnderlyingV1), - MemoryLocation::getBeforeOrAfter(UnderlyingV2), AAQI); + MemoryLocation::getBeforeOrAfter(DecompGEP1.Base), + MemoryLocation::getBeforeOrAfter(DecompGEP2.Base), AAQI); // If we get a No or May, then return it immediately, no amount of analysis // will improve this situation. @@ -1100,7 +1186,7 @@ AliasResult BasicAAResult::aliasGEP( // is less than the size of the associated memory object, then we know // that the objects are partially overlapping. If the difference is // greater, we know they do not overlap. - if (DecompGEP1.Offset != 0 && DecompGEP1.VarIndices.empty()) { + if (DecompGEP1.VarIndices.empty()) { APInt &Off = DecompGEP1.Offset; // Initialize for Off >= 0 (V2 <= GEP1) case. @@ -1122,133 +1208,124 @@ AliasResult BasicAAResult::aliasGEP( Off = -Off; } - if (VLeftSize.hasValue()) { - const uint64_t LSize = VLeftSize.getValue(); - if (Off.ult(LSize)) { - // Conservatively drop processing if a phi was visited and/or offset is - // too big. - AliasResult AR = AliasResult::PartialAlias; - if (VRightSize.hasValue() && Off.ule(INT32_MAX) && - (Off + VRightSize.getValue()).ule(LSize)) { - // Memory referenced by right pointer is nested. Save the offset in - // cache. Note that originally offset estimated as GEP1-V2, but - // AliasResult contains the shift that represents GEP1+Offset=V2. - AR.setOffset(-Off.getSExtValue()); - AR.swap(Swapped); - } - return AR; + if (!VLeftSize.hasValue()) + return AliasResult::MayAlias; + + const uint64_t LSize = VLeftSize.getValue(); + if (Off.ult(LSize)) { + // Conservatively drop processing if a phi was visited and/or offset is + // too big. + AliasResult AR = AliasResult::PartialAlias; + if (VRightSize.hasValue() && Off.ule(INT32_MAX) && + (Off + VRightSize.getValue()).ule(LSize)) { + // Memory referenced by right pointer is nested. Save the offset in + // cache. Note that originally offset estimated as GEP1-V2, but + // AliasResult contains the shift that represents GEP1+Offset=V2. + AR.setOffset(-Off.getSExtValue()); + AR.swap(Swapped); } - return AliasResult::NoAlias; + return AR; } + return AliasResult::NoAlias; } - if (!DecompGEP1.VarIndices.empty()) { - APInt GCD; - bool AllNonNegative = DecompGEP1.Offset.isNonNegative(); - bool AllNonPositive = DecompGEP1.Offset.isNonPositive(); - for (unsigned i = 0, e = DecompGEP1.VarIndices.size(); i != e; ++i) { - APInt Scale = DecompGEP1.VarIndices[i].Scale; - APInt ScaleForGCD = DecompGEP1.VarIndices[i].Scale; - if (!DecompGEP1.VarIndices[i].IsNSW) - ScaleForGCD = APInt::getOneBitSet(Scale.getBitWidth(), - Scale.countTrailingZeros()); - - if (i == 0) - GCD = ScaleForGCD.abs(); - else - GCD = APIntOps::GreatestCommonDivisor(GCD, ScaleForGCD.abs()); - - if (AllNonNegative || AllNonPositive) { - // If the Value could change between cycles, then any reasoning about - // the Value this cycle may not hold in the next cycle. We'll just - // give up if we can't determine conditions that hold for every cycle: - const Value *V = DecompGEP1.VarIndices[i].V; - const Instruction *CxtI = DecompGEP1.VarIndices[i].CxtI; - - KnownBits Known = computeKnownBits(V, DL, 0, &AC, CxtI, DT); - bool SignKnownZero = Known.isNonNegative(); - bool SignKnownOne = Known.isNegative(); - - // Zero-extension widens the variable, and so forces the sign - // bit to zero. - bool IsZExt = DecompGEP1.VarIndices[i].ZExtBits > 0 || isa<ZExtInst>(V); - SignKnownZero |= IsZExt; - SignKnownOne &= !IsZExt; - - AllNonNegative &= (SignKnownZero && Scale.isNonNegative()) || - (SignKnownOne && Scale.isNonPositive()); - AllNonPositive &= (SignKnownZero && Scale.isNonPositive()) || - (SignKnownOne && Scale.isNonNegative()); - } - } + // We need to know both acess sizes for all the following heuristics. + if (!V1Size.hasValue() || !V2Size.hasValue()) + return AliasResult::MayAlias; - // We now have accesses at two offsets from the same base: - // 1. (...)*GCD + DecompGEP1.Offset with size V1Size - // 2. 0 with size V2Size - // Using arithmetic modulo GCD, the accesses are at - // [ModOffset..ModOffset+V1Size) and [0..V2Size). If the first access fits - // into the range [V2Size..GCD), then we know they cannot overlap. - APInt ModOffset = DecompGEP1.Offset.srem(GCD); - if (ModOffset.isNegative()) - ModOffset += GCD; // We want mod, not rem. - if (V1Size.hasValue() && V2Size.hasValue() && - ModOffset.uge(V2Size.getValue()) && - (GCD - ModOffset).uge(V1Size.getValue())) - return AliasResult::NoAlias; + APInt GCD; + ConstantRange OffsetRange = ConstantRange(DecompGEP1.Offset); + for (unsigned i = 0, e = DecompGEP1.VarIndices.size(); i != e; ++i) { + const VariableGEPIndex &Index = DecompGEP1.VarIndices[i]; + const APInt &Scale = Index.Scale; + APInt ScaleForGCD = Scale; + if (!Index.IsNSW) + ScaleForGCD = APInt::getOneBitSet(Scale.getBitWidth(), + Scale.countTrailingZeros()); + + if (i == 0) + GCD = ScaleForGCD.abs(); + else + GCD = APIntOps::GreatestCommonDivisor(GCD, ScaleForGCD.abs()); + + ConstantRange CR = + computeConstantRange(Index.Val.V, true, &AC, Index.CxtI); + KnownBits Known = + computeKnownBits(Index.Val.V, DL, 0, &AC, Index.CxtI, DT); + CR = CR.intersectWith( + ConstantRange::fromKnownBits(Known, /* Signed */ true), + ConstantRange::Signed); + CR = Index.Val.evaluateWith(CR).sextOrTrunc(OffsetRange.getBitWidth()); + + assert(OffsetRange.getBitWidth() == Scale.getBitWidth() && + "Bit widths are normalized to MaxIndexSize"); + if (Index.IsNSW) + OffsetRange = OffsetRange.add(CR.smul_sat(ConstantRange(Scale))); + else + OffsetRange = OffsetRange.add(CR.smul_fast(ConstantRange(Scale))); + } - // If we know all the variables are non-negative, then the total offset is - // also non-negative and >= DecompGEP1.Offset. We have the following layout: - // [0, V2Size) ... [TotalOffset, TotalOffer+V1Size] - // If DecompGEP1.Offset >= V2Size, the accesses don't alias. - if (AllNonNegative && V2Size.hasValue() && - DecompGEP1.Offset.uge(V2Size.getValue())) - return AliasResult::NoAlias; - // Similarly, if the variables are non-positive, then the total offset is - // also non-positive and <= DecompGEP1.Offset. We have the following layout: - // [TotalOffset, TotalOffset+V1Size) ... [0, V2Size) - // If -DecompGEP1.Offset >= V1Size, the accesses don't alias. - if (AllNonPositive && V1Size.hasValue() && - (-DecompGEP1.Offset).uge(V1Size.getValue())) - return AliasResult::NoAlias; + // We now have accesses at two offsets from the same base: + // 1. (...)*GCD + DecompGEP1.Offset with size V1Size + // 2. 0 with size V2Size + // Using arithmetic modulo GCD, the accesses are at + // [ModOffset..ModOffset+V1Size) and [0..V2Size). If the first access fits + // into the range [V2Size..GCD), then we know they cannot overlap. + APInt ModOffset = DecompGEP1.Offset.srem(GCD); + if (ModOffset.isNegative()) + ModOffset += GCD; // We want mod, not rem. + if (ModOffset.uge(V2Size.getValue()) && + (GCD - ModOffset).uge(V1Size.getValue())) + return AliasResult::NoAlias; - if (V1Size.hasValue() && V2Size.hasValue()) { - // Try to determine whether abs(VarIndex) > 0. - Optional<APInt> MinAbsVarIndex; - if (DecompGEP1.VarIndices.size() == 1) { - // VarIndex = Scale*V. If V != 0 then abs(VarIndex) >= abs(Scale). - const VariableGEPIndex &Var = DecompGEP1.VarIndices[0]; - if (isKnownNonZero(Var.V, DL, 0, &AC, Var.CxtI, DT)) - MinAbsVarIndex = Var.Scale.abs(); - } else if (DecompGEP1.VarIndices.size() == 2) { - // VarIndex = Scale*V0 + (-Scale)*V1. - // If V0 != V1 then abs(VarIndex) >= abs(Scale). - // Check that VisitedPhiBBs is empty, to avoid reasoning about - // inequality of values across loop iterations. - const VariableGEPIndex &Var0 = DecompGEP1.VarIndices[0]; - const VariableGEPIndex &Var1 = DecompGEP1.VarIndices[1]; - if (Var0.Scale == -Var1.Scale && Var0.ZExtBits == Var1.ZExtBits && - Var0.SExtBits == Var1.SExtBits && VisitedPhiBBs.empty() && - isKnownNonEqual(Var0.V, Var1.V, DL, &AC, /* CxtI */ nullptr, DT)) - MinAbsVarIndex = Var0.Scale.abs(); - } + // Compute ranges of potentially accessed bytes for both accesses. If the + // interseciton is empty, there can be no overlap. + unsigned BW = OffsetRange.getBitWidth(); + ConstantRange Range1 = OffsetRange.add( + ConstantRange(APInt(BW, 0), APInt(BW, V1Size.getValue()))); + ConstantRange Range2 = + ConstantRange(APInt(BW, 0), APInt(BW, V2Size.getValue())); + if (Range1.intersectWith(Range2).isEmptySet()) + return AliasResult::NoAlias; - if (MinAbsVarIndex) { - // The constant offset will have added at least +/-MinAbsVarIndex to it. - APInt OffsetLo = DecompGEP1.Offset - *MinAbsVarIndex; - APInt OffsetHi = DecompGEP1.Offset + *MinAbsVarIndex; - // Check that an access at OffsetLo or lower, and an access at OffsetHi - // or higher both do not alias. - if (OffsetLo.isNegative() && (-OffsetLo).uge(V1Size.getValue()) && - OffsetHi.isNonNegative() && OffsetHi.uge(V2Size.getValue())) - return AliasResult::NoAlias; - } + // Try to determine the range of values for VarIndex such that + // VarIndex <= -MinAbsVarIndex || MinAbsVarIndex <= VarIndex. + Optional<APInt> MinAbsVarIndex; + if (DecompGEP1.VarIndices.size() == 1) { + // VarIndex = Scale*V. + const VariableGEPIndex &Var = DecompGEP1.VarIndices[0]; + if (Var.Val.TruncBits == 0 && + isKnownNonZero(Var.Val.V, DL, 0, &AC, Var.CxtI, DT)) { + // If V != 0 then abs(VarIndex) >= abs(Scale). + MinAbsVarIndex = Var.Scale.abs(); } + } else if (DecompGEP1.VarIndices.size() == 2) { + // VarIndex = Scale*V0 + (-Scale)*V1. + // If V0 != V1 then abs(VarIndex) >= abs(Scale). + // Check that VisitedPhiBBs is empty, to avoid reasoning about + // inequality of values across loop iterations. + const VariableGEPIndex &Var0 = DecompGEP1.VarIndices[0]; + const VariableGEPIndex &Var1 = DecompGEP1.VarIndices[1]; + if (Var0.Scale == -Var1.Scale && Var0.Val.TruncBits == 0 && + Var0.Val.hasSameCastsAs(Var1.Val) && VisitedPhiBBs.empty() && + isKnownNonEqual(Var0.Val.V, Var1.Val.V, DL, &AC, /* CxtI */ nullptr, + DT)) + MinAbsVarIndex = Var0.Scale.abs(); + } - if (constantOffsetHeuristic(DecompGEP1.VarIndices, V1Size, V2Size, - DecompGEP1.Offset, &AC, DT)) + if (MinAbsVarIndex) { + // The constant offset will have added at least +/-MinAbsVarIndex to it. + APInt OffsetLo = DecompGEP1.Offset - *MinAbsVarIndex; + APInt OffsetHi = DecompGEP1.Offset + *MinAbsVarIndex; + // We know that Offset <= OffsetLo || Offset >= OffsetHi + if (OffsetLo.isNegative() && (-OffsetLo).uge(V1Size.getValue()) && + OffsetHi.isNonNegative() && OffsetHi.uge(V2Size.getValue())) return AliasResult::NoAlias; } + if (constantOffsetHeuristic(DecompGEP1, V1Size, V2Size, &AC, DT)) + return AliasResult::NoAlias; + // Statically, we can see that the base objects are the same, but the // pointers have dynamic offsets which we can't resolve. And none of our // little tricks above worked. @@ -1517,10 +1594,10 @@ AliasResult BasicAAResult::aliasCheck(const Value *V1, LocationSize V1Size, // location if that memory location doesn't escape. Or it may pass a // nocapture value to other functions as long as they don't capture it. if (isEscapeSource(O1) && - isNonEscapingLocalObject(O2, &AAQI.IsCapturedCache)) + AAQI.CI->isNotCapturedBeforeOrAt(O2, cast<Instruction>(O1))) return AliasResult::NoAlias; if (isEscapeSource(O2) && - isNonEscapingLocalObject(O1, &AAQI.IsCapturedCache)) + AAQI.CI->isNotCapturedBeforeOrAt(O1, cast<Instruction>(O2))) return AliasResult::NoAlias; } @@ -1692,62 +1769,54 @@ bool BasicAAResult::isValueEqualInPotentialCycles(const Value *V, } /// Computes the symbolic difference between two de-composed GEPs. -/// -/// Dest and Src are the variable indices from two decomposed GetElementPtr -/// instructions GEP1 and GEP2 which have common base pointers. -void BasicAAResult::GetIndexDifference( - SmallVectorImpl<VariableGEPIndex> &Dest, - const SmallVectorImpl<VariableGEPIndex> &Src) { - if (Src.empty()) - return; - - for (unsigned i = 0, e = Src.size(); i != e; ++i) { - const Value *V = Src[i].V; - unsigned ZExtBits = Src[i].ZExtBits, SExtBits = Src[i].SExtBits; - APInt Scale = Src[i].Scale; - +void BasicAAResult::subtractDecomposedGEPs(DecomposedGEP &DestGEP, + const DecomposedGEP &SrcGEP) { + DestGEP.Offset -= SrcGEP.Offset; + for (const VariableGEPIndex &Src : SrcGEP.VarIndices) { // Find V in Dest. This is N^2, but pointer indices almost never have more // than a few variable indexes. - for (unsigned j = 0, e = Dest.size(); j != e; ++j) { - if (!isValueEqualInPotentialCycles(Dest[j].V, V) || - Dest[j].ZExtBits != ZExtBits || Dest[j].SExtBits != SExtBits) + bool Found = false; + for (auto I : enumerate(DestGEP.VarIndices)) { + VariableGEPIndex &Dest = I.value(); + if (!isValueEqualInPotentialCycles(Dest.Val.V, Src.Val.V) || + !Dest.Val.hasSameCastsAs(Src.Val)) continue; // If we found it, subtract off Scale V's from the entry in Dest. If it // goes to zero, remove the entry. - if (Dest[j].Scale != Scale) { - Dest[j].Scale -= Scale; - Dest[j].IsNSW = false; - } else - Dest.erase(Dest.begin() + j); - Scale = 0; + if (Dest.Scale != Src.Scale) { + Dest.Scale -= Src.Scale; + Dest.IsNSW = false; + } else { + DestGEP.VarIndices.erase(DestGEP.VarIndices.begin() + I.index()); + } + Found = true; break; } // If we didn't consume this entry, add it to the end of the Dest list. - if (!!Scale) { - VariableGEPIndex Entry = {V, ZExtBits, SExtBits, - -Scale, Src[i].CxtI, Src[i].IsNSW}; - Dest.push_back(Entry); + if (!Found) { + VariableGEPIndex Entry = {Src.Val, -Src.Scale, Src.CxtI, Src.IsNSW}; + DestGEP.VarIndices.push_back(Entry); } } } bool BasicAAResult::constantOffsetHeuristic( - const SmallVectorImpl<VariableGEPIndex> &VarIndices, - LocationSize MaybeV1Size, LocationSize MaybeV2Size, const APInt &BaseOffset, - AssumptionCache *AC, DominatorTree *DT) { - if (VarIndices.size() != 2 || !MaybeV1Size.hasValue() || + const DecomposedGEP &GEP, LocationSize MaybeV1Size, + LocationSize MaybeV2Size, AssumptionCache *AC, DominatorTree *DT) { + if (GEP.VarIndices.size() != 2 || !MaybeV1Size.hasValue() || !MaybeV2Size.hasValue()) return false; const uint64_t V1Size = MaybeV1Size.getValue(); const uint64_t V2Size = MaybeV2Size.getValue(); - const VariableGEPIndex &Var0 = VarIndices[0], &Var1 = VarIndices[1]; + const VariableGEPIndex &Var0 = GEP.VarIndices[0], &Var1 = GEP.VarIndices[1]; - if (Var0.ZExtBits != Var1.ZExtBits || Var0.SExtBits != Var1.SExtBits || - Var0.Scale != -Var1.Scale || Var0.V->getType() != Var1.V->getType()) + if (Var0.Val.TruncBits != 0 || !Var0.Val.hasSameCastsAs(Var1.Val) || + Var0.Scale != -Var1.Scale || + Var0.Val.V->getType() != Var1.Val.V->getType()) return false; // We'll strip off the Extensions of Var0 and Var1 and do another round @@ -1755,11 +1824,10 @@ bool BasicAAResult::constantOffsetHeuristic( // is zext(%x + 1) we should get V1 == %x and V1Offset == 1. LinearExpression E0 = - GetLinearExpression(ExtendedValue(Var0.V), DL, 0, AC, DT); + GetLinearExpression(CastedValue(Var0.Val.V), DL, 0, AC, DT); LinearExpression E1 = - GetLinearExpression(ExtendedValue(Var1.V), DL, 0, AC, DT); - if (E0.Scale != E1.Scale || E0.Val.ZExtBits != E1.Val.ZExtBits || - E0.Val.SExtBits != E1.Val.SExtBits || + GetLinearExpression(CastedValue(Var1.Val.V), DL, 0, AC, DT); + if (E0.Scale != E1.Scale || !E0.Val.hasSameCastsAs(E1.Val) || !isValueEqualInPotentialCycles(E0.Val.V, E1.Val.V)) return false; @@ -1779,8 +1847,8 @@ bool BasicAAResult::constantOffsetHeuristic( // arithmetic (i.e. for some values of GEP1 and V2 GEP1 < V2, and for other // values GEP1 > V2). We'll therefore only declare NoAlias if both V1Size and // V2Size can fit in the MinDiffBytes gap. - return MinDiffBytes.uge(V1Size + BaseOffset.abs()) && - MinDiffBytes.uge(V2Size + BaseOffset.abs()); + return MinDiffBytes.uge(V1Size + GEP.Offset.abs()) && + MinDiffBytes.uge(V2Size + GEP.Offset.abs()); } //===----------------------------------------------------------------------===// |