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 @@ -3178,6 +3178,27 @@ return &SI; } } + + // Fold two-way clamps: + // s1 = (n < C1) ? n : C1 + // s2 = (s1 > C1 - 1) ? s1 : C2 (C2 == C1 - 1) + // into: + // s2 = n > C1 - 1 ? C1 : C2 + const APInt *C1, *C2; + if (match(TrueSI->getFalseValue(), m_APInt(C1)) && + match(FalseVal, m_APInt(C2))) { + Value *Inner, *N, *InnerC; + auto OuterFlavor = matchSelectPattern(&SI, Inner, FalseVal).Flavor; + auto InnerFlavor = matchSelectPattern(TrueVal, N, InnerC).Flavor; + Pred = cast(SI.getCondition())->getPredicate(); + if ((OuterFlavor == SelectPatternFlavor::SPF_SMAX && + InnerFlavor == SelectPatternFlavor::SPF_SMIN && *C2 == *C1 - 1) || + (OuterFlavor == SelectPatternFlavor::SPF_SMIN && + InnerFlavor == SelectPatternFlavor::SPF_SMAX && *C2 == *C1 + 1)) + return SelectInst::Create( + Builder.CreateICmp(Pred, TrueSI->getTrueValue(), FalseVal), + TrueSI->getFalseValue(), FalseVal); + } } 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 ; @@ -1080,8 +1077,8 @@ define i37 @add_umax_simplify(i37 %x) { ; CHECK-LABEL: @add_umax_simplify( -; CHECK-NEXT: [[A:%.*]] = add nuw i37 [[X:%.*]], 42 -; CHECK-NEXT: ret i37 [[A]] +; CHECK-NEXT: [[R:%.*]] = add nuw i37 [[X:%.*]], 42 +; CHECK-NEXT: ret i37 [[R]] ; %a = add nuw i37 %x, 42 %c = icmp ugt i37 %a, 42 @@ -1464,13 +1461,13 @@ ret i8 %r } +; FIXME: The result pattern can't be recognized as min/max in scalar evolution, +; which can be improved. define i32 @twoway_clamp_lt(i32 %num) { ; CHECK-LABEL: @twoway_clamp_lt( ; CHECK-NEXT: entry: -; CHECK-NEXT: [[CMP1:%.*]] = icmp slt i32 [[NUM:%.*]], 13768 -; CHECK-NEXT: [[S1:%.*]] = select i1 [[CMP1]], i32 [[NUM]], i32 13768 -; CHECK-NEXT: [[CMP2:%.*]] = icmp sgt i32 [[S1]], 13767 -; CHECK-NEXT: [[R:%.*]] = select i1 [[CMP2]], i32 [[S1]], i32 13767 +; CHECK-NEXT: [[TMP0:%.*]] = icmp sgt i32 [[NUM:%.*]], 13767 +; CHECK-NEXT: [[R:%.*]] = select i1 [[TMP0]], i32 13768, i32 13767 ; CHECK-NEXT: ret i32 [[R]] ; entry: @@ -1484,10 +1481,8 @@ define i32 @twoway_clamp_gt(i32 %num) { ; CHECK-LABEL: @twoway_clamp_gt( ; CHECK-NEXT: entry: -; CHECK-NEXT: [[CMP1:%.*]] = icmp sgt i32 [[NUM:%.*]], 13767 -; CHECK-NEXT: [[S1:%.*]] = select i1 [[CMP1]], i32 [[NUM]], i32 13767 -; CHECK-NEXT: [[CMP2:%.*]] = icmp slt i32 [[S1]], 13768 -; CHECK-NEXT: [[R:%.*]] = select i1 [[CMP2]], i32 [[S1]], i32 13768 +; CHECK-NEXT: [[TMP0:%.*]] = icmp slt i32 [[NUM:%.*]], 13768 +; CHECK-NEXT: [[R:%.*]] = select i1 [[TMP0]], i32 13767, i32 13768 ; CHECK-NEXT: ret i32 [[R]] ; entry: @@ -1516,3 +1511,18 @@ %r = select i1 %cmp2, i32 %s1, i32 %k1 ret i32 %r } + +define <4 x i32> @twoway_clamp_gt_vec(<4 x i32> %num) { +; CHECK-LABEL: @twoway_clamp_gt_vec( +; CHECK-NEXT: entry: +; CHECK-NEXT: [[TMP0:%.*]] = icmp slt <4 x i32> [[NUM:%.*]], +; CHECK-NEXT: [[R:%.*]] = select <4 x i1> [[TMP0]], <4 x i32> , <4 x i32> +; CHECK-NEXT: ret <4 x i32> [[R]] +; +entry: + %cmp1 = icmp sgt <4 x i32> %num, + %s1 = select <4 x i1> %cmp1, <4 x i32> %num, <4 x i32> + %cmp2 = icmp slt <4 x i32> %s1, + %r = select <4 x i1> %cmp2, <4 x i32> %s1, <4 x i32> + ret <4 x i32> %r +}