[llvm] e6b6787 - [InstCombine] fold abs(X)/X to cmp+select
Sanjay Patel via llvm-commits
llvm-commits at lists.llvm.org
Mon Aug 17 05:01:44 PDT 2020
Author: Sanjay Patel
Date: 2020-08-17T08:01:28-04:00
New Revision: e6b6787d01e9ea6338b5b51c6e3ba1b903876b3a
URL: https://github.com/llvm/llvm-project/commit/e6b6787d01e9ea6338b5b51c6e3ba1b903876b3a
DIFF: https://github.com/llvm/llvm-project/commit/e6b6787d01e9ea6338b5b51c6e3ba1b903876b3a.diff
LOG: [InstCombine] fold abs(X)/X to cmp+select
The backend can convert the select-of-constants to
bit-hack shift+logic if desirable.
https://alive2.llvm.org/ce/z/pgJT6E
define i8 @src(i8 %x) {
%0:
%a = abs i8 %x, 1
%d = sdiv i8 %x, %a
ret i8 %d
}
=>
define i8 @tgt(i8 %x) {
%0:
%cond = icmp sgt i8 %x, 255
%r = select i1 %cond, i8 1, i8 255
ret i8 %r
}
Transformation seems to be correct!
Added:
Modified:
llvm/lib/Transforms/InstCombine/InstCombineMulDivRem.cpp
llvm/test/Transforms/InstCombine/sdiv-canonicalize.ll
Removed:
################################################################################
diff --git a/llvm/lib/Transforms/InstCombine/InstCombineMulDivRem.cpp b/llvm/lib/Transforms/InstCombine/InstCombineMulDivRem.cpp
index fb8b640c7c93..ec610b4f3469 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineMulDivRem.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineMulDivRem.cpp
@@ -1179,6 +1179,16 @@ Instruction *InstCombinerImpl::visitSDiv(BinaryOperator &I) {
return BinaryOperator::CreateNSWNeg(
Builder.CreateSDiv(X, Y, I.getName(), I.isExact()));
+ // abs(X) / X --> X > -1 ? 1 : -1
+ // X / abs(X) --> X > -1 ? 1 : -1
+ if (match(&I, m_c_BinOp(
+ m_OneUse(m_Intrinsic<Intrinsic::abs>(m_Value(X), m_One())),
+ m_Deferred(X)))) {
+ Constant *NegOne = ConstantInt::getAllOnesValue(Ty);
+ Value *Cond = Builder.CreateICmpSGT(X, NegOne);
+ return SelectInst::Create(Cond, ConstantInt::get(Ty, 1), NegOne);
+ }
+
// If the sign bits of both operands are zero (i.e. we can prove they are
// unsigned inputs), turn this into a udiv.
APInt Mask(APInt::getSignMask(Ty->getScalarSizeInBits()));
diff --git a/llvm/test/Transforms/InstCombine/sdiv-canonicalize.ll b/llvm/test/Transforms/InstCombine/sdiv-canonicalize.ll
index 52f7b1b01dae..b2a7a0da6cb5 100644
--- a/llvm/test/Transforms/InstCombine/sdiv-canonicalize.ll
+++ b/llvm/test/Transforms/InstCombine/sdiv-canonicalize.ll
@@ -96,8 +96,8 @@ define i64 @test_sdiv_canonicalize_constexpr(i64 %L1) {
define i32 @sdiv_abs_nsw(i32 %x) {
; CHECK-LABEL: @sdiv_abs_nsw(
-; CHECK-NEXT: [[A:%.*]] = call i32 @llvm.abs.i32(i32 [[X:%.*]], i1 true)
-; CHECK-NEXT: [[R:%.*]] = sdiv i32 [[A]], [[X]]
+; CHECK-NEXT: [[DOTINV:%.*]] = icmp sgt i32 [[X:%.*]], -1
+; CHECK-NEXT: [[R:%.*]] = select i1 [[DOTINV]], i32 1, i32 -1
; CHECK-NEXT: ret i32 [[R]]
;
%a = call i32 @llvm.abs.i32(i32 %x, i1 true)
@@ -107,8 +107,8 @@ define i32 @sdiv_abs_nsw(i32 %x) {
define <4 x i32> @sdiv_abs_nsw_vec(<4 x i32> %x) {
; CHECK-LABEL: @sdiv_abs_nsw_vec(
-; CHECK-NEXT: [[A:%.*]] = call <4 x i32> @llvm.abs.v4i32(<4 x i32> [[X:%.*]], i1 true)
-; CHECK-NEXT: [[R:%.*]] = sdiv <4 x i32> [[X]], [[A]]
+; CHECK-NEXT: [[DOTINV:%.*]] = icmp sgt <4 x i32> [[X:%.*]], <i32 -1, i32 -1, i32 -1, i32 -1>
+; CHECK-NEXT: [[R:%.*]] = select <4 x i1> [[DOTINV]], <4 x i32> <i32 1, i32 1, i32 1, i32 1>, <4 x i32> <i32 -1, i32 -1, i32 -1, i32 -1>
; CHECK-NEXT: ret <4 x i32> [[R]]
;
%a = call <4 x i32> @llvm.abs.v4i32(<4 x i32> %x, i1 true)
@@ -116,6 +116,8 @@ define <4 x i32> @sdiv_abs_nsw_vec(<4 x i32> %x) {
ret <4 x i32> %r
}
+; Negative test - requires poison int min (nsw)
+
define i32 @sdiv_abs(i32 %x) {
; CHECK-LABEL: @sdiv_abs(
; CHECK-NEXT: [[A:%.*]] = call i32 @llvm.abs.i32(i32 [[X:%.*]], i1 false)
@@ -127,6 +129,8 @@ define i32 @sdiv_abs(i32 %x) {
ret i32 %r
}
+; Negative test
+
define i32 @sdiv_abs_extra_use(i32 %x) {
; CHECK-LABEL: @sdiv_abs_extra_use(
; CHECK-NEXT: [[A:%.*]] = call i32 @llvm.abs.i32(i32 [[X:%.*]], i1 true)
More information about the llvm-commits
mailing list