diff --git a/README.md b/README.md index cdb38794..97e95bb9 100644 --- a/README.md +++ b/README.md @@ -152,7 +152,7 @@ See [github.com/goplus/llgo/py](https://pkg.go.dev/github.com/goplus/llgo/py) fo LLGo can easily import any libraries from the C ecosystem. Currently, this import process is still manual, but in the future, it will be automated similar to Python library imports. -The currently imported libraries include: +The currently supported libraries include: * [llama2.c](https://pkg.go.dev/github.com/goplus/llgo/c/llama2) * [cjson](https://pkg.go.dev/github.com/goplus/llgo/c/cjson) diff --git a/chore/llvmtargets/llvm_targets.go b/chore/llvmtargets/llvm_targets.go new file mode 100644 index 00000000..936ae7e9 --- /dev/null +++ b/chore/llvmtargets/llvm_targets.go @@ -0,0 +1,18 @@ +package main + +import ( + "fmt" + + "github.com/goplus/llvm" +) + +func main() { + llvm.InitializeAllTargetInfos() + llvm.InitializeAllTargets() + llvm.InitializeAllTargetMCs() + llvm.InitializeNativeTarget() + fmt.Println("targets:") + for it := llvm.FirstTarget(); it.C != nil; it = it.NextTarget() { + fmt.Printf("- %s: %s\n", it.Name(), it.Description()) + } +} diff --git a/cl/_testdata/print/out.ll b/cl/_testdata/print/out.ll index dd88c08e..5aa0ca70 100644 --- a/cl/_testdata/print/out.ll +++ b/cl/_testdata/print/out.ll @@ -99,11 +99,11 @@ _llgo_0: 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) + %4 = call %"github.com/goplus/llgo/internal/runtime.iface" @"github.com/goplus/llgo/internal/runtime.MakeAnyIntptr"(ptr %3, i64 1315859240) call void @main.printany(%"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) + %6 = call %"github.com/goplus/llgo/internal/runtime.iface" @"github.com/goplus/llgo/internal/runtime.MakeAnyIntptr"(ptr %5, i64 4746175415993761792) call void @main.printany(%"github.com/goplus/llgo/internal/runtime.iface" %6) call void @main.printnl() br i1 true, label %_llgo_3, label %_llgo_2 @@ -116,7 +116,7 @@ _llgo_1: ; preds = %_llgo_3 store %"github.com/goplus/llgo/internal/runtime.iface" %10, ptr %8, align 8 %11 = getelementptr inbounds %"github.com/goplus/llgo/internal/runtime.iface", ptr %7, i64 1 %12 = call ptr @"github.com/goplus/llgo/internal/runtime.Basic"(i64 1) - %13 = call %"github.com/goplus/llgo/internal/runtime.iface" @"github.com/goplus/llgo/internal/runtime.MakeAnyInt"(ptr %12, i64 -1) + %13 = call %"github.com/goplus/llgo/internal/runtime.iface" @"github.com/goplus/llgo/internal/runtime.MakeAnyIntptr"(ptr %12, i64 -1) store %"github.com/goplus/llgo/internal/runtime.iface" %13, ptr %11, align 8 %14 = call %"github.com/goplus/llgo/internal/runtime.Slice" @"github.com/goplus/llgo/internal/runtime.NewSlice3"(ptr %7, i64 16, i64 2, i64 0, i64 2, i64 2) call void @main.println(%"github.com/goplus/llgo/internal/runtime.Slice" %14) @@ -130,74 +130,74 @@ _llgo_2: ; preds = %_llgo_3, %_llgo_1, store %"github.com/goplus/llgo/internal/runtime.iface" %18, ptr %16, align 8 %19 = getelementptr inbounds %"github.com/goplus/llgo/internal/runtime.iface", ptr %15, i64 1 %20 = call ptr @"github.com/goplus/llgo/internal/runtime.Basic"(i64 1) - %21 = call %"github.com/goplus/llgo/internal/runtime.iface" @"github.com/goplus/llgo/internal/runtime.MakeAnyInt"(ptr %20, i64 -1) + %21 = call %"github.com/goplus/llgo/internal/runtime.iface" @"github.com/goplus/llgo/internal/runtime.MakeAnyIntptr"(ptr %20, i64 -1) store %"github.com/goplus/llgo/internal/runtime.iface" %21, ptr %19, align 8 %22 = getelementptr inbounds %"github.com/goplus/llgo/internal/runtime.iface", ptr %15, i64 2 %23 = call ptr @"github.com/goplus/llgo/internal/runtime.Basic"(i64 1) - %24 = call %"github.com/goplus/llgo/internal/runtime.iface" @"github.com/goplus/llgo/internal/runtime.MakeAnyInt"(ptr %23, i64 -1) + %24 = call %"github.com/goplus/llgo/internal/runtime.iface" @"github.com/goplus/llgo/internal/runtime.MakeAnyIntptr"(ptr %23, i64 -1) store %"github.com/goplus/llgo/internal/runtime.iface" %24, ptr %22, align 8 %25 = call %"github.com/goplus/llgo/internal/runtime.Slice" @"github.com/goplus/llgo/internal/runtime.NewSlice3"(ptr %15, i64 16, i64 3, i64 0, i64 3, i64 3) call void @main.println(%"github.com/goplus/llgo/internal/runtime.Slice" %25) %26 = call ptr @"github.com/goplus/llgo/internal/runtime.AllocZ"(i64 256) %27 = getelementptr inbounds %"github.com/goplus/llgo/internal/runtime.iface", ptr %26, i64 0 %28 = call ptr @"github.com/goplus/llgo/internal/runtime.Basic"(i64 1) - %29 = call %"github.com/goplus/llgo/internal/runtime.iface" @"github.com/goplus/llgo/internal/runtime.MakeAnyInt"(ptr %28, i64 -1) + %29 = call %"github.com/goplus/llgo/internal/runtime.iface" @"github.com/goplus/llgo/internal/runtime.MakeAnyIntptr"(ptr %28, i64 -1) store %"github.com/goplus/llgo/internal/runtime.iface" %29, ptr %27, align 8 %30 = getelementptr inbounds %"github.com/goplus/llgo/internal/runtime.iface", ptr %26, i64 1 %31 = call ptr @"github.com/goplus/llgo/internal/runtime.Basic"(i64 1) - %32 = call %"github.com/goplus/llgo/internal/runtime.iface" @"github.com/goplus/llgo/internal/runtime.MakeAnyInt"(ptr %31, i64 0) + %32 = call %"github.com/goplus/llgo/internal/runtime.iface" @"github.com/goplus/llgo/internal/runtime.MakeAnyIntptr"(ptr %31, i64 0) store %"github.com/goplus/llgo/internal/runtime.iface" %32, ptr %30, align 8 %33 = getelementptr inbounds %"github.com/goplus/llgo/internal/runtime.iface", ptr %26, i64 2 %34 = call ptr @"github.com/goplus/llgo/internal/runtime.Basic"(i64 5) - %35 = call %"github.com/goplus/llgo/internal/runtime.iface" @"github.com/goplus/llgo/internal/runtime.MakeAnyInt"(ptr %34, i64 97) + %35 = call %"github.com/goplus/llgo/internal/runtime.iface" @"github.com/goplus/llgo/internal/runtime.MakeAnyIntptr"(ptr %34, i64 97) store %"github.com/goplus/llgo/internal/runtime.iface" %35, ptr %33, align 8 %36 = getelementptr inbounds %"github.com/goplus/llgo/internal/runtime.iface", ptr %26, i64 3 %37 = call ptr @"github.com/goplus/llgo/internal/runtime.Basic"(i64 5) - %38 = call %"github.com/goplus/llgo/internal/runtime.iface" @"github.com/goplus/llgo/internal/runtime.MakeAnyInt"(ptr %37, i64 65) + %38 = call %"github.com/goplus/llgo/internal/runtime.iface" @"github.com/goplus/llgo/internal/runtime.MakeAnyIntptr"(ptr %37, i64 65) store %"github.com/goplus/llgo/internal/runtime.iface" %38, ptr %36, align 8 %39 = getelementptr inbounds %"github.com/goplus/llgo/internal/runtime.iface", ptr %26, i64 4 %40 = call ptr @"github.com/goplus/llgo/internal/runtime.Basic"(i64 5) - %41 = call %"github.com/goplus/llgo/internal/runtime.iface" @"github.com/goplus/llgo/internal/runtime.MakeAnyInt"(ptr %40, i64 20013) + %41 = call %"github.com/goplus/llgo/internal/runtime.iface" @"github.com/goplus/llgo/internal/runtime.MakeAnyIntptr"(ptr %40, i64 20013) store %"github.com/goplus/llgo/internal/runtime.iface" %41, ptr %39, align 8 %42 = getelementptr inbounds %"github.com/goplus/llgo/internal/runtime.iface", ptr %26, i64 5 %43 = call ptr @"github.com/goplus/llgo/internal/runtime.Basic"(i64 3) - %44 = call %"github.com/goplus/llgo/internal/runtime.iface" @"github.com/goplus/llgo/internal/runtime.MakeAnyInt"(ptr %43, i64 1) + %44 = call %"github.com/goplus/llgo/internal/runtime.iface" @"github.com/goplus/llgo/internal/runtime.MakeAnyIntptr"(ptr %43, i64 1) store %"github.com/goplus/llgo/internal/runtime.iface" %44, ptr %42, align 8 %45 = getelementptr inbounds %"github.com/goplus/llgo/internal/runtime.iface", ptr %26, i64 6 %46 = call ptr @"github.com/goplus/llgo/internal/runtime.Basic"(i64 4) - %47 = call %"github.com/goplus/llgo/internal/runtime.iface" @"github.com/goplus/llgo/internal/runtime.MakeAnyInt"(ptr %46, i64 2) + %47 = call %"github.com/goplus/llgo/internal/runtime.iface" @"github.com/goplus/llgo/internal/runtime.MakeAnyIntptr"(ptr %46, i64 2) store %"github.com/goplus/llgo/internal/runtime.iface" %47, ptr %45, align 8 %48 = getelementptr inbounds %"github.com/goplus/llgo/internal/runtime.iface", ptr %26, i64 7 %49 = call ptr @"github.com/goplus/llgo/internal/runtime.Basic"(i64 5) - %50 = call %"github.com/goplus/llgo/internal/runtime.iface" @"github.com/goplus/llgo/internal/runtime.MakeAnyInt"(ptr %49, i64 3) + %50 = call %"github.com/goplus/llgo/internal/runtime.iface" @"github.com/goplus/llgo/internal/runtime.MakeAnyIntptr"(ptr %49, i64 3) store %"github.com/goplus/llgo/internal/runtime.iface" %50, ptr %48, align 8 %51 = getelementptr inbounds %"github.com/goplus/llgo/internal/runtime.iface", ptr %26, i64 8 %52 = call ptr @"github.com/goplus/llgo/internal/runtime.Basic"(i64 6) - %53 = call %"github.com/goplus/llgo/internal/runtime.iface" @"github.com/goplus/llgo/internal/runtime.MakeAnyInt"(ptr %52, i64 4) + %53 = call %"github.com/goplus/llgo/internal/runtime.iface" @"github.com/goplus/llgo/internal/runtime.MakeAnyIntptr"(ptr %52, i64 4) store %"github.com/goplus/llgo/internal/runtime.iface" %53, ptr %51, align 8 %54 = getelementptr inbounds %"github.com/goplus/llgo/internal/runtime.iface", ptr %26, i64 9 %55 = call ptr @"github.com/goplus/llgo/internal/runtime.Basic"(i64 2) - %56 = call %"github.com/goplus/llgo/internal/runtime.iface" @"github.com/goplus/llgo/internal/runtime.MakeAnyInt"(ptr %55, i64 5) + %56 = call %"github.com/goplus/llgo/internal/runtime.iface" @"github.com/goplus/llgo/internal/runtime.MakeAnyIntptr"(ptr %55, i64 5) store %"github.com/goplus/llgo/internal/runtime.iface" %56, ptr %54, align 8 %57 = getelementptr inbounds %"github.com/goplus/llgo/internal/runtime.iface", ptr %26, i64 10 %58 = call ptr @"github.com/goplus/llgo/internal/runtime.Basic"(i64 8) - %59 = call %"github.com/goplus/llgo/internal/runtime.iface" @"github.com/goplus/llgo/internal/runtime.MakeAnyInt"(ptr %58, i64 1) + %59 = call %"github.com/goplus/llgo/internal/runtime.iface" @"github.com/goplus/llgo/internal/runtime.MakeAnyIntptr"(ptr %58, i64 1) store %"github.com/goplus/llgo/internal/runtime.iface" %59, ptr %57, align 8 %60 = getelementptr inbounds %"github.com/goplus/llgo/internal/runtime.iface", ptr %26, i64 11 %61 = call ptr @"github.com/goplus/llgo/internal/runtime.Basic"(i64 9) - %62 = call %"github.com/goplus/llgo/internal/runtime.iface" @"github.com/goplus/llgo/internal/runtime.MakeAnyInt"(ptr %61, i64 2) + %62 = call %"github.com/goplus/llgo/internal/runtime.iface" @"github.com/goplus/llgo/internal/runtime.MakeAnyIntptr"(ptr %61, i64 2) store %"github.com/goplus/llgo/internal/runtime.iface" %62, ptr %60, align 8 %63 = getelementptr inbounds %"github.com/goplus/llgo/internal/runtime.iface", ptr %26, i64 12 %64 = call ptr @"github.com/goplus/llgo/internal/runtime.Basic"(i64 10) - %65 = call %"github.com/goplus/llgo/internal/runtime.iface" @"github.com/goplus/llgo/internal/runtime.MakeAnyInt"(ptr %64, i64 3) + %65 = call %"github.com/goplus/llgo/internal/runtime.iface" @"github.com/goplus/llgo/internal/runtime.MakeAnyIntptr"(ptr %64, i64 3) store %"github.com/goplus/llgo/internal/runtime.iface" %65, ptr %63, align 8 %66 = getelementptr inbounds %"github.com/goplus/llgo/internal/runtime.iface", ptr %26, i64 13 %67 = call ptr @"github.com/goplus/llgo/internal/runtime.Basic"(i64 11) - %68 = call %"github.com/goplus/llgo/internal/runtime.iface" @"github.com/goplus/llgo/internal/runtime.MakeAnyInt"(ptr %67, i64 4) + %68 = call %"github.com/goplus/llgo/internal/runtime.iface" @"github.com/goplus/llgo/internal/runtime.MakeAnyIntptr"(ptr %67, i64 4) store %"github.com/goplus/llgo/internal/runtime.iface" %68, ptr %66, align 8 %69 = getelementptr inbounds %"github.com/goplus/llgo/internal/runtime.iface", ptr %26, i64 14 %70 = call ptr @"github.com/goplus/llgo/internal/runtime.Basic"(i64 12) - %71 = call %"github.com/goplus/llgo/internal/runtime.iface" @"github.com/goplus/llgo/internal/runtime.MakeAnyInt"(ptr %70, i64 5) + %71 = call %"github.com/goplus/llgo/internal/runtime.iface" @"github.com/goplus/llgo/internal/runtime.MakeAnyIntptr"(ptr %70, i64 5) store %"github.com/goplus/llgo/internal/runtime.iface" %71, ptr %69, align 8 %72 = getelementptr inbounds %"github.com/goplus/llgo/internal/runtime.iface", ptr %26, i64 15 %73 = call %"github.com/goplus/llgo/internal/runtime.String" @"github.com/goplus/llgo/internal/runtime.NewString"(ptr @4, i64 4) @@ -801,9 +801,9 @@ 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.MakeAnyIntptr"(ptr, i64) -declare %"github.com/goplus/llgo/internal/runtime.iface" @"github.com/goplus/llgo/internal/runtime.MakeAnyInt"(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.MakeAnyString"(%"github.com/goplus/llgo/internal/runtime.String") diff --git a/cl/_testdata/vargs/out.ll b/cl/_testdata/vargs/out.ll index def89a93..86c098c9 100644 --- a/cl/_testdata/vargs/out.ll +++ b/cl/_testdata/vargs/out.ll @@ -31,15 +31,15 @@ _llgo_0: %2 = call ptr @"github.com/goplus/llgo/internal/runtime.AllocZ"(i64 48) %3 = getelementptr inbounds %"github.com/goplus/llgo/internal/runtime.iface", ptr %2, i64 0 %4 = call ptr @"github.com/goplus/llgo/internal/runtime.Basic"(i64 2) - %5 = call %"github.com/goplus/llgo/internal/runtime.iface" @"github.com/goplus/llgo/internal/runtime.MakeAnyInt"(ptr %4, i64 1) + %5 = call %"github.com/goplus/llgo/internal/runtime.iface" @"github.com/goplus/llgo/internal/runtime.MakeAnyIntptr"(ptr %4, i64 1) store %"github.com/goplus/llgo/internal/runtime.iface" %5, ptr %3, align 8 %6 = getelementptr inbounds %"github.com/goplus/llgo/internal/runtime.iface", ptr %2, i64 1 %7 = call ptr @"github.com/goplus/llgo/internal/runtime.Basic"(i64 2) - %8 = call %"github.com/goplus/llgo/internal/runtime.iface" @"github.com/goplus/llgo/internal/runtime.MakeAnyInt"(ptr %7, i64 2) + %8 = call %"github.com/goplus/llgo/internal/runtime.iface" @"github.com/goplus/llgo/internal/runtime.MakeAnyIntptr"(ptr %7, i64 2) store %"github.com/goplus/llgo/internal/runtime.iface" %8, ptr %6, align 8 %9 = getelementptr inbounds %"github.com/goplus/llgo/internal/runtime.iface", ptr %2, i64 2 %10 = call ptr @"github.com/goplus/llgo/internal/runtime.Basic"(i64 2) - %11 = call %"github.com/goplus/llgo/internal/runtime.iface" @"github.com/goplus/llgo/internal/runtime.MakeAnyInt"(ptr %10, i64 3) + %11 = call %"github.com/goplus/llgo/internal/runtime.iface" @"github.com/goplus/llgo/internal/runtime.MakeAnyIntptr"(ptr %10, i64 3) store %"github.com/goplus/llgo/internal/runtime.iface" %11, ptr %9, align 8 %12 = call %"github.com/goplus/llgo/internal/runtime.Slice" @"github.com/goplus/llgo/internal/runtime.NewSlice3"(ptr %2, i64 16, i64 3, i64 0, i64 3, i64 3) call void @main.test(%"github.com/goplus/llgo/internal/runtime.Slice" %12) @@ -76,9 +76,9 @@ declare void @"github.com/goplus/llgo/internal/runtime.init"() declare ptr @"github.com/goplus/llgo/internal/runtime.AllocZ"(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.MakeAnyIntptr"(ptr, i64) -declare %"github.com/goplus/llgo/internal/runtime.iface" @"github.com/goplus/llgo/internal/runtime.MakeAnyInt"(ptr, i64) +declare ptr @"github.com/goplus/llgo/internal/runtime.Basic"(i64) declare %"github.com/goplus/llgo/internal/runtime.Slice" @"github.com/goplus/llgo/internal/runtime.NewSlice3"(ptr, i64, i64, i64, i64, i64) diff --git a/cl/_testrt/any/out.ll b/cl/_testrt/any/out.ll index fdd52ad1..fbf58289 100644 --- a/cl/_testrt/any/out.ll +++ b/cl/_testrt/any/out.ll @@ -36,7 +36,7 @@ _llgo_0: call void @"github.com/goplus/llgo/internal/runtime.init"() call void @main.init() %2 = call ptr @"github.com/goplus/llgo/internal/runtime.Basic"(i64 2) - %3 = call %"github.com/goplus/llgo/internal/runtime.iface" @"github.com/goplus/llgo/internal/runtime.MakeAnyInt"(ptr %2, i64 100) + %3 = call %"github.com/goplus/llgo/internal/runtime.iface" @"github.com/goplus/llgo/internal/runtime.MakeAnyIntptr"(ptr %2, i64 100) %4 = call i64 @main.incVal(%"github.com/goplus/llgo/internal/runtime.iface" %3) %5 = call i32 (ptr, ...) @printf(ptr @0, i64 %4) ret i32 0 @@ -48,6 +48,6 @@ declare ptr @"github.com/goplus/llgo/internal/runtime.Basic"(i64) declare void @"github.com/goplus/llgo/internal/runtime.init"() -declare %"github.com/goplus/llgo/internal/runtime.iface" @"github.com/goplus/llgo/internal/runtime.MakeAnyInt"(ptr, i64) +declare %"github.com/goplus/llgo/internal/runtime.iface" @"github.com/goplus/llgo/internal/runtime.MakeAnyIntptr"(ptr, i64) declare i32 @printf(ptr, ...) diff --git a/cl/_testrt/builtin/out.ll b/cl/_testrt/builtin/out.ll index 2af18d2b..39388613 100644 --- a/cl/_testrt/builtin/out.ll +++ b/cl/_testrt/builtin/out.ll @@ -288,7 +288,7 @@ _llgo_0: call void @"github.com/goplus/llgo/internal/runtime.PrintString"(%"github.com/goplus/llgo/internal/runtime.String" %121) %122 = call ptr @"github.com/goplus/llgo/internal/runtime.AllocZ"(i64 16) %123 = call ptr @"github.com/goplus/llgo/internal/runtime.Basic"(i64 2) - %124 = call %"github.com/goplus/llgo/internal/runtime.iface" @"github.com/goplus/llgo/internal/runtime.MakeAnyInt"(ptr %123, i64 100) + %124 = call %"github.com/goplus/llgo/internal/runtime.iface" @"github.com/goplus/llgo/internal/runtime.MakeAnyIntptr"(ptr %123, i64 100) store %"github.com/goplus/llgo/internal/runtime.iface" %124, ptr %122, align 8 %125 = load %"github.com/goplus/llgo/internal/runtime.iface", ptr %122, align 8 %126 = ptrtoint ptr %122 to i64 @@ -392,9 +392,9 @@ declare %"github.com/goplus/llgo/internal/runtime.String" @"github.com/goplus/ll declare %"github.com/goplus/llgo/internal/runtime.Slice" @"github.com/goplus/llgo/internal/runtime.SliceAppend"(%"github.com/goplus/llgo/internal/runtime.Slice", ptr, i64, 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.MakeAnyIntptr"(ptr, i64) -declare %"github.com/goplus/llgo/internal/runtime.iface" @"github.com/goplus/llgo/internal/runtime.MakeAnyInt"(ptr, i64) +declare ptr @"github.com/goplus/llgo/internal/runtime.Basic"(i64) declare void @"github.com/goplus/llgo/internal/runtime.PrintBool"(i1) diff --git a/cl/cltest/cltest.go b/cl/cltest/cltest.go index 3b8c60b2..a0d0b750 100644 --- a/cl/cltest/cltest.go +++ b/cl/cltest/cltest.go @@ -32,6 +32,7 @@ import ( "github.com/goplus/gogen/packages" "github.com/goplus/llgo/cl" "github.com/goplus/llgo/internal/llgen" + "github.com/goplus/llgo/ssa/ssatest" "golang.org/x/tools/go/ssa" "golang.org/x/tools/go/ssa/ssautil" @@ -139,21 +140,7 @@ func TestCompileEx(t *testing.T, src any, fname, expected string) { t.Fatal("BuildPackage failed:", err) } foo.WriteTo(os.Stderr) - prog := llssa.NewProgram(nil) - prog.SetRuntime(func() *types.Package { - rt, err := imp.Import(llssa.PkgRuntime) - if err != nil { - t.Fatal("load runtime failed:", err) - } - return rt - }) - prog.SetPython(func() *types.Package { - rt, err := imp.Import(llssa.PkgPython) - if err != nil { - t.Fatal("load python failed:", err) - } - return rt - }) + prog := ssatest.NewProgramEx(t, nil, imp) ret, err := cl.NewPackage(prog, foo, files) if err != nil { diff --git a/go.mod b/go.mod index d1455dbd..5e702b52 100644 --- a/go.mod +++ b/go.mod @@ -1,6 +1,6 @@ module github.com/goplus/llgo -go 1.18 +go 1.20 require ( github.com/aykevl/go-wasm v0.0.1 diff --git a/internal/abi/llgo_autogen.lla b/internal/abi/llgo_autogen.lla index cccf2f81..4f8bcd99 100644 Binary files a/internal/abi/llgo_autogen.lla and b/internal/abi/llgo_autogen.lla differ diff --git a/internal/abi/type.go b/internal/abi/type.go index 549a135a..17b61967 100644 --- a/internal/abi/type.go +++ b/internal/abi/type.go @@ -213,36 +213,6 @@ type StructType struct { Fields []StructField } -// Name is an encoded type Name with optional extra data. -// -// The first byte is a bit field containing: -// -// 1<<0 the name is exported -// 1<<1 tag data follows the name -// 1<<2 pkgPath nameOff follows the name and tag -// 1<<3 the name is of an embedded (a.k.a. anonymous) field -// -// Following that, there is a varint-encoded length of the name, -// followed by the name itself. -// -// If tag data is present, it also has a varint-encoded length -// followed by the tag itself. -// -// If the import path follows, then 4 bytes at the end of -// the data form a nameOff. The import path is only set for concrete -// methods that are defined in a different package than their type. -// -// If a name starts with "*", then the exported bit represents -// whether the pointed to type is exported. -// -// Note: this encoding must match here and in: -// cmd/compile/internal/reflectdata/reflect.go -// cmd/link/internal/ld/decodesym.go - -type Name struct { - Bytes *byte -} - type InterfaceType struct { Type PkgPath Name // import path @@ -330,3 +300,168 @@ func (t *Type) InterfaceType() *InterfaceType { } // ----------------------------------------------------------------------------- + +// addChecked returns p+x. +// +// The whySafe string is ignored, so that the function still inlines +// as efficiently as p+x, but all call sites should use the string to +// record why the addition is safe, which is to say why the addition +// does not cause x to advance to the very end of p's allocation +// and therefore point incorrectly at the next block in memory. +func addChecked(p unsafe.Pointer, x uintptr, whySafe string) unsafe.Pointer { + _ = whySafe + return unsafe.Pointer(uintptr(p) + x) +} + +// Name is an encoded type Name with optional extra data. +// +// The first byte is a bit field containing: +// +// 1<<0 the name is exported +// 1<<1 tag data follows the name +// 1<<2 pkgPath nameOff follows the name and tag +// 1<<3 the name is of an embedded (a.k.a. anonymous) field +// +// Following that, there is a varint-encoded length of the name, +// followed by the name itself. +// +// If tag data is present, it also has a varint-encoded length +// followed by the tag itself. +// +// If the import path follows, then 4 bytes at the end of +// the data form a nameOff. The import path is only set for concrete +// methods that are defined in a different package than their type. +// +// If a name starts with "*", then the exported bit represents +// whether the pointed to type is exported. +// +// Note: this encoding must match here and in: +// cmd/compile/internal/reflectdata/reflect.go +// cmd/link/internal/ld/decodesym.go + +type Name struct { + Bytes *byte +} + +// DataChecked does pointer arithmetic on n's Bytes, and that arithmetic is asserted to +// be safe for the reason in whySafe (which can appear in a backtrace, etc.) +func (n Name) DataChecked(off int, whySafe string) *byte { + return (*byte)(addChecked(unsafe.Pointer(n.Bytes), uintptr(off), whySafe)) +} + +// Data does pointer arithmetic on n's Bytes, and that arithmetic is asserted to +// be safe because the runtime made the call (other packages use DataChecked) +func (n Name) Data(off int) *byte { + return (*byte)(addChecked(unsafe.Pointer(n.Bytes), uintptr(off), "the runtime doesn't need to give you a reason")) +} + +// IsExported returns "is n exported?" +func (n Name) IsExported() bool { + return (*n.Bytes)&(1<<0) != 0 +} + +// HasTag returns true iff there is tag data following this name +func (n Name) HasTag() bool { + return (*n.Bytes)&(1<<1) != 0 +} + +// IsEmbedded returns true iff n is embedded (an anonymous field). +func (n Name) IsEmbedded() bool { + return (*n.Bytes)&(1<<3) != 0 +} + +// ReadVarint parses a varint as encoded by encoding/binary. +// It returns the number of encoded bytes and the encoded value. +func (n Name) ReadVarint(off int) (int, int) { + v := 0 + for i := 0; ; i++ { + x := *n.DataChecked(off+i, "read varint") + v += int(x&0x7f) << (7 * i) + if x&0x80 == 0 { + return i + 1, v + } + } +} + +// IsBlank indicates whether n is "_". +func (n Name) IsBlank() bool { + if n.Bytes == nil { + return false + } + _, l := n.ReadVarint(1) + return l == 1 && *n.Data(2) == '_' +} + +// writeVarint writes n to buf in varint form. Returns the +// number of bytes written. n must be nonnegative. +// Writes at most 10 bytes. +func writeVarint(buf []byte, n int) int { + for i := 0; ; i++ { + b := byte(n & 0x7f) + n >>= 7 + if n == 0 { + buf[i] = b + return i + 1 + } + buf[i] = b | 0x80 + } +} + +// Name returns the tag string for n, or empty if there is none. +func (n Name) Name() string { + if n.Bytes == nil { + return "" + } + i, l := n.ReadVarint(1) + return unsafe.String(n.DataChecked(1+i, "non-empty string"), l) +} + +// Tag returns the tag string for n, or empty if there is none. +func (n Name) Tag() string { + if !n.HasTag() { + return "" + } + i, l := n.ReadVarint(1) + i2, l2 := n.ReadVarint(1 + i + l) + return unsafe.String(n.DataChecked(1+i+l+i2, "non-empty string"), l2) +} + +func NewName(n, tag string, exported, embedded bool) Name { + if len(n) >= 1<<29 { + panic("abi.NewName: name too long: " + n[:1024] + "...") + } + if len(tag) >= 1<<29 { + panic("abi.NewName: tag too long: " + tag[:1024] + "...") + } + var nameLen [10]byte + var tagLen [10]byte + nameLenLen := writeVarint(nameLen[:], len(n)) + tagLenLen := writeVarint(tagLen[:], len(tag)) + + var bits byte + l := 1 + nameLenLen + len(n) + if exported { + bits |= 1 << 0 + } + if len(tag) > 0 { + l += tagLenLen + len(tag) + bits |= 1 << 1 + } + if embedded { + bits |= 1 << 3 + } + + b := make([]byte, l) + b[0] = bits + copy(b[1:], nameLen[:nameLenLen]) + copy(b[1+nameLenLen:], n) + if len(tag) > 0 { + tb := b[1+nameLenLen+len(n):] + copy(tb, tagLen[:tagLenLen]) + copy(tb[tagLenLen:], tag) + } + + return Name{Bytes: &b[0]} +} + +// ----------------------------------------------------------------------------- diff --git a/internal/runtime/llgo_autogen.lla b/internal/runtime/llgo_autogen.lla index 6257d02d..94569d30 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 e8d8c747..c64449ca 100644 --- a/internal/runtime/z_iface.go +++ b/internal/runtime/z_iface.go @@ -34,7 +34,7 @@ var ( type Interface = iface -func MakeAnyInt(typ *Type, data uintptr) Interface { +func MakeAnyIntptr(typ *Type, data uintptr) Interface { tab := &itab{inter: TyAny, _type: typ, hash: 0, fun: [1]uintptr{0}} return Interface{ tab: tab, data: unsafe.Pointer(data), diff --git a/internal/runtime/z_string.go b/internal/runtime/z_string.go index b137447d..6f9ad609 100644 --- a/internal/runtime/z_string.go +++ b/internal/runtime/z_string.go @@ -40,6 +40,7 @@ func EmptyString() String { return String{nil, 0} } +// TODO(xsw): unsafe.String // NewString creates a new string. func NewString(data unsafe.Pointer, len int) String { return String{data, len} diff --git a/ssa/_abi/abi.go b/ssa/_abi/abi.go new file mode 100644 index 00000000..65578218 --- /dev/null +++ b/ssa/_abi/abi.go @@ -0,0 +1,73 @@ +/* + * Copyright (c) 2024 The GoPlus Authors (goplus.org). All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package abi + +import ( + "crypto/sha256" + "encoding/base64" + "fmt" + "go/types" + "hash" +) + +// Builder is a helper for constructing ABI types. +type Builder struct { + h hash.Hash + buf []byte +} + +// New creates a new ABI type Builder. +func New() *Builder { + h := sha256.New() + buf := make([]byte, sha256.Size) + return &Builder{h, buf} +} + +// TypeName returns the ABI type name for the specified type. +func (b *Builder) TypeName(t types.Type) string { + switch t := t.(type) { + case *types.Basic: + return t.Name() + case *types.Pointer: + return "*" + b.TypeName(t.Elem()) + case *types.Struct: + return b.StructName(t) + } + panic("todo") +} + +// StructName returns the ABI type name for the specified struct type. +func (b *Builder) StructName(t *types.Struct) string { + hash := b.structHash(t) + return "struct$" + base64.RawURLEncoding.EncodeToString(hash) +} + +func (b *Builder) structHash(t *types.Struct) []byte { + h := b.h + h.Reset() + n := t.NumFields() + fmt.Fprintln(h, "struct", n) + for i := 0; i < n; i++ { + f := t.Field(i) + name := f.Name() + if f.Embedded() { + name = "-" + } + fmt.Fprintln(h, name, b.TypeName(f.Type())) + } + return h.Sum(b.buf[:0]) +} diff --git a/ssa/cl_test.go b/ssa/cl_test.go index 4d79ec49..c89a0958 100644 --- a/ssa/cl_test.go +++ b/ssa/cl_test.go @@ -17,9 +17,12 @@ package ssa_test import ( + "go/types" "testing" "github.com/goplus/llgo/cl/cltest" + "github.com/goplus/llgo/ssa" + "github.com/goplus/llgo/ssa/ssatest" ) func TestFromTestpy(t *testing.T) { @@ -36,9 +39,46 @@ func TestFromTestdata(t *testing.T) { func TestRuntime(t *testing.T) { cltest.Pkg(t, "github.com/goplus/llgo/internal/runtime", "../internal/runtime/llgo_autogen.ll") +} + +func TestAbi(t *testing.T) { cltest.Pkg(t, "github.com/goplus/llgo/internal/abi", "../internal/abi/llgo_autogen.ll") } +func TestMakeInterface(t *testing.T) { + prog := ssatest.NewProgram(t, &ssa.Target{GOARCH: "x86"}) + pkg := prog.NewPackage("foo", "foo") + fn := pkg.NewFunc("main", types.NewSignatureType(nil, nil, nil, nil, nil, false), ssa.InC) + b := fn.MakeBody(1) + b.MakeInterface(prog.Any(), prog.IntVal(100, prog.Int64())) + b.MakeInterface(prog.Any(), prog.FloatVal(100, prog.Float64())) + b.Return() + ssatest.Assert(t, pkg, `; ModuleID = 'foo' +source_filename = "foo" + +%"github.com/goplus/llgo/internal/runtime.iface" = type { ptr, ptr } + +define void @main() { +_llgo_0: + %0 = call ptr @"github.com/goplus/llgo/internal/runtime.AllocU"(i64 8) + store i64 100, ptr %0, align 4 + %1 = call ptr @"github.com/goplus/llgo/internal/runtime.Basic"(i64 6) + %2 = call %"github.com/goplus/llgo/internal/runtime.iface" @"github.com/goplus/llgo/internal/runtime.MakeAny"(ptr %1, ptr %0) + %3 = call ptr @"github.com/goplus/llgo/internal/runtime.AllocU"(i64 8) + store double 1.000000e+02, ptr %3, align 8 + %4 = call ptr @"github.com/goplus/llgo/internal/runtime.Basic"(i64 14) + %5 = call %"github.com/goplus/llgo/internal/runtime.iface" @"github.com/goplus/llgo/internal/runtime.MakeAny"(ptr %4, ptr %3) + ret void +} + +declare ptr @"github.com/goplus/llgo/internal/runtime.AllocU"(i64) + +declare %"github.com/goplus/llgo/internal/runtime.iface" @"github.com/goplus/llgo/internal/runtime.MakeAny"(ptr, ptr) + +declare ptr @"github.com/goplus/llgo/internal/runtime.Basic"(i64) +`) +} + /* func TestCallback(t *testing.T) { ctx := llvm.NewContext() diff --git a/ssa/expr.go b/ssa/expr.go index 722060a7..1f18f269 100644 --- a/ssa/expr.go +++ b/ssa/expr.go @@ -665,7 +665,18 @@ func (b Builder) Alloc(elem Type, heap bool) (ret Expr) { return } -// Alloca allocates space for n bytes. +// AllocU allocates uninitialized space for n*sizeof(elem) bytes. +func (b Builder) AllocU(elem Type, n ...int64) (ret Expr) { + if debugInstr { + log.Printf("AllocU %v, %v\n", elem.raw.Type, n) + } + size := b.SizeOf(elem, n...) + ret = b.InlineCall(b.Pkg.rtFunc("AllocU"), size) + ret.Type = b.Prog.Pointer(elem) + return +} + +// Alloca allocates uninitialized space for n bytes. func (b Builder) Alloca(n Expr) (ret Expr) { if debugInstr { log.Printf("Alloca %v\n", n.impl) @@ -984,9 +995,10 @@ func (b Builder) BuiltinCall(fn string, args ...Expr) (ret Expr) { for i, arg := range args { if ln && i > 0 { b.InlineCall(b.Pkg.rtFunc("PrintString"), b.Str(" ")) + // TODO(visualfc): maybe use PrintCStr is more efficient } var fn string - var typ Type + var typ Type // TODO(visualfc): typ uninitialized in some cases switch arg.kind { case vkBool: fn = "PrintBool" @@ -1002,6 +1014,8 @@ func (b Builder) BuiltinCall(fn string, args ...Expr) (ret Expr) { case vkSlice: fn = "PrintSlice" case vkPtr, vkFuncPtr, vkFuncDecl, vkClosure, vkPyVarRef, vkPyFuncRef: + // TODO(visualfc): vkClosure is not a pointer + // TODO(visualfc): vkPyVarRef, vkPyFuncRef is pointer of pointer fn = "PrintPointer" typ = b.Prog.VoidPtr() case vkString: @@ -1037,8 +1051,11 @@ func (b Builder) BuiltinCall(fn string, args ...Expr) (ret Expr) { } } } + case "String": // unsafe.String + // TODO(xsw): make this a builtin + return b.InlineCall(b.Pkg.rtFunc("NewString"), args[0], args[1]) } - panic("todo") + panic("todo: " + fn) } // ----------------------------------------------------------------------------- diff --git a/ssa/interface.go b/ssa/interface.go index ee9a451e..16004054 100644 --- a/ssa/interface.go +++ b/ssa/interface.go @@ -27,19 +27,29 @@ import ( // ----------------------------------------------------------------------------- -// AbiBasic returns the abi type of the specified basic kind. -func (b Builder) AbiBasic(kind types.BasicKind) Expr { +// abiBasic returns the abi type of the specified basic kind. +func (b Builder) abiBasic(kind types.BasicKind) Expr { return b.InlineCall(b.Pkg.rtFunc("Basic"), b.Prog.Val(int(kind))) } /* -// AbiStruct returns the abi type of the specified struct type. -func (b Builder) AbiStruct(t *types.Struct) Expr { - panic("todo") - // return b.InlineCall(b.Pkg.rtFunc("Struct"), b.Prog.Val(t.NumFields())) +// abiStruct returns the abi type of the specified struct type. +func (b Builder) abiStruct(t *types.Struct) Expr { + // name := "__llgo_" + b.Prog.abi.StructName(t) } */ +// AbiType returns the abi type of the specified type. +func (b Builder) AbiType(t Type) Expr { + switch tx := t.raw.Type.(type) { + case *types.Basic: + return b.abiBasic(tx.Kind()) + //case *types.Struct: + // return b.abiStruct(tx) + } + panic("todo") +} + // ----------------------------------------------------------------------------- // MakeInterface constructs an instance of an interface type from a @@ -57,37 +67,66 @@ func (b Builder) AbiStruct(t *types.Struct) Expr { // t1 = make interface{} <- int (42:int) // t2 = make Stringer <- t0 func (b Builder) MakeInterface(tinter Type, x Expr) (ret Expr) { - raw := tinter.raw.Type + rawIntf := tinter.raw.Type.Underlying().(*types.Interface) if debugInstr { - log.Printf("MakeInterface %v, %v\n", raw, x.impl) + log.Printf("MakeInterface %v, %v\n", rawIntf, x.impl) } prog := b.Prog - pkg := b.Pkg - switch tx := x.raw.Type.Underlying().(type) { + typ := x.Type + switch tx := typ.raw.Type.Underlying().(type) { case *types.Basic: kind := tx.Kind() switch { case kind >= types.Bool && kind <= types.Uintptr: - t := b.AbiBasic(kind) - 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} + if prog.is32Bits && (kind == types.Int64 || kind == types.Uint64) { + return b.makeIntfAlloc(tinter, rawIntf, typ, x) + } + return b.makeIntfByIntptr(tinter, rawIntf, typ, x.impl) case kind == types.Float32: - t := b.AbiBasic(kind) - tptr := prog.Uintptr() - i32 := llvm.CreateBitCast(b.impl, x.impl, prog.tyInt32()) // TODO(xsw): more effective - vptr := Expr{llvm.CreateIntCast(b.impl, i32, tptr.ll), tptr} - return Expr{b.InlineCall(pkg.rtFunc("MakeAnyInt"), t, vptr).impl, tinter} + i32 := llvm.CreateBitCast(b.impl, x.impl, prog.tyInt32()) + return b.makeIntfByIntptr(tinter, rawIntf, typ, i32) case kind == types.Float64: - t := b.AbiBasic(kind) - tptr := prog.Uintptr() - vptr := Expr{llvm.CreateBitCast(b.impl, x.impl, tptr.ll), tptr} - return Expr{b.InlineCall(pkg.rtFunc("MakeAnyInt"), t, vptr).impl, tinter} + if prog.is32Bits { + return b.makeIntfAlloc(tinter, rawIntf, typ, x) + } + i64 := llvm.CreateBitCast(b.impl, x.impl, prog.tyInt64()) + return b.makeIntfByIntptr(tinter, rawIntf, typ, i64) case kind == types.String: - return Expr{b.InlineCall(pkg.rtFunc("MakeAnyString"), x).impl, tinter} + return Expr{b.InlineCall(b.Pkg.rtFunc("MakeAnyString"), x).impl, tinter} } - // case *types.Struct: - // t := b.AbiStruct(tx) + /* case *types.Struct: + size := int(prog.SizeOf(typ)) + if size > prog.PointerSize() { + return b.makeIntfAlloc(tinter, rawIntf, typ, x) + } + tv := prog.ctx.IntType(size * 8) + iv := llvm.CreateBitCast(b.impl, x.impl, tv) + return b.makeIntfByIntptr(tinter, rawIntf, typ, iv) */ + } + panic("todo") +} + +func (b Builder) makeIntfAlloc(tinter Type, rawIntf *types.Interface, typ Type, x Expr) (ret Expr) { + vptr := b.AllocU(typ) + b.Store(vptr, x) + return b.makeIntfByPtr(tinter, rawIntf, typ, vptr) +} + +func (b Builder) makeIntfByPtr(tinter Type, rawIntf *types.Interface, typ Type, vptr Expr) (ret Expr) { + if rawIntf.Empty() { + ret = b.InlineCall(b.Pkg.rtFunc("MakeAny"), b.AbiType(typ), vptr) + ret.Type = tinter + return + } + panic("todo") +} + +func (b Builder) makeIntfByIntptr(tinter Type, rawIntf *types.Interface, typ Type, x llvm.Value) (ret Expr) { + if rawIntf.Empty() { + tptr := b.Prog.Uintptr() + x = llvm.CreateIntCast(b.impl, x, tptr.ll) + impl := b.InlineCall(b.Pkg.rtFunc("MakeAnyIntptr"), b.AbiType(typ), Expr{x, tptr}).impl + return Expr{impl, tinter} } panic("todo") } diff --git a/ssa/package.go b/ssa/package.go index bc9cb7cc..9e9356bb 100644 --- a/ssa/package.go +++ b/ssa/package.go @@ -99,6 +99,7 @@ type aProgram struct { ctx llvm.Context typs typeutil.Map // rawType -> Type gocvt goTypes + //abi *abi.Builder rt *types.Package rtget func() *types.Package @@ -158,6 +159,7 @@ type aProgram struct { NeedRuntime bool NeedPyInit bool + is32Bits bool } // A Program presents a program. @@ -180,7 +182,12 @@ func NewProgram(target *Target) Program { // TODO(xsw): Finalize may cause panic, so comment it. ctx.Finalize() */ - return &aProgram{ctx: ctx, gocvt: newGoTypes(), target: target, td: td, named: make(map[string]llvm.Type)} + is32Bits := (td.PointerSize() == 4 || target.GOARCH == "x86") // TODO(xsw): remove temp code + return &aProgram{ + ctx: ctx, gocvt: newGoTypes(), // abi: abi.New(), + target: target, td: td, is32Bits: is32Bits, + named: make(map[string]llvm.Type), + } } // SetPython sets the Python package. diff --git a/ssa/ssa_test.go b/ssa/ssa_test.go index 05496769..103ee79e 100644 --- a/ssa/ssa_test.go +++ b/ssa/ssa_test.go @@ -21,10 +21,18 @@ import ( "go/token" "go/types" "testing" + "unsafe" "github.com/goplus/llvm" ) +func TestPointerSize(t *testing.T) { + expected := unsafe.Sizeof(uintptr(0)) + if size := NewProgram(nil).PointerSize(); size != int(expected) { + t.Fatal("bad PointerSize:", size) + } +} + func TestSetBlock(t *testing.T) { defer func() { if r := recover(); r == nil { diff --git a/ssa/ssatest/ssautil.go b/ssa/ssatest/ssautil.go new file mode 100644 index 00000000..bbb8ae9a --- /dev/null +++ b/ssa/ssatest/ssautil.go @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2024 The GoPlus Authors (goplus.org). All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package ssatest + +import ( + "go/token" + "go/types" + "testing" + + "github.com/goplus/gogen/packages" + "github.com/goplus/llgo/ssa" +) + +func NewProgram(t *testing.T, target *ssa.Target) ssa.Program { + fset := token.NewFileSet() + imp := packages.NewImporter(fset) + return NewProgramEx(t, target, imp) +} + +func NewProgramEx(t *testing.T, target *ssa.Target, imp types.Importer) ssa.Program { + prog := ssa.NewProgram(target) + prog.SetRuntime(func() *types.Package { + rt, err := imp.Import(ssa.PkgRuntime) + if err != nil { + t.Fatal("load runtime failed:", err) + } + return rt + }) + prog.SetPython(func() *types.Package { + rt, err := imp.Import(ssa.PkgPython) + if err != nil { + t.Fatal("load python failed:", err) + } + return rt + }) + return prog +} + +func Assert(t *testing.T, p ssa.Package, expected string) { + t.Helper() + if v := p.String(); v != expected { + t.Fatalf("\n==> got:\n%s\n==> expected:\n%s\n", v, expected) + } +} diff --git a/ssa/type.go b/ssa/type.go index 17f5bd07..b7307c39 100644 --- a/ssa/type.go +++ b/ssa/type.go @@ -99,6 +99,10 @@ func (p Program) SizeOf(typ Type, n ...int64) uint64 { return size } +func (p Program) PointerSize() int { + return p.td.PointerSize() +} + func (p Program) Slice(typ Type) Type { return p.rawType(types.NewSlice(typ.raw.Type)) }