From: Shilei Tian Date: Sun, 8 Jan 2023 21:45:42 +0000 (-0500) Subject: [AAUnderlyingObjects] Introduce an AA for getting underlying objects of a pointer X-Git-Tag: upstream/17.0.6~21770 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=acd22b275131a965f4a6006dfa0b237ed6b6572e;p=platform%2Fupstream%2Fllvm.git [AAUnderlyingObjects] Introduce an AA for getting underlying objects of a pointer This patch introduces a new AA `AAUnderlyingObjects`. It is basically like a wrapper AA of the function `AA::getAssumedUnderlyingObjects`, but it can recursively do query if the underlying object is an indirect access, such as a phi node or a select instruction. Reviewed By: jdoerfert Differential Revision: https://reviews.llvm.org/D141164 --- diff --git a/llvm/include/llvm/Transforms/IPO/Attributor.h b/llvm/include/llvm/Transforms/IPO/Attributor.h index 1d813cb..aec4fc8 100644 --- a/llvm/include/llvm/Transforms/IPO/Attributor.h +++ b/llvm/include/llvm/Transforms/IPO/Attributor.h @@ -301,19 +301,6 @@ Constant *getInitialValueForObj(Value &Obj, Type &Ty, const DataLayout &DL, RangeTy *RangePtr = nullptr); -/// Collect all potential underlying objects of \p Ptr at position \p CtxI in -/// \p Objects. Assumed information is used and dependences onto \p QueryingAA -/// are added appropriately. -/// -/// \returns True if \p Objects contains all assumed underlying objects, and -/// false if something went wrong and the objects could not be -/// determined. -bool getAssumedUnderlyingObjects( - Attributor &A, const Value &Ptr, SmallSetVector &Objects, - const AbstractAttribute &QueryingAA, const Instruction *CtxI, - bool &UsedAssumedInformation, AA::ValueScope VS = AA::Interprocedural, - SmallPtrSetImpl *SeenObjects = nullptr); - /// Collect all potential values \p LI could read into \p PotentialValues. That /// is, the only values read by \p LI are assumed to be known and all are in /// \p PotentialValues. \p PotentialValueOrigins will contain all the @@ -5445,6 +5432,38 @@ struct AAAssumptionInfo static const char ID; }; +/// An abstract attribute for getting all assumption underlying objects. +struct AAUnderlyingObjects : AbstractAttribute { + AAUnderlyingObjects(const IRPosition &IRP) : AbstractAttribute(IRP) {} + + /// Create an abstract attribute biew for the position \p IRP. + static AAUnderlyingObjects &createForPosition(const IRPosition &IRP, + Attributor &A); + + /// See AbstractAttribute::getName() + const std::string getName() const override { return "AAUnderlyingObjects"; } + + /// See AbstractAttribute::getIdAddr() + const char *getIdAddr() const override { return &ID; } + + /// This function should return true if the type of the \p AA is + /// AAUnderlyingObjects. + static bool classof(const AbstractAttribute *AA) { + return (AA->getIdAddr() == &ID); + } + + /// Unique ID (due to the unique address) + static const char ID; + + /// Check \p Pred on all underlying objects in \p Scope collected so far. + /// + /// This method will evaluate \p Pred on all underlying objects in \p Scope + /// collected so far and return true if \p Pred holds on all of them. + virtual bool + forallUnderlyingObjects(function_ref Pred, + AA::ValueScope Scope = AA::Interprocedural) const = 0; +}; + raw_ostream &operator<<(raw_ostream &, const AAPointerInfo::Access &); /// Run options, used by the pass manager. diff --git a/llvm/lib/Transforms/IPO/Attributor.cpp b/llvm/lib/Transforms/IPO/Attributor.cpp index b017961..70de4d5 100644 --- a/llvm/lib/Transforms/IPO/Attributor.cpp +++ b/llvm/lib/Transforms/IPO/Attributor.cpp @@ -340,14 +340,6 @@ static bool getPotentialCopiesOfMemoryValue( << " (only exact: " << OnlyExact << ")\n";); Value &Ptr = *I.getPointerOperand(); - SmallSetVector Objects; - if (!AA::getAssumedUnderlyingObjects(A, Ptr, Objects, QueryingAA, &I, - UsedAssumedInformation)) { - LLVM_DEBUG( - dbgs() << "Underlying objects stored into could not be determined\n";); - return false; - } - // Containers to remember the pointer infos and new copies while we are not // sure that we can find all of them. If we abort we want to avoid spurious // dependences and potential copies in the provided container. @@ -357,36 +349,36 @@ static bool getPotentialCopiesOfMemoryValue( const auto *TLI = A.getInfoCache().getTargetLibraryInfoForFunction(*I.getFunction()); - LLVM_DEBUG(dbgs() << "Visit " << Objects.size() << " objects:\n"); - for (Value *Obj : Objects) { - LLVM_DEBUG(dbgs() << "Visit underlying object " << *Obj << "\n"); - if (isa(Obj)) - continue; - if (isa(Obj)) { + + auto Pred = [&](Value &Obj) { + LLVM_DEBUG(dbgs() << "Visit underlying object " << Obj << "\n"); + if (isa(&Obj)) + return true; + if (isa(&Obj)) { // A null pointer access can be undefined but any offset from null may // be OK. We do not try to optimize the latter. if (!NullPointerIsDefined(I.getFunction(), Ptr.getType()->getPointerAddressSpace()) && A.getAssumedSimplified(Ptr, QueryingAA, UsedAssumedInformation, - AA::Interprocedural) == Obj) - continue; + AA::Interprocedural) == &Obj) + return true; LLVM_DEBUG( dbgs() << "Underlying object is a valid nullptr, giving up.\n";); return false; } // TODO: Use assumed noalias return. - if (!isa(Obj) && !isa(Obj) && - !(IsLoad ? isAllocationFn(Obj, TLI) : isNoAliasCall(Obj))) { - LLVM_DEBUG(dbgs() << "Underlying object is not supported yet: " << *Obj + if (!isa(&Obj) && !isa(&Obj) && + !(IsLoad ? isAllocationFn(&Obj, TLI) : isNoAliasCall(&Obj))) { + LLVM_DEBUG(dbgs() << "Underlying object is not supported yet: " << Obj << "\n";); return false; } - if (auto *GV = dyn_cast(Obj)) + if (auto *GV = dyn_cast(&Obj)) if (!GV->hasLocalLinkage() && !(GV->isConstant() && GV->hasInitializer())) { LLVM_DEBUG(dbgs() << "Underlying object is global with external " "linkage, not supported yet: " - << *Obj << "\n";); + << Obj << "\n";); return false; } @@ -457,21 +449,21 @@ static bool getPotentialCopiesOfMemoryValue( bool HasBeenWrittenTo = false; AA::RangeTy Range; - auto &PI = A.getAAFor(QueryingAA, IRPosition::value(*Obj), + auto &PI = A.getAAFor(QueryingAA, IRPosition::value(Obj), DepClassTy::NONE); if (!PI.forallInterferingAccesses(A, QueryingAA, I, CheckAccess, HasBeenWrittenTo, Range)) { LLVM_DEBUG( dbgs() << "Failed to verify all interfering accesses for underlying object: " - << *Obj << "\n"); + << Obj << "\n"); return false; } if (IsLoad && !HasBeenWrittenTo && !Range.isUnassigned()) { const DataLayout &DL = A.getDataLayout(); Value *InitialValue = - AA::getInitialValueForObj(*Obj, *I.getType(), TLI, DL, &Range); + AA::getInitialValueForObj(Obj, *I.getType(), TLI, DL, &Range); if (!InitialValue) { LLVM_DEBUG(dbgs() << "Could not determine required initial value of " "underlying object, abort!\n"); @@ -489,6 +481,16 @@ static bool getPotentialCopiesOfMemoryValue( } PIs.push_back(&PI); + + return true; + }; + + const auto &AAUO = A.getAAFor( + QueryingAA, IRPosition::value(Ptr), DepClassTy::OPTIONAL); + if (!AAUO.forallUnderlyingObjects(Pred)) { + LLVM_DEBUG( + dbgs() << "Underlying objects stored into could not be determined\n";); + return false; } // Only if we were successful collection all potential copies we record diff --git a/llvm/lib/Transforms/IPO/AttributorAttributes.cpp b/llvm/lib/Transforms/IPO/AttributorAttributes.cpp index 0af298b..9c67a001 100644 --- a/llvm/lib/Transforms/IPO/AttributorAttributes.cpp +++ b/llvm/lib/Transforms/IPO/AttributorAttributes.cpp @@ -185,6 +185,7 @@ PIPE_OPERATOR(AACallEdges) PIPE_OPERATOR(AAFunctionReachability) PIPE_OPERATOR(AAPointerInfo) PIPE_OPERATOR(AAAssumptionInfo) +PIPE_OPERATOR(AAUnderlyingObjects) #undef PIPE_OPERATOR @@ -311,38 +312,6 @@ static Value *constructPointer(Type *ResTy, Type *PtrElemTy, Value *Ptr, return Ptr; } -bool AA::getAssumedUnderlyingObjects(Attributor &A, const Value &Ptr, - SmallSetVector &Objects, - const AbstractAttribute &QueryingAA, - const Instruction *CtxI, - bool &UsedAssumedInformation, - AA::ValueScope S, - SmallPtrSetImpl *SeenObjects) { - SmallPtrSet LocalSeenObjects; - if (!SeenObjects) - SeenObjects = &LocalSeenObjects; - - SmallVector Values; - if (!A.getAssumedSimplifiedValues(IRPosition::value(Ptr), &QueryingAA, Values, - S, UsedAssumedInformation)) { - Objects.insert(const_cast(&Ptr)); - return true; - } - - for (auto &VAC : Values) { - Value *UO = getUnderlyingObject(VAC.getValue()); - if (UO && UO != VAC.getValue() && SeenObjects->insert(UO).second) { - if (!getAssumedUnderlyingObjects(A, *UO, Objects, QueryingAA, - VAC.getCtxI(), UsedAssumedInformation, S, - SeenObjects)) - return false; - continue; - } - Objects.insert(VAC.getValue()); - } - return true; -} - static const Value * stripAndAccumulateOffsets(Attributor &A, const AbstractAttribute &QueryingAA, const Value *Val, const DataLayout &DL, APInt &Offset, @@ -8193,24 +8162,12 @@ void AAMemoryLocationImpl::categorizePtrValue( << Ptr << " [" << getMemoryLocationsAsStr(State.getAssumed()) << "]\n"); - SmallSetVector Objects; - bool UsedAssumedInformation = false; - if (!AA::getAssumedUnderlyingObjects(A, Ptr, Objects, *this, &I, - UsedAssumedInformation, - AA::Intraprocedural)) { - LLVM_DEBUG( - dbgs() << "[AAMemoryLocation] Pointer locations not categorized\n"); - updateStateAndAccessesMap(State, NO_UNKOWN_MEM, &I, nullptr, Changed, - getAccessKindFromInst(&I)); - return; - } - - for (Value *Obj : Objects) { + auto Pred = [&](Value &Obj) { // TODO: recognize the TBAA used for constant accesses. MemoryLocationsKind MLK = NO_LOCATIONS; - if (isa(Obj)) - continue; - if (isa(Obj)) { + if (isa(&Obj)) + return true; + if (isa(&Obj)) { // TODO: For now we do not treat byval arguments as local copies performed // on the call edge, though, we should. To make that happen we need to // teach various passes, e.g., DSE, about the copy effect of a byval. That @@ -8218,25 +8175,25 @@ void AAMemoryLocationImpl::categorizePtrValue( // readnone again, arguably their accesses have no effect outside of the // function, like accesses to allocas. MLK = NO_ARGUMENT_MEM; - } else if (auto *GV = dyn_cast(Obj)) { + } else if (auto *GV = dyn_cast(&Obj)) { // Reading constant memory is not treated as a read "effect" by the // function attr pass so we won't neither. Constants defined by TBAA are // similar. (We know we do not write it because it is constant.) if (auto *GVar = dyn_cast(GV)) if (GVar->isConstant()) - continue; + return true; if (GV->hasLocalLinkage()) MLK = NO_GLOBAL_INTERNAL_MEM; else MLK = NO_GLOBAL_EXTERNAL_MEM; - } else if (isa(Obj) && + } else if (isa(&Obj) && !NullPointerIsDefined(getAssociatedFunction(), Ptr.getType()->getPointerAddressSpace())) { - continue; - } else if (isa(Obj)) { + return true; + } else if (isa(&Obj)) { MLK = NO_LOCAL_MEM; - } else if (const auto *CB = dyn_cast(Obj)) { + } else if (const auto *CB = dyn_cast(&Obj)) { const auto &NoAliasAA = A.getAAFor( *this, IRPosition::callsite_returned(*CB), DepClassTy::OPTIONAL); if (NoAliasAA.isAssumedNoAlias()) @@ -8249,10 +8206,21 @@ void AAMemoryLocationImpl::categorizePtrValue( assert(MLK != NO_LOCATIONS && "No location specified!"); LLVM_DEBUG(dbgs() << "[AAMemoryLocation] Ptr value can be categorized: " - << *Obj << " -> " << getMemoryLocationsAsStr(MLK) - << "\n"); - updateStateAndAccessesMap(getState(), MLK, &I, Obj, Changed, + << Obj << " -> " << getMemoryLocationsAsStr(MLK) << "\n"); + updateStateAndAccessesMap(getState(), MLK, &I, &Obj, Changed, getAccessKindFromInst(&I)); + + return true; + }; + + const auto &AA = A.getAAFor( + *this, IRPosition::value(Ptr), DepClassTy::OPTIONAL); + if (!AA.forallUnderlyingObjects(Pred, AA::Intraprocedural)) { + LLVM_DEBUG( + dbgs() << "[AAMemoryLocation] Pointer locations not categorized\n"); + updateStateAndAccessesMap(State, NO_UNKOWN_MEM, &I, nullptr, Changed, + getAccessKindFromInst(&I)); + return; } LLVM_DEBUG( @@ -11231,6 +11199,159 @@ AACallGraphNode *AACallEdgeIterator::operator*() const { void AttributorCallGraph::print() { llvm::WriteGraph(outs(), this); } +/// ------------------------ UnderlyingObjects --------------------------------- + +namespace { +struct AAUnderlyingObjectsImpl + : StateWrapper { + using BaseTy = StateWrapper; + AAUnderlyingObjectsImpl(const IRPosition &IRP, Attributor &A) : BaseTy(IRP) {} + + /// See AbstractAttribute::getAsStr(). + const std::string getAsStr() const override { + return std::string("UnderlyingObjects ") + + (isValidState() + ? (std::string("inter #") + + std::to_string(InterAssumedUnderlyingObjects.size()) + + " objs" + std::string(", intra #") + + std::to_string(IntraAssumedUnderlyingObjects.size()) + + " objs") + : ""); + } + + /// See AbstractAttribute::trackStatistics() + void trackStatistics() const override {} + + /// See AbstractAttribute::updateImpl(...). + ChangeStatus updateImpl(Attributor &A) override { + auto &Ptr = getAssociatedValue(); + + auto DoUpdate = [&](SmallSetVector &UnderlyingObjects, + AA::ValueScope Scope) { + bool UsedAssumedInformation; + SmallPtrSet SeenObjects; + SmallVector Values; + + if (!A.getAssumedSimplifiedValues(IRPosition::value(Ptr), *this, Values, + Scope, UsedAssumedInformation)) + return UnderlyingObjects.insert(&Ptr); + + bool Changed = false; + + for (unsigned I = 0; I < Values.size(); ++I) { + auto &VAC = Values[I]; + auto *Obj = VAC.getValue(); + Value *UO = getUnderlyingObject(Obj); + if (UO && UO != VAC.getValue() && SeenObjects.insert(UO).second) { + const auto &OtherAA = A.getAAFor( + *this, IRPosition::value(*UO), DepClassTy::OPTIONAL); + auto Pred = [&Values](Value &V) { + Values.emplace_back(V, nullptr); + return true; + }; + + if (!OtherAA.forallUnderlyingObjects(Pred, Scope)) + llvm_unreachable( + "The forall call should not return false at this position"); + + continue; + } + + if (isa(Obj) || isa(Obj)) { + Changed |= handleIndirect(A, *Obj, UnderlyingObjects, Scope); + continue; + } + + Changed |= UnderlyingObjects.insert(Obj); + } + + return Changed; + }; + + bool Changed = false; + Changed |= DoUpdate(IntraAssumedUnderlyingObjects, AA::Intraprocedural); + Changed |= DoUpdate(InterAssumedUnderlyingObjects, AA::Interprocedural); + + return Changed ? ChangeStatus::CHANGED : ChangeStatus::UNCHANGED; + } + + bool forallUnderlyingObjects( + function_ref Pred, + AA::ValueScope Scope = AA::Interprocedural) const override { + if (!isValidState()) + return Pred(getAssociatedValue()); + + auto &AssumedUnderlyingObjects = Scope == AA::Intraprocedural + ? IntraAssumedUnderlyingObjects + : InterAssumedUnderlyingObjects; + for (Value *Obj : AssumedUnderlyingObjects) + if (!Pred(*Obj)) + return false; + + return true; + } + +private: + /// Handle the case where the value is not the actual underlying value, such + /// as a phi node or a select instruction. + bool handleIndirect(Attributor &A, Value &V, + SmallSetVector &UnderlyingObjects, + AA::ValueScope Scope) { + bool Changed = false; + const auto &AA = A.getAAFor( + *this, IRPosition::value(V), DepClassTy::OPTIONAL); + auto Pred = [&](Value &V) { + Changed |= UnderlyingObjects.insert(&V); + return true; + }; + if (!AA.forallUnderlyingObjects(Pred, Scope)) + llvm_unreachable( + "The forall call should not return false at this position"); + return Changed; + } + + /// All the underlying objects collected so far via intra procedural scope. + SmallSetVector IntraAssumedUnderlyingObjects; + /// All the underlying objects collected so far via inter procedural scope. + SmallSetVector InterAssumedUnderlyingObjects; +}; + +struct AAUnderlyingObjectsFloating final : AAUnderlyingObjectsImpl { + AAUnderlyingObjectsFloating(const IRPosition &IRP, Attributor &A) + : AAUnderlyingObjectsImpl(IRP, A) {} +}; + +struct AAUnderlyingObjectsArgument final : AAUnderlyingObjectsImpl { + AAUnderlyingObjectsArgument(const IRPosition &IRP, Attributor &A) + : AAUnderlyingObjectsImpl(IRP, A) {} +}; + +struct AAUnderlyingObjectsCallSite final : AAUnderlyingObjectsImpl { + AAUnderlyingObjectsCallSite(const IRPosition &IRP, Attributor &A) + : AAUnderlyingObjectsImpl(IRP, A) {} +}; + +struct AAUnderlyingObjectsCallSiteArgument final : AAUnderlyingObjectsImpl { + AAUnderlyingObjectsCallSiteArgument(const IRPosition &IRP, Attributor &A) + : AAUnderlyingObjectsImpl(IRP, A) {} +}; + +struct AAUnderlyingObjectsReturned final : AAUnderlyingObjectsImpl { + AAUnderlyingObjectsReturned(const IRPosition &IRP, Attributor &A) + : AAUnderlyingObjectsImpl(IRP, A) {} +}; + +struct AAUnderlyingObjectsCallSiteReturned final : AAUnderlyingObjectsImpl { + AAUnderlyingObjectsCallSiteReturned(const IRPosition &IRP, Attributor &A) + : AAUnderlyingObjectsImpl(IRP, A) {} +}; + +struct AAUnderlyingObjectsFunction final : AAUnderlyingObjectsImpl { + AAUnderlyingObjectsFunction(const IRPosition &IRP, Attributor &A) + : AAUnderlyingObjectsImpl(IRP, A) {} +}; +} + const char AAReturnedValues::ID = 0; const char AANoUnwind::ID = 0; const char AANoSync::ID = 0; @@ -11260,6 +11381,7 @@ const char AACallEdges::ID = 0; const char AAFunctionReachability::ID = 0; const char AAPointerInfo::ID = 0; const char AAAssumptionInfo::ID = 0; +const char AAUnderlyingObjects::ID = 0; // Macro magic to create the static generator function for attributes that // follow the naming scheme. @@ -11380,6 +11502,7 @@ CREATE_VALUE_ABSTRACT_ATTRIBUTE_FOR_POSITION(AAPointerInfo) CREATE_ALL_ABSTRACT_ATTRIBUTE_FOR_POSITION(AAValueSimplify) CREATE_ALL_ABSTRACT_ATTRIBUTE_FOR_POSITION(AAIsDead) CREATE_ALL_ABSTRACT_ATTRIBUTE_FOR_POSITION(AANoFree) +CREATE_ALL_ABSTRACT_ATTRIBUTE_FOR_POSITION(AAUnderlyingObjects) CREATE_FUNCTION_ONLY_ABSTRACT_ATTRIBUTE_FOR_POSITION(AAHeapToStack) CREATE_FUNCTION_ONLY_ABSTRACT_ATTRIBUTE_FOR_POSITION(AAReachability) diff --git a/llvm/test/Transforms/Attributor/ArgumentPromotion/chained.ll b/llvm/test/Transforms/Attributor/ArgumentPromotion/chained.ll index 316060e..55c3f6b 100644 --- a/llvm/test/Transforms/Attributor/ArgumentPromotion/chained.ll +++ b/llvm/test/Transforms/Attributor/ArgumentPromotion/chained.ll @@ -1,5 +1,5 @@ ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --function-signature --check-attributes --check-globals -; RUN: opt -aa-pipeline=basic-aa -passes=attributor -attributor-manifest-internal -attributor-max-iterations-verify -attributor-annotate-decl-cs -attributor-max-iterations=7 -S < %s | FileCheck %s --check-prefixes=CHECK,TUNIT +; RUN: opt -aa-pipeline=basic-aa -passes=attributor -attributor-manifest-internal -attributor-max-iterations-verify -attributor-annotate-decl-cs -attributor-max-iterations=9 -S < %s | FileCheck %s --check-prefixes=CHECK,TUNIT ; RUN: opt -aa-pipeline=basic-aa -passes=attributor-cgscc -attributor-manifest-internal -attributor-annotate-decl-cs -S < %s | FileCheck %s --check-prefixes=CHECK,CGSCC @G1 = constant i32 0 diff --git a/llvm/test/Transforms/Attributor/ArgumentPromotion/crash.ll b/llvm/test/Transforms/Attributor/ArgumentPromotion/crash.ll index 89f418f..2566fef 100644 --- a/llvm/test/Transforms/Attributor/ArgumentPromotion/crash.ll +++ b/llvm/test/Transforms/Attributor/ArgumentPromotion/crash.ll @@ -1,5 +1,5 @@ ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --function-signature --check-attributes --check-globals -; RUN: opt -aa-pipeline=basic-aa -passes=attributor -attributor-manifest-internal -attributor-max-iterations-verify -attributor-annotate-decl-cs -attributor-max-iterations=3 -S < %s | FileCheck %s --check-prefixes=CHECK,TUNIT +; RUN: opt -aa-pipeline=basic-aa -passes=attributor -attributor-manifest-internal -attributor-max-iterations-verify -attributor-annotate-decl-cs -attributor-max-iterations=4 -S < %s | FileCheck %s --check-prefixes=CHECK,TUNIT ; RUN: opt -aa-pipeline=basic-aa -passes=attributor-cgscc -attributor-manifest-internal -attributor-annotate-decl-cs -S < %s | FileCheck %s --check-prefixes=CHECK,CGSCC %S = type { ptr } diff --git a/llvm/test/Transforms/Attributor/IPConstantProp/PR26044.ll b/llvm/test/Transforms/Attributor/IPConstantProp/PR26044.ll index d623d81..1dc375d 100644 --- a/llvm/test/Transforms/Attributor/IPConstantProp/PR26044.ll +++ b/llvm/test/Transforms/Attributor/IPConstantProp/PR26044.ll @@ -1,5 +1,5 @@ ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --function-signature --check-attributes --check-globals -; RUN: opt -aa-pipeline=basic-aa -passes=attributor -attributor-manifest-internal -attributor-max-iterations-verify -attributor-annotate-decl-cs -attributor-max-iterations=11 -S < %s | FileCheck %s --check-prefixes=CHECK,TUNIT +; RUN: opt -aa-pipeline=basic-aa -passes=attributor -attributor-manifest-internal -attributor-max-iterations-verify -attributor-annotate-decl-cs -attributor-max-iterations=12 -S < %s | FileCheck %s --check-prefixes=CHECK,TUNIT ; RUN: opt -aa-pipeline=basic-aa -passes=attributor-cgscc -attributor-manifest-internal -attributor-annotate-decl-cs -S < %s | FileCheck %s --check-prefixes=CHECK,CGSCC target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" target triple = "x86_64-unknown-linux-gnu" diff --git a/llvm/test/Transforms/Attributor/call-simplify-pointer-info.ll b/llvm/test/Transforms/Attributor/call-simplify-pointer-info.ll index 8e2a347..91fcc13 100644 --- a/llvm/test/Transforms/Attributor/call-simplify-pointer-info.ll +++ b/llvm/test/Transforms/Attributor/call-simplify-pointer-info.ll @@ -1,5 +1,5 @@ ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --function-signature --check-attributes --check-globals -; RUN: opt -aa-pipeline=basic-aa -passes=attributor -attributor-manifest-internal -attributor-max-iterations-verify -attributor-annotate-decl-cs -attributor-max-iterations=7 -S < %s | FileCheck %s --check-prefixes=TUNIT +; RUN: opt -aa-pipeline=basic-aa -passes=attributor -attributor-manifest-internal -attributor-max-iterations-verify -attributor-annotate-decl-cs -attributor-max-iterations=2 -S < %s | FileCheck %s --check-prefixes=TUNIT ; RUN: opt -aa-pipeline=basic-aa -passes=attributor-cgscc -attributor-manifest-internal -attributor-annotate-decl-cs -S < %s | FileCheck %s --check-prefixes=CGSCC ; diff --git a/llvm/test/Transforms/Attributor/depgraph.ll b/llvm/test/Transforms/Attributor/depgraph.ll index 12254de..fce4e24 100644 --- a/llvm/test/Transforms/Attributor/depgraph.ll +++ b/llvm/test/Transforms/Attributor/depgraph.ll @@ -57,6 +57,8 @@ define ptr @checkAndAdvance(ptr align 16 %0) { ; GRAPH-EMPTY: ; GRAPH-NEXT: [AAPotentialValues] for CtxI ' %2 = load i32, ptr %0, align 4' at position {flt: [@-1]} with state set-state(< { %2 = load i32, ptr %0, align 4[3], } >) ; GRAPH-EMPTY: +; GRAPH-NEXT: [AAUnderlyingObjects] for CtxI ' %2 = load i32, ptr %0, align 4' at position {arg: [@0]} with state UnderlyingObjects inter #1 objs, intra #1 objs +; GRAPH-EMPTY: ; GRAPH-NEXT: [AAPotentialValues] for CtxI ' %2 = load i32, ptr %0, align 4' at position {arg: [@0]} with state set-state(< {ptr %0[3], } >) ; GRAPH-EMPTY: ; GRAPH-NEXT: [AAPotentialValues] for CtxI <> at position {flt: [@-1]} with state set-state(< {i32 0[3], } >) @@ -264,6 +266,8 @@ define ptr @checkAndAdvance(ptr align 16 %0) { ; GRAPH-EMPTY: ; GRAPH-NEXT: [AANoFree] for CtxI ' %6 = call ptr @checkAndAdvance(ptr %5)' at position {cs_arg: [@0]} with state nofree ; GRAPH-EMPTY: +; GRAPH-NEXT: [AAUnderlyingObjects] for CtxI ' %5 = getelementptr inbounds i32, ptr %0, i64 4' at position {flt: [@-1]} with state UnderlyingObjects inter #1 objs, intra #1 objs +; GRAPH-EMPTY: ; GRAPH-NEXT: [AADereferenceable] for CtxI ' %5 = getelementptr inbounds i32, ptr %0, i64 4' at position {flt: [@-1]} with state unknown-dereferenceable ; GRAPH-NOT: update diff --git a/llvm/test/Transforms/Attributor/value-simplify-gpu.ll b/llvm/test/Transforms/Attributor/value-simplify-gpu.ll index 0dbc6d3..02700f2 100644 --- a/llvm/test/Transforms/Attributor/value-simplify-gpu.ll +++ b/llvm/test/Transforms/Attributor/value-simplify-gpu.ll @@ -1,5 +1,5 @@ ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --function-signature --check-attributes --check-globals -; RUN: opt -aa-pipeline=basic-aa -passes=attributor -attributor-manifest-internal -attributor-max-iterations-verify -attributor-annotate-decl-cs -attributor-max-iterations=6 -S < %s | FileCheck %s --check-prefixes=CHECK,TUNIT +; RUN: opt -aa-pipeline=basic-aa -passes=attributor -attributor-manifest-internal -attributor-max-iterations-verify -attributor-annotate-decl-cs -attributor-max-iterations=7 -S < %s | FileCheck %s --check-prefixes=CHECK,TUNIT ; RUN: opt -aa-pipeline=basic-aa -passes=attributor-cgscc -attributor-manifest-internal -attributor-annotate-decl-cs -S < %s | FileCheck %s --check-prefixes=CHECK,CGSCC target triple = "amdgcn-amd-amdhsa" diff --git a/llvm/test/Transforms/Attributor/value-simplify-pointer-info.ll b/llvm/test/Transforms/Attributor/value-simplify-pointer-info.ll index 76ebcc5..ace8a20 100644 --- a/llvm/test/Transforms/Attributor/value-simplify-pointer-info.ll +++ b/llvm/test/Transforms/Attributor/value-simplify-pointer-info.ll @@ -2097,45 +2097,25 @@ define i32 @single_read_of_static_global() { } define i8 @phi_store() { -; TUNIT: Function Attrs: nofree norecurse nosync nounwind willreturn -; TUNIT-LABEL: define {{[^@]+}}@phi_store -; TUNIT-SAME: () #[[ATTR3]] { -; TUNIT-NEXT: entry: -; TUNIT-NEXT: [[A:%.*]] = alloca i16, align 2 -; TUNIT-NEXT: [[B:%.*]] = bitcast i16* [[A]] to i8* -; TUNIT-NEXT: br label [[LOOP:%.*]] -; TUNIT: loop: -; TUNIT-NEXT: [[P:%.*]] = phi i8* [ [[B]], [[ENTRY:%.*]] ], [ [[G:%.*]], [[LOOP]] ] -; TUNIT-NEXT: [[I:%.*]] = phi i8 [ 0, [[ENTRY]] ], [ [[O:%.*]], [[LOOP]] ] -; TUNIT-NEXT: store i8 1, i8* [[P]], align 1 -; TUNIT-NEXT: [[G]] = getelementptr i8, i8* [[P]], i64 1 -; TUNIT-NEXT: [[O]] = add nsw i8 [[I]], 1 -; TUNIT-NEXT: [[C:%.*]] = icmp eq i8 [[O]], 2 -; TUNIT-NEXT: br i1 [[C]], label [[END:%.*]], label [[LOOP]] -; TUNIT: end: -; TUNIT-NEXT: [[S:%.*]] = getelementptr i8, i8* [[B]], i64 1 -; TUNIT-NEXT: [[L:%.*]] = load i8, i8* [[S]], align 1 -; TUNIT-NEXT: ret i8 [[L]] -; -; CGSCC: Function Attrs: nofree norecurse nosync nounwind willreturn -; CGSCC-LABEL: define {{[^@]+}}@phi_store -; CGSCC-SAME: () #[[ATTR5]] { -; CGSCC-NEXT: entry: -; CGSCC-NEXT: [[A:%.*]] = alloca i16, align 2 -; CGSCC-NEXT: [[B:%.*]] = bitcast i16* [[A]] to i8* -; CGSCC-NEXT: br label [[LOOP:%.*]] -; CGSCC: loop: -; CGSCC-NEXT: [[P:%.*]] = phi i8* [ [[B]], [[ENTRY:%.*]] ], [ [[G:%.*]], [[LOOP]] ] -; CGSCC-NEXT: [[I:%.*]] = phi i8 [ 0, [[ENTRY]] ], [ [[O:%.*]], [[LOOP]] ] -; CGSCC-NEXT: store i8 1, i8* [[P]], align 1 -; CGSCC-NEXT: [[G]] = getelementptr i8, i8* [[P]], i64 1 -; CGSCC-NEXT: [[O]] = add nsw i8 [[I]], 1 -; CGSCC-NEXT: [[C:%.*]] = icmp eq i8 [[O]], 2 -; CGSCC-NEXT: br i1 [[C]], label [[END:%.*]], label [[LOOP]] -; CGSCC: end: -; CGSCC-NEXT: [[S:%.*]] = getelementptr i8, i8* [[B]], i64 1 -; CGSCC-NEXT: [[L:%.*]] = load i8, i8* [[S]], align 1 -; CGSCC-NEXT: ret i8 [[L]] +; CHECK: Function Attrs: nofree norecurse nosync nounwind willreturn memory(none) +; CHECK-LABEL: define {{[^@]+}}@phi_store +; CHECK-SAME: () #[[ATTR4]] { +; CHECK-NEXT: entry: +; CHECK-NEXT: [[A:%.*]] = alloca i16, align 2 +; CHECK-NEXT: [[B:%.*]] = bitcast i16* [[A]] to i8* +; CHECK-NEXT: br label [[LOOP:%.*]] +; CHECK: loop: +; CHECK-NEXT: [[P:%.*]] = phi i8* [ [[B]], [[ENTRY:%.*]] ], [ [[G:%.*]], [[LOOP]] ] +; CHECK-NEXT: [[I:%.*]] = phi i8 [ 0, [[ENTRY]] ], [ [[O:%.*]], [[LOOP]] ] +; CHECK-NEXT: store i8 1, i8* [[P]], align 1 +; CHECK-NEXT: [[G]] = getelementptr i8, i8* [[P]], i64 1 +; CHECK-NEXT: [[O]] = add nsw i8 [[I]], 1 +; CHECK-NEXT: [[C:%.*]] = icmp eq i8 [[O]], 2 +; CHECK-NEXT: br i1 [[C]], label [[END:%.*]], label [[LOOP]] +; CHECK: end: +; CHECK-NEXT: [[S:%.*]] = getelementptr i8, i8* [[B]], i64 1 +; CHECK-NEXT: [[L:%.*]] = load i8, i8* [[S]], align 1 +; CHECK-NEXT: ret i8 [[L]] ; entry: %a = alloca i16