@@ -191,6 +191,7 @@ PIPE_OPERATOR(AAInterFnReachability)
191191PIPE_OPERATOR (AAPointerInfo)
192192PIPE_OPERATOR (AAAssumptionInfo)
193193PIPE_OPERATOR (AAUnderlyingObjects)
194+ PIPE_OPERATOR (AAInvariantLoadPointer)
194195PIPE_OPERATOR (AAAddressSpace)
195196PIPE_OPERATOR (AAAllocationInfo)
196197PIPE_OPERATOR (AAIndirectCallInfo)
@@ -12534,6 +12535,248 @@ struct AAIndirectCallInfoCallSite : public AAIndirectCallInfo {
1253412535};
1253512536} // namespace
1253612537
12538+ // / --------------------- Invariant Load Pointer -------------------------------
12539+ namespace {
12540+
12541+ struct AAInvariantLoadPointerImpl
12542+ : public StateWrapper<BitIntegerState<uint8_t , 7 >, AAInvariantLoadPointer,
12543+ uint8_t > {
12544+ // load invariance is implied by, but not equivalent to IS_NOALIAS |
12545+ // IS_READONLY, as load invariance is also implied by all underlying objects
12546+ // being load invariant.
12547+ //
12548+ // IS_INVARIANT is set to indicate that the contents of the pointer are
12549+ // *known* to be invariant.
12550+ enum {
12551+ IS_INVARIANT = 1 << 0 ,
12552+ IS_NOALIAS = 1 << 1 ,
12553+ IS_READONLY = 1 << 2 ,
12554+ };
12555+ static_assert (getBestState() == (IS_INVARIANT | IS_NOALIAS | IS_READONLY),
12556+ " Unexpected best state!" );
12557+
12558+ using Base = StateWrapper<BitIntegerState<uint8_t , 7 >, AAInvariantLoadPointer,
12559+ uint8_t >;
12560+
12561+ // the BitIntegerState is optimistic about noalias and readonly, but
12562+ // pessimistic about invariance
12563+ AAInvariantLoadPointerImpl (const IRPosition &IRP, Attributor &A)
12564+ : Base(IRP, IS_NOALIAS | IS_READONLY) {}
12565+
12566+ void initialize (Attributor &A) final {
12567+ // conservatively assume that the pointer's contents are not invariant,
12568+ // until proven otherwise.
12569+ removeAssumedBits (IS_INVARIANT);
12570+ }
12571+
12572+ bool isKnownInvariant () const final {
12573+ return isKnown (IS_INVARIANT) || isKnown (IS_NOALIAS | IS_READONLY);
12574+ }
12575+
12576+ bool isAssumedInvariant () const final {
12577+ return isAssumed (IS_INVARIANT) || isAssumed (IS_NOALIAS | IS_READONLY);
12578+ }
12579+
12580+ ChangeStatus updateImpl (Attributor &A) override {
12581+ if (isKnownInvariant ())
12582+ return ChangeStatus::UNCHANGED;
12583+
12584+ ChangeStatus Changed = ChangeStatus::UNCHANGED;
12585+
12586+ Changed |= updateNoAlias (A);
12587+ Changed |= updateReadOnly (A);
12588+
12589+ bool UsedAssumedInformation = false ;
12590+ const auto IsInvariantLoadIfPointer = [&](const Value &V) {
12591+ if (!V.getType ()->isPointerTy ())
12592+ return true ;
12593+ const auto *IsInvariantLoadPointer =
12594+ A.getOrCreateAAFor <AAInvariantLoadPointer>(IRPosition::value (V), this ,
12595+ DepClassTy::REQUIRED);
12596+ if (IsInvariantLoadPointer->isKnownInvariant ())
12597+ return true ;
12598+ if (!IsInvariantLoadPointer->isAssumedInvariant ())
12599+ return false ;
12600+
12601+ UsedAssumedInformation = true ;
12602+ return true ;
12603+ };
12604+
12605+ const auto *AUO = A.getOrCreateAAFor <AAUnderlyingObjects>(
12606+ getIRPosition (), this , DepClassTy::REQUIRED);
12607+
12608+ if (!AUO->forallUnderlyingObjects (IsInvariantLoadIfPointer)) {
12609+ removeAssumedBits (IS_INVARIANT);
12610+ return ChangeStatus::CHANGED;
12611+ }
12612+
12613+ if (!UsedAssumedInformation) {
12614+ // pointer is known (not assumed) to be invariant
12615+ addKnownBits (IS_INVARIANT);
12616+ return ChangeStatus::CHANGED;
12617+ }
12618+
12619+ return Changed;
12620+ }
12621+
12622+ ChangeStatus manifest (Attributor &A) override {
12623+ if (!isKnownInvariant ())
12624+ return ChangeStatus::UNCHANGED;
12625+
12626+ ChangeStatus Changed = ChangeStatus::UNCHANGED;
12627+ Value *Ptr = &getAssociatedValue ();
12628+ const auto TagInvariantLoads = [&](const Use &U, bool &) {
12629+ if (U.get () != Ptr)
12630+ return true ;
12631+ auto *I = dyn_cast<Instruction>(U.getUser ());
12632+ if (!I)
12633+ return true ;
12634+
12635+ // Ensure that we are only changing uses from the corresponding callgraph
12636+ // SSC in the case that the AA isn't run on the entire module
12637+ if (!A.isRunOn (I->getFunction ()))
12638+ return true ;
12639+
12640+ if (I->hasMetadata (LLVMContext::MD_invariant_load))
12641+ return true ;
12642+
12643+ if (auto *LI = dyn_cast<LoadInst>(I)) {
12644+ if (LI->isVolatile () || LI->isAtomic ())
12645+ return true ;
12646+
12647+ LI->setMetadata (LLVMContext::MD_invariant_load,
12648+ MDNode::get (LI->getContext (), {}));
12649+ Changed = ChangeStatus::CHANGED;
12650+ }
12651+ return true ;
12652+ };
12653+
12654+ (void )A.checkForAllUses (TagInvariantLoads, *this , *Ptr);
12655+ return Changed;
12656+ }
12657+
12658+ // / See AbstractAttribute::getAsStr().
12659+ const std::string getAsStr (Attributor *) const override {
12660+ std::string Str;
12661+ raw_string_ostream OS (Str);
12662+ OS << " load invariant pointer: " << isKnown () << ' \n ' ;
12663+ return Str;
12664+ }
12665+
12666+ // / See AbstractAttribute::trackStatistics().
12667+ void trackStatistics () const override {}
12668+
12669+ protected:
12670+ ChangeStatus updateNoAlias (Attributor &A) {
12671+ if (isKnown (IS_NOALIAS) || !isAssumed (IS_NOALIAS))
12672+ return ChangeStatus::UNCHANGED;
12673+
12674+ const auto *ANoAlias = A.getOrCreateAAFor <AANoAlias>(getIRPosition (), this ,
12675+ DepClassTy::REQUIRED);
12676+ if (!ANoAlias)
12677+ return tryInferNoAlias (A);
12678+
12679+ if (!ANoAlias->isAssumedNoAlias ()) {
12680+ removeAssumedBits (IS_NOALIAS);
12681+ return ChangeStatus::CHANGED;
12682+ }
12683+ if (ANoAlias->isKnownNoAlias ())
12684+ addKnownBits (IS_NOALIAS);
12685+
12686+ return ChangeStatus::UNCHANGED;
12687+ }
12688+
12689+ // / Fallback method if updateNoAlias fails to infer noalias information from
12690+ // / AANoAlias.
12691+ virtual ChangeStatus tryInferNoAlias (Attributor &A) {
12692+ return ChangeStatus::UNCHANGED;
12693+ }
12694+
12695+ ChangeStatus updateReadOnly (Attributor &A) {
12696+ if (isKnown (IS_READONLY) || !isAssumed (IS_READONLY))
12697+ return ChangeStatus::UNCHANGED;
12698+
12699+ // AAMemoryBehavior may crash if value is global
12700+ if (!getAssociatedFunction ())
12701+ return tryInferReadOnly (A);
12702+
12703+ const auto *AMemoryBehavior = A.getOrCreateAAFor <AAMemoryBehavior>(
12704+ getIRPosition (), this , DepClassTy::REQUIRED);
12705+ if (!AMemoryBehavior)
12706+ return tryInferReadOnly (A);
12707+
12708+ if (!AMemoryBehavior->isAssumedReadOnly ()) {
12709+ removeAssumedBits (IS_READONLY);
12710+ return ChangeStatus::CHANGED;
12711+ }
12712+ if (AMemoryBehavior->isKnownReadOnly ())
12713+ addKnownBits (IS_READONLY);
12714+
12715+ return ChangeStatus::UNCHANGED;
12716+ }
12717+
12718+ // / Fallback method if updateReadOnly fails to infer readonly information from
12719+ // / AAMemoryBehavior.
12720+ virtual ChangeStatus tryInferReadOnly (Attributor &A) {
12721+ return ChangeStatus::UNCHANGED;
12722+ }
12723+ };
12724+
12725+ struct AAInvariantLoadPointerFloating final : AAInvariantLoadPointerImpl {
12726+ AAInvariantLoadPointerFloating (const IRPosition &IRP, Attributor &A)
12727+ : AAInvariantLoadPointerImpl(IRP, A) {}
12728+ };
12729+
12730+ struct AAInvariantLoadPointerReturned final : AAInvariantLoadPointerImpl {
12731+ AAInvariantLoadPointerReturned (const IRPosition &IRP, Attributor &A)
12732+ : AAInvariantLoadPointerImpl(IRP, A) {}
12733+ };
12734+
12735+ struct AAInvariantLoadPointerCallSiteReturned final
12736+ : AAInvariantLoadPointerImpl {
12737+ AAInvariantLoadPointerCallSiteReturned (const IRPosition &IRP, Attributor &A)
12738+ : AAInvariantLoadPointerImpl(IRP, A) {}
12739+ };
12740+
12741+ struct AAInvariantLoadPointerArgument final : AAInvariantLoadPointerImpl {
12742+ AAInvariantLoadPointerArgument (const IRPosition &IRP, Attributor &A)
12743+ : AAInvariantLoadPointerImpl(IRP, A) {}
12744+
12745+ protected:
12746+ ChangeStatus tryInferNoAlias (Attributor &A) override {
12747+ const auto *Arg = getAssociatedArgument ();
12748+ if (Arg->hasNoAliasAttr ()) {
12749+ addKnownBits (IS_NOALIAS);
12750+ return ChangeStatus::UNCHANGED;
12751+ }
12752+
12753+ // noalias information is not provided, and cannot be inferred from
12754+ // AANoAlias
12755+ removeAssumedBits (IS_NOALIAS);
12756+ return ChangeStatus::CHANGED;
12757+ }
12758+
12759+ ChangeStatus tryInferReadOnly (Attributor &A) override {
12760+ const auto *Arg = getAssociatedArgument ();
12761+ if (Arg->onlyReadsMemory ()) {
12762+ addKnownBits (IS_READONLY);
12763+ return ChangeStatus::UNCHANGED;
12764+ }
12765+
12766+ // readonly information is not provided, and cannot be inferred from
12767+ // AAMemoryBehavior
12768+ removeAssumedBits (IS_READONLY);
12769+ return ChangeStatus::CHANGED;
12770+ }
12771+ };
12772+
12773+ struct AAInvariantLoadPointerCallSiteArgument final
12774+ : AAInvariantLoadPointerImpl {
12775+ AAInvariantLoadPointerCallSiteArgument (const IRPosition &IRP, Attributor &A)
12776+ : AAInvariantLoadPointerImpl(IRP, A) {}
12777+ };
12778+ } // namespace
12779+
1253712780// / ------------------------ Address Space ------------------------------------
1253812781namespace {
1253912782
@@ -13031,6 +13274,7 @@ const char AAInterFnReachability::ID = 0;
1303113274const char AAPointerInfo::ID = 0 ;
1303213275const char AAAssumptionInfo::ID = 0 ;
1303313276const char AAUnderlyingObjects::ID = 0 ;
13277+ const char AAInvariantLoadPointer::ID = 0 ;
1303413278const char AAAddressSpace::ID = 0 ;
1303513279const char AAAllocationInfo::ID = 0 ;
1303613280const char AAIndirectCallInfo::ID = 0 ;
@@ -13165,6 +13409,7 @@ CREATE_VALUE_ABSTRACT_ATTRIBUTE_FOR_POSITION(AAPotentialValues)
1316513409CREATE_VALUE_ABSTRACT_ATTRIBUTE_FOR_POSITION (AANoUndef)
1316613410CREATE_VALUE_ABSTRACT_ATTRIBUTE_FOR_POSITION (AANoFPClass)
1316713411CREATE_VALUE_ABSTRACT_ATTRIBUTE_FOR_POSITION (AAPointerInfo)
13412+ CREATE_VALUE_ABSTRACT_ATTRIBUTE_FOR_POSITION (AAInvariantLoadPointer)
1316813413CREATE_VALUE_ABSTRACT_ATTRIBUTE_FOR_POSITION (AAAddressSpace)
1316913414CREATE_VALUE_ABSTRACT_ATTRIBUTE_FOR_POSITION (AAAllocationInfo)
1317013415
0 commit comments