Index: llvm/include/llvm/Transforms/IPO/Attributor.h =================================================================== --- llvm/include/llvm/Transforms/IPO/Attributor.h +++ llvm/include/llvm/Transforms/IPO/Attributor.h @@ -3362,9 +3362,10 @@ struct PotentialValuesState : AbstractState { using SetTy = DenseSet; - 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(); } @@ -3393,11 +3394,19 @@ 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(); } @@ -3425,6 +3434,9 @@ /// 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; @@ -3446,6 +3458,10 @@ 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()) @@ -3466,9 +3482,17 @@ } 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. @@ -3485,6 +3509,8 @@ IntersectSet.insert(C); } Set = IntersectSet; + UndefIsContained &= R.undefIsContained(); + reduceUndefValue(); } /// A helper state which indicate whether this state is valid or not. @@ -3492,6 +3518,9 @@ /// Container for potential values SetTy Set; + + /// Flag for undef value + bool UndefIsContained; }; using PotentialConstantIntValuesState = PotentialValuesState; @@ -3538,8 +3567,12 @@ if (getAssumedSet().size() == 1) return cast(ConstantInt::get(getAssociatedValue().getType(), *(getAssumedSet().begin()))); - if (getAssumedSet().size() == 0) + if (getAssumedSet().size() == 0) { + if (undefIsContained()) + return cast( + ConstantInt::get(getAssociatedValue().getType(), 0)); return llvm::None; + } return nullptr; } Index: llvm/lib/Transforms/IPO/Attributor.cpp =================================================================== --- llvm/lib/Transforms/IPO/Attributor.cpp +++ llvm/lib/Transforms/IPO/Attributor.cpp @@ -2139,9 +2139,12 @@ 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; Index: llvm/lib/Transforms/IPO/AttributorAttributes.cpp =================================================================== --- llvm/lib/Transforms/IPO/AttributorAttributes.cpp +++ llvm/lib/Transforms/IPO/AttributorAttributes.cpp @@ -7266,10 +7266,7 @@ } if (isa(&V)) { - // Collapse the undef state to 0. - unionAssumed( - APInt(/* numBits */ getAssociatedType()->getIntegerBitWidth(), - /* val */ 0)); + unionAssumedWithUndef(); indicateOptimisticFixpoint(); return; } @@ -7390,6 +7387,20 @@ } } + 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 true; + } + ChangeStatus updateWithICmpInst(Attributor &A, ICmpInst *ICI) { auto AssumedBefore = getAssumed(); Value *LHS = ICI->getOperand(0); @@ -7408,16 +7419,40 @@ const DenseSet &LHSAAPVS = LHSAA.getAssumedSet(); const DenseSet &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)); @@ -7443,8 +7478,13 @@ 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; } @@ -7460,11 +7500,14 @@ if (!SrcAA.isValidState()) return indicatePessimisticFixpoint(); const DenseSet &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; } @@ -7486,19 +7529,28 @@ const DenseSet &LHSAAPVS = LHSAA.getAssumedSet(); const DenseSet &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 @@ -7513,7 +7565,10 @@ *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; Index: llvm/test/Transforms/Attributor/potential.ll =================================================================== --- llvm/test/Transforms/Attributor/potential.ll +++ llvm/test/Transforms/Attributor/potential.ll @@ -493,20 +493,6 @@ ; 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 @@ } 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,205 @@ 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 +} + ; 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