[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