[llvm] a7ed21a - [InstCombine] try to fold div with constant dividend and select-of-constants divisor

Sanjay Patel via llvm-commits llvm-commits at lists.llvm.org
Wed Dec 8 07:31:04 PST 2021


Author: Sanjay Patel
Date: 2021-12-08T10:27:50-05:00
New Revision: a7ed21aa1e1d73e8c51490a52d6ebe6975fc558b

URL: https://github.com/llvm/llvm-project/commit/a7ed21aa1e1d73e8c51490a52d6ebe6975fc558b
DIFF: https://github.com/llvm/llvm-project/commit/a7ed21aa1e1d73e8c51490a52d6ebe6975fc558b.diff

LOG: [InstCombine] try to fold div with constant dividend and select-of-constants 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 / f65be726ab50

Added: 
    

Modified: 
    llvm/lib/Transforms/InstCombine/InstCombineMulDivRem.cpp
    llvm/test/Transforms/InstCombine/div.ll

Removed: 
    


################################################################################
diff  --git a/llvm/lib/Transforms/InstCombine/InstCombineMulDivRem.cpp b/llvm/lib/Transforms/InstCombine/InstCombineMulDivRem.cpp
index 69a611ef3a83b..aca7ec8d7325a 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineMulDivRem.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineMulDivRem.cpp
@@ -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;

diff  --git a/llvm/test/Transforms/InstCombine/div.ll b/llvm/test/Transforms/InstCombine/div.ll
index f84ec873b2740..71e83e64d7cce 100644
--- a/llvm/test/Transforms/InstCombine/div.ll
+++ b/llvm/test/Transforms/InstCombine/div.ll
@@ -1090,8 +1090,7 @@ 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
@@ -1099,6 +1098,8 @@ define i32 @sdiv_constant_dividend_select_of_constants_divisor(i1 %b) {
   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
@@ -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
@@ -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:%.*]]
@@ -1145,8 +1150,7 @@ 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>
@@ -1154,6 +1158,8 @@ define <2 x i8> @sdiv_constant_dividend_select_of_constants_divisor_vec(i1 %b) {
   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>
@@ -1163,10 +1169,11 @@ 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>
@@ -1174,6 +1181,8 @@ define <2 x i8> @sdiv_constant_dividend_select_of_constants_divisor_vec_ub2(i1 %
   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
@@ -1187,8 +1196,7 @@ 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
@@ -1196,6 +1204,8 @@ define i32 @udiv_constant_dividend_select_of_constants_divisor(i1 %b) {
   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
@@ -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
@@ -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
@@ -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:%.*]]
@@ -1242,8 +1258,7 @@ 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>
@@ -1251,6 +1266,8 @@ define <2 x i8> @udiv_constant_dividend_select_of_constants_divisor_vec(i1 %b) {
   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>
@@ -1260,10 +1277,11 @@ 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>
@@ -1271,6 +1289,8 @@ define <2 x i8> @udiv_constant_dividend_select_of_constants_divisor_vec_ub2(i1 %
   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


        


More information about the llvm-commits mailing list