Browse Source

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

pull/1585/head
Nia Weiss 4 years ago
committed by Ayke
parent
commit
a5cf704d83
  1. 13
      compiler/compiler.go
  2. 1
      compiler/compiler_test.go
  3. 39
      compiler/testdata/float.go
  4. 80
      compiler/testdata/float.ll
  5. 15
      testdata/float.go
  6. 3
      testdata/float.txt

13
compiler/compiler.go

@ -2569,7 +2569,7 @@ func (b *builder) createConvert(typeFrom, typeTo types.Type, value llvm.Value, p
maxFloat := float64(max) maxFloat := float64(max)
if bits.Len64(max) > significandBits { if bits.Len64(max) > significandBits {
// Round the max down to fit within the significand. // 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). // 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
maxFloat := float64(max) maxFloat := float64(max)
if bits.Len64(max) > significandBits { if bits.Len64(max) > significandBits {
// Round the max down to fit within the significand. // 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). // 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
// Assuming that the value is out-of-bounds, select a saturated value. // Assuming that the value is out-of-bounds, select a saturated value.
saturated := b.CreateSelect(aboveMin, saturated := b.CreateSelect(aboveMin,
llvm.ConstInt(llvmTypeTo, max, false), // value > max llvm.ConstInt(llvmTypeTo, max, false), // value > max
llvm.ConstInt(llvmTypeTo, min, false), // value < min (or NaN) llvm.ConstInt(llvmTypeTo, min, false), // value < min
"saturated", "saturated",
) )
// Map NaN to 0.
saturated = b.CreateSelect(b.CreateFCmp(llvm.FloatUNO, value, value, "isnan"),
llvm.ConstNull(llvmTypeTo),
saturated,
"remapped",
)
// Do a normal conversion. // Do a normal conversion.
normal := b.CreateFPToSI(value, llvmTypeTo, "normal") normal := b.CreateFPToSI(value, llvmTypeTo, "normal")

1
compiler/compiler_test.go

@ -37,6 +37,7 @@ func TestCompiler(t *testing.T) {
"basic.go", "basic.go",
"pointer.go", "pointer.go",
"slice.go", "slice.go",
"float.go",
} }
for _, testCase := range tests { for _, testCase := range tests {

39
compiler/testdata/float.go

@ -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
compiler/testdata/float.ll

@ -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
testdata/float.go

@ -29,12 +29,21 @@ func main() {
var f2 float32 = 5.7 var f2 float32 = 5.7
var f3 float32 = -2.3 var f3 float32 = -2.3
var f4 float32 = -11.8 var f4 float32 = -11.8
println(int32(f1), int32(f2), int32(f3), int32(f4))
// float -> int saturating behavior
var f5 float32 = -1 var f5 float32 = -1
var f6 float32 = 256 var f6 float32 = 256
var f7 float32 = -129 var f7 float32 = -129
var f8 float32 = 0 f8 := float32(^uint32(0))
f8 /= 0 f9 := float32(int32(-2147483648))
println(int32(f1), int32(f2), int32(f3), int32(f4), uint8(f5), uint8(f6), int8(f7), int8(f6), uint8(f8), int8(f8)) 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 // int -> float
var i1 int32 = 53 var i1 int32 = 53

3
testdata/float.txt

@ -11,7 +11,8 @@
+3.333333e-001 +3.333333e-001
+6.666667e-001 +6.666667e-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 +5.300000e+001 -8.000000e+000 +2.000000e+001
(+6.666667e-001+1.200000e+000i) (+6.666667e-001+1.200000e+000i)
+6.666667e-001 +6.666667e-001

Loading…
Cancel
Save