diff --git a/cl/_testdata/print/in.go b/cl/_testdata/print/in.go index aa623c27..7b44b61b 100644 --- a/cl/_testdata/print/in.go +++ b/cl/_testdata/print/in.go @@ -177,6 +177,41 @@ func main() { printnl() prinfsub(100.1) printnl() + printnum(float32(1e9)) + printnl() + printnum(float64(2e9)) + printnl() +} + +func printnum(v any) { + switch v := v.(type) { + case int: + printint(int64(v)) + case int8: + printint(int64(v)) + case int16: + printint(int64(v)) + case int32: + printint(int64(v)) + case int64: + printint(int64(v)) + case uint: + printuint(uint64(v)) + case uint8: + printuint(uint64(v)) + case uint16: + printuint(uint64(v)) + case uint32: + printuint(uint64(v)) + case uint64: + printuint(uint64(v)) + case uintptr: + printuint(uint64(v)) + case float32: + printfloat(float64(v)) + case float64: + printfloat(float64(v)) + } } func prinxor(n int64) { diff --git a/cl/_testdata/print/out.ll b/cl/_testdata/print/out.ll index d47b639f..73ea91b5 100644 --- a/cl/_testdata/print/out.ll +++ b/cl/_testdata/print/out.ll @@ -5,6 +5,7 @@ source_filename = "main" %"github.com/goplus/llgo/internal/runtime.String" = type { ptr, i64 } %main.stringStruct = type { ptr, i64 } %main.slice = type { ptr, i64, i64 } +%"github.com/goplus/llgo/internal/runtime.iface" = type { ptr, ptr } @"main.init$guard" = global ptr null @main.minhexdigits = global ptr null @@ -91,6 +92,14 @@ _llgo_0: call void @main.printnl() call void @main.prinfsub(double 1.001000e+02) call void @main.printnl() + %3 = call ptr @"github.com/goplus/llgo/internal/runtime.Basic"(i64 13) + %4 = call %"github.com/goplus/llgo/internal/runtime.iface" @"github.com/goplus/llgo/internal/runtime.MakeAnyInt"(ptr %3, i64 1315859240) + call void @main.printnum(%"github.com/goplus/llgo/internal/runtime.iface" %4) + call void @main.printnl() + %5 = call ptr @"github.com/goplus/llgo/internal/runtime.Basic"(i64 14) + %6 = call %"github.com/goplus/llgo/internal/runtime.iface" @"github.com/goplus/llgo/internal/runtime.MakeAnyInt"(ptr %5, i64 4746175415993761792) + call void @main.printnum(%"github.com/goplus/llgo/internal/runtime.iface" %6) + call void @main.printnl() ret void } @@ -363,6 +372,155 @@ _llgo_0: ret void } +define void @main.printnum(%"github.com/goplus/llgo/internal/runtime.iface" %0) { +_llgo_0: + %1 = call ptr @"github.com/goplus/llgo/internal/runtime.Basic"(i64 2) + %2 = call { i64, i1 } @"github.com/goplus/llgo/internal/runtime.CheckI2Int"(%"github.com/goplus/llgo/internal/runtime.iface" %0, ptr %1) + %3 = extractvalue { i64, i1 } %2, 0 + %4 = extractvalue { i64, i1 } %2, 1 + br i1 %4, label %_llgo_2, label %_llgo_3 + +_llgo_1: ; preds = %_llgo_26, %_llgo_25, %_llgo_24, %_llgo_22, %_llgo_20, %_llgo_18, %_llgo_16, %_llgo_14, %_llgo_12, %_llgo_10, %_llgo_8, %_llgo_6, %_llgo_4, %_llgo_2 + ret void + +_llgo_2: ; preds = %_llgo_0 + call void @main.printint(i64 %3) + br label %_llgo_1 + +_llgo_3: ; preds = %_llgo_0 + %5 = call ptr @"github.com/goplus/llgo/internal/runtime.Basic"(i64 3) + %6 = call { i64, i1 } @"github.com/goplus/llgo/internal/runtime.CheckI2Int"(%"github.com/goplus/llgo/internal/runtime.iface" %0, ptr %5) + %7 = extractvalue { i64, i1 } %6, 0 + %8 = extractvalue { i64, i1 } %6, 1 + br i1 %8, label %_llgo_4, label %_llgo_5 + +_llgo_4: ; preds = %_llgo_3 + call void @main.printint(i64 %7) + br label %_llgo_1 + +_llgo_5: ; preds = %_llgo_3 + %9 = call ptr @"github.com/goplus/llgo/internal/runtime.Basic"(i64 4) + %10 = call { i64, i1 } @"github.com/goplus/llgo/internal/runtime.CheckI2Int"(%"github.com/goplus/llgo/internal/runtime.iface" %0, ptr %9) + %11 = extractvalue { i64, i1 } %10, 0 + %12 = extractvalue { i64, i1 } %10, 1 + br i1 %12, label %_llgo_6, label %_llgo_7 + +_llgo_6: ; preds = %_llgo_5 + call void @main.printint(i64 %11) + br label %_llgo_1 + +_llgo_7: ; preds = %_llgo_5 + %13 = call ptr @"github.com/goplus/llgo/internal/runtime.Basic"(i64 5) + %14 = call { i64, i1 } @"github.com/goplus/llgo/internal/runtime.CheckI2Int"(%"github.com/goplus/llgo/internal/runtime.iface" %0, ptr %13) + %15 = extractvalue { i64, i1 } %14, 0 + %16 = extractvalue { i64, i1 } %14, 1 + br i1 %16, label %_llgo_8, label %_llgo_9 + +_llgo_8: ; preds = %_llgo_7 + call void @main.printint(i64 %15) + br label %_llgo_1 + +_llgo_9: ; preds = %_llgo_7 + %17 = call ptr @"github.com/goplus/llgo/internal/runtime.Basic"(i64 6) + %18 = call { i64, i1 } @"github.com/goplus/llgo/internal/runtime.CheckI2Int"(%"github.com/goplus/llgo/internal/runtime.iface" %0, ptr %17) + %19 = extractvalue { i64, i1 } %18, 0 + %20 = extractvalue { i64, i1 } %18, 1 + br i1 %20, label %_llgo_10, label %_llgo_11 + +_llgo_10: ; preds = %_llgo_9 + call void @main.printint(i64 %19) + br label %_llgo_1 + +_llgo_11: ; preds = %_llgo_9 + %21 = call ptr @"github.com/goplus/llgo/internal/runtime.Basic"(i64 7) + %22 = call { i64, i1 } @"github.com/goplus/llgo/internal/runtime.CheckI2Int"(%"github.com/goplus/llgo/internal/runtime.iface" %0, ptr %21) + %23 = extractvalue { i64, i1 } %22, 0 + %24 = extractvalue { i64, i1 } %22, 1 + br i1 %24, label %_llgo_12, label %_llgo_13 + +_llgo_12: ; preds = %_llgo_11 + call void @main.printuint(i64 %23) + br label %_llgo_1 + +_llgo_13: ; preds = %_llgo_11 + %25 = call ptr @"github.com/goplus/llgo/internal/runtime.Basic"(i64 8) + %26 = call { i64, i1 } @"github.com/goplus/llgo/internal/runtime.CheckI2Int"(%"github.com/goplus/llgo/internal/runtime.iface" %0, ptr %25) + %27 = extractvalue { i64, i1 } %26, 0 + %28 = extractvalue { i64, i1 } %26, 1 + br i1 %28, label %_llgo_14, label %_llgo_15 + +_llgo_14: ; preds = %_llgo_13 + call void @main.printuint(i64 %27) + br label %_llgo_1 + +_llgo_15: ; preds = %_llgo_13 + %29 = call ptr @"github.com/goplus/llgo/internal/runtime.Basic"(i64 9) + %30 = call { i64, i1 } @"github.com/goplus/llgo/internal/runtime.CheckI2Int"(%"github.com/goplus/llgo/internal/runtime.iface" %0, ptr %29) + %31 = extractvalue { i64, i1 } %30, 0 + %32 = extractvalue { i64, i1 } %30, 1 + br i1 %32, label %_llgo_16, label %_llgo_17 + +_llgo_16: ; preds = %_llgo_15 + call void @main.printuint(i64 %31) + br label %_llgo_1 + +_llgo_17: ; preds = %_llgo_15 + %33 = call ptr @"github.com/goplus/llgo/internal/runtime.Basic"(i64 10) + %34 = call { i64, i1 } @"github.com/goplus/llgo/internal/runtime.CheckI2Int"(%"github.com/goplus/llgo/internal/runtime.iface" %0, ptr %33) + %35 = extractvalue { i64, i1 } %34, 0 + %36 = extractvalue { i64, i1 } %34, 1 + br i1 %36, label %_llgo_18, label %_llgo_19 + +_llgo_18: ; preds = %_llgo_17 + call void @main.printuint(i64 %35) + br label %_llgo_1 + +_llgo_19: ; preds = %_llgo_17 + %37 = call ptr @"github.com/goplus/llgo/internal/runtime.Basic"(i64 11) + %38 = call { i64, i1 } @"github.com/goplus/llgo/internal/runtime.CheckI2Int"(%"github.com/goplus/llgo/internal/runtime.iface" %0, ptr %37) + %39 = extractvalue { i64, i1 } %38, 0 + %40 = extractvalue { i64, i1 } %38, 1 + br i1 %40, label %_llgo_20, label %_llgo_21 + +_llgo_20: ; preds = %_llgo_19 + call void @main.printuint(i64 %39) + br label %_llgo_1 + +_llgo_21: ; preds = %_llgo_19 + %41 = call ptr @"github.com/goplus/llgo/internal/runtime.Basic"(i64 12) + %42 = call { i64, i1 } @"github.com/goplus/llgo/internal/runtime.CheckI2Int"(%"github.com/goplus/llgo/internal/runtime.iface" %0, ptr %41) + %43 = extractvalue { i64, i1 } %42, 0 + %44 = extractvalue { i64, i1 } %42, 1 + br i1 %44, label %_llgo_22, label %_llgo_23 + +_llgo_22: ; preds = %_llgo_21 + call void @main.printuint(i64 %43) + br label %_llgo_1 + +_llgo_23: ; preds = %_llgo_21 + %45 = call ptr @"github.com/goplus/llgo/internal/runtime.Basic"(i64 13) + %46 = call { float, i1 } @"github.com/goplus/llgo/internal/runtime.CheckI2Float32"(%"github.com/goplus/llgo/internal/runtime.iface" %0, ptr %45) + %47 = extractvalue { float, i1 } %46, 0 + %48 = extractvalue { float, i1 } %46, 1 + br i1 %48, label %_llgo_24, label %_llgo_25 + +_llgo_24: ; preds = %_llgo_23 + %49 = fpext float %47 to double + call void @main.printfloat(double %49) + br label %_llgo_1 + +_llgo_25: ; preds = %_llgo_23 + %50 = call ptr @"github.com/goplus/llgo/internal/runtime.Basic"(i64 14) + %51 = call { double, i1 } @"github.com/goplus/llgo/internal/runtime.CheckI2Float64"(%"github.com/goplus/llgo/internal/runtime.iface" %0, ptr %50) + %52 = extractvalue { double, i1 } %51, 0 + %53 = extractvalue { double, i1 } %51, 1 + br i1 %53, label %_llgo_26, label %_llgo_1 + +_llgo_26: ; preds = %_llgo_25 + call void @main.printfloat(double %52) + br label %_llgo_1 +} + define void @main.printsp() { _llgo_0: %0 = call %"github.com/goplus/llgo/internal/runtime.String" @"github.com/goplus/llgo/internal/runtime.NewString"(ptr @8, i64 1) @@ -437,6 +595,16 @@ declare void @"github.com/goplus/llgo/internal/runtime.init"() declare %"github.com/goplus/llgo/internal/runtime.String" @"github.com/goplus/llgo/internal/runtime.NewString"(ptr, i64) +declare ptr @"github.com/goplus/llgo/internal/runtime.Basic"(i64) + +declare %"github.com/goplus/llgo/internal/runtime.iface" @"github.com/goplus/llgo/internal/runtime.MakeAnyInt"(ptr, i64) + declare %"github.com/goplus/llgo/internal/runtime.Slice" @"github.com/goplus/llgo/internal/runtime.NewSlice3"(ptr, i64, i64, i64, i64, i64) declare ptr @"github.com/goplus/llgo/internal/runtime.StringData"(%"github.com/goplus/llgo/internal/runtime.String") + +declare { i64, i1 } @"github.com/goplus/llgo/internal/runtime.CheckI2Int"(%"github.com/goplus/llgo/internal/runtime.iface", ptr) + +declare { float, i1 } @"github.com/goplus/llgo/internal/runtime.CheckI2Float32"(%"github.com/goplus/llgo/internal/runtime.iface", ptr) + +declare { double, i1 } @"github.com/goplus/llgo/internal/runtime.CheckI2Float64"(%"github.com/goplus/llgo/internal/runtime.iface", ptr) diff --git a/cl/compile.go b/cl/compile.go index 62b4fc0c..aedc0b01 100644 --- a/cl/compile.go +++ b/cl/compile.go @@ -290,6 +290,10 @@ func (p *context) funcOf(fn *ssa.Function) (ret llssa.Function, ftype int) { ftype = llgoAllocaCStr case "unreachable": ftype = llgoUnreachable + case "bitCastTo64F": + ftype = llgoBitCastTo64F + case "bitCastTo32F": + ftype = llgoBitCastTo32F default: panic("unknown llgo instruction: " + name) } @@ -523,6 +527,10 @@ func (p *context) compileInstrOrValue(b llssa.Builder, iv instrOrValue, asValue ret = p.allocaCStr(b, args) case llgoUnreachable: // func unreachable() b.Unreachable() + case llgoBitCastTo32F: + ret = b.BitCast(p.compileValue(b, args[0]), b.Prog.Type(types.Typ[types.Float32], llssa.InGo)) + case llgoBitCastTo64F: + ret = b.BitCast(p.compileValue(b, args[0]), b.Prog.Float64()) default: panic("todo") } diff --git a/cl/import.go b/cl/import.go index 3f3e08ae..5e2b23e7 100644 --- a/cl/import.go +++ b/cl/import.go @@ -305,13 +305,15 @@ const ( cFunc = int(llssa.InC) llgoInstr = -1 - llgoInstrBase = 0x80 - llgoUnreachable = llgoInstrBase + 0 - llgoCstr = llgoInstrBase + 1 - llgoAlloca = llgoInstrBase + 2 - llgoAllocaCStr = llgoInstrBase + 3 - llgoAdvance = llgoInstrBase + 4 - llgoIndex = llgoInstrBase + 5 + llgoInstrBase = 0x80 + llgoUnreachable = llgoInstrBase + 0 + llgoCstr = llgoInstrBase + 1 + llgoAlloca = llgoInstrBase + 2 + llgoAllocaCStr = llgoInstrBase + 3 + llgoAdvance = llgoInstrBase + 4 + llgoIndex = llgoInstrBase + 5 + llgoBitCastTo32F = llgoInstrBase + 6 + llgoBitCastTo64F = llgoInstrBase + 7 ) func (p *context) funcName(fn *ssa.Function, ignore bool) (*types.Package, string, int) { diff --git a/internal/runtime/llgo_autogen.lla b/internal/runtime/llgo_autogen.lla index 88a6bf69..1bb3e9d8 100644 Binary files a/internal/runtime/llgo_autogen.lla and b/internal/runtime/llgo_autogen.lla differ diff --git a/internal/runtime/z_iface.go b/internal/runtime/z_iface.go index 9c8f4f6f..2c4a1e8d 100644 --- a/internal/runtime/z_iface.go +++ b/internal/runtime/z_iface.go @@ -77,4 +77,38 @@ func CheckI2Int(v Interface, t *Type) (uintptr, bool) { return 0, false } +func I2Float64(v Interface, t *Type) float64 { + if v.tab._type == t { + return bitCastTo64F(uint64(uintptr(v.data))) + } + panic("I2Float64: type mismatch") +} + +func CheckI2Float64(v Interface, t *Type) (float64, bool) { + if v.tab._type == t { + return bitCastTo64F(uint64(uintptr(v.data))), true + } + return 0, false +} + +func I2Float32(v Interface, t *Type) float32 { + if v.tab._type == t { + return bitCastTo32F(uint32(uintptr(v.data))) + } + panic("I2Float32: type mismatch") +} + +func CheckI2Float32(v Interface, t *Type) (float32, bool) { + if v.tab._type == t { + return bitCastTo32F(uint32(uintptr(v.data))), true + } + return 0, false +} + +//go:linkname bitCastTo64F llgo.bitCastTo64F +func bitCastTo64F(uint64) float64 + +//go:linkname bitCastTo32F llgo.bitCastTo32F +func bitCastTo32F(uint32) float32 + // ----------------------------------------------------------------------------- diff --git a/ssa/expr.go b/ssa/expr.go index 8b254a75..7d2715d6 100644 --- a/ssa/expr.go +++ b/ssa/expr.go @@ -1056,6 +1056,17 @@ func (b Builder) MakeInterface(tinter Type, x Expr) (ret Expr) { tptr := prog.Uintptr() vptr := Expr{llvm.CreateIntCast(b.impl, x.impl, tptr.ll), tptr} return Expr{b.InlineCall(pkg.rtFunc("MakeAnyInt"), t, vptr).impl, tinter} + case kind == types.Float32: + t := b.InlineCall(pkg.rtFunc("Basic"), prog.Val(int(kind))) + tptr := prog.Uintptr() + i32 := b.impl.CreateBitCast(x.impl, prog.tyInt32(), "") + vptr := Expr{llvm.CreateIntCast(b.impl, i32, tptr.ll), tptr} + return Expr{b.InlineCall(pkg.rtFunc("MakeAnyInt"), t, vptr).impl, tinter} + case kind == types.Float64: + t := b.InlineCall(pkg.rtFunc("Basic"), prog.Val(int(kind))) + tptr := prog.Uintptr() + vptr := Expr{b.impl.CreateBitCast(x.impl, tptr.ll, ""), tptr} + return Expr{b.InlineCall(pkg.rtFunc("MakeAnyInt"), t, vptr).impl, tinter} case kind == types.String: return Expr{b.InlineCall(pkg.rtFunc("MakeAnyString"), x).impl, tinter} } @@ -1107,7 +1118,7 @@ func (b Builder) TypeAssert(x Expr, assertedTyp Type, commaOk bool) (ret Expr) { log.Printf("TypeAssert %v, %v, %v\n", x.impl, assertedTyp.raw.Type, commaOk) } switch assertedTyp.kind { - case vkSigned, vkUnsigned, vkFloat: + case vkSigned, vkUnsigned: pkg := b.Func.Pkg fnName := "I2Int" if commaOk { @@ -1123,6 +1134,25 @@ func (b Builder) TypeAssert(x Expr, assertedTyp Type, commaOk bool) (ret Expr) { } typ := b.InlineCall(pkg.rtFunc("Basic"), b.Prog.Val(int(kind))) return b.InlineCall(fn, x, typ) + case vkFloat: + var fnName string + kind := assertedTyp.raw.Underlying().(*types.Basic).Kind() + switch kind { + case types.Float32: + fnName = "I2Float32" + if commaOk { + fnName = "CheckI2Float32" + } + case types.Float64: + fnName = "I2Float64" + if commaOk { + fnName = "CheckI2Float64" + } + } + pkg := b.Func.Pkg + fn := pkg.rtFunc(fnName) + typ := b.InlineCall(pkg.rtFunc("Basic"), b.Prog.Val(int(kind))) + return b.InlineCall(fn, x, typ) } panic("todo") } @@ -1232,4 +1262,11 @@ func (b Builder) BuiltinCall(fn string, args ...Expr) (ret Expr) { panic("todo") } +// BitCast bit cast expr to type +func (b Builder) BitCast(val Expr, typ Type) (ret Expr) { + ret.Type = typ + ret.impl = b.impl.CreateBitCast(val.impl, typ.ll, "") + return +} + // -----------------------------------------------------------------------------