[llvm] 6c25eca - [Attributor] Add flag for undef value to the state of AAPotentialValues
Shinji Okumura via llvm-commits
llvm-commits at lists.llvm.org
Thu Aug 27 00:46:37 PDT 2020
Author: Shinji Okumura
Date: 2020-08-27T16:30:29+09:00
New Revision: 6c25eca6142cec0695016b6fd012df56b50ee01b
URL: https://github.com/llvm/llvm-project/commit/6c25eca6142cec0695016b6fd012df56b50ee01b
DIFF: https://github.com/llvm/llvm-project/commit/6c25eca6142cec0695016b6fd012df56b50ee01b.diff
LOG: [Attributor] Add flag for undef value to the state of AAPotentialValues
Currently, an undef value is reduced to 0 when it is added to a set of potential values.
This patch introduces a flag for under values. By this, for example, we can merge two states `{undef}`, `{1}` to `{1}` (because we can reduce the undef to 1).
Reviewed By: jdoerfert
Differential Revision: https://reviews.llvm.org/D85592
Added:
Modified:
llvm/include/llvm/Transforms/IPO/Attributor.h
llvm/lib/Transforms/IPO/Attributor.cpp
llvm/lib/Transforms/IPO/AttributorAttributes.cpp
llvm/test/Transforms/Attributor/potential.ll
llvm/test/Transforms/Attributor/value-simplify.ll
Removed:
################################################################################
diff --git a/llvm/include/llvm/Transforms/IPO/Attributor.h b/llvm/include/llvm/Transforms/IPO/Attributor.h
index 2dfb2b189046..43fd7cfe0bbb 100644
--- a/llvm/include/llvm/Transforms/IPO/Attributor.h
+++ b/llvm/include/llvm/Transforms/IPO/Attributor.h
@@ -3368,9 +3368,10 @@ template <typename MemberTy, typename KeyInfo = DenseMapInfo<MemberTy>>
struct PotentialValuesState : AbstractState {
using SetTy = DenseSet<MemberTy, KeyInfo>;
- PotentialValuesState() : IsValidState(true) {}
+ PotentialValuesState() : IsValidState(true), UndefIsContained(false) {}
- PotentialValuesState(bool IsValid) : IsValidState(IsValid) {}
+ PotentialValuesState(bool IsValid)
+ : IsValidState(IsValid), UndefIsContained(false) {}
/// See AbstractState::isValidState(...)
bool isValidState() const override { return IsValidState.isValidState(); }
@@ -3399,11 +3400,19 @@ struct PotentialValuesState : AbstractState {
return Set;
}
+ /// Returns whether this state contains an undef value or not.
+ bool undefIsContained() const {
+ assert(isValidState() && "This flag shoud not be used when it is invalid!");
+ return UndefIsContained;
+ }
+
bool operator==(const PotentialValuesState &RHS) const {
if (isValidState() != RHS.isValidState())
return false;
if (!isValidState() && !RHS.isValidState())
return true;
+ if (undefIsContained() != RHS.undefIsContained())
+ return false;
return Set == RHS.getAssumedSet();
}
@@ -3431,6 +3440,9 @@ struct PotentialValuesState : AbstractState {
/// Union assumed set with assumed set of the passed state \p PVS.
void unionAssumed(const PotentialValuesState &PVS) { unionWith(PVS); }
+ /// Union assumed set with an undef value.
+ void unionAssumedWithUndef() { unionWithUndef(); }
+
/// "Clamp" this state with \p PVS.
PotentialValuesState operator^=(const PotentialValuesState &PVS) {
IsValidState ^= PVS.IsValidState;
@@ -3452,6 +3464,10 @@ struct PotentialValuesState : AbstractState {
indicatePessimisticFixpoint();
}
+ /// If this state contains both undef and not undef, we can reduce
+ /// undef to the not undef value.
+ void reduceUndefValue() { UndefIsContained = UndefIsContained & Set.empty(); }
+
/// Insert an element into this set.
void insert(const MemberTy &C) {
if (!isValidState())
@@ -3472,9 +3488,17 @@ struct PotentialValuesState : AbstractState {
}
for (const MemberTy &C : R.Set)
Set.insert(C);
+ UndefIsContained |= R.undefIsContained();
+ reduceUndefValue();
checkAndInvalidate();
}
+ /// Take union with an undef value.
+ void unionWithUndef() {
+ UndefIsContained = true;
+ reduceUndefValue();
+ }
+
/// Take intersection with R.
void intersectWith(const PotentialValuesState &R) {
/// If R is a full set, do nothing.
@@ -3491,6 +3515,8 @@ struct PotentialValuesState : AbstractState {
IntersectSet.insert(C);
}
Set = IntersectSet;
+ UndefIsContained &= R.undefIsContained();
+ reduceUndefValue();
}
/// A helper state which indicate whether this state is valid or not.
@@ -3498,6 +3524,9 @@ struct PotentialValuesState : AbstractState {
/// Container for potential values
SetTy Set;
+
+ /// Flag for undef value
+ bool UndefIsContained;
};
using PotentialConstantIntValuesState = PotentialValuesState<APInt>;
@@ -3544,8 +3573,12 @@ struct AAPotentialValues
if (getAssumedSet().size() == 1)
return cast<ConstantInt>(ConstantInt::get(getAssociatedValue().getType(),
*(getAssumedSet().begin())));
- if (getAssumedSet().size() == 0)
+ if (getAssumedSet().size() == 0) {
+ if (undefIsContained())
+ return cast<ConstantInt>(
+ ConstantInt::get(getAssociatedValue().getType(), 0));
return llvm::None;
+ }
return nullptr;
}
diff --git a/llvm/lib/Transforms/IPO/Attributor.cpp b/llvm/lib/Transforms/IPO/Attributor.cpp
index d34f4438d4c6..f4351ee11f9b 100644
--- a/llvm/lib/Transforms/IPO/Attributor.cpp
+++ b/llvm/lib/Transforms/IPO/Attributor.cpp
@@ -2165,9 +2165,12 @@ raw_ostream &llvm::operator<<(raw_ostream &OS,
OS << "set-state(< {";
if (!S.isValidState())
OS << "full-set";
- else
+ else {
for (auto &it : S.getAssumedSet())
OS << it << ", ";
+ if (S.undefIsContained())
+ OS << "undef ";
+ }
OS << "} >)";
return OS;
diff --git a/llvm/lib/Transforms/IPO/AttributorAttributes.cpp b/llvm/lib/Transforms/IPO/AttributorAttributes.cpp
index 33952a836e25..d96fa4189ab0 100644
--- a/llvm/lib/Transforms/IPO/AttributorAttributes.cpp
+++ b/llvm/lib/Transforms/IPO/AttributorAttributes.cpp
@@ -7353,10 +7353,7 @@ struct AAPotentialValuesFloating : AAPotentialValuesImpl {
}
if (isa<UndefValue>(&V)) {
- // Collapse the undef state to 0.
- unionAssumed(
- APInt(/* numBits */ getAssociatedType()->getIntegerBitWidth(),
- /* val */ 0));
+ unionAssumedWithUndef();
indicateOptimisticFixpoint();
return;
}
@@ -7477,6 +7474,20 @@ struct AAPotentialValuesFloating : AAPotentialValuesImpl {
}
}
+ bool calculateBinaryOperatorAndTakeUnion(const BinaryOperator *BinOp,
+ const APInt &LHS, const APInt &RHS) {
+ bool SkipOperation = false;
+ bool Unsupported = false;
+ APInt Result =
+ calculateBinaryOperator(BinOp, LHS, RHS, SkipOperation, Unsupported);
+ if (Unsupported)
+ return false;
+ // If SkipOperation is true, we can ignore this operand pair (L, R).
+ if (!SkipOperation)
+ unionAssumed(Result);
+ return isValidState();
+ }
+
ChangeStatus updateWithICmpInst(Attributor &A, ICmpInst *ICI) {
auto AssumedBefore = getAssumed();
Value *LHS = ICI->getOperand(0);
@@ -7495,16 +7506,40 @@ struct AAPotentialValuesFloating : AAPotentialValuesImpl {
const DenseSet<APInt> &LHSAAPVS = LHSAA.getAssumedSet();
const DenseSet<APInt> &RHSAAPVS = RHSAA.getAssumedSet();
- // TODO: Handle undef correctly.
+ // TODO: make use of undef flag to limit potential values aggressively.
bool MaybeTrue = false, MaybeFalse = false;
- for (const APInt &L : LHSAAPVS) {
+ const APInt Zero(RHS->getType()->getIntegerBitWidth(), 0);
+ if (LHSAA.undefIsContained() && RHSAA.undefIsContained()) {
+ // The result of any comparison between undefs can be soundly replaced
+ // with undef.
+ unionAssumedWithUndef();
+ } else if (LHSAA.undefIsContained()) {
+ bool MaybeTrue = false, MaybeFalse = false;
for (const APInt &R : RHSAAPVS) {
- bool CmpResult = calculateICmpInst(ICI, L, R);
+ bool CmpResult = calculateICmpInst(ICI, Zero, R);
MaybeTrue |= CmpResult;
MaybeFalse |= !CmpResult;
if (MaybeTrue & MaybeFalse)
return indicatePessimisticFixpoint();
}
+ } else if (RHSAA.undefIsContained()) {
+ for (const APInt &L : LHSAAPVS) {
+ bool CmpResult = calculateICmpInst(ICI, L, Zero);
+ MaybeTrue |= CmpResult;
+ MaybeFalse |= !CmpResult;
+ if (MaybeTrue & MaybeFalse)
+ return indicatePessimisticFixpoint();
+ }
+ } else {
+ for (const APInt &L : LHSAAPVS) {
+ for (const APInt &R : RHSAAPVS) {
+ bool CmpResult = calculateICmpInst(ICI, L, R);
+ MaybeTrue |= CmpResult;
+ MaybeFalse |= !CmpResult;
+ if (MaybeTrue & MaybeFalse)
+ return indicatePessimisticFixpoint();
+ }
+ }
}
if (MaybeTrue)
unionAssumed(APInt(/* numBits */ 1, /* val */ 1));
@@ -7530,8 +7565,13 @@ struct AAPotentialValuesFloating : AAPotentialValuesImpl {
if (!RHSAA.isValidState())
return indicatePessimisticFixpoint();
- unionAssumed(LHSAA);
- unionAssumed(RHSAA);
+ if (LHSAA.undefIsContained() && RHSAA.undefIsContained())
+ // select i1 *, undef , undef => undef
+ unionAssumedWithUndef();
+ else {
+ unionAssumed(LHSAA);
+ unionAssumed(RHSAA);
+ }
return AssumedBefore == getAssumed() ? ChangeStatus::UNCHANGED
: ChangeStatus::CHANGED;
}
@@ -7547,11 +7587,14 @@ struct AAPotentialValuesFloating : AAPotentialValuesImpl {
if (!SrcAA.isValidState())
return indicatePessimisticFixpoint();
const DenseSet<APInt> &SrcAAPVS = SrcAA.getAssumedSet();
- for (const APInt &S : SrcAAPVS) {
- APInt T = calculateCastInst(CI, S, ResultBitWidth);
- unionAssumed(T);
+ if (SrcAA.undefIsContained())
+ unionAssumedWithUndef();
+ else {
+ for (const APInt &S : SrcAAPVS) {
+ APInt T = calculateCastInst(CI, S, ResultBitWidth);
+ unionAssumed(T);
+ }
}
- // TODO: Handle undef correctly.
return AssumedBefore == getAssumed() ? ChangeStatus::UNCHANGED
: ChangeStatus::CHANGED;
}
@@ -7573,19 +7616,28 @@ struct AAPotentialValuesFloating : AAPotentialValuesImpl {
const DenseSet<APInt> &LHSAAPVS = LHSAA.getAssumedSet();
const DenseSet<APInt> &RHSAAPVS = RHSAA.getAssumedSet();
+ const APInt Zero = APInt(LHS->getType()->getIntegerBitWidth(), 0);
- // TODO: Handle undef correctly
- for (const APInt &L : LHSAAPVS) {
+ // TODO: make use of undef flag to limit potential values aggressively.
+ if (LHSAA.undefIsContained() && RHSAA.undefIsContained()) {
+ if (!calculateBinaryOperatorAndTakeUnion(BinOp, Zero, Zero))
+ return indicatePessimisticFixpoint();
+ } else if (LHSAA.undefIsContained()) {
for (const APInt &R : RHSAAPVS) {
- bool SkipOperation = false;
- bool Unsupported = false;
- APInt Result =
- calculateBinaryOperator(BinOp, L, R, SkipOperation, Unsupported);
- if (Unsupported)
+ if (!calculateBinaryOperatorAndTakeUnion(BinOp, Zero, R))
+ return indicatePessimisticFixpoint();
+ }
+ } else if (RHSAA.undefIsContained()) {
+ for (const APInt &L : LHSAAPVS) {
+ if (!calculateBinaryOperatorAndTakeUnion(BinOp, L, Zero))
return indicatePessimisticFixpoint();
- // If SkipOperation is true, we can ignore this operand pair (L, R).
- if (!SkipOperation)
- unionAssumed(Result);
+ }
+ } else {
+ for (const APInt &L : LHSAAPVS) {
+ for (const APInt &R : RHSAAPVS) {
+ if (!calculateBinaryOperatorAndTakeUnion(BinOp, L, R))
+ return indicatePessimisticFixpoint();
+ }
}
}
return AssumedBefore == getAssumed() ? ChangeStatus::UNCHANGED
@@ -7600,7 +7652,10 @@ struct AAPotentialValuesFloating : AAPotentialValuesImpl {
*this, IRPosition::value(*IncomingValue));
if (!PotentialValuesAA.isValidState())
return indicatePessimisticFixpoint();
- unionAssumed(PotentialValuesAA.getAssumed());
+ if (PotentialValuesAA.undefIsContained())
+ unionAssumedWithUndef();
+ else
+ unionAssumed(PotentialValuesAA.getAssumed());
}
return AssumedBefore == getAssumed() ? ChangeStatus::UNCHANGED
: ChangeStatus::CHANGED;
@@ -7688,10 +7743,7 @@ struct AAPotentialValuesCallSiteArgument : AAPotentialValuesFloating {
}
if (isa<UndefValue>(&V)) {
- // Collapse the undef state to 0.
- unionAssumed(
- APInt(/* numBits */ getAssociatedType()->getIntegerBitWidth(),
- /* val */ 0));
+ unionAssumedWithUndef();
indicateOptimisticFixpoint();
return;
}
diff --git a/llvm/test/Transforms/Attributor/potential.ll b/llvm/test/Transforms/Attributor/potential.ll
index 41818fc95924..99e2a71ddc85 100644
--- a/llvm/test/Transforms/Attributor/potential.ll
+++ b/llvm/test/Transforms/Attributor/potential.ll
@@ -493,20 +493,6 @@ end:
; and returned value of @potential_test10 can be simplified to 0(false)
define internal i32 @may_return_undef(i32 %c) {
-; IS__TUNIT____: Function Attrs: nofree nosync nounwind readnone willreturn
-; IS__TUNIT____-LABEL: define {{[^@]+}}@may_return_undef
-; IS__TUNIT____-SAME: (i32 [[C:%.*]])
-; IS__TUNIT____-NEXT: switch i32 [[C]], label [[OTHERWISE:%.*]] [
-; IS__TUNIT____-NEXT: i32 1, label [[A:%.*]]
-; IS__TUNIT____-NEXT: i32 -1, label [[B:%.*]]
-; IS__TUNIT____-NEXT: ]
-; IS__TUNIT____: a:
-; IS__TUNIT____-NEXT: ret i32 1
-; IS__TUNIT____: b:
-; IS__TUNIT____-NEXT: ret i32 -1
-; IS__TUNIT____: otherwise:
-; IS__TUNIT____-NEXT: ret i32 undef
-;
; IS__CGSCC____: Function Attrs: nofree norecurse nosync nounwind readnone willreturn
; IS__CGSCC____-LABEL: define {{[^@]+}}@may_return_undef
; IS__CGSCC____-SAME: (i32 [[C:%.*]])
@@ -532,19 +518,10 @@ otherwise:
}
define i1 @potential_test10(i32 %c) {
-; IS__TUNIT_OPM: Function Attrs: nofree nosync nounwind readnone willreturn
-; IS__TUNIT_OPM-LABEL: define {{[^@]+}}@potential_test10
-; IS__TUNIT_OPM-SAME: (i32 [[C:%.*]])
-; IS__TUNIT_OPM-NEXT: [[RET:%.*]] = call i32 @may_return_undef(i32 [[C]]) [[ATTR0]], [[RNG2:!range !.*]]
-; IS__TUNIT_OPM-NEXT: [[CMP:%.*]] = icmp eq i32 [[RET]], 0
-; IS__TUNIT_OPM-NEXT: ret i1 [[CMP]]
-;
-; IS__TUNIT_NPM: Function Attrs: nofree nosync nounwind readnone willreturn
-; IS__TUNIT_NPM-LABEL: define {{[^@]+}}@potential_test10
-; IS__TUNIT_NPM-SAME: (i32 [[C:%.*]])
-; IS__TUNIT_NPM-NEXT: [[RET:%.*]] = call i32 @may_return_undef(i32 [[C]]) [[ATTR0]], [[RNG3:!range !.*]]
-; IS__TUNIT_NPM-NEXT: [[CMP:%.*]] = icmp eq i32 [[RET]], 0
-; IS__TUNIT_NPM-NEXT: ret i1 [[CMP]]
+; IS__TUNIT____: Function Attrs: nofree nosync nounwind readnone willreturn
+; IS__TUNIT____-LABEL: define {{[^@]+}}@potential_test10
+; IS__TUNIT____-SAME: (i32 [[C:%.*]])
+; IS__TUNIT____-NEXT: ret i1 false
;
; IS__CGSCC____: Function Attrs: nofree norecurse nosync nounwind readnone willreturn
; IS__CGSCC____-LABEL: define {{[^@]+}}@potential_test10
@@ -558,15 +535,350 @@ define i1 @potential_test10(i32 %c) {
ret i1 %cmp
}
+define i32 @optimize_undef_1(i1 %c) {
+; IS__TUNIT____: Function Attrs: nofree nosync nounwind readnone willreturn
+; IS__TUNIT____-LABEL: define {{[^@]+}}@optimize_undef_1
+; IS__TUNIT____-SAME: (i1 [[C:%.*]])
+; IS__TUNIT____-NEXT: br i1 [[C]], label [[T:%.*]], label [[F:%.*]]
+; IS__TUNIT____: t:
+; IS__TUNIT____-NEXT: ret i32 0
+; IS__TUNIT____: f:
+; IS__TUNIT____-NEXT: ret i32 1
+;
+; IS__CGSCC____: Function Attrs: nofree norecurse nosync nounwind readnone willreturn
+; IS__CGSCC____-LABEL: define {{[^@]+}}@optimize_undef_1
+; IS__CGSCC____-SAME: (i1 [[C:%.*]])
+; IS__CGSCC____-NEXT: br i1 [[C]], label [[T:%.*]], label [[F:%.*]]
+; IS__CGSCC____: t:
+; IS__CGSCC____-NEXT: ret i32 0
+; IS__CGSCC____: f:
+; IS__CGSCC____-NEXT: ret i32 1
+;
+ br i1 %c, label %t, label %f
+t:
+ ret i32 0
+f:
+ %undef = add i32 undef, 1
+ ret i32 %undef
+}
+
+define i32 @optimize_undef_2(i1 %c) {
+; IS__TUNIT____: Function Attrs: nofree nosync nounwind readnone willreturn
+; IS__TUNIT____-LABEL: define {{[^@]+}}@optimize_undef_2
+; IS__TUNIT____-SAME: (i1 [[C:%.*]])
+; IS__TUNIT____-NEXT: br i1 [[C]], label [[T:%.*]], label [[F:%.*]]
+; IS__TUNIT____: t:
+; IS__TUNIT____-NEXT: ret i32 0
+; IS__TUNIT____: f:
+; IS__TUNIT____-NEXT: ret i32 -1
+;
+; IS__CGSCC____: Function Attrs: nofree norecurse nosync nounwind readnone willreturn
+; IS__CGSCC____-LABEL: define {{[^@]+}}@optimize_undef_2
+; IS__CGSCC____-SAME: (i1 [[C:%.*]])
+; IS__CGSCC____-NEXT: br i1 [[C]], label [[T:%.*]], label [[F:%.*]]
+; IS__CGSCC____: t:
+; IS__CGSCC____-NEXT: ret i32 0
+; IS__CGSCC____: f:
+; IS__CGSCC____-NEXT: ret i32 -1
+;
+ br i1 %c, label %t, label %f
+t:
+ ret i32 0
+f:
+ %undef = sub i32 undef, 1
+ ret i32 %undef
+}
+
+define i32 @optimize_undef_3(i1 %c) {
+; IS__TUNIT____: Function Attrs: nofree nosync nounwind readnone willreturn
+; IS__TUNIT____-LABEL: define {{[^@]+}}@optimize_undef_3
+; IS__TUNIT____-SAME: (i1 [[C:%.*]])
+; IS__TUNIT____-NEXT: br i1 [[C]], label [[T:%.*]], label [[F:%.*]]
+; IS__TUNIT____: t:
+; IS__TUNIT____-NEXT: ret i32 0
+; IS__TUNIT____: f:
+; IS__TUNIT____-NEXT: ret i32 1
+;
+; IS__CGSCC____: Function Attrs: nofree norecurse nosync nounwind readnone willreturn
+; IS__CGSCC____-LABEL: define {{[^@]+}}@optimize_undef_3
+; IS__CGSCC____-SAME: (i1 [[C:%.*]])
+; IS__CGSCC____-NEXT: br i1 [[C]], label [[T:%.*]], label [[F:%.*]]
+; IS__CGSCC____: t:
+; IS__CGSCC____-NEXT: ret i32 0
+; IS__CGSCC____: f:
+; IS__CGSCC____-NEXT: ret i32 1
+;
+ br i1 %c, label %t, label %f
+t:
+ ret i32 0
+f:
+ %undef = icmp eq i32 undef, 0
+ %undef2 = zext i1 %undef to i32
+ ret i32 %undef2
+}
+
+
+; FIXME: returned value can be simplified to 0
+define i32 @potential_test11(i1 %c) {
+; IS__TUNIT_OPM: Function Attrs: nofree nosync nounwind readnone willreturn
+; IS__TUNIT_OPM-LABEL: define {{[^@]+}}@potential_test11
+; IS__TUNIT_OPM-SAME: (i1 [[C:%.*]])
+; IS__TUNIT_OPM-NEXT: [[ZERO1:%.*]] = call i32 @optimize_undef_1(i1 [[C]]) [[ATTR0]], [[RNG2:!range !.*]]
+; IS__TUNIT_OPM-NEXT: [[ZERO2:%.*]] = call i32 @optimize_undef_2(i1 [[C]]) [[ATTR0]], [[RNG3:!range !.*]]
+; IS__TUNIT_OPM-NEXT: [[ACC1:%.*]] = add i32 [[ZERO1]], [[ZERO2]]
+; IS__TUNIT_OPM-NEXT: [[ACC2:%.*]] = add i32 [[ACC1]], 0
+; IS__TUNIT_OPM-NEXT: ret i32 [[ACC2]]
+;
+; IS__TUNIT_NPM: Function Attrs: nofree nosync nounwind readnone willreturn
+; IS__TUNIT_NPM-LABEL: define {{[^@]+}}@potential_test11
+; IS__TUNIT_NPM-SAME: (i1 [[C:%.*]])
+; IS__TUNIT_NPM-NEXT: [[ZERO1:%.*]] = call i32 @optimize_undef_1(i1 [[C]]) [[ATTR0]], [[RNG0]]
+; IS__TUNIT_NPM-NEXT: [[ZERO2:%.*]] = call i32 @optimize_undef_2(i1 [[C]]) [[ATTR0]], [[RNG3:!range !.*]]
+; IS__TUNIT_NPM-NEXT: [[ACC1:%.*]] = add i32 [[ZERO1]], [[ZERO2]]
+; IS__TUNIT_NPM-NEXT: [[ACC2:%.*]] = add i32 [[ACC1]], 0
+; IS__TUNIT_NPM-NEXT: ret i32 [[ACC2]]
+;
+; IS__CGSCC____: Function Attrs: nofree norecurse nosync nounwind readnone willreturn
+; IS__CGSCC____-LABEL: define {{[^@]+}}@potential_test11
+; IS__CGSCC____-SAME: (i1 [[C:%.*]])
+; IS__CGSCC____-NEXT: [[ZERO1:%.*]] = call i32 @optimize_undef_1(i1 [[C]])
+; IS__CGSCC____-NEXT: [[ZERO2:%.*]] = call i32 @optimize_undef_2(i1 [[C]])
+; IS__CGSCC____-NEXT: [[ZERO3:%.*]] = call i32 @optimize_undef_3(i1 [[C]])
+; IS__CGSCC____-NEXT: [[ACC1:%.*]] = add i32 [[ZERO1]], [[ZERO2]]
+; IS__CGSCC____-NEXT: [[ACC2:%.*]] = add i32 [[ACC1]], [[ZERO3]]
+; IS__CGSCC____-NEXT: ret i32 [[ACC2]]
+;
+ %zero1 = call i32 @optimize_undef_1(i1 %c)
+ %zero2 = call i32 @optimize_undef_2(i1 %c)
+ %zero3 = call i32 @optimize_undef_3(i1 %c)
+ %acc1 = add i32 %zero1, %zero2
+ %acc2 = add i32 %acc1, %zero3
+ ret i32 %acc2
+}
+
+define i32 @optimize_poison_1(i1 %c) {
+; IS__TUNIT_OPM: Function Attrs: nofree nosync nounwind readnone willreturn
+; IS__TUNIT_OPM-LABEL: define {{[^@]+}}@optimize_poison_1
+; IS__TUNIT_OPM-SAME: (i1 [[C:%.*]])
+; IS__TUNIT_OPM-NEXT: br i1 [[C]], label [[T:%.*]], label [[F:%.*]]
+; IS__TUNIT_OPM: t:
+; IS__TUNIT_OPM-NEXT: ret i32 0
+; IS__TUNIT_OPM: f:
+; IS__TUNIT_OPM-NEXT: ret i32 -1
+;
+; IS__TUNIT_NPM: Function Attrs: nofree nosync nounwind readnone willreturn
+; IS__TUNIT_NPM-LABEL: define {{[^@]+}}@optimize_poison_1
+; IS__TUNIT_NPM-SAME: (i1 [[C:%.*]])
+; IS__TUNIT_NPM-NEXT: br i1 [[C]], label [[T:%.*]], label [[F:%.*]]
+; IS__TUNIT_NPM: t:
+; IS__TUNIT_NPM-NEXT: ret i32 0
+; IS__TUNIT_NPM: f:
+; IS__TUNIT_NPM-NEXT: ret i32 undef
+;
+; IS__CGSCC_OPM: Function Attrs: nofree norecurse nosync nounwind readnone willreturn
+; IS__CGSCC_OPM-LABEL: define {{[^@]+}}@optimize_poison_1
+; IS__CGSCC_OPM-SAME: (i1 [[C:%.*]])
+; IS__CGSCC_OPM-NEXT: br i1 [[C]], label [[T:%.*]], label [[F:%.*]]
+; IS__CGSCC_OPM: t:
+; IS__CGSCC_OPM-NEXT: ret i32 0
+; IS__CGSCC_OPM: f:
+; IS__CGSCC_OPM-NEXT: ret i32 -1
+;
+; IS__CGSCC_NPM: Function Attrs: nofree norecurse nosync nounwind readnone willreturn
+; IS__CGSCC_NPM-LABEL: define {{[^@]+}}@optimize_poison_1
+; IS__CGSCC_NPM-SAME: (i1 [[C:%.*]])
+; IS__CGSCC_NPM-NEXT: br i1 [[C]], label [[T:%.*]], label [[F:%.*]]
+; IS__CGSCC_NPM: t:
+; IS__CGSCC_NPM-NEXT: ret i32 0
+; IS__CGSCC_NPM: f:
+; IS__CGSCC_NPM-NEXT: ret i32 undef
+;
+ br i1 %c, label %t, label %f
+t:
+ ret i32 0
+f:
+ %poison = sub nuw i32 0, 1
+ ret i32 %poison
+}
+
+; FIXME: returned value can be simplified to 0
+define i32 @potential_test12(i1 %c) {
+; IS__TUNIT_OPM: Function Attrs: nofree nosync nounwind readnone willreturn
+; IS__TUNIT_OPM-LABEL: define {{[^@]+}}@potential_test12
+; IS__TUNIT_OPM-SAME: (i1 [[C:%.*]])
+; IS__TUNIT_OPM-NEXT: [[ZERO:%.*]] = call i32 @optimize_poison_1(i1 [[C]]) [[ATTR0]], [[RNG3]]
+; IS__TUNIT_OPM-NEXT: ret i32 [[ZERO]]
+;
+; IS__TUNIT_NPM: Function Attrs: nofree nosync nounwind readnone willreturn
+; IS__TUNIT_NPM-LABEL: define {{[^@]+}}@potential_test12
+; IS__TUNIT_NPM-SAME: (i1 [[C:%.*]])
+; IS__TUNIT_NPM-NEXT: ret i32 0
+;
+; IS__CGSCC____: Function Attrs: nofree norecurse nosync nounwind readnone willreturn
+; IS__CGSCC____-LABEL: define {{[^@]+}}@potential_test12
+; IS__CGSCC____-SAME: (i1 [[C:%.*]])
+; IS__CGSCC____-NEXT: [[ZERO:%.*]] = call i32 @optimize_poison_1(i1 [[C]])
+; IS__CGSCC____-NEXT: ret i32 [[ZERO]]
+;
+ %zero = call i32 @optimize_poison_1(i1 %c)
+ ret i32 %zero
+}
+
+; Test 13
+; Do not simplify %ret in the callee to `%c`.
+; The potential value of %c is {0, 1} (undef is merged).
+; However, we should not simplify `and i32 %c, 3` to `%c`
+
+define internal i32 @potential_test13_callee(i32 %c) {
+; IS__TUNIT____: Function Attrs: nofree nosync nounwind readnone willreturn
+; IS__TUNIT____-LABEL: define {{[^@]+}}@potential_test13_callee
+; IS__TUNIT____-SAME: (i32 [[C:%.*]])
+; IS__TUNIT____-NEXT: [[RET:%.*]] = and i32 [[C]], 3
+; IS__TUNIT____-NEXT: ret i32 [[RET]]
+;
+; IS__CGSCC____: Function Attrs: nofree norecurse nosync nounwind readnone willreturn
+; IS__CGSCC____-LABEL: define {{[^@]+}}@potential_test13_callee
+; IS__CGSCC____-SAME: (i32 [[C:%.*]])
+; IS__CGSCC____-NEXT: [[RET:%.*]] = and i32 [[C]], 3
+; IS__CGSCC____-NEXT: ret i32 [[RET]]
+;
+ %ret = and i32 %c, 3
+ ret i32 %ret
+}
+
+define i32 @potential_test13_caller1() {
+; IS__TUNIT_OPM: Function Attrs: nofree nosync nounwind readnone willreturn
+; IS__TUNIT_OPM-LABEL: define {{[^@]+}}@potential_test13_caller1()
+; IS__TUNIT_OPM-NEXT: [[RET:%.*]] = call i32 @potential_test13_callee(i32 0) [[ATTR0]], [[RNG2]]
+; IS__TUNIT_OPM-NEXT: ret i32 [[RET]]
+;
+; IS__TUNIT_NPM: Function Attrs: nofree nosync nounwind readnone willreturn
+; IS__TUNIT_NPM-LABEL: define {{[^@]+}}@potential_test13_caller1()
+; IS__TUNIT_NPM-NEXT: [[RET:%.*]] = call i32 @potential_test13_callee(i32 0) [[ATTR0]], [[RNG0]]
+; IS__TUNIT_NPM-NEXT: ret i32 [[RET]]
+;
+; IS__CGSCC____: Function Attrs: nofree norecurse nosync nounwind readnone willreturn
+; IS__CGSCC____-LABEL: define {{[^@]+}}@potential_test13_caller1()
+; IS__CGSCC____-NEXT: [[RET:%.*]] = call i32 @potential_test13_callee(i32 0)
+; IS__CGSCC____-NEXT: ret i32 [[RET]]
+;
+ %ret = call i32 @potential_test13_callee(i32 0)
+ ret i32 %ret
+}
+
+define i32 @potential_test13_caller2() {
+; IS__TUNIT_OPM: Function Attrs: nofree nosync nounwind readnone willreturn
+; IS__TUNIT_OPM-LABEL: define {{[^@]+}}@potential_test13_caller2()
+; IS__TUNIT_OPM-NEXT: [[RET:%.*]] = call i32 @potential_test13_callee(i32 1) [[ATTR0]], [[RNG2]]
+; IS__TUNIT_OPM-NEXT: ret i32 [[RET]]
+;
+; IS__TUNIT_NPM: Function Attrs: nofree nosync nounwind readnone willreturn
+; IS__TUNIT_NPM-LABEL: define {{[^@]+}}@potential_test13_caller2()
+; IS__TUNIT_NPM-NEXT: [[RET:%.*]] = call i32 @potential_test13_callee(i32 1) [[ATTR0]], [[RNG0]]
+; IS__TUNIT_NPM-NEXT: ret i32 [[RET]]
+;
+; IS__CGSCC____: Function Attrs: nofree norecurse nosync nounwind readnone willreturn
+; IS__CGSCC____-LABEL: define {{[^@]+}}@potential_test13_caller2()
+; IS__CGSCC____-NEXT: [[RET:%.*]] = call i32 @potential_test13_callee(i32 1)
+; IS__CGSCC____-NEXT: ret i32 [[RET]]
+;
+ %ret = call i32 @potential_test13_callee(i32 1)
+ ret i32 %ret
+}
+
+define i32 @potential_test13_caller3() {
+; IS__TUNIT_OPM: Function Attrs: nofree nosync nounwind readnone willreturn
+; IS__TUNIT_OPM-LABEL: define {{[^@]+}}@potential_test13_caller3()
+; IS__TUNIT_OPM-NEXT: [[RET:%.*]] = call i32 @potential_test13_callee(i32 undef) [[ATTR0]], [[RNG2]]
+; IS__TUNIT_OPM-NEXT: ret i32 [[RET]]
+;
+; IS__TUNIT_NPM: Function Attrs: nofree nosync nounwind readnone willreturn
+; IS__TUNIT_NPM-LABEL: define {{[^@]+}}@potential_test13_caller3()
+; IS__TUNIT_NPM-NEXT: [[RET:%.*]] = call i32 @potential_test13_callee(i32 undef) [[ATTR0]], [[RNG0]]
+; IS__TUNIT_NPM-NEXT: ret i32 [[RET]]
+;
+; IS__CGSCC____: Function Attrs: nofree norecurse nosync nounwind readnone willreturn
+; IS__CGSCC____-LABEL: define {{[^@]+}}@potential_test13_caller3()
+; IS__CGSCC____-NEXT: [[RET:%.*]] = call i32 @potential_test13_callee(i32 undef)
+; IS__CGSCC____-NEXT: ret i32 [[RET]]
+;
+ %ret = call i32 @potential_test13_callee(i32 undef)
+ ret i32 %ret
+}
+
+define i1 @potential_test14(i1 %c0, i1 %c1, i1 %c2, i1 %c3) {
+; IS__TUNIT____: Function Attrs: nofree nosync nounwind readnone willreturn
+; IS__TUNIT____-LABEL: define {{[^@]+}}@potential_test14
+; IS__TUNIT____-SAME: (i1 [[C0:%.*]], i1 [[C1:%.*]], i1 [[C2:%.*]], i1 [[C3:%.*]])
+; IS__TUNIT____-NEXT: [[X0:%.*]] = select i1 [[C0]], i32 0, i32 1
+; IS__TUNIT____-NEXT: [[X1:%.*]] = select i1 [[C1]], i32 [[X0]], i32 undef
+; IS__TUNIT____-NEXT: [[Y2:%.*]] = select i1 [[C2]], i32 0, i32 7
+; IS__TUNIT____-NEXT: [[Z3:%.*]] = select i1 [[C3]], i32 [[X1]], i32 [[Y2]]
+; IS__TUNIT____-NEXT: [[RET:%.*]] = icmp slt i32 [[Z3]], 7
+; IS__TUNIT____-NEXT: ret i1 [[RET]]
+;
+; IS__CGSCC____: Function Attrs: nofree norecurse nosync nounwind readnone willreturn
+; IS__CGSCC____-LABEL: define {{[^@]+}}@potential_test14
+; IS__CGSCC____-SAME: (i1 [[C0:%.*]], i1 [[C1:%.*]], i1 [[C2:%.*]], i1 [[C3:%.*]])
+; IS__CGSCC____-NEXT: [[X0:%.*]] = select i1 [[C0]], i32 0, i32 1
+; IS__CGSCC____-NEXT: [[X1:%.*]] = select i1 [[C1]], i32 [[X0]], i32 undef
+; IS__CGSCC____-NEXT: [[Y2:%.*]] = select i1 [[C2]], i32 0, i32 7
+; IS__CGSCC____-NEXT: [[Z3:%.*]] = select i1 [[C3]], i32 [[X1]], i32 [[Y2]]
+; IS__CGSCC____-NEXT: [[RET:%.*]] = icmp slt i32 [[Z3]], 7
+; IS__CGSCC____-NEXT: ret i1 [[RET]]
+;
+ %x0 = select i1 %c0, i32 0, i32 1
+ %x1 = select i1 %c1, i32 %x0, i32 undef
+ %y2 = select i1 %c2, i32 0, i32 7
+ %z3 = select i1 %c3, i32 %x1, i32 %y2
+ %ret = icmp slt i32 %z3, 7
+ ret i1 %ret
+}
+
+define i1 @potential_test15(i1 %c0, i1 %c1) {
+; IS__TUNIT____: Function Attrs: nofree nosync nounwind readnone willreturn
+; IS__TUNIT____-LABEL: define {{[^@]+}}@potential_test15
+; IS__TUNIT____-SAME: (i1 [[C0:%.*]], i1 [[C1:%.*]])
+; IS__TUNIT____-NEXT: ret i1 false
+;
+; IS__CGSCC____: Function Attrs: nofree norecurse nosync nounwind readnone willreturn
+; IS__CGSCC____-LABEL: define {{[^@]+}}@potential_test15
+; IS__CGSCC____-SAME: (i1 [[C0:%.*]], i1 [[C1:%.*]])
+; IS__CGSCC____-NEXT: ret i1 false
+;
+ %x0 = select i1 %c0, i32 0, i32 1
+ %x1 = select i1 %c1, i32 %x0, i32 undef
+ %ret = icmp eq i32 %x1, 7
+ ret i1 %ret
+}
+
+define i1 @potential_test16(i1 %c0, i1 %c1) {
+; IS__TUNIT____: Function Attrs: nofree nosync nounwind readnone willreturn
+; IS__TUNIT____-LABEL: define {{[^@]+}}@potential_test16
+; IS__TUNIT____-SAME: (i1 [[C0:%.*]], i1 [[C1:%.*]])
+; IS__TUNIT____-NEXT: ret i1 false
+;
+; IS__CGSCC____: Function Attrs: nofree norecurse nosync nounwind readnone willreturn
+; IS__CGSCC____-LABEL: define {{[^@]+}}@potential_test16
+; IS__CGSCC____-SAME: (i1 [[C0:%.*]], i1 [[C1:%.*]])
+; IS__CGSCC____-NEXT: ret i1 false
+;
+ %x0 = select i1 %c0, i32 0, i32 undef
+ %x1 = select i1 %c1, i32 %x0, i32 1
+ %ret = icmp eq i32 %x1, 7
+ ret i1 %ret
+}
+
; IS__TUNIT_NPM: !0 = !{i32 0, i32 2}
; IS__TUNIT_NPM: !1 = !{i32 1, i32 4}
; IS__TUNIT_NPM: !2 = !{i32 3, i32 5}
-; IS__TUNIT_NPM: !3 = !{i32 -1, i32 2}
+; IS__TUNIT_NPM: !3 = !{i32 -1, i32 1}
; IS__TUNIT_NPM-NOT: !4
; IS__TUNIT_OPM: !0 = !{i32 1, i32 4}
; IS__TUNIT_OPM: !1 = !{i32 3, i32 5}
-; IS__TUNIT_OPM: !2 = !{i32 -1, i32 2}
-; IS__TUNIT_OPM-NOT: !3
+; IS__TUNIT_OPM: !2 = !{i32 0, i32 2}
+; IS__TUNIT_OPM: !3 = !{i32 -1, i32 1}
+; IS__TUNIT_OPM-NOT: !4
; IS__CGSCC____-NOT: !0
diff --git a/llvm/test/Transforms/Attributor/value-simplify.ll b/llvm/test/Transforms/Attributor/value-simplify.ll
index 7ae8cd378011..125d76926d09 100644
--- a/llvm/test/Transforms/Attributor/value-simplify.ll
+++ b/llvm/test/Transforms/Attributor/value-simplify.ll
@@ -644,12 +644,10 @@ for.end:
}
; Check we merge undef and a constant properly.
-; FIXME fold the addition and return the constant.
define i8 @caller0() {
; IS__TUNIT____: Function Attrs: nofree nosync nounwind readnone willreturn
; IS__TUNIT____-LABEL: define {{[^@]+}}@caller0()
-; IS__TUNIT____-NEXT: [[C:%.*]] = call i8 @callee()
-; IS__TUNIT____-NEXT: ret i8 [[C]]
+; IS__TUNIT____-NEXT: ret i8 49
;
; IS__CGSCC____: Function Attrs: nofree norecurse nosync nounwind readnone willreturn
; IS__CGSCC____-LABEL: define {{[^@]+}}@caller0()
@@ -662,8 +660,7 @@ define i8 @caller0() {
define i8 @caller1() {
; IS__TUNIT____: Function Attrs: nofree nosync nounwind readnone willreturn
; IS__TUNIT____-LABEL: define {{[^@]+}}@caller1()
-; IS__TUNIT____-NEXT: [[C:%.*]] = call i8 @callee()
-; IS__TUNIT____-NEXT: ret i8 [[C]]
+; IS__TUNIT____-NEXT: ret i8 49
;
; IS__CGSCC____: Function Attrs: nofree norecurse nosync nounwind readnone willreturn
; IS__CGSCC____-LABEL: define {{[^@]+}}@caller1()
@@ -676,8 +673,7 @@ define i8 @caller1() {
define i8 @caller2() {
; IS__TUNIT____: Function Attrs: nofree nosync nounwind readnone willreturn
; IS__TUNIT____-LABEL: define {{[^@]+}}@caller2()
-; IS__TUNIT____-NEXT: [[C:%.*]] = call i8 @callee()
-; IS__TUNIT____-NEXT: ret i8 [[C]]
+; IS__TUNIT____-NEXT: ret i8 49
;
; IS__CGSCC____: Function Attrs: nofree norecurse nosync nounwind readnone willreturn
; IS__CGSCC____-LABEL: define {{[^@]+}}@caller2()
@@ -690,8 +686,7 @@ define i8 @caller2() {
define i8 @caller_middle() {
; IS__TUNIT____: Function Attrs: nofree nosync nounwind readnone willreturn
; IS__TUNIT____-LABEL: define {{[^@]+}}@caller_middle()
-; IS__TUNIT____-NEXT: [[C:%.*]] = call i8 @callee()
-; IS__TUNIT____-NEXT: ret i8 [[C]]
+; IS__TUNIT____-NEXT: ret i8 49
;
; IS__CGSCC____: Function Attrs: nofree norecurse nosync nounwind readnone willreturn
; IS__CGSCC____-LABEL: define {{[^@]+}}@caller_middle()
@@ -704,8 +699,7 @@ define i8 @caller_middle() {
define i8 @caller3() {
; IS__TUNIT____: Function Attrs: nofree nosync nounwind readnone willreturn
; IS__TUNIT____-LABEL: define {{[^@]+}}@caller3()
-; IS__TUNIT____-NEXT: [[C:%.*]] = call i8 @callee()
-; IS__TUNIT____-NEXT: ret i8 [[C]]
+; IS__TUNIT____-NEXT: ret i8 49
;
; IS__CGSCC____: Function Attrs: nofree norecurse nosync nounwind readnone willreturn
; IS__CGSCC____-LABEL: define {{[^@]+}}@caller3()
@@ -718,8 +712,7 @@ define i8 @caller3() {
define i8 @caller4() {
; IS__TUNIT____: Function Attrs: nofree nosync nounwind readnone willreturn
; IS__TUNIT____-LABEL: define {{[^@]+}}@caller4()
-; IS__TUNIT____-NEXT: [[C:%.*]] = call i8 @callee()
-; IS__TUNIT____-NEXT: ret i8 [[C]]
+; IS__TUNIT____-NEXT: ret i8 49
;
; IS__CGSCC____: Function Attrs: nofree norecurse nosync nounwind readnone willreturn
; IS__CGSCC____-LABEL: define {{[^@]+}}@caller4()
@@ -730,15 +723,9 @@ define i8 @caller4() {
ret i8 %c
}
define internal i8 @callee(i8 %a) {
-; IS__TUNIT____: Function Attrs: nofree nosync nounwind readnone willreturn
-; IS__TUNIT____-LABEL: define {{[^@]+}}@callee()
-; IS__TUNIT____-NEXT: [[C:%.*]] = add i8 42, 7
-; IS__TUNIT____-NEXT: ret i8 [[C]]
-;
; IS__CGSCC____: Function Attrs: nofree norecurse nosync nounwind readnone willreturn
; IS__CGSCC____-LABEL: define {{[^@]+}}@callee()
-; IS__CGSCC____-NEXT: [[C:%.*]] = add i8 42, 7
-; IS__CGSCC____-NEXT: ret i8 [[C]]
+; IS__CGSCC____-NEXT: ret i8 49
;
%c = add i8 %a, 7
ret i8 %c
More information about the llvm-commits
mailing list