diff --git a/llvm/include/llvm/Transforms/IPO/Attributor.h b/llvm/include/llvm/Transforms/IPO/Attributor.h --- a/llvm/include/llvm/Transforms/IPO/Attributor.h +++ b/llvm/include/llvm/Transforms/IPO/Attributor.h @@ -5445,6 +5445,30 @@ static const char ID; }; +struct AAUnderlyingObjects : AbstractAttribute { + AAUnderlyingObjects(const IRPosition &IRP, Attributor &A) + : 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; +}; + raw_ostream &operator<<(raw_ostream &, const AAPointerInfo::Access &); /// Run options, used by the pass manager. diff --git a/llvm/lib/Transforms/IPO/AttributorAttributes.cpp b/llvm/lib/Transforms/IPO/AttributorAttributes.cpp --- a/llvm/lib/Transforms/IPO/AttributorAttributes.cpp +++ b/llvm/lib/Transforms/IPO/AttributorAttributes.cpp @@ -185,6 +185,7 @@ PIPE_OPERATOR(AAFunctionReachability) PIPE_OPERATOR(AAPointerInfo) PIPE_OPERATOR(AAAssumptionInfo) +PIPE_OPERATOR(AAUnderlyingObjects) #undef PIPE_OPERATOR @@ -11231,6 +11232,153 @@ void AttributorCallGraph::print() { llvm::WriteGraph(outs(), this); } +/// ------------------------ UnderlyingObjects --------------------------------- + +namespace llvm { +namespace AA { +namespace UnderlyingObjects { + +struct State; + +} // namespace UnderlyingObjects + +} // namespace AA + +/// A type to track all underlying objects for AAUnderlyingObjects. +struct AA::UnderlyingObjects::State : public AbstractState { + /// Return the best possible representable state. + static State getBestState(const State &) { return State(); } + + /// Return the worst possible representable state. + static State getWorstState(const State &) { + State R; + R.indicatePessimisticFixpoint(); + return R; + } + + State() = default; + State(State &&) = default; + + const State &getAssumed() const { return *this; } + + /// See AbstractState::isValidState(). + bool isValidState() const override { return BS.isValidState(); } + + /// See AbstractState::isAtFixpoint(). + bool isAtFixpoint() const override { return BS.isAtFixpoint(); } + + /// See AbstractState::indicateOptimisticFixpoint(). + ChangeStatus indicateOptimisticFixpoint() override { + BS.indicateOptimisticFixpoint(); + return ChangeStatus::UNCHANGED; + } + + /// See AbstractState::indicatePessimisticFixpoint(). + ChangeStatus indicatePessimisticFixpoint() override { + UnderlyingObjects.clear(); + BS.indicatePessimisticFixpoint(); + return ChangeStatus::CHANGED; + } + + using const_obj_iterator = SmallSetVector::const_iterator; + const_obj_iterator begin() const { return UnderlyingObjects.begin(); } + const_obj_iterator end() const { return UnderlyingObjects.end(); } + + /// Insert a new underlying object. + /// \returns true if the object was inserted into the set. + bool insert(Value *V) { return UnderlyingObjects.insert(V); } + +private: + /// Contains all assumed objects found yet. + SmallSetVector UnderlyingObjects; + + /// State to track fixpoint and validity. + BooleanState BS; +}; + +namespace { +struct AAUnderlyingObjectsImpl + : public StateWrapper { + using BaseTy = + StateWrapper; + AAUnderlyingObjectsImpl(const IRPosition &IRP, Attributor &A) : BaseTy(IRP) {} + + /// See AbstractAttribute::getAsStr(). + const std::string getAsStr() const override { + // TODO: Finish this. + return ""; + } + + /// See AbstractAttribute::trackStatistics() + void trackStatistics() const override {} + + /// See AbstractAttribute::updateImpl(...). + ChangeStatus updateImpl(Attributor &A) override { + auto &Ptr = getAssociatedValue(); + SmallSetVector Objects; + + bool UsedAssumedInformation; + if (!AA::getAssumedUnderlyingObjects(A, Ptr, Objects, *this, getCtxI(), + UsedAssumedInformation)) + return indicatePessimisticFixpoint(); + + bool Changed = false; + for (auto *Obj : Objects) { + if (isa(Obj) || isa(Obj)) { + Changed |= handleIndirect(A, *reinterpret_cast(Obj)); + continue; + } + + Changed |= insert(Obj); + } + + return Changed ? ChangeStatus::CHANGED : ChangeStatus::UNCHANGED; + } + +private: + bool handleIndirect(Attributor &A, Instruction &Inst) { + const auto &AA = A.getOrCreateAAFor( + IRPosition::value(Inst), this, DepClassTy::REQUIRED); + const auto &AAImpl = reinterpret_cast(AA); + bool Changed = false; + for (const auto &Itr : AAImpl.getState()) + Changed |= State::insert(Itr); + + return Changed; + } +}; + +struct AAUnderlyingObjectsFloat final : AAUnderlyingObjectsImpl { + AAUnderlyingObjectsFloat(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) {} +}; +} + const char AAReturnedValues::ID = 0; const char AANoUnwind::ID = 0; const char AANoSync::ID = 0; @@ -11260,6 +11408,7 @@ 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 +11529,8 @@ CREATE_ALL_ABSTRACT_ATTRIBUTE_FOR_POSITION(AAValueSimplify) CREATE_ALL_ABSTRACT_ATTRIBUTE_FOR_POSITION(AAIsDead) CREATE_ALL_ABSTRACT_ATTRIBUTE_FOR_POSITION(AANoFree) +// TODO: This should not be all positions. IRP_FUNCTION is invalid. +CREATE_ALL_ABSTRACT_ATTRIBUTE_FOR_POSITION(AAUnderlyingObjects) CREATE_FUNCTION_ONLY_ABSTRACT_ATTRIBUTE_FOR_POSITION(AAHeapToStack) CREATE_FUNCTION_ONLY_ABSTRACT_ATTRIBUTE_FOR_POSITION(AAReachability)