Skip to content

Commit 69d4890

Browse files
authored
[InstCombine] Fold abs(a * abs(b)) --> abs(a * b) (llvm#78110)
Proof: https://alive2.llvm.org/ce/z/hfbEra Fixes: llvm#73211
1 parent eddf9cf commit 69d4890

File tree

2 files changed

+140
-0
lines changed

2 files changed

+140
-0
lines changed

llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1569,6 +1569,17 @@ Instruction *InstCombinerImpl::visitCallInst(CallInst &CI) {
15691569
if (match(IIOperand, m_Select(m_Value(), m_Neg(m_Value(X)), m_Deferred(X))))
15701570
return replaceOperand(*II, 0, X);
15711571

1572+
Value *Y;
1573+
// abs(a * abs(b)) -> abs(a * b)
1574+
if (match(IIOperand,
1575+
m_OneUse(m_c_Mul(m_Value(X),
1576+
m_Intrinsic<Intrinsic::abs>(m_Value(Y)))))) {
1577+
bool NSW =
1578+
cast<Instruction>(IIOperand)->hasNoSignedWrap() && IntMinIsPoison;
1579+
auto *XY = NSW ? Builder.CreateNSWMul(X, Y) : Builder.CreateMul(X, Y);
1580+
return replaceOperand(*II, 0, XY);
1581+
}
1582+
15721583
if (std::optional<bool> Known =
15731584
getKnownSignOrZero(IIOperand, II, DL, &AC, &DT)) {
15741585
// abs(x) -> x if x >= 0 (include abs(x-y) --> x - y where x >= y)

llvm/test/Transforms/InstCombine/abs-intrinsic.ll

Lines changed: 129 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,136 @@ declare i8 @llvm.abs.i8(i8, i1)
55
declare i32 @llvm.abs.i32(i32, i1)
66
declare <4 x i32> @llvm.abs.v4i32(<4 x i32>, i1)
77
declare <3 x i82> @llvm.abs.v3i82(<3 x i82>, i1)
8+
declare <2 x i8> @llvm.abs.v2i8(<2 x i8>, i1)
89
declare void @llvm.assume(i1)
10+
declare void @use(i32)
11+
12+
define i8 @test_abs_abs_a_mul_b_i8(i8 %a, i8 %b) {
13+
; CHECK-LABEL: @test_abs_abs_a_mul_b_i8(
14+
; CHECK-NEXT: [[TMP1:%.*]] = mul i8 [[B:%.*]], [[A:%.*]]
15+
; CHECK-NEXT: [[ABS2:%.*]] = call i8 @llvm.abs.i8(i8 [[TMP1]], i1 true)
16+
; CHECK-NEXT: ret i8 [[ABS2]]
17+
;
18+
%abs1 = call i8 @llvm.abs.i8(i8 %a, i1 true)
19+
%mul = mul i8 %abs1, %b
20+
%abs2 = call i8 @llvm.abs.i8(i8 %mul, i1 true)
21+
ret i8 %abs2
22+
}
23+
24+
define i8 @test_abs_a_mul_abs_b_i8(i8 %a, i8 %b) {
25+
; CHECK-LABEL: @test_abs_a_mul_abs_b_i8(
26+
; CHECK-NEXT: [[A1:%.*]] = urem i8 123, [[A:%.*]]
27+
; CHECK-NEXT: [[TMP1:%.*]] = mul i8 [[A1]], [[B:%.*]]
28+
; CHECK-NEXT: [[ABS2:%.*]] = call i8 @llvm.abs.i8(i8 [[TMP1]], i1 true)
29+
; CHECK-NEXT: ret i8 [[ABS2]]
30+
;
31+
%a1 = urem i8 123, %a ; thwart complexity-based canonicalization
32+
%abs1 = call i8 @llvm.abs.i8(i8 %b, i1 true)
33+
%mul = mul i8 %a1, %abs1
34+
%abs2 = call i8 @llvm.abs.i8(i8 %mul, i1 true)
35+
ret i8 %abs2
36+
}
37+
38+
define i32 @test_abs_abs_a_mul_b_i32(i32 %a, i32 %b) {
39+
; CHECK-LABEL: @test_abs_abs_a_mul_b_i32(
40+
; CHECK-NEXT: [[TMP1:%.*]] = mul i32 [[B:%.*]], [[A:%.*]]
41+
; CHECK-NEXT: [[ABS2:%.*]] = call i32 @llvm.abs.i32(i32 [[TMP1]], i1 true)
42+
; CHECK-NEXT: ret i32 [[ABS2]]
43+
;
44+
%abs1 = call i32 @llvm.abs.i32(i32 %a, i1 true)
45+
%mul = mul i32 %abs1, %b
46+
%abs2 = call i32 @llvm.abs.i32(i32 %mul, i1 true)
47+
ret i32 %abs2
48+
}
49+
50+
define i32 @test_abs_abs_a_mul_b_i32_abs_false_true(i32 %a, i32 %b) {
51+
; CHECK-LABEL: @test_abs_abs_a_mul_b_i32_abs_false_true(
52+
; CHECK-NEXT: [[TMP1:%.*]] = mul i32 [[B:%.*]], [[A:%.*]]
53+
; CHECK-NEXT: [[ABS2:%.*]] = call i32 @llvm.abs.i32(i32 [[TMP1]], i1 true)
54+
; CHECK-NEXT: ret i32 [[ABS2]]
55+
;
56+
%abs1 = call i32 @llvm.abs.i32(i32 %a, i1 false)
57+
%mul = mul i32 %abs1, %b
58+
%abs2 = call i32 @llvm.abs.i32(i32 %mul, i1 true)
59+
ret i32 %abs2
60+
}
61+
62+
define i32 @test_abs_abs_a_mul_b_i32_abs_true_false(i32 %a, i32 %b) {
63+
; CHECK-LABEL: @test_abs_abs_a_mul_b_i32_abs_true_false(
64+
; CHECK-NEXT: [[TMP1:%.*]] = mul i32 [[B:%.*]], [[A:%.*]]
65+
; CHECK-NEXT: [[ABS2:%.*]] = call i32 @llvm.abs.i32(i32 [[TMP1]], i1 false)
66+
; CHECK-NEXT: ret i32 [[ABS2]]
67+
;
68+
%abs1 = call i32 @llvm.abs.i32(i32 %a, i1 true)
69+
%mul = mul i32 %abs1, %b
70+
%abs2 = call i32 @llvm.abs.i32(i32 %mul, i1 false)
71+
ret i32 %abs2
72+
}
73+
74+
define i32 @test_abs_abs_a_mul_b_i32_abs_false_false(i32 %a, i32 %b) {
75+
; CHECK-LABEL: @test_abs_abs_a_mul_b_i32_abs_false_false(
76+
; CHECK-NEXT: [[TMP1:%.*]] = mul i32 [[B:%.*]], [[A:%.*]]
77+
; CHECK-NEXT: [[ABS2:%.*]] = call i32 @llvm.abs.i32(i32 [[TMP1]], i1 false)
78+
; CHECK-NEXT: ret i32 [[ABS2]]
79+
;
80+
%abs1 = call i32 @llvm.abs.i32(i32 %a, i1 false)
81+
%mul = mul i32 %abs1, %b
82+
%abs2 = call i32 @llvm.abs.i32(i32 %mul, i1 false)
83+
ret i32 %abs2
84+
}
85+
86+
; this should work
87+
define i8 @test_nsw_with_true(i8 %a, i8 %b) {
88+
; CHECK-LABEL: @test_nsw_with_true(
89+
; CHECK-NEXT: [[TMP1:%.*]] = mul nsw i8 [[B:%.*]], [[A:%.*]]
90+
; CHECK-NEXT: [[ABS2:%.*]] = call i8 @llvm.abs.i8(i8 [[TMP1]], i1 true)
91+
; CHECK-NEXT: ret i8 [[ABS2]]
92+
;
93+
%abs1 = call i8 @llvm.abs.i8(i8 %a, i1 false)
94+
%mul = mul nsw i8 %abs1, %b
95+
%abs2 = call i8 @llvm.abs.i8(i8 %mul, i1 true)
96+
ret i8 %abs2
97+
}
98+
99+
; this should't propagate the nsw
100+
define i8 @test_nsw_with_false(i8 %a, i8 %b) {
101+
; CHECK-LABEL: @test_nsw_with_false(
102+
; CHECK-NEXT: [[TMP1:%.*]] = mul i8 [[B:%.*]], [[A:%.*]]
103+
; CHECK-NEXT: [[ABS2:%.*]] = call i8 @llvm.abs.i8(i8 [[TMP1]], i1 false)
104+
; CHECK-NEXT: ret i8 [[ABS2]]
105+
;
106+
%abs1 = call i8 @llvm.abs.i8(i8 %a, i1 false)
107+
%mul = mul nsw i8 %abs1, %b
108+
%abs2 = call i8 @llvm.abs.i8(i8 %mul, i1 false)
109+
ret i8 %abs2
110+
}
111+
112+
define i32 @test_abs_abs_a_mul_b_more_one_use(i32 %a, i32 %b) {
113+
; CHECK-LABEL: @test_abs_abs_a_mul_b_more_one_use(
114+
; CHECK-NEXT: [[ABS1:%.*]] = call i32 @llvm.abs.i32(i32 [[A:%.*]], i1 true)
115+
; CHECK-NEXT: [[MUL:%.*]] = mul i32 [[ABS1]], [[B:%.*]]
116+
; CHECK-NEXT: [[ABS2:%.*]] = call i32 @llvm.abs.i32(i32 [[MUL]], i1 false)
117+
; CHECK-NEXT: call void @use(i32 [[MUL]])
118+
; CHECK-NEXT: ret i32 [[ABS2]]
119+
;
120+
%abs1 = call i32 @llvm.abs.i32(i32 %a, i1 true)
121+
%mul = mul i32 %abs1, %b
122+
%abs2 = call i32 @llvm.abs.i32(i32 %mul, i1 false)
123+
call void @use(i32 %mul)
124+
ret i32 %abs2
125+
}
126+
127+
define <2 x i8> @test_abs_abs_a_mul_b_vector_i8(<2 x i8> %a, <2 x i8> %b) {
128+
; CHECK-LABEL: @test_abs_abs_a_mul_b_vector_i8(
129+
; CHECK-NEXT: [[TMP1:%.*]] = mul <2 x i8> [[B:%.*]], [[A:%.*]]
130+
; CHECK-NEXT: [[ABS2:%.*]] = call <2 x i8> @llvm.abs.v2i8(<2 x i8> [[TMP1]], i1 true)
131+
; CHECK-NEXT: ret <2 x i8> [[ABS2]]
132+
;
133+
%abs = call <2 x i8> @llvm.abs.v2i8(<2 x i8> %a, i1 true)
134+
%mul = mul <2 x i8> %abs, %b
135+
%abs2 = call <2 x i8> @llvm.abs.v2i8(<2 x i8> %mul, i1 true)
136+
ret <2 x i8> %abs2
137+
}
9138

10139
; abs preserves trailing zeros so the second and is unneeded
11140
define i32 @abs_trailing_zeros(i32 %x) {

0 commit comments

Comments
 (0)