Skip to content

Commit 408df51

Browse files
author
James Molloy
committedMar 24, 2015
"float2int": Add a new pass to demote from float to int where possible.
It is possible to have code that converts from integer to float, performs operations then converts back, and the result is provably the same as if integers were used. This can come from different sources, but the most obvious is a helper function that uses floats but the arguments given at an inlined callsites are integers. This pass considers all integers requiring a bitwidth less than or equal to the bitwidth of the mantissa of a floating point type (23 for floats, 52 for doubles) as exactly representable in floating point. To reduce the risk of harming efficient code, the pass only attempts to perform complete removal of inttofp/fptoint operations, not just move them around. llvm-svn: 233062
1 parent 7cb18bf commit 408df51

File tree

9 files changed

+795
-1
lines changed

9 files changed

+795
-1
lines changed
 

Diff for: ‎llvm/include/llvm/InitializePasses.h

+1
Original file line numberDiff line numberDiff line change
@@ -294,6 +294,7 @@ void initializeWinEHPreparePass(PassRegistry&);
294294
void initializePlaceBackedgeSafepointsImplPass(PassRegistry&);
295295
void initializePlaceSafepointsPass(PassRegistry&);
296296
void initializeDwarfEHPreparePass(PassRegistry&);
297+
void initializeFloat2IntPass(PassRegistry&);
297298
}
298299

299300
#endif

Diff for: ‎llvm/include/llvm/LinkAllPasses.h

+1
Original file line numberDiff line numberDiff line change
@@ -169,6 +169,7 @@ namespace {
169169
(void) llvm::createRewriteSymbolsPass();
170170
(void) llvm::createStraightLineStrengthReducePass();
171171
(void) llvm::createMemDerefPrinter();
172+
(void) llvm::createFloat2IntPass();
172173

173174
(void)new llvm::IntervalPartition();
174175
(void)new llvm::ScalarEvolution();

Diff for: ‎llvm/include/llvm/Transforms/Scalar.h

+6-1
Original file line numberDiff line numberDiff line change
@@ -429,7 +429,6 @@ BasicBlockPass *createLoadCombinePass();
429429

430430
FunctionPass *createStraightLineStrengthReducePass();
431431

432-
433432
//===----------------------------------------------------------------------===//
434433
//
435434
// PlaceSafepoints - Rewrite any IR calls to gc.statepoints and insert any
@@ -447,6 +446,12 @@ ModulePass *createPlaceSafepointsPass();
447446
//
448447
FunctionPass *createRewriteStatepointsForGCPass();
449448

449+
//===----------------------------------------------------------------------===//
450+
//
451+
// Float2Int - Demote floats to ints where possible.
452+
//
453+
FunctionPass *createFloat2IntPass();
454+
450455
} // End llvm namespace
451456

452457
#endif

Diff for: ‎llvm/lib/Transforms/IPO/PassManagerBuilder.cpp

+7
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,10 @@ static cl::opt<bool>
5959
RunLoopRerolling("reroll-loops", cl::Hidden,
6060
cl::desc("Run the loop rerolling pass"));
6161

62+
static cl::opt<bool>
63+
RunFloat2Int("float-to-int", cl::Hidden, cl::init(true),
64+
cl::desc("Run the float2int (float demotion) pass"));
65+
6266
static cl::opt<bool> RunLoadCombine("combine-loads", cl::init(false),
6367
cl::Hidden,
6468
cl::desc("Run the load combining pass"));
@@ -307,6 +311,9 @@ void PassManagerBuilder::populateModulePassManager(
307311
// we must insert a no-op module pass to reset the pass manager.
308312
MPM.add(createBarrierNoopPass());
309313

314+
if (RunFloat2Int)
315+
MPM.add(createFloat2IntPass());
316+
310317
// Re-rotate loops in all our loop nests. These may have fallout out of
311318
// rotated form due to GVN or other transformations, and the vectorizer relies
312319
// on the rotated form.

Diff for: ‎llvm/lib/Transforms/Scalar/CMakeLists.txt

+1
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ add_llvm_library(LLVMScalarOpts
99
DeadStoreElimination.cpp
1010
EarlyCSE.cpp
1111
FlattenCFGPass.cpp
12+
Float2Int.cpp
1213
GVN.cpp
1314
InductiveRangeCheckElimination.cpp
1415
IndVarSimplify.cpp

Diff for: ‎llvm/lib/Transforms/Scalar/Float2Int.cpp

+535
Large diffs are not rendered by default.

Diff for: ‎llvm/lib/Transforms/Scalar/Scalar.cpp

+1
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,7 @@ void llvm::initializeScalarOpts(PassRegistry &Registry) {
7777
initializeLoadCombinePass(Registry);
7878
initializePlaceBackedgeSafepointsImplPass(Registry);
7979
initializePlaceSafepointsPass(Registry);
80+
initializeFloat2IntPass(Registry);
8081
}
8182

8283
void LLVMInitializeScalarOpts(LLVMPassRegistryRef R) {

Diff for: ‎llvm/test/Transforms/Float2Int/basic.ll

+227
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,227 @@
1+
; RUN: opt < %s -float2int -S | FileCheck %s
2+
3+
;
4+
; Positive tests
5+
;
6+
7+
; CHECK-LABEL: @simple1
8+
; CHECK: %1 = zext i8 %a to i32
9+
; CHECK: %2 = add i32 %1, 1
10+
; CHECK: %3 = trunc i32 %2 to i16
11+
; CHECK: ret i16 %3
12+
define i16 @simple1(i8 %a) {
13+
%1 = uitofp i8 %a to float
14+
%2 = fadd float %1, 1.0
15+
%3 = fptoui float %2 to i16
16+
ret i16 %3
17+
}
18+
19+
; CHECK-LABEL: @simple2
20+
; CHECK: %1 = zext i8 %a to i32
21+
; CHECK: %2 = sub i32 %1, 1
22+
; CHECK: %3 = trunc i32 %2 to i8
23+
; CHECK: ret i8 %3
24+
define i8 @simple2(i8 %a) {
25+
%1 = uitofp i8 %a to float
26+
%2 = fsub float %1, 1.0
27+
%3 = fptoui float %2 to i8
28+
ret i8 %3
29+
}
30+
31+
; CHECK-LABEL: @simple3
32+
; CHECK: %1 = zext i8 %a to i32
33+
; CHECK: %2 = sub i32 %1, 1
34+
; CHECK: ret i32 %2
35+
define i32 @simple3(i8 %a) {
36+
%1 = uitofp i8 %a to float
37+
%2 = fsub float %1, 1.0
38+
%3 = fptoui float %2 to i32
39+
ret i32 %3
40+
}
41+
42+
; CHECK-LABEL: @cmp
43+
; CHECK: %1 = zext i8 %a to i32
44+
; CHECK: %2 = zext i8 %b to i32
45+
; CHECK: %3 = icmp slt i32 %1, %2
46+
; CHECK: ret i1 %3
47+
define i1 @cmp(i8 %a, i8 %b) {
48+
%1 = uitofp i8 %a to float
49+
%2 = uitofp i8 %b to float
50+
%3 = fcmp ult float %1, %2
51+
ret i1 %3
52+
}
53+
54+
; CHECK-LABEL: @simple4
55+
; CHECK: %1 = zext i32 %a to i64
56+
; CHECK: %2 = add i64 %1, 1
57+
; CHECK: %3 = trunc i64 %2 to i32
58+
; CHECK: ret i32 %3
59+
define i32 @simple4(i32 %a) {
60+
%1 = uitofp i32 %a to double
61+
%2 = fadd double %1, 1.0
62+
%3 = fptoui double %2 to i32
63+
ret i32 %3
64+
}
65+
66+
; CHECK-LABEL: @simple5
67+
; CHECK: %1 = zext i8 %a to i32
68+
; CHECK: %2 = zext i8 %b to i32
69+
; CHECK: %3 = add i32 %1, 1
70+
; CHECK: %4 = mul i32 %3, %2
71+
; CHECK: ret i32 %4
72+
define i32 @simple5(i8 %a, i8 %b) {
73+
%1 = uitofp i8 %a to float
74+
%2 = uitofp i8 %b to float
75+
%3 = fadd float %1, 1.0
76+
%4 = fmul float %3, %2
77+
%5 = fptoui float %4 to i32
78+
ret i32 %5
79+
}
80+
81+
; The two chains don't interact - failure of one shouldn't
82+
; cause failure of the other.
83+
84+
; CHECK-LABEL: @multi1
85+
; CHECK: %1 = zext i8 %a to i32
86+
; CHECK: %2 = zext i8 %b to i32
87+
; CHECK: %fc = uitofp i8 %c to float
88+
; CHECK: %x1 = add i32 %1, %2
89+
; CHECK: %z = fadd float %fc, %d
90+
; CHECK: %w = fptoui float %z to i32
91+
; CHECK: %r = add i32 %x1, %w
92+
; CHECK: ret i32 %r
93+
define i32 @multi1(i8 %a, i8 %b, i8 %c, float %d) {
94+
%fa = uitofp i8 %a to float
95+
%fb = uitofp i8 %b to float
96+
%fc = uitofp i8 %c to float
97+
%x = fadd float %fa, %fb
98+
%y = fptoui float %x to i32
99+
%z = fadd float %fc, %d
100+
%w = fptoui float %z to i32
101+
%r = add i32 %y, %w
102+
ret i32 %r
103+
}
104+
105+
; CHECK-LABEL: @simple_negzero
106+
; CHECK: %1 = zext i8 %a to i32
107+
; CHECK: %2 = add i32 %1, 0
108+
; CHECK: %3 = trunc i32 %2 to i16
109+
; CHECK: ret i16 %3
110+
define i16 @simple_negzero(i8 %a) {
111+
%1 = uitofp i8 %a to float
112+
%2 = fadd fast float %1, -0.0
113+
%3 = fptoui float %2 to i16
114+
ret i16 %3
115+
}
116+
117+
;
118+
; Negative tests
119+
;
120+
121+
; CHECK-LABEL: @neg_multi1
122+
; CHECK: %fa = uitofp i8 %a to float
123+
; CHECK: %fc = uitofp i8 %c to float
124+
; CHECK: %x = fadd float %fa, %fc
125+
; CHECK: %y = fptoui float %x to i32
126+
; CHECK: %z = fadd float %fc, %d
127+
; CHECK: %w = fptoui float %z to i32
128+
; CHECK: %r = add i32 %y, %w
129+
; CHECK: ret i32 %r
130+
; The two chains intersect, which means because one fails, no
131+
; transform can occur.
132+
define i32 @neg_multi1(i8 %a, i8 %b, i8 %c, float %d) {
133+
%fa = uitofp i8 %a to float
134+
%fc = uitofp i8 %c to float
135+
%x = fadd float %fa, %fc
136+
%y = fptoui float %x to i32
137+
%z = fadd float %fc, %d
138+
%w = fptoui float %z to i32
139+
%r = add i32 %y, %w
140+
ret i32 %r
141+
}
142+
143+
; CHECK-LABEL: @neg_muld
144+
; CHECK: %fa = uitofp i32 %a to double
145+
; CHECK: %fb = uitofp i32 %b to double
146+
; CHECK: %mul = fmul double %fa, %fb
147+
; CHECK: %r = fptoui double %mul to i64
148+
; CHECK: ret i64 %r
149+
; The i32 * i32 = i64, which has 64 bits, which is greater than the 52 bits
150+
; that can be exactly represented in a double.
151+
define i64 @neg_muld(i32 %a, i32 %b) {
152+
%fa = uitofp i32 %a to double
153+
%fb = uitofp i32 %b to double
154+
%mul = fmul double %fa, %fb
155+
%r = fptoui double %mul to i64
156+
ret i64 %r
157+
}
158+
159+
; CHECK-LABEL: @neg_mulf
160+
; CHECK: %fa = uitofp i16 %a to float
161+
; CHECK: %fb = uitofp i16 %b to float
162+
; CHECK: %mul = fmul float %fa, %fb
163+
; CHECK: %r = fptoui float %mul to i32
164+
; CHECK: ret i32 %r
165+
; The i16 * i16 = i32, which can't be represented in a float, but can in a
166+
; double. This should fail, as the written code uses floats, not doubles so
167+
; the original result may be inaccurate.
168+
define i32 @neg_mulf(i16 %a, i16 %b) {
169+
%fa = uitofp i16 %a to float
170+
%fb = uitofp i16 %b to float
171+
%mul = fmul float %fa, %fb
172+
%r = fptoui float %mul to i32
173+
ret i32 %r
174+
}
175+
176+
; CHECK-LABEL: @neg_cmp
177+
; CHECK: %1 = uitofp i8 %a to float
178+
; CHECK: %2 = uitofp i8 %b to float
179+
; CHECK: %3 = fcmp false float %1, %2
180+
; CHECK: ret i1 %3
181+
; "false" doesn't have an icmp equivalent.
182+
define i1 @neg_cmp(i8 %a, i8 %b) {
183+
%1 = uitofp i8 %a to float
184+
%2 = uitofp i8 %b to float
185+
%3 = fcmp false float %1, %2
186+
ret i1 %3
187+
}
188+
189+
; CHECK-LABEL: @neg_div
190+
; CHECK: %1 = uitofp i8 %a to float
191+
; CHECK: %2 = fdiv float %1, 1.0
192+
; CHECK: %3 = fptoui float %2 to i16
193+
; CHECK: ret i16 %3
194+
; Division isn't a supported operator.
195+
define i16 @neg_div(i8 %a) {
196+
%1 = uitofp i8 %a to float
197+
%2 = fdiv float %1, 1.0
198+
%3 = fptoui float %2 to i16
199+
ret i16 %3
200+
}
201+
202+
; CHECK-LABEL: @neg_remainder
203+
; CHECK: %1 = uitofp i8 %a to float
204+
; CHECK: %2 = fadd float %1, 1.2
205+
; CHECK: %3 = fptoui float %2 to i16
206+
; CHECK: ret i16 %3
207+
; 1.2 is not an integer.
208+
define i16 @neg_remainder(i8 %a) {
209+
%1 = uitofp i8 %a to float
210+
%2 = fadd float %1, 1.25
211+
%3 = fptoui float %2 to i16
212+
ret i16 %3
213+
}
214+
215+
; CHECK-LABEL: @neg_toolarge
216+
; CHECK: %1 = uitofp i80 %a to fp128
217+
; CHECK: %2 = fadd fp128 %1, %1
218+
; CHECK: %3 = fptoui fp128 %2 to i80
219+
; CHECK: ret i80 %3
220+
; i80 > i64, which is the largest bitwidth handleable by default.
221+
define i80 @neg_toolarge(i80 %a) {
222+
%1 = uitofp i80 %a to fp128
223+
%2 = fadd fp128 %1, %1
224+
%3 = fptoui fp128 %2 to i80
225+
ret i80 %3
226+
}
227+

Diff for: ‎llvm/test/Transforms/Float2Int/toolarge.ll

+16
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
; RUN: opt < %s -float2int -float2int-max-integer-bw=256 -S | FileCheck %s
2+
3+
; CHECK-LABEL: @neg_toolarge
4+
; CHECK: %1 = uitofp i80 %a to fp128
5+
; CHECK: %2 = fadd fp128 %1, %1
6+
; CHECK: %3 = fptoui fp128 %2 to i80
7+
; CHECK: ret i80 %3
8+
; fp128 has a 112-bit mantissa, which can hold an i80. But we only support
9+
; up to i64, so it should fail (even though the max integer bitwidth is 256).
10+
define i80 @neg_toolarge(i80 %a) {
11+
%1 = uitofp i80 %a to fp128
12+
%2 = fadd fp128 %1, %1
13+
%3 = fptoui fp128 %2 to i80
14+
ret i80 %3
15+
}
16+

0 commit comments

Comments
 (0)
Please sign in to comment.