diff --git a/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp b/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp --- a/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp +++ b/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp @@ -3094,6 +3094,33 @@ return &SI; } } + + // Fold two-way clamps: + // s1 = (n < C1) ? n : C1 + // s2 = (s1 > C1 - 1) ? s1 : C1 - 1 + // into: + // s2 = C1 - 1 + (n > C1 - 1) + CmpInst::Predicate InnerPred; + if (match(CondVal, + m_ICmp(Pred, m_Specific(TrueVal), m_Specific(FalseVal))) && + match(TrueSI->getCondition(), + m_ICmp(InnerPred, m_Specific(TrueSI->getTrueValue()), + m_Specific(TrueSI->getFalseValue())))) { + ConstantInt *C1 = dyn_cast(TrueSI->getFalseValue()); + ConstantInt *C2 = dyn_cast(FalseVal); + if (C1 && C2 && + ((Pred == CmpInst::ICMP_SGT && InnerPred == CmpInst::ICMP_SLT && + C2->getValue() == C1->getValue() - 1) || + (Pred == CmpInst::ICMP_SLT && InnerPred == CmpInst::ICMP_SGT && + C2->getValue() == C1->getValue() + 1))) { + Value *NewCmp = Builder.CreateICmp(Pred, TrueSI->getTrueValue(), C2); + Value *Ext = Builder.CreateZExt(NewCmp, TrueVal->getType()); + Instruction *Add = BinaryOperator::Create( + Pred == CmpInst::ICMP_SGT ? Instruction::Add : Instruction::Sub, C2, + Ext); + return Add; + } + } } if (SelectInst *FalseSI = dyn_cast(FalseVal)) { if (FalseSI->getCondition()->getType() == CondVal->getType()) { diff --git a/llvm/test/Transforms/InstCombine/icmp-dom.ll b/llvm/test/Transforms/InstCombine/icmp-dom.ll --- a/llvm/test/Transforms/InstCombine/icmp-dom.ll +++ b/llvm/test/Transforms/InstCombine/icmp-dom.ll @@ -9,8 +9,8 @@ ; CHECK: land.lhs.true: ; CHECK-NEXT: br label [[LOR_END:%.*]] ; CHECK: lor.rhs: -; CHECK-NEXT: [[CMP2:%.*]] = icmp eq i64 [[A]], 0 -; CHECK-NEXT: br i1 [[CMP2]], label [[LOR_END]], label [[LAND_RHS:%.*]] +; CHECK-NEXT: [[CMP2_NOT:%.*]] = icmp eq i64 [[A]], 0 +; CHECK-NEXT: br i1 [[CMP2_NOT]], label [[LOR_END]], label [[LAND_RHS:%.*]] ; CHECK: land.rhs: ; CHECK-NEXT: br label [[LOR_END]] ; CHECK: lor.end: @@ -393,13 +393,13 @@ define i8 @PR48900_alt(i8 %i, i1* %p) { ; CHECK-LABEL: @PR48900_alt( -; CHECK-NEXT: [[MAXCMP:%.*]] = icmp sgt i8 [[I:%.*]], -127 -; CHECK-NEXT: [[SMAX:%.*]] = select i1 [[MAXCMP]], i8 [[I]], i8 -127 -; CHECK-NEXT: [[I4:%.*]] = icmp ugt i8 [[SMAX]], -128 +; CHECK-NEXT: [[MAXCMP:%.*]] = icmp slt i8 [[I:%.*]], -126 +; CHECK-NEXT: [[I41:%.*]] = icmp ugt i8 [[I]], -128 +; CHECK-NEXT: [[I4:%.*]] = or i1 [[MAXCMP]], [[I41]] ; CHECK-NEXT: br i1 [[I4]], label [[TRUELABEL:%.*]], label [[FALSELABEL:%.*]] ; CHECK: truelabel: -; CHECK-NEXT: [[MINCMP:%.*]] = icmp slt i8 [[SMAX]], -126 -; CHECK-NEXT: [[UMIN:%.*]] = select i1 [[MINCMP]], i8 [[SMAX]], i8 -126 +; CHECK-NEXT: [[TMP1:%.*]] = icmp slt i8 [[I]], -126 +; CHECK-NEXT: [[UMIN:%.*]] = select i1 [[TMP1]], i8 -127, i8 -126 ; CHECK-NEXT: ret i8 [[UMIN]] ; CHECK: falselabel: ; CHECK-NEXT: ret i8 0 diff --git a/llvm/test/Transforms/InstCombine/minmax-fold.ll b/llvm/test/Transforms/InstCombine/minmax-fold.ll --- a/llvm/test/Transforms/InstCombine/minmax-fold.ll +++ b/llvm/test/Transforms/InstCombine/minmax-fold.ll @@ -537,14 +537,11 @@ ; (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: br i1 true, 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-NEXT: [[TMP1:%.*]] = icmp slt i32 [[I:%.*]], 2 +; CHECK-NEXT: [[I6:%.*]] = select i1 [[TMP1]], i32 4, i32 8 +; CHECK-NEXT: ret i32 [[I6]] ; CHECK: falselabel: ; CHECK-NEXT: ret i32 0 ; @@ -1463,3 +1460,52 @@ %r = extractelement <2 x i8> %not, i32 1 ret i8 %r } + +define i32 @twoway_clamp_lt(i32 %num) { +; CHECK-LABEL: @twoway_clamp_lt( +; CHECK-NEXT: entry: +; CHECK-NEXT: [[TMP0:%.*]] = icmp sgt i32 [[NUM:%.*]], 13767 +; CHECK-NEXT: [[R:%.*]] = select i1 [[TMP0]], i32 13768, i32 13767 +; CHECK-NEXT: ret i32 [[R]] +; +entry: + %cmp1 = icmp slt i32 %num, 13768 + %s1 = select i1 %cmp1, i32 %num, i32 13768 + %cmp2 = icmp sgt i32 %s1, 13767 + %r = select i1 %cmp2, i32 %s1, i32 13767 + ret i32 %r +} + +define i32 @twoway_clamp_gt(i32 %num) { +; CHECK-LABEL: @twoway_clamp_gt( +; CHECK-NEXT: entry: +; CHECK-NEXT: [[TMP0:%.*]] = icmp slt i32 [[NUM:%.*]], 13768 +; CHECK-NEXT: [[R:%.*]] = select i1 [[TMP0]], i32 13767, i32 13768 +; CHECK-NEXT: ret i32 [[R]] +; +entry: + %cmp1 = icmp sgt i32 %num, 13767 + %s1 = select i1 %cmp1, i32 %num, i32 13767 + %cmp2 = icmp slt i32 %s1, 13768 + %r = select i1 %cmp2, i32 %s1, i32 13768 + ret i32 %r +} + +define i32 @twoway_clamp_gt_nonconst(i32 %num, i32 %k) { +; CHECK-LABEL: @twoway_clamp_gt_nonconst( +; CHECK-NEXT: entry: +; CHECK-NEXT: [[K1:%.*]] = add i32 [[K:%.*]], 1 +; CHECK-NEXT: [[CMP1:%.*]] = icmp sgt i32 [[NUM:%.*]], [[K]] +; CHECK-NEXT: [[S1:%.*]] = select i1 [[CMP1]], i32 [[NUM]], i32 [[K]] +; CHECK-NEXT: [[CMP2:%.*]] = icmp slt i32 [[S1]], [[K1]] +; CHECK-NEXT: [[R:%.*]] = select i1 [[CMP2]], i32 [[S1]], i32 [[K1]] +; CHECK-NEXT: ret i32 [[R]] +; +entry: + %k1 = add i32 %k, 1 + %cmp1 = icmp sgt i32 %num, %k + %s1 = select i1 %cmp1, i32 %num, i32 %k + %cmp2 = icmp slt i32 %s1, %k1 + %r = select i1 %cmp2, i32 %s1, i32 %k1 + ret i32 %r +}