for (unsigned u = 0, e = PHI->getNumIncomingValues(); u < e; u++) {
const BasicBlock *IncomingBB = PHI->getIncomingBlock(u);
if (LivenessAA->isAssumedDead(IncomingBB->getTerminator())) {
- AnyDead =true;
+ AnyDead = true;
continue;
}
Worklist.push_back(PHI->getIncomingValue(u));
}
};
+/// ------------------ 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<Value *> getAssumedSimplifiedValue(Attributor &A) const override {
+ if (!getAssumed())
+ return const_cast<Value *>(&getAssociatedValue());
+ return SimplifiedAssociatedValue;
+ }
+ void initialize(Attributor &A) override {}
+
+ /// Helper function for querying AAValueSimplify and updating candicate.
+ /// \param QueryingValue Value trying to unify with SimplifiedValue
+ /// \param AccumulatedSimplifiedValue Current simplification result.
+ static bool checkAndUpdate(Attributor &A, const AbstractAttribute &QueryingAA,
+ Value &QueryingValue,
+ Optional<Value *> &AccumulatedSimplifiedValue) {
+ // FIXME: Add a typecast support.
+
+ auto &ValueSimpifyAA = A.getAAFor<AAValueSimplify>(
+ QueryingAA, IRPosition::value(QueryingValue));
+
+ Optional<Value *> QueryingValueSimplified =
+ ValueSimpifyAA.getAssumedSimplifiedValue(A);
+
+ if (!QueryingValueSimplified.hasValue())
+ return true;
+
+ if (!QueryingValueSimplified.getValue())
+ return false;
+
+ Value &QueryingValueSimplifiedUnwrapped =
+ *QueryingValueSimplified.getValue();
+
+ if (isa<UndefValue>(QueryingValueSimplifiedUnwrapped))
+ return true;
+
+ if (AccumulatedSimplifiedValue.hasValue())
+ return AccumulatedSimplifiedValue == QueryingValueSimplified;
+
+ LLVM_DEBUG(dbgs() << "[Attributor][ValueSimplify] " << QueryingValue
+ << " is assumed to be "
+ << QueryingValueSimplifiedUnwrapped << "\n");
+
+ AccumulatedSimplifiedValue = QueryingValueSimplified;
+ return true;
+ }
+
+ /// See AbstractAttribute::manifest(...).
+ ChangeStatus manifest(Attributor &A) override {
+ ChangeStatus Changed = ChangeStatus::UNCHANGED;
+
+ if (!SimplifiedAssociatedValue.hasValue() ||
+ !SimplifiedAssociatedValue.getValue())
+ return Changed;
+
+ if (auto *C = dyn_cast<Constant>(SimplifiedAssociatedValue.getValue())) {
+ // We can replace the AssociatedValue with the constant.
+ Value &V = getAssociatedValue();
+ if (!V.user_empty() && &V != C && V.getType() == C->getType()) {
+ LLVM_DEBUG(dbgs() << "[Attributor][ValueSimplify] " << V << " -> " << *C
+ << "\n");
+ V.replaceAllUsesWith(C);
+ Changed = ChangeStatus::CHANGED;
+ }
+ }
+
+ return Changed | AAValueSimplify::manifest(A);
+ }
+
+protected:
+ // An assumed simplified value. Initially, it is set to Optional::None, which
+ // means that the value is not clear under current assumption. If in the
+ // pessimistic state, getAssumedSimplifiedValue doesn't return this value but
+ // returns orignal associated value.
+ Optional<Value *> SimplifiedAssociatedValue;
+};
+
+struct AAValueSimplifyArgument final : AAValueSimplifyImpl {
+ AAValueSimplifyArgument(const IRPosition &IRP) : AAValueSimplifyImpl(IRP) {}
+
+ /// See AbstractAttribute::updateImpl(...).
+ ChangeStatus updateImpl(Attributor &A) override {
+ bool HasValueBefore = SimplifiedAssociatedValue.hasValue();
+
+ auto PredForCallSite = [&](CallSite CS) {
+ return checkAndUpdate(A, *this, *CS.getArgOperand(getArgNo()),
+ SimplifiedAssociatedValue);
+ };
+
+ if (!A.checkForAllCallSites(PredForCallSite, *this, true))
+ return indicatePessimisticFixpoint();
+
+ // If a candicate was found in this update, return CHANGED.
+ return HasValueBefore == SimplifiedAssociatedValue.hasValue()
+ ? ChangeStatus::UNCHANGED
+ : ChangeStatus ::CHANGED;
+ }
+
+ /// See AbstractAttribute::trackStatistics()
+ void trackStatistics() const override {
+ STATS_DECLTRACK_ARG_ATTR(value_simplify)
+ }
+};
+
+struct AAValueSimplifyReturned : AAValueSimplifyImpl {
+ AAValueSimplifyReturned(const IRPosition &IRP) : AAValueSimplifyImpl(IRP) {}
+
+ /// See AbstractAttribute::updateImpl(...).
+ ChangeStatus updateImpl(Attributor &A) override {
+ bool HasValueBefore = SimplifiedAssociatedValue.hasValue();
+
+ auto PredForReturned = [&](Value &V) {
+ return checkAndUpdate(A, *this, V, SimplifiedAssociatedValue);
+ };
+
+ if (!A.checkForAllReturnedValues(PredForReturned, *this))
+ return indicatePessimisticFixpoint();
+
+ // If a candicate was found in this update, return CHANGED.
+ return HasValueBefore == SimplifiedAssociatedValue.hasValue()
+ ? ChangeStatus::UNCHANGED
+ : ChangeStatus ::CHANGED;
+ }
+ /// See AbstractAttribute::trackStatistics()
+ void trackStatistics() const override {
+ STATS_DECLTRACK_FNRET_ATTR(value_simplify)
+ }
+};
+
+struct AAValueSimplifyFloating : AAValueSimplifyImpl {
+ AAValueSimplifyFloating(const IRPosition &IRP) : AAValueSimplifyImpl(IRP) {}
+
+ /// See AbstractAttribute::initialize(...).
+ void initialize(Attributor &A) override {
+ Value &V = getAnchorValue();
+
+ // TODO: add other stuffs
+ if (isa<Constant>(V) || isa<UndefValue>(V))
+ indicatePessimisticFixpoint();
+ }
+
+ /// See AbstractAttribute::updateImpl(...).
+ ChangeStatus updateImpl(Attributor &A) override {
+ bool HasValueBefore = SimplifiedAssociatedValue.hasValue();
+
+ auto VisitValueCB = [&](Value &V, BooleanState, bool Stripped) -> bool {
+ auto &AA = A.getAAFor<AAValueSimplify>(*this, IRPosition::value(V));
+ if (!Stripped && this == &AA) {
+ // TODO: Look the instruction and check recursively.
+ LLVM_DEBUG(
+ dbgs() << "[Attributor][ValueSimplify] Can't be stripped more : "
+ << V << "\n");
+ indicatePessimisticFixpoint();
+ return false;
+ }
+ return checkAndUpdate(A, *this, V, SimplifiedAssociatedValue);
+ };
+
+ if (!genericValueTraversal<AAValueSimplify, BooleanState>(
+ A, getIRPosition(), *this, static_cast<BooleanState &>(*this),
+ VisitValueCB))
+ return indicatePessimisticFixpoint();
+
+ // If a candicate was found in this update, return CHANGED.
+
+ return HasValueBefore == SimplifiedAssociatedValue.hasValue()
+ ? ChangeStatus::UNCHANGED
+ : ChangeStatus ::CHANGED;
+ }
+
+ /// See AbstractAttribute::trackStatistics()
+ void trackStatistics() const override {
+ STATS_DECLTRACK_FLOATING_ATTR(value_simplify)
+ }
+};
+
+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");
+ }
+ /// See AbstractAttribute::trackStatistics()
+ void trackStatistics() const override {
+ STATS_DECLTRACK_FN_ATTR(value_simplify)
+ }
+};
+
+struct AAValueSimplifyCallSite : AAValueSimplifyFunction {
+ AAValueSimplifyCallSite(const IRPosition &IRP)
+ : AAValueSimplifyFunction(IRP) {}
+ /// See AbstractAttribute::trackStatistics()
+ void trackStatistics() const override {
+ STATS_DECLTRACK_CS_ATTR(value_simplify)
+ }
+};
+
+struct AAValueSimplifyCallSiteReturned : AAValueSimplifyReturned {
+ AAValueSimplifyCallSiteReturned(const IRPosition &IRP)
+ : AAValueSimplifyReturned(IRP) {}
+
+ void trackStatistics() const override {
+ STATS_DECLTRACK_CSRET_ATTR(value_simplify)
+ }
+};
+struct AAValueSimplifyCallSiteArgument : AAValueSimplifyFloating {
+ AAValueSimplifyCallSiteArgument(const IRPosition &IRP)
+ : AAValueSimplifyFloating(IRP) {}
+
+ void trackStatistics() const override {
+ STATS_DECLTRACK_CSARG_ATTR(value_simplify)
+ }
+};
+
/// ----------------------------------------------------------------------------
/// Attributor
/// ----------------------------------------------------------------------------
// though it is an argument attribute.
getOrCreateAAFor<AAReturnedValues>(FPos);
+ IRPosition RetPos = IRPosition::returned(F);
+
+ // Every function might be simplified.
+ getOrCreateAAFor<AAValueSimplify>(RetPos);
+
if (ReturnType->isPointerTy()) {
- IRPosition RetPos = IRPosition::returned(F);
// Every function with pointer return type might be marked align.
getOrCreateAAFor<AAAlign>(RetPos);
}
for (Argument &Arg : F.args()) {
+ IRPosition ArgPos = IRPosition::argument(Arg);
+
+ // Every argument might be simplified.
+ getOrCreateAAFor<AAValueSimplify>(ArgPos);
+
if (Arg.getType()->isPointerTy()) {
- IRPosition ArgPos = IRPosition::argument(Arg);
// Every argument with pointer type might be marked nonnull.
getOrCreateAAFor<AANonNull>(ArgPos);
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);
+
+ // Call site argument might be simplified.
+ getOrCreateAAFor<AAValueSimplify>(CSArgPos);
+
if (!CS.getArgument(i)->getType()->isPointerTy())
continue;
- IRPosition CSArgPos = IRPosition::callsite_argument(CS, i);
// Call site argument attribute "non-null".
getOrCreateAAFor<AANonNull>(CSArgPos);
const char AADereferenceable::ID = 0;
const char AAAlign::ID = 0;
const char AANoCapture::ID = 0;
+const char AAValueSimplify::ID = 0;
// Macro magic to create the static generator function for attributes that
// follow the naming scheme.
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) \
+ } \
+ return *AA; \
+ }
+
CREATE_FUNCTION_ABSTRACT_ATTRIBUTE_FOR_POSITION(AANoUnwind)
CREATE_FUNCTION_ABSTRACT_ATTRIBUTE_FOR_POSITION(AANoSync)
CREATE_FUNCTION_ABSTRACT_ATTRIBUTE_FOR_POSITION(AANoFree)
CREATE_VALUE_ABSTRACT_ATTRIBUTE_FOR_POSITION(AAAlign)
CREATE_VALUE_ABSTRACT_ATTRIBUTE_FOR_POSITION(AANoCapture)
+CREATE_ALL_ABSTRACT_ATTRIBUTE_FOR_POSITION(AAValueSimplify)
+
#undef CREATE_FUNCTION_ABSTRACT_ATTRIBUTE_FOR_POSITION
#undef CREATE_VALUE_ABSTRACT_ATTRIBUTE_FOR_POSITION
+#undef CREATE_ALL_ABSTRACT_ATTRIBUTE_FOR_POSITION
#undef SWITCH_PK_CREATE
#undef SWITCH_PK_INV
--- /dev/null
+; RUN: opt -attributor --attributor-disable=false -S < %s | FileCheck %s
+; TODO: Add max-iteration check
+; ModuleID = 'value-simplify.ll'
+source_filename = "value-simplify.ll"
+target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128"
+declare void @f(i32)
+
+; Test1: Replace argument with constant
+define internal void @test1(i32 %a) {
+; CHECK: tail call void @f(i32 1)
+ tail call void @f(i32 %a)
+ ret void
+}
+
+define void @test1_helper() {
+ tail call void @test1(i32 1)
+ ret void
+}
+
+; TEST 2 : Simplify return value
+define i32 @return0() {
+ ret i32 0
+}
+
+define i32 @return1() {
+ ret i32 1
+}
+
+; CHECK: define i32 @test2_1(i1 %c)
+define i32 @test2_1(i1 %c) {
+ br i1 %c, label %if.true, label %if.false
+if.true:
+ %call = tail call i32 @return0()
+
+; FIXME: %ret0 should be replaced with i32 1.
+; CHECK: %ret0 = add i32 0, 1
+ %ret0 = add i32 %call, 1
+ br label %end
+if.false:
+ %ret1 = tail call i32 @return1()
+ br label %end
+end:
+
+; FIXME: %ret should be replaced with i32 1.
+; CHECK: %ret = phi i32 [ %ret0, %if.true ], [ 1, %if.false ]
+ %ret = phi i32 [ %ret0, %if.true ], [ %ret1, %if.false ]
+
+; FIXME: ret i32 1
+; CHECK: ret i32 %ret
+ ret i32 %ret
+}
+
+
+
+; CHECK: define i32 @test2_2(i1 %c)
+define i32 @test2_2(i1 %c) {
+; FIXME: %ret should be replaced with i32 1.
+ %ret = tail call i32 @test2_1(i1 %c)
+; FIXME: ret i32 1
+; CHECK: ret i32 %ret
+ ret i32 %ret
+}
+
+declare void @use(i32)
+; CHECK: define void @test3(i1 %c)
+define void @test3(i1 %c) {
+ br i1 %c, label %if.true, label %if.false
+if.true:
+ br label %end
+if.false:
+ %ret1 = tail call i32 @return1()
+ br label %end
+end:
+
+; CHECK: %r = phi i32 [ 1, %if.true ], [ 1, %if.false ]
+ %r = phi i32 [ 1, %if.true ], [ %ret1, %if.false ]
+
+; CHECK: tail call void @use(i32 1)
+ tail call void @use(i32 %r)
+ ret void
+}
+
+define void @test-select-phi(i1 %c) {
+ %select-same = select i1 %c, i32 1, i32 1
+ ; CHECK: tail call void @use(i32 1)
+ tail call void @use(i32 %select-same)
+
+ %select-not-same = select i1 %c, i32 1, i32 0
+ ; CHECK: tail call void @use(i32 %select-not-same)
+ tail call void @use(i32 %select-not-same)
+ br i1 %c, label %if-true, label %if-false
+if-true:
+ br label %end
+if-false:
+ br label %end
+end:
+ %phi-same = phi i32 [ 1, %if-true ], [ 1, %if-false ]
+ %phi-not-same = phi i32 [ 0, %if-true ], [ 1, %if-false ]
+ %phi-same-prop = phi i32 [ 1, %if-true ], [ %select-same, %if-false ]
+ %phi-same-undef = phi i32 [ 1, %if-true ], [ undef, %if-false ]
+ %select-not-same-undef = select i1 %c, i32 %phi-not-same, i32 undef
+
+
+ ; CHECK: tail call void @use(i32 1)
+ tail call void @use(i32 %phi-same)
+
+ ; CHECK: tail call void @use(i32 %phi-not-same)
+ tail call void @use(i32 %phi-not-same)
+
+ ; CHECK: tail call void @use(i32 1)
+ tail call void @use(i32 %phi-same-prop)
+
+ ; CHECK: tail call void @use(i32 1)
+ tail call void @use(i32 %phi-same-undef)
+
+ ; CHECK: tail call void @use(i32 %select-not-same-undef)
+ tail call void @use(i32 %select-not-same-undef)
+
+ ret void
+
+}