Skip to content

Commit fc166a9

Browse files
committed
compiler: test float to int conversions and fix upper-bound calculation
1 parent a867b56 commit fc166a9

File tree

6 files changed

+144
-7
lines changed

6 files changed

+144
-7
lines changed

compiler/compiler.go

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2569,7 +2569,7 @@ func (b *builder) createConvert(typeFrom, typeTo types.Type, value llvm.Value, p
25692569
maxFloat := float64(max)
25702570
if bits.Len64(max) > significandBits {
25712571
// Round the max down to fit within the significand.
2572-
maxFloat = float64(max & ^uint64(0) << uint(bits.Len64(max)-significandBits))
2572+
maxFloat = float64(max & (^uint64(0) << uint(bits.Len64(max)-significandBits)))
25732573
}
25742574

25752575
// Check if the value is in-bounds (0 <= value <= max).
@@ -2598,7 +2598,7 @@ func (b *builder) createConvert(typeFrom, typeTo types.Type, value llvm.Value, p
25982598
maxFloat := float64(max)
25992599
if bits.Len64(max) > significandBits {
26002600
// Round the max down to fit within the significand.
2601-
maxFloat = float64(max & ^uint64(0) << uint(bits.Len64(max)-significandBits))
2601+
maxFloat = float64(max & (^uint64(0) << uint(bits.Len64(max)-significandBits)))
26022602
}
26032603

26042604
// Check if the value is in-bounds (min <= value <= max).
@@ -2609,10 +2609,17 @@ func (b *builder) createConvert(typeFrom, typeTo types.Type, value llvm.Value, p
26092609
// Assuming that the value is out-of-bounds, select a saturated value.
26102610
saturated := b.CreateSelect(aboveMin,
26112611
llvm.ConstInt(llvmTypeTo, max, false), // value > max
2612-
llvm.ConstInt(llvmTypeTo, min, false), // value < min (or NaN)
2612+
llvm.ConstInt(llvmTypeTo, min, false), // value < min
26132613
"saturated",
26142614
)
26152615

2616+
// Map NaN to 0.
2617+
saturated = b.CreateSelect(b.CreateFCmp(llvm.FloatUNO, value, value, "isnan"),
2618+
llvm.ConstNull(llvmTypeTo),
2619+
saturated,
2620+
"remapped",
2621+
)
2622+
26162623
// Do a normal conversion.
26172624
normal := b.CreateFPToSI(value, llvmTypeTo, "normal")
26182625

compiler/compiler_test.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ func TestCompiler(t *testing.T) {
3737
"basic.go",
3838
"pointer.go",
3939
"slice.go",
40+
"float.go",
4041
}
4142

4243
for _, testCase := range tests {

compiler/testdata/float.go

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
package main
2+
3+
// Test converting floats to ints.
4+
5+
func f32tou32(v float32) uint32 {
6+
return uint32(v)
7+
}
8+
9+
func maxu32f() float32 {
10+
return float32(^uint32(0))
11+
}
12+
13+
func maxu32tof32() uint32 {
14+
f := float32(^uint32(0))
15+
return uint32(f)
16+
}
17+
18+
func inftoi32() (uint32, uint32, int32, int32) {
19+
inf := 1.0
20+
inf /= 0.0
21+
22+
return uint32(inf), uint32(-inf), int32(inf), int32(-inf)
23+
}
24+
25+
func u32tof32tou32(v uint32) uint32 {
26+
return uint32(float32(v))
27+
}
28+
29+
func f32tou32tof32(v float32) float32 {
30+
return float32(uint32(v))
31+
}
32+
33+
func f32tou8(v float32) uint8 {
34+
return uint8(v)
35+
}
36+
37+
func f32toi8(v float32) int8 {
38+
return int8(v)
39+
}

compiler/testdata/float.ll

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
; ModuleID = 'float.go'
2+
source_filename = "float.go"
3+
target datalayout = "e-m:e-p:32:32-p270:32:32-p271:32:32-p272:64:64-f64:32:64-f80:32-n8:16:32-S128"
4+
target triple = "i686--linux"
5+
6+
define internal void @main.init(i8* %context, i8* %parentHandle) unnamed_addr {
7+
entry:
8+
ret void
9+
}
10+
11+
define internal i32 @main.f32tou32(float %v, i8* %context, i8* %parentHandle) unnamed_addr {
12+
entry:
13+
%positive = fcmp oge float %v, 0.000000e+00
14+
%withinmax = fcmp ole float %v, 0x41EFFFFFC0000000
15+
%inbounds = and i1 %positive, %withinmax
16+
%saturated = sext i1 %positive to i32
17+
%normal = fptoui float %v to i32
18+
%0 = select i1 %inbounds, i32 %normal, i32 %saturated
19+
ret i32 %0
20+
}
21+
22+
define internal float @main.maxu32f(i8* %context, i8* %parentHandle) unnamed_addr {
23+
entry:
24+
ret float 0x41F0000000000000
25+
}
26+
27+
define internal i32 @main.maxu32tof32(i8* %context, i8* %parentHandle) unnamed_addr {
28+
entry:
29+
ret i32 -1
30+
}
31+
32+
define internal { i32, i32, i32, i32 } @main.inftoi32(i8* %context, i8* %parentHandle) unnamed_addr {
33+
entry:
34+
ret { i32, i32, i32, i32 } { i32 -1, i32 0, i32 2147483647, i32 -2147483648 }
35+
}
36+
37+
define internal i32 @main.u32tof32tou32(i32 %v, i8* %context, i8* %parentHandle) unnamed_addr {
38+
entry:
39+
%0 = uitofp i32 %v to float
40+
%withinmax = fcmp ole float %0, 0x41EFFFFFC0000000
41+
%normal = fptoui float %0 to i32
42+
%1 = select i1 %withinmax, i32 %normal, i32 -1
43+
ret i32 %1
44+
}
45+
46+
define internal float @main.f32tou32tof32(float %v, i8* %context, i8* %parentHandle) unnamed_addr {
47+
entry:
48+
%positive = fcmp oge float %v, 0.000000e+00
49+
%withinmax = fcmp ole float %v, 0x41EFFFFFC0000000
50+
%inbounds = and i1 %positive, %withinmax
51+
%saturated = sext i1 %positive to i32
52+
%normal = fptoui float %v to i32
53+
%0 = select i1 %inbounds, i32 %normal, i32 %saturated
54+
%1 = uitofp i32 %0 to float
55+
ret float %1
56+
}
57+
58+
define internal i8 @main.f32tou8(float %v, i8* %context, i8* %parentHandle) unnamed_addr {
59+
entry:
60+
%positive = fcmp oge float %v, 0.000000e+00
61+
%withinmax = fcmp ole float %v, 2.550000e+02
62+
%inbounds = and i1 %positive, %withinmax
63+
%saturated = sext i1 %positive to i8
64+
%normal = fptoui float %v to i8
65+
%0 = select i1 %inbounds, i8 %normal, i8 %saturated
66+
ret i8 %0
67+
}
68+
69+
define internal i8 @main.f32toi8(float %v, i8* %context, i8* %parentHandle) unnamed_addr {
70+
entry:
71+
%abovemin = fcmp oge float %v, -1.280000e+02
72+
%belowmax = fcmp ole float %v, 1.270000e+02
73+
%inbounds = and i1 %abovemin, %belowmax
74+
%saturated = select i1 %abovemin, i8 127, i8 -128
75+
%isnan = fcmp uno float %v, 0.000000e+00
76+
%remapped = select i1 %isnan, i8 0, i8 %saturated
77+
%normal = fptosi float %v to i8
78+
%0 = select i1 %inbounds, i8 %normal, i8 %remapped
79+
ret i8 %0
80+
}

testdata/float.go

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -29,12 +29,21 @@ func main() {
2929
var f2 float32 = 5.7
3030
var f3 float32 = -2.3
3131
var f4 float32 = -11.8
32+
println(int32(f1), int32(f2), int32(f3), int32(f4))
33+
34+
// float -> int saturating behavior
3235
var f5 float32 = -1
3336
var f6 float32 = 256
3437
var f7 float32 = -129
35-
var f8 float32 = 0
36-
f8 /= 0
37-
println(int32(f1), int32(f2), int32(f3), int32(f4), uint8(f5), uint8(f6), int8(f7), int8(f6), uint8(f8), int8(f8))
38+
f8 := float32(^uint32(0))
39+
f9 := float32(int32(-2147483648))
40+
f10 := float32(int32(2147483647))
41+
var inf float32 = 1
42+
inf /= 0
43+
var nan float32 = 0
44+
nan /= 0
45+
println(uint8(f5), uint8(f6), int8(f7), int8(f6), uint32(f8), int32(f9), int32(f10),
46+
uint8(inf), uint8(-inf), int8(inf), int8(-inf), uint8(nan), int64(nan))
3847

3948
// int -> float
4049
var i1 int32 = 53

testdata/float.txt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,8 @@
1111
+3.333333e-001
1212
+6.666667e-001
1313
+6.666667e-001
14-
3 5 -2 -11 0 255 -128 127 0 -128
14+
3 5 -2 -11
15+
0 255 -128 127 4294967295 -2147483648 2147483647 255 0 127 -128 0 0
1516
+5.300000e+001 -8.000000e+000 +2.000000e+001
1617
(+6.666667e-001+1.200000e+000i)
1718
+6.666667e-001

0 commit comments

Comments
 (0)