Skip to content
21 changes: 21 additions & 0 deletions _demo/go/issue1538-floatcvtuint-over/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package main

func main() {
cvt32Fto8U(-1, 255)
cvt32Fto32U(4294967295.1, 0)
cvt32Fto32U(5294967295.1, 1000000000)
cvt32Fto32U(-1294967295.1, 3000000000)
cvt32Fto32U(-1.1, 4294967295)
}

func cvt32Fto8U(a float32, b uint8) {
if uint8(a) != b {
panic("error")
}
}

func cvt32Fto32U(a float32, b uint32) {
if uint32(a) != b {
panic("error")
}
}
153 changes: 153 additions & 0 deletions _demo/go/issue1538/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,153 @@
package main

func main() {
cvt64to8(0, 0)
cvt64to8(127, 127)
cvt64to8(128, -128)
cvt64to8(-128, -128)
cvt64to8(-129, 127)
cvt64to8(256, 0)

cvt64to8U(0, 0)
cvt64to8U(255, 255)
cvt64to8U(256, 0)
cvt64to8U(257, 1)
cvt64to8U(-1, 255)

cvt32Fto8(0.1, 0)
cvt32Fto8(127.1, 127)
cvt32Fto8(128.1, -128)
cvt32Fto8(-128.1, -128)
cvt32Fto8(-129.1, 127)
cvt32Fto8(256.1, 0)

cvt32Fto8U(0, 0)
cvt32Fto8U(255, 255)
cvt32Fto8U(256, 0)
cvt32Fto8U(257, 1)
cvt32Fto8U(-1, 255)

// MaxInt32 = 1<<31 - 1 // 2147483647
// MinInt32 = -1 << 31 // -2147483648
cvt32Fto32(0, 0)
cvt32Fto32(1.5, 1)
cvt32Fto32(1147483647.1, 1147483648)
cvt32Fto32(-2147483648.1, -2147483648)

// MaxUint32 = 1<<32 - 1 // 4294967295
cvt32Fto32U(0, 0)
cvt32Fto32U(1.5, 1)
cvt32Fto32U(4294967295.1, 0)
cvt32Fto32U(5294967295.1, 1000000000)
cvt32Fto32U(-4294967295.1, 0)
cvt32Fto32U(-1294967295.1, 3000000000)
cvt32Fto32U(-1.1, 4294967295)

// MaxFloat32 = 0x1p127 * (1 + (1 - 0x1p-23))
// SmallestNonzeroFloat32 = 0x1p-126 * 0x1p-23
// MaxFloat64 = 0x1p1023 * (1 + (1 - 0x1p-52))
// SmallestNonzeroFloat64 = 0x1p-1022 * 0x1p-52

cvt32Fto64F(0, 0)
cvt32Fto64F(1.5, 1.5)
cvt32Fto64F(1e10, 1e10)
cvt32Fto64F(-1e10, -1e10)

cvt64Fto32F(0, 0)
cvt64Fto32F(1.5, 1.5)
cvt64Fto32F(1e10, 1e10)
cvt64Fto32F(-1e10, -1e10)

// MaxInt64 = 1<<63 - 1 // 9223372036854775807
// MinInt64 = -1 << 63 // -9223372036854775808
cvt64to64F(0, 0)
cvt64to64F(1e10, 1e10)
cvt64to64F(9223372036854775807, 9223372036854775807)
cvt64to64F(-9223372036854775807, -9223372036854775807)

// MaxUint64 = 1<<64 - 1 // 18446744073709551615
cvt64Uto64F(0, 0)
cvt64Uto64F(1e10, 1e10)
cvt64Uto64F(9223372036854775807, 9223372036854775807)
cvt64Uto64F(18446744073709551615, 18446744073709551615)

cvt32to64(0, 0)
cvt32to64(2147483647, 2147483647)

cvtUinptr(1024, 1024)
}

func cvtUinptr(a int32, b uintptr) {
if uintptr(a) != b {
panic("error")
}
if int32(b) != a {
panic("error")
}
}

func cvt32to64(a int32, b int64) {
if int64(a) != b {
panic("error")
}
}

func cvt64to64F(a int64, b float64) {
if float64(a) != b {
panic("error")
}
}

func cvt64Uto64F(a uint64, b float64) {
if float64(a) != b {
panic("error")
}
}

func cvt64Fto32F(a float64, b float32) {
if float32(a) != b {
panic("error")
}
}

func cvt32Fto64F(a float32, b float64) {
if float64(a) != b {
panic("error")
}
}

func cvt32Fto32(a float32, b int32) {
if int32(a) != b {
panic("error")
}
}

func cvt32Fto32U(a float32, b uint32) {
if uint32(a) != b {
panic("error")
}
}

func cvt32Fto8(a float32, b int8) {
if int8(a) != b {
panic("error")
}
}

func cvt32Fto8U(a float32, b uint8) {
if uint8(a) != b {
panic("error")
}
}

func cvt64to8(a int64, b int8) {
if int8(a) != b {
panic("error")
}
}

func cvt64to8U(a int, b uint8) {
if uint8(a) != b {
panic("error")
}
}
66 changes: 38 additions & 28 deletions cl/_testrt/cast/out.ll
Original file line number Diff line number Diff line change
Expand Up @@ -14,15 +14,16 @@ source_filename = "github.com/goplus/llgo/cl/_testrt/cast"

define void @"github.com/goplus/llgo/cl/_testrt/cast.cvt32Fto32"(float %0, i32 %1) {
_llgo_0:
%2 = fptosi float %0 to i32
%3 = icmp ne i32 %2, %1
br i1 %3, label %_llgo_1, label %_llgo_2
%2 = fptosi float %0 to i64
%3 = trunc i64 %2 to i32
%4 = icmp ne i32 %3, %1
br i1 %4, label %_llgo_1, label %_llgo_2

_llgo_1: ; preds = %_llgo_0
%4 = call ptr @"github.com/goplus/llgo/runtime/internal/runtime.AllocU"(i64 16)
store %"github.com/goplus/llgo/runtime/internal/runtime.String" { ptr @0, i64 5 }, ptr %4, align 8
%5 = insertvalue %"github.com/goplus/llgo/runtime/internal/runtime.eface" { ptr @_llgo_string, ptr undef }, ptr %4, 1
call void @"github.com/goplus/llgo/runtime/internal/runtime.Panic"(%"github.com/goplus/llgo/runtime/internal/runtime.eface" %5)
%5 = call ptr @"github.com/goplus/llgo/runtime/internal/runtime.AllocU"(i64 16)
store %"github.com/goplus/llgo/runtime/internal/runtime.String" { ptr @0, i64 5 }, ptr %5, align 8
%6 = insertvalue %"github.com/goplus/llgo/runtime/internal/runtime.eface" { ptr @_llgo_string, ptr undef }, ptr %5, 1
call void @"github.com/goplus/llgo/runtime/internal/runtime.Panic"(%"github.com/goplus/llgo/runtime/internal/runtime.eface" %6)
unreachable

_llgo_2: ; preds = %_llgo_0
Expand All @@ -31,15 +32,19 @@ _llgo_2: ; preds = %_llgo_0

define void @"github.com/goplus/llgo/cl/_testrt/cast.cvt32Fto32U"(float %0, i32 %1) {
_llgo_0:
%2 = fptoui float %0 to i32
%3 = icmp ne i32 %2, %1
br i1 %3, label %_llgo_1, label %_llgo_2
%2 = fcmp olt float %0, 0.000000e+00
%3 = fptosi float %0 to i64
%4 = fptoui float %0 to i64
%5 = select i1 %2, i64 %3, i64 %4
%6 = trunc i64 %5 to i32
%7 = icmp ne i32 %6, %1
br i1 %7, label %_llgo_1, label %_llgo_2

_llgo_1: ; preds = %_llgo_0
%4 = call ptr @"github.com/goplus/llgo/runtime/internal/runtime.AllocU"(i64 16)
store %"github.com/goplus/llgo/runtime/internal/runtime.String" { ptr @0, i64 5 }, ptr %4, align 8
%5 = insertvalue %"github.com/goplus/llgo/runtime/internal/runtime.eface" { ptr @_llgo_string, ptr undef }, ptr %4, 1
call void @"github.com/goplus/llgo/runtime/internal/runtime.Panic"(%"github.com/goplus/llgo/runtime/internal/runtime.eface" %5)
%8 = call ptr @"github.com/goplus/llgo/runtime/internal/runtime.AllocU"(i64 16)
store %"github.com/goplus/llgo/runtime/internal/runtime.String" { ptr @0, i64 5 }, ptr %8, align 8
%9 = insertvalue %"github.com/goplus/llgo/runtime/internal/runtime.eface" { ptr @_llgo_string, ptr undef }, ptr %8, 1
call void @"github.com/goplus/llgo/runtime/internal/runtime.Panic"(%"github.com/goplus/llgo/runtime/internal/runtime.eface" %9)
unreachable

_llgo_2: ; preds = %_llgo_0
Expand All @@ -65,15 +70,16 @@ _llgo_2: ; preds = %_llgo_0

define void @"github.com/goplus/llgo/cl/_testrt/cast.cvt32Fto8"(float %0, i8 %1) {
_llgo_0:
%2 = fptosi float %0 to i8
%3 = icmp ne i8 %2, %1
br i1 %3, label %_llgo_1, label %_llgo_2
%2 = fptosi float %0 to i64
%3 = trunc i64 %2 to i8
%4 = icmp ne i8 %3, %1
br i1 %4, label %_llgo_1, label %_llgo_2

_llgo_1: ; preds = %_llgo_0
%4 = call ptr @"github.com/goplus/llgo/runtime/internal/runtime.AllocU"(i64 16)
store %"github.com/goplus/llgo/runtime/internal/runtime.String" { ptr @0, i64 5 }, ptr %4, align 8
%5 = insertvalue %"github.com/goplus/llgo/runtime/internal/runtime.eface" { ptr @_llgo_string, ptr undef }, ptr %4, 1
call void @"github.com/goplus/llgo/runtime/internal/runtime.Panic"(%"github.com/goplus/llgo/runtime/internal/runtime.eface" %5)
%5 = call ptr @"github.com/goplus/llgo/runtime/internal/runtime.AllocU"(i64 16)
store %"github.com/goplus/llgo/runtime/internal/runtime.String" { ptr @0, i64 5 }, ptr %5, align 8
%6 = insertvalue %"github.com/goplus/llgo/runtime/internal/runtime.eface" { ptr @_llgo_string, ptr undef }, ptr %5, 1
call void @"github.com/goplus/llgo/runtime/internal/runtime.Panic"(%"github.com/goplus/llgo/runtime/internal/runtime.eface" %6)
unreachable

_llgo_2: ; preds = %_llgo_0
Expand All @@ -82,15 +88,19 @@ _llgo_2: ; preds = %_llgo_0

define void @"github.com/goplus/llgo/cl/_testrt/cast.cvt32Fto8U"(float %0, i8 %1) {
_llgo_0:
%2 = fptoui float %0 to i8
%3 = icmp ne i8 %2, %1
br i1 %3, label %_llgo_1, label %_llgo_2
%2 = fcmp olt float %0, 0.000000e+00
%3 = fptosi float %0 to i64
%4 = fptoui float %0 to i64
%5 = select i1 %2, i64 %3, i64 %4
%6 = trunc i64 %5 to i8
%7 = icmp ne i8 %6, %1
br i1 %7, label %_llgo_1, label %_llgo_2

_llgo_1: ; preds = %_llgo_0
%4 = call ptr @"github.com/goplus/llgo/runtime/internal/runtime.AllocU"(i64 16)
store %"github.com/goplus/llgo/runtime/internal/runtime.String" { ptr @0, i64 5 }, ptr %4, align 8
%5 = insertvalue %"github.com/goplus/llgo/runtime/internal/runtime.eface" { ptr @_llgo_string, ptr undef }, ptr %4, 1
call void @"github.com/goplus/llgo/runtime/internal/runtime.Panic"(%"github.com/goplus/llgo/runtime/internal/runtime.eface" %5)
%8 = call ptr @"github.com/goplus/llgo/runtime/internal/runtime.AllocU"(i64 16)
store %"github.com/goplus/llgo/runtime/internal/runtime.String" { ptr @0, i64 5 }, ptr %8, align 8
%9 = insertvalue %"github.com/goplus/llgo/runtime/internal/runtime.eface" { ptr @_llgo_string, ptr undef }, ptr %8, 1
call void @"github.com/goplus/llgo/runtime/internal/runtime.Panic"(%"github.com/goplus/llgo/runtime/internal/runtime.eface" %9)
unreachable

_llgo_2: ; preds = %_llgo_0
Expand Down
34 changes: 29 additions & 5 deletions ssa/expr.go
Original file line number Diff line number Diff line change
Expand Up @@ -862,11 +862,7 @@ func (b Builder) Convert(t Type, x Expr) (ret Expr) {
ret.impl = castInt(b, x.impl, x.Type, t)
return
} else if xtyp.Info()&types.IsFloat != 0 {
if typ.Info()&types.IsUnsigned != 0 {
ret.impl = llvm.CreateFPToUI(b.impl, x.impl, t.ll)
} else {
ret.impl = llvm.CreateFPToSI(b.impl, x.impl, t.ll)
}
ret.impl = castFloatToInt(b, x.impl, t)
return
}
} else if typ.Info()&types.IsFloat != 0 {
Expand Down Expand Up @@ -935,6 +931,34 @@ func castInt(b Builder, x llvm.Value, xtyp Type, typ Type) llvm.Value {
}
}

func castFloatToInt(b Builder, x llvm.Value, typ Type) llvm.Value {
dstSize := b.Prog.td.TypeAllocSize(typ.ll)
if dstSize < 8 {
i64 := b.Prog.Int64()
if typ.kind == vkUnsigned {
// note(zzy): for unsigned targets, split negative vs non-negative.
// Negative values need signed expansion (FPToSI) before truncation;
// non-negative values can use unsigned expansion (FPToUI). This avoids
// direct float->narrow-unsigned conversions and preserves wrap/trunc behavior.
zero := llvm.ConstNull(x.Type())
isNeg := b.impl.CreateFCmp(llvm.FloatOLT, x, zero, "")
neg := llvm.CreateFPToSI(b.impl, x, i64.ll)
pos := llvm.CreateFPToUI(b.impl, x, i64.ll)
tmp := b.impl.CreateSelect(isNeg, neg, pos, "")
return llvm.CreateTrunc(b.impl, tmp, typ.ll)
}
tmp := llvm.CreateFPToSI(b.impl, x, i64.ll)
return llvm.CreateTrunc(b.impl, tmp, typ.ll)
}
// note(zzy): dst is already 64-bit wide, so no extra widen+trunc roundtrip is needed here;
// see LLVM fptoui/fptosi semantics: https://llvm.org/docs/LangRef.html#fptoui-to-instruction
// and https://llvm.org/docs/LangRef.html#fptosi-to-instruction
if typ.kind == vkUnsigned {
return llvm.CreateFPToUI(b.impl, x, typ.ll)
}
return llvm.CreateFPToSI(b.impl, x, typ.ll)
}

func castFloat(b Builder, x llvm.Value, typ Type) llvm.Value {
xsize := b.Prog.td.TypeAllocSize(x.Type())
size := b.Prog.td.TypeAllocSize(typ.ll)
Expand Down
Loading