diff --git a/llvm/lib/Transforms/Scalar/SCCP.cpp b/llvm/lib/Transforms/Scalar/SCCP.cpp --- a/llvm/lib/Transforms/Scalar/SCCP.cpp +++ b/llvm/lib/Transforms/Scalar/SCCP.cpp @@ -1241,24 +1241,19 @@ if (auto *II = dyn_cast(I)) { if (II->getIntrinsicID() == Intrinsic::ssa_copy) { - if (isOverdefined(ValueState[I])) - return (void)markOverdefined(I); - - auto *PI = getPredicateInfoFor(I); - if (!PI) + if (ValueState[I].isOverdefined()) return; Value *CopyOf = I->getOperand(0); - auto *PBranch = dyn_cast(PI); - if (!PBranch) { + auto *PI = getPredicateInfoFor(I); + auto *PBranch = dyn_cast_or_null(PI); + if (!PI || !PBranch) { mergeInValue(ValueState[I], I, getValueState(CopyOf)); return; } - Value *Cond = PBranch->Condition; - // Everything below relies on the condition being a comparison. - auto *Cmp = dyn_cast(Cond); + auto *Cmp = dyn_cast(PBranch->Condition); if (!Cmp) { mergeInValue(ValueState[I], I, getValueState(CopyOf)); return; @@ -1271,26 +1266,49 @@ return; } - if (CmpOp0 != CopyOf) + auto Pred = Cmp->getPredicate(); + if (CmpOp0 != CopyOf) { std::swap(CmpOp0, CmpOp1); + Pred = Cmp->getSwappedPredicate(); + } - LatticeVal OriginalVal = getValueState(CopyOf); - LatticeVal EqVal = getValueState(CmpOp1); - LatticeVal &IV = ValueState[I]; - if (PBranch->TrueEdge && Cmp->getPredicate() == CmpInst::ICMP_EQ) { + // Wait until CmpOp1 is resolved. + if (getValueState(CmpOp1).isUnknown()) { addAdditionalUser(CmpOp1, I); - if (isConstant(OriginalVal)) - mergeInValue(IV, I, OriginalVal); - else - mergeInValue(IV, I, EqVal); return; } - if (!PBranch->TrueEdge && Cmp->getPredicate() == CmpInst::ICMP_NE) { + + if (!PBranch->TrueEdge) + Pred = CmpInst::getInversePredicate(Pred); + + LatticeVal CondVal = getValueState(CmpOp1); + LatticeVal &IV = ValueState[I]; + LatticeVal OriginalVal = getValueState(CopyOf); + if (CondVal.isConstantRange() || OriginalVal.isConstantRange()) { + auto NewCR = + ConstantRange::getFull(DL.getTypeSizeInBits(CopyOf->getType())); + + // Get the range imposed by the condition. + if (CondVal.isConstantRange()) + NewCR = ConstantRange::makeAllowedICmpRegion( + Pred, CondVal.getConstantRange()); + + // Combine range info for the original value with the new range from the + // condition. + auto OriginalCR = OriginalVal.isConstantRange() + ? OriginalVal.getConstantRange() + : ConstantRange::getFull( + DL.getTypeSizeInBits(CopyOf->getType())); + NewCR = NewCR.intersectWith(OriginalCR); + + addAdditionalUser(CmpOp1, I); + mergeInValue(IV, I, LatticeVal::getRange(NewCR)); + return; + } else if (Pred == CmpInst::ICMP_EQ && CondVal.isConstant()) { + // For non-integer values or integer constant expressions, only + // propagate equal constants. addAdditionalUser(CmpOp1, I); - if (isConstant(OriginalVal)) - mergeInValue(IV, I, OriginalVal); - else - mergeInValue(IV, I, EqVal); + mergeInValue(IV, I, CondVal); return; } diff --git a/llvm/test/Transforms/SCCP/conditions-ranges.ll b/llvm/test/Transforms/SCCP/conditions-ranges.ll --- a/llvm/test/Transforms/SCCP/conditions-ranges.ll +++ b/llvm/test/Transforms/SCCP/conditions-ranges.ll @@ -11,16 +11,11 @@ ; CHECK-NEXT: [[BC:%.*]] = icmp ugt i32 [[B:%.*]], [[A_2]] ; CHECK-NEXT: br i1 [[BC]], label [[TRUE:%.*]], label [[FALSE:%.*]] ; CHECK: true: -; CHECK-NEXT: [[F_1:%.*]] = icmp eq i32 [[B]], 0 -; CHECK-NEXT: call void @use(i1 [[F_1]]) -; CHECK-NEXT: [[F_2:%.*]] = icmp eq i32 [[B]], 20 -; CHECK-NEXT: call void @use(i1 [[F_2]]) -; CHECK-NEXT: [[F_3:%.*]] = icmp ult i32 [[B]], 20 -; CHECK-NEXT: call void @use(i1 [[F_3]]) -; CHECK-NEXT: [[T_1:%.*]] = icmp ugt i32 [[B]], 5 -; CHECK-NEXT: call void @use(i1 [[T_1]]) -; CHECK-NEXT: [[T_2:%.*]] = icmp ne i32 [[B]], 20 -; CHECK-NEXT: call void @use(i1 [[T_2]]) +; CHECK-NEXT: call void @use(i1 false) +; CHECK-NEXT: call void @use(i1 false) +; CHECK-NEXT: call void @use(i1 false) +; CHECK-NEXT: call void @use(i1 true) +; CHECK-NEXT: call void @use(i1 true) ; CHECK-NEXT: [[C_1:%.*]] = icmp eq i32 [[B]], 21 ; CHECK-NEXT: call void @use(i1 [[C_1]]) ; CHECK-NEXT: [[C_2:%.*]] = icmp ugt i32 [[B]], 21 @@ -29,14 +24,10 @@ ; CHECK-NEXT: call void @use(i1 [[C_3]]) ; CHECK-NEXT: ret void ; CHECK: false: -; CHECK-NEXT: [[F_4:%.*]] = icmp eq i32 [[B]], 276 -; CHECK-NEXT: call void @use(i1 [[F_4]]) -; CHECK-NEXT: [[F_5:%.*]] = icmp ugt i32 [[B]], 275 -; CHECK-NEXT: call void @use(i1 [[F_5]]) -; CHECK-NEXT: [[T_3:%.*]] = icmp ne i32 [[B]], 276 -; CHECK-NEXT: call void @use(i1 [[T_3]]) -; CHECK-NEXT: [[T_4:%.*]] = icmp ule i32 [[B]], 275 -; CHECK-NEXT: call void @use(i1 [[T_4]]) +; CHECK-NEXT: call void @use(i1 false) +; CHECK-NEXT: call void @use(i1 false) +; CHECK-NEXT: call void @use(i1 true) +; CHECK-NEXT: call void @use(i1 true) ; CHECK-NEXT: [[C_4:%.*]] = icmp eq i32 [[B]], 21 ; CHECK-NEXT: call void @use(i1 [[C_4]]) ; CHECK-NEXT: [[C_5:%.*]] = icmp eq i32 [[B]], 275 @@ -279,24 +270,15 @@ ; CHECK-NEXT: [[BC_2:%.*]] = icmp ult i32 [[B]], 255 ; CHECK-NEXT: br i1 [[BC_2]], label [[TRUE_2:%.*]], label [[FALSE_2:%.*]] ; CHECK: true.2: -; CHECK-NEXT: [[F_1:%.*]] = icmp eq i32 [[B]], 0 -; CHECK-NEXT: call void @use(i1 [[F_1]]) -; CHECK-NEXT: [[F_2:%.*]] = icmp eq i32 [[B]], 20 -; CHECK-NEXT: call void @use(i1 [[F_2]]) -; CHECK-NEXT: [[F_3:%.*]] = icmp ult i32 [[B]], 20 -; CHECK-NEXT: call void @use(i1 [[F_3]]) -; CHECK-NEXT: [[F_4:%.*]] = icmp eq i32 [[B]], 255 -; CHECK-NEXT: call void @use(i1 [[F_4]]) -; CHECK-NEXT: [[F_5:%.*]] = icmp ugt i32 [[B]], 255 -; CHECK-NEXT: call void @use(i1 [[F_5]]) -; CHECK-NEXT: [[T_1:%.*]] = icmp ugt i32 [[B]], 5 -; CHECK-NEXT: call void @use(i1 [[T_1]]) -; CHECK-NEXT: [[T_2:%.*]] = icmp ne i32 [[B]], 20 -; CHECK-NEXT: call void @use(i1 [[T_2]]) -; CHECK-NEXT: [[T_3:%.*]] = icmp ult i32 [[B]], 255 -; CHECK-NEXT: call void @use(i1 [[T_3]]) -; CHECK-NEXT: [[T_4:%.*]] = icmp ne i32 [[B]], 300 -; CHECK-NEXT: call void @use(i1 [[T_4]]) +; CHECK-NEXT: call void @use(i1 false) +; CHECK-NEXT: call void @use(i1 false) +; CHECK-NEXT: call void @use(i1 false) +; CHECK-NEXT: call void @use(i1 false) +; CHECK-NEXT: call void @use(i1 false) +; CHECK-NEXT: call void @use(i1 true) +; CHECK-NEXT: call void @use(i1 true) +; CHECK-NEXT: call void @use(i1 true) +; CHECK-NEXT: call void @use(i1 true) ; CHECK-NEXT: [[C_1:%.*]] = icmp eq i32 [[B]], 21 ; CHECK-NEXT: call void @use(i1 [[C_1]]) ; CHECK-NEXT: [[C_2:%.*]] = icmp ugt i32 [[B]], 21 @@ -305,14 +287,10 @@ ; CHECK-NEXT: call void @use(i1 [[C_3]]) ; CHECK-NEXT: ret void ; CHECK: false.2: -; CHECK-NEXT: [[F_6:%.*]] = icmp eq i32 [[B]], 254 -; CHECK-NEXT: call void @use(i1 [[F_6]]) -; CHECK-NEXT: [[F_7:%.*]] = icmp ult i32 [[B]], 255 -; CHECK-NEXT: call void @use(i1 [[F_7]]) -; CHECK-NEXT: [[T_5:%.*]] = icmp ne i32 [[B]], 254 -; CHECK-NEXT: call void @use(i1 [[T_5]]) -; CHECK-NEXT: [[T_6:%.*]] = icmp uge i32 [[B]], 255 -; CHECK-NEXT: call void @use(i1 [[T_6]]) +; CHECK-NEXT: call void @use(i1 false) +; CHECK-NEXT: call void @use(i1 false) +; CHECK-NEXT: call void @use(i1 true) +; CHECK-NEXT: call void @use(i1 true) ; CHECK-NEXT: [[C_4:%.*]] = icmp eq i32 [[B]], 255 ; CHECK-NEXT: call void @use(i1 [[C_4]]) ; CHECK-NEXT: [[C_5:%.*]] = icmp ne i32 [[B]], 275 @@ -395,14 +373,10 @@ ; CHECK-NEXT: [[BC_1:%.*]] = icmp ugt i32 [[B:%.*]], 10 ; CHECK-NEXT: br i1 [[BC_1]], label [[TRUE:%.*]], label [[FALSE:%.*]] ; CHECK: true: -; CHECK-NEXT: [[F_1:%.*]] = icmp eq i32 [[B]], 0 -; CHECK-NEXT: call void @use(i1 [[F_1]]) -; CHECK-NEXT: [[F_2:%.*]] = icmp eq i32 [[B]], 10 -; CHECK-NEXT: call void @use(i1 [[F_2]]) -; CHECK-NEXT: [[T_1:%.*]] = icmp ugt i32 [[B]], 5 -; CHECK-NEXT: call void @use(i1 [[T_1]]) -; CHECK-NEXT: [[T_2:%.*]] = icmp ne i32 [[B]], 10 -; CHECK-NEXT: call void @use(i1 [[T_2]]) +; CHECK-NEXT: call void @use(i1 false) +; CHECK-NEXT: call void @use(i1 false) +; CHECK-NEXT: call void @use(i1 true) +; CHECK-NEXT: call void @use(i1 true) ; CHECK-NEXT: [[C_1:%.*]] = icmp eq i32 [[B]], 11 ; CHECK-NEXT: call void @use(i1 [[C_1]]) ; CHECK-NEXT: [[C_2:%.*]] = icmp ugt i32 [[B]], 11 @@ -410,14 +384,10 @@ ; CHECK-NEXT: [[BC_2:%.*]] = icmp ugt i32 [[B]], 20 ; CHECK-NEXT: br i1 [[BC_2]], label [[TRUE_2:%.*]], label [[FALSE_2:%.*]] ; CHECK: true.2: -; CHECK-NEXT: [[F_3:%.*]] = icmp eq i32 [[B]], 11 -; CHECK-NEXT: call void @use(i1 [[F_3]]) -; CHECK-NEXT: [[F_4:%.*]] = icmp eq i32 [[B]], 20 -; CHECK-NEXT: call void @use(i1 [[F_4]]) -; CHECK-NEXT: [[T_3:%.*]] = icmp ugt i32 [[B]], 11 -; CHECK-NEXT: call void @use(i1 [[T_3]]) -; CHECK-NEXT: [[T_4:%.*]] = icmp ne i32 [[B]], 20 -; CHECK-NEXT: call void @use(i1 [[T_4]]) +; CHECK-NEXT: call void @use(i1 false) +; CHECK-NEXT: call void @use(i1 false) +; CHECK-NEXT: call void @use(i1 true) +; CHECK-NEXT: call void @use(i1 true) ; CHECK-NEXT: [[C_3:%.*]] = icmp eq i32 [[B]], 21 ; CHECK-NEXT: call void @use(i1 [[C_3]]) ; CHECK-NEXT: [[C_4:%.*]] = icmp ugt i32 [[B]], 21 @@ -426,18 +396,12 @@ ; CHECK-NEXT: call void @use(i1 [[C_5]]) ; CHECK-NEXT: ret void ; CHECK: false.2: -; CHECK-NEXT: [[F_5:%.*]] = icmp eq i32 [[B]], 21 -; CHECK-NEXT: call void @use(i1 [[F_5]]) -; CHECK-NEXT: [[F_6:%.*]] = icmp ugt i32 [[B]], 21 -; CHECK-NEXT: call void @use(i1 [[F_6]]) -; CHECK-NEXT: [[F_7:%.*]] = icmp ne i32 [[B]], 5 -; CHECK-NEXT: call void @use(i1 [[F_7]]) -; CHECK-NEXT: [[T_5:%.*]] = icmp ne i32 [[B]], 21 -; CHECK-NEXT: call void @use(i1 [[T_5]]) -; CHECK-NEXT: [[T_6:%.*]] = icmp ult i32 [[B]], 21 -; CHECK-NEXT: call void @use(i1 [[T_6]]) -; CHECK-NEXT: [[T_7:%.*]] = icmp ne i32 [[B]], 5 -; CHECK-NEXT: call void @use(i1 [[T_7]]) +; CHECK-NEXT: call void @use(i1 false) +; CHECK-NEXT: call void @use(i1 false) +; CHECK-NEXT: call void @use(i1 true) +; CHECK-NEXT: call void @use(i1 true) +; CHECK-NEXT: call void @use(i1 true) +; CHECK-NEXT: call void @use(i1 true) ; CHECK-NEXT: [[C_6:%.*]] = icmp eq i32 [[B]], 11 ; CHECK-NEXT: call void @use(i1 [[C_6]]) ; CHECK-NEXT: [[C_7:%.*]] = icmp ne i32 [[B]], 15 @@ -530,18 +494,12 @@ ; CHECK-NEXT: [[B_255:%.*]] = and i32 [[B:%.*]], 255 ; CHECK-NEXT: br label [[TRUE:%.*]] ; CHECK: true: -; CHECK-NEXT: [[F_1:%.*]] = icmp eq i32 [[B_255]], 256 -; CHECK-NEXT: call void @use(i1 [[F_1]]) -; CHECK-NEXT: [[F_2:%.*]] = icmp eq i32 [[B_255]], 300 -; CHECK-NEXT: call void @use(i1 [[F_2]]) -; CHECK-NEXT: [[T_1:%.*]] = icmp ult i32 [[B_255]], 256 -; CHECK-NEXT: call void @use(i1 [[T_1]]) -; CHECK-NEXT: [[T_2:%.*]] = icmp ult i32 [[B_255]], 300 -; CHECK-NEXT: call void @use(i1 [[T_2]]) -; CHECK-NEXT: [[T_3:%.*]] = icmp ne i32 [[B_255]], 256 -; CHECK-NEXT: call void @use(i1 [[T_3]]) -; CHECK-NEXT: [[T_4:%.*]] = icmp ne i32 [[B_255]], 300 -; CHECK-NEXT: call void @use(i1 [[T_4]]) +; CHECK-NEXT: call void @use(i1 false) +; CHECK-NEXT: call void @use(i1 false) +; CHECK-NEXT: call void @use(i1 true) +; CHECK-NEXT: call void @use(i1 true) +; CHECK-NEXT: call void @use(i1 true) +; CHECK-NEXT: call void @use(i1 true) ; CHECK-NEXT: [[C_1:%.*]] = icmp eq i32 [[B_255]], 11 ; CHECK-NEXT: call void @use(i1 [[C_1]]) ; CHECK-NEXT: [[C_2:%.*]] = icmp ugt i32 [[B_255]], 30 @@ -649,10 +607,8 @@ ; CHECK-NEXT: [[BC_1:%.*]] = icmp eq i32 add (i32 ptrtoint (i32* @A to i32), i32 10), 55 ; CHECK-NEXT: br i1 [[BC_1]], label [[TRUE:%.*]], label [[FALSE:%.*]] ; CHECK: true: -; CHECK-NEXT: [[F_1:%.*]] = icmp eq i32 add (i32 ptrtoint (i32* @A to i32), i32 10), 10 -; CHECK-NEXT: call void @use(i1 [[F_1]]) -; CHECK-NEXT: [[F_2:%.*]] = icmp eq i32 add (i32 ptrtoint (i32* @A to i32), i32 10), 55 -; CHECK-NEXT: call void @use(i1 [[F_2]]) +; CHECK-NEXT: call void @use(i1 false) +; CHECK-NEXT: call void @use(i1 true) ; CHECK-NEXT: ret void ; CHECK: false: ; CHECK-NEXT: ret void @@ -680,8 +636,8 @@ ; CHECK-NEXT: entry: ; CHECK-NEXT: br i1 icmp eq (i32 ptrtoint (i32* @A to i32), i32 ptrtoint (i32* @B to i32)), label [[TRUE:%.*]], label [[FALSE:%.*]] ; CHECK: true: -; CHECK-NEXT: call void @use(i1 icmp ne (i32 ptrtoint (i32* @A to i32), i32 ptrtoint (i32* @B to i32))) -; CHECK-NEXT: call void @use(i1 icmp eq (i32 ptrtoint (i32* @A to i32), i32 ptrtoint (i32* @B to i32))) +; CHECK-NEXT: call void @use(i1 icmp ne (i32 ptrtoint (i32* @B to i32), i32 ptrtoint (i32* @A to i32))) +; CHECK-NEXT: call void @use(i1 icmp eq (i32 ptrtoint (i32* @B to i32), i32 ptrtoint (i32* @A to i32))) ; CHECK-NEXT: ret void ; CHECK: false: ; CHECK-NEXT: ret void @@ -830,10 +786,9 @@ ; CHECK-NEXT: [[CMP:%.*]] = icmp ugt i64 [[SZ:%.*]], 4088 ; CHECK-NEXT: br i1 [[CMP]], label [[COND_TRUE:%.*]], label [[COND_END:%.*]] ; CHECK: cond.true: -; CHECK-NEXT: [[DIV:%.*]] = udiv i64 4088, [[SZ]] ; CHECK-NEXT: br label [[COND_END]] ; CHECK: cond.end: -; CHECK-NEXT: [[COND:%.*]] = phi i64 [ [[DIV]], [[COND_TRUE]] ], [ 1, [[ENTRY:%.*]] ] +; CHECK-NEXT: [[COND:%.*]] = phi i64 [ 0, [[COND_TRUE]] ], [ 1, [[ENTRY:%.*]] ] ; CHECK-NEXT: [[CONV:%.*]] = trunc i64 [[COND]] to i32 ; CHECK-NEXT: ret i32 [[CONV]] ; diff --git a/llvm/test/Transforms/SCCP/ip-constant-ranges.ll b/llvm/test/Transforms/SCCP/ip-constant-ranges.ll --- a/llvm/test/Transforms/SCCP/ip-constant-ranges.ll +++ b/llvm/test/Transforms/SCCP/ip-constant-ranges.ll @@ -84,9 +84,7 @@ } ; CHECK-LABEL: f4 -; CHECK: %cmp = icmp sgt i32 %x, 300 -; CHECK: %res = select i1 %cmp, i32 1, i32 2 -; CHECK: ret i32 %res +; CHECK: ret i32 undef define internal i32 @f4(i32 %x) { entry: %cmp = icmp sgt i32 %x, 300 @@ -94,8 +92,13 @@ ret i32 %res } -; ICmp could introduce bounds on ConstantRanges. +; ICmp introduces bounds on ConstantRanges. define i32 @caller3(i32 %x) { +; CHECK-LABEL: define i32 @caller3(i32 %x) +; CHECK-LABEL: end: +; CHECK-NEXT: %res = phi i32 [ 0, %entry ], [ 1, %if.true ] +; CHECK-NEXT: ret i32 %res +; entry: %cmp = icmp sgt i32 %x, 300 br i1 %cmp, label %if.true, label %end