Skip to content

Commit e6b6787

Browse files
committed
[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!
1 parent 61512dd commit e6b6787

File tree

2 files changed

+18
-4
lines changed

2 files changed

+18
-4
lines changed

llvm/lib/Transforms/InstCombine/InstCombineMulDivRem.cpp

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1179,6 +1179,16 @@ Instruction *InstCombinerImpl::visitSDiv(BinaryOperator &I) {
11791179
return BinaryOperator::CreateNSWNeg(
11801180
Builder.CreateSDiv(X, Y, I.getName(), I.isExact()));
11811181

1182+
// abs(X) / X --> X > -1 ? 1 : -1
1183+
// X / abs(X) --> X > -1 ? 1 : -1
1184+
if (match(&I, m_c_BinOp(
1185+
m_OneUse(m_Intrinsic<Intrinsic::abs>(m_Value(X), m_One())),
1186+
m_Deferred(X)))) {
1187+
Constant *NegOne = ConstantInt::getAllOnesValue(Ty);
1188+
Value *Cond = Builder.CreateICmpSGT(X, NegOne);
1189+
return SelectInst::Create(Cond, ConstantInt::get(Ty, 1), NegOne);
1190+
}
1191+
11821192
// If the sign bits of both operands are zero (i.e. we can prove they are
11831193
// unsigned inputs), turn this into a udiv.
11841194
APInt Mask(APInt::getSignMask(Ty->getScalarSizeInBits()));

llvm/test/Transforms/InstCombine/sdiv-canonicalize.ll

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -96,8 +96,8 @@ define i64 @test_sdiv_canonicalize_constexpr(i64 %L1) {
9696

9797
define i32 @sdiv_abs_nsw(i32 %x) {
9898
; CHECK-LABEL: @sdiv_abs_nsw(
99-
; CHECK-NEXT: [[A:%.*]] = call i32 @llvm.abs.i32(i32 [[X:%.*]], i1 true)
100-
; CHECK-NEXT: [[R:%.*]] = sdiv i32 [[A]], [[X]]
99+
; CHECK-NEXT: [[DOTINV:%.*]] = icmp sgt i32 [[X:%.*]], -1
100+
; CHECK-NEXT: [[R:%.*]] = select i1 [[DOTINV]], i32 1, i32 -1
101101
; CHECK-NEXT: ret i32 [[R]]
102102
;
103103
%a = call i32 @llvm.abs.i32(i32 %x, i1 true)
@@ -107,15 +107,17 @@ define i32 @sdiv_abs_nsw(i32 %x) {
107107

108108
define <4 x i32> @sdiv_abs_nsw_vec(<4 x i32> %x) {
109109
; CHECK-LABEL: @sdiv_abs_nsw_vec(
110-
; CHECK-NEXT: [[A:%.*]] = call <4 x i32> @llvm.abs.v4i32(<4 x i32> [[X:%.*]], i1 true)
111-
; CHECK-NEXT: [[R:%.*]] = sdiv <4 x i32> [[X]], [[A]]
110+
; CHECK-NEXT: [[DOTINV:%.*]] = icmp sgt <4 x i32> [[X:%.*]], <i32 -1, i32 -1, i32 -1, i32 -1>
111+
; 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>
112112
; CHECK-NEXT: ret <4 x i32> [[R]]
113113
;
114114
%a = call <4 x i32> @llvm.abs.v4i32(<4 x i32> %x, i1 true)
115115
%r = sdiv <4 x i32> %x, %a
116116
ret <4 x i32> %r
117117
}
118118

119+
; Negative test - requires poison int min (nsw)
120+
119121
define i32 @sdiv_abs(i32 %x) {
120122
; CHECK-LABEL: @sdiv_abs(
121123
; CHECK-NEXT: [[A:%.*]] = call i32 @llvm.abs.i32(i32 [[X:%.*]], i1 false)
@@ -127,6 +129,8 @@ define i32 @sdiv_abs(i32 %x) {
127129
ret i32 %r
128130
}
129131

132+
; Negative test
133+
130134
define i32 @sdiv_abs_extra_use(i32 %x) {
131135
; CHECK-LABEL: @sdiv_abs_extra_use(
132136
; CHECK-NEXT: [[A:%.*]] = call i32 @llvm.abs.i32(i32 [[X:%.*]], i1 true)

0 commit comments

Comments
 (0)