Skip to content

Commit ea68668

Browse files
[InstCombine] Add fold for fabs(-x) -> fabs(x) (#95627)
This patch folds `fabs(-x) -> fabs(x)` Closes #94170 Proofs: https://alive2.llvm.org/ce/z/gjzmgf
1 parent fa0e9ac commit ea68668

File tree

2 files changed

+196
-4
lines changed

2 files changed

+196
-4
lines changed

llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2511,16 +2511,22 @@ Instruction *InstCombinerImpl::visitCallInst(CallInst &CI) {
25112511
}
25122512
case Intrinsic::fabs: {
25132513
Value *Cond, *TVal, *FVal;
2514-
if (match(II->getArgOperand(0),
2515-
m_Select(m_Value(Cond), m_Value(TVal), m_Value(FVal)))) {
2514+
Value *Arg = II->getArgOperand(0);
2515+
Value *X;
2516+
// fabs (-X) --> fabs (X)
2517+
if (match(Arg, m_FNeg(m_Value(X)))) {
2518+
CallInst *Fabs = Builder.CreateUnaryIntrinsic(Intrinsic::fabs, X, II);
2519+
return replaceInstUsesWith(CI, Fabs);
2520+
}
2521+
2522+
if (match(Arg, m_Select(m_Value(Cond), m_Value(TVal), m_Value(FVal)))) {
25162523
// fabs (select Cond, TrueC, FalseC) --> select Cond, AbsT, AbsF
25172524
if (isa<Constant>(TVal) || isa<Constant>(FVal)) {
25182525
CallInst *AbsT = Builder.CreateCall(II->getCalledFunction(), {TVal});
25192526
CallInst *AbsF = Builder.CreateCall(II->getCalledFunction(), {FVal});
25202527
SelectInst *SI = SelectInst::Create(Cond, AbsT, AbsF);
25212528
FastMathFlags FMF1 = II->getFastMathFlags();
2522-
FastMathFlags FMF2 =
2523-
cast<SelectInst>(II->getArgOperand(0))->getFastMathFlags();
2529+
FastMathFlags FMF2 = cast<SelectInst>(Arg)->getFastMathFlags();
25242530
FMF2.setNoSignedZeros(false);
25252531
SI->setFastMathFlags(FMF1 | FMF2);
25262532
return SI;
Lines changed: 186 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,186 @@
1+
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 5
2+
; RUN: opt -S -passes=instcombine %s | FileCheck %s
3+
4+
define float @fabs_fneg_basic(float %x) {
5+
; CHECK-LABEL: define float @fabs_fneg_basic(
6+
; CHECK-SAME: float [[X:%.*]]) {
7+
; CHECK-NEXT: [[FABS:%.*]] = call float @llvm.fabs.f32(float [[X]])
8+
; CHECK-NEXT: ret float [[FABS]]
9+
;
10+
%neg = fneg float %x
11+
%fabs = call float @llvm.fabs.f32(float %neg)
12+
ret float %fabs
13+
}
14+
15+
define <2 x float> @fabs_fneg_v2f32(<2 x float> %x) {
16+
; CHECK-LABEL: define <2 x float> @fabs_fneg_v2f32(
17+
; CHECK-SAME: <2 x float> [[X:%.*]]) {
18+
; CHECK-NEXT: [[FABS:%.*]] = call <2 x float> @llvm.fabs.v2f32(<2 x float> [[X]])
19+
; CHECK-NEXT: ret <2 x float> [[FABS]]
20+
;
21+
%neg = fneg <2 x float> %x
22+
%fabs = call <2 x float> @llvm.fabs.v2f32(<2 x float> %neg)
23+
ret <2 x float> %fabs
24+
}
25+
26+
define double @fabs_fneg_f64(double %x) {
27+
; CHECK-LABEL: define double @fabs_fneg_f64(
28+
; CHECK-SAME: double [[X:%.*]]) {
29+
; CHECK-NEXT: [[FABS:%.*]] = call double @llvm.fabs.f64(double [[X]])
30+
; CHECK-NEXT: ret double [[FABS]]
31+
;
32+
%neg = fneg double %x
33+
%fabs = call double @llvm.fabs.f64(double %neg)
34+
ret double %fabs
35+
}
36+
37+
define <4 x double> @fabs_fneg_v4f64(<4 x double> %x) {
38+
; CHECK-LABEL: define <4 x double> @fabs_fneg_v4f64(
39+
; CHECK-SAME: <4 x double> [[X:%.*]]) {
40+
; CHECK-NEXT: [[FABS:%.*]] = call <4 x double> @llvm.fabs.v4f64(<4 x double> [[X]])
41+
; CHECK-NEXT: ret <4 x double> [[FABS]]
42+
;
43+
%neg = fneg <4 x double> %x
44+
%fabs = call <4 x double> @llvm.fabs.v4f64(<4 x double> %neg)
45+
ret <4 x double> %fabs
46+
}
47+
48+
define half @fabs_fneg_f16(half %x) {
49+
; CHECK-LABEL: define half @fabs_fneg_f16(
50+
; CHECK-SAME: half [[X:%.*]]) {
51+
; CHECK-NEXT: [[FABS:%.*]] = call half @llvm.fabs.f16(half [[X]])
52+
; CHECK-NEXT: ret half [[FABS]]
53+
;
54+
%neg = fneg half %x
55+
%fabs = call half @llvm.fabs.f16(half %neg)
56+
ret half %fabs
57+
}
58+
59+
define float @fabs_copysign_nnan(float %x, float %y) {
60+
; CHECK-LABEL: define float @fabs_copysign_nnan(
61+
; CHECK-SAME: float [[X:%.*]], float [[Y:%.*]]) {
62+
; CHECK-NEXT: [[FABS:%.*]] = call nnan float @llvm.fabs.f32(float [[X]])
63+
; CHECK-NEXT: ret float [[FABS]]
64+
;
65+
%copysign = call float @llvm.copysign.f32(float %x, float %y)
66+
%fabs = call nnan float @llvm.fabs.f32(float %copysign)
67+
ret float %fabs
68+
}
69+
70+
71+
define float @fabs_copysign_ninf(float %x, float %y) {
72+
; CHECK-LABEL: define float @fabs_copysign_ninf(
73+
; CHECK-SAME: float [[X:%.*]], float [[Y:%.*]]) {
74+
; CHECK-NEXT: [[FABS:%.*]] = call ninf float @llvm.fabs.f32(float [[X]])
75+
; CHECK-NEXT: ret float [[FABS]]
76+
;
77+
%copysign = call float @llvm.copysign.f32(float %x, float %y)
78+
%fabs = call ninf float @llvm.fabs.f32(float %copysign)
79+
ret float %fabs
80+
}
81+
82+
define float @fabs_copysign_nsz(float %x, float %y) {
83+
; CHECK-LABEL: define float @fabs_copysign_nsz(
84+
; CHECK-SAME: float [[X:%.*]], float [[Y:%.*]]) {
85+
; CHECK-NEXT: [[FABS:%.*]] = call nsz float @llvm.fabs.f32(float [[X]])
86+
; CHECK-NEXT: ret float [[FABS]]
87+
;
88+
%copysign = call float @llvm.copysign.f32(float %x, float %y)
89+
%fabs = call nsz float @llvm.fabs.f32(float %copysign)
90+
ret float %fabs
91+
}
92+
93+
define float @fabs_copysign_nnan_negative(float %x, float %y) {
94+
; CHECK-LABEL: define float @fabs_copysign_nnan_negative(
95+
; CHECK-SAME: float [[X:%.*]], float [[Y:%.*]]) {
96+
; CHECK-NEXT: [[FABS:%.*]] = call nnan float @llvm.fabs.f32(float [[X]])
97+
; CHECK-NEXT: ret float [[FABS]]
98+
;
99+
%copysign = call float @llvm.copysign.f32(float %x, float %y)
100+
%fabs = call nnan float @llvm.fabs.f32(float %copysign)
101+
ret float %fabs
102+
}
103+
104+
105+
define float @fabs_copysign_ninf_negative(float %x, float %y) {
106+
; CHECK-LABEL: define float @fabs_copysign_ninf_negative(
107+
; CHECK-SAME: float [[X:%.*]], float [[Y:%.*]]) {
108+
; CHECK-NEXT: [[FABS:%.*]] = call ninf float @llvm.fabs.f32(float [[X]])
109+
; CHECK-NEXT: ret float [[FABS]]
110+
;
111+
%copysign = call float @llvm.copysign.f32(float %x, float %y)
112+
%fabs = call ninf float @llvm.fabs.f32(float %copysign)
113+
ret float %fabs
114+
}
115+
116+
define float @fabs_copysign_nsz_negative(float %x, float %y) {
117+
; CHECK-LABEL: define float @fabs_copysign_nsz_negative(
118+
; CHECK-SAME: float [[X:%.*]], float [[Y:%.*]]) {
119+
; CHECK-NEXT: [[FABS:%.*]] = call nsz float @llvm.fabs.f32(float [[X]])
120+
; CHECK-NEXT: ret float [[FABS]]
121+
;
122+
%copysign = call float @llvm.copysign.f32(float %x, float %y)
123+
%fabs = call nsz float @llvm.fabs.f32(float %copysign)
124+
ret float %fabs
125+
}
126+
127+
define float @fabs_fneg_no_fabs(float %x) {
128+
; CHECK-LABEL: define float @fabs_fneg_no_fabs(
129+
; CHECK-SAME: float [[X:%.*]]) {
130+
; CHECK-NEXT: [[NEG:%.*]] = fneg float [[X]]
131+
; CHECK-NEXT: ret float [[NEG]]
132+
;
133+
%neg = fneg float %x
134+
ret float %neg
135+
}
136+
137+
define <2 x float> @fabs_fneg_splat_v2f32(<2 x float> %x) {
138+
; CHECK-LABEL: define <2 x float> @fabs_fneg_splat_v2f32(
139+
; CHECK-SAME: <2 x float> [[X:%.*]]) {
140+
; CHECK-NEXT: ret <2 x float> <float 2.000000e+00, float 2.000000e+00>
141+
;
142+
%neg = fneg <2 x float> <float -2.0, float -2.0>
143+
%fabs = call <2 x float> @llvm.fabs.v2f32(<2 x float> %neg)
144+
ret <2 x float> %fabs
145+
}
146+
147+
148+
define <2 x float> @fabs_fneg_splat_poison_v2f32(<2 x float> %x) {
149+
; CHECK-LABEL: define <2 x float> @fabs_fneg_splat_poison_v2f32(
150+
; CHECK-SAME: <2 x float> [[X:%.*]]) {
151+
; CHECK-NEXT: [[FABS:%.*]] = call <2 x float> @llvm.fabs.v2f32(<2 x float> <float -2.000000e+00, float poison>)
152+
; CHECK-NEXT: ret <2 x float> [[FABS]]
153+
;
154+
%neg = fneg <2 x float> <float 2.0, float poison>
155+
%fabs = call <2 x float> @llvm.fabs.v2f32(<2 x float> %neg)
156+
ret <2 x float> %fabs
157+
}
158+
159+
define <2 x float> @fabs_fneg_non_splat_v2f32(<2 x float> %x) {
160+
; CHECK-LABEL: define <2 x float> @fabs_fneg_non_splat_v2f32(
161+
; CHECK-SAME: <2 x float> [[X:%.*]]) {
162+
; CHECK-NEXT: ret <2 x float> <float 2.000000e+00, float 3.000000e+00>
163+
;
164+
%neg = fneg <2 x float> <float 2.0, float 3.0>
165+
%fabs = call <2 x float> @llvm.fabs.v2f32(<2 x float> %neg)
166+
ret <2 x float> %fabs
167+
}
168+
169+
declare void @use(float)
170+
171+
define float @fabs_fneg_multi_use(float %x) {
172+
; CHECK-LABEL: define float @fabs_fneg_multi_use(
173+
; CHECK-SAME: float [[X:%.*]]) {
174+
; CHECK-NEXT: [[NEG:%.*]] = fneg float [[X]]
175+
; CHECK-NEXT: call void @use(float [[NEG]])
176+
; CHECK-NEXT: [[FABS:%.*]] = call float @llvm.fabs.f32(float [[X]])
177+
; CHECK-NEXT: ret float [[FABS]]
178+
;
179+
%neg = fneg float %x
180+
call void @use(float %neg)
181+
%fabs = call float @llvm.fabs.f32(float %neg)
182+
ret float %fabs
183+
}
184+
185+
186+

0 commit comments

Comments
 (0)