forked from OSchip/llvm-project
[Attributor] ValueSimplify Abstract Attribute
Summary: This patch introduces initial `AAValueSimplify` which simplifies a value in a context. example - (for function returned) If all the return values are the same and constant, then we can replace callsite returned with the constant. - If an internal function takes the same value(constant) as an argument in the callsite, then we can replace the argument with that constant. Reviewers: jdoerfert, sstefan1 Reviewed By: jdoerfert Subscribers: hiraditya, llvm-commits Tags: #llvm Differential Revision: https://reviews.llvm.org/D66967 llvm-svn: 371291
This commit is contained in:
parent
7faffd544b
commit
f2b9dc4758
|
@ -1700,6 +1700,31 @@ struct AANoCapture
|
||||||
static const char ID;
|
static const char ID;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/// An abstract interface for value simplify abstract attribute.
|
||||||
|
struct AAValueSimplify : public StateWrapper<BooleanState, AbstractAttribute>,
|
||||||
|
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 original value. If it is not clear yet, return the
|
||||||
|
/// Optional::NoneType.
|
||||||
|
virtual Optional<Value *> 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
|
} // end namespace llvm
|
||||||
|
|
||||||
#endif // LLVM_TRANSFORMS_IPO_FUNCTIONATTRS_H
|
#endif // LLVM_TRANSFORMS_IPO_FUNCTIONATTRS_H
|
||||||
|
|
|
@ -218,7 +218,7 @@ bool genericValueTraversal(
|
||||||
for (unsigned u = 0, e = PHI->getNumIncomingValues(); u < e; u++) {
|
for (unsigned u = 0, e = PHI->getNumIncomingValues(); u < e; u++) {
|
||||||
const BasicBlock *IncomingBB = PHI->getIncomingBlock(u);
|
const BasicBlock *IncomingBB = PHI->getIncomingBlock(u);
|
||||||
if (LivenessAA->isAssumedDead(IncomingBB->getTerminator())) {
|
if (LivenessAA->isAssumedDead(IncomingBB->getTerminator())) {
|
||||||
AnyDead =true;
|
AnyDead = true;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
Worklist.push_back(PHI->getIncomingValue(u));
|
Worklist.push_back(PHI->getIncomingValue(u));
|
||||||
|
@ -2900,6 +2900,238 @@ struct AANoCaptureCallSiteReturned final : AANoCaptureImpl {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/// ------------------ 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
|
/// Attributor
|
||||||
/// ----------------------------------------------------------------------------
|
/// ----------------------------------------------------------------------------
|
||||||
|
@ -3380,8 +3612,12 @@ void Attributor::identifyDefaultAbstractAttributes(Function &F) {
|
||||||
// though it is an argument attribute.
|
// though it is an argument attribute.
|
||||||
getOrCreateAAFor<AAReturnedValues>(FPos);
|
getOrCreateAAFor<AAReturnedValues>(FPos);
|
||||||
|
|
||||||
|
IRPosition RetPos = IRPosition::returned(F);
|
||||||
|
|
||||||
|
// Every function might be simplified.
|
||||||
|
getOrCreateAAFor<AAValueSimplify>(RetPos);
|
||||||
|
|
||||||
if (ReturnType->isPointerTy()) {
|
if (ReturnType->isPointerTy()) {
|
||||||
IRPosition RetPos = IRPosition::returned(F);
|
|
||||||
|
|
||||||
// Every function with pointer return type might be marked align.
|
// Every function with pointer return type might be marked align.
|
||||||
getOrCreateAAFor<AAAlign>(RetPos);
|
getOrCreateAAFor<AAAlign>(RetPos);
|
||||||
|
@ -3399,8 +3635,12 @@ void Attributor::identifyDefaultAbstractAttributes(Function &F) {
|
||||||
}
|
}
|
||||||
|
|
||||||
for (Argument &Arg : F.args()) {
|
for (Argument &Arg : F.args()) {
|
||||||
|
IRPosition ArgPos = IRPosition::argument(Arg);
|
||||||
|
|
||||||
|
// Every argument might be simplified.
|
||||||
|
getOrCreateAAFor<AAValueSimplify>(ArgPos);
|
||||||
|
|
||||||
if (Arg.getType()->isPointerTy()) {
|
if (Arg.getType()->isPointerTy()) {
|
||||||
IRPosition ArgPos = IRPosition::argument(Arg);
|
|
||||||
// Every argument with pointer type might be marked nonnull.
|
// Every argument with pointer type might be marked nonnull.
|
||||||
getOrCreateAAFor<AANonNull>(ArgPos);
|
getOrCreateAAFor<AANonNull>(ArgPos);
|
||||||
|
|
||||||
|
@ -3465,9 +3705,14 @@ void Attributor::identifyDefaultAbstractAttributes(Function &F) {
|
||||||
CallSite CS(&I);
|
CallSite CS(&I);
|
||||||
if (CS && CS.getCalledFunction()) {
|
if (CS && CS.getCalledFunction()) {
|
||||||
for (int i = 0, e = CS.getCalledFunction()->arg_size(); i < e; i++) {
|
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())
|
if (!CS.getArgument(i)->getType()->isPointerTy())
|
||||||
continue;
|
continue;
|
||||||
IRPosition CSArgPos = IRPosition::callsite_argument(CS, i);
|
|
||||||
|
|
||||||
// Call site argument attribute "non-null".
|
// Call site argument attribute "non-null".
|
||||||
getOrCreateAAFor<AANonNull>(CSArgPos);
|
getOrCreateAAFor<AANonNull>(CSArgPos);
|
||||||
|
@ -3632,6 +3877,7 @@ const char AAIsDead::ID = 0;
|
||||||
const char AADereferenceable::ID = 0;
|
const char AADereferenceable::ID = 0;
|
||||||
const char AAAlign::ID = 0;
|
const char AAAlign::ID = 0;
|
||||||
const char AANoCapture::ID = 0;
|
const char AANoCapture::ID = 0;
|
||||||
|
const char AAValueSimplify::ID = 0;
|
||||||
|
|
||||||
// Macro magic to create the static generator function for attributes that
|
// Macro magic to create the static generator function for attributes that
|
||||||
// follow the naming scheme.
|
// follow the naming scheme.
|
||||||
|
@ -3677,6 +3923,22 @@ const char AANoCapture::ID = 0;
|
||||||
return *AA; \
|
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(AANoUnwind)
|
||||||
CREATE_FUNCTION_ABSTRACT_ATTRIBUTE_FOR_POSITION(AANoSync)
|
CREATE_FUNCTION_ABSTRACT_ATTRIBUTE_FOR_POSITION(AANoSync)
|
||||||
CREATE_FUNCTION_ABSTRACT_ATTRIBUTE_FOR_POSITION(AANoFree)
|
CREATE_FUNCTION_ABSTRACT_ATTRIBUTE_FOR_POSITION(AANoFree)
|
||||||
|
@ -3692,8 +3954,11 @@ CREATE_VALUE_ABSTRACT_ATTRIBUTE_FOR_POSITION(AADereferenceable)
|
||||||
CREATE_VALUE_ABSTRACT_ATTRIBUTE_FOR_POSITION(AAAlign)
|
CREATE_VALUE_ABSTRACT_ATTRIBUTE_FOR_POSITION(AAAlign)
|
||||||
CREATE_VALUE_ABSTRACT_ATTRIBUTE_FOR_POSITION(AANoCapture)
|
CREATE_VALUE_ABSTRACT_ATTRIBUTE_FOR_POSITION(AANoCapture)
|
||||||
|
|
||||||
|
CREATE_ALL_ABSTRACT_ATTRIBUTE_FOR_POSITION(AAValueSimplify)
|
||||||
|
|
||||||
#undef CREATE_FUNCTION_ABSTRACT_ATTRIBUTE_FOR_POSITION
|
#undef CREATE_FUNCTION_ABSTRACT_ATTRIBUTE_FOR_POSITION
|
||||||
#undef CREATE_VALUE_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_CREATE
|
||||||
#undef SWITCH_PK_INV
|
#undef SWITCH_PK_INV
|
||||||
|
|
||||||
|
|
|
@ -107,7 +107,7 @@ define internal i8* @f2(i8* readnone %0) local_unnamed_addr #0 {
|
||||||
|
|
||||||
; <label>:3: ; preds = %1
|
; <label>:3: ; preds = %1
|
||||||
|
|
||||||
; ATTRIBUTOR: %4 = tail call i8* @f1(i8* nonnull align 8 dereferenceable(1) "no-capture-maybe-returned" %0)
|
; ATTRIBUTOR: %4 = tail call i8* @f1(i8* nonnull align 8 dereferenceable(1) "no-capture-maybe-returned" @a1)
|
||||||
%4 = tail call i8* @f1(i8* nonnull %0)
|
%4 = tail call i8* @f1(i8* nonnull %0)
|
||||||
br label %7
|
br label %7
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
; RUN: opt -functionattrs -attributor -attributor-disable=false -attributor-max-iterations-verify -attributor-max-iterations=4 -S < %s | FileCheck %s
|
; RUN: opt -functionattrs -attributor -attributor-disable=false -attributor-max-iterations-verify -attributor-max-iterations=5 -S < %s | FileCheck %s
|
||||||
;
|
;
|
||||||
; This file is the same as noreturn_async.ll but with a personality which
|
; This file is the same as noreturn_async.ll but with a personality which
|
||||||
; indicates that the exception handler *cannot* catch asynchronous exceptions.
|
; indicates that the exception handler *cannot* catch asynchronous exceptions.
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
; RUN: opt < %s -functionattrs -S | FileCheck %s
|
; RUN: opt < %s -functionattrs -S | FileCheck %s
|
||||||
; RUN: opt < %s -attributor -attributor-disable=false -attributor-max-iterations-verify -attributor-max-iterations=4 -S | FileCheck %s --check-prefix=ATTRIBUTOR
|
; RUN: opt < %s -attributor -attributor-disable=false -attributor-max-iterations-verify -attributor-max-iterations=5 -S | FileCheck %s --check-prefix=ATTRIBUTOR
|
||||||
|
|
||||||
; TEST 1
|
; TEST 1
|
||||||
; CHECK: Function Attrs: norecurse nounwind readnone
|
; CHECK: Function Attrs: norecurse nounwind readnone
|
||||||
|
|
|
@ -0,0 +1,121 @@
|
||||||
|
; 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
|
||||||
|
|
||||||
|
}
|
Loading…
Reference in New Issue