Skip to content

Commit

Permalink
[InstCombine] try to fold div with constant dividend and select-of-co…
Browse files Browse the repository at this point in the history
…nstants divisor

We avoid this fold in the more general cases where we use FoldOpIntoSelect.
That's because -- unlike most binary opcodes -- 'div' can't usually be
speculated with a variable divisor since it can have immediate UB. But in
the case where both arms of the select are constants, we can safely evaluate
both sides and eliminate 'div' completely.

This is a follow-up to the equivalent fold for 'rem' opcodes:
D115173 / f65be72
  • Loading branch information
rotateright committed Dec 8, 2021
1 parent 2676759 commit a7ed21a
Show file tree
Hide file tree
Showing 2 changed files with 41 additions and 12 deletions.
9 changes: 9 additions & 0 deletions llvm/lib/Transforms/InstCombine/InstCombineMulDivRem.cpp
Expand Up @@ -755,6 +755,15 @@ Instruction *InstCombinerImpl::commonIDivTransforms(BinaryOperator &I) {
if (simplifyDivRemOfSelectWithZeroOp(I))
return &I;

// If the divisor is a select-of-constants, try to constant fold all div ops:
// C / (select Cond, TrueC, FalseC) --> select Cond, (C / TrueC), (C / FalseC)
// TODO: Adapt simplifyDivRemOfSelectWithZeroOp to allow this and other folds.
if (match(Op0, m_ImmConstant()) &&
match(Op1, m_Select(m_Value(), m_ImmConstant(), m_ImmConstant()))) {
if (Instruction *R = FoldOpIntoSelect(I, cast<SelectInst>(Op1)))
return R;
}

const APInt *C2;
if (match(Op1, m_APInt(C2))) {
Value *X;
Expand Down
44 changes: 32 additions & 12 deletions llvm/test/Transforms/InstCombine/div.ll
Expand Up @@ -1090,15 +1090,16 @@ define <vscale x 2 x i8> @sdiv_by_minSigned_nxv2i8(<vscale x 2 x i8> %x) {

define i32 @sdiv_constant_dividend_select_of_constants_divisor(i1 %b) {
; CHECK-LABEL: @sdiv_constant_dividend_select_of_constants_divisor(
; CHECK-NEXT: [[S:%.*]] = select i1 [[B:%.*]], i32 12, i32 -3
; CHECK-NEXT: [[R:%.*]] = sdiv i32 42, [[S]]
; CHECK-NEXT: [[R:%.*]] = select i1 [[B:%.*]], i32 3, i32 -14
; CHECK-NEXT: ret i32 [[R]]
;
%s = select i1 %b, i32 12, i32 -3
%r = sdiv i32 42, %s
ret i32 %r
}

; TODO: sdiv should still be replaced by select.

define i32 @sdiv_constant_dividend_select_of_constants_divisor_use(i1 %b) {
; CHECK-LABEL: @sdiv_constant_dividend_select_of_constants_divisor_use(
; CHECK-NEXT: [[S:%.*]] = select i1 [[B:%.*]], i32 12, i32 -3
Expand All @@ -1121,6 +1122,8 @@ define i32 @sdiv_constant_dividend_select_of_constants_divisor_0_arm(i1 %b) {
ret i32 %r
}

; negative test - not safe to speculate div with variable divisor

define i32 @sdiv_constant_dividend_select_divisor1(i1 %b, i32 %x) {
; CHECK-LABEL: @sdiv_constant_dividend_select_divisor1(
; CHECK-NEXT: [[S:%.*]] = select i1 [[B:%.*]], i32 [[X:%.*]], i32 -3
Expand All @@ -1132,6 +1135,8 @@ define i32 @sdiv_constant_dividend_select_divisor1(i1 %b, i32 %x) {
ret i32 %r
}

; negative test - not safe to speculate div with variable divisor

define i32 @sdiv_constant_dividend_select_divisor2(i1 %b, i32 %x) {
; CHECK-LABEL: @sdiv_constant_dividend_select_divisor2(
; CHECK-NEXT: [[S:%.*]] = select i1 [[B:%.*]], i32 12, i32 [[X:%.*]]
Expand All @@ -1145,15 +1150,16 @@ define i32 @sdiv_constant_dividend_select_divisor2(i1 %b, i32 %x) {

define <2 x i8> @sdiv_constant_dividend_select_of_constants_divisor_vec(i1 %b) {
; CHECK-LABEL: @sdiv_constant_dividend_select_of_constants_divisor_vec(
; CHECK-NEXT: [[S:%.*]] = select i1 [[B:%.*]], <2 x i8> <i8 12, i8 -5>, <2 x i8> <i8 -4, i8 4>
; CHECK-NEXT: [[R:%.*]] = sdiv <2 x i8> <i8 42, i8 -42>, [[S]]
; CHECK-NEXT: [[R:%.*]] = select i1 [[B:%.*]], <2 x i8> <i8 3, i8 8>, <2 x i8> <i8 -10, i8 -10>
; CHECK-NEXT: ret <2 x i8> [[R]]
;
%s = select i1 %b, <2 x i8> <i8 12, i8 -5>, <2 x i8> <i8 -4, i8 4>
%r = sdiv <2 x i8> <i8 42, i8 -42>, %s
ret <2 x i8> %r
}

; Div-by-0 element is immediate UB, so select is simplified.

define <2 x i8> @sdiv_constant_dividend_select_of_constants_divisor_vec_ub1(i1 %b) {
; CHECK-LABEL: @sdiv_constant_dividend_select_of_constants_divisor_vec_ub1(
; CHECK-NEXT: ret <2 x i8> <i8 -10, i8 -10>
Expand All @@ -1163,17 +1169,20 @@ define <2 x i8> @sdiv_constant_dividend_select_of_constants_divisor_vec_ub1(i1 %
ret <2 x i8> %r
}

; SMIN / -1 element is poison.

define <2 x i8> @sdiv_constant_dividend_select_of_constants_divisor_vec_ub2(i1 %b) {
; CHECK-LABEL: @sdiv_constant_dividend_select_of_constants_divisor_vec_ub2(
; CHECK-NEXT: [[S:%.*]] = select i1 [[B:%.*]], <2 x i8> <i8 12, i8 -5>, <2 x i8> <i8 -4, i8 -1>
; CHECK-NEXT: [[R:%.*]] = sdiv <2 x i8> <i8 42, i8 -128>, [[S]]
; CHECK-NEXT: [[R:%.*]] = select i1 [[B:%.*]], <2 x i8> <i8 3, i8 25>, <2 x i8> <i8 -10, i8 poison>
; CHECK-NEXT: ret <2 x i8> [[R]]
;
%s = select i1 %b, <2 x i8> <i8 12, i8 -5>, <2 x i8> <i8 -4, i8 -1>
%r = sdiv <2 x i8> <i8 42, i8 -128>, %s
ret <2 x i8> %r
}

; negative test - must have constant dividend

define i32 @sdiv_select_of_constants_divisor(i1 %b, i32 %x) {
; CHECK-LABEL: @sdiv_select_of_constants_divisor(
; CHECK-NEXT: [[S:%.*]] = select i1 [[B:%.*]], i32 12, i32 -3
Expand All @@ -1187,15 +1196,16 @@ define i32 @sdiv_select_of_constants_divisor(i1 %b, i32 %x) {

define i32 @udiv_constant_dividend_select_of_constants_divisor(i1 %b) {
; CHECK-LABEL: @udiv_constant_dividend_select_of_constants_divisor(
; CHECK-NEXT: [[S:%.*]] = select i1 [[B:%.*]], i32 12, i32 -3
; CHECK-NEXT: [[R:%.*]] = udiv i32 42, [[S]]
; CHECK-NEXT: [[R:%.*]] = select i1 [[B:%.*]], i32 3, i32 0
; CHECK-NEXT: ret i32 [[R]]
;
%s = select i1 %b, i32 12, i32 -3
%r = udiv i32 42, %s
ret i32 %r
}

; TODO: udiv should still be replaced by select.

define i32 @udiv_constant_dividend_select_of_constants_divisor_use(i1 %b) {
; CHECK-LABEL: @udiv_constant_dividend_select_of_constants_divisor_use(
; CHECK-NEXT: [[S:%.*]] = select i1 [[B:%.*]], i32 12, i32 -3
Expand All @@ -1209,6 +1219,8 @@ define i32 @udiv_constant_dividend_select_of_constants_divisor_use(i1 %b) {
ret i32 %r
}

; Div-by-0 is immediate UB, so select is simplified.

define i32 @udiv_constant_dividend_select_of_constants_divisor_0_arm(i1 %b) {
; CHECK-LABEL: @udiv_constant_dividend_select_of_constants_divisor_0_arm(
; CHECK-NEXT: ret i32 3
Expand All @@ -1218,6 +1230,8 @@ define i32 @udiv_constant_dividend_select_of_constants_divisor_0_arm(i1 %b) {
ret i32 %r
}

; negative test - not safe to speculate div with variable divisor

define i32 @udiv_constant_dividend_select_divisor1(i1 %b, i32 %x) {
; CHECK-LABEL: @udiv_constant_dividend_select_divisor1(
; CHECK-NEXT: [[S:%.*]] = select i1 [[B:%.*]], i32 [[X:%.*]], i32 -3
Expand All @@ -1229,6 +1243,8 @@ define i32 @udiv_constant_dividend_select_divisor1(i1 %b, i32 %x) {
ret i32 %r
}

; negative test - not safe to speculate div with variable divisor

define i32 @udiv_constant_dividend_select_divisor2(i1 %b, i32 %x) {
; CHECK-LABEL: @udiv_constant_dividend_select_divisor2(
; CHECK-NEXT: [[S:%.*]] = select i1 [[B:%.*]], i32 12, i32 [[X:%.*]]
Expand All @@ -1242,15 +1258,16 @@ define i32 @udiv_constant_dividend_select_divisor2(i1 %b, i32 %x) {

define <2 x i8> @udiv_constant_dividend_select_of_constants_divisor_vec(i1 %b) {
; CHECK-LABEL: @udiv_constant_dividend_select_of_constants_divisor_vec(
; CHECK-NEXT: [[S:%.*]] = select i1 [[B:%.*]], <2 x i8> <i8 12, i8 -5>, <2 x i8> <i8 -4, i8 4>
; CHECK-NEXT: [[R:%.*]] = udiv <2 x i8> <i8 42, i8 -42>, [[S]]
; CHECK-NEXT: [[R:%.*]] = select i1 [[B:%.*]], <2 x i8> <i8 3, i8 0>, <2 x i8> <i8 0, i8 53>
; CHECK-NEXT: ret <2 x i8> [[R]]
;
%s = select i1 %b, <2 x i8> <i8 12, i8 -5>, <2 x i8> <i8 -4, i8 4>
%r = udiv <2 x i8> <i8 42, i8 -42>, %s
ret <2 x i8> %r
}

; Div-by-0 element is immediate UB, so select is simplified.

define <2 x i8> @udiv_constant_dividend_select_of_constants_divisor_vec_ub1(i1 %b) {
; CHECK-LABEL: @udiv_constant_dividend_select_of_constants_divisor_vec_ub1(
; CHECK-NEXT: ret <2 x i8> <i8 0, i8 53>
Expand All @@ -1260,17 +1277,20 @@ define <2 x i8> @udiv_constant_dividend_select_of_constants_divisor_vec_ub1(i1 %
ret <2 x i8> %r
}

; There's no unsigned equivalent to "SMIN / -1", so this is just the usual constant folding.

define <2 x i8> @udiv_constant_dividend_select_of_constants_divisor_vec_ub2(i1 %b) {
; CHECK-LABEL: @udiv_constant_dividend_select_of_constants_divisor_vec_ub2(
; CHECK-NEXT: [[S:%.*]] = select i1 [[B:%.*]], <2 x i8> <i8 12, i8 -5>, <2 x i8> <i8 -4, i8 -1>
; CHECK-NEXT: [[R:%.*]] = udiv <2 x i8> <i8 42, i8 -128>, [[S]]
; CHECK-NEXT: [[R:%.*]] = select i1 [[B:%.*]], <2 x i8> <i8 3, i8 0>, <2 x i8> zeroinitializer
; CHECK-NEXT: ret <2 x i8> [[R]]
;
%s = select i1 %b, <2 x i8> <i8 12, i8 -5>, <2 x i8> <i8 -4, i8 -1>
%r = udiv <2 x i8> <i8 42, i8 -128>, %s
ret <2 x i8> %r
}

; negative test - must have constant dividend

define i32 @udiv_select_of_constants_divisor(i1 %b, i32 %x) {
; CHECK-LABEL: @udiv_select_of_constants_divisor(
; CHECK-NEXT: [[S:%.*]] = select i1 [[B:%.*]], i32 12, i32 -3
Expand Down

0 comments on commit a7ed21a

Please sign in to comment.