Skip to content

Commit 390b997

Browse files
authored
[InstCombine] Handle isNanOrInf idioms (#80414)
This patch folds: ``` (icmp eq (and (bitcast X to int), ExponentMask), ExponentMask) --> llvm.is.fpclass(X, fcInf|fcNan) (icmp ne (and (bitcast X to int), ExponentMask), ExponentMask) --> llvm.is.fpclass(X, ~(fcInf|fcNan)) ``` Alive2: https://alive2.llvm.org/ce/z/_hXAAF
1 parent 08e942a commit 390b997

File tree

2 files changed

+230
-0
lines changed

2 files changed

+230
-0
lines changed

llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1827,6 +1827,33 @@ Instruction *InstCombinerImpl::foldICmpAndConstConst(ICmpInst &Cmp,
18271827
}
18281828
}
18291829

1830+
// (icmp eq (and (bitcast X to int), ExponentMask), ExponentMask) -->
1831+
// llvm.is.fpclass(X, fcInf|fcNan)
1832+
// (icmp ne (and (bitcast X to int), ExponentMask), ExponentMask) -->
1833+
// llvm.is.fpclass(X, ~(fcInf|fcNan))
1834+
Value *V;
1835+
if (!Cmp.getParent()->getParent()->hasFnAttribute(
1836+
Attribute::NoImplicitFloat) &&
1837+
Cmp.isEquality() && match(X, m_OneUse(m_BitCast(m_Value(V))))) {
1838+
Type *SrcType = V->getType();
1839+
Type *DstType = X->getType();
1840+
Type *FPType = SrcType->getScalarType();
1841+
// Make sure the bitcast doesn't change between scalar and vector and
1842+
// doesn't change the number of vector elements.
1843+
if (SrcType->isVectorTy() == DstType->isVectorTy() &&
1844+
SrcType->getScalarSizeInBits() == DstType->getScalarSizeInBits() &&
1845+
FPType->isIEEELikeFPTy() && C1 == *C2) {
1846+
APInt ExponentMask =
1847+
APFloat::getInf(FPType->getFltSemantics()).bitcastToAPInt();
1848+
if (C1 == ExponentMask) {
1849+
unsigned Mask = FPClassTest::fcNan | FPClassTest::fcInf;
1850+
if (isICMP_NE)
1851+
Mask = ~Mask & fcAllFlags;
1852+
return replaceInstUsesWith(Cmp, Builder.createIsFPClass(V, Mask));
1853+
}
1854+
}
1855+
}
1856+
18301857
return nullptr;
18311858
}
18321859

Lines changed: 203 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,203 @@
1+
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 4
2+
; RUN: opt -S -passes=instcombine < %s | FileCheck %s
3+
4+
define i1 @f32_fcnan_fcinf(float %a) {
5+
; CHECK-LABEL: define i1 @f32_fcnan_fcinf(
6+
; CHECK-SAME: float [[A:%.*]]) {
7+
; CHECK-NEXT: [[TMP1:%.*]] = call float @llvm.fabs.f32(float [[A]])
8+
; CHECK-NEXT: [[CMP:%.*]] = fcmp ueq float [[TMP1]], 0x7FF0000000000000
9+
; CHECK-NEXT: ret i1 [[CMP]]
10+
;
11+
%i32 = bitcast float %a to i32
12+
%and = and i32 %i32, 2139095040
13+
%cmp = icmp eq i32 %and, 2139095040
14+
ret i1 %cmp
15+
}
16+
17+
define i1 @f32_not_fcnan_fcinf(float %a) {
18+
; CHECK-LABEL: define i1 @f32_not_fcnan_fcinf(
19+
; CHECK-SAME: float [[A:%.*]]) {
20+
; CHECK-NEXT: [[TMP1:%.*]] = call float @llvm.fabs.f32(float [[A]])
21+
; CHECK-NEXT: [[CMP:%.*]] = fcmp one float [[TMP1]], 0x7FF0000000000000
22+
; CHECK-NEXT: ret i1 [[CMP]]
23+
;
24+
%i32 = bitcast float %a to i32
25+
%and = and i32 %i32, 2139095040
26+
%cmp = icmp ne i32 %and, 2139095040
27+
ret i1 %cmp
28+
}
29+
30+
define i1 @f64_fcnan_fcinf(double %a) {
31+
; CHECK-LABEL: define i1 @f64_fcnan_fcinf(
32+
; CHECK-SAME: double [[A:%.*]]) {
33+
; CHECK-NEXT: [[TMP1:%.*]] = call double @llvm.fabs.f64(double [[A]])
34+
; CHECK-NEXT: [[CMP:%.*]] = fcmp ueq double [[TMP1]], 0x7FF0000000000000
35+
; CHECK-NEXT: ret i1 [[CMP]]
36+
;
37+
%i64 = bitcast double %a to i64
38+
%and = and i64 %i64, 9218868437227405312
39+
%cmp = icmp eq i64 %and, 9218868437227405312
40+
ret i1 %cmp
41+
}
42+
43+
; TODO: handle more fpclass check idioms
44+
define i1 @f32_fcinf(float %a) {
45+
; CHECK-LABEL: define i1 @f32_fcinf(
46+
; CHECK-SAME: float [[A:%.*]]) {
47+
; CHECK-NEXT: [[TMP1:%.*]] = call float @llvm.fabs.f32(float [[A]])
48+
; CHECK-NEXT: [[AND:%.*]] = bitcast float [[TMP1]] to i32
49+
; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[AND]], 2139095040
50+
; CHECK-NEXT: ret i1 [[CMP]]
51+
;
52+
%i32 = bitcast float %a to i32
53+
%and = and i32 %i32, 2147483647
54+
%cmp = icmp eq i32 %and, 2139095040
55+
ret i1 %cmp
56+
}
57+
58+
define i1 @f32_fcnan(float %a) {
59+
; CHECK-LABEL: define i1 @f32_fcnan(
60+
; CHECK-SAME: float [[A:%.*]]) {
61+
; CHECK-NEXT: [[I32:%.*]] = bitcast float [[A]] to i32
62+
; CHECK-NEXT: [[AND1:%.*]] = and i32 [[I32]], 2139095040
63+
; CHECK-NEXT: [[CMP1:%.*]] = icmp eq i32 [[AND1]], 2139095040
64+
; CHECK-NEXT: [[AND2:%.*]] = and i32 [[I32]], 8388607
65+
; CHECK-NEXT: [[CMP2:%.*]] = icmp ne i32 [[AND2]], 0
66+
; CHECK-NEXT: [[RES:%.*]] = and i1 [[CMP1]], [[CMP2]]
67+
; CHECK-NEXT: ret i1 [[RES]]
68+
;
69+
%i32 = bitcast float %a to i32
70+
%and1 = and i32 %i32, 2139095040
71+
%cmp1 = icmp eq i32 %and1, 2139095040
72+
%and2 = and i32 %i32, 8388607
73+
%cmp2 = icmp ne i32 %and2, 0
74+
%res = and i1 %cmp1, %cmp2
75+
ret i1 %res
76+
}
77+
78+
define i1 @f32_fcnan_fcinf_strictfp(float %a) strictfp {
79+
; CHECK-LABEL: define i1 @f32_fcnan_fcinf_strictfp(
80+
; CHECK-SAME: float [[A:%.*]]) #[[ATTR0:[0-9]+]] {
81+
; CHECK-NEXT: [[TMP1:%.*]] = call float @llvm.fabs.f32(float [[A]])
82+
; CHECK-NEXT: [[CMP:%.*]] = fcmp ueq float [[TMP1]], 0x7FF0000000000000
83+
; CHECK-NEXT: ret i1 [[CMP]]
84+
;
85+
%i32 = bitcast float %a to i32
86+
%and = and i32 %i32, 2139095040
87+
%cmp = icmp eq i32 %and, 2139095040
88+
ret i1 %cmp
89+
}
90+
91+
define <2 x i1> @f32_fcnan_fcinf_vec(<2 x float> %a) {
92+
; CHECK-LABEL: define <2 x i1> @f32_fcnan_fcinf_vec(
93+
; CHECK-SAME: <2 x float> [[A:%.*]]) {
94+
; CHECK-NEXT: [[TMP1:%.*]] = call <2 x float> @llvm.fabs.v2f32(<2 x float> [[A]])
95+
; CHECK-NEXT: [[CMP:%.*]] = fcmp ueq <2 x float> [[TMP1]], <float 0x7FF0000000000000, float 0x7FF0000000000000>
96+
; CHECK-NEXT: ret <2 x i1> [[CMP]]
97+
;
98+
%i32 = bitcast <2 x float> %a to <2 x i32>
99+
%and = and <2 x i32> %i32, <i32 2139095040, i32 2139095040>
100+
%cmp = icmp eq <2 x i32> %and, <i32 2139095040, i32 2139095040>
101+
ret <2 x i1> %cmp
102+
}
103+
104+
; Negative tests
105+
106+
define i1 @f32_fcnan_fcinf_wrong_mask1(float %a) {
107+
; CHECK-LABEL: define i1 @f32_fcnan_fcinf_wrong_mask1(
108+
; CHECK-SAME: float [[A:%.*]]) {
109+
; CHECK-NEXT: [[I32:%.*]] = bitcast float [[A]] to i32
110+
; CHECK-NEXT: [[AND:%.*]] = and i32 [[I32]], 2139095041
111+
; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[AND]], 2139095040
112+
; CHECK-NEXT: ret i1 [[CMP]]
113+
;
114+
%i32 = bitcast float %a to i32
115+
%and = and i32 %i32, 2139095041
116+
%cmp = icmp eq i32 %and, 2139095040
117+
ret i1 %cmp
118+
}
119+
120+
define i1 @f32_fcnan_fcinf_wrong_mask2(float %a) {
121+
; CHECK-LABEL: define i1 @f32_fcnan_fcinf_wrong_mask2(
122+
; CHECK-SAME: float [[A:%.*]]) {
123+
; CHECK-NEXT: [[I32:%.*]] = bitcast float [[A]] to i32
124+
; CHECK-NEXT: [[AND:%.*]] = and i32 [[I32]], 2139095040
125+
; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[AND]], 2130706432
126+
; CHECK-NEXT: ret i1 [[CMP]]
127+
;
128+
%i32 = bitcast float %a to i32
129+
%and = and i32 %i32, 2139095040
130+
%cmp = icmp eq i32 %and, 2130706432
131+
ret i1 %cmp
132+
}
133+
134+
define i1 @f64_fcnan_fcinf_wrong_mask3(double %a) {
135+
; CHECK-LABEL: define i1 @f64_fcnan_fcinf_wrong_mask3(
136+
; CHECK-SAME: double [[A:%.*]]) {
137+
; CHECK-NEXT: [[I64:%.*]] = bitcast double [[A]] to i64
138+
; CHECK-NEXT: [[AND:%.*]] = and i64 [[I64]], 2139095040
139+
; CHECK-NEXT: [[CMP:%.*]] = icmp eq i64 [[AND]], 2139095040
140+
; CHECK-NEXT: ret i1 [[CMP]]
141+
;
142+
%i64 = bitcast double %a to i64
143+
%and = and i64 %i64, 2139095040
144+
%cmp = icmp eq i64 %and, 2139095040
145+
ret i1 %cmp
146+
}
147+
148+
define i1 @f32_fcnan_fcinf_wrong_pred(float %a) {
149+
; CHECK-LABEL: define i1 @f32_fcnan_fcinf_wrong_pred(
150+
; CHECK-SAME: float [[A:%.*]]) {
151+
; CHECK-NEXT: [[TMP1:%.*]] = call float @llvm.fabs.f32(float [[A]])
152+
; CHECK-NEXT: [[CMP:%.*]] = fcmp one float [[TMP1]], 0x7FF0000000000000
153+
; CHECK-NEXT: ret i1 [[CMP]]
154+
;
155+
%i32 = bitcast float %a to i32
156+
%and = and i32 %i32, 2139095040
157+
%cmp = icmp slt i32 %and, 2139095040
158+
ret i1 %cmp
159+
}
160+
161+
define i1 @f32_fcnan_fcinf_wrong_type1(<2 x float> %a) {
162+
; CHECK-LABEL: define i1 @f32_fcnan_fcinf_wrong_type1(
163+
; CHECK-SAME: <2 x float> [[A:%.*]]) {
164+
; CHECK-NEXT: [[I64:%.*]] = bitcast <2 x float> [[A]] to i64
165+
; CHECK-NEXT: [[AND:%.*]] = and i64 [[I64]], 2139095040
166+
; CHECK-NEXT: [[CMP:%.*]] = icmp eq i64 [[AND]], 2139095040
167+
; CHECK-NEXT: ret i1 [[CMP]]
168+
;
169+
%i64 = bitcast <2 x float> %a to i64
170+
%and = and i64 %i64, 2139095040
171+
%cmp = icmp eq i64 %and, 2139095040
172+
ret i1 %cmp
173+
}
174+
175+
define i1 @f32_fcnan_fcinf_wrong_type2(x86_fp80 %a) {
176+
; CHECK-LABEL: define i1 @f32_fcnan_fcinf_wrong_type2(
177+
; CHECK-SAME: x86_fp80 [[A:%.*]]) {
178+
; CHECK-NEXT: [[I80:%.*]] = bitcast x86_fp80 [[A]] to i80
179+
; CHECK-NEXT: [[AND:%.*]] = and i80 [[I80]], 2139095040
180+
; CHECK-NEXT: [[CMP:%.*]] = icmp eq i80 [[AND]], 2139095040
181+
; CHECK-NEXT: ret i1 [[CMP]]
182+
;
183+
%i80 = bitcast x86_fp80 %a to i80
184+
%and = and i80 %i80, 2139095040
185+
%cmp = icmp eq i80 %and, 2139095040
186+
ret i1 %cmp
187+
}
188+
189+
define i1 @f32_fcnan_fcinf_noimplicitfloat(float %a) #0 {
190+
; CHECK-LABEL: define i1 @f32_fcnan_fcinf_noimplicitfloat(
191+
; CHECK-SAME: float [[A:%.*]]) #[[ATTR1:[0-9]+]] {
192+
; CHECK-NEXT: [[I32:%.*]] = bitcast float [[A]] to i32
193+
; CHECK-NEXT: [[AND:%.*]] = and i32 [[I32]], 2139095040
194+
; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[AND]], 2139095040
195+
; CHECK-NEXT: ret i1 [[CMP]]
196+
;
197+
%i32 = bitcast float %a to i32
198+
%and = and i32 %i32, 2139095040
199+
%cmp = icmp eq i32 %and, 2139095040
200+
ret i1 %cmp
201+
}
202+
203+
attributes #0 = { noimplicitfloat }

0 commit comments

Comments
 (0)