[llvm] 1d1d1e6 - [InstCombine] fold full-shift of sdiv to icmp+extend

Sanjay Patel via llvm-commits llvm-commits at lists.llvm.org
Sun Sep 18 10:13:26 PDT 2022


Author: Sanjay Patel
Date: 2022-09-18T13:13:14-04:00
New Revision: 1d1d1e6f226dd9d56f824b4cf502a0037ff86f32

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

LOG: [InstCombine] fold full-shift of sdiv to icmp+extend

This is a disguised sign-bit test with offset:
(X / +DivC) >> (Width - 1) --> ext (X <= -DivC)
(X / -DivC) >> (Width - 1) --> ext (X >= +DivC)

https://alive2.llvm.org/ce/z/cO8JO4

We don't match/test poison in the sdiv constant because
that would be immediate undefined behavior.

Added: 
    

Modified: 
    llvm/lib/Transforms/InstCombine/InstCombineShifts.cpp
    llvm/test/Transforms/InstCombine/shift.ll

Removed: 
    


################################################################################
diff  --git a/llvm/lib/Transforms/InstCombine/InstCombineShifts.cpp b/llvm/lib/Transforms/InstCombine/InstCombineShifts.cpp
index 13c98b935adfb..83de1d5f5c8e8 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineShifts.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineShifts.cpp
@@ -730,13 +730,34 @@ Instruction *InstCombinerImpl::FoldShiftByConstant(Value *Op0, Constant *C1,
     return BinaryOperator::Create(
         I.getOpcode(), Builder.CreateBinOp(I.getOpcode(), C2, C1), X);
 
+  bool IsLeftShift = I.getOpcode() == Instruction::Shl;
+  Type *Ty = I.getType();
+  unsigned TypeBits = Ty->getScalarSizeInBits();
+
+  // (X / +DivC) >> (Width - 1) --> ext (X <= -DivC)
+  // (X / -DivC) >> (Width - 1) --> ext (X >= +DivC)
+  const APInt *DivC;
+  if (!IsLeftShift && match(C1, m_SpecificIntAllowUndef(TypeBits - 1)) &&
+      match(Op0, m_SDiv(m_Value(X), m_APInt(DivC))) && !DivC->isZero() &&
+      !DivC->isMinSignedValue()) {
+    Constant *NegDivC = ConstantInt::get(Ty, -(*DivC));
+    ICmpInst::Predicate Pred =
+        DivC->isNegative() ? ICmpInst::ICMP_SGE : ICmpInst::ICMP_SLE;
+    Value *Cmp = Builder.CreateICmp(Pred, X, NegDivC);
+    auto ExtOpcode = (I.getOpcode() == Instruction::AShr) ? Instruction::SExt
+                                                          : Instruction::ZExt;
+    return CastInst::Create(ExtOpcode, Cmp, Ty);
+  }
+
   const APInt *Op1C;
   if (!match(C1, m_APInt(Op1C)))
     return nullptr;
 
+  assert(!Op1C->uge(TypeBits) &&
+         "Shift over the type width should have been removed already");
+
   // See if we can propagate this shift into the input, this covers the trivial
   // cast of lshr(shl(x,c1),c2) as well as other more complex cases.
-  bool IsLeftShift = I.getOpcode() == Instruction::Shl;
   if (I.getOpcode() != Instruction::AShr &&
       canEvaluateShifted(Op0, Op1C->getZExtValue(), IsLeftShift, *this, &I)) {
     LLVM_DEBUG(
@@ -748,14 +769,6 @@ Instruction *InstCombinerImpl::FoldShiftByConstant(Value *Op0, Constant *C1,
         I, getShiftedValue(Op0, Op1C->getZExtValue(), IsLeftShift, *this, DL));
   }
 
-  // See if we can simplify any instructions used by the instruction whose sole
-  // purpose is to compute bits we don't care about.
-  Type *Ty = I.getType();
-  unsigned TypeBits = Ty->getScalarSizeInBits();
-  assert(!Op1C->uge(TypeBits) &&
-         "Shift over the type width should have been removed already");
-  (void)TypeBits;
-
   if (Instruction *FoldedShift = foldBinOpIntoSelectOrPhi(I))
     return FoldedShift;
 

diff  --git a/llvm/test/Transforms/InstCombine/shift.ll b/llvm/test/Transforms/InstCombine/shift.ll
index 787e76d130504..3a0cd27ceaf98 100644
--- a/llvm/test/Transforms/InstCombine/shift.ll
+++ b/llvm/test/Transforms/InstCombine/shift.ll
@@ -1905,8 +1905,8 @@ define i64 @lshr_mul_negpow2_extra_use(i64 %x) {
 
 define i8 @ashr_sdiv_pos(i8 %x) {
 ; CHECK-LABEL: @ashr_sdiv_pos(
-; CHECK-NEXT:    [[D:%.*]] = sdiv i8 [[X:%.*]], 42
-; CHECK-NEXT:    [[R:%.*]] = ashr i8 [[D]], 7
+; CHECK-NEXT:    [[TMP1:%.*]] = icmp slt i8 [[X:%.*]], -41
+; CHECK-NEXT:    [[R:%.*]] = sext i1 [[TMP1]] to i8
 ; CHECK-NEXT:    ret i8 [[R]]
 ;
   %d = sdiv i8 %x, 42
@@ -1916,8 +1916,8 @@ define i8 @ashr_sdiv_pos(i8 %x) {
 
 define <2 x i8> @ashr_sdiv_neg_splat_vec(<2 x i8> %x) {
 ; CHECK-LABEL: @ashr_sdiv_neg_splat_vec(
-; CHECK-NEXT:    [[D:%.*]] = sdiv <2 x i8> [[X:%.*]], <i8 -42, i8 -42>
-; CHECK-NEXT:    [[R:%.*]] = ashr <2 x i8> [[D]], <i8 7, i8 7>
+; CHECK-NEXT:    [[TMP1:%.*]] = icmp sgt <2 x i8> [[X:%.*]], <i8 41, i8 41>
+; CHECK-NEXT:    [[R:%.*]] = sext <2 x i1> [[TMP1]] to <2 x i8>
 ; CHECK-NEXT:    ret <2 x i8> [[R]]
 ;
   %d = sdiv <2 x i8> %x, <i8 -42, i8 -42>
@@ -1927,8 +1927,8 @@ define <2 x i8> @ashr_sdiv_neg_splat_vec(<2 x i8> %x) {
 
 define <2 x i8> @ashr_sdiv_neg_splat_vec_poison(<2 x i8> %x) {
 ; CHECK-LABEL: @ashr_sdiv_neg_splat_vec_poison(
-; CHECK-NEXT:    [[D:%.*]] = sdiv <2 x i8> [[X:%.*]], <i8 -127, i8 -127>
-; CHECK-NEXT:    [[R:%.*]] = ashr <2 x i8> [[D]], <i8 7, i8 poison>
+; CHECK-NEXT:    [[TMP1:%.*]] = icmp eq <2 x i8> [[X:%.*]], <i8 127, i8 127>
+; CHECK-NEXT:    [[R:%.*]] = sext <2 x i1> [[TMP1]] to <2 x i8>
 ; CHECK-NEXT:    ret <2 x i8> [[R]]
 ;
   %d = sdiv <2 x i8> %x, <i8 -127, i8 -127>
@@ -1938,8 +1938,8 @@ define <2 x i8> @ashr_sdiv_neg_splat_vec_poison(<2 x i8> %x) {
 
 define i8 @lshr_sdiv_pos(i8 %x) {
 ; CHECK-LABEL: @lshr_sdiv_pos(
-; CHECK-NEXT:    [[D:%.*]] = sdiv i8 [[X:%.*]], 12
-; CHECK-NEXT:    [[R:%.*]] = lshr i8 [[D]], 7
+; CHECK-NEXT:    [[TMP1:%.*]] = icmp slt i8 [[X:%.*]], -11
+; CHECK-NEXT:    [[R:%.*]] = zext i1 [[TMP1]] to i8
 ; CHECK-NEXT:    ret i8 [[R]]
 ;
   %d = sdiv i8 %x, 12
@@ -1949,8 +1949,8 @@ define i8 @lshr_sdiv_pos(i8 %x) {
 
 define i18 @lshr_sdiv_neg(i18 %x) {
 ; CHECK-LABEL: @lshr_sdiv_neg(
-; CHECK-NEXT:    [[D:%.*]] = sdiv i18 [[X:%.*]], -12
-; CHECK-NEXT:    [[R:%.*]] = lshr i18 [[D]], 17
+; CHECK-NEXT:    [[TMP1:%.*]] = icmp sgt i18 [[X:%.*]], 11
+; CHECK-NEXT:    [[R:%.*]] = zext i1 [[TMP1]] to i18
 ; CHECK-NEXT:    ret i18 [[R]]
 ;
   %d = sdiv i18 %x, -12
@@ -1958,6 +1958,8 @@ define i18 @lshr_sdiv_neg(i18 %x) {
   ret i18 %r
 }
 
+; negative test
+
 define i8 @ashr_sdiv_not_full_shift(i8 %x) {
 ; CHECK-LABEL: @ashr_sdiv_not_full_shift(
 ; CHECK-NEXT:    [[D:%.*]] = sdiv i8 [[X:%.*]], 42
@@ -1969,11 +1971,14 @@ define i8 @ashr_sdiv_not_full_shift(i8 %x) {
   ret i8 %r
 }
 
+; negative test
+
 define i32 @ashr_sdiv_extra_use(i32 %x) {
 ; CHECK-LABEL: @ashr_sdiv_extra_use(
 ; CHECK-NEXT:    [[D:%.*]] = sdiv i32 [[X:%.*]], 42
 ; CHECK-NEXT:    call void @use_i32(i32 [[D]])
-; CHECK-NEXT:    [[R:%.*]] = ashr i32 [[D]], 31
+; CHECK-NEXT:    [[TMP1:%.*]] = icmp slt i32 [[X]], -41
+; CHECK-NEXT:    [[R:%.*]] = sext i1 [[TMP1]] to i32
 ; CHECK-NEXT:    ret i32 [[R]]
 ;
   %d = sdiv i32 %x, 42


        


More information about the llvm-commits mailing list