Index: lib/Transforms/InstCombine/InstCombineCompares.cpp =================================================================== --- lib/Transforms/InstCombine/InstCombineCompares.cpp +++ lib/Transforms/InstCombine/InstCombineCompares.cpp @@ -1362,7 +1362,8 @@ } /// Canonicalize icmp instructions based on dominating conditions. -Instruction *InstCombiner::foldICmpWithDominatingICmp(ICmpInst &Cmp) { +Instruction *InstCombiner::foldICmpWithDominatingICmp(ICmpInst &Cmp, + bool CmpUsedInMinMax) { // This is a cheap/incomplete check for dominance - just match a single // predecessor with a conditional branch. BasicBlock *CmpBB = Cmp.getParent(); @@ -1421,9 +1422,11 @@ bool IsSignBit = isSignBitCheck(Pred, *C, UnusedBit); if (Cmp.isEquality() || (IsSignBit && hasBranchUse(Cmp))) return nullptr; - - if (const APInt *EqC = Intersection.getSingleElement()) - return new ICmpInst(ICmpInst::ICMP_EQ, X, Builder.getInt(*EqC)); + // This next case can cause an infinite loop if we end up decanonicalizing a + // min/max sequence involving a select. + if (!CmpUsedInMinMax) + if (const APInt *EqC = Intersection.getSingleElement()) + return new ICmpInst(ICmpInst::ICMP_EQ, X, Builder.getInt(*EqC)); if (const APInt *NeC = Difference.getSingleElement()) return new ICmpInst(ICmpInst::ICMP_NE, X, Builder.getInt(*NeC)); } @@ -4891,6 +4894,23 @@ Changed = true; } + // Test if the ICmpInst instruction is used exclusively by a select as + // part of a minimum or maximum operation. If so, refrain from doing + // any other folding. This helps out other analyses which understand + // non-obfuscated minimum and maximum idioms, such as ScalarEvolution + // and CodeGen. And in this case, at least one of the comparison + // operands has at least one user besides the compare (the select), + // which would often largely negate the benefit of folding anyway. + // + // Do the same for the other patterns recognized by matchSelectPattern. + bool CmpUsedInMinMax = false; + if (I.hasOneUse()) + if (SelectInst *SI = dyn_cast(I.user_back())) { + Value *A, *B; + SelectPatternResult SPR = matchSelectPattern(SI, A, B); + CmpUsedInMinMax = SPR.Flavor != SPF_UNKNOWN; + } + if (Value *V = SimplifyICmpInst(I.getPredicate(), Op0, Op1, SQ.getWithInstruction(&I))) return replaceInstUsesWith(I, V); @@ -4922,28 +4942,14 @@ if (Instruction *Res = foldICmpWithConstant(I)) return Res; - if (Instruction *Res = foldICmpWithDominatingICmp(I)) + if (Instruction *Res = foldICmpWithDominatingICmp(I, CmpUsedInMinMax)) return Res; if (Instruction *Res = foldICmpUsingKnownBits(I)) return Res; - // Test if the ICmpInst instruction is used exclusively by a select as - // part of a minimum or maximum operation. If so, refrain from doing - // any other folding. This helps out other analyses which understand - // non-obfuscated minimum and maximum idioms, such as ScalarEvolution - // and CodeGen. And in this case, at least one of the comparison - // operands has at least one user besides the compare (the select), - // which would often largely negate the benefit of folding anyway. - // - // Do the same for the other patterns recognized by matchSelectPattern. - if (I.hasOneUse()) - if (SelectInst *SI = dyn_cast(I.user_back())) { - Value *A, *B; - SelectPatternResult SPR = matchSelectPattern(SI, A, B); - if (SPR.Flavor != SPF_UNKNOWN) - return nullptr; - } + if (CmpUsedInMinMax) + return nullptr; // Do this after checking for min/max to prevent infinite looping. if (Instruction *Res = foldICmpWithZero(I)) Index: lib/Transforms/InstCombine/InstCombineInternal.h =================================================================== --- lib/Transforms/InstCombine/InstCombineInternal.h +++ lib/Transforms/InstCombine/InstCombineInternal.h @@ -859,7 +859,7 @@ Instruction *foldICmpWithCastAndCast(ICmpInst &ICI); Instruction *foldICmpUsingKnownBits(ICmpInst &Cmp); - Instruction *foldICmpWithDominatingICmp(ICmpInst &Cmp); + Instruction *foldICmpWithDominatingICmp(ICmpInst &Cmp, bool CmpUsedInMinMax); Instruction *foldICmpWithConstant(ICmpInst &Cmp); Instruction *foldICmpInstWithConstant(ICmpInst &Cmp); Instruction *foldICmpInstWithConstantNotInt(ICmpInst &Cmp); Index: test/Transforms/InstCombine/icmp-dom.ll =================================================================== --- test/Transforms/InstCombine/icmp-dom.ll +++ test/Transforms/InstCombine/icmp-dom.ll @@ -160,6 +160,34 @@ ret void } +define void @trueblock_cmp_eq(i32 %a, i32 %b) { +; CHECK-LABEL: @trueblock_cmp_eq( +; CHECK-NEXT: entry: +; CHECK-NEXT: [[CMP:%.*]] = icmp sgt i32 [[A:%.*]], 0 +; CHECK-NEXT: br i1 [[CMP]], label [[IF_END:%.*]], label [[RETURN:%.*]] +; CHECK: if.end: +; CHECK-NEXT: [[CMP1:%.*]] = icmp eq i32 [[A]], 1 +; CHECK-NEXT: br i1 [[CMP1]], label [[IF_THEN3:%.*]], label [[RETURN]] +; CHECK: if.then3: +; CHECK-NEXT: br label [[RETURN]] +; CHECK: return: +; CHECK-NEXT: ret void +; +entry: + %cmp = icmp sgt i32 %a, 0 + br i1 %cmp, label %if.end, label %return + +if.end: + %cmp1 = icmp slt i32 %a, 2 + br i1 %cmp1, label %if.then3, label %return + +if.then3: + br label %return + +return: + ret void +} + define i1 @trueblock_cmp_is_false(i32 %x, i32 %y) { ; CHECK-LABEL: @trueblock_cmp_is_false( ; CHECK-NEXT: entry: Index: test/Transforms/InstCombine/minmax-fold.ll =================================================================== --- test/Transforms/InstCombine/minmax-fold.ll +++ test/Transforms/InstCombine/minmax-fold.ll @@ -533,6 +533,38 @@ ret i32 %res } +; Check that there is no infinite loop because of reverse cmp transformation: +; (icmp slt smax(PositiveA, B) 2) -> (icmp eq B 1) +define i32 @clamp_check_for_no_infinite_loop3(i32 %i) { +; CHECK-LABEL: @clamp_check_for_no_infinite_loop3( +; CHECK-NEXT: [[I2:%.*]] = icmp sgt i32 [[I:%.*]], 1 +; CHECK-NEXT: [[I3:%.*]] = select i1 [[I2]], i32 [[I]], i32 1 +; CHECK-NEXT: [[I4:%.*]] = icmp sgt i32 [[I3]], 0 +; CHECK-NEXT: br i1 [[I4]], label [[TRUELABEL:%.*]], label [[FALSELABEL:%.*]] +; CHECK: truelabel: +; CHECK-NEXT: [[I5:%.*]] = icmp slt i32 [[I3]], 2 +; CHECK-NEXT: [[I6:%.*]] = select i1 [[I5]], i32 [[I3]], i32 2 +; CHECK-NEXT: [[I7:%.*]] = shl nuw nsw i32 [[I6]], 2 +; CHECK-NEXT: ret i32 [[I7]] +; CHECK: falselabel: +; CHECK-NEXT: ret i32 0 +; + + %i2 = icmp sgt i32 %i, 1 + %i3 = select i1 %i2, i32 %i, i32 1 + %i4 = icmp sgt i32 %i3, 0 + br i1 %i4, label %truelabel, label %falselabel + +truelabel: ; %i<=1, %i3>0 + %i5 = icmp slt i32 %i3, 2 + %i6 = select i1 %i5, i32 %i3, i32 2 + %i7 = shl nuw nsw i32 %i6, 2 + ret i32 %i7 + +falselabel: + ret i32 0 +} + ; The next 3 min tests should canonicalize to the same form...and not infinite loop. define double @PR31751_umin1(i32 %x) {