diff --git a/cl/_testrt/qsortfn/out.ll b/cl/_testrt/qsortfn/out.ll index 50d3b69e8..8f862d90d 100644 --- a/cl/_testrt/qsortfn/out.ll +++ b/cl/_testrt/qsortfn/out.ll @@ -263,31 +263,25 @@ _llgo_0: store i64 23, ptr %4, align 4 store i64 2, ptr %5, align 4 store i64 7, ptr %6, align 4 - %7 = alloca { ptr, ptr }, align 8 - %8 = getelementptr inbounds { ptr, ptr }, ptr %7, i32 0, i32 0 - store ptr @"__llgo_stub.main.sort3a$1", ptr %8, align 8 - %9 = getelementptr inbounds { ptr, ptr }, ptr %7, i32 0, i32 1 - store ptr null, ptr %9, align 8 - %10 = load { ptr, ptr }, ptr %7, align 8 - %11 = getelementptr inbounds i64, ptr %1, i64 0 - call void @qsort(ptr %11, i64 5, i64 8, { ptr, ptr } %10) - %12 = load [5 x i64], ptr %1, align 4 + %7 = getelementptr inbounds i64, ptr %1, i64 0 + call void @qsort(ptr %7, i64 5, i64 8, ptr @"main.sort3a$1") + %8 = load [5 x i64], ptr %1, align 4 br label %_llgo_1 _llgo_1: ; preds = %_llgo_2, %_llgo_0 - %13 = phi i64 [ -1, %_llgo_0 ], [ %14, %_llgo_2 ] - %14 = add i64 %13, 1 - %15 = icmp slt i64 %14, 5 - br i1 %15, label %_llgo_2, label %_llgo_3 + %9 = phi i64 [ -1, %_llgo_0 ], [ %10, %_llgo_2 ] + %10 = add i64 %9, 1 + %11 = icmp slt i64 %10, 5 + br i1 %11, label %_llgo_2, label %_llgo_3 _llgo_2: ; preds = %_llgo_1 - %16 = icmp slt i64 %14, 0 - %17 = icmp sge i64 %14, 5 - %18 = or i1 %17, %16 - call void @"github.com/goplus/llgo/internal/runtime.AssertIndexRange"(i1 %18) - %19 = getelementptr inbounds i64, ptr %1, i64 %14 - %20 = load i64, ptr %19, align 4 - %21 = call i32 (ptr, ...) @printf(ptr @9, i64 %20) + %12 = icmp slt i64 %10, 0 + %13 = icmp sge i64 %10, 5 + %14 = or i1 %13, %12 + call void @"github.com/goplus/llgo/internal/runtime.AssertIndexRange"(i1 %14) + %15 = getelementptr inbounds i64, ptr %1, i64 %10 + %16 = load i64, ptr %15, align 4 + %17 = call i32 (ptr, ...) @printf(ptr @9, i64 %16) br label %_llgo_1 _llgo_3: ; preds = %_llgo_1 @@ -318,30 +312,24 @@ _llgo_0: store i64 2, ptr %5, align 4 store i64 7, ptr %6, align 4 %7 = getelementptr inbounds i64, ptr %1, i64 0 - %8 = alloca { ptr, ptr }, align 8 - %9 = getelementptr inbounds { ptr, ptr }, ptr %8, i32 0, i32 0 - store ptr @"__llgo_stub.main.sort3b$1", ptr %9, align 8 - %10 = getelementptr inbounds { ptr, ptr }, ptr %8, i32 0, i32 1 - store ptr null, ptr %10, align 8 - %11 = load { ptr, ptr }, ptr %8, align 8 - call void @qsort(ptr %7, i64 5, i64 8, { ptr, ptr } %11) - %12 = load [5 x i64], ptr %1, align 4 + call void @qsort(ptr %7, i64 5, i64 8, ptr @"main.sort3b$1") + %8 = load [5 x i64], ptr %1, align 4 br label %_llgo_1 _llgo_1: ; preds = %_llgo_2, %_llgo_0 - %13 = phi i64 [ -1, %_llgo_0 ], [ %14, %_llgo_2 ] - %14 = add i64 %13, 1 - %15 = icmp slt i64 %14, 5 - br i1 %15, label %_llgo_2, label %_llgo_3 + %9 = phi i64 [ -1, %_llgo_0 ], [ %10, %_llgo_2 ] + %10 = add i64 %9, 1 + %11 = icmp slt i64 %10, 5 + br i1 %11, label %_llgo_2, label %_llgo_3 _llgo_2: ; preds = %_llgo_1 - %16 = icmp slt i64 %14, 0 - %17 = icmp sge i64 %14, 5 - %18 = or i1 %17, %16 - call void @"github.com/goplus/llgo/internal/runtime.AssertIndexRange"(i1 %18) - %19 = getelementptr inbounds i64, ptr %1, i64 %14 - %20 = load i64, ptr %19, align 4 - %21 = call i32 (ptr, ...) @printf(ptr @11, i64 %20) + %12 = icmp slt i64 %10, 0 + %13 = icmp sge i64 %10, 5 + %14 = or i1 %13, %12 + call void @"github.com/goplus/llgo/internal/runtime.AssertIndexRange"(i1 %14) + %15 = getelementptr inbounds i64, ptr %1, i64 %10 + %16 = load i64, ptr %15, align 4 + %17 = call i32 (ptr, ...) @printf(ptr @11, i64 %16) br label %_llgo_1 _llgo_3: ; preds = %_llgo_1 @@ -371,31 +359,25 @@ _llgo_0: store i64 23, ptr %4, align 4 store i64 2, ptr %5, align 4 store i64 7, ptr %6, align 4 - %7 = alloca { ptr, ptr }, align 8 - %8 = getelementptr inbounds { ptr, ptr }, ptr %7, i32 0, i32 0 - store ptr @"__llgo_stub.main.sort4a$1", ptr %8, align 8 - %9 = getelementptr inbounds { ptr, ptr }, ptr %7, i32 0, i32 1 - store ptr null, ptr %9, align 8 - %10 = load { ptr, ptr }, ptr %7, align 8 - %11 = getelementptr inbounds i64, ptr %1, i64 0 - call void @qsort(ptr %11, i64 5, i64 8, { ptr, ptr } %10) - %12 = load [5 x i64], ptr %1, align 4 + %7 = getelementptr inbounds i64, ptr %1, i64 0 + call void @qsort(ptr %7, i64 5, i64 8, ptr @"main.sort4a$1") + %8 = load [5 x i64], ptr %1, align 4 br label %_llgo_1 _llgo_1: ; preds = %_llgo_2, %_llgo_0 - %13 = phi i64 [ -1, %_llgo_0 ], [ %14, %_llgo_2 ] - %14 = add i64 %13, 1 - %15 = icmp slt i64 %14, 5 - br i1 %15, label %_llgo_2, label %_llgo_3 + %9 = phi i64 [ -1, %_llgo_0 ], [ %10, %_llgo_2 ] + %10 = add i64 %9, 1 + %11 = icmp slt i64 %10, 5 + br i1 %11, label %_llgo_2, label %_llgo_3 _llgo_2: ; preds = %_llgo_1 - %16 = icmp slt i64 %14, 0 - %17 = icmp sge i64 %14, 5 - %18 = or i1 %17, %16 - call void @"github.com/goplus/llgo/internal/runtime.AssertIndexRange"(i1 %18) - %19 = getelementptr inbounds i64, ptr %1, i64 %14 - %20 = load i64, ptr %19, align 4 - %21 = call i32 (ptr, ...) @printf(ptr @13, i64 %20) + %12 = icmp slt i64 %10, 0 + %13 = icmp sge i64 %10, 5 + %14 = or i1 %13, %12 + call void @"github.com/goplus/llgo/internal/runtime.AssertIndexRange"(i1 %14) + %15 = getelementptr inbounds i64, ptr %1, i64 %10 + %16 = load i64, ptr %15, align 4 + %17 = call i32 (ptr, ...) @printf(ptr @13, i64 %16) br label %_llgo_1 _llgo_3: ; preds = %_llgo_1 @@ -473,31 +455,25 @@ _llgo_0: store i64 23, ptr %4, align 4 store i64 2, ptr %5, align 4 store i64 7, ptr %6, align 4 - %7 = alloca { ptr, ptr }, align 8 - %8 = getelementptr inbounds { ptr, ptr }, ptr %7, i32 0, i32 0 - store ptr @"__llgo_stub.main.sort5a$1", ptr %8, align 8 - %9 = getelementptr inbounds { ptr, ptr }, ptr %7, i32 0, i32 1 - store ptr null, ptr %9, align 8 - %10 = load { ptr, ptr }, ptr %7, align 8 - %11 = getelementptr inbounds i64, ptr %1, i64 0 - call void @qsort(ptr %11, i64 5, i64 8, { ptr, ptr } %10) - %12 = load [5 x i64], ptr %1, align 4 + %7 = getelementptr inbounds i64, ptr %1, i64 0 + call void @qsort(ptr %7, i64 5, i64 8, ptr @"main.sort5a$1") + %8 = load [5 x i64], ptr %1, align 4 br label %_llgo_1 _llgo_1: ; preds = %_llgo_2, %_llgo_0 - %13 = phi i64 [ -1, %_llgo_0 ], [ %14, %_llgo_2 ] - %14 = add i64 %13, 1 - %15 = icmp slt i64 %14, 5 - br i1 %15, label %_llgo_2, label %_llgo_3 + %9 = phi i64 [ -1, %_llgo_0 ], [ %10, %_llgo_2 ] + %10 = add i64 %9, 1 + %11 = icmp slt i64 %10, 5 + br i1 %11, label %_llgo_2, label %_llgo_3 _llgo_2: ; preds = %_llgo_1 - %16 = icmp slt i64 %14, 0 - %17 = icmp sge i64 %14, 5 - %18 = or i1 %17, %16 - call void @"github.com/goplus/llgo/internal/runtime.AssertIndexRange"(i1 %18) - %19 = getelementptr inbounds i64, ptr %1, i64 %14 - %20 = load i64, ptr %19, align 4 - %21 = call i32 (ptr, ...) @printf(ptr @17, i64 %20) + %12 = icmp slt i64 %10, 0 + %13 = icmp sge i64 %10, 5 + %14 = or i1 %13, %12 + call void @"github.com/goplus/llgo/internal/runtime.AssertIndexRange"(i1 %14) + %15 = getelementptr inbounds i64, ptr %1, i64 %10 + %16 = load i64, ptr %15, align 4 + %17 = call i32 (ptr, ...) @printf(ptr @17, i64 %16) br label %_llgo_1 _llgo_3: ; preds = %_llgo_1 @@ -570,27 +546,3 @@ declare ptr @"github.com/goplus/llgo/internal/runtime.AllocZ"(i64) declare void @qsort(ptr, i64, i64, ptr) declare void @"github.com/goplus/llgo/internal/runtime.AssertIndexRange"(i1) - -define linkonce i32 @"__llgo_stub.main.sort3a$1"(ptr %0, ptr %1, ptr %2) { -_llgo_0: - %3 = tail call i32 @"main.sort3a$1"(ptr %1, ptr %2) - ret i32 %3 -} - -define linkonce i32 @"__llgo_stub.main.sort3b$1"(ptr %0, ptr %1, ptr %2) { -_llgo_0: - %3 = tail call i32 @"main.sort3b$1"(ptr %1, ptr %2) - ret i32 %3 -} - -define linkonce i32 @"__llgo_stub.main.sort4a$1"(ptr %0, ptr %1, ptr %2) { -_llgo_0: - %3 = tail call i32 @"main.sort4a$1"(ptr %1, ptr %2) - ret i32 %3 -} - -define linkonce i32 @"__llgo_stub.main.sort5a$1"(ptr %0, ptr %1, ptr %2) { -_llgo_0: - %3 = tail call i32 @"main.sort5a$1"(ptr %1, ptr %2) - ret i32 %3 -} diff --git a/cl/_testrt/unsafe/in.go b/cl/_testrt/unsafe/in.go new file mode 100644 index 000000000..fee5d5c38 --- /dev/null +++ b/cl/_testrt/unsafe/in.go @@ -0,0 +1,30 @@ +package main + +import ( + "unsafe" +) + +//llgo:type C +type T func() + +type M struct { + v int + fn T +} + +type N struct { + v int + fn func() +} + +func main() { + if unsafe.Sizeof(*(*T)(nil)) != unsafe.Sizeof(0) { + panic("error") + } + if unsafe.Sizeof(*(*M)(nil)) != unsafe.Sizeof([2]int{}) { + panic("error") + } + if unsafe.Sizeof(*(*N)(nil)) != unsafe.Sizeof([3]int{}) { + panic("error") + } +} diff --git a/cl/_testrt/unsafe/out.ll b/cl/_testrt/unsafe/out.ll new file mode 100644 index 000000000..f0be430d0 --- /dev/null +++ b/cl/_testrt/unsafe/out.ll @@ -0,0 +1,123 @@ +; ModuleID = 'main' +source_filename = "main" + +%"github.com/goplus/llgo/internal/runtime.String" = type { ptr, i64 } +%"github.com/goplus/llgo/internal/runtime.eface" = type { ptr, ptr } + +@"main.init$guard" = global i1 false, align 1 +@__llgo_argc = global i32 0, align 4 +@__llgo_argv = global ptr null, align 8 +@0 = private unnamed_addr constant [5 x i8] c"error", align 1 +@_llgo_string = linkonce global ptr null, align 8 + +define void @main.init() { +_llgo_0: + %0 = load i1, ptr @"main.init$guard", align 1 + br i1 %0, label %_llgo_2, label %_llgo_1 + +_llgo_1: ; preds = %_llgo_0 + store i1 true, ptr @"main.init$guard", align 1 + call void @"main.init$after"() + br label %_llgo_2 + +_llgo_2: ; preds = %_llgo_1, %_llgo_0 + ret void +} + +define i32 @main(i32 %0, ptr %1) { +_llgo_0: + store i32 %0, ptr @__llgo_argc, align 4 + store ptr %1, ptr @__llgo_argv, align 8 + call void @"github.com/goplus/llgo/internal/runtime.init"() + call void @main.init() + br i1 false, label %_llgo_1, label %_llgo_2 + +_llgo_1: ; preds = %_llgo_0 + %2 = alloca %"github.com/goplus/llgo/internal/runtime.String", align 8 + %3 = getelementptr inbounds %"github.com/goplus/llgo/internal/runtime.String", ptr %2, i32 0, i32 0 + store ptr @0, ptr %3, align 8 + %4 = getelementptr inbounds %"github.com/goplus/llgo/internal/runtime.String", ptr %2, i32 0, i32 1 + store i64 5, ptr %4, align 4 + %5 = load %"github.com/goplus/llgo/internal/runtime.String", ptr %2, align 8 + %6 = load ptr, ptr @_llgo_string, align 8 + %7 = call ptr @"github.com/goplus/llgo/internal/runtime.AllocU"(i64 16) + store %"github.com/goplus/llgo/internal/runtime.String" %5, ptr %7, align 8 + %8 = alloca %"github.com/goplus/llgo/internal/runtime.eface", align 8 + %9 = getelementptr inbounds %"github.com/goplus/llgo/internal/runtime.eface", ptr %8, i32 0, i32 0 + store ptr %6, ptr %9, align 8 + %10 = getelementptr inbounds %"github.com/goplus/llgo/internal/runtime.eface", ptr %8, i32 0, i32 1 + store ptr %7, ptr %10, align 8 + %11 = load %"github.com/goplus/llgo/internal/runtime.eface", ptr %8, align 8 + call void @"github.com/goplus/llgo/internal/runtime.Panic"(%"github.com/goplus/llgo/internal/runtime.eface" %11) + unreachable + +_llgo_2: ; preds = %_llgo_0 + br i1 false, label %_llgo_3, label %_llgo_4 + +_llgo_3: ; preds = %_llgo_2 + %12 = alloca %"github.com/goplus/llgo/internal/runtime.String", align 8 + %13 = getelementptr inbounds %"github.com/goplus/llgo/internal/runtime.String", ptr %12, i32 0, i32 0 + store ptr @0, ptr %13, align 8 + %14 = getelementptr inbounds %"github.com/goplus/llgo/internal/runtime.String", ptr %12, i32 0, i32 1 + store i64 5, ptr %14, align 4 + %15 = load %"github.com/goplus/llgo/internal/runtime.String", ptr %12, align 8 + %16 = load ptr, ptr @_llgo_string, align 8 + %17 = call ptr @"github.com/goplus/llgo/internal/runtime.AllocU"(i64 16) + store %"github.com/goplus/llgo/internal/runtime.String" %15, ptr %17, align 8 + %18 = alloca %"github.com/goplus/llgo/internal/runtime.eface", align 8 + %19 = getelementptr inbounds %"github.com/goplus/llgo/internal/runtime.eface", ptr %18, i32 0, i32 0 + store ptr %16, ptr %19, align 8 + %20 = getelementptr inbounds %"github.com/goplus/llgo/internal/runtime.eface", ptr %18, i32 0, i32 1 + store ptr %17, ptr %20, align 8 + %21 = load %"github.com/goplus/llgo/internal/runtime.eface", ptr %18, align 8 + call void @"github.com/goplus/llgo/internal/runtime.Panic"(%"github.com/goplus/llgo/internal/runtime.eface" %21) + unreachable + +_llgo_4: ; preds = %_llgo_2 + br i1 false, label %_llgo_5, label %_llgo_6 + +_llgo_5: ; preds = %_llgo_4 + %22 = alloca %"github.com/goplus/llgo/internal/runtime.String", align 8 + %23 = getelementptr inbounds %"github.com/goplus/llgo/internal/runtime.String", ptr %22, i32 0, i32 0 + store ptr @0, ptr %23, align 8 + %24 = getelementptr inbounds %"github.com/goplus/llgo/internal/runtime.String", ptr %22, i32 0, i32 1 + store i64 5, ptr %24, align 4 + %25 = load %"github.com/goplus/llgo/internal/runtime.String", ptr %22, align 8 + %26 = load ptr, ptr @_llgo_string, align 8 + %27 = call ptr @"github.com/goplus/llgo/internal/runtime.AllocU"(i64 16) + store %"github.com/goplus/llgo/internal/runtime.String" %25, ptr %27, align 8 + %28 = alloca %"github.com/goplus/llgo/internal/runtime.eface", align 8 + %29 = getelementptr inbounds %"github.com/goplus/llgo/internal/runtime.eface", ptr %28, i32 0, i32 0 + store ptr %26, ptr %29, align 8 + %30 = getelementptr inbounds %"github.com/goplus/llgo/internal/runtime.eface", ptr %28, i32 0, i32 1 + store ptr %27, ptr %30, align 8 + %31 = load %"github.com/goplus/llgo/internal/runtime.eface", ptr %28, align 8 + call void @"github.com/goplus/llgo/internal/runtime.Panic"(%"github.com/goplus/llgo/internal/runtime.eface" %31) + unreachable + +_llgo_6: ; preds = %_llgo_4 + ret i32 0 +} + +declare void @"github.com/goplus/llgo/internal/runtime.init"() + +define void @"main.init$after"() { +_llgo_0: + %0 = load ptr, ptr @_llgo_string, align 8 + %1 = icmp eq ptr %0, null + br i1 %1, label %_llgo_1, label %_llgo_2 + +_llgo_1: ; preds = %_llgo_0 + %2 = call ptr @"github.com/goplus/llgo/internal/runtime.Basic"(i64 24) + store ptr %2, ptr @_llgo_string, align 8 + br label %_llgo_2 + +_llgo_2: ; preds = %_llgo_1, %_llgo_0 + ret void +} + +declare ptr @"github.com/goplus/llgo/internal/runtime.Basic"(i64) + +declare ptr @"github.com/goplus/llgo/internal/runtime.AllocU"(i64) + +declare void @"github.com/goplus/llgo/internal/runtime.Panic"(%"github.com/goplus/llgo/internal/runtime.eface") diff --git a/cl/import.go b/cl/import.go index f779de893..031b1b46f 100644 --- a/cl/import.go +++ b/cl/import.go @@ -196,8 +196,6 @@ func (p *context) initFiles(pkgPath string, files []*ast.File) { p.collectSkipNames(line) } } - case token.TYPE: - handleTypeDecl(p.prog, p.goTyps, decl) } } } @@ -568,9 +566,7 @@ func handleTypeDecl(prog llssa.Program, pkg *types.Package, decl *ast.GenDecl) { if len(decl.Specs) == 1 { if bg := typeBackground(decl.Doc); bg != "" { inPkgName := decl.Specs[0].(*ast.TypeSpec).Name.Name - if obj := pkg.Scope().Lookup(inPkgName); obj != nil { - prog.Type(obj.Type(), toBackground(bg)) - } + prog.SetTypeBackground(pkg.Path()+"."+inPkgName, toBackground(bg)) } } } diff --git a/internal/build/build.go b/internal/build/build.go index 047321085..5df0f4978 100644 --- a/internal/build/build.go +++ b/internal/build/build.go @@ -18,6 +18,7 @@ package build import ( "fmt" + "go/ast" "go/constant" "go/token" "go/types" @@ -136,6 +137,12 @@ func Do(args []string, conf *Config) { prog := llssa.NewProgram(nil) sizes := prog.TypeSizes dedup := packages.NewDeduper() + dedup.SetPreload(func(pkg *types.Package, files []*ast.File) { + if canSkipToBuild(pkg.Path()) { + return + } + cl.ParsePkgSyntax(prog, pkg, files) + }) if patterns == nil { patterns = []string{"."} @@ -256,7 +263,6 @@ func buildAllPkgs(ctx *context, initial []*packages.Package, verbose bool) (pkgs case cl.PkgDeclOnly: // skip packages that only contain declarations // and set no export file - cl.ParsePkgSyntax(ctx.prog, pkg.Types, pkg.Syntax) pkg.ExportFile = "" case cl.PkgLinkIR, cl.PkgLinkExtern, cl.PkgPyModule: if len(pkg.GoFiles) > 0 { diff --git a/internal/llgen/llgen.go b/internal/llgen/llgen.go index 840bc1326..9dfe75f59 100644 --- a/internal/llgen/llgen.go +++ b/internal/llgen/llgen.go @@ -17,17 +17,10 @@ package llgen import ( - "go/ast" - "go/parser" - "go/token" - "go/types" "os" - "github.com/goplus/gogen/packages" "github.com/goplus/llgo/cl" "github.com/goplus/llgo/internal/mod" - "golang.org/x/tools/go/ssa" - "golang.org/x/tools/go/ssa/ssautil" llssa "github.com/goplus/llgo/ssa" ) @@ -45,51 +38,11 @@ func PkgPath(dir string) string { } func Do(pkgPath, inFile, outFile string) { - ret := Gen(pkgPath, inFile, nil) + ret := genFrom(inFile, pkgPath) err := os.WriteFile(outFile, []byte(ret), 0644) check(err) } -func Gen(pkgPath, inFile string, src any) string { - fset := token.NewFileSet() - f, err := parser.ParseFile(fset, inFile, src, parser.ParseComments) - check(err) - - files := []*ast.File{f} - name := f.Name.Name - if pkgPath == "" { - pkgPath = name - } - pkg := types.NewPackage(pkgPath, name) - imp := packages.NewImporter(fset) - ssaPkg, _, err := ssautil.BuildPackage( - &types.Config{Importer: imp}, fset, pkg, files, ssa.SanityCheckFunctions|ssa.InstantiateGenerics) - check(err) - - if Verbose { - ssaPkg.WriteTo(os.Stderr) - } - - prog := llssa.NewProgram(nil) - prog.SetRuntime(func() *types.Package { - ret, _ := imp.Import(llssa.PkgRuntime) - return ret - }) - prog.SetPython(func() *types.Package { - ret, _ := imp.Import(llssa.PkgPython) - return ret - }) - - ret, err := cl.NewPackage(prog, ssaPkg, files) - check(err) - - if prog.NeedPyInit { // call PyInit if needed - ret.PyInit() - } - - return ret.String() -} - func check(err error) { if err != nil { panic(err) diff --git a/internal/llgen/llgenf.go b/internal/llgen/llgenf.go index 43209a2cf..f9cc49799 100644 --- a/internal/llgen/llgenf.go +++ b/internal/llgen/llgenf.go @@ -17,6 +17,7 @@ package llgen import ( + "go/ast" "go/types" "os" "os/exec" @@ -60,12 +61,32 @@ func initRtAndPy(prog llssa.Program, cfg *packages.Config) { } func GenFrom(fileOrPkg string) string { + return genFrom(fileOrPkg, "") +} + +func genFrom(fileOrPkg string, pkgPath string) string { prog := llssa.NewProgram(nil) cfg := &packages.Config{ Mode: loadSyntax | packages.NeedDeps, } - initial, err := packages.LoadEx(nil, prog.TypeSizes, cfg, fileOrPkg) + + dedup := packages.NewDeduper() + dedup.SetPkgPath(func(path, name string) string { + if path == "command-line-arguments" { + if pkgPath != "" { + path = pkgPath + } else { + path = name + } + } + return path + }) + dedup.SetPreload(func(pkg *types.Package, files []*ast.File) { + cl.ParsePkgSyntax(prog, pkg, files) + }) + + initial, err := packages.LoadEx(dedup, prog.TypeSizes, cfg, fileOrPkg) check(err) _, pkgs := ssautil.AllPackages(initial, ssa.SanityCheckFunctions|ssa.InstantiateGenerics) diff --git a/internal/packages/load.go b/internal/packages/load.go index 05aaf61b5..2ef993e7d 100644 --- a/internal/packages/load.go +++ b/internal/packages/load.go @@ -110,7 +110,9 @@ type Cached struct { } type aDeduper struct { - cache sync.Map + cache sync.Map + setpath func(path string, name string) string + preload func(pkg *types.Package, syntax []*ast.File) } type Deduper = *aDeduper @@ -119,6 +121,14 @@ func NewDeduper() Deduper { return &aDeduper{} } +func (p Deduper) SetPreload(fn func(pkg *types.Package, syntax []*ast.File)) { + p.preload = fn +} + +func (p Deduper) SetPkgPath(fn func(path, name string) string) { + p.setpath = fn +} + func (p Deduper) Check(pkgPath string) *Cached { if v, ok := p.cache.Load(pkgPath); ok { return v.(*Cached) @@ -186,6 +196,9 @@ func loadPackageEx(dedup Deduper, ld *loader, lpkg *loaderPackage) { }) } }() + if dedup.setpath != nil { + lpkg.PkgPath = dedup.setpath(lpkg.PkgPath, lpkg.Name) + } } // Call NewPackage directly with explicit name. @@ -369,6 +382,10 @@ func loadPackageEx(dedup Deduper, ld *loader, lpkg *loaderPackage) { panic("unreachable") }) + if dedup != nil && dedup.preload != nil { + dedup.preload(lpkg.Types, lpkg.Syntax) + } + // type-check tc := &types.Config{ Importer: importer, diff --git a/ssa/package.go b/ssa/package.go index c273fd7e1..382ef3658 100644 --- a/ssa/package.go +++ b/ssa/package.go @@ -236,6 +236,10 @@ func (p Program) SetRuntime(runtime any) { } } +func (p Program) SetTypeBackground(fullName string, bg Background) { + p.gocvt.typbg[fullName] = bg +} + func (p Program) runtime() *types.Package { if p.rt == nil { p.rt = p.rtget() diff --git a/ssa/type.go b/ssa/type.go index af48f47cc..5e2dcf88c 100644 --- a/ssa/type.go +++ b/ssa/type.go @@ -103,7 +103,7 @@ func (p *goProgram) Offsetsof(fields []*types.Var) (ret []int64) { ret = p.sizes.Offsetsof(fields) for i, f := range fields { ret[i] += extra - extra += extraSize(f.Type(), ptrSize) + extra += p.extraSize(f.Type(), ptrSize) } return } @@ -114,26 +114,34 @@ func (p *goProgram) Offsetsof(fields []*types.Var) (ret []int64) { func (p *goProgram) Sizeof(T types.Type) int64 { prog := Program(p) ptrSize := int64(prog.PointerSize()) - baseSize := prog.sizes.Sizeof(T) + extraSize(T, ptrSize) - if _, ok := T.Underlying().(*types.Struct); ok { + baseSize := prog.sizes.Sizeof(T) + p.extraSize(T, ptrSize) + switch T.Underlying().(type) { + case *types.Struct, *types.Array: return align(baseSize, prog.sizes.Alignof(T)) } return baseSize } -func extraSize(t types.Type, ptrSize int64) (ret int64) { - switch t := t.Underlying().(type) { +func (p *goProgram) extraSize(typ types.Type, ptrSize int64) (ret int64) { +retry: + switch t := typ.(type) { + case *types.Named: + if p.gocvt.typbg[t.String()] == InC { + return 0 + } + typ = t.Underlying() + goto retry case *types.Signature: return ptrSize case *types.Struct: n := t.NumFields() for i := 0; i < n; i++ { f := t.Field(i) - ret += extraSize(f.Type(), ptrSize) + ret += p.extraSize(f.Type(), ptrSize) } return case *types.Array: - return extraSize(t.Elem(), ptrSize) * t.Len() + return p.extraSize(t.Elem(), ptrSize) * t.Len() } return 0 } diff --git a/ssa/type_cvt.go b/ssa/type_cvt.go index 299a09701..03d0e07eb 100644 --- a/ssa/type_cvt.go +++ b/ssa/type_cvt.go @@ -26,12 +26,14 @@ import ( // ----------------------------------------------------------------------------- type goTypes struct { - typs map[unsafe.Pointer]unsafe.Pointer + typs map[unsafe.Pointer]unsafe.Pointer + typbg map[string]Background } func newGoTypes() goTypes { typs := make(map[unsafe.Pointer]unsafe.Pointer) - return goTypes{typs} + typbk := make(map[string]Background) + return goTypes{typs, typbk} } type Background int @@ -93,6 +95,9 @@ func (p goTypes) cvtType(typ types.Type) (raw types.Type, cvt bool) { case *types.Struct: return p.cvtStruct(t) case *types.Named: + if p.typbg[t.String()] == InC { + break + } return p.cvtNamed(t) case *types.Signature: return p.cvtClosure(t), true