Index: llvm/include/llvm/Transforms/IPO/Attributor.h =================================================================== --- llvm/include/llvm/Transforms/IPO/Attributor.h +++ llvm/include/llvm/Transforms/IPO/Attributor.h @@ -1545,6 +1545,31 @@ static const char ID; }; +/// An abstract interface for value simplify abstract attribute. +struct AAValueSimplify : public StateWrapper, + public IRPosition { + AAValueSimplify(const IRPosition &IRP) : IRPosition(IRP) {} + + /// Return an IR position, see struct IRPosition. + /// + ///{ + IRPosition &getIRPosition() { return *this; } + const IRPosition &getIRPosition() const { return *this; } + ///} + + /// Return an assumed simplified value if a single candidate is found. If + /// there cannot be one, return a nullptr. If it is not clear yet, return the + /// Optional::NoneType. + virtual Optional getAssumedSimplifiedValue(Attributor &A) const; + + /// Create an abstract attribute view for the position \p IRP. + static AAValueSimplify &createForPosition(const IRPosition &IRP, + Attributor &A); + + /// Unique ID (due to the unique address) + static const char ID; +}; + } // end namespace llvm #endif // LLVM_TRANSFORMS_IPO_FUNCTIONATTRS_H Index: llvm/lib/Transforms/IPO/Attributor.cpp =================================================================== --- llvm/lib/Transforms/IPO/Attributor.cpp +++ llvm/lib/Transforms/IPO/Attributor.cpp @@ -2348,6 +2348,225 @@ /// NoReturn attribute deduction for a call sites. using AANoReturnCallSite = AANoReturnFunction; +/// ------------------ Value Simplify Attribute ---------------------------- +struct AAValueSimplifyImpl : AAValueSimplify { + AAValueSimplifyImpl(const IRPosition &IRP) : AAValueSimplify(IRP) {} + + /// See AbstractAttribute::getAsStr(). + const std::string getAsStr() const override { + return getAssumed() ? (getKnown() ? "simplified" : "maybe-simple") + : "not-simple"; + } + + /// See AbstractAttribute::trackStatistics() + void trackStatistics() const override {} + + /// See AAValueSimplify::getAssumedSimplifiedValue() + Optional getAssumedSimplifiedValue(Attributor &A) const override { + if (!getAssumed()) + return nullptr; + return SimplifiedAssociatedValue; + } + + /// Helper function for querying AAValueSimplify and updating candicate. + static bool checkAndUpdate(Attributor &A, const AbstractAttribute &QueryingAA, + Value &V, bool &ExistNone, + Optional &SimplifiedValue) { + auto &ValueSimpifyAA = + A.getAAFor(QueryingAA, IRPosition::value(V)); + + Optional Simplified = ValueSimpifyAA.getAssumedSimplifiedValue(A); + + if (!Simplified.hasValue()) { + ExistNone = true; + return true; + } + + if (SimplifiedValue.hasValue()) + return SimplifiedValue == Simplified; + + SimplifiedValue = Simplified; + return true; + } + + /// See AbstractAttribute::manifest(...). + ChangeStatus manifest(Attributor &A) override { + ChangeStatus Changed = ChangeStatus::UNCHANGED; + + // Bookkeeping. + assert(isValidState()); + // TODO: add stats + + if (!SimplifiedAssociatedValue.hasValue() || + !SimplifiedAssociatedValue.getValue()) + return Changed; + + if (auto *C = dyn_cast(SimplifiedAssociatedValue.getValue())) { + // We can replace the AssociatedValue with the constant. + Value &V = getAssociatedValue(); + if (isa(V)) { + Argument &Arg = cast(V); + if (!Arg.user_empty()) { + Arg.replaceAllUsesWith(C); + Changed = ChangeStatus::CHANGED; + } + } + } + + return Changed | AAValueSimplify::manifest(A); + } + +protected: + Optional SimplifiedAssociatedValue; +}; + +struct AAValueSimplifyArgument final : AAValueSimplifyImpl { + AAValueSimplifyArgument(const IRPosition &IRP) : AAValueSimplifyImpl(IRP) {} + + /// See AbstractAttribute::initialize(...). + void initialize(Attributor &A) override { + if (!getAssociatedFunction() || + !getAssociatedFunction()->hasExactDefinition()) + indicatePessimisticFixpoint(); + } + + /// See AbstractAttribute::updateImpl(...). + ChangeStatus updateImpl(Attributor &A) override { + bool ExistNone = false; + bool HasValueBefore = SimplifiedAssociatedValue.hasValue(); + + auto PredForCallSite = [&](CallSite CS) { + return checkAndUpdate(A, *this, *CS.getArgOperand(getArgNo()), ExistNone, + SimplifiedAssociatedValue); + }; + + if (!A.checkForAllCallSites(PredForCallSite, *this, true)) + return indicatePessimisticFixpoint(); + + // If everyting is clear, reach optimistic fixpoint. + if (!ExistNone) + return indicateOptimisticFixpoint(); + + // If a candicate was found in this update, return CHANGED. + if (!HasValueBefore) + return ChangeStatus::CHANGED; + + return ChangeStatus::UNCHANGED; + } +}; + +struct AAValueSimplifyReturned : AAValueSimplifyImpl { + AAValueSimplifyReturned(const IRPosition &IRP) : AAValueSimplifyImpl(IRP) {} + + /// See AbstractAttribute::initialize(...). + void initialize(Attributor &A) override { + if (!getAssociatedFunction()) + indicatePessimisticFixpoint(); + } + + /// See AbstractAttribute::updateImpl(...). + ChangeStatus updateImpl(Attributor &A) override { + bool ExistNone = false; + bool HasValueBefore = SimplifiedAssociatedValue.hasValue(); + + auto PredForReturned = [&](Value &V) { + return checkAndUpdate(A, *this, V, ExistNone, SimplifiedAssociatedValue); + }; + + if (!A.checkForAllReturnedValues(PredForReturned, *this)) + return indicatePessimisticFixpoint(); + + // If everyting is clear, reach optimistic fixpoint. + if (!ExistNone) + return indicateOptimisticFixpoint(); + + // If a candicate was found in this update, return CHANGED. + if (!HasValueBefore) + return ChangeStatus::CHANGED; + + return ChangeStatus::UNCHANGED; + } +}; + +struct AAValueSimplifyFloating : AAValueSimplifyImpl { + AAValueSimplifyFloating(const IRPosition &IRP) : AAValueSimplifyImpl(IRP) {} + + /// See AbstractAttribute::manifest(...). + /// TODO: Consider wether there is manifest for floating value + ChangeStatus manifest(Attributor &A) override { + return ChangeStatus ::UNCHANGED; + } + /// See AbstractAttribute::initialize(...). + void initialize(Attributor &A) override { + Value &V = getAnchorValue(); + if (isa(V)) { + // TODO: add other stuffs + SimplifiedAssociatedValue = &V; + indicateOptimisticFixpoint(); + } + } + + /// See AbstractAttribute::updateImpl(...). + ChangeStatus updateImpl(Attributor &A) override { + bool ExistNone = false; + bool HasValueBefore = SimplifiedAssociatedValue.hasValue(); + + auto VisitValueCB = [&](Value &V, BooleanState, bool Stripped) -> bool { + auto &AA = A.getAAFor(*this, IRPosition::value(V)); + if (!Stripped && this == &AA) { + // TODO: Look the instruction and check recursively. + indicatePessimisticFixpoint(); + return false; + } + return checkAndUpdate(A, *this, V, ExistNone, SimplifiedAssociatedValue); + }; + + if (!genericValueTraversal( + A, getIRPosition(), *this, static_cast(*this), + VisitValueCB)) + return indicatePessimisticFixpoint(); + + // If everyting is clear, reach optimistic fixpoint. + if (!ExistNone) + return indicateOptimisticFixpoint(); + + // If a candicate was found in this update, return CHANGED. + if (!HasValueBefore) + return ChangeStatus::CHANGED; + + return ChangeStatus::UNCHANGED; + } +}; + +struct AAValueSimplifyFunction : AAValueSimplifyImpl { + AAValueSimplifyFunction(const IRPosition &IRP) : AAValueSimplifyImpl(IRP) {} + + /// See AbstractAttribute::initialize(...). + void initialize(Attributor &A) override { + SimplifiedAssociatedValue = &getAnchorValue(); + indicateOptimisticFixpoint(); + } + /// See AbstractAttribute::initialize(...). + ChangeStatus updateImpl(Attributor &A) override { + llvm_unreachable( + "AAValueSimplify(Function|CallSite)::updateImpl will not be called"); + } +}; + +struct AAValueSimplifyCallSite : AAValueSimplifyFunction { + AAValueSimplifyCallSite(const IRPosition &IRP) + : AAValueSimplifyFunction(IRP) {} +}; + +struct AAValueSimplifyCallSiteReturned : AAValueSimplifyReturned { + AAValueSimplifyCallSiteReturned(const IRPosition &IRP) + : AAValueSimplifyReturned(IRP) {} +}; +struct AAValueSimplifyCallSiteArgument : AAValueSimplifyFloating { + AAValueSimplifyCallSiteArgument(const IRPosition &IRP) + : AAValueSimplifyFloating(IRP) {} +}; + /// ---------------------------------------------------------------------------- /// Attributor /// ---------------------------------------------------------------------------- @@ -2811,8 +3030,9 @@ // though it is an argument attribute. checkAndRegisterAA(FPos, *this, Whitelist); + IRPosition RetPos = IRPosition::returned(F); + checkAndRegisterAA(RetPos, *this, Whitelist); if (ReturnType->isPointerTy()) { - IRPosition RetPos = IRPosition::returned(F); // Every function with pointer return type might be marked align. checkAndRegisterAA(RetPos, *this, Whitelist); @@ -2830,8 +3050,10 @@ } for (Argument &Arg : F.args()) { + IRPosition ArgPos = IRPosition::argument(Arg); + checkAndRegisterAA(ArgPos, *this, Whitelist); + if (Arg.getType()->isPointerTy()) { - IRPosition ArgPos = IRPosition::argument(Arg); // Every argument with pointer type might be marked nonnull. checkAndRegisterAA(ArgPos, *this, Whitelist); @@ -2895,9 +3117,13 @@ CallSite CS(&I); if (CS && CS.getCalledFunction()) { for (int i = 0, e = CS.getCalledFunction()->arg_size(); i < e; i++) { + + IRPosition CSArgPos = IRPosition::callsite_argument(CS, i); + checkAndRegisterAA(CSArgPos, *this, + Whitelist); + if (!CS.getArgument(i)->getType()->isPointerTy()) continue; - IRPosition CSArgPos = IRPosition::callsite_argument(CS, i); // Call site argument attribute "non-null". checkAndRegisterAA(CSArgPos, *this, @@ -3064,6 +3290,7 @@ const char AAIsDead::ID = 0; const char AADereferenceable::ID = 0; const char AAAlign::ID = 0; +const char AAValueSimplify::ID = 0; // Macro magic to create the static generator function for attributes that // follow the naming scheme. @@ -3111,6 +3338,23 @@ return *AA; \ } +#define CREATE_ALL_ABSTRACT_ATTRIBUTE_FOR_POSITION(CLASS) \ + CLASS &CLASS::createForPosition(const IRPosition &IRP, Attributor &A) { \ + CLASS *AA = nullptr; \ + switch (IRP.getPositionKind()) { \ + SWITCH_PK_INV(CLASS, IRP_INVALID, "invalid") \ + SWITCH_PK_CREATE(CLASS, IRP, IRP_FUNCTION, Function) \ + SWITCH_PK_CREATE(CLASS, IRP, IRP_CALL_SITE, CallSite) \ + SWITCH_PK_CREATE(CLASS, IRP, IRP_FLOAT, Floating) \ + SWITCH_PK_CREATE(CLASS, IRP, IRP_ARGUMENT, Argument) \ + SWITCH_PK_CREATE(CLASS, IRP, IRP_RETURNED, Returned) \ + SWITCH_PK_CREATE(CLASS, IRP, IRP_CALL_SITE_RETURNED, CallSiteReturned) \ + SWITCH_PK_CREATE(CLASS, IRP, IRP_CALL_SITE_ARGUMENT, CallSiteArgument) \ + } \ + AA->initialize(A); \ + return *AA; \ + } + CREATE_FUNCTION_ABSTRACT_ATTRIBUTE_FOR_POSITION(AANoUnwind) CREATE_FUNCTION_ABSTRACT_ATTRIBUTE_FOR_POSITION(AANoSync) CREATE_FUNCTION_ABSTRACT_ATTRIBUTE_FOR_POSITION(AANoFree) @@ -3125,6 +3369,8 @@ CREATE_VALUE_ABSTRACT_ATTRIBUTE_FOR_POSITION(AADereferenceable) CREATE_VALUE_ABSTRACT_ATTRIBUTE_FOR_POSITION(AAAlign) +CREATE_ALL_ABSTRACT_ATTRIBUTE_FOR_POSITION(AAValueSimplify) + #undef CREATE_FUNCTION_ABSTRACT_ATTRIBUTE_FOR_POSITION #undef CREATE_VALUE_ABSTRACT_ATTRIBUTE_FOR_POSITION #undef SWITCH_PK_CREATE Index: llvm/test/Transforms/FunctionAttrs/align.ll =================================================================== --- llvm/test/Transforms/FunctionAttrs/align.ll +++ llvm/test/Transforms/FunctionAttrs/align.ll @@ -105,7 +105,7 @@ ;