Skip to content

Commit 80fce05

Browse files
authored
[InstCombine] Fold minmax (X & NegPow2C, Y & NegPow2C) -> minmax(X, Y) & NegPow2C (#88859)
Alive2: https://alive2.llvm.org/ce/z/NFtkSX This optimization will be beneficial to jemalloc users.
1 parent 485d556 commit 80fce05

File tree

2 files changed

+96
-1
lines changed

2 files changed

+96
-1
lines changed

llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1774,6 +1774,13 @@ Instruction *InstCombinerImpl::visitCallInst(CallInst &CI) {
17741774
if (Instruction *I = moveAddAfterMinMax(II, Builder))
17751775
return I;
17761776

1777+
// minmax (X & NegPow2C, Y & NegPow2C) --> minmax(X, Y) & NegPow2C
1778+
const APInt *RHSC;
1779+
if (match(I0, m_OneUse(m_And(m_Value(X), m_NegatedPower2(RHSC)))) &&
1780+
match(I1, m_OneUse(m_And(m_Value(Y), m_SpecificInt(*RHSC)))))
1781+
return BinaryOperator::CreateAnd(Builder.CreateBinaryIntrinsic(IID, X, Y),
1782+
ConstantInt::get(II->getType(), *RHSC));
1783+
17771784
// smax(X, -X) --> abs(X)
17781785
// smin(X, -X) --> -abs(X)
17791786
// umax(X, -X) --> -abs(X)
@@ -1815,7 +1822,6 @@ Instruction *InstCombinerImpl::visitCallInst(CallInst &CI) {
18151822
return NewMinMax;
18161823

18171824
// Try to fold minmax with constant RHS based on range information
1818-
const APInt *RHSC;
18191825
if (match(I1, m_APIntAllowUndef(RHSC))) {
18201826
ICmpInst::Predicate Pred =
18211827
ICmpInst::getNonStrictPredicate(MinMaxIntrinsic::getPredicate(IID));

llvm/test/Transforms/InstCombine/minmax-intrinsics.ll

Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2581,3 +2581,92 @@ entry:
25812581
%val = call i8 @llvm.umin.i8(i8 %sub, i8 3)
25822582
ret i8 %val
25832583
}
2584+
2585+
define i8 @test_umax_and(i8 %x, i8 %y) {
2586+
; CHECK-LABEL: @test_umax_and(
2587+
; CHECK-NEXT: [[RES:%.*]] = call i8 @llvm.umax.i8(i8 [[X1:%.*]], i8 [[Y1:%.*]])
2588+
; CHECK-NEXT: [[RES1:%.*]] = and i8 [[RES]], -64
2589+
; CHECK-NEXT: ret i8 [[RES1]]
2590+
;
2591+
%x1 = and i8 %x, -64
2592+
%y1 = and i8 %y, -64
2593+
%res = call i8 @llvm.umax.i8(i8 %x1, i8 %y1)
2594+
ret i8 %res
2595+
}
2596+
2597+
define i8 @test_umin_and(i8 %x, i8 %y) {
2598+
; CHECK-LABEL: @test_umin_and(
2599+
; CHECK-NEXT: [[RES:%.*]] = call i8 @llvm.umin.i8(i8 [[X1:%.*]], i8 [[Y1:%.*]])
2600+
; CHECK-NEXT: [[RES1:%.*]] = and i8 [[RES]], -64
2601+
; CHECK-NEXT: ret i8 [[RES1]]
2602+
;
2603+
%x1 = and i8 %x, -64
2604+
%y1 = and i8 %y, -64
2605+
%res = call i8 @llvm.umin.i8(i8 %x1, i8 %y1)
2606+
ret i8 %res
2607+
}
2608+
2609+
define i8 @test_smax_and(i8 %x, i8 %y) {
2610+
; CHECK-LABEL: @test_smax_and(
2611+
; CHECK-NEXT: [[RES:%.*]] = call i8 @llvm.smax.i8(i8 [[X1:%.*]], i8 [[Y1:%.*]])
2612+
; CHECK-NEXT: [[RES1:%.*]] = and i8 [[RES]], -64
2613+
; CHECK-NEXT: ret i8 [[RES1]]
2614+
;
2615+
%x1 = and i8 %x, -64
2616+
%y1 = and i8 %y, -64
2617+
%res = call i8 @llvm.smax.i8(i8 %x1, i8 %y1)
2618+
ret i8 %res
2619+
}
2620+
2621+
define i8 @test_smin_and(i8 %x, i8 %y) {
2622+
; CHECK-LABEL: @test_smin_and(
2623+
; CHECK-NEXT: [[RES:%.*]] = call i8 @llvm.smin.i8(i8 [[X1:%.*]], i8 [[Y1:%.*]])
2624+
; CHECK-NEXT: [[RES1:%.*]] = and i8 [[RES]], -64
2625+
; CHECK-NEXT: ret i8 [[RES1]]
2626+
;
2627+
%x1 = and i8 %x, -64
2628+
%y1 = and i8 %y, -64
2629+
%res = call i8 @llvm.smin.i8(i8 %x1, i8 %y1)
2630+
ret i8 %res
2631+
}
2632+
2633+
define i8 @test_smin_and_mismatch(i8 %x, i8 %y) {
2634+
; CHECK-LABEL: @test_smin_and_mismatch(
2635+
; CHECK-NEXT: [[X1:%.*]] = and i8 [[X:%.*]], -64
2636+
; CHECK-NEXT: [[Y1:%.*]] = and i8 [[Y:%.*]], -32
2637+
; CHECK-NEXT: [[RES:%.*]] = call i8 @llvm.smin.i8(i8 [[X1]], i8 [[Y1]])
2638+
; CHECK-NEXT: ret i8 [[RES]]
2639+
;
2640+
%x1 = and i8 %x, -64
2641+
%y1 = and i8 %y, -32
2642+
%res = call i8 @llvm.smin.i8(i8 %x1, i8 %y1)
2643+
ret i8 %res
2644+
}
2645+
2646+
define i8 @test_smin_and_non_negated_pow2(i8 %x, i8 %y) {
2647+
; CHECK-LABEL: @test_smin_and_non_negated_pow2(
2648+
; CHECK-NEXT: [[X1:%.*]] = and i8 [[X:%.*]], 31
2649+
; CHECK-NEXT: [[Y1:%.*]] = and i8 [[Y:%.*]], 31
2650+
; CHECK-NEXT: [[RES:%.*]] = call i8 @llvm.smin.i8(i8 [[X1]], i8 [[Y1]])
2651+
; CHECK-NEXT: ret i8 [[RES]]
2652+
;
2653+
%x1 = and i8 %x, 31
2654+
%y1 = and i8 %y, 31
2655+
%res = call i8 @llvm.smin.i8(i8 %x1, i8 %y1)
2656+
ret i8 %res
2657+
}
2658+
2659+
define i8 @test_smin_and_multiuse(i8 %x, i8 %y) {
2660+
; CHECK-LABEL: @test_smin_and_multiuse(
2661+
; CHECK-NEXT: [[X1:%.*]] = and i8 [[X:%.*]], 31
2662+
; CHECK-NEXT: [[Y1:%.*]] = and i8 [[Y:%.*]], 31
2663+
; CHECK-NEXT: call void @use(i8 [[Y1]])
2664+
; CHECK-NEXT: [[RES:%.*]] = call i8 @llvm.smin.i8(i8 [[X1]], i8 [[Y1]])
2665+
; CHECK-NEXT: ret i8 [[RES]]
2666+
;
2667+
%x1 = and i8 %x, 31
2668+
%y1 = and i8 %y, 31
2669+
call void @use(i8 %y1)
2670+
%res = call i8 @llvm.smin.i8(i8 %x1, i8 %y1)
2671+
ret i8 %res
2672+
}

0 commit comments

Comments
 (0)