[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
This commit is contained in:
Shinji Okumura 2020-08-27 16:30:29 +09:00
parent 03141aa04a
commit 6c25eca614
5 changed files with 469 additions and 82 deletions

View File

@ -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 @@ private:
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 @@ private:
}
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 @@ private:
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 @@ private:
/// 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;
}

View File

@ -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;

View File

@ -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();
// If SkipOperation is true, we can ignore this operand pair (L, R).
if (!SkipOperation)
unionAssumed(Result);
}
} else if (RHSAA.undefIsContained()) {
for (const APInt &L : LHSAAPVS) {
if (!calculateBinaryOperatorAndTakeUnion(BinOp, L, Zero))
return indicatePessimisticFixpoint();
}
} 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;
}

View File

@ -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

View File

@ -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