Skip to content

compiler: test float to int conversions and fix upper-bound calculation #1582

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Jan 19, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 10 additions & 3 deletions compiler/compiler.go
Original file line number Diff line number Diff line change
Expand Up @@ -2569,7 +2569,7 @@ func (b *builder) createConvert(typeFrom, typeTo types.Type, value llvm.Value, p
maxFloat := float64(max)
if bits.Len64(max) > significandBits {
// Round the max down to fit within the significand.
maxFloat = float64(max & ^uint64(0) << uint(bits.Len64(max)-significandBits))
maxFloat = float64(max & (^uint64(0) << uint(bits.Len64(max)-significandBits)))
}

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

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

// Map NaN to 0.
saturated = b.CreateSelect(b.CreateFCmp(llvm.FloatUNO, value, value, "isnan"),
llvm.ConstNull(llvmTypeTo),
saturated,
"remapped",
)

// Do a normal conversion.
normal := b.CreateFPToSI(value, llvmTypeTo, "normal")

Expand Down
1 change: 1 addition & 0 deletions compiler/compiler_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ func TestCompiler(t *testing.T) {
"basic.go",
"pointer.go",
"slice.go",
"float.go",
}

for _, testCase := range tests {
Expand Down
39 changes: 39 additions & 0 deletions compiler/testdata/float.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
package main

// Test converting floats to ints.

func f32tou32(v float32) uint32 {
return uint32(v)
}

func maxu32f() float32 {
return float32(^uint32(0))
}

func maxu32tof32() uint32 {
f := float32(^uint32(0))
return uint32(f)
}

func inftoi32() (uint32, uint32, int32, int32) {
inf := 1.0
inf /= 0.0

return uint32(inf), uint32(-inf), int32(inf), int32(-inf)
}

func u32tof32tou32(v uint32) uint32 {
return uint32(float32(v))
}

func f32tou32tof32(v float32) float32 {
return float32(uint32(v))
}

func f32tou8(v float32) uint8 {
return uint8(v)
}

func f32toi8(v float32) int8 {
return int8(v)
}
80 changes: 80 additions & 0 deletions compiler/testdata/float.ll
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
; ModuleID = 'float.go'
source_filename = "float.go"
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"
target triple = "i686--linux"

define internal void @main.init(i8* %context, i8* %parentHandle) unnamed_addr {
entry:
ret void
}

define internal i32 @main.f32tou32(float %v, i8* %context, i8* %parentHandle) unnamed_addr {
entry:
%positive = fcmp oge float %v, 0.000000e+00
%withinmax = fcmp ole float %v, 0x41EFFFFFC0000000
%inbounds = and i1 %positive, %withinmax
%saturated = sext i1 %positive to i32
%normal = fptoui float %v to i32
%0 = select i1 %inbounds, i32 %normal, i32 %saturated
ret i32 %0
}

define internal float @main.maxu32f(i8* %context, i8* %parentHandle) unnamed_addr {
entry:
ret float 0x41F0000000000000
}

define internal i32 @main.maxu32tof32(i8* %context, i8* %parentHandle) unnamed_addr {
entry:
ret i32 -1
}

define internal { i32, i32, i32, i32 } @main.inftoi32(i8* %context, i8* %parentHandle) unnamed_addr {
entry:
ret { i32, i32, i32, i32 } { i32 -1, i32 0, i32 2147483647, i32 -2147483648 }
}

define internal i32 @main.u32tof32tou32(i32 %v, i8* %context, i8* %parentHandle) unnamed_addr {
entry:
%0 = uitofp i32 %v to float
%withinmax = fcmp ole float %0, 0x41EFFFFFC0000000
%normal = fptoui float %0 to i32
%1 = select i1 %withinmax, i32 %normal, i32 -1
ret i32 %1
}

define internal float @main.f32tou32tof32(float %v, i8* %context, i8* %parentHandle) unnamed_addr {
entry:
%positive = fcmp oge float %v, 0.000000e+00
%withinmax = fcmp ole float %v, 0x41EFFFFFC0000000
%inbounds = and i1 %positive, %withinmax
%saturated = sext i1 %positive to i32
%normal = fptoui float %v to i32
%0 = select i1 %inbounds, i32 %normal, i32 %saturated
%1 = uitofp i32 %0 to float
ret float %1
}

define internal i8 @main.f32tou8(float %v, i8* %context, i8* %parentHandle) unnamed_addr {
entry:
%positive = fcmp oge float %v, 0.000000e+00
%withinmax = fcmp ole float %v, 2.550000e+02
%inbounds = and i1 %positive, %withinmax
%saturated = sext i1 %positive to i8
%normal = fptoui float %v to i8
%0 = select i1 %inbounds, i8 %normal, i8 %saturated
ret i8 %0
}

define internal i8 @main.f32toi8(float %v, i8* %context, i8* %parentHandle) unnamed_addr {
entry:
%abovemin = fcmp oge float %v, -1.280000e+02
%belowmax = fcmp ole float %v, 1.270000e+02
%inbounds = and i1 %abovemin, %belowmax
%saturated = select i1 %abovemin, i8 127, i8 -128
%isnan = fcmp uno float %v, 0.000000e+00
%remapped = select i1 %isnan, i8 0, i8 %saturated
%normal = fptosi float %v to i8
%0 = select i1 %inbounds, i8 %normal, i8 %remapped
ret i8 %0
}
15 changes: 12 additions & 3 deletions testdata/float.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,12 +29,21 @@ func main() {
var f2 float32 = 5.7
var f3 float32 = -2.3
var f4 float32 = -11.8
println(int32(f1), int32(f2), int32(f3), int32(f4))

// float -> int saturating behavior
var f5 float32 = -1
var f6 float32 = 256
var f7 float32 = -129
var f8 float32 = 0
f8 /= 0
println(int32(f1), int32(f2), int32(f3), int32(f4), uint8(f5), uint8(f6), int8(f7), int8(f6), uint8(f8), int8(f8))
f8 := float32(^uint32(0))
f9 := float32(int32(-2147483648))
f10 := float32(int32(2147483647))
var inf float32 = 1
inf /= 0
var nan float32 = 0
nan /= 0
println(uint8(f5), uint8(f6), int8(f7), int8(f6), uint32(f8), int32(f9), int32(f10),
uint8(inf), uint8(-inf), int8(inf), int8(-inf), uint8(nan), int64(nan))

// int -> float
var i1 int32 = 53
Expand Down
3 changes: 2 additions & 1 deletion testdata/float.txt
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,8 @@
+3.333333e-001
+6.666667e-001
+6.666667e-001
3 5 -2 -11 0 255 -128 127 0 -128
3 5 -2 -11
0 255 -128 127 4294967295 -2147483648 2147483647 255 0 127 -128 0 0
+5.300000e+001 -8.000000e+000 +2.000000e+001
(+6.666667e-001+1.200000e+000i)
+6.666667e-001
Expand Down