diff --git a/README.md b/README.md index e6be8b1fb4..a8185aec21 100644 --- a/README.md +++ b/README.md @@ -377,7 +377,7 @@ brew link --overwrite llvm@19 lld@19 libffi echo "deb http://apt.llvm.org/$(lsb_release -cs)/ llvm-toolchain-$(lsb_release -cs)-19 main" | sudo tee /etc/apt/sources.list.d/llvm.list wget -O - https://apt.llvm.org/llvm-snapshot.gpg.key | sudo apt-key add - sudo apt-get update -sudo apt-get install -y llvm-19-dev clang-19 libclang-19-dev lld-19 libunwind-19-dev libc++-19-dev pkg-config libgc-dev libssl-dev zlib1g-dev libcjson-dev libsqlite3-dev libuv1-dev +sudo apt-get install -y llvm-19-dev clang-19 libclang-19-dev lld-19 libunwind-19-dev libc++-19-dev pkg-config libgc-dev libssl-dev zlib1g-dev libffi-dev libcjson-dev libsqlite3-dev libuv1-dev sudo apt-get install -y python3.12-dev # optional #curl https://raw.githubusercontent.com/xgo-dev/llgo/refs/heads/main/install.sh | bash ./install.sh diff --git a/chore/litgen/rewrite.go b/chore/litgen/rewrite.go index 209a1a3d7f..37585a9a9c 100644 --- a/chore/litgen/rewrite.go +++ b/chore/litgen/rewrite.go @@ -67,6 +67,7 @@ var ( globalRefRE = regexp.MustCompile(`@"([^"]+)"|@([A-Za-z0-9$._-]+)`) checkLineRE = regexp.MustCompile(`^\s*//\s*CHECK(?:-[A-Z]+)?:`) debugMetaRE = regexp.MustCompile(`, ![A-Za-z0-9_.-]+ ![0-9]+`) + closureEnvRE = regexp.MustCompile(`(\s)(?:nest|swiftself)(\s)`) numericNameRE = regexp.MustCompile(`^\d+$`) ) @@ -439,9 +440,37 @@ func generalizeIRLine(line, modulePath string) string { func scrubIRLine(line string) string { line = debugMetaRE.ReplaceAllString(line, "") + line = generalizeClosureEnvAttrs(line) return strings.TrimRight(line, " \t") } +func generalizeClosureEnvAttrs(line string) string { + var b strings.Builder + start := 0 + inQuote := false + for i := 0; i < len(line); i++ { + if line[i] != '"' || isEscapedQuote(line, i) { + continue + } + if !inQuote { + b.WriteString(closureEnvRE.ReplaceAllString(line[start:i], `${1}{{(nest|swiftself)}}${2}`)) + b.WriteByte('"') + start = i + 1 + inQuote = true + continue + } + b.WriteString(line[start : i+1]) + start = i + 1 + inQuote = false + } + if inQuote { + b.WriteString(line[start:]) + } else { + b.WriteString(closureEnvRE.ReplaceAllString(line[start:], `${1}{{(nest|swiftself)}}${2}`)) + } + return b.String() +} + func generalizeModulePath(line, modulePath string) string { if modulePath == "" { return line @@ -499,10 +528,9 @@ func collectRefs(line string) []string { } func shouldSkipFunctionCheck(symbol string) bool { - base := strings.TrimPrefix(symbol, "__llgo_stub.") - return strings.HasSuffix(base, "/runtime/internal/runtime.memequal32") || - strings.HasSuffix(base, "/runtime/internal/runtime.memequalptr") || - strings.HasSuffix(base, "/runtime/internal/runtime.strequal") + return strings.HasSuffix(symbol, "/runtime/internal/runtime.memequal32") || + strings.HasSuffix(symbol, "/runtime/internal/runtime.memequalptr") || + strings.HasSuffix(symbol, "/runtime/internal/runtime.strequal") } func trimPkgPrefix(symbol, pkgPath string) (string, bool) { diff --git a/chore/litgen/rewrite_test.go b/chore/litgen/rewrite_test.go index 17eccd1a1f..296a6091a2 100644 --- a/chore/litgen/rewrite_test.go +++ b/chore/litgen/rewrite_test.go @@ -5,7 +5,7 @@ import ( "testing" ) -func TestRewriteSource_InsertsMainClosureAndStub(t *testing.T) { +func TestRewriteSource_InsertsMainAndClosure(t *testing.T) { const src = `// LITTEST package main @@ -25,11 +25,6 @@ _llgo_0: ret void } -define linkonce void @"__llgo_stub.example.com/p.main$1"(ptr %0) { -_llgo_0: - tail call void @"example.com/p.main$1"() - ret void -} ` got, err := rewriteSource(src, "in.go", "example.com/p", "example.com", ir) if err != nil { @@ -51,12 +46,6 @@ _llgo_0: if strings.Index(got, closureCheck) > strings.Index(got, closureStmt) { t.Fatalf("closure checks should appear before func literal:\n%s", got) } - if !strings.Contains(got, `// CHECK-LABEL: define linkonce void @"__llgo_stub.{{.*}}/p.main$1"(ptr %0){{.*}} {`) { - t.Fatalf("stub checks missing:\n%s", got) - } - if strings.Index(got, `// CHECK-LABEL: define linkonce void @"__llgo_stub.{{.*}}/p.main$1"(ptr %0){{.*}} {`) < strings.Index(got, "func main()") { - t.Fatalf("stub checks should be appended after source:\n%s", got) - } } func TestRewriteSource_AddsInitAndCheckEmptyAndSkipsHelpers(t *testing.T) { @@ -233,6 +222,35 @@ func TestGeneralizeDefineLine_WildcardsAttrsBeforeBrace(t *testing.T) { } } +func TestGeneralizeClosureEnvAttrs(t *testing.T) { + tests := []struct { + line string + want string + }{ + { + `define void @"example.com/nest.swiftself"(ptr swiftself %env) {`, + `define void @"example.com/nest.swiftself"(ptr {{(nest|swiftself)}} %env) {`, + }, + { + ` call void %fn(ptr nest %env, ptr %arg)`, + ` call void %fn(ptr {{(nest|swiftself)}} %env, ptr %arg)`, + }, + { + `@0 = private constant [14 x i8] c"nest swiftself"`, + `@0 = private constant [14 x i8] c"nest swiftself"`, + }, + { + `@nest = global ptr @swiftself`, + `@nest = global ptr @swiftself`, + }, + } + for _, test := range tests { + if got := generalizeClosureEnvAttrs(test.line); got != test.want { + t.Errorf("generalizeClosureEnvAttrs(%q) = %q, want %q", test.line, got, test.want) + } + } +} + func TestGeneralizeModulePath_ReplacesOnlyQuotedSegments(t *testing.T) { line := ` %0 = getelementptr inbounds %"go/example.Type", ptr @"go/example.fn"` got := generalizeModulePath(line, "go") diff --git a/chore/pclnpost/main.go b/chore/pclnpost/main.go index 22a7efe2c5..0a1a70156c 100644 --- a/chore/pclnpost/main.go +++ b/chore/pclnpost/main.go @@ -38,6 +38,6 @@ func main() { fmt.Fprintln(os.Stderr, "pclnpost:", err) os.Exit(1) } - fmt.Printf("%s: entry=%d stub=%d kept=%d inlineCopies=%d noSymbol=%d -> ftab=%d buckets=%d\n", - st.Format, st.EntryRecords, st.StubRecords, st.Kept, st.InlineCopies, st.NoSymbol, st.FtabEntries, st.Buckets) + fmt.Printf("%s: entry=%d kept=%d inlineCopies=%d noSymbol=%d -> ftab=%d buckets=%d\n", + st.Format, st.EntryRecords, st.Kept, st.InlineCopies, st.NoSymbol, st.FtabEntries, st.Buckets) } diff --git a/cl/_testdata/foo/foo.go b/cl/_testdata/foo/foo.go index 5b61d65807..a76da65cd9 100644 --- a/cl/_testdata/foo/foo.go +++ b/cl/_testdata/foo/foo.go @@ -106,9 +106,3 @@ func (g *Game) Load() { // CHECK-NEXT: _llgo_2: ; preds = %_llgo_1, %_llgo_0 // CHECK-NEXT: ret void // CHECK-NEXT: } - -// CHECK-LABEL: define linkonce i1 @"__llgo_stub.{{.*}}/runtime/internal/runtime.memequal64"(ptr %0, ptr %1, ptr %2){{.*}} { -// CHECK-NEXT: _llgo_0: -// CHECK-NEXT: %3 = tail call i1 @"{{.*}}/runtime/internal/runtime.memequal64"(ptr %1, ptr %2) -// CHECK-NEXT: ret i1 %3 -// CHECK-NEXT: } diff --git a/cl/_testdata/llgointrinsics/in.go b/cl/_testdata/llgointrinsics/in.go index e4befe675b..75971309d1 100644 --- a/cl/_testdata/llgointrinsics/in.go +++ b/cl/_testdata/llgointrinsics/in.go @@ -58,7 +58,7 @@ func UseCTrampoline() uintptr { // CHECK-NEXT: %0 = call ptr @"{{.*}}.AllocZ"(i64 8) // CHECK-NEXT: %1 = call ptr @"{{.*}}.AllocU"(i64 8) // CHECK: ret i64 ptrtoint (ptr @"{{.*}}.UseClosure$1" to i64) -// CHECK-LABEL: define void @"{{.*}}.UseClosure$1"(ptr %0){{.*}} { +// CHECK-LABEL: define void @"{{.*}}.UseClosure$1"(ptr {{(nest|swiftself)}} %0){{.*}} { // CHECK-NEXT: _llgo_0: // CHECK: %4 = add i64 %3, 1 // CHECK: ret void diff --git a/cl/_testdata/print/in.go b/cl/_testdata/print/in.go index b934f989bc..4d2f80ace1 100644 --- a/cl/_testdata/print/in.go +++ b/cl/_testdata/print/in.go @@ -1389,45 +1389,3 @@ func prinxor(n int64) { func stringStructOf(sp *string) *stringStruct { return (*stringStruct)(unsafe.Pointer(sp)) } - -// CHECK-LABEL: define linkonce i1 @"__llgo_stub.{{.*}}/runtime/internal/runtime.f32equal"(ptr %0, ptr %1, ptr %2){{.*}} { -// CHECK-NEXT: _llgo_0: -// CHECK-NEXT: %3 = tail call i1 @"{{.*}}/runtime/internal/runtime.f32equal"(ptr %1, ptr %2) -// CHECK-NEXT: ret i1 %3 -// CHECK-NEXT: } - -// CHECK-LABEL: define linkonce i1 @"__llgo_stub.{{.*}}/runtime/internal/runtime.f64equal"(ptr %0, ptr %1, ptr %2){{.*}} { -// CHECK-NEXT: _llgo_0: -// CHECK-NEXT: %3 = tail call i1 @"{{.*}}/runtime/internal/runtime.f64equal"(ptr %1, ptr %2) -// CHECK-NEXT: ret i1 %3 -// CHECK-NEXT: } - -// CHECK-LABEL: define linkonce i1 @"__llgo_stub.{{.*}}/runtime/internal/runtime.memequal8"(ptr %0, ptr %1, ptr %2){{.*}} { -// CHECK-NEXT: _llgo_0: -// CHECK-NEXT: %3 = tail call i1 @"{{.*}}/runtime/internal/runtime.memequal8"(ptr %1, ptr %2) -// CHECK-NEXT: ret i1 %3 -// CHECK-NEXT: } - -// CHECK-LABEL: define linkonce i1 @"__llgo_stub.{{.*}}/runtime/internal/runtime.memequal16"(ptr %0, ptr %1, ptr %2){{.*}} { -// CHECK-NEXT: _llgo_0: -// CHECK-NEXT: %3 = tail call i1 @"{{.*}}/runtime/internal/runtime.memequal16"(ptr %1, ptr %2) -// CHECK-NEXT: ret i1 %3 -// CHECK-NEXT: } - -// CHECK-LABEL: define linkonce i1 @"__llgo_stub.{{.*}}/runtime/internal/runtime.memequal64"(ptr %0, ptr %1, ptr %2){{.*}} { -// CHECK-NEXT: _llgo_0: -// CHECK-NEXT: %3 = tail call i1 @"{{.*}}/runtime/internal/runtime.memequal64"(ptr %1, ptr %2) -// CHECK-NEXT: ret i1 %3 -// CHECK-NEXT: } - -// CHECK-LABEL: define linkonce i1 @"__llgo_stub.{{.*}}/runtime/internal/runtime.c128equal"(ptr %0, ptr %1, ptr %2){{.*}} { -// CHECK-NEXT: _llgo_0: -// CHECK-NEXT: %3 = tail call i1 @"{{.*}}/runtime/internal/runtime.c128equal"(ptr %1, ptr %2) -// CHECK-NEXT: ret i1 %3 -// CHECK-NEXT: } - -// CHECK-LABEL: define linkonce i1 @"__llgo_stub.{{.*}}/runtime/internal/runtime.c64equal"(ptr %0, ptr %1, ptr %2){{.*}} { -// CHECK-NEXT: _llgo_0: -// CHECK-NEXT: %3 = tail call i1 @"{{.*}}/runtime/internal/runtime.c64equal"(ptr %1, ptr %2) -// CHECK-NEXT: ret i1 %3 -// CHECK-NEXT: } diff --git a/cl/_testdata/print/out.ll b/cl/_testdata/print/out.ll deleted file mode 100644 index 0e5a51eccd..0000000000 --- a/cl/_testdata/print/out.ll +++ /dev/null @@ -1,1258 +0,0 @@ -; ModuleID = 'github.com/goplus/llgo/cl/_testdata/print' -source_filename = "github.com/goplus/llgo/cl/_testdata/print" - -%"github.com/goplus/llgo/runtime/abi.Type" = type { i64, i64, i32, i8, i8, i8, i8, { ptr, ptr }, ptr, %"github.com/goplus/llgo/runtime/internal/runtime.String", ptr } -%"github.com/goplus/llgo/runtime/internal/runtime.String" = type { ptr, i64 } -%"github.com/goplus/llgo/runtime/abi.PtrType" = type { %"github.com/goplus/llgo/runtime/abi.Type", ptr } -%"github.com/goplus/llgo/runtime/internal/runtime.Slice" = type { ptr, i64, i64 } -%"github.com/goplus/llgo/cl/_testdata/print.stringStruct" = type { ptr, i64 } -%"github.com/goplus/llgo/cl/_testdata/print.slice" = type { ptr, i64, i64 } -%"github.com/goplus/llgo/runtime/internal/runtime.eface" = type { ptr, ptr } - -@"github.com/goplus/llgo/cl/_testdata/print.init$guard" = global i1 false, align 1 -@"github.com/goplus/llgo/cl/_testdata/print.minhexdigits" = global i64 0, align 8 -@0 = private unnamed_addr constant [3 x i8] c"%c\00", align 1 -@1 = private unnamed_addr constant [4 x i8] c"llgo", align 1 -@_llgo_float32 = weak_odr constant %"github.com/goplus/llgo/runtime/abi.Type" { i64 4, i64 0, i32 62173712, i8 4, i8 4, i8 4, i8 13, { ptr, ptr } { ptr @"__llgo_stub.github.com/goplus/llgo/runtime/internal/runtime.f32equal", ptr null }, ptr null, %"github.com/goplus/llgo/runtime/internal/runtime.String" { ptr @2, i64 7 }, ptr @"*_llgo_float32" }, align 8 -@2 = private unnamed_addr constant [7 x i8] c"float32", align 1 -@"*_llgo_float32" = weak_odr constant %"github.com/goplus/llgo/runtime/abi.PtrType" { %"github.com/goplus/llgo/runtime/abi.Type" { i64 8, i64 8, i32 -1426958587, i8 10, i8 8, i8 8, i8 54, { ptr, ptr } { ptr @"__llgo_stub.github.com/goplus/llgo/runtime/internal/runtime.memequalptr", ptr null }, ptr null, %"github.com/goplus/llgo/runtime/internal/runtime.String" { ptr @2, i64 7 }, ptr null }, ptr @_llgo_float32 }, align 8 -@_llgo_float64 = weak_odr constant %"github.com/goplus/llgo/runtime/abi.Type" { i64 8, i64 0, i32 -1233032631, i8 4, i8 8, i8 8, i8 14, { ptr, ptr } { ptr @"__llgo_stub.github.com/goplus/llgo/runtime/internal/runtime.f64equal", ptr null }, ptr null, %"github.com/goplus/llgo/runtime/internal/runtime.String" { ptr @3, i64 7 }, ptr @"*_llgo_float64" }, align 8 -@3 = private unnamed_addr constant [7 x i8] c"float64", align 1 -@"*_llgo_float64" = weak_odr constant %"github.com/goplus/llgo/runtime/abi.PtrType" { %"github.com/goplus/llgo/runtime/abi.Type" { i64 8, i64 8, i32 1664509894, i8 10, i8 8, i8 8, i8 54, { ptr, ptr } { ptr @"__llgo_stub.github.com/goplus/llgo/runtime/internal/runtime.memequalptr", ptr null }, ptr null, %"github.com/goplus/llgo/runtime/internal/runtime.String" { ptr @3, i64 7 }, ptr null }, ptr @_llgo_float64 }, align 8 -@4 = private unnamed_addr constant [10 x i8] c"check bool", align 1 -@_llgo_string = weak_odr constant %"github.com/goplus/llgo/runtime/abi.Type" { i64 16, i64 8, i32 1749264893, i8 4, i8 8, i8 8, i8 24, { ptr, ptr } { ptr @"__llgo_stub.github.com/goplus/llgo/runtime/internal/runtime.strequal", ptr null }, ptr null, %"github.com/goplus/llgo/runtime/internal/runtime.String" { ptr @5, i64 6 }, ptr @"*_llgo_string" }, align 8 -@5 = private unnamed_addr constant [6 x i8] c"string", align 1 -@"*_llgo_string" = weak_odr constant %"github.com/goplus/llgo/runtime/abi.PtrType" { %"github.com/goplus/llgo/runtime/abi.Type" { i64 8, i64 8, i32 -1323879264, i8 10, i8 8, i8 8, i8 54, { ptr, ptr } { ptr @"__llgo_stub.github.com/goplus/llgo/runtime/internal/runtime.memequalptr", ptr null }, ptr null, %"github.com/goplus/llgo/runtime/internal/runtime.String" { ptr @5, i64 6 }, ptr null }, ptr @_llgo_string }, align 8 -@_llgo_bool = weak_odr constant %"github.com/goplus/llgo/runtime/abi.Type" { i64 1, i64 0, i32 554183389, i8 12, i8 1, i8 1, i8 1, { ptr, ptr } { ptr @"__llgo_stub.github.com/goplus/llgo/runtime/internal/runtime.memequal8", ptr null }, ptr null, %"github.com/goplus/llgo/runtime/internal/runtime.String" { ptr @6, i64 4 }, ptr @"*_llgo_bool" }, align 8 -@6 = private unnamed_addr constant [4 x i8] c"bool", align 1 -@"*_llgo_bool" = weak_odr constant %"github.com/goplus/llgo/runtime/abi.PtrType" { %"github.com/goplus/llgo/runtime/abi.Type" { i64 8, i64 8, i32 -1896950390, i8 10, i8 8, i8 8, i8 54, { ptr, ptr } { ptr @"__llgo_stub.github.com/goplus/llgo/runtime/internal/runtime.memequalptr", ptr null }, ptr null, %"github.com/goplus/llgo/runtime/internal/runtime.String" { ptr @6, i64 4 }, ptr null }, ptr @_llgo_bool }, align 8 -@7 = private unnamed_addr constant [8 x i8] c"check &^", align 1 -@_llgo_int32 = weak_odr constant %"github.com/goplus/llgo/runtime/abi.Type" { i64 4, i64 0, i32 1448558410, i8 12, i8 4, i8 4, i8 5, { ptr, ptr } { ptr @"__llgo_stub.github.com/goplus/llgo/runtime/internal/runtime.memequal32", ptr null }, ptr null, %"github.com/goplus/llgo/runtime/internal/runtime.String" { ptr @8, i64 5 }, ptr @"*_llgo_int32" }, align 8 -@8 = private unnamed_addr constant [5 x i8] c"int32", align 1 -@"*_llgo_int32" = weak_odr constant %"github.com/goplus/llgo/runtime/abi.PtrType" { %"github.com/goplus/llgo/runtime/abi.Type" { i64 8, i64 8, i32 -38689692, i8 10, i8 8, i8 8, i8 54, { ptr, ptr } { ptr @"__llgo_stub.github.com/goplus/llgo/runtime/internal/runtime.memequalptr", ptr null }, ptr null, %"github.com/goplus/llgo/runtime/internal/runtime.String" { ptr @8, i64 5 }, ptr null }, ptr @_llgo_int32 }, align 8 -@_llgo_int8 = weak_odr constant %"github.com/goplus/llgo/runtime/abi.Type" { i64 1, i64 0, i32 1444672578, i8 12, i8 1, i8 1, i8 3, { ptr, ptr } { ptr @"__llgo_stub.github.com/goplus/llgo/runtime/internal/runtime.memequal8", ptr null }, ptr null, %"github.com/goplus/llgo/runtime/internal/runtime.String" { ptr @9, i64 4 }, ptr @"*_llgo_int8" }, align 8 -@9 = private unnamed_addr constant [4 x i8] c"int8", align 1 -@"*_llgo_int8" = weak_odr constant %"github.com/goplus/llgo/runtime/abi.PtrType" { %"github.com/goplus/llgo/runtime/abi.Type" { i64 8, i64 8, i32 -1399554408, i8 10, i8 8, i8 8, i8 54, { ptr, ptr } { ptr @"__llgo_stub.github.com/goplus/llgo/runtime/internal/runtime.memequalptr", ptr null }, ptr null, %"github.com/goplus/llgo/runtime/internal/runtime.String" { ptr @9, i64 4 }, ptr null }, ptr @_llgo_int8 }, align 8 -@_llgo_int16 = weak_odr constant %"github.com/goplus/llgo/runtime/abi.Type" { i64 2, i64 0, i32 1041867489, i8 12, i8 2, i8 2, i8 4, { ptr, ptr } { ptr @"__llgo_stub.github.com/goplus/llgo/runtime/internal/runtime.memequal16", ptr null }, ptr null, %"github.com/goplus/llgo/runtime/internal/runtime.String" { ptr @10, i64 5 }, ptr @"*_llgo_int16" }, align 8 -@10 = private unnamed_addr constant [5 x i8] c"int16", align 1 -@"*_llgo_int16" = weak_odr constant %"github.com/goplus/llgo/runtime/abi.PtrType" { %"github.com/goplus/llgo/runtime/abi.Type" { i64 8, i64 8, i32 575772759, i8 10, i8 8, i8 8, i8 54, { ptr, ptr } { ptr @"__llgo_stub.github.com/goplus/llgo/runtime/internal/runtime.memequalptr", ptr null }, ptr null, %"github.com/goplus/llgo/runtime/internal/runtime.String" { ptr @10, i64 5 }, ptr null }, ptr @_llgo_int16 }, align 8 -@_llgo_int64 = weak_odr constant %"github.com/goplus/llgo/runtime/abi.Type" { i64 8, i64 0, i32 394795202, i8 12, i8 8, i8 8, i8 6, { ptr, ptr } { ptr @"__llgo_stub.github.com/goplus/llgo/runtime/internal/runtime.memequal64", ptr null }, ptr null, %"github.com/goplus/llgo/runtime/internal/runtime.String" { ptr @11, i64 5 }, ptr @"*_llgo_int64" }, align 8 -@11 = private unnamed_addr constant [5 x i8] c"int64", align 1 -@"*_llgo_int64" = weak_odr constant %"github.com/goplus/llgo/runtime/abi.PtrType" { %"github.com/goplus/llgo/runtime/abi.Type" { i64 8, i64 8, i32 -1901231210, i8 10, i8 8, i8 8, i8 54, { ptr, ptr } { ptr @"__llgo_stub.github.com/goplus/llgo/runtime/internal/runtime.memequalptr", ptr null }, ptr null, %"github.com/goplus/llgo/runtime/internal/runtime.String" { ptr @11, i64 5 }, ptr null }, ptr @_llgo_int64 }, align 8 -@_llgo_int = weak_odr constant %"github.com/goplus/llgo/runtime/abi.Type" { i64 8, i64 0, i32 -25294021, i8 12, i8 8, i8 8, i8 2, { ptr, ptr } { ptr @"__llgo_stub.github.com/goplus/llgo/runtime/internal/runtime.memequal64", ptr null }, ptr null, %"github.com/goplus/llgo/runtime/internal/runtime.String" { ptr @12, i64 3 }, ptr @"*_llgo_int" }, align 8 -@12 = private unnamed_addr constant [3 x i8] c"int", align 1 -@"*_llgo_int" = weak_odr constant %"github.com/goplus/llgo/runtime/abi.PtrType" { %"github.com/goplus/llgo/runtime/abi.Type" { i64 8, i64 8, i32 -939606833, i8 10, i8 8, i8 8, i8 54, { ptr, ptr } { ptr @"__llgo_stub.github.com/goplus/llgo/runtime/internal/runtime.memequalptr", ptr null }, ptr null, %"github.com/goplus/llgo/runtime/internal/runtime.String" { ptr @12, i64 3 }, ptr null }, ptr @_llgo_int }, align 8 -@_llgo_uint8 = weak_odr constant %"github.com/goplus/llgo/runtime/abi.Type" { i64 1, i64 0, i32 269156761, i8 12, i8 1, i8 1, i8 8, { ptr, ptr } { ptr @"__llgo_stub.github.com/goplus/llgo/runtime/internal/runtime.memequal8", ptr null }, ptr null, %"github.com/goplus/llgo/runtime/internal/runtime.String" { ptr @13, i64 5 }, ptr @"*_llgo_uint8" }, align 8 -@13 = private unnamed_addr constant [5 x i8] c"uint8", align 1 -@"*_llgo_uint8" = weak_odr constant %"github.com/goplus/llgo/runtime/abi.PtrType" { %"github.com/goplus/llgo/runtime/abi.Type" { i64 8, i64 8, i32 1277858201, i8 10, i8 8, i8 8, i8 54, { ptr, ptr } { ptr @"__llgo_stub.github.com/goplus/llgo/runtime/internal/runtime.memequalptr", ptr null }, ptr null, %"github.com/goplus/llgo/runtime/internal/runtime.String" { ptr @13, i64 5 }, ptr null }, ptr @_llgo_uint8 }, align 8 -@_llgo_uint16 = weak_odr constant %"github.com/goplus/llgo/runtime/abi.Type" { i64 2, i64 0, i32 -75471123, i8 12, i8 2, i8 2, i8 9, { ptr, ptr } { ptr @"__llgo_stub.github.com/goplus/llgo/runtime/internal/runtime.memequal16", ptr null }, ptr null, %"github.com/goplus/llgo/runtime/internal/runtime.String" { ptr @14, i64 6 }, ptr @"*_llgo_uint16" }, align 8 -@14 = private unnamed_addr constant [6 x i8] c"uint16", align 1 -@"*_llgo_uint16" = weak_odr constant %"github.com/goplus/llgo/runtime/abi.PtrType" { %"github.com/goplus/llgo/runtime/abi.Type" { i64 8, i64 8, i32 530818523, i8 10, i8 8, i8 8, i8 54, { ptr, ptr } { ptr @"__llgo_stub.github.com/goplus/llgo/runtime/internal/runtime.memequalptr", ptr null }, ptr null, %"github.com/goplus/llgo/runtime/internal/runtime.String" { ptr @14, i64 6 }, ptr null }, ptr @_llgo_uint16 }, align 8 -@_llgo_uint32 = weak_odr constant %"github.com/goplus/llgo/runtime/abi.Type" { i64 4, i64 0, i32 -625909322, i8 12, i8 4, i8 4, i8 10, { ptr, ptr } { ptr @"__llgo_stub.github.com/goplus/llgo/runtime/internal/runtime.memequal32", ptr null }, ptr null, %"github.com/goplus/llgo/runtime/internal/runtime.String" { ptr @15, i64 6 }, ptr @"*_llgo_uint32" }, align 8 -@15 = private unnamed_addr constant [6 x i8] c"uint32", align 1 -@"*_llgo_uint32" = weak_odr constant %"github.com/goplus/llgo/runtime/abi.PtrType" { %"github.com/goplus/llgo/runtime/abi.Type" { i64 8, i64 8, i32 1605480511, i8 10, i8 8, i8 8, i8 54, { ptr, ptr } { ptr @"__llgo_stub.github.com/goplus/llgo/runtime/internal/runtime.memequalptr", ptr null }, ptr null, %"github.com/goplus/llgo/runtime/internal/runtime.String" { ptr @15, i64 6 }, ptr null }, ptr @_llgo_uint32 }, align 8 -@_llgo_uint64 = weak_odr constant %"github.com/goplus/llgo/runtime/abi.Type" { i64 8, i64 0, i32 -1994022077, i8 12, i8 8, i8 8, i8 11, { ptr, ptr } { ptr @"__llgo_stub.github.com/goplus/llgo/runtime/internal/runtime.memequal64", ptr null }, ptr null, %"github.com/goplus/llgo/runtime/internal/runtime.String" { ptr @16, i64 6 }, ptr @"*_llgo_uint64" }, align 8 -@16 = private unnamed_addr constant [6 x i8] c"uint64", align 1 -@"*_llgo_uint64" = weak_odr constant %"github.com/goplus/llgo/runtime/abi.PtrType" { %"github.com/goplus/llgo/runtime/abi.Type" { i64 8, i64 8, i32 89591114, i8 10, i8 8, i8 8, i8 54, { ptr, ptr } { ptr @"__llgo_stub.github.com/goplus/llgo/runtime/internal/runtime.memequalptr", ptr null }, ptr null, %"github.com/goplus/llgo/runtime/internal/runtime.String" { ptr @16, i64 6 }, ptr null }, ptr @_llgo_uint64 }, align 8 -@_llgo_uintptr = weak_odr constant %"github.com/goplus/llgo/runtime/abi.Type" { i64 8, i64 0, i32 1268343028, i8 12, i8 8, i8 8, i8 12, { ptr, ptr } { ptr @"__llgo_stub.github.com/goplus/llgo/runtime/internal/runtime.memequal64", ptr null }, ptr null, %"github.com/goplus/llgo/runtime/internal/runtime.String" { ptr @17, i64 7 }, ptr @"*_llgo_uintptr" }, align 8 -@17 = private unnamed_addr constant [7 x i8] c"uintptr", align 1 -@"*_llgo_uintptr" = weak_odr constant %"github.com/goplus/llgo/runtime/abi.PtrType" { %"github.com/goplus/llgo/runtime/abi.Type" { i64 8, i64 8, i32 -1684891952, i8 10, i8 8, i8 8, i8 54, { ptr, ptr } { ptr @"__llgo_stub.github.com/goplus/llgo/runtime/internal/runtime.memequalptr", ptr null }, ptr null, %"github.com/goplus/llgo/runtime/internal/runtime.String" { ptr @17, i64 7 }, ptr null }, ptr @_llgo_uintptr }, align 8 -@_llgo_complex128 = weak_odr constant %"github.com/goplus/llgo/runtime/abi.Type" { i64 16, i64 0, i32 -185553283, i8 4, i8 8, i8 8, i8 16, { ptr, ptr } { ptr @"__llgo_stub.github.com/goplus/llgo/runtime/internal/runtime.c128equal", ptr null }, ptr null, %"github.com/goplus/llgo/runtime/internal/runtime.String" { ptr @18, i64 10 }, ptr @"*_llgo_complex128" }, align 8 -@18 = private unnamed_addr constant [10 x i8] c"complex128", align 1 -@"*_llgo_complex128" = weak_odr constant %"github.com/goplus/llgo/runtime/abi.PtrType" { %"github.com/goplus/llgo/runtime/abi.Type" { i64 8, i64 8, i32 -210097625, i8 10, i8 8, i8 8, i8 54, { ptr, ptr } { ptr @"__llgo_stub.github.com/goplus/llgo/runtime/internal/runtime.memequalptr", ptr null }, ptr null, %"github.com/goplus/llgo/runtime/internal/runtime.String" { ptr @18, i64 10 }, ptr null }, ptr @_llgo_complex128 }, align 8 -@_llgo_uint = weak_odr constant %"github.com/goplus/llgo/runtime/abi.Type" { i64 8, i64 0, i32 172771804, i8 12, i8 8, i8 8, i8 7, { ptr, ptr } { ptr @"__llgo_stub.github.com/goplus/llgo/runtime/internal/runtime.memequal64", ptr null }, ptr null, %"github.com/goplus/llgo/runtime/internal/runtime.String" { ptr @19, i64 4 }, ptr @"*_llgo_uint" }, align 8 -@19 = private unnamed_addr constant [4 x i8] c"uint", align 1 -@"*_llgo_uint" = weak_odr constant %"github.com/goplus/llgo/runtime/abi.PtrType" { %"github.com/goplus/llgo/runtime/abi.Type" { i64 8, i64 8, i32 -1001256076, i8 10, i8 8, i8 8, i8 54, { ptr, ptr } { ptr @"__llgo_stub.github.com/goplus/llgo/runtime/internal/runtime.memequalptr", ptr null }, ptr null, %"github.com/goplus/llgo/runtime/internal/runtime.String" { ptr @19, i64 4 }, ptr null }, ptr @_llgo_uint }, align 8 -@_llgo_complex64 = weak_odr constant %"github.com/goplus/llgo/runtime/abi.Type" { i64 8, i64 0, i32 -1545857875, i8 4, i8 4, i8 4, i8 15, { ptr, ptr } { ptr @"__llgo_stub.github.com/goplus/llgo/runtime/internal/runtime.c64equal", ptr null }, ptr null, %"github.com/goplus/llgo/runtime/internal/runtime.String" { ptr @20, i64 9 }, ptr @"*_llgo_complex64" }, align 8 -@20 = private unnamed_addr constant [9 x i8] c"complex64", align 1 -@"*_llgo_complex64" = weak_odr constant %"github.com/goplus/llgo/runtime/abi.PtrType" { %"github.com/goplus/llgo/runtime/abi.Type" { i64 8, i64 8, i32 -1953092460, i8 10, i8 8, i8 8, i8 54, { ptr, ptr } { ptr @"__llgo_stub.github.com/goplus/llgo/runtime/internal/runtime.memequalptr", ptr null }, ptr null, %"github.com/goplus/llgo/runtime/internal/runtime.String" { ptr @20, i64 9 }, ptr null }, ptr @_llgo_complex64 }, align 8 -@21 = private unnamed_addr constant [1 x i8] c"(", align 1 -@22 = private unnamed_addr constant [2 x i8] c"i)", align 1 -@23 = private unnamed_addr constant [4 x i8] c"true", align 1 -@24 = private unnamed_addr constant [5 x i8] c"false", align 1 -@25 = private unnamed_addr constant [3 x i8] c"NaN", align 1 -@26 = private unnamed_addr constant [4 x i8] c"+Inf", align 1 -@27 = private unnamed_addr constant [4 x i8] c"-Inf", align 1 -@28 = private unnamed_addr constant [16 x i8] c"0123456789abcdef", align 1 -@29 = private unnamed_addr constant [1 x i8] c"-", align 1 -@30 = private unnamed_addr constant [1 x i8] c" ", align 1 -@31 = private unnamed_addr constant [1 x i8] c"\0A", align 1 - -define %"github.com/goplus/llgo/runtime/internal/runtime.Slice" @"github.com/goplus/llgo/cl/_testdata/print.bytes"(%"github.com/goplus/llgo/runtime/internal/runtime.String" %0) { -_llgo_0: - %1 = call ptr @"github.com/goplus/llgo/runtime/internal/runtime.AllocZ"(i64 16) - store %"github.com/goplus/llgo/runtime/internal/runtime.String" %0, ptr %1, align 8 - %2 = call ptr @"github.com/goplus/llgo/runtime/internal/runtime.AllocZ"(i64 24) - %3 = call ptr @"github.com/goplus/llgo/cl/_testdata/print.stringStructOf"(ptr %1) - %4 = getelementptr inbounds %"github.com/goplus/llgo/cl/_testdata/print.stringStruct", ptr %3, i32 0, i32 0 - %5 = load ptr, ptr %4, align 8 - %6 = getelementptr inbounds %"github.com/goplus/llgo/cl/_testdata/print.slice", ptr %2, i32 0, i32 0 - store ptr %5, ptr %6, align 8 - %7 = getelementptr inbounds %"github.com/goplus/llgo/cl/_testdata/print.stringStruct", ptr %3, i32 0, i32 1 - %8 = load i64, ptr %7, align 4 - %9 = getelementptr inbounds %"github.com/goplus/llgo/cl/_testdata/print.slice", ptr %2, i32 0, i32 1 - store i64 %8, ptr %9, align 4 - %10 = getelementptr inbounds %"github.com/goplus/llgo/cl/_testdata/print.stringStruct", ptr %3, i32 0, i32 1 - %11 = load i64, ptr %10, align 4 - %12 = getelementptr inbounds %"github.com/goplus/llgo/cl/_testdata/print.slice", ptr %2, i32 0, i32 2 - store i64 %11, ptr %12, align 4 - %13 = load %"github.com/goplus/llgo/runtime/internal/runtime.Slice", ptr %2, align 8 - ret %"github.com/goplus/llgo/runtime/internal/runtime.Slice" %13 -} - -define void @"github.com/goplus/llgo/cl/_testdata/print.gwrite"(%"github.com/goplus/llgo/runtime/internal/runtime.Slice" %0) { -_llgo_0: - %1 = extractvalue %"github.com/goplus/llgo/runtime/internal/runtime.Slice" %0, 1 - %2 = icmp eq i64 %1, 0 - br i1 %2, label %_llgo_1, label %_llgo_2 - -_llgo_1: ; preds = %_llgo_0 - ret void - -_llgo_2: ; preds = %_llgo_0 - %3 = extractvalue %"github.com/goplus/llgo/runtime/internal/runtime.Slice" %0, 1 - br label %_llgo_3 - -_llgo_3: ; preds = %_llgo_4, %_llgo_2 - %4 = phi i64 [ -1, %_llgo_2 ], [ %5, %_llgo_4 ] - %5 = add i64 %4, 1 - %6 = icmp slt i64 %5, %3 - br i1 %6, label %_llgo_4, label %_llgo_5 - -_llgo_4: ; preds = %_llgo_3 - %7 = extractvalue %"github.com/goplus/llgo/runtime/internal/runtime.Slice" %0, 0 - %8 = extractvalue %"github.com/goplus/llgo/runtime/internal/runtime.Slice" %0, 1 - %9 = icmp slt i64 %5, 0 - %10 = icmp uge i64 %5, %8 - %11 = or i1 %10, %9 - call void @"github.com/goplus/llgo/runtime/internal/runtime.AssertIndexRange"(i1 %11) - %12 = getelementptr inbounds i8, ptr %7, i64 %5 - %13 = load i8, ptr %12, align 1 - %14 = call i32 (ptr, ...) @printf(ptr @0, i8 %13) - br label %_llgo_3 - -_llgo_5: ; preds = %_llgo_3 - ret void -} - -define void @"github.com/goplus/llgo/cl/_testdata/print.init"() { -_llgo_0: - %0 = load i1, ptr @"github.com/goplus/llgo/cl/_testdata/print.init$guard", align 1 - br i1 %0, label %_llgo_2, label %_llgo_1 - -_llgo_1: ; preds = %_llgo_0 - store i1 true, ptr @"github.com/goplus/llgo/cl/_testdata/print.init$guard", align 1 - store i64 0, ptr @"github.com/goplus/llgo/cl/_testdata/print.minhexdigits", align 4 - br label %_llgo_2 - -_llgo_2: ; preds = %_llgo_1, %_llgo_0 - ret void -} - -define void @"github.com/goplus/llgo/cl/_testdata/print.main"() { -_llgo_0: - call void @"github.com/goplus/llgo/cl/_testdata/print.printstring"(%"github.com/goplus/llgo/runtime/internal/runtime.String" { ptr @1, i64 4 }) - call void @"github.com/goplus/llgo/cl/_testdata/print.printnl"() - call void @"github.com/goplus/llgo/cl/_testdata/print.printuint"(i64 1024) - call void @"github.com/goplus/llgo/cl/_testdata/print.printnl"() - call void @"github.com/goplus/llgo/cl/_testdata/print.printhex"(i64 305441743) - call void @"github.com/goplus/llgo/cl/_testdata/print.printnl"() - call void @"github.com/goplus/llgo/cl/_testdata/print.prinxor"(i64 1) - call void @"github.com/goplus/llgo/cl/_testdata/print.printnl"() - call void @"github.com/goplus/llgo/cl/_testdata/print.prinsub"(i64 100) - call void @"github.com/goplus/llgo/cl/_testdata/print.printnl"() - call void @"github.com/goplus/llgo/cl/_testdata/print.prinusub"(i64 -1) - call void @"github.com/goplus/llgo/cl/_testdata/print.printnl"() - call void @"github.com/goplus/llgo/cl/_testdata/print.prinfsub"(double 1.001000e+02) - call void @"github.com/goplus/llgo/cl/_testdata/print.printnl"() - %0 = call ptr @"github.com/goplus/llgo/runtime/internal/runtime.AllocU"(i64 4) - store float 1.000000e+09, ptr %0, align 4 - %1 = insertvalue %"github.com/goplus/llgo/runtime/internal/runtime.eface" { ptr @_llgo_float32, ptr undef }, ptr %0, 1 - call void @"github.com/goplus/llgo/cl/_testdata/print.printany"(%"github.com/goplus/llgo/runtime/internal/runtime.eface" %1) - call void @"github.com/goplus/llgo/cl/_testdata/print.printnl"() - %2 = call ptr @"github.com/goplus/llgo/runtime/internal/runtime.AllocU"(i64 8) - store double 2.000000e+09, ptr %2, align 8 - %3 = insertvalue %"github.com/goplus/llgo/runtime/internal/runtime.eface" { ptr @_llgo_float64, ptr undef }, ptr %2, 1 - call void @"github.com/goplus/llgo/cl/_testdata/print.printany"(%"github.com/goplus/llgo/runtime/internal/runtime.eface" %3) - call void @"github.com/goplus/llgo/cl/_testdata/print.printnl"() - br i1 true, label %_llgo_3, label %_llgo_2 - -_llgo_1: ; preds = %_llgo_3 - %4 = call ptr @"github.com/goplus/llgo/runtime/internal/runtime.AllocZ"(i64 32) - %5 = getelementptr inbounds %"github.com/goplus/llgo/runtime/internal/runtime.eface", ptr %4, i64 0 - %6 = call ptr @"github.com/goplus/llgo/runtime/internal/runtime.AllocU"(i64 16) - store %"github.com/goplus/llgo/runtime/internal/runtime.String" { ptr @4, i64 10 }, ptr %6, align 8 - %7 = insertvalue %"github.com/goplus/llgo/runtime/internal/runtime.eface" { ptr @_llgo_string, ptr undef }, ptr %6, 1 - store %"github.com/goplus/llgo/runtime/internal/runtime.eface" %7, ptr %5, align 8 - %8 = getelementptr inbounds %"github.com/goplus/llgo/runtime/internal/runtime.eface", ptr %4, i64 1 - %9 = call ptr @"github.com/goplus/llgo/runtime/internal/runtime.AllocU"(i64 1) - store i1 true, ptr %9, align 1 - %10 = insertvalue %"github.com/goplus/llgo/runtime/internal/runtime.eface" { ptr @_llgo_bool, ptr undef }, ptr %9, 1 - store %"github.com/goplus/llgo/runtime/internal/runtime.eface" %10, ptr %8, align 8 - %11 = insertvalue %"github.com/goplus/llgo/runtime/internal/runtime.Slice" undef, ptr %4, 0 - %12 = insertvalue %"github.com/goplus/llgo/runtime/internal/runtime.Slice" %11, i64 2, 1 - %13 = insertvalue %"github.com/goplus/llgo/runtime/internal/runtime.Slice" %12, i64 2, 2 - call void @"github.com/goplus/llgo/cl/_testdata/print.println"(%"github.com/goplus/llgo/runtime/internal/runtime.Slice" %13) - br label %_llgo_2 - -_llgo_2: ; preds = %_llgo_1, %_llgo_3, %_llgo_0 - %14 = call ptr @"github.com/goplus/llgo/runtime/internal/runtime.AllocZ"(i64 48) - %15 = getelementptr inbounds %"github.com/goplus/llgo/runtime/internal/runtime.eface", ptr %14, i64 0 - %16 = call ptr @"github.com/goplus/llgo/runtime/internal/runtime.AllocU"(i64 16) - store %"github.com/goplus/llgo/runtime/internal/runtime.String" { ptr @7, i64 8 }, ptr %16, align 8 - %17 = insertvalue %"github.com/goplus/llgo/runtime/internal/runtime.eface" { ptr @_llgo_string, ptr undef }, ptr %16, 1 - store %"github.com/goplus/llgo/runtime/internal/runtime.eface" %17, ptr %15, align 8 - %18 = getelementptr inbounds %"github.com/goplus/llgo/runtime/internal/runtime.eface", ptr %14, i64 1 - %19 = call ptr @"github.com/goplus/llgo/runtime/internal/runtime.AllocU"(i64 1) - store i1 true, ptr %19, align 1 - %20 = insertvalue %"github.com/goplus/llgo/runtime/internal/runtime.eface" { ptr @_llgo_bool, ptr undef }, ptr %19, 1 - store %"github.com/goplus/llgo/runtime/internal/runtime.eface" %20, ptr %18, align 8 - %21 = getelementptr inbounds %"github.com/goplus/llgo/runtime/internal/runtime.eface", ptr %14, i64 2 - %22 = call ptr @"github.com/goplus/llgo/runtime/internal/runtime.AllocU"(i64 1) - store i1 true, ptr %22, align 1 - %23 = insertvalue %"github.com/goplus/llgo/runtime/internal/runtime.eface" { ptr @_llgo_bool, ptr undef }, ptr %22, 1 - store %"github.com/goplus/llgo/runtime/internal/runtime.eface" %23, ptr %21, align 8 - %24 = insertvalue %"github.com/goplus/llgo/runtime/internal/runtime.Slice" undef, ptr %14, 0 - %25 = insertvalue %"github.com/goplus/llgo/runtime/internal/runtime.Slice" %24, i64 3, 1 - %26 = insertvalue %"github.com/goplus/llgo/runtime/internal/runtime.Slice" %25, i64 3, 2 - call void @"github.com/goplus/llgo/cl/_testdata/print.println"(%"github.com/goplus/llgo/runtime/internal/runtime.Slice" %26) - %27 = call ptr @"github.com/goplus/llgo/runtime/internal/runtime.AllocZ"(i64 256) - %28 = getelementptr inbounds %"github.com/goplus/llgo/runtime/internal/runtime.eface", ptr %27, i64 0 - %29 = call ptr @"github.com/goplus/llgo/runtime/internal/runtime.AllocU"(i64 1) - store i1 true, ptr %29, align 1 - %30 = insertvalue %"github.com/goplus/llgo/runtime/internal/runtime.eface" { ptr @_llgo_bool, ptr undef }, ptr %29, 1 - store %"github.com/goplus/llgo/runtime/internal/runtime.eface" %30, ptr %28, align 8 - %31 = getelementptr inbounds %"github.com/goplus/llgo/runtime/internal/runtime.eface", ptr %27, i64 1 - %32 = call ptr @"github.com/goplus/llgo/runtime/internal/runtime.AllocU"(i64 1) - store i1 false, ptr %32, align 1 - %33 = insertvalue %"github.com/goplus/llgo/runtime/internal/runtime.eface" { ptr @_llgo_bool, ptr undef }, ptr %32, 1 - store %"github.com/goplus/llgo/runtime/internal/runtime.eface" %33, ptr %31, align 8 - %34 = getelementptr inbounds %"github.com/goplus/llgo/runtime/internal/runtime.eface", ptr %27, i64 2 - %35 = call ptr @"github.com/goplus/llgo/runtime/internal/runtime.AllocU"(i64 4) - store i32 97, ptr %35, align 4 - %36 = insertvalue %"github.com/goplus/llgo/runtime/internal/runtime.eface" { ptr @_llgo_int32, ptr undef }, ptr %35, 1 - store %"github.com/goplus/llgo/runtime/internal/runtime.eface" %36, ptr %34, align 8 - %37 = getelementptr inbounds %"github.com/goplus/llgo/runtime/internal/runtime.eface", ptr %27, i64 3 - %38 = call ptr @"github.com/goplus/llgo/runtime/internal/runtime.AllocU"(i64 4) - store i32 65, ptr %38, align 4 - %39 = insertvalue %"github.com/goplus/llgo/runtime/internal/runtime.eface" { ptr @_llgo_int32, ptr undef }, ptr %38, 1 - store %"github.com/goplus/llgo/runtime/internal/runtime.eface" %39, ptr %37, align 8 - %40 = getelementptr inbounds %"github.com/goplus/llgo/runtime/internal/runtime.eface", ptr %27, i64 4 - %41 = call ptr @"github.com/goplus/llgo/runtime/internal/runtime.AllocU"(i64 4) - store i32 20013, ptr %41, align 4 - %42 = insertvalue %"github.com/goplus/llgo/runtime/internal/runtime.eface" { ptr @_llgo_int32, ptr undef }, ptr %41, 1 - store %"github.com/goplus/llgo/runtime/internal/runtime.eface" %42, ptr %40, align 8 - %43 = getelementptr inbounds %"github.com/goplus/llgo/runtime/internal/runtime.eface", ptr %27, i64 5 - %44 = call ptr @"github.com/goplus/llgo/runtime/internal/runtime.AllocU"(i64 1) - store i8 1, ptr %44, align 1 - %45 = insertvalue %"github.com/goplus/llgo/runtime/internal/runtime.eface" { ptr @_llgo_int8, ptr undef }, ptr %44, 1 - store %"github.com/goplus/llgo/runtime/internal/runtime.eface" %45, ptr %43, align 8 - %46 = getelementptr inbounds %"github.com/goplus/llgo/runtime/internal/runtime.eface", ptr %27, i64 6 - %47 = call ptr @"github.com/goplus/llgo/runtime/internal/runtime.AllocU"(i64 2) - store i16 2, ptr %47, align 2 - %48 = insertvalue %"github.com/goplus/llgo/runtime/internal/runtime.eface" { ptr @_llgo_int16, ptr undef }, ptr %47, 1 - store %"github.com/goplus/llgo/runtime/internal/runtime.eface" %48, ptr %46, align 8 - %49 = getelementptr inbounds %"github.com/goplus/llgo/runtime/internal/runtime.eface", ptr %27, i64 7 - %50 = call ptr @"github.com/goplus/llgo/runtime/internal/runtime.AllocU"(i64 4) - store i32 3, ptr %50, align 4 - %51 = insertvalue %"github.com/goplus/llgo/runtime/internal/runtime.eface" { ptr @_llgo_int32, ptr undef }, ptr %50, 1 - store %"github.com/goplus/llgo/runtime/internal/runtime.eface" %51, ptr %49, align 8 - %52 = getelementptr inbounds %"github.com/goplus/llgo/runtime/internal/runtime.eface", ptr %27, i64 8 - %53 = call ptr @"github.com/goplus/llgo/runtime/internal/runtime.AllocU"(i64 8) - store i64 4, ptr %53, align 4 - %54 = insertvalue %"github.com/goplus/llgo/runtime/internal/runtime.eface" { ptr @_llgo_int64, ptr undef }, ptr %53, 1 - store %"github.com/goplus/llgo/runtime/internal/runtime.eface" %54, ptr %52, align 8 - %55 = getelementptr inbounds %"github.com/goplus/llgo/runtime/internal/runtime.eface", ptr %27, i64 9 - %56 = call ptr @"github.com/goplus/llgo/runtime/internal/runtime.AllocU"(i64 8) - store i64 5, ptr %56, align 4 - %57 = insertvalue %"github.com/goplus/llgo/runtime/internal/runtime.eface" { ptr @_llgo_int, ptr undef }, ptr %56, 1 - store %"github.com/goplus/llgo/runtime/internal/runtime.eface" %57, ptr %55, align 8 - %58 = getelementptr inbounds %"github.com/goplus/llgo/runtime/internal/runtime.eface", ptr %27, i64 10 - %59 = call ptr @"github.com/goplus/llgo/runtime/internal/runtime.AllocU"(i64 1) - store i8 1, ptr %59, align 1 - %60 = insertvalue %"github.com/goplus/llgo/runtime/internal/runtime.eface" { ptr @_llgo_uint8, ptr undef }, ptr %59, 1 - store %"github.com/goplus/llgo/runtime/internal/runtime.eface" %60, ptr %58, align 8 - %61 = getelementptr inbounds %"github.com/goplus/llgo/runtime/internal/runtime.eface", ptr %27, i64 11 - %62 = call ptr @"github.com/goplus/llgo/runtime/internal/runtime.AllocU"(i64 2) - store i16 2, ptr %62, align 2 - %63 = insertvalue %"github.com/goplus/llgo/runtime/internal/runtime.eface" { ptr @_llgo_uint16, ptr undef }, ptr %62, 1 - store %"github.com/goplus/llgo/runtime/internal/runtime.eface" %63, ptr %61, align 8 - %64 = getelementptr inbounds %"github.com/goplus/llgo/runtime/internal/runtime.eface", ptr %27, i64 12 - %65 = call ptr @"github.com/goplus/llgo/runtime/internal/runtime.AllocU"(i64 4) - store i32 3, ptr %65, align 4 - %66 = insertvalue %"github.com/goplus/llgo/runtime/internal/runtime.eface" { ptr @_llgo_uint32, ptr undef }, ptr %65, 1 - store %"github.com/goplus/llgo/runtime/internal/runtime.eface" %66, ptr %64, align 8 - %67 = getelementptr inbounds %"github.com/goplus/llgo/runtime/internal/runtime.eface", ptr %27, i64 13 - %68 = call ptr @"github.com/goplus/llgo/runtime/internal/runtime.AllocU"(i64 8) - store i64 4, ptr %68, align 4 - %69 = insertvalue %"github.com/goplus/llgo/runtime/internal/runtime.eface" { ptr @_llgo_uint64, ptr undef }, ptr %68, 1 - store %"github.com/goplus/llgo/runtime/internal/runtime.eface" %69, ptr %67, align 8 - %70 = getelementptr inbounds %"github.com/goplus/llgo/runtime/internal/runtime.eface", ptr %27, i64 14 - %71 = call ptr @"github.com/goplus/llgo/runtime/internal/runtime.AllocU"(i64 8) - store i64 5, ptr %71, align 4 - %72 = insertvalue %"github.com/goplus/llgo/runtime/internal/runtime.eface" { ptr @_llgo_uintptr, ptr undef }, ptr %71, 1 - store %"github.com/goplus/llgo/runtime/internal/runtime.eface" %72, ptr %70, align 8 - %73 = getelementptr inbounds %"github.com/goplus/llgo/runtime/internal/runtime.eface", ptr %27, i64 15 - %74 = call ptr @"github.com/goplus/llgo/runtime/internal/runtime.AllocU"(i64 16) - store %"github.com/goplus/llgo/runtime/internal/runtime.String" { ptr @1, i64 4 }, ptr %74, align 8 - %75 = insertvalue %"github.com/goplus/llgo/runtime/internal/runtime.eface" { ptr @_llgo_string, ptr undef }, ptr %74, 1 - store %"github.com/goplus/llgo/runtime/internal/runtime.eface" %75, ptr %73, align 8 - %76 = insertvalue %"github.com/goplus/llgo/runtime/internal/runtime.Slice" undef, ptr %27, 0 - %77 = insertvalue %"github.com/goplus/llgo/runtime/internal/runtime.Slice" %76, i64 16, 1 - %78 = insertvalue %"github.com/goplus/llgo/runtime/internal/runtime.Slice" %77, i64 16, 2 - call void @"github.com/goplus/llgo/cl/_testdata/print.println"(%"github.com/goplus/llgo/runtime/internal/runtime.Slice" %78) - %79 = call ptr @"github.com/goplus/llgo/runtime/internal/runtime.AllocZ"(i64 16) - %80 = getelementptr inbounds %"github.com/goplus/llgo/runtime/internal/runtime.eface", ptr %79, i64 0 - %81 = call ptr @"github.com/goplus/llgo/runtime/internal/runtime.AllocU"(i64 16) - store { double, double } { double 1.000000e+00, double 2.000000e+00 }, ptr %81, align 8 - %82 = insertvalue %"github.com/goplus/llgo/runtime/internal/runtime.eface" { ptr @_llgo_complex128, ptr undef }, ptr %81, 1 - store %"github.com/goplus/llgo/runtime/internal/runtime.eface" %82, ptr %80, align 8 - %83 = insertvalue %"github.com/goplus/llgo/runtime/internal/runtime.Slice" undef, ptr %79, 0 - %84 = insertvalue %"github.com/goplus/llgo/runtime/internal/runtime.Slice" %83, i64 1, 1 - %85 = insertvalue %"github.com/goplus/llgo/runtime/internal/runtime.Slice" %84, i64 1, 2 - call void @"github.com/goplus/llgo/cl/_testdata/print.println"(%"github.com/goplus/llgo/runtime/internal/runtime.Slice" %85) - ret void - -_llgo_3: ; preds = %_llgo_0 - br i1 true, label %_llgo_1, label %_llgo_2 -} - -define void @"github.com/goplus/llgo/cl/_testdata/print.prinfsub"(double %0) { -_llgo_0: - %1 = fneg double %0 - call void @"github.com/goplus/llgo/cl/_testdata/print.printfloat"(double %1) - ret void -} - -define void @"github.com/goplus/llgo/cl/_testdata/print.prinsub"(i64 %0) { -_llgo_0: - %1 = sub i64 0, %0 - call void @"github.com/goplus/llgo/cl/_testdata/print.printint"(i64 %1) - ret void -} - -define void @"github.com/goplus/llgo/cl/_testdata/print.printany"(%"github.com/goplus/llgo/runtime/internal/runtime.eface" %0) { -_llgo_0: - %1 = extractvalue %"github.com/goplus/llgo/runtime/internal/runtime.eface" %0, 0 - %2 = icmp eq ptr %1, @_llgo_bool - br i1 %2, label %_llgo_35, label %_llgo_36 - -_llgo_1: ; preds = %_llgo_34, %_llgo_85, %_llgo_32, %_llgo_30, %_llgo_28, %_llgo_26, %_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_37 - call void @"github.com/goplus/llgo/cl/_testdata/print.printbool"(i1 %53) - br label %_llgo_1 - -_llgo_3: ; preds = %_llgo_37 - %3 = extractvalue %"github.com/goplus/llgo/runtime/internal/runtime.eface" %0, 0 - %4 = icmp eq ptr %3, @_llgo_int - br i1 %4, label %_llgo_38, label %_llgo_39 - -_llgo_4: ; preds = %_llgo_40 - call void @"github.com/goplus/llgo/cl/_testdata/print.printint"(i64 %60) - br label %_llgo_1 - -_llgo_5: ; preds = %_llgo_40 - %5 = extractvalue %"github.com/goplus/llgo/runtime/internal/runtime.eface" %0, 0 - %6 = icmp eq ptr %5, @_llgo_int8 - br i1 %6, label %_llgo_41, label %_llgo_42 - -_llgo_6: ; preds = %_llgo_43 - %7 = sext i8 %67 to i64 - call void @"github.com/goplus/llgo/cl/_testdata/print.printint"(i64 %7) - br label %_llgo_1 - -_llgo_7: ; preds = %_llgo_43 - %8 = extractvalue %"github.com/goplus/llgo/runtime/internal/runtime.eface" %0, 0 - %9 = icmp eq ptr %8, @_llgo_int16 - br i1 %9, label %_llgo_44, label %_llgo_45 - -_llgo_8: ; preds = %_llgo_46 - %10 = sext i16 %74 to i64 - call void @"github.com/goplus/llgo/cl/_testdata/print.printint"(i64 %10) - br label %_llgo_1 - -_llgo_9: ; preds = %_llgo_46 - %11 = extractvalue %"github.com/goplus/llgo/runtime/internal/runtime.eface" %0, 0 - %12 = icmp eq ptr %11, @_llgo_int32 - br i1 %12, label %_llgo_47, label %_llgo_48 - -_llgo_10: ; preds = %_llgo_49 - %13 = sext i32 %81 to i64 - call void @"github.com/goplus/llgo/cl/_testdata/print.printint"(i64 %13) - br label %_llgo_1 - -_llgo_11: ; preds = %_llgo_49 - %14 = extractvalue %"github.com/goplus/llgo/runtime/internal/runtime.eface" %0, 0 - %15 = icmp eq ptr %14, @_llgo_int64 - br i1 %15, label %_llgo_50, label %_llgo_51 - -_llgo_12: ; preds = %_llgo_52 - call void @"github.com/goplus/llgo/cl/_testdata/print.printint"(i64 %88) - br label %_llgo_1 - -_llgo_13: ; preds = %_llgo_52 - %16 = extractvalue %"github.com/goplus/llgo/runtime/internal/runtime.eface" %0, 0 - %17 = icmp eq ptr %16, @_llgo_uint - br i1 %17, label %_llgo_53, label %_llgo_54 - -_llgo_14: ; preds = %_llgo_55 - call void @"github.com/goplus/llgo/cl/_testdata/print.printuint"(i64 %95) - br label %_llgo_1 - -_llgo_15: ; preds = %_llgo_55 - %18 = extractvalue %"github.com/goplus/llgo/runtime/internal/runtime.eface" %0, 0 - %19 = icmp eq ptr %18, @_llgo_uint8 - br i1 %19, label %_llgo_56, label %_llgo_57 - -_llgo_16: ; preds = %_llgo_58 - %20 = zext i8 %102 to i64 - call void @"github.com/goplus/llgo/cl/_testdata/print.printuint"(i64 %20) - br label %_llgo_1 - -_llgo_17: ; preds = %_llgo_58 - %21 = extractvalue %"github.com/goplus/llgo/runtime/internal/runtime.eface" %0, 0 - %22 = icmp eq ptr %21, @_llgo_uint16 - br i1 %22, label %_llgo_59, label %_llgo_60 - -_llgo_18: ; preds = %_llgo_61 - %23 = zext i16 %109 to i64 - call void @"github.com/goplus/llgo/cl/_testdata/print.printuint"(i64 %23) - br label %_llgo_1 - -_llgo_19: ; preds = %_llgo_61 - %24 = extractvalue %"github.com/goplus/llgo/runtime/internal/runtime.eface" %0, 0 - %25 = icmp eq ptr %24, @_llgo_uint32 - br i1 %25, label %_llgo_62, label %_llgo_63 - -_llgo_20: ; preds = %_llgo_64 - %26 = zext i32 %116 to i64 - call void @"github.com/goplus/llgo/cl/_testdata/print.printuint"(i64 %26) - br label %_llgo_1 - -_llgo_21: ; preds = %_llgo_64 - %27 = extractvalue %"github.com/goplus/llgo/runtime/internal/runtime.eface" %0, 0 - %28 = icmp eq ptr %27, @_llgo_uint64 - br i1 %28, label %_llgo_65, label %_llgo_66 - -_llgo_22: ; preds = %_llgo_67 - call void @"github.com/goplus/llgo/cl/_testdata/print.printuint"(i64 %123) - br label %_llgo_1 - -_llgo_23: ; preds = %_llgo_67 - %29 = extractvalue %"github.com/goplus/llgo/runtime/internal/runtime.eface" %0, 0 - %30 = icmp eq ptr %29, @_llgo_uintptr - br i1 %30, label %_llgo_68, label %_llgo_69 - -_llgo_24: ; preds = %_llgo_70 - call void @"github.com/goplus/llgo/cl/_testdata/print.printuint"(i64 %130) - br label %_llgo_1 - -_llgo_25: ; preds = %_llgo_70 - %31 = extractvalue %"github.com/goplus/llgo/runtime/internal/runtime.eface" %0, 0 - %32 = icmp eq ptr %31, @_llgo_float32 - br i1 %32, label %_llgo_71, label %_llgo_72 - -_llgo_26: ; preds = %_llgo_73 - %33 = fpext float %137 to double - call void @"github.com/goplus/llgo/cl/_testdata/print.printfloat"(double %33) - br label %_llgo_1 - -_llgo_27: ; preds = %_llgo_73 - %34 = extractvalue %"github.com/goplus/llgo/runtime/internal/runtime.eface" %0, 0 - %35 = icmp eq ptr %34, @_llgo_float64 - br i1 %35, label %_llgo_74, label %_llgo_75 - -_llgo_28: ; preds = %_llgo_76 - call void @"github.com/goplus/llgo/cl/_testdata/print.printfloat"(double %144) - br label %_llgo_1 - -_llgo_29: ; preds = %_llgo_76 - %36 = extractvalue %"github.com/goplus/llgo/runtime/internal/runtime.eface" %0, 0 - %37 = icmp eq ptr %36, @_llgo_complex64 - br i1 %37, label %_llgo_77, label %_llgo_78 - -_llgo_30: ; preds = %_llgo_79 - call void @"github.com/goplus/llgo/cl/_testdata/print.printstring"(%"github.com/goplus/llgo/runtime/internal/runtime.String" { ptr @21, i64 1 }) - %38 = extractvalue { float, float } %151, 0 - %39 = fpext float %38 to double - call void @"github.com/goplus/llgo/cl/_testdata/print.printfloat"(double %39) - %40 = extractvalue { float, float } %151, 1 - %41 = fpext float %40 to double - call void @"github.com/goplus/llgo/cl/_testdata/print.printfloat"(double %41) - call void @"github.com/goplus/llgo/cl/_testdata/print.printstring"(%"github.com/goplus/llgo/runtime/internal/runtime.String" { ptr @22, i64 2 }) - br label %_llgo_1 - -_llgo_31: ; preds = %_llgo_79 - %42 = extractvalue %"github.com/goplus/llgo/runtime/internal/runtime.eface" %0, 0 - %43 = icmp eq ptr %42, @_llgo_complex128 - br i1 %43, label %_llgo_80, label %_llgo_81 - -_llgo_32: ; preds = %_llgo_82 - call void @"github.com/goplus/llgo/cl/_testdata/print.printstring"(%"github.com/goplus/llgo/runtime/internal/runtime.String" { ptr @21, i64 1 }) - %44 = extractvalue { double, double } %158, 0 - call void @"github.com/goplus/llgo/cl/_testdata/print.printfloat"(double %44) - %45 = extractvalue { double, double } %158, 1 - call void @"github.com/goplus/llgo/cl/_testdata/print.printfloat"(double %45) - call void @"github.com/goplus/llgo/cl/_testdata/print.printstring"(%"github.com/goplus/llgo/runtime/internal/runtime.String" { ptr @22, i64 2 }) - br label %_llgo_1 - -_llgo_33: ; preds = %_llgo_82 - %46 = extractvalue %"github.com/goplus/llgo/runtime/internal/runtime.eface" %0, 0 - %47 = icmp eq ptr %46, @_llgo_string - br i1 %47, label %_llgo_83, label %_llgo_84 - -_llgo_34: ; preds = %_llgo_85 - call void @"github.com/goplus/llgo/cl/_testdata/print.printstring"(%"github.com/goplus/llgo/runtime/internal/runtime.String" %165) - br label %_llgo_1 - -_llgo_35: ; preds = %_llgo_0 - %48 = extractvalue %"github.com/goplus/llgo/runtime/internal/runtime.eface" %0, 1 - %49 = load i1, ptr %48, align 1 - %50 = insertvalue { i1, i1 } undef, i1 %49, 0 - %51 = insertvalue { i1, i1 } %50, i1 true, 1 - br label %_llgo_37 - -_llgo_36: ; preds = %_llgo_0 - br label %_llgo_37 - -_llgo_37: ; preds = %_llgo_36, %_llgo_35 - %52 = phi { i1, i1 } [ %51, %_llgo_35 ], [ zeroinitializer, %_llgo_36 ] - %53 = extractvalue { i1, i1 } %52, 0 - %54 = extractvalue { i1, i1 } %52, 1 - br i1 %54, label %_llgo_2, label %_llgo_3 - -_llgo_38: ; preds = %_llgo_3 - %55 = extractvalue %"github.com/goplus/llgo/runtime/internal/runtime.eface" %0, 1 - %56 = load i64, ptr %55, align 4 - %57 = insertvalue { i64, i1 } undef, i64 %56, 0 - %58 = insertvalue { i64, i1 } %57, i1 true, 1 - br label %_llgo_40 - -_llgo_39: ; preds = %_llgo_3 - br label %_llgo_40 - -_llgo_40: ; preds = %_llgo_39, %_llgo_38 - %59 = phi { i64, i1 } [ %58, %_llgo_38 ], [ zeroinitializer, %_llgo_39 ] - %60 = extractvalue { i64, i1 } %59, 0 - %61 = extractvalue { i64, i1 } %59, 1 - br i1 %61, label %_llgo_4, label %_llgo_5 - -_llgo_41: ; preds = %_llgo_5 - %62 = extractvalue %"github.com/goplus/llgo/runtime/internal/runtime.eface" %0, 1 - %63 = load i8, ptr %62, align 1 - %64 = insertvalue { i8, i1 } undef, i8 %63, 0 - %65 = insertvalue { i8, i1 } %64, i1 true, 1 - br label %_llgo_43 - -_llgo_42: ; preds = %_llgo_5 - br label %_llgo_43 - -_llgo_43: ; preds = %_llgo_42, %_llgo_41 - %66 = phi { i8, i1 } [ %65, %_llgo_41 ], [ zeroinitializer, %_llgo_42 ] - %67 = extractvalue { i8, i1 } %66, 0 - %68 = extractvalue { i8, i1 } %66, 1 - br i1 %68, label %_llgo_6, label %_llgo_7 - -_llgo_44: ; preds = %_llgo_7 - %69 = extractvalue %"github.com/goplus/llgo/runtime/internal/runtime.eface" %0, 1 - %70 = load i16, ptr %69, align 2 - %71 = insertvalue { i16, i1 } undef, i16 %70, 0 - %72 = insertvalue { i16, i1 } %71, i1 true, 1 - br label %_llgo_46 - -_llgo_45: ; preds = %_llgo_7 - br label %_llgo_46 - -_llgo_46: ; preds = %_llgo_45, %_llgo_44 - %73 = phi { i16, i1 } [ %72, %_llgo_44 ], [ zeroinitializer, %_llgo_45 ] - %74 = extractvalue { i16, i1 } %73, 0 - %75 = extractvalue { i16, i1 } %73, 1 - br i1 %75, label %_llgo_8, label %_llgo_9 - -_llgo_47: ; preds = %_llgo_9 - %76 = extractvalue %"github.com/goplus/llgo/runtime/internal/runtime.eface" %0, 1 - %77 = load i32, ptr %76, align 4 - %78 = insertvalue { i32, i1 } undef, i32 %77, 0 - %79 = insertvalue { i32, i1 } %78, i1 true, 1 - br label %_llgo_49 - -_llgo_48: ; preds = %_llgo_9 - br label %_llgo_49 - -_llgo_49: ; preds = %_llgo_48, %_llgo_47 - %80 = phi { i32, i1 } [ %79, %_llgo_47 ], [ zeroinitializer, %_llgo_48 ] - %81 = extractvalue { i32, i1 } %80, 0 - %82 = extractvalue { i32, i1 } %80, 1 - br i1 %82, label %_llgo_10, label %_llgo_11 - -_llgo_50: ; preds = %_llgo_11 - %83 = extractvalue %"github.com/goplus/llgo/runtime/internal/runtime.eface" %0, 1 - %84 = load i64, ptr %83, align 4 - %85 = insertvalue { i64, i1 } undef, i64 %84, 0 - %86 = insertvalue { i64, i1 } %85, i1 true, 1 - br label %_llgo_52 - -_llgo_51: ; preds = %_llgo_11 - br label %_llgo_52 - -_llgo_52: ; preds = %_llgo_51, %_llgo_50 - %87 = phi { i64, i1 } [ %86, %_llgo_50 ], [ zeroinitializer, %_llgo_51 ] - %88 = extractvalue { i64, i1 } %87, 0 - %89 = extractvalue { i64, i1 } %87, 1 - br i1 %89, label %_llgo_12, label %_llgo_13 - -_llgo_53: ; preds = %_llgo_13 - %90 = extractvalue %"github.com/goplus/llgo/runtime/internal/runtime.eface" %0, 1 - %91 = load i64, ptr %90, align 4 - %92 = insertvalue { i64, i1 } undef, i64 %91, 0 - %93 = insertvalue { i64, i1 } %92, i1 true, 1 - br label %_llgo_55 - -_llgo_54: ; preds = %_llgo_13 - br label %_llgo_55 - -_llgo_55: ; preds = %_llgo_54, %_llgo_53 - %94 = phi { i64, i1 } [ %93, %_llgo_53 ], [ zeroinitializer, %_llgo_54 ] - %95 = extractvalue { i64, i1 } %94, 0 - %96 = extractvalue { i64, i1 } %94, 1 - br i1 %96, label %_llgo_14, label %_llgo_15 - -_llgo_56: ; preds = %_llgo_15 - %97 = extractvalue %"github.com/goplus/llgo/runtime/internal/runtime.eface" %0, 1 - %98 = load i8, ptr %97, align 1 - %99 = insertvalue { i8, i1 } undef, i8 %98, 0 - %100 = insertvalue { i8, i1 } %99, i1 true, 1 - br label %_llgo_58 - -_llgo_57: ; preds = %_llgo_15 - br label %_llgo_58 - -_llgo_58: ; preds = %_llgo_57, %_llgo_56 - %101 = phi { i8, i1 } [ %100, %_llgo_56 ], [ zeroinitializer, %_llgo_57 ] - %102 = extractvalue { i8, i1 } %101, 0 - %103 = extractvalue { i8, i1 } %101, 1 - br i1 %103, label %_llgo_16, label %_llgo_17 - -_llgo_59: ; preds = %_llgo_17 - %104 = extractvalue %"github.com/goplus/llgo/runtime/internal/runtime.eface" %0, 1 - %105 = load i16, ptr %104, align 2 - %106 = insertvalue { i16, i1 } undef, i16 %105, 0 - %107 = insertvalue { i16, i1 } %106, i1 true, 1 - br label %_llgo_61 - -_llgo_60: ; preds = %_llgo_17 - br label %_llgo_61 - -_llgo_61: ; preds = %_llgo_60, %_llgo_59 - %108 = phi { i16, i1 } [ %107, %_llgo_59 ], [ zeroinitializer, %_llgo_60 ] - %109 = extractvalue { i16, i1 } %108, 0 - %110 = extractvalue { i16, i1 } %108, 1 - br i1 %110, label %_llgo_18, label %_llgo_19 - -_llgo_62: ; preds = %_llgo_19 - %111 = extractvalue %"github.com/goplus/llgo/runtime/internal/runtime.eface" %0, 1 - %112 = load i32, ptr %111, align 4 - %113 = insertvalue { i32, i1 } undef, i32 %112, 0 - %114 = insertvalue { i32, i1 } %113, i1 true, 1 - br label %_llgo_64 - -_llgo_63: ; preds = %_llgo_19 - br label %_llgo_64 - -_llgo_64: ; preds = %_llgo_63, %_llgo_62 - %115 = phi { i32, i1 } [ %114, %_llgo_62 ], [ zeroinitializer, %_llgo_63 ] - %116 = extractvalue { i32, i1 } %115, 0 - %117 = extractvalue { i32, i1 } %115, 1 - br i1 %117, label %_llgo_20, label %_llgo_21 - -_llgo_65: ; preds = %_llgo_21 - %118 = extractvalue %"github.com/goplus/llgo/runtime/internal/runtime.eface" %0, 1 - %119 = load i64, ptr %118, align 4 - %120 = insertvalue { i64, i1 } undef, i64 %119, 0 - %121 = insertvalue { i64, i1 } %120, i1 true, 1 - br label %_llgo_67 - -_llgo_66: ; preds = %_llgo_21 - br label %_llgo_67 - -_llgo_67: ; preds = %_llgo_66, %_llgo_65 - %122 = phi { i64, i1 } [ %121, %_llgo_65 ], [ zeroinitializer, %_llgo_66 ] - %123 = extractvalue { i64, i1 } %122, 0 - %124 = extractvalue { i64, i1 } %122, 1 - br i1 %124, label %_llgo_22, label %_llgo_23 - -_llgo_68: ; preds = %_llgo_23 - %125 = extractvalue %"github.com/goplus/llgo/runtime/internal/runtime.eface" %0, 1 - %126 = load i64, ptr %125, align 4 - %127 = insertvalue { i64, i1 } undef, i64 %126, 0 - %128 = insertvalue { i64, i1 } %127, i1 true, 1 - br label %_llgo_70 - -_llgo_69: ; preds = %_llgo_23 - br label %_llgo_70 - -_llgo_70: ; preds = %_llgo_69, %_llgo_68 - %129 = phi { i64, i1 } [ %128, %_llgo_68 ], [ zeroinitializer, %_llgo_69 ] - %130 = extractvalue { i64, i1 } %129, 0 - %131 = extractvalue { i64, i1 } %129, 1 - br i1 %131, label %_llgo_24, label %_llgo_25 - -_llgo_71: ; preds = %_llgo_25 - %132 = extractvalue %"github.com/goplus/llgo/runtime/internal/runtime.eface" %0, 1 - %133 = load float, ptr %132, align 4 - %134 = insertvalue { float, i1 } undef, float %133, 0 - %135 = insertvalue { float, i1 } %134, i1 true, 1 - br label %_llgo_73 - -_llgo_72: ; preds = %_llgo_25 - br label %_llgo_73 - -_llgo_73: ; preds = %_llgo_72, %_llgo_71 - %136 = phi { float, i1 } [ %135, %_llgo_71 ], [ zeroinitializer, %_llgo_72 ] - %137 = extractvalue { float, i1 } %136, 0 - %138 = extractvalue { float, i1 } %136, 1 - br i1 %138, label %_llgo_26, label %_llgo_27 - -_llgo_74: ; preds = %_llgo_27 - %139 = extractvalue %"github.com/goplus/llgo/runtime/internal/runtime.eface" %0, 1 - %140 = load double, ptr %139, align 8 - %141 = insertvalue { double, i1 } undef, double %140, 0 - %142 = insertvalue { double, i1 } %141, i1 true, 1 - br label %_llgo_76 - -_llgo_75: ; preds = %_llgo_27 - br label %_llgo_76 - -_llgo_76: ; preds = %_llgo_75, %_llgo_74 - %143 = phi { double, i1 } [ %142, %_llgo_74 ], [ zeroinitializer, %_llgo_75 ] - %144 = extractvalue { double, i1 } %143, 0 - %145 = extractvalue { double, i1 } %143, 1 - br i1 %145, label %_llgo_28, label %_llgo_29 - -_llgo_77: ; preds = %_llgo_29 - %146 = extractvalue %"github.com/goplus/llgo/runtime/internal/runtime.eface" %0, 1 - %147 = load { float, float }, ptr %146, align 4 - %148 = insertvalue { { float, float }, i1 } undef, { float, float } %147, 0 - %149 = insertvalue { { float, float }, i1 } %148, i1 true, 1 - br label %_llgo_79 - -_llgo_78: ; preds = %_llgo_29 - br label %_llgo_79 - -_llgo_79: ; preds = %_llgo_78, %_llgo_77 - %150 = phi { { float, float }, i1 } [ %149, %_llgo_77 ], [ zeroinitializer, %_llgo_78 ] - %151 = extractvalue { { float, float }, i1 } %150, 0 - %152 = extractvalue { { float, float }, i1 } %150, 1 - br i1 %152, label %_llgo_30, label %_llgo_31 - -_llgo_80: ; preds = %_llgo_31 - %153 = extractvalue %"github.com/goplus/llgo/runtime/internal/runtime.eface" %0, 1 - %154 = load { double, double }, ptr %153, align 8 - %155 = insertvalue { { double, double }, i1 } undef, { double, double } %154, 0 - %156 = insertvalue { { double, double }, i1 } %155, i1 true, 1 - br label %_llgo_82 - -_llgo_81: ; preds = %_llgo_31 - br label %_llgo_82 - -_llgo_82: ; preds = %_llgo_81, %_llgo_80 - %157 = phi { { double, double }, i1 } [ %156, %_llgo_80 ], [ zeroinitializer, %_llgo_81 ] - %158 = extractvalue { { double, double }, i1 } %157, 0 - %159 = extractvalue { { double, double }, i1 } %157, 1 - br i1 %159, label %_llgo_32, label %_llgo_33 - -_llgo_83: ; preds = %_llgo_33 - %160 = extractvalue %"github.com/goplus/llgo/runtime/internal/runtime.eface" %0, 1 - %161 = load %"github.com/goplus/llgo/runtime/internal/runtime.String", ptr %160, align 8 - %162 = insertvalue { %"github.com/goplus/llgo/runtime/internal/runtime.String", i1 } undef, %"github.com/goplus/llgo/runtime/internal/runtime.String" %161, 0 - %163 = insertvalue { %"github.com/goplus/llgo/runtime/internal/runtime.String", i1 } %162, i1 true, 1 - br label %_llgo_85 - -_llgo_84: ; preds = %_llgo_33 - br label %_llgo_85 - -_llgo_85: ; preds = %_llgo_84, %_llgo_83 - %164 = phi { %"github.com/goplus/llgo/runtime/internal/runtime.String", i1 } [ %163, %_llgo_83 ], [ zeroinitializer, %_llgo_84 ] - %165 = extractvalue { %"github.com/goplus/llgo/runtime/internal/runtime.String", i1 } %164, 0 - %166 = extractvalue { %"github.com/goplus/llgo/runtime/internal/runtime.String", i1 } %164, 1 - br i1 %166, label %_llgo_34, label %_llgo_1 -} - -define void @"github.com/goplus/llgo/cl/_testdata/print.printbool"(i1 %0) { -_llgo_0: - br i1 %0, label %_llgo_1, label %_llgo_3 - -_llgo_1: ; preds = %_llgo_0 - call void @"github.com/goplus/llgo/cl/_testdata/print.printstring"(%"github.com/goplus/llgo/runtime/internal/runtime.String" { ptr @23, i64 4 }) - br label %_llgo_2 - -_llgo_2: ; preds = %_llgo_3, %_llgo_1 - ret void - -_llgo_3: ; preds = %_llgo_0 - call void @"github.com/goplus/llgo/cl/_testdata/print.printstring"(%"github.com/goplus/llgo/runtime/internal/runtime.String" { ptr @24, i64 5 }) - br label %_llgo_2 -} - -define void @"github.com/goplus/llgo/cl/_testdata/print.printfloat"(double %0) { -_llgo_0: - %1 = fcmp une double %0, %0 - br i1 %1, label %_llgo_1, label %_llgo_3 - -_llgo_1: ; preds = %_llgo_0 - call void @"github.com/goplus/llgo/cl/_testdata/print.printstring"(%"github.com/goplus/llgo/runtime/internal/runtime.String" { ptr @25, i64 3 }) - ret void - -_llgo_2: ; preds = %_llgo_7 - call void @"github.com/goplus/llgo/cl/_testdata/print.printstring"(%"github.com/goplus/llgo/runtime/internal/runtime.String" { ptr @26, i64 4 }) - ret void - -_llgo_3: ; preds = %_llgo_0 - %2 = fadd double %0, %0 - %3 = fcmp oeq double %2, %0 - br i1 %3, label %_llgo_6, label %_llgo_7 - -_llgo_4: ; preds = %_llgo_10 - call void @"github.com/goplus/llgo/cl/_testdata/print.printstring"(%"github.com/goplus/llgo/runtime/internal/runtime.String" { ptr @27, i64 4 }) - ret void - -_llgo_5: ; preds = %_llgo_7 - %4 = fadd double %0, %0 - %5 = fcmp oeq double %4, %0 - br i1 %5, label %_llgo_9, label %_llgo_10 - -_llgo_6: ; preds = %_llgo_3 - %6 = fcmp ogt double %0, 0.000000e+00 - br label %_llgo_7 - -_llgo_7: ; preds = %_llgo_6, %_llgo_3 - %7 = phi i1 [ false, %_llgo_3 ], [ %6, %_llgo_6 ] - br i1 %7, label %_llgo_2, label %_llgo_5 - -_llgo_8: ; preds = %_llgo_10 - %8 = call ptr @"github.com/goplus/llgo/runtime/internal/runtime.AllocZ"(i64 14) - %9 = getelementptr inbounds i8, ptr %8, i64 0 - store i8 43, ptr %9, align 1 - %10 = fcmp oeq double %0, 0.000000e+00 - br i1 %10, label %_llgo_11, label %_llgo_13 - -_llgo_9: ; preds = %_llgo_5 - %11 = fcmp olt double %0, 0.000000e+00 - br label %_llgo_10 - -_llgo_10: ; preds = %_llgo_9, %_llgo_5 - %12 = phi i1 [ false, %_llgo_5 ], [ %11, %_llgo_9 ] - br i1 %12, label %_llgo_4, label %_llgo_8 - -_llgo_11: ; preds = %_llgo_8 - %13 = fdiv double 1.000000e+00, %0 - %14 = fcmp olt double %13, 0.000000e+00 - br i1 %14, label %_llgo_14, label %_llgo_12 - -_llgo_12: ; preds = %_llgo_24, %_llgo_23, %_llgo_14, %_llgo_11 - %15 = phi double [ %0, %_llgo_11 ], [ %36, %_llgo_23 ], [ %0, %_llgo_14 ], [ %39, %_llgo_24 ] - %16 = phi i64 [ 0, %_llgo_11 ], [ %29, %_llgo_23 ], [ 0, %_llgo_14 ], [ %38, %_llgo_24 ] - br label %_llgo_25 - -_llgo_13: ; preds = %_llgo_8 - %17 = fcmp olt double %0, 0.000000e+00 - br i1 %17, label %_llgo_15, label %_llgo_17 - -_llgo_14: ; preds = %_llgo_11 - %18 = getelementptr inbounds i8, ptr %8, i64 0 - store i8 45, ptr %18, align 1 - br label %_llgo_12 - -_llgo_15: ; preds = %_llgo_13 - %19 = fneg double %0 - %20 = getelementptr inbounds i8, ptr %8, i64 0 - store i8 45, ptr %20, align 1 - br label %_llgo_17 - -_llgo_16: ; preds = %_llgo_17 - %21 = add i64 %24, 1 - %22 = fdiv double %23, 1.000000e+01 - br label %_llgo_17 - -_llgo_17: ; preds = %_llgo_16, %_llgo_15, %_llgo_13 - %23 = phi double [ %0, %_llgo_13 ], [ %22, %_llgo_16 ], [ %19, %_llgo_15 ] - %24 = phi i64 [ 0, %_llgo_13 ], [ %21, %_llgo_16 ], [ 0, %_llgo_15 ] - %25 = fcmp oge double %23, 1.000000e+01 - br i1 %25, label %_llgo_16, label %_llgo_20 - -_llgo_18: ; preds = %_llgo_20 - %26 = sub i64 %29, 1 - %27 = fmul double %28, 1.000000e+01 - br label %_llgo_20 - -_llgo_19: ; preds = %_llgo_20 - br label %_llgo_21 - -_llgo_20: ; preds = %_llgo_18, %_llgo_17 - %28 = phi double [ %23, %_llgo_17 ], [ %27, %_llgo_18 ] - %29 = phi i64 [ %24, %_llgo_17 ], [ %26, %_llgo_18 ] - %30 = fcmp olt double %28, 1.000000e+00 - br i1 %30, label %_llgo_18, label %_llgo_19 - -_llgo_21: ; preds = %_llgo_22, %_llgo_19 - %31 = phi double [ 5.000000e+00, %_llgo_19 ], [ %34, %_llgo_22 ] - %32 = phi i64 [ 0, %_llgo_19 ], [ %35, %_llgo_22 ] - %33 = icmp slt i64 %32, 7 - br i1 %33, label %_llgo_22, label %_llgo_23 - -_llgo_22: ; preds = %_llgo_21 - %34 = fdiv double %31, 1.000000e+01 - %35 = add i64 %32, 1 - br label %_llgo_21 - -_llgo_23: ; preds = %_llgo_21 - %36 = fadd double %28, %31 - %37 = fcmp oge double %36, 1.000000e+01 - br i1 %37, label %_llgo_24, label %_llgo_12 - -_llgo_24: ; preds = %_llgo_23 - %38 = add i64 %29, 1 - %39 = fdiv double %36, 1.000000e+01 - br label %_llgo_12 - -_llgo_25: ; preds = %_llgo_26, %_llgo_12 - %40 = phi double [ %15, %_llgo_12 ], [ %53, %_llgo_26 ] - %41 = phi i64 [ 0, %_llgo_12 ], [ %54, %_llgo_26 ] - %42 = icmp slt i64 %41, 7 - br i1 %42, label %_llgo_26, label %_llgo_27 - -_llgo_26: ; preds = %_llgo_25 - %43 = fptosi double %40 to i64 - %44 = add i64 %41, 2 - %45 = add i64 %43, 48 - %46 = trunc i64 %45 to i8 - %47 = icmp slt i64 %44, 0 - %48 = icmp uge i64 %44, 14 - %49 = or i1 %48, %47 - call void @"github.com/goplus/llgo/runtime/internal/runtime.AssertIndexRange"(i1 %49) - %50 = getelementptr inbounds i8, ptr %8, i64 %44 - store i8 %46, ptr %50, align 1 - %51 = sitofp i64 %43 to double - %52 = fsub double %40, %51 - %53 = fmul double %52, 1.000000e+01 - %54 = add i64 %41, 1 - br label %_llgo_25 - -_llgo_27: ; preds = %_llgo_25 - %55 = getelementptr inbounds i8, ptr %8, i64 2 - %56 = load i8, ptr %55, align 1 - %57 = getelementptr inbounds i8, ptr %8, i64 1 - store i8 %56, ptr %57, align 1 - %58 = getelementptr inbounds i8, ptr %8, i64 2 - store i8 46, ptr %58, align 1 - %59 = getelementptr inbounds i8, ptr %8, i64 9 - store i8 101, ptr %59, align 1 - %60 = getelementptr inbounds i8, ptr %8, i64 10 - store i8 43, ptr %60, align 1 - %61 = icmp slt i64 %16, 0 - br i1 %61, label %_llgo_28, label %_llgo_29 - -_llgo_28: ; preds = %_llgo_27 - %62 = sub i64 0, %16 - %63 = getelementptr inbounds i8, ptr %8, i64 10 - store i8 45, ptr %63, align 1 - br label %_llgo_29 - -_llgo_29: ; preds = %_llgo_28, %_llgo_27 - %64 = phi i64 [ %16, %_llgo_27 ], [ %62, %_llgo_28 ] - %65 = sdiv i64 %64, 100 - %66 = trunc i64 %65 to i8 - %67 = add i8 %66, 48 - %68 = getelementptr inbounds i8, ptr %8, i64 11 - store i8 %67, ptr %68, align 1 - %69 = sdiv i64 %64, 10 - %70 = trunc i64 %69 to i8 - %71 = urem i8 %70, 10 - %72 = add i8 %71, 48 - %73 = getelementptr inbounds i8, ptr %8, i64 12 - store i8 %72, ptr %73, align 1 - %74 = srem i64 %64, 10 - %75 = trunc i64 %74 to i8 - %76 = add i8 %75, 48 - %77 = getelementptr inbounds i8, ptr %8, i64 13 - store i8 %76, ptr %77, align 1 - %78 = insertvalue %"github.com/goplus/llgo/runtime/internal/runtime.Slice" undef, ptr %8, 0 - %79 = insertvalue %"github.com/goplus/llgo/runtime/internal/runtime.Slice" %78, i64 14, 1 - %80 = insertvalue %"github.com/goplus/llgo/runtime/internal/runtime.Slice" %79, i64 14, 2 - call void @"github.com/goplus/llgo/cl/_testdata/print.gwrite"(%"github.com/goplus/llgo/runtime/internal/runtime.Slice" %80) - ret void -} - -define void @"github.com/goplus/llgo/cl/_testdata/print.printhex"(i64 %0) { -_llgo_0: - %1 = call ptr @"github.com/goplus/llgo/runtime/internal/runtime.AllocZ"(i64 100) - br label %_llgo_3 - -_llgo_1: ; preds = %_llgo_3 - %2 = urem i64 %22, 16 - %3 = icmp uge i64 %2, 16 - call void @"github.com/goplus/llgo/runtime/internal/runtime.AssertIndexRange"(i1 %3) - %4 = getelementptr inbounds i8, ptr @28, i64 %2 - %5 = load i8, ptr %4, align 1 - %6 = icmp slt i64 %23, 0 - %7 = icmp uge i64 %23, 100 - %8 = or i1 %7, %6 - call void @"github.com/goplus/llgo/runtime/internal/runtime.AssertIndexRange"(i1 %8) - %9 = getelementptr inbounds i8, ptr %1, i64 %23 - store i8 %5, ptr %9, align 1 - %10 = icmp ult i64 %22, 16 - br i1 %10, label %_llgo_5, label %_llgo_4 - -_llgo_2: ; preds = %_llgo_5, %_llgo_3 - %11 = sub i64 %23, 1 - %12 = icmp slt i64 %11, 0 - %13 = icmp uge i64 %11, 100 - %14 = or i1 %13, %12 - call void @"github.com/goplus/llgo/runtime/internal/runtime.AssertIndexRange"(i1 %14) - %15 = getelementptr inbounds i8, ptr %1, i64 %11 - store i8 120, ptr %15, align 1 - %16 = sub i64 %11, 1 - %17 = icmp slt i64 %16, 0 - %18 = icmp uge i64 %16, 100 - %19 = or i1 %18, %17 - call void @"github.com/goplus/llgo/runtime/internal/runtime.AssertIndexRange"(i1 %19) - %20 = getelementptr inbounds i8, ptr %1, i64 %16 - store i8 48, ptr %20, align 1 - %21 = call %"github.com/goplus/llgo/runtime/internal/runtime.Slice" @"github.com/goplus/llgo/runtime/internal/runtime.NewSlice3"(ptr %1, i64 1, i64 100, i64 %16, i64 100, i64 100) - call void @"github.com/goplus/llgo/cl/_testdata/print.gwrite"(%"github.com/goplus/llgo/runtime/internal/runtime.Slice" %21) - ret void - -_llgo_3: ; preds = %_llgo_4, %_llgo_0 - %22 = phi i64 [ %0, %_llgo_0 ], [ %25, %_llgo_4 ] - %23 = phi i64 [ 99, %_llgo_0 ], [ %26, %_llgo_4 ] - %24 = icmp sgt i64 %23, 0 - br i1 %24, label %_llgo_1, label %_llgo_2 - -_llgo_4: ; preds = %_llgo_5, %_llgo_1 - %25 = udiv i64 %22, 16 - %26 = sub i64 %23, 1 - br label %_llgo_3 - -_llgo_5: ; preds = %_llgo_1 - %27 = sub i64 100, %23 - %28 = load i64, ptr @"github.com/goplus/llgo/cl/_testdata/print.minhexdigits", align 4 - %29 = icmp sge i64 %27, %28 - br i1 %29, label %_llgo_2, label %_llgo_4 -} - -define void @"github.com/goplus/llgo/cl/_testdata/print.printint"(i64 %0) { -_llgo_0: - %1 = icmp slt i64 %0, 0 - br i1 %1, label %_llgo_1, label %_llgo_2 - -_llgo_1: ; preds = %_llgo_0 - call void @"github.com/goplus/llgo/cl/_testdata/print.printstring"(%"github.com/goplus/llgo/runtime/internal/runtime.String" { ptr @29, i64 1 }) - %2 = sub i64 0, %0 - br label %_llgo_2 - -_llgo_2: ; preds = %_llgo_1, %_llgo_0 - %3 = phi i64 [ %0, %_llgo_0 ], [ %2, %_llgo_1 ] - call void @"github.com/goplus/llgo/cl/_testdata/print.printuint"(i64 %3) - ret void -} - -define void @"github.com/goplus/llgo/cl/_testdata/print.println"(%"github.com/goplus/llgo/runtime/internal/runtime.Slice" %0) { -_llgo_0: - %1 = extractvalue %"github.com/goplus/llgo/runtime/internal/runtime.Slice" %0, 1 - br label %_llgo_1 - -_llgo_1: ; preds = %_llgo_5, %_llgo_0 - %2 = phi i64 [ -1, %_llgo_0 ], [ %3, %_llgo_5 ] - %3 = add i64 %2, 1 - %4 = icmp slt i64 %3, %1 - br i1 %4, label %_llgo_2, label %_llgo_3 - -_llgo_2: ; preds = %_llgo_1 - %5 = extractvalue %"github.com/goplus/llgo/runtime/internal/runtime.Slice" %0, 0 - %6 = extractvalue %"github.com/goplus/llgo/runtime/internal/runtime.Slice" %0, 1 - %7 = icmp slt i64 %3, 0 - %8 = icmp uge i64 %3, %6 - %9 = or i1 %8, %7 - call void @"github.com/goplus/llgo/runtime/internal/runtime.AssertIndexRange"(i1 %9) - %10 = getelementptr inbounds %"github.com/goplus/llgo/runtime/internal/runtime.eface", ptr %5, i64 %3 - %11 = load %"github.com/goplus/llgo/runtime/internal/runtime.eface", ptr %10, align 8 - %12 = icmp ne i64 %3, 0 - br i1 %12, label %_llgo_4, label %_llgo_5 - -_llgo_3: ; preds = %_llgo_1 - call void @"github.com/goplus/llgo/cl/_testdata/print.printnl"() - ret void - -_llgo_4: ; preds = %_llgo_2 - call void @"github.com/goplus/llgo/cl/_testdata/print.printstring"(%"github.com/goplus/llgo/runtime/internal/runtime.String" { ptr @30, i64 1 }) - br label %_llgo_5 - -_llgo_5: ; preds = %_llgo_4, %_llgo_2 - call void @"github.com/goplus/llgo/cl/_testdata/print.printany"(%"github.com/goplus/llgo/runtime/internal/runtime.eface" %11) - br label %_llgo_1 -} - -define void @"github.com/goplus/llgo/cl/_testdata/print.printnl"() { -_llgo_0: - call void @"github.com/goplus/llgo/cl/_testdata/print.printstring"(%"github.com/goplus/llgo/runtime/internal/runtime.String" { ptr @31, i64 1 }) - ret void -} - -define void @"github.com/goplus/llgo/cl/_testdata/print.printsp"() { -_llgo_0: - call void @"github.com/goplus/llgo/cl/_testdata/print.printstring"(%"github.com/goplus/llgo/runtime/internal/runtime.String" { ptr @30, i64 1 }) - ret void -} - -define void @"github.com/goplus/llgo/cl/_testdata/print.printstring"(%"github.com/goplus/llgo/runtime/internal/runtime.String" %0) { -_llgo_0: - %1 = call %"github.com/goplus/llgo/runtime/internal/runtime.Slice" @"github.com/goplus/llgo/cl/_testdata/print.bytes"(%"github.com/goplus/llgo/runtime/internal/runtime.String" %0) - call void @"github.com/goplus/llgo/cl/_testdata/print.gwrite"(%"github.com/goplus/llgo/runtime/internal/runtime.Slice" %1) - ret void -} - -define void @"github.com/goplus/llgo/cl/_testdata/print.printuint"(i64 %0) { -_llgo_0: - %1 = call ptr @"github.com/goplus/llgo/runtime/internal/runtime.AllocZ"(i64 100) - br label %_llgo_3 - -_llgo_1: ; preds = %_llgo_3 - %2 = urem i64 %11, 10 - %3 = add i64 %2, 48 - %4 = trunc i64 %3 to i8 - %5 = icmp slt i64 %12, 0 - %6 = icmp uge i64 %12, 100 - %7 = or i1 %6, %5 - call void @"github.com/goplus/llgo/runtime/internal/runtime.AssertIndexRange"(i1 %7) - %8 = getelementptr inbounds i8, ptr %1, i64 %12 - store i8 %4, ptr %8, align 1 - %9 = icmp ult i64 %11, 10 - br i1 %9, label %_llgo_2, label %_llgo_4 - -_llgo_2: ; preds = %_llgo_1, %_llgo_3 - %10 = call %"github.com/goplus/llgo/runtime/internal/runtime.Slice" @"github.com/goplus/llgo/runtime/internal/runtime.NewSlice3"(ptr %1, i64 1, i64 100, i64 %12, i64 100, i64 100) - call void @"github.com/goplus/llgo/cl/_testdata/print.gwrite"(%"github.com/goplus/llgo/runtime/internal/runtime.Slice" %10) - ret void - -_llgo_3: ; preds = %_llgo_4, %_llgo_0 - %11 = phi i64 [ %0, %_llgo_0 ], [ %14, %_llgo_4 ] - %12 = phi i64 [ 99, %_llgo_0 ], [ %15, %_llgo_4 ] - %13 = icmp sgt i64 %12, 0 - br i1 %13, label %_llgo_1, label %_llgo_2 - -_llgo_4: ; preds = %_llgo_1 - %14 = udiv i64 %11, 10 - %15 = sub i64 %12, 1 - br label %_llgo_3 -} - -define void @"github.com/goplus/llgo/cl/_testdata/print.prinusub"(i64 %0) { -_llgo_0: - %1 = sub i64 0, %0 - call void @"github.com/goplus/llgo/cl/_testdata/print.printuint"(i64 %1) - ret void -} - -define void @"github.com/goplus/llgo/cl/_testdata/print.prinxor"(i64 %0) { -_llgo_0: - %1 = xor i64 %0, -1 - call void @"github.com/goplus/llgo/cl/_testdata/print.printint"(i64 %1) - ret void -} - -define ptr @"github.com/goplus/llgo/cl/_testdata/print.stringStructOf"(ptr %0) { -_llgo_0: - ret ptr %0 -} - -declare ptr @"github.com/goplus/llgo/runtime/internal/runtime.AllocZ"(i64) - -declare void @"github.com/goplus/llgo/runtime/internal/runtime.AssertIndexRange"(i1) - -declare i32 @printf(ptr, ...) - -declare i1 @"github.com/goplus/llgo/runtime/internal/runtime.f32equal"(ptr, ptr) - -define linkonce i1 @"__llgo_stub.github.com/goplus/llgo/runtime/internal/runtime.f32equal"(ptr %0, ptr %1, ptr %2) { -_llgo_0: - %3 = tail call i1 @"github.com/goplus/llgo/runtime/internal/runtime.f32equal"(ptr %1, ptr %2) - ret i1 %3 -} - -declare i1 @"github.com/goplus/llgo/runtime/internal/runtime.memequalptr"(ptr, ptr) - -define linkonce i1 @"__llgo_stub.github.com/goplus/llgo/runtime/internal/runtime.memequalptr"(ptr %0, ptr %1, ptr %2) { -_llgo_0: - %3 = tail call i1 @"github.com/goplus/llgo/runtime/internal/runtime.memequalptr"(ptr %1, ptr %2) - ret i1 %3 -} - -declare ptr @"github.com/goplus/llgo/runtime/internal/runtime.AllocU"(i64) - -declare i1 @"github.com/goplus/llgo/runtime/internal/runtime.f64equal"(ptr, ptr) - -define linkonce i1 @"__llgo_stub.github.com/goplus/llgo/runtime/internal/runtime.f64equal"(ptr %0, ptr %1, ptr %2) { -_llgo_0: - %3 = tail call i1 @"github.com/goplus/llgo/runtime/internal/runtime.f64equal"(ptr %1, ptr %2) - ret i1 %3 -} - -declare i1 @"github.com/goplus/llgo/runtime/internal/runtime.strequal"(ptr, ptr) - -define linkonce i1 @"__llgo_stub.github.com/goplus/llgo/runtime/internal/runtime.strequal"(ptr %0, ptr %1, ptr %2) { -_llgo_0: - %3 = tail call i1 @"github.com/goplus/llgo/runtime/internal/runtime.strequal"(ptr %1, ptr %2) - ret i1 %3 -} - -declare i1 @"github.com/goplus/llgo/runtime/internal/runtime.memequal8"(ptr, ptr) - -define linkonce i1 @"__llgo_stub.github.com/goplus/llgo/runtime/internal/runtime.memequal8"(ptr %0, ptr %1, ptr %2) { -_llgo_0: - %3 = tail call i1 @"github.com/goplus/llgo/runtime/internal/runtime.memequal8"(ptr %1, ptr %2) - ret i1 %3 -} - -declare i1 @"github.com/goplus/llgo/runtime/internal/runtime.memequal32"(ptr, ptr) - -define linkonce i1 @"__llgo_stub.github.com/goplus/llgo/runtime/internal/runtime.memequal32"(ptr %0, ptr %1, ptr %2) { -_llgo_0: - %3 = tail call i1 @"github.com/goplus/llgo/runtime/internal/runtime.memequal32"(ptr %1, ptr %2) - ret i1 %3 -} - -declare i1 @"github.com/goplus/llgo/runtime/internal/runtime.memequal16"(ptr, ptr) - -define linkonce i1 @"__llgo_stub.github.com/goplus/llgo/runtime/internal/runtime.memequal16"(ptr %0, ptr %1, ptr %2) { -_llgo_0: - %3 = tail call i1 @"github.com/goplus/llgo/runtime/internal/runtime.memequal16"(ptr %1, ptr %2) - ret i1 %3 -} - -declare i1 @"github.com/goplus/llgo/runtime/internal/runtime.memequal64"(ptr, ptr) - -define linkonce i1 @"__llgo_stub.github.com/goplus/llgo/runtime/internal/runtime.memequal64"(ptr %0, ptr %1, ptr %2) { -_llgo_0: - %3 = tail call i1 @"github.com/goplus/llgo/runtime/internal/runtime.memequal64"(ptr %1, ptr %2) - ret i1 %3 -} - -declare i1 @"github.com/goplus/llgo/runtime/internal/runtime.c128equal"(ptr, ptr) - -define linkonce i1 @"__llgo_stub.github.com/goplus/llgo/runtime/internal/runtime.c128equal"(ptr %0, ptr %1, ptr %2) { -_llgo_0: - %3 = tail call i1 @"github.com/goplus/llgo/runtime/internal/runtime.c128equal"(ptr %1, ptr %2) - ret i1 %3 -} - -declare i1 @"github.com/goplus/llgo/runtime/internal/runtime.c64equal"(ptr, ptr) - -define linkonce i1 @"__llgo_stub.github.com/goplus/llgo/runtime/internal/runtime.c64equal"(ptr %0, ptr %1, ptr %2) { -_llgo_0: - %3 = tail call i1 @"github.com/goplus/llgo/runtime/internal/runtime.c64equal"(ptr %1, ptr %2) - ret i1 %3 -} - -declare %"github.com/goplus/llgo/runtime/internal/runtime.Slice" @"github.com/goplus/llgo/runtime/internal/runtime.NewSlice3"(ptr, i64, i64, i64, i64, i64) diff --git a/cl/_testdata/vargs/in.go b/cl/_testdata/vargs/in.go index 804a8d9eef..8a9f6901ee 100644 --- a/cl/_testdata/vargs/in.go +++ b/cl/_testdata/vargs/in.go @@ -91,9 +91,3 @@ func test(a ...any) { // CHECK-NEXT: call void @"{{.*}}/runtime/internal/runtime.PanicTypeAssert"(ptr %12, %"{{.*}}/runtime/internal/runtime.String" { ptr @0, i64 3 }, %"{{.*}}/runtime/internal/runtime.String" zeroinitializer) // CHECK-NEXT: unreachable // CHECK-NEXT: } - -// CHECK-LABEL: define linkonce i1 @"__llgo_stub.{{.*}}/runtime/internal/runtime.memequal64"(ptr %0, ptr %1, ptr %2){{.*}} { -// CHECK-NEXT: _llgo_0: -// CHECK-NEXT: %3 = tail call i1 @"{{.*}}/runtime/internal/runtime.memequal64"(ptr %1, ptr %2) -// CHECK-NEXT: ret i1 %3 -// CHECK-NEXT: } diff --git a/cl/_testgo/abimethod/in.go b/cl/_testgo/abimethod/in.go index fbd6f43e77..37d16f8c6d 100644 --- a/cl/_testgo/abimethod/in.go +++ b/cl/_testgo/abimethod/in.go @@ -913,78 +913,6 @@ type I2 interface { // CHECK-NEXT: ret i64 %4 // CHECK-NEXT: } -// CHECK-LABEL: define linkonce i1 @"__llgo_stub.{{.*}}/runtime/internal/runtime.memequal64"(ptr %0, ptr %1, ptr %2){{.*}} { -// CHECK-NEXT: _llgo_0: -// CHECK-NEXT: %3 = tail call i1 @"{{.*}}/runtime/internal/runtime.memequal64"(ptr %1, ptr %2) -// CHECK-NEXT: ret i1 %3 -// CHECK-NEXT: } - -// CHECK-LABEL: define linkonce i64 @__llgo_stub.main.T.Demo1(ptr %0, %main.T %1){{.*}} { -// CHECK-NEXT: _llgo_0: -// CHECK-NEXT: %2 = tail call i64 @main.T.Demo1(%main.T %1) -// CHECK-NEXT: ret i64 %2 -// CHECK-NEXT: } - -// CHECK-LABEL: define linkonce i64 @"__llgo_stub.main.(*T).Demo1"(ptr %0, ptr %1){{.*}} { -// CHECK-NEXT: _llgo_0: -// CHECK-NEXT: %2 = tail call i64 @"main.(*T).Demo1"(ptr %1) -// CHECK-NEXT: ret i64 %2 -// CHECK-NEXT: } - -// CHECK-LABEL: define linkonce i64 @"__llgo_stub.main.(*T).Demo2"(ptr %0, ptr %1){{.*}} { -// CHECK-NEXT: _llgo_0: -// CHECK-NEXT: %2 = tail call i64 @"main.(*T).Demo2"(ptr %1) -// CHECK-NEXT: ret i64 %2 -// CHECK-NEXT: } - -// CHECK-LABEL: define linkonce i64 @"__llgo_stub.main.(*T).demo3"(ptr %0, ptr %1){{.*}} { -// CHECK-NEXT: _llgo_0: -// CHECK-NEXT: %2 = tail call i64 @"main.(*T).demo3"(ptr %1) -// CHECK-NEXT: ret i64 %2 -// CHECK-NEXT: } - -// CHECK-LABEL: define linkonce i64 @"__llgo_stub.main.struct{m int; *main.T}.Demo1"(ptr %0, { i64, ptr } %1){{.*}} { -// CHECK-NEXT: _llgo_0: -// CHECK-NEXT: %2 = tail call i64 @"main.struct{m int; *main.T}.Demo1"({ i64, ptr } %1) -// CHECK-NEXT: ret i64 %2 -// CHECK-NEXT: } - -// CHECK-LABEL: define linkonce i64 @"__llgo_stub.main.struct{m int; *main.T}.Demo2"(ptr %0, { i64, ptr } %1){{.*}} { -// CHECK-NEXT: _llgo_0: -// CHECK-NEXT: %2 = tail call i64 @"main.struct{m int; *main.T}.Demo2"({ i64, ptr } %1) -// CHECK-NEXT: ret i64 %2 -// CHECK-NEXT: } - -// CHECK-LABEL: define linkonce i64 @"__llgo_stub.main.struct{m int; *main.T}.demo3"(ptr %0, { i64, ptr } %1){{.*}} { -// CHECK-NEXT: _llgo_0: -// CHECK-NEXT: %2 = tail call i64 @"main.struct{m int; *main.T}.demo3"({ i64, ptr } %1) -// CHECK-NEXT: ret i64 %2 -// CHECK-NEXT: } - -// CHECK-LABEL: define linkonce i64 @"__llgo_stub.main.*struct{m int; *main.T}.Demo1"(ptr %0, ptr %1){{.*}} { -// CHECK-NEXT: _llgo_0: -// CHECK-NEXT: %2 = tail call i64 @"main.*struct{m int; *main.T}.Demo1"(ptr %1) -// CHECK-NEXT: ret i64 %2 -// CHECK-NEXT: } - -// CHECK-LABEL: define linkonce i64 @"__llgo_stub.main.*struct{m int; *main.T}.Demo2"(ptr %0, ptr %1){{.*}} { -// CHECK-NEXT: _llgo_0: -// CHECK-NEXT: %2 = tail call i64 @"main.*struct{m int; *main.T}.Demo2"(ptr %1) -// CHECK-NEXT: ret i64 %2 -// CHECK-NEXT: } - -// CHECK-LABEL: define linkonce i64 @"__llgo_stub.main.*struct{m int; *main.T}.demo3"(ptr %0, ptr %1){{.*}} { -// CHECK-NEXT: _llgo_0: -// CHECK-NEXT: %2 = tail call i64 @"main.*struct{m int; *main.T}.demo3"(ptr %1) -// CHECK-NEXT: ret i64 %2 -// CHECK-NEXT: } - -// CHECK-LABEL: define linkonce i1 @"__llgo_stub.{{.*}}/runtime/internal/runtime.interequal"(ptr %0, ptr %1, ptr %2){{.*}} { -// CHECK-NEXT: _llgo_0: -// CHECK-NEXT: %3 = tail call i1 @"{{.*}}/runtime/internal/runtime.interequal"(ptr %1, ptr %2) -// CHECK-NEXT: ret i1 %3 -// CHECK-NEXT: } - // CHECK-LABEL: define i64 @"main.struct{m int; main.T}.Demo1"({ i64, %main.T } %0){{.*}} { // CHECK-NEXT: _llgo_0: // CHECK-NEXT: %1 = alloca { i64, %main.T }, align 8 @@ -1021,30 +949,6 @@ type I2 interface { // CHECK-NEXT: ret i64 %2 // CHECK-NEXT: } -// CHECK-LABEL: define linkonce i64 @"__llgo_stub.main.*struct{m int; main.T}.Demo1"(ptr %0, ptr %1){{.*}} { -// CHECK-NEXT: _llgo_0: -// CHECK-NEXT: %2 = tail call i64 @"main.*struct{m int; main.T}.Demo1"(ptr %1) -// CHECK-NEXT: ret i64 %2 -// CHECK-NEXT: } - -// CHECK-LABEL: define linkonce i64 @"__llgo_stub.main.*struct{m int; main.T}.Demo2"(ptr %0, ptr %1){{.*}} { -// CHECK-NEXT: _llgo_0: -// CHECK-NEXT: %2 = tail call i64 @"main.*struct{m int; main.T}.Demo2"(ptr %1) -// CHECK-NEXT: ret i64 %2 -// CHECK-NEXT: } - -// CHECK-LABEL: define linkonce i64 @"__llgo_stub.main.*struct{m int; main.T}.demo3"(ptr %0, ptr %1){{.*}} { -// CHECK-NEXT: _llgo_0: -// CHECK-NEXT: %2 = tail call i64 @"main.*struct{m int; main.T}.demo3"(ptr %1) -// CHECK-NEXT: ret i64 %2 -// CHECK-NEXT: } - -// CHECK-LABEL: define linkonce i64 @"__llgo_stub.main.struct{m int; main.T}.Demo1"(ptr %0, { i64, %main.T } %1){{.*}} { -// CHECK-NEXT: _llgo_0: -// CHECK-NEXT: %2 = tail call i64 @"main.struct{m int; main.T}.Demo1"({ i64, %main.T } %1) -// CHECK-NEXT: ret i64 %2 -// CHECK-NEXT: } - // CHECK-LABEL: define i64 @"main.*struct{m int; *bytes.Buffer}.Available"(ptr %0){{.*}} { // CHECK-NEXT: _llgo_0: // CHECK-NEXT: %1 = getelementptr inbounds { i64, ptr }, ptr %0, i32 0, i32 1 @@ -1658,498 +1562,6 @@ type I2 interface { // CHECK-NEXT: ret { i64, i1 } %9 // CHECK-NEXT: } -// CHECK-LABEL: define linkonce i1 @"__llgo_stub.{{.*}}/runtime/internal/runtime.memequal8"(ptr %0, ptr %1, ptr %2){{.*}} { -// CHECK-NEXT: _llgo_0: -// CHECK-NEXT: %3 = tail call i1 @"{{.*}}/runtime/internal/runtime.memequal8"(ptr %1, ptr %2) -// CHECK-NEXT: ret i1 %3 -// CHECK-NEXT: } - -// CHECK-LABEL: define linkonce i64 @"__llgo_stub.bytes.(*Buffer).Available"(ptr %0, ptr %1){{.*}} { -// CHECK-NEXT: _llgo_0: -// CHECK-NEXT: %2 = tail call i64 @"bytes.(*Buffer).Available"(ptr %1) -// CHECK-NEXT: ret i64 %2 -// CHECK-NEXT: } - -// CHECK-LABEL: define linkonce %"{{.*}}/runtime/internal/runtime.Slice" @"__llgo_stub.bytes.(*Buffer).AvailableBuffer"(ptr %0, ptr %1){{.*}} { -// CHECK-NEXT: _llgo_0: -// CHECK-NEXT: %2 = tail call %"{{.*}}/runtime/internal/runtime.Slice" @"bytes.(*Buffer).AvailableBuffer"(ptr %1) -// CHECK-NEXT: ret %"{{.*}}/runtime/internal/runtime.Slice" %2 -// CHECK-NEXT: } - -// CHECK-LABEL: define linkonce %"{{.*}}/runtime/internal/runtime.Slice" @"__llgo_stub.bytes.(*Buffer).Bytes"(ptr %0, ptr %1){{.*}} { -// CHECK-NEXT: _llgo_0: -// CHECK-NEXT: %2 = tail call %"{{.*}}/runtime/internal/runtime.Slice" @"bytes.(*Buffer).Bytes"(ptr %1) -// CHECK-NEXT: ret %"{{.*}}/runtime/internal/runtime.Slice" %2 -// CHECK-NEXT: } - -// CHECK-LABEL: define linkonce i64 @"__llgo_stub.bytes.(*Buffer).Cap"(ptr %0, ptr %1){{.*}} { -// CHECK-NEXT: _llgo_0: -// CHECK-NEXT: %2 = tail call i64 @"bytes.(*Buffer).Cap"(ptr %1) -// CHECK-NEXT: ret i64 %2 -// CHECK-NEXT: } - -// CHECK-LABEL: define linkonce void @"__llgo_stub.bytes.(*Buffer).Grow"(ptr %0, ptr %1, i64 %2){{.*}} { -// CHECK-NEXT: _llgo_0: -// CHECK-NEXT: tail call void @"bytes.(*Buffer).Grow"(ptr %1, i64 %2) -// CHECK-NEXT: ret void -// CHECK-NEXT: } - -// CHECK-LABEL: define linkonce i64 @"__llgo_stub.bytes.(*Buffer).Len"(ptr %0, ptr %1){{.*}} { -// CHECK-NEXT: _llgo_0: -// CHECK-NEXT: %2 = tail call i64 @"bytes.(*Buffer).Len"(ptr %1) -// CHECK-NEXT: ret i64 %2 -// CHECK-NEXT: } - -// CHECK-LABEL: define linkonce %"{{.*}}/runtime/internal/runtime.Slice" @"__llgo_stub.bytes.(*Buffer).Next"(ptr %0, ptr %1, i64 %2){{.*}} { -// CHECK-NEXT: _llgo_0: -// CHECK-NEXT: %3 = tail call %"{{.*}}/runtime/internal/runtime.Slice" @"bytes.(*Buffer).Next"(ptr %1, i64 %2) -// CHECK-NEXT: ret %"{{.*}}/runtime/internal/runtime.Slice" %3 -// CHECK-NEXT: } - -// CHECK-LABEL: define linkonce { i64, %"{{.*}}/runtime/internal/runtime.iface" } @"__llgo_stub.bytes.(*Buffer).Read"(ptr %0, ptr %1, %"{{.*}}/runtime/internal/runtime.Slice" %2){{.*}} { -// CHECK-NEXT: _llgo_0: -// CHECK-NEXT: %3 = tail call { i64, %"{{.*}}/runtime/internal/runtime.iface" } @"bytes.(*Buffer).Read"(ptr %1, %"{{.*}}/runtime/internal/runtime.Slice" %2) -// CHECK-NEXT: ret { i64, %"{{.*}}/runtime/internal/runtime.iface" } %3 -// CHECK-NEXT: } - -// CHECK-LABEL: define linkonce { i8, %"{{.*}}/runtime/internal/runtime.iface" } @"__llgo_stub.bytes.(*Buffer).ReadByte"(ptr %0, ptr %1){{.*}} { -// CHECK-NEXT: _llgo_0: -// CHECK-NEXT: %2 = tail call { i8, %"{{.*}}/runtime/internal/runtime.iface" } @"bytes.(*Buffer).ReadByte"(ptr %1) -// CHECK-NEXT: ret { i8, %"{{.*}}/runtime/internal/runtime.iface" } %2 -// CHECK-NEXT: } - -// CHECK-LABEL: define linkonce { %"{{.*}}/runtime/internal/runtime.Slice", %"{{.*}}/runtime/internal/runtime.iface" } @"__llgo_stub.bytes.(*Buffer).ReadBytes"(ptr %0, ptr %1, i8 %2){{.*}} { -// CHECK-NEXT: _llgo_0: -// CHECK-NEXT: %3 = tail call { %"{{.*}}/runtime/internal/runtime.Slice", %"{{.*}}/runtime/internal/runtime.iface" } @"bytes.(*Buffer).ReadBytes"(ptr %1, i8 %2) -// CHECK-NEXT: ret { %"{{.*}}/runtime/internal/runtime.Slice", %"{{.*}}/runtime/internal/runtime.iface" } %3 -// CHECK-NEXT: } - -// CHECK-LABEL: define linkonce { i64, %"{{.*}}/runtime/internal/runtime.iface" } @"__llgo_stub.bytes.(*Buffer).ReadFrom"(ptr %0, ptr %1, %"{{.*}}/runtime/internal/runtime.iface" %2){{.*}} { -// CHECK-NEXT: _llgo_0: -// CHECK-NEXT: %3 = tail call { i64, %"{{.*}}/runtime/internal/runtime.iface" } @"bytes.(*Buffer).ReadFrom"(ptr %1, %"{{.*}}/runtime/internal/runtime.iface" %2) -// CHECK-NEXT: ret { i64, %"{{.*}}/runtime/internal/runtime.iface" } %3 -// CHECK-NEXT: } - -// CHECK-LABEL: define linkonce { i32, i64, %"{{.*}}/runtime/internal/runtime.iface" } @"__llgo_stub.bytes.(*Buffer).ReadRune"(ptr %0, ptr %1){{.*}} { -// CHECK-NEXT: _llgo_0: -// CHECK-NEXT: %2 = tail call { i32, i64, %"{{.*}}/runtime/internal/runtime.iface" } @"bytes.(*Buffer).ReadRune"(ptr %1) -// CHECK-NEXT: ret { i32, i64, %"{{.*}}/runtime/internal/runtime.iface" } %2 -// CHECK-NEXT: } - -// CHECK-LABEL: define linkonce { %"{{.*}}/runtime/internal/runtime.String", %"{{.*}}/runtime/internal/runtime.iface" } @"__llgo_stub.bytes.(*Buffer).ReadString"(ptr %0, ptr %1, i8 %2){{.*}} { -// CHECK-NEXT: _llgo_0: -// CHECK-NEXT: %3 = tail call { %"{{.*}}/runtime/internal/runtime.String", %"{{.*}}/runtime/internal/runtime.iface" } @"bytes.(*Buffer).ReadString"(ptr %1, i8 %2) -// CHECK-NEXT: ret { %"{{.*}}/runtime/internal/runtime.String", %"{{.*}}/runtime/internal/runtime.iface" } %3 -// CHECK-NEXT: } - -// CHECK-LABEL: define linkonce void @"__llgo_stub.bytes.(*Buffer).Reset"(ptr %0, ptr %1){{.*}} { -// CHECK-NEXT: _llgo_0: -// CHECK-NEXT: tail call void @"bytes.(*Buffer).Reset"(ptr %1) -// CHECK-NEXT: ret void -// CHECK-NEXT: } - -// CHECK-LABEL: define linkonce %"{{.*}}/runtime/internal/runtime.String" @"__llgo_stub.bytes.(*Buffer).String"(ptr %0, ptr %1){{.*}} { -// CHECK-NEXT: _llgo_0: -// CHECK-NEXT: %2 = tail call %"{{.*}}/runtime/internal/runtime.String" @"bytes.(*Buffer).String"(ptr %1) -// CHECK-NEXT: ret %"{{.*}}/runtime/internal/runtime.String" %2 -// CHECK-NEXT: } - -// CHECK-LABEL: define linkonce void @"__llgo_stub.bytes.(*Buffer).Truncate"(ptr %0, ptr %1, i64 %2){{.*}} { -// CHECK-NEXT: _llgo_0: -// CHECK-NEXT: tail call void @"bytes.(*Buffer).Truncate"(ptr %1, i64 %2) -// CHECK-NEXT: ret void -// CHECK-NEXT: } - -// CHECK-LABEL: define linkonce %"{{.*}}/runtime/internal/runtime.iface" @"__llgo_stub.bytes.(*Buffer).UnreadByte"(ptr %0, ptr %1){{.*}} { -// CHECK-NEXT: _llgo_0: -// CHECK-NEXT: %2 = tail call %"{{.*}}/runtime/internal/runtime.iface" @"bytes.(*Buffer).UnreadByte"(ptr %1) -// CHECK-NEXT: ret %"{{.*}}/runtime/internal/runtime.iface" %2 -// CHECK-NEXT: } - -// CHECK-LABEL: define linkonce %"{{.*}}/runtime/internal/runtime.iface" @"__llgo_stub.bytes.(*Buffer).UnreadRune"(ptr %0, ptr %1){{.*}} { -// CHECK-NEXT: _llgo_0: -// CHECK-NEXT: %2 = tail call %"{{.*}}/runtime/internal/runtime.iface" @"bytes.(*Buffer).UnreadRune"(ptr %1) -// CHECK-NEXT: ret %"{{.*}}/runtime/internal/runtime.iface" %2 -// CHECK-NEXT: } - -// CHECK-LABEL: define linkonce { i64, %"{{.*}}/runtime/internal/runtime.iface" } @"__llgo_stub.bytes.(*Buffer).Write"(ptr %0, ptr %1, %"{{.*}}/runtime/internal/runtime.Slice" %2){{.*}} { -// CHECK-NEXT: _llgo_0: -// CHECK-NEXT: %3 = tail call { i64, %"{{.*}}/runtime/internal/runtime.iface" } @"bytes.(*Buffer).Write"(ptr %1, %"{{.*}}/runtime/internal/runtime.Slice" %2) -// CHECK-NEXT: ret { i64, %"{{.*}}/runtime/internal/runtime.iface" } %3 -// CHECK-NEXT: } - -// CHECK-LABEL: define linkonce %"{{.*}}/runtime/internal/runtime.iface" @"__llgo_stub.bytes.(*Buffer).WriteByte"(ptr %0, ptr %1, i8 %2){{.*}} { -// CHECK-NEXT: _llgo_0: -// CHECK-NEXT: %3 = tail call %"{{.*}}/runtime/internal/runtime.iface" @"bytes.(*Buffer).WriteByte"(ptr %1, i8 %2) -// CHECK-NEXT: ret %"{{.*}}/runtime/internal/runtime.iface" %3 -// CHECK-NEXT: } - -// CHECK-LABEL: define linkonce { i64, %"{{.*}}/runtime/internal/runtime.iface" } @"__llgo_stub.bytes.(*Buffer).WriteRune"(ptr %0, ptr %1, i32 %2){{.*}} { -// CHECK-NEXT: _llgo_0: -// CHECK-NEXT: %3 = tail call { i64, %"{{.*}}/runtime/internal/runtime.iface" } @"bytes.(*Buffer).WriteRune"(ptr %1, i32 %2) -// CHECK-NEXT: ret { i64, %"{{.*}}/runtime/internal/runtime.iface" } %3 -// CHECK-NEXT: } - -// CHECK-LABEL: define linkonce { i64, %"{{.*}}/runtime/internal/runtime.iface" } @"__llgo_stub.bytes.(*Buffer).WriteString"(ptr %0, ptr %1, %"{{.*}}/runtime/internal/runtime.String" %2){{.*}} { -// CHECK-NEXT: _llgo_0: -// CHECK-NEXT: %3 = tail call { i64, %"{{.*}}/runtime/internal/runtime.iface" } @"bytes.(*Buffer).WriteString"(ptr %1, %"{{.*}}/runtime/internal/runtime.String" %2) -// CHECK-NEXT: ret { i64, %"{{.*}}/runtime/internal/runtime.iface" } %3 -// CHECK-NEXT: } - -// CHECK-LABEL: define linkonce { i64, %"{{.*}}/runtime/internal/runtime.iface" } @"__llgo_stub.bytes.(*Buffer).WriteTo"(ptr %0, ptr %1, %"{{.*}}/runtime/internal/runtime.iface" %2){{.*}} { -// CHECK-NEXT: _llgo_0: -// CHECK-NEXT: %3 = tail call { i64, %"{{.*}}/runtime/internal/runtime.iface" } @"bytes.(*Buffer).WriteTo"(ptr %1, %"{{.*}}/runtime/internal/runtime.iface" %2) -// CHECK-NEXT: ret { i64, %"{{.*}}/runtime/internal/runtime.iface" } %3 -// CHECK-NEXT: } - -// CHECK-LABEL: define linkonce i1 @"__llgo_stub.bytes.(*Buffer).empty"(ptr %0, ptr %1){{.*}} { -// CHECK-NEXT: _llgo_0: -// CHECK-NEXT: %2 = tail call i1 @"bytes.(*Buffer).empty"(ptr %1) -// CHECK-NEXT: ret i1 %2 -// CHECK-NEXT: } - -// CHECK-LABEL: define linkonce i64 @"__llgo_stub.bytes.(*Buffer).grow"(ptr %0, ptr %1, i64 %2){{.*}} { -// CHECK-NEXT: _llgo_0: -// CHECK-NEXT: %3 = tail call i64 @"bytes.(*Buffer).grow"(ptr %1, i64 %2) -// CHECK-NEXT: ret i64 %3 -// CHECK-NEXT: } - -// CHECK-LABEL: define linkonce { %"{{.*}}/runtime/internal/runtime.Slice", %"{{.*}}/runtime/internal/runtime.iface" } @"__llgo_stub.bytes.(*Buffer).readSlice"(ptr %0, ptr %1, i8 %2){{.*}} { -// CHECK-NEXT: _llgo_0: -// CHECK-NEXT: %3 = tail call { %"{{.*}}/runtime/internal/runtime.Slice", %"{{.*}}/runtime/internal/runtime.iface" } @"bytes.(*Buffer).readSlice"(ptr %1, i8 %2) -// CHECK-NEXT: ret { %"{{.*}}/runtime/internal/runtime.Slice", %"{{.*}}/runtime/internal/runtime.iface" } %3 -// CHECK-NEXT: } - -// CHECK-LABEL: define linkonce { i64, i1 } @"__llgo_stub.bytes.(*Buffer).tryGrowByReslice"(ptr %0, ptr %1, i64 %2){{.*}} { -// CHECK-NEXT: _llgo_0: -// CHECK-NEXT: %3 = tail call { i64, i1 } @"bytes.(*Buffer).tryGrowByReslice"(ptr %1, i64 %2) -// CHECK-NEXT: ret { i64, i1 } %3 -// CHECK-NEXT: } - -// CHECK-LABEL: define linkonce i64 @"__llgo_stub.main.struct{m int; *bytes.Buffer}.Available"(ptr %0, { i64, ptr } %1){{.*}} { -// CHECK-NEXT: _llgo_0: -// CHECK-NEXT: %2 = tail call i64 @"main.struct{m int; *bytes.Buffer}.Available"({ i64, ptr } %1) -// CHECK-NEXT: ret i64 %2 -// CHECK-NEXT: } - -// CHECK-LABEL: define linkonce %"{{.*}}/runtime/internal/runtime.Slice" @"__llgo_stub.main.struct{m int; *bytes.Buffer}.AvailableBuffer"(ptr %0, { i64, ptr } %1){{.*}} { -// CHECK-NEXT: _llgo_0: -// CHECK-NEXT: %2 = tail call %"{{.*}}/runtime/internal/runtime.Slice" @"main.struct{m int; *bytes.Buffer}.AvailableBuffer"({ i64, ptr } %1) -// CHECK-NEXT: ret %"{{.*}}/runtime/internal/runtime.Slice" %2 -// CHECK-NEXT: } - -// CHECK-LABEL: define linkonce %"{{.*}}/runtime/internal/runtime.Slice" @"__llgo_stub.main.struct{m int; *bytes.Buffer}.Bytes"(ptr %0, { i64, ptr } %1){{.*}} { -// CHECK-NEXT: _llgo_0: -// CHECK-NEXT: %2 = tail call %"{{.*}}/runtime/internal/runtime.Slice" @"main.struct{m int; *bytes.Buffer}.Bytes"({ i64, ptr } %1) -// CHECK-NEXT: ret %"{{.*}}/runtime/internal/runtime.Slice" %2 -// CHECK-NEXT: } - -// CHECK-LABEL: define linkonce i64 @"__llgo_stub.main.struct{m int; *bytes.Buffer}.Cap"(ptr %0, { i64, ptr } %1){{.*}} { -// CHECK-NEXT: _llgo_0: -// CHECK-NEXT: %2 = tail call i64 @"main.struct{m int; *bytes.Buffer}.Cap"({ i64, ptr } %1) -// CHECK-NEXT: ret i64 %2 -// CHECK-NEXT: } - -// CHECK-LABEL: define linkonce void @"__llgo_stub.main.struct{m int; *bytes.Buffer}.Grow"(ptr %0, { i64, ptr } %1, i64 %2){{.*}} { -// CHECK-NEXT: _llgo_0: -// CHECK-NEXT: tail call void @"main.struct{m int; *bytes.Buffer}.Grow"({ i64, ptr } %1, i64 %2) -// CHECK-NEXT: ret void -// CHECK-NEXT: } - -// CHECK-LABEL: define linkonce i64 @"__llgo_stub.main.struct{m int; *bytes.Buffer}.Len"(ptr %0, { i64, ptr } %1){{.*}} { -// CHECK-NEXT: _llgo_0: -// CHECK-NEXT: %2 = tail call i64 @"main.struct{m int; *bytes.Buffer}.Len"({ i64, ptr } %1) -// CHECK-NEXT: ret i64 %2 -// CHECK-NEXT: } - -// CHECK-LABEL: define linkonce %"{{.*}}/runtime/internal/runtime.Slice" @"__llgo_stub.main.struct{m int; *bytes.Buffer}.Next"(ptr %0, { i64, ptr } %1, i64 %2){{.*}} { -// CHECK-NEXT: _llgo_0: -// CHECK-NEXT: %3 = tail call %"{{.*}}/runtime/internal/runtime.Slice" @"main.struct{m int; *bytes.Buffer}.Next"({ i64, ptr } %1, i64 %2) -// CHECK-NEXT: ret %"{{.*}}/runtime/internal/runtime.Slice" %3 -// CHECK-NEXT: } - -// CHECK-LABEL: define linkonce { i64, %"{{.*}}/runtime/internal/runtime.iface" } @"__llgo_stub.main.struct{m int; *bytes.Buffer}.Read"(ptr %0, { i64, ptr } %1, %"{{.*}}/runtime/internal/runtime.Slice" %2){{.*}} { -// CHECK-NEXT: _llgo_0: -// CHECK-NEXT: %3 = tail call { i64, %"{{.*}}/runtime/internal/runtime.iface" } @"main.struct{m int; *bytes.Buffer}.Read"({ i64, ptr } %1, %"{{.*}}/runtime/internal/runtime.Slice" %2) -// CHECK-NEXT: ret { i64, %"{{.*}}/runtime/internal/runtime.iface" } %3 -// CHECK-NEXT: } - -// CHECK-LABEL: define linkonce { i8, %"{{.*}}/runtime/internal/runtime.iface" } @"__llgo_stub.main.struct{m int; *bytes.Buffer}.ReadByte"(ptr %0, { i64, ptr } %1){{.*}} { -// CHECK-NEXT: _llgo_0: -// CHECK-NEXT: %2 = tail call { i8, %"{{.*}}/runtime/internal/runtime.iface" } @"main.struct{m int; *bytes.Buffer}.ReadByte"({ i64, ptr } %1) -// CHECK-NEXT: ret { i8, %"{{.*}}/runtime/internal/runtime.iface" } %2 -// CHECK-NEXT: } - -// CHECK-LABEL: define linkonce { %"{{.*}}/runtime/internal/runtime.Slice", %"{{.*}}/runtime/internal/runtime.iface" } @"__llgo_stub.main.struct{m int; *bytes.Buffer}.ReadBytes"(ptr %0, { i64, ptr } %1, i8 %2){{.*}} { -// CHECK-NEXT: _llgo_0: -// CHECK-NEXT: %3 = tail call { %"{{.*}}/runtime/internal/runtime.Slice", %"{{.*}}/runtime/internal/runtime.iface" } @"main.struct{m int; *bytes.Buffer}.ReadBytes"({ i64, ptr } %1, i8 %2) -// CHECK-NEXT: ret { %"{{.*}}/runtime/internal/runtime.Slice", %"{{.*}}/runtime/internal/runtime.iface" } %3 -// CHECK-NEXT: } - -// CHECK-LABEL: define linkonce { i64, %"{{.*}}/runtime/internal/runtime.iface" } @"__llgo_stub.main.struct{m int; *bytes.Buffer}.ReadFrom"(ptr %0, { i64, ptr } %1, %"{{.*}}/runtime/internal/runtime.iface" %2){{.*}} { -// CHECK-NEXT: _llgo_0: -// CHECK-NEXT: %3 = tail call { i64, %"{{.*}}/runtime/internal/runtime.iface" } @"main.struct{m int; *bytes.Buffer}.ReadFrom"({ i64, ptr } %1, %"{{.*}}/runtime/internal/runtime.iface" %2) -// CHECK-NEXT: ret { i64, %"{{.*}}/runtime/internal/runtime.iface" } %3 -// CHECK-NEXT: } - -// CHECK-LABEL: define linkonce { i32, i64, %"{{.*}}/runtime/internal/runtime.iface" } @"__llgo_stub.main.struct{m int; *bytes.Buffer}.ReadRune"(ptr %0, { i64, ptr } %1){{.*}} { -// CHECK-NEXT: _llgo_0: -// CHECK-NEXT: %2 = tail call { i32, i64, %"{{.*}}/runtime/internal/runtime.iface" } @"main.struct{m int; *bytes.Buffer}.ReadRune"({ i64, ptr } %1) -// CHECK-NEXT: ret { i32, i64, %"{{.*}}/runtime/internal/runtime.iface" } %2 -// CHECK-NEXT: } - -// CHECK-LABEL: define linkonce { %"{{.*}}/runtime/internal/runtime.String", %"{{.*}}/runtime/internal/runtime.iface" } @"__llgo_stub.main.struct{m int; *bytes.Buffer}.ReadString"(ptr %0, { i64, ptr } %1, i8 %2){{.*}} { -// CHECK-NEXT: _llgo_0: -// CHECK-NEXT: %3 = tail call { %"{{.*}}/runtime/internal/runtime.String", %"{{.*}}/runtime/internal/runtime.iface" } @"main.struct{m int; *bytes.Buffer}.ReadString"({ i64, ptr } %1, i8 %2) -// CHECK-NEXT: ret { %"{{.*}}/runtime/internal/runtime.String", %"{{.*}}/runtime/internal/runtime.iface" } %3 -// CHECK-NEXT: } - -// CHECK-LABEL: define linkonce void @"__llgo_stub.main.struct{m int; *bytes.Buffer}.Reset"(ptr %0, { i64, ptr } %1){{.*}} { -// CHECK-NEXT: _llgo_0: -// CHECK-NEXT: tail call void @"main.struct{m int; *bytes.Buffer}.Reset"({ i64, ptr } %1) -// CHECK-NEXT: ret void -// CHECK-NEXT: } - -// CHECK-LABEL: define linkonce %"{{.*}}/runtime/internal/runtime.String" @"__llgo_stub.main.struct{m int; *bytes.Buffer}.String"(ptr %0, { i64, ptr } %1){{.*}} { -// CHECK-NEXT: _llgo_0: -// CHECK-NEXT: %2 = tail call %"{{.*}}/runtime/internal/runtime.String" @"main.struct{m int; *bytes.Buffer}.String"({ i64, ptr } %1) -// CHECK-NEXT: ret %"{{.*}}/runtime/internal/runtime.String" %2 -// CHECK-NEXT: } - -// CHECK-LABEL: define linkonce void @"__llgo_stub.main.struct{m int; *bytes.Buffer}.Truncate"(ptr %0, { i64, ptr } %1, i64 %2){{.*}} { -// CHECK-NEXT: _llgo_0: -// CHECK-NEXT: tail call void @"main.struct{m int; *bytes.Buffer}.Truncate"({ i64, ptr } %1, i64 %2) -// CHECK-NEXT: ret void -// CHECK-NEXT: } - -// CHECK-LABEL: define linkonce %"{{.*}}/runtime/internal/runtime.iface" @"__llgo_stub.main.struct{m int; *bytes.Buffer}.UnreadByte"(ptr %0, { i64, ptr } %1){{.*}} { -// CHECK-NEXT: _llgo_0: -// CHECK-NEXT: %2 = tail call %"{{.*}}/runtime/internal/runtime.iface" @"main.struct{m int; *bytes.Buffer}.UnreadByte"({ i64, ptr } %1) -// CHECK-NEXT: ret %"{{.*}}/runtime/internal/runtime.iface" %2 -// CHECK-NEXT: } - -// CHECK-LABEL: define linkonce %"{{.*}}/runtime/internal/runtime.iface" @"__llgo_stub.main.struct{m int; *bytes.Buffer}.UnreadRune"(ptr %0, { i64, ptr } %1){{.*}} { -// CHECK-NEXT: _llgo_0: -// CHECK-NEXT: %2 = tail call %"{{.*}}/runtime/internal/runtime.iface" @"main.struct{m int; *bytes.Buffer}.UnreadRune"({ i64, ptr } %1) -// CHECK-NEXT: ret %"{{.*}}/runtime/internal/runtime.iface" %2 -// CHECK-NEXT: } - -// CHECK-LABEL: define linkonce { i64, %"{{.*}}/runtime/internal/runtime.iface" } @"__llgo_stub.main.struct{m int; *bytes.Buffer}.Write"(ptr %0, { i64, ptr } %1, %"{{.*}}/runtime/internal/runtime.Slice" %2){{.*}} { -// CHECK-NEXT: _llgo_0: -// CHECK-NEXT: %3 = tail call { i64, %"{{.*}}/runtime/internal/runtime.iface" } @"main.struct{m int; *bytes.Buffer}.Write"({ i64, ptr } %1, %"{{.*}}/runtime/internal/runtime.Slice" %2) -// CHECK-NEXT: ret { i64, %"{{.*}}/runtime/internal/runtime.iface" } %3 -// CHECK-NEXT: } - -// CHECK-LABEL: define linkonce %"{{.*}}/runtime/internal/runtime.iface" @"__llgo_stub.main.struct{m int; *bytes.Buffer}.WriteByte"(ptr %0, { i64, ptr } %1, i8 %2){{.*}} { -// CHECK-NEXT: _llgo_0: -// CHECK-NEXT: %3 = tail call %"{{.*}}/runtime/internal/runtime.iface" @"main.struct{m int; *bytes.Buffer}.WriteByte"({ i64, ptr } %1, i8 %2) -// CHECK-NEXT: ret %"{{.*}}/runtime/internal/runtime.iface" %3 -// CHECK-NEXT: } - -// CHECK-LABEL: define linkonce { i64, %"{{.*}}/runtime/internal/runtime.iface" } @"__llgo_stub.main.struct{m int; *bytes.Buffer}.WriteRune"(ptr %0, { i64, ptr } %1, i32 %2){{.*}} { -// CHECK-NEXT: _llgo_0: -// CHECK-NEXT: %3 = tail call { i64, %"{{.*}}/runtime/internal/runtime.iface" } @"main.struct{m int; *bytes.Buffer}.WriteRune"({ i64, ptr } %1, i32 %2) -// CHECK-NEXT: ret { i64, %"{{.*}}/runtime/internal/runtime.iface" } %3 -// CHECK-NEXT: } - -// CHECK-LABEL: define linkonce { i64, %"{{.*}}/runtime/internal/runtime.iface" } @"__llgo_stub.main.struct{m int; *bytes.Buffer}.WriteString"(ptr %0, { i64, ptr } %1, %"{{.*}}/runtime/internal/runtime.String" %2){{.*}} { -// CHECK-NEXT: _llgo_0: -// CHECK-NEXT: %3 = tail call { i64, %"{{.*}}/runtime/internal/runtime.iface" } @"main.struct{m int; *bytes.Buffer}.WriteString"({ i64, ptr } %1, %"{{.*}}/runtime/internal/runtime.String" %2) -// CHECK-NEXT: ret { i64, %"{{.*}}/runtime/internal/runtime.iface" } %3 -// CHECK-NEXT: } - -// CHECK-LABEL: define linkonce { i64, %"{{.*}}/runtime/internal/runtime.iface" } @"__llgo_stub.main.struct{m int; *bytes.Buffer}.WriteTo"(ptr %0, { i64, ptr } %1, %"{{.*}}/runtime/internal/runtime.iface" %2){{.*}} { -// CHECK-NEXT: _llgo_0: -// CHECK-NEXT: %3 = tail call { i64, %"{{.*}}/runtime/internal/runtime.iface" } @"main.struct{m int; *bytes.Buffer}.WriteTo"({ i64, ptr } %1, %"{{.*}}/runtime/internal/runtime.iface" %2) -// CHECK-NEXT: ret { i64, %"{{.*}}/runtime/internal/runtime.iface" } %3 -// CHECK-NEXT: } - -// CHECK-LABEL: define linkonce i1 @"__llgo_stub.main.struct{m int; *bytes.Buffer}.empty"(ptr %0, { i64, ptr } %1){{.*}} { -// CHECK-NEXT: _llgo_0: -// CHECK-NEXT: %2 = tail call i1 @"main.struct{m int; *bytes.Buffer}.empty"({ i64, ptr } %1) -// CHECK-NEXT: ret i1 %2 -// CHECK-NEXT: } - -// CHECK-LABEL: define linkonce i64 @"__llgo_stub.main.struct{m int; *bytes.Buffer}.grow"(ptr %0, { i64, ptr } %1, i64 %2){{.*}} { -// CHECK-NEXT: _llgo_0: -// CHECK-NEXT: %3 = tail call i64 @"main.struct{m int; *bytes.Buffer}.grow"({ i64, ptr } %1, i64 %2) -// CHECK-NEXT: ret i64 %3 -// CHECK-NEXT: } - -// CHECK-LABEL: define linkonce { %"{{.*}}/runtime/internal/runtime.Slice", %"{{.*}}/runtime/internal/runtime.iface" } @"__llgo_stub.main.struct{m int; *bytes.Buffer}.readSlice"(ptr %0, { i64, ptr } %1, i8 %2){{.*}} { -// CHECK-NEXT: _llgo_0: -// CHECK-NEXT: %3 = tail call { %"{{.*}}/runtime/internal/runtime.Slice", %"{{.*}}/runtime/internal/runtime.iface" } @"main.struct{m int; *bytes.Buffer}.readSlice"({ i64, ptr } %1, i8 %2) -// CHECK-NEXT: ret { %"{{.*}}/runtime/internal/runtime.Slice", %"{{.*}}/runtime/internal/runtime.iface" } %3 -// CHECK-NEXT: } - -// CHECK-LABEL: define linkonce { i64, i1 } @"__llgo_stub.main.struct{m int; *bytes.Buffer}.tryGrowByReslice"(ptr %0, { i64, ptr } %1, i64 %2){{.*}} { -// CHECK-NEXT: _llgo_0: -// CHECK-NEXT: %3 = tail call { i64, i1 } @"main.struct{m int; *bytes.Buffer}.tryGrowByReslice"({ i64, ptr } %1, i64 %2) -// CHECK-NEXT: ret { i64, i1 } %3 -// CHECK-NEXT: } - -// CHECK-LABEL: define linkonce i64 @"__llgo_stub.main.*struct{m int; *bytes.Buffer}.Available"(ptr %0, ptr %1){{.*}} { -// CHECK-NEXT: _llgo_0: -// CHECK-NEXT: %2 = tail call i64 @"main.*struct{m int; *bytes.Buffer}.Available"(ptr %1) -// CHECK-NEXT: ret i64 %2 -// CHECK-NEXT: } - -// CHECK-LABEL: define linkonce %"{{.*}}/runtime/internal/runtime.Slice" @"__llgo_stub.main.*struct{m int; *bytes.Buffer}.AvailableBuffer"(ptr %0, ptr %1){{.*}} { -// CHECK-NEXT: _llgo_0: -// CHECK-NEXT: %2 = tail call %"{{.*}}/runtime/internal/runtime.Slice" @"main.*struct{m int; *bytes.Buffer}.AvailableBuffer"(ptr %1) -// CHECK-NEXT: ret %"{{.*}}/runtime/internal/runtime.Slice" %2 -// CHECK-NEXT: } - -// CHECK-LABEL: define linkonce %"{{.*}}/runtime/internal/runtime.Slice" @"__llgo_stub.main.*struct{m int; *bytes.Buffer}.Bytes"(ptr %0, ptr %1){{.*}} { -// CHECK-NEXT: _llgo_0: -// CHECK-NEXT: %2 = tail call %"{{.*}}/runtime/internal/runtime.Slice" @"main.*struct{m int; *bytes.Buffer}.Bytes"(ptr %1) -// CHECK-NEXT: ret %"{{.*}}/runtime/internal/runtime.Slice" %2 -// CHECK-NEXT: } - -// CHECK-LABEL: define linkonce i64 @"__llgo_stub.main.*struct{m int; *bytes.Buffer}.Cap"(ptr %0, ptr %1){{.*}} { -// CHECK-NEXT: _llgo_0: -// CHECK-NEXT: %2 = tail call i64 @"main.*struct{m int; *bytes.Buffer}.Cap"(ptr %1) -// CHECK-NEXT: ret i64 %2 -// CHECK-NEXT: } - -// CHECK-LABEL: define linkonce void @"__llgo_stub.main.*struct{m int; *bytes.Buffer}.Grow"(ptr %0, ptr %1, i64 %2){{.*}} { -// CHECK-NEXT: _llgo_0: -// CHECK-NEXT: tail call void @"main.*struct{m int; *bytes.Buffer}.Grow"(ptr %1, i64 %2) -// CHECK-NEXT: ret void -// CHECK-NEXT: } - -// CHECK-LABEL: define linkonce i64 @"__llgo_stub.main.*struct{m int; *bytes.Buffer}.Len"(ptr %0, ptr %1){{.*}} { -// CHECK-NEXT: _llgo_0: -// CHECK-NEXT: %2 = tail call i64 @"main.*struct{m int; *bytes.Buffer}.Len"(ptr %1) -// CHECK-NEXT: ret i64 %2 -// CHECK-NEXT: } - -// CHECK-LABEL: define linkonce %"{{.*}}/runtime/internal/runtime.Slice" @"__llgo_stub.main.*struct{m int; *bytes.Buffer}.Next"(ptr %0, ptr %1, i64 %2){{.*}} { -// CHECK-NEXT: _llgo_0: -// CHECK-NEXT: %3 = tail call %"{{.*}}/runtime/internal/runtime.Slice" @"main.*struct{m int; *bytes.Buffer}.Next"(ptr %1, i64 %2) -// CHECK-NEXT: ret %"{{.*}}/runtime/internal/runtime.Slice" %3 -// CHECK-NEXT: } - -// CHECK-LABEL: define linkonce { i64, %"{{.*}}/runtime/internal/runtime.iface" } @"__llgo_stub.main.*struct{m int; *bytes.Buffer}.Read"(ptr %0, ptr %1, %"{{.*}}/runtime/internal/runtime.Slice" %2){{.*}} { -// CHECK-NEXT: _llgo_0: -// CHECK-NEXT: %3 = tail call { i64, %"{{.*}}/runtime/internal/runtime.iface" } @"main.*struct{m int; *bytes.Buffer}.Read"(ptr %1, %"{{.*}}/runtime/internal/runtime.Slice" %2) -// CHECK-NEXT: ret { i64, %"{{.*}}/runtime/internal/runtime.iface" } %3 -// CHECK-NEXT: } - -// CHECK-LABEL: define linkonce { i8, %"{{.*}}/runtime/internal/runtime.iface" } @"__llgo_stub.main.*struct{m int; *bytes.Buffer}.ReadByte"(ptr %0, ptr %1){{.*}} { -// CHECK-NEXT: _llgo_0: -// CHECK-NEXT: %2 = tail call { i8, %"{{.*}}/runtime/internal/runtime.iface" } @"main.*struct{m int; *bytes.Buffer}.ReadByte"(ptr %1) -// CHECK-NEXT: ret { i8, %"{{.*}}/runtime/internal/runtime.iface" } %2 -// CHECK-NEXT: } - -// CHECK-LABEL: define linkonce { %"{{.*}}/runtime/internal/runtime.Slice", %"{{.*}}/runtime/internal/runtime.iface" } @"__llgo_stub.main.*struct{m int; *bytes.Buffer}.ReadBytes"(ptr %0, ptr %1, i8 %2){{.*}} { -// CHECK-NEXT: _llgo_0: -// CHECK-NEXT: %3 = tail call { %"{{.*}}/runtime/internal/runtime.Slice", %"{{.*}}/runtime/internal/runtime.iface" } @"main.*struct{m int; *bytes.Buffer}.ReadBytes"(ptr %1, i8 %2) -// CHECK-NEXT: ret { %"{{.*}}/runtime/internal/runtime.Slice", %"{{.*}}/runtime/internal/runtime.iface" } %3 -// CHECK-NEXT: } - -// CHECK-LABEL: define linkonce { i64, %"{{.*}}/runtime/internal/runtime.iface" } @"__llgo_stub.main.*struct{m int; *bytes.Buffer}.ReadFrom"(ptr %0, ptr %1, %"{{.*}}/runtime/internal/runtime.iface" %2){{.*}} { -// CHECK-NEXT: _llgo_0: -// CHECK-NEXT: %3 = tail call { i64, %"{{.*}}/runtime/internal/runtime.iface" } @"main.*struct{m int; *bytes.Buffer}.ReadFrom"(ptr %1, %"{{.*}}/runtime/internal/runtime.iface" %2) -// CHECK-NEXT: ret { i64, %"{{.*}}/runtime/internal/runtime.iface" } %3 -// CHECK-NEXT: } - -// CHECK-LABEL: define linkonce { i32, i64, %"{{.*}}/runtime/internal/runtime.iface" } @"__llgo_stub.main.*struct{m int; *bytes.Buffer}.ReadRune"(ptr %0, ptr %1){{.*}} { -// CHECK-NEXT: _llgo_0: -// CHECK-NEXT: %2 = tail call { i32, i64, %"{{.*}}/runtime/internal/runtime.iface" } @"main.*struct{m int; *bytes.Buffer}.ReadRune"(ptr %1) -// CHECK-NEXT: ret { i32, i64, %"{{.*}}/runtime/internal/runtime.iface" } %2 -// CHECK-NEXT: } - -// CHECK-LABEL: define linkonce { %"{{.*}}/runtime/internal/runtime.String", %"{{.*}}/runtime/internal/runtime.iface" } @"__llgo_stub.main.*struct{m int; *bytes.Buffer}.ReadString"(ptr %0, ptr %1, i8 %2){{.*}} { -// CHECK-NEXT: _llgo_0: -// CHECK-NEXT: %3 = tail call { %"{{.*}}/runtime/internal/runtime.String", %"{{.*}}/runtime/internal/runtime.iface" } @"main.*struct{m int; *bytes.Buffer}.ReadString"(ptr %1, i8 %2) -// CHECK-NEXT: ret { %"{{.*}}/runtime/internal/runtime.String", %"{{.*}}/runtime/internal/runtime.iface" } %3 -// CHECK-NEXT: } - -// CHECK-LABEL: define linkonce void @"__llgo_stub.main.*struct{m int; *bytes.Buffer}.Reset"(ptr %0, ptr %1){{.*}} { -// CHECK-NEXT: _llgo_0: -// CHECK-NEXT: tail call void @"main.*struct{m int; *bytes.Buffer}.Reset"(ptr %1) -// CHECK-NEXT: ret void -// CHECK-NEXT: } - -// CHECK-LABEL: define linkonce %"{{.*}}/runtime/internal/runtime.String" @"__llgo_stub.main.*struct{m int; *bytes.Buffer}.String"(ptr %0, ptr %1){{.*}} { -// CHECK-NEXT: _llgo_0: -// CHECK-NEXT: %2 = tail call %"{{.*}}/runtime/internal/runtime.String" @"main.*struct{m int; *bytes.Buffer}.String"(ptr %1) -// CHECK-NEXT: ret %"{{.*}}/runtime/internal/runtime.String" %2 -// CHECK-NEXT: } - -// CHECK-LABEL: define linkonce void @"__llgo_stub.main.*struct{m int; *bytes.Buffer}.Truncate"(ptr %0, ptr %1, i64 %2){{.*}} { -// CHECK-NEXT: _llgo_0: -// CHECK-NEXT: tail call void @"main.*struct{m int; *bytes.Buffer}.Truncate"(ptr %1, i64 %2) -// CHECK-NEXT: ret void -// CHECK-NEXT: } - -// CHECK-LABEL: define linkonce %"{{.*}}/runtime/internal/runtime.iface" @"__llgo_stub.main.*struct{m int; *bytes.Buffer}.UnreadByte"(ptr %0, ptr %1){{.*}} { -// CHECK-NEXT: _llgo_0: -// CHECK-NEXT: %2 = tail call %"{{.*}}/runtime/internal/runtime.iface" @"main.*struct{m int; *bytes.Buffer}.UnreadByte"(ptr %1) -// CHECK-NEXT: ret %"{{.*}}/runtime/internal/runtime.iface" %2 -// CHECK-NEXT: } - -// CHECK-LABEL: define linkonce %"{{.*}}/runtime/internal/runtime.iface" @"__llgo_stub.main.*struct{m int; *bytes.Buffer}.UnreadRune"(ptr %0, ptr %1){{.*}} { -// CHECK-NEXT: _llgo_0: -// CHECK-NEXT: %2 = tail call %"{{.*}}/runtime/internal/runtime.iface" @"main.*struct{m int; *bytes.Buffer}.UnreadRune"(ptr %1) -// CHECK-NEXT: ret %"{{.*}}/runtime/internal/runtime.iface" %2 -// CHECK-NEXT: } - -// CHECK-LABEL: define linkonce { i64, %"{{.*}}/runtime/internal/runtime.iface" } @"__llgo_stub.main.*struct{m int; *bytes.Buffer}.Write"(ptr %0, ptr %1, %"{{.*}}/runtime/internal/runtime.Slice" %2){{.*}} { -// CHECK-NEXT: _llgo_0: -// CHECK-NEXT: %3 = tail call { i64, %"{{.*}}/runtime/internal/runtime.iface" } @"main.*struct{m int; *bytes.Buffer}.Write"(ptr %1, %"{{.*}}/runtime/internal/runtime.Slice" %2) -// CHECK-NEXT: ret { i64, %"{{.*}}/runtime/internal/runtime.iface" } %3 -// CHECK-NEXT: } - -// CHECK-LABEL: define linkonce %"{{.*}}/runtime/internal/runtime.iface" @"__llgo_stub.main.*struct{m int; *bytes.Buffer}.WriteByte"(ptr %0, ptr %1, i8 %2){{.*}} { -// CHECK-NEXT: _llgo_0: -// CHECK-NEXT: %3 = tail call %"{{.*}}/runtime/internal/runtime.iface" @"main.*struct{m int; *bytes.Buffer}.WriteByte"(ptr %1, i8 %2) -// CHECK-NEXT: ret %"{{.*}}/runtime/internal/runtime.iface" %3 -// CHECK-NEXT: } - -// CHECK-LABEL: define linkonce { i64, %"{{.*}}/runtime/internal/runtime.iface" } @"__llgo_stub.main.*struct{m int; *bytes.Buffer}.WriteRune"(ptr %0, ptr %1, i32 %2){{.*}} { -// CHECK-NEXT: _llgo_0: -// CHECK-NEXT: %3 = tail call { i64, %"{{.*}}/runtime/internal/runtime.iface" } @"main.*struct{m int; *bytes.Buffer}.WriteRune"(ptr %1, i32 %2) -// CHECK-NEXT: ret { i64, %"{{.*}}/runtime/internal/runtime.iface" } %3 -// CHECK-NEXT: } - -// CHECK-LABEL: define linkonce { i64, %"{{.*}}/runtime/internal/runtime.iface" } @"__llgo_stub.main.*struct{m int; *bytes.Buffer}.WriteString"(ptr %0, ptr %1, %"{{.*}}/runtime/internal/runtime.String" %2){{.*}} { -// CHECK-NEXT: _llgo_0: -// CHECK-NEXT: %3 = tail call { i64, %"{{.*}}/runtime/internal/runtime.iface" } @"main.*struct{m int; *bytes.Buffer}.WriteString"(ptr %1, %"{{.*}}/runtime/internal/runtime.String" %2) -// CHECK-NEXT: ret { i64, %"{{.*}}/runtime/internal/runtime.iface" } %3 -// CHECK-NEXT: } - -// CHECK-LABEL: define linkonce { i64, %"{{.*}}/runtime/internal/runtime.iface" } @"__llgo_stub.main.*struct{m int; *bytes.Buffer}.WriteTo"(ptr %0, ptr %1, %"{{.*}}/runtime/internal/runtime.iface" %2){{.*}} { -// CHECK-NEXT: _llgo_0: -// CHECK-NEXT: %3 = tail call { i64, %"{{.*}}/runtime/internal/runtime.iface" } @"main.*struct{m int; *bytes.Buffer}.WriteTo"(ptr %1, %"{{.*}}/runtime/internal/runtime.iface" %2) -// CHECK-NEXT: ret { i64, %"{{.*}}/runtime/internal/runtime.iface" } %3 -// CHECK-NEXT: } - -// CHECK-LABEL: define linkonce i1 @"__llgo_stub.main.*struct{m int; *bytes.Buffer}.empty"(ptr %0, ptr %1){{.*}} { -// CHECK-NEXT: _llgo_0: -// CHECK-NEXT: %2 = tail call i1 @"main.*struct{m int; *bytes.Buffer}.empty"(ptr %1) -// CHECK-NEXT: ret i1 %2 -// CHECK-NEXT: } - -// CHECK-LABEL: define linkonce i64 @"__llgo_stub.main.*struct{m int; *bytes.Buffer}.grow"(ptr %0, ptr %1, i64 %2){{.*}} { -// CHECK-NEXT: _llgo_0: -// CHECK-NEXT: %3 = tail call i64 @"main.*struct{m int; *bytes.Buffer}.grow"(ptr %1, i64 %2) -// CHECK-NEXT: ret i64 %3 -// CHECK-NEXT: } - -// CHECK-LABEL: define linkonce { %"{{.*}}/runtime/internal/runtime.Slice", %"{{.*}}/runtime/internal/runtime.iface" } @"__llgo_stub.main.*struct{m int; *bytes.Buffer}.readSlice"(ptr %0, ptr %1, i8 %2){{.*}} { -// CHECK-NEXT: _llgo_0: -// CHECK-NEXT: %3 = tail call { %"{{.*}}/runtime/internal/runtime.Slice", %"{{.*}}/runtime/internal/runtime.iface" } @"main.*struct{m int; *bytes.Buffer}.readSlice"(ptr %1, i8 %2) -// CHECK-NEXT: ret { %"{{.*}}/runtime/internal/runtime.Slice", %"{{.*}}/runtime/internal/runtime.iface" } %3 -// CHECK-NEXT: } - -// CHECK-LABEL: define linkonce { i64, i1 } @"__llgo_stub.main.*struct{m int; *bytes.Buffer}.tryGrowByReslice"(ptr %0, ptr %1, i64 %2){{.*}} { -// CHECK-NEXT: _llgo_0: -// CHECK-NEXT: %3 = tail call { i64, i1 } @"main.*struct{m int; *bytes.Buffer}.tryGrowByReslice"(ptr %1, i64 %2) -// CHECK-NEXT: ret { i64, i1 } %3 -// CHECK-NEXT: } - // CHECK-LABEL: define linkonce ptr @"main.(*Pointer[any]).Load"(ptr %0){{.*}} { // CHECK-NEXT: _llgo_0: // CHECK-NEXT: %1 = icmp eq ptr %0, null @@ -2167,21 +1579,3 @@ type I2 interface { // CHECK-NEXT: store atomic ptr %1, ptr %3 seq_cst, align 8 // CHECK-NEXT: ret void // CHECK-NEXT: } - -// CHECK-LABEL: define linkonce i1 @"__llgo_stub.{{.*}}/runtime/internal/runtime.nilinterequal"(ptr %0, ptr %1, ptr %2){{.*}} { -// CHECK-NEXT: _llgo_0: -// CHECK-NEXT: %3 = tail call i1 @"{{.*}}/runtime/internal/runtime.nilinterequal"(ptr %1, ptr %2) -// CHECK-NEXT: ret i1 %3 -// CHECK-NEXT: } - -// CHECK-LABEL: define linkonce ptr @"__llgo_stub.main.(*Pointer[any]).Load"(ptr %0, ptr %1){{.*}} { -// CHECK-NEXT: _llgo_0: -// CHECK-NEXT: %2 = tail call ptr @"main.(*Pointer[any]).Load"(ptr %1) -// CHECK-NEXT: ret ptr %2 -// CHECK-NEXT: } - -// CHECK-LABEL: define linkonce void @"__llgo_stub.main.(*Pointer[any]).Store"(ptr %0, ptr %1, ptr %2){{.*}} { -// CHECK-NEXT: _llgo_0: -// CHECK-NEXT: tail call void @"main.(*Pointer[any]).Store"(ptr %1, ptr %2) -// CHECK-NEXT: ret void -// CHECK-NEXT: } diff --git a/cl/_testgo/cgobasic/cgobasic.go b/cl/_testgo/cgobasic/cgobasic.go index 8017d92376..d7fef6b914 100644 --- a/cl/_testgo/cgobasic/cgobasic.go +++ b/cl/_testgo/cgobasic/cgobasic.go @@ -139,7 +139,7 @@ func main() { C.free(cbytes) } -// CHECK-LABEL: define ptr @"main.main$1"(ptr %0){{.*}} { +// CHECK-LABEL: define ptr @"main.main$1"(ptr {{(nest|swiftself)}} %0){{.*}} { // CHECK-NEXT: _llgo_0: // CHECK-NEXT: %1 = load { ptr }, ptr %0, align 8 // CHECK-NEXT: %2 = extractvalue { ptr } %1, 0 @@ -151,7 +151,7 @@ func main() { // CHECK-NEXT: ret ptr %6 // CHECK-NEXT: } -// CHECK-LABEL: define %"{{.*}}/runtime/internal/runtime.Slice" @"main.main$2"(ptr %0){{.*}} { +// CHECK-LABEL: define %"{{.*}}/runtime/internal/runtime.Slice" @"main.main$2"(ptr {{(nest|swiftself)}} %0){{.*}} { // CHECK-NEXT: _llgo_0: // CHECK-NEXT: %1 = load { ptr }, ptr %0, align 8 // CHECK-NEXT: %2 = extractvalue { ptr } %1, 0 @@ -161,7 +161,7 @@ func main() { // CHECK-NEXT: ret %"{{.*}}/runtime/internal/runtime.Slice" %5 // CHECK-NEXT: } -// CHECK-LABEL: define void @"main.main$3"(ptr %0){{.*}} { +// CHECK-LABEL: define void @"main.main$3"(ptr {{(nest|swiftself)}} %0){{.*}} { // CHECK-NEXT: _llgo_0: // CHECK-NEXT: %1 = load { ptr }, ptr %0, align 8 // CHECK-NEXT: %2 = extractvalue { ptr } %1, 0 @@ -171,7 +171,7 @@ func main() { // CHECK-NEXT: ret void // CHECK-NEXT: } -// CHECK-LABEL: define void @"main.main$4"(ptr %0){{.*}} { +// CHECK-LABEL: define void @"main.main$4"(ptr {{(nest|swiftself)}} %0){{.*}} { // CHECK-NEXT: _llgo_0: // CHECK-NEXT: %1 = load { ptr }, ptr %0, align 8 // CHECK-NEXT: %2 = extractvalue { ptr } %1, 0 diff --git a/cl/_testgo/cgodefer/cgodefer.go b/cl/_testgo/cgodefer/cgodefer.go index 8d9bca1306..5ce8dd6bfe 100644 --- a/cl/_testgo/cgodefer/cgodefer.go +++ b/cl/_testgo/cgodefer/cgodefer.go @@ -26,7 +26,8 @@ import "C" // CHECK-NEXT: %4 = insertvalue { ptr, ptr } { ptr @"main.main$1", ptr undef }, ptr %2, 1 // CHECK-NEXT: %5 = extractvalue { ptr, ptr } %4, 1 // CHECK-NEXT: %6 = extractvalue { ptr, ptr } %4, 0 -// CHECK-NEXT: %7 = call { ptr, ptr } %6(ptr %5) +// CHECK-NEXT: %__llgo_funcval_code = call ptr asm "", "=r,0"(ptr %6) +// CHECK-NEXT: %7 = call { ptr, ptr } %__llgo_funcval_code(ptr {{(nest|swiftself)}} %5) // CHECK-NEXT: %8 = call ptr @"{{.*}}/runtime/internal/runtime.GetThreadDefer"() // CHECK-NEXT: %9 = alloca i8, i64 {{.*}}, align 1 // CHECK-NEXT: %10 = call ptr @"{{.*}}/runtime/internal/runtime.AllocU"(i64 48) @@ -92,7 +93,8 @@ import "C" // CHECK-NEXT: call void @"{{.*}}/runtime/internal/runtime.FreeDeferNode"(ptr %30) // CHECK-NEXT: %34 = extractvalue { ptr, ptr } %33, 1 // CHECK-NEXT: %35 = extractvalue { ptr, ptr } %33, 0 -// CHECK-NEXT: call void %35(ptr %34) +// CHECK-NEXT: %__llgo_funcval_code1 = call ptr asm "", "=r,0"(ptr %35) +// CHECK-NEXT: call void %__llgo_funcval_code1(ptr {{(nest|swiftself)}} %34) // CHECK-NEXT: br label %_llgo_8 // CHECK-EMPTY: // CHECK-NEXT: _llgo_8: ; preds = %_llgo_7, %_llgo_2 @@ -103,7 +105,7 @@ import "C" // CHECK-NEXT: indirectbr ptr %38, [label %_llgo_3, label %_llgo_6] // CHECK-NEXT: } func main() { - // CHECK-LABEL: define { ptr, ptr } @"main.main$1"(ptr %0){{.*}} { + // CHECK-LABEL: define { ptr, ptr } @"main.main$1"(ptr {{(nest|swiftself)}} %0){{.*}} { // CHECK-NEXT: _llgo_0: // CHECK-NEXT: %1 = call ptr @"{{.*}}/runtime/internal/runtime.AllocZ"(i64 8) // CHECK-NEXT: %2 = load { ptr }, ptr %0, align 8 @@ -117,7 +119,7 @@ func main() { // CHECK-NEXT: ret { ptr, ptr } %7 // CHECK-NEXT: } p := C.malloc(1024) - // CHECK-LABEL: define void @"main.main$1$1"(ptr %0){{.*}} { + // CHECK-LABEL: define void @"main.main$1$1"(ptr {{(nest|swiftself)}} %0){{.*}} { // CHECK-NEXT: _llgo_0: // CHECK-NEXT: %1 = load { ptr }, ptr %0, align 8 // CHECK-NEXT: %2 = extractvalue { ptr } %1, 0 diff --git a/cl/_testgo/closure/in.go b/cl/_testgo/closure/in.go index eabccf6e81..ad7eabba2e 100644 --- a/cl/_testgo/closure/in.go +++ b/cl/_testgo/closure/in.go @@ -9,8 +9,9 @@ func main() { // CHECK: store %"{{.*}}String" { ptr @0, i64 3 }, ptr %0, align 8 // CHECK: call ptr @"{{.*}}AllocU"(i64 8) // CHECK: { ptr @"main.main$2", ptr undef } - // CHECK: call void @"__llgo_stub.main.main$1"(ptr null, i64 100) - // CHECK: call void %7(ptr %6, i64 200) + // CHECK: call void @"main.main$1"(i64 100) + // CHECK: %__llgo_funcval_code = call ptr asm "", "=r,0"(ptr %7) + // CHECK: call void %__llgo_funcval_code(ptr {{(nest|swiftself)}} %6, i64 200) // CHECK: ret void var env string = "env" var v1 T = func(i int) { @@ -24,7 +25,7 @@ func main() { println("func", i) } var v2 T = func(i int) { - // CHECK-LABEL: define void @"main.main$2"(ptr %0, i64 %1){{.*}} { + // CHECK-LABEL: define void @"main.main$2"(ptr {{(nest|swiftself)}} %0, i64 %1){{.*}} { // CHECK-NEXT: _llgo_0: // CHECK-NEXT: %2 = load { ptr }, ptr %0, align 8 // CHECK-NEXT: %3 = extractvalue { ptr } %2, 0 diff --git a/cl/_testgo/closure2/in.go b/cl/_testgo/closure2/in.go index a32d628efd..0e19371aa7 100644 --- a/cl/_testgo/closure2/in.go +++ b/cl/_testgo/closure2/in.go @@ -7,12 +7,14 @@ func main() { // CHECK: store i64 1, ptr %0, align 8 // CHECK: call ptr @"{{.*}}AllocU"(i64 8) // CHECK: { ptr @"main.main$1", ptr undef } - // CHECK: call { ptr, ptr } %5(ptr %4, i64 1) - // CHECK: call void %8(ptr %7, i64 2) + // CHECK: %__llgo_funcval_code = call ptr asm "", "=r,0"(ptr %5) + // CHECK: call { ptr, ptr } %__llgo_funcval_code(ptr {{(nest|swiftself)}} %4, i64 1) + // CHECK: %__llgo_funcval_code1 = call ptr asm "", "=r,0"(ptr %8) + // CHECK: call void %__llgo_funcval_code1(ptr {{(nest|swiftself)}} %7, i64 2) // CHECK: ret void x := 1 f := func(i int) func(int) { - // CHECK-LABEL: define { ptr, ptr } @"main.main$1"(ptr %0, i64 %1){{.*}} { + // CHECK-LABEL: define { ptr, ptr } @"main.main$1"(ptr {{(nest|swiftself)}} %0, i64 %1){{.*}} { // CHECK-NEXT: _llgo_0: // CHECK-NEXT: %2 = load { ptr }, ptr %0, align 8 // CHECK-NEXT: %3 = extractvalue { ptr } %2, 0 @@ -22,7 +24,7 @@ func main() { // CHECK-NEXT: %6 = insertvalue { ptr, ptr } { ptr @"main.main$1$1", ptr undef }, ptr %4, 1 // CHECK-NEXT: ret { ptr, ptr } %6 return func(i int) { - // CHECK-LABEL: define void @"main.main$1$1"(ptr %0, i64 %1){{.*}} { + // CHECK-LABEL: define void @"main.main$1$1"(ptr {{(nest|swiftself)}} %0, i64 %1){{.*}} { // CHECK-NEXT: _llgo_0: // CHECK-NEXT: %2 = load { ptr }, ptr %0, align 8 // CHECK-NEXT: %3 = extractvalue { ptr } %2, 0 diff --git a/cl/_testgo/closureall/in.go b/cl/_testgo/closureall/in.go index 185b4f7854..5d7e0ed0d9 100644 --- a/cl/_testgo/closureall/in.go +++ b/cl/_testgo/closureall/in.go @@ -21,6 +21,11 @@ type CCallback func(c.Int) c.Int type Fn func(int) int +//go:noinline +func callCInt(fn func(c.Int) c.Int, x c.Int) c.Int { + return fn(x) +} + type S struct { v int } @@ -81,8 +86,7 @@ func main() { cs := cSqrt _ = cs(4) - ca := cAbs - _ = ca(-3) + _ = callCInt(cAbs, -3) cb := CCallback(func(x c.Int) c.Int { return x + 1 }) _ = callCallback(cb, 7) @@ -105,6 +109,15 @@ func makeWithFree(base int) Fn { // CHECK-NEXT: ret i64 %4 // CHECK-NEXT: } +// CHECK-LABEL: define i32 @main.callCInt({ ptr, ptr } %0, i32 %1){{.*}} { +// CHECK-NEXT: _llgo_0: +// CHECK-NEXT: %2 = extractvalue { ptr, ptr } %0, 1 +// CHECK-NEXT: %3 = extractvalue { ptr, ptr } %0, 0 +// CHECK-NEXT: %__llgo_funcval_code = call ptr asm "", "=r,0"(ptr %3) +// CHECK-NEXT: %4 = call i32 %__llgo_funcval_code(ptr {{(nest|swiftself)}} %2, i32 %1) +// CHECK-NEXT: ret i32 %4 +// CHECK-NEXT: } + // CHECK-LABEL: define i32 @main.callCallback(ptr %0, i32 %1){{.*}} { // CHECK-NEXT: _llgo_0: // CHECK-NEXT: %2 = call i32 %0(i32 %1) @@ -136,10 +149,12 @@ func makeWithFree(base int) Fn { // CHECK-NEXT: %1 = call %main.Fn @main.makeWithFree(i64 3) // CHECK-NEXT: %2 = extractvalue %main.Fn %0, 1 // CHECK-NEXT: %3 = extractvalue %main.Fn %0, 0 -// CHECK-NEXT: %4 = call i64 %3(ptr %2, i64 1) +// CHECK-NEXT: %__llgo_funcval_code = call ptr asm "", "=r,0"(ptr %3) +// CHECK-NEXT: %4 = call i64 %__llgo_funcval_code(ptr {{(nest|swiftself)}} %2, i64 1) // CHECK-NEXT: %5 = extractvalue %main.Fn %1, 1 // CHECK-NEXT: %6 = extractvalue %main.Fn %1, 0 -// CHECK-NEXT: %7 = call i64 %6(ptr %5, i64 2) +// CHECK-NEXT: %__llgo_funcval_code1 = call ptr asm "", "=r,0"(ptr %6) +// CHECK-NEXT: %7 = call i64 %__llgo_funcval_code1(ptr {{(nest|swiftself)}} %5, i64 2) // CHECK-NEXT: %8 = call i64 @main.globalAdd(i64 1, i64 2) // CHECK-NEXT: %9 = call ptr @"{{.*}}/runtime/internal/runtime.AllocZ"(i64 8) // CHECK-NEXT: %10 = getelementptr inbounds %main.S, ptr %9, i32 0, i32 0 @@ -150,7 +165,8 @@ func makeWithFree(base int) Fn { // CHECK-NEXT: %13 = insertvalue { ptr, ptr } { ptr @"main.(*S).Add$bound", ptr undef }, ptr %11, 1 // CHECK-NEXT: %14 = extractvalue { ptr, ptr } %13, 1 // CHECK-NEXT: %15 = extractvalue { ptr, ptr } %13, 0 -// CHECK-NEXT: %16 = call i64 %15(ptr %14, i64 7) +// CHECK-NEXT: %__llgo_funcval_code2 = call ptr asm "", "=r,0"(ptr %15) +// CHECK-NEXT: %16 = call i64 %__llgo_funcval_code2(ptr {{(nest|swiftself)}} %14, i64 7) // CHECK-NEXT: %17 = call i64 @"main.(*S).Add$thunk"(ptr %9, i64 8) // CHECK-NEXT: %18 = call ptr @"{{.*}}/runtime/internal/runtime.NewItab"(ptr @"_llgo_iface${{[-A-Za-z0-9_]+}}", ptr @"*_llgo_main.S") // CHECK-NEXT: %19 = insertvalue %"{{.*}}/runtime/internal/runtime.iface" undef, ptr %18, 0 @@ -166,9 +182,10 @@ func makeWithFree(base int) Fn { // CHECK-NEXT: %25 = insertvalue { ptr, ptr } { ptr @"main.interface{Add(int) int}.Add$bound", ptr undef }, ptr %23, 1 // CHECK-NEXT: %26 = extractvalue { ptr, ptr } %25, 1 // CHECK-NEXT: %27 = extractvalue { ptr, ptr } %25, 0 -// CHECK-NEXT: %28 = call i64 %27(ptr %26, i64 9) -// CHECK-NEXT: %29 = call double {{.*}}sqrt{{.*}}(double 4.000000e+00) -// CHECK-NEXT: %30 = call i32 @abs(i32 -3) +// CHECK-NEXT: %__llgo_funcval_code3 = call ptr asm "", "=r,0"(ptr %27) +// CHECK-NEXT: %28 = call i64 %__llgo_funcval_code3(ptr {{(nest|swiftself)}} %26, i64 9) +// CHECK-NEXT: %29 = call double @sqrt(double 4.000000e+00) +// CHECK-NEXT: %30 = call i32 @main.callCInt({ ptr, ptr } { ptr @abs, ptr null }, i32 -3) // CHECK-NEXT: %31 = call i32 @main.callCallback(ptr @"main.main$1", i32 7) // CHECK-NEXT: ret void // CHECK-EMPTY: @@ -185,7 +202,7 @@ func makeWithFree(base int) Fn { // CHECK-LABEL: define %main.Fn @main.makeNoFree(){{.*}} { // CHECK-NEXT: _llgo_0: -// CHECK-NEXT: ret %main.Fn { ptr @"__llgo_stub.main.makeNoFree$1", ptr null } +// CHECK-NEXT: ret %main.Fn { ptr @"main.makeNoFree$1", ptr null } // CHECK-NEXT: } // CHECK-LABEL: define i64 @"main.makeNoFree$1"(i64 %0){{.*}} { @@ -208,7 +225,7 @@ func makeWithFree(base int) Fn { // CHECK-NEXT: ret %main.Fn %6 // CHECK-NEXT: } -// CHECK-LABEL: define i64 @"main.makeWithFree$1"(ptr %0, i64 %1){{.*}} { +// CHECK-LABEL: define i64 @"main.makeWithFree$1"(ptr {{(nest|swiftself)}} %0, i64 %1){{.*}} { // CHECK-NEXT: _llgo_0: // CHECK-NEXT: %2 = load { ptr }, ptr %0, align 8 // CHECK-NEXT: %3 = extractvalue { ptr } %2, 0 @@ -217,7 +234,7 @@ func makeWithFree(base int) Fn { // CHECK-NEXT: ret i64 %5 // CHECK-NEXT: } -// CHECK-LABEL: define i64 @"main.(*S).Add$bound"(ptr %0, i64 %1){{.*}} { +// CHECK-LABEL: define i64 @"main.(*S).Add$bound"(ptr {{(nest|swiftself)}} %0, i64 %1){{.*}} { // CHECK-NEXT: _llgo_0: // CHECK-NEXT: %2 = load { ptr }, ptr %0, align 8 // CHECK-NEXT: %3 = extractvalue { ptr } %2, 0 @@ -231,37 +248,7 @@ func makeWithFree(base int) Fn { // CHECK-NEXT: ret i64 %2 // CHECK-NEXT: } -// CHECK-LABEL: define linkonce i1 @"__llgo_stub.{{.*}}/runtime/internal/runtime.memequal64"(ptr %0, ptr %1, ptr %2){{.*}} { -// CHECK-NEXT: _llgo_0: -// CHECK-NEXT: %3 = tail call i1 @"{{.*}}/runtime/internal/runtime.memequal64"(ptr %1, ptr %2) -// CHECK-NEXT: ret i1 %3 -// CHECK-NEXT: } - -// CHECK-LABEL: define linkonce i64 @__llgo_stub.main.S.Inc(ptr %0, %main.S %1, i64 %2){{.*}} { -// CHECK-NEXT: _llgo_0: -// CHECK-NEXT: %3 = tail call i64 @main.S.Inc(%main.S %1, i64 %2) -// CHECK-NEXT: ret i64 %3 -// CHECK-NEXT: } - -// CHECK-LABEL: define linkonce i64 @"__llgo_stub.main.(*S).Add"(ptr %0, ptr %1, i64 %2){{.*}} { -// CHECK-NEXT: _llgo_0: -// CHECK-NEXT: %3 = tail call i64 @"main.(*S).Add"(ptr %1, i64 %2) -// CHECK-NEXT: ret i64 %3 -// CHECK-NEXT: } - -// CHECK-LABEL: define linkonce i64 @"__llgo_stub.main.(*S).Inc"(ptr %0, ptr %1, i64 %2){{.*}} { -// CHECK-NEXT: _llgo_0: -// CHECK-NEXT: %3 = tail call i64 @"main.(*S).Inc"(ptr %1, i64 %2) -// CHECK-NEXT: ret i64 %3 -// CHECK-NEXT: } - -// CHECK-LABEL: define linkonce i1 @"__llgo_stub.{{.*}}/runtime/internal/runtime.interequal"(ptr %0, ptr %1, ptr %2){{.*}} { -// CHECK-NEXT: _llgo_0: -// CHECK-NEXT: %3 = tail call i1 @"{{.*}}/runtime/internal/runtime.interequal"(ptr %1, ptr %2) -// CHECK-NEXT: ret i1 %3 -// CHECK-NEXT: } - -// CHECK-LABEL: define i64 @"main.interface{Add(int) int}.Add$bound"(ptr %0, i64 %1){{.*}} { +// CHECK-LABEL: define i64 @"main.interface{Add(int) int}.Add$bound"(ptr {{(nest|swiftself)}} %0, i64 %1){{.*}} { // CHECK-NEXT: _llgo_0: // CHECK-NEXT: %2 = load { %"{{.*}}/runtime/internal/runtime.iface" }, ptr %0, align 8 // CHECK-NEXT: %3 = extractvalue { %"{{.*}}/runtime/internal/runtime.iface" } %2, 0 @@ -276,9 +263,3 @@ func makeWithFree(base int) Fn { // CHECK-NEXT: %12 = call i64 %11(ptr %10, i64 %1) // CHECK-NEXT: ret i64 %12 // CHECK-NEXT: } - -// CHECK-LABEL: define linkonce i64 @"__llgo_stub.main.makeNoFree$1"(ptr %0, i64 %1){{.*}} { -// CHECK-NEXT: _llgo_0: -// CHECK-NEXT: %2 = tail call i64 @"main.makeNoFree$1"(i64 %1) -// CHECK-NEXT: ret i64 %2 -// CHECK-NEXT: } diff --git a/cl/_testgo/closureenv/expect.txt b/cl/_testgo/closureenv/expect.txt new file mode 100644 index 0000000000..9766475a41 --- /dev/null +++ b/cl/_testgo/closureenv/expect.txt @@ -0,0 +1 @@ +ok diff --git a/cl/_testgo/closureenv/in.go b/cl/_testgo/closureenv/in.go new file mode 100644 index 0000000000..b83578930d --- /dev/null +++ b/cl/_testgo/closureenv/in.go @@ -0,0 +1,255 @@ +// LITTEST +package main + +// CHECK: {{^}}@0 = private unnamed_addr constant [18 x i8] c"zero-sized capture", align 1{{$}} +// CHECK: {{^}}@2 = private unnamed_addr constant [26 x i8] c"zero-sized capture address", align 1{{$}} +// CHECK: {{^}}@3 = private unnamed_addr constant [26 x i8] c"zero-sized pointer capture", align 1{{$}} +// CHECK: {{^}}@6 = private unnamed_addr constant [5 x i8] c"IsNil", align 1{{$}} +// CHECK: {{^}}@10 = private unnamed_addr constant [23 x i8] c"interface{IsNil() bool}", align 1{{$}} +// CHECK: {{^}}@11 = private unnamed_addr constant [25 x i8] c"nil receiver method value", align 1{{$}} +// CHECK: {{^}}@12 = private unnamed_addr constant [2 x i8] c"ok", align 1{{$}} +// CHECK: {{^}}@13 = private unnamed_addr constant [32 x i8] c"typed-nil interface method value", align 1{{$}} + +type nilReceiver struct{} + +func (p *nilReceiver) IsNil() bool { + return p == nil +} + +func zeroSizedCapture() func() int { + captured := struct{}{} + return func() int { + if captured != (struct{}{}) { + return 0 + } + return 42 + } +} + +func zeroSizedAddressCapture() (func() *struct{}, *struct{}) { + captured := struct{}{} + return func() *struct{} { return &captured }, &captured +} + +func zeroSizedPointerCapture(pointer *struct{}) func() bool { + return func() bool { return pointer == nil } +} + +func main() { + if zeroSizedCapture()() != 42 { + panic("zero-sized capture") + } + addressClosure, address := zeroSizedAddressCapture() + if addressClosure() != address { + panic("zero-sized capture address") + } + if !zeroSizedPointerCapture(nil)() { + panic("zero-sized pointer capture") + } + + var receiver *nilReceiver + method := receiver.IsNil + if !method() { + panic("nil receiver method value") + } + + var typedNil interface{ IsNil() bool } = receiver + interfaceMethod := typedNil.IsNil + if !interfaceMethod() { + panic("typed-nil interface method value") + } + println("ok") +} + +// CHECK-LABEL: define void @main.init(){{.*}} { +// CHECK-NEXT: _llgo_0: +// CHECK-NEXT: %0 = load i1, ptr @"main.init$guard", align 1 +// CHECK-NEXT: br i1 %0, label %_llgo_2, label %_llgo_1 +// CHECK-EMPTY: +// CHECK-NEXT: _llgo_1: ; preds = %_llgo_0 +// CHECK-NEXT: store i1 true, ptr @"main.init$guard", align 1 +// CHECK-NEXT: br label %_llgo_2 +// CHECK-EMPTY: +// CHECK-NEXT: _llgo_2: ; preds = %_llgo_1, %_llgo_0 +// CHECK-NEXT: ret void +// CHECK-NEXT: } + +// CHECK-LABEL: define void @main.main(){{.*}} { +// CHECK-NEXT: _llgo_0: +// CHECK-NEXT: %0 = call { ptr, ptr } @main.zeroSizedCapture() +// CHECK-NEXT: %1 = extractvalue { ptr, ptr } %0, 1 +// CHECK-NEXT: %2 = extractvalue { ptr, ptr } %0, 0 +// CHECK-NEXT: %__llgo_funcval_code = call ptr asm "", "=r,0"(ptr %2) +// CHECK-NEXT: %3 = call i64 %__llgo_funcval_code(ptr {{(nest|swiftself)}} %1) +// CHECK-NEXT: %4 = icmp ne i64 %3, 42 +// CHECK-NEXT: br i1 %4, label %_llgo_1, label %_llgo_2 +// CHECK-EMPTY: +// CHECK-NEXT: _llgo_1: ; preds = %_llgo_0 +// CHECK-NEXT: %5 = call ptr @"{{.*}}/runtime/internal/runtime.AllocU"(i64 16) +// CHECK-NEXT: store %"{{.*}}/runtime/internal/runtime.String" { ptr @0, i64 18 }, ptr %5, align 8 +// CHECK-NEXT: %6 = insertvalue %"{{.*}}/runtime/internal/runtime.eface" { ptr @_llgo_string, ptr undef }, ptr %5, 1 +// CHECK-NEXT: call void @"{{.*}}/runtime/internal/runtime.Panic"(%"{{.*}}/runtime/internal/runtime.eface" %6) +// CHECK-NEXT: unreachable +// CHECK-EMPTY: +// CHECK-NEXT: _llgo_2: ; preds = %_llgo_0 +// CHECK-NEXT: %7 = call { { ptr, ptr }, ptr } @main.zeroSizedAddressCapture() +// CHECK-NEXT: %8 = extractvalue { { ptr, ptr }, ptr } %7, 0 +// CHECK-NEXT: %9 = extractvalue { { ptr, ptr }, ptr } %7, 1 +// CHECK-NEXT: %10 = extractvalue { ptr, ptr } %8, 1 +// CHECK-NEXT: %11 = extractvalue { ptr, ptr } %8, 0 +// CHECK-NEXT: %__llgo_funcval_code1 = call ptr asm "", "=r,0"(ptr %11) +// CHECK-NEXT: %12 = call ptr %__llgo_funcval_code1(ptr {{(nest|swiftself)}} %10) +// CHECK-NEXT: %13 = icmp ne ptr %12, %9 +// CHECK-NEXT: br i1 %13, label %_llgo_3, label %_llgo_4 +// CHECK-EMPTY: +// CHECK-NEXT: _llgo_3: ; preds = %_llgo_2 +// CHECK-NEXT: %14 = call ptr @"{{.*}}/runtime/internal/runtime.AllocU"(i64 16) +// CHECK-NEXT: store %"{{.*}}/runtime/internal/runtime.String" { ptr @2, i64 26 }, ptr %14, align 8 +// CHECK-NEXT: %15 = insertvalue %"{{.*}}/runtime/internal/runtime.eface" { ptr @_llgo_string, ptr undef }, ptr %14, 1 +// CHECK-NEXT: call void @"{{.*}}/runtime/internal/runtime.Panic"(%"{{.*}}/runtime/internal/runtime.eface" %15) +// CHECK-NEXT: unreachable +// CHECK-EMPTY: +// CHECK-NEXT: _llgo_4: ; preds = %_llgo_2 +// CHECK-NEXT: %16 = call { ptr, ptr } @main.zeroSizedPointerCapture(ptr null) +// CHECK-NEXT: %17 = extractvalue { ptr, ptr } %16, 1 +// CHECK-NEXT: %18 = extractvalue { ptr, ptr } %16, 0 +// CHECK-NEXT: %__llgo_funcval_code2 = call ptr asm "", "=r,0"(ptr %18) +// CHECK-NEXT: %19 = call i1 %__llgo_funcval_code2(ptr {{(nest|swiftself)}} %17) +// CHECK-NEXT: br i1 %19, label %_llgo_6, label %_llgo_5 +// CHECK-EMPTY: +// CHECK-NEXT: _llgo_5: ; preds = %_llgo_4 +// CHECK-NEXT: %20 = call ptr @"{{.*}}/runtime/internal/runtime.AllocU"(i64 16) +// CHECK-NEXT: store %"{{.*}}/runtime/internal/runtime.String" { ptr @3, i64 26 }, ptr %20, align 8 +// CHECK-NEXT: %21 = insertvalue %"{{.*}}/runtime/internal/runtime.eface" { ptr @_llgo_string, ptr undef }, ptr %20, 1 +// CHECK-NEXT: call void @"{{.*}}/runtime/internal/runtime.Panic"(%"{{.*}}/runtime/internal/runtime.eface" %21) +// CHECK-NEXT: unreachable +// CHECK-EMPTY: +// CHECK-NEXT: _llgo_6: ; preds = %_llgo_4 +// CHECK-NEXT: %22 = call ptr @"{{.*}}/runtime/internal/runtime.AllocU"(i64 8) +// CHECK-NEXT: %23 = getelementptr inbounds { ptr }, ptr %22, i32 0, i32 0 +// CHECK-NEXT: store ptr null, ptr %23, align 8 +// CHECK-NEXT: %24 = insertvalue { ptr, ptr } { ptr @"main.(*nilReceiver).IsNil$bound", ptr undef }, ptr %22, 1 +// CHECK-NEXT: %25 = extractvalue { ptr, ptr } %24, 1 +// CHECK-NEXT: %26 = extractvalue { ptr, ptr } %24, 0 +// CHECK-NEXT: %__llgo_funcval_code3 = call ptr asm "", "=r,0"(ptr %26) +// CHECK-NEXT: %27 = call i1 %__llgo_funcval_code3(ptr {{(nest|swiftself)}} %25) +// CHECK-NEXT: br i1 %27, label %_llgo_8, label %_llgo_7 +// CHECK-EMPTY: +// CHECK-NEXT: _llgo_7: ; preds = %_llgo_6 +// CHECK-NEXT: %28 = call ptr @"{{.*}}/runtime/internal/runtime.AllocU"(i64 16) +// CHECK-NEXT: store %"{{.*}}/runtime/internal/runtime.String" { ptr @11, i64 25 }, ptr %28, align 8 +// CHECK-NEXT: %29 = insertvalue %"{{.*}}/runtime/internal/runtime.eface" { ptr @_llgo_string, ptr undef }, ptr %28, 1 +// CHECK-NEXT: call void @"{{.*}}/runtime/internal/runtime.Panic"(%"{{.*}}/runtime/internal/runtime.eface" %29) +// CHECK-NEXT: unreachable +// CHECK-EMPTY: +// CHECK-NEXT: _llgo_8: ; preds = %_llgo_6 +// CHECK-NEXT: %30 = call ptr @"{{.*}}/runtime/internal/runtime.NewItab"(ptr @"_llgo_iface$36psrSzSiKQuwmDQNUwPgWt23w6DHhlw0KM1_Hu7IbY", ptr @"*_llgo_main.nilReceiver") +// CHECK-NEXT: %31 = insertvalue %"{{.*}}/runtime/internal/runtime.iface" undef, ptr %30, 0 +// CHECK-NEXT: %32 = insertvalue %"{{.*}}/runtime/internal/runtime.iface" %31, ptr null, 1 +// CHECK-NEXT: %33 = call ptr @"{{.*}}/runtime/internal/runtime.IfaceType"(%"{{.*}}/runtime/internal/runtime.iface" %32) +// CHECK-NEXT: %34 = icmp ne ptr %33, null +// CHECK-NEXT: br i1 %34, label %_llgo_11, label %_llgo_12 +// CHECK-EMPTY: +// CHECK-NEXT: _llgo_9: ; preds = %_llgo_11 +// CHECK-NEXT: %35 = call ptr @"{{.*}}/runtime/internal/runtime.AllocU"(i64 16) +// CHECK-NEXT: store %"{{.*}}/runtime/internal/runtime.String" { ptr @13, i64 32 }, ptr %35, align 8 +// CHECK-NEXT: %36 = insertvalue %"{{.*}}/runtime/internal/runtime.eface" { ptr @_llgo_string, ptr undef }, ptr %35, 1 +// CHECK-NEXT: call void @"{{.*}}/runtime/internal/runtime.Panic"(%"{{.*}}/runtime/internal/runtime.eface" %36) +// CHECK-NEXT: unreachable +// CHECK-EMPTY: +// CHECK-NEXT: _llgo_10: ; preds = %_llgo_11 +// CHECK-NEXT: call void @"{{.*}}/runtime/internal/runtime.PrintString"(%"{{.*}}/runtime/internal/runtime.String" { ptr @12, i64 2 }) +// CHECK-NEXT: call void @"{{.*}}/runtime/internal/runtime.PrintByte"(i8 10) +// CHECK-NEXT: ret void +// CHECK-EMPTY: +// CHECK-NEXT: _llgo_11: ; preds = %_llgo_8 +// CHECK-NEXT: %37 = call ptr @"{{.*}}/runtime/internal/runtime.AllocU"(i64 16) +// CHECK-NEXT: %38 = getelementptr inbounds { %"{{.*}}/runtime/internal/runtime.iface" }, ptr %37, i32 0, i32 0 +// CHECK-NEXT: store %"{{.*}}/runtime/internal/runtime.iface" %32, ptr %38, align 8 +// CHECK-NEXT: %39 = insertvalue { ptr, ptr } { ptr @"main.interface{IsNil() bool}.IsNil$bound", ptr undef }, ptr %37, 1 +// CHECK-NEXT: %40 = extractvalue { ptr, ptr } %39, 1 +// CHECK-NEXT: %41 = extractvalue { ptr, ptr } %39, 0 +// CHECK-NEXT: %__llgo_funcval_code4 = call ptr asm "", "=r,0"(ptr %41) +// CHECK-NEXT: %42 = call i1 %__llgo_funcval_code4(ptr {{(nest|swiftself)}} %40) +// CHECK-NEXT: br i1 %42, label %_llgo_10, label %_llgo_9 +// CHECK-EMPTY: +// CHECK-NEXT: _llgo_12: ; preds = %_llgo_8 +// CHECK-NEXT: call void @"{{.*}}/runtime/internal/runtime.PanicTypeAssert"(ptr %33, %"{{.*}}/runtime/internal/runtime.String" { ptr @10, i64 23 }, %"{{.*}}/runtime/internal/runtime.String" { ptr @6, i64 5 }) +// CHECK-NEXT: unreachable +// CHECK-NEXT: } + +// CHECK-LABEL: define i1 @"main.(*nilReceiver).IsNil"(ptr %0){{.*}} { +// CHECK-NEXT: _llgo_0: +// CHECK-NEXT: %1 = icmp eq ptr %0, null +// CHECK-NEXT: ret i1 %1 +// CHECK-NEXT: } + +// CHECK-LABEL: define { { ptr, ptr }, ptr } @main.zeroSizedAddressCapture(){{.*}} { +// CHECK-NEXT: _llgo_0: +// CHECK-NEXT: ret { { ptr, ptr }, ptr } { { ptr, ptr } { ptr @"main.zeroSizedAddressCapture$1", ptr null }, ptr @"__llgo.moduleZeroSizedAlloc$" } +// CHECK-NEXT: } + +// CHECK-LABEL: define ptr @"main.zeroSizedAddressCapture$1"(){{.*}} { +// CHECK-NEXT: _llgo_0: +// CHECK-NEXT: ret ptr @"__llgo.moduleZeroSizedAlloc$" +// CHECK-NEXT: } + +// CHECK-LABEL: define { ptr, ptr } @main.zeroSizedCapture(){{.*}} { +// CHECK-NEXT: _llgo_0: +// CHECK-NEXT: ret { ptr, ptr } { ptr @"main.zeroSizedCapture$1", ptr null } +// CHECK-NEXT: } + +// CHECK-LABEL: define i64 @"main.zeroSizedCapture$1"(){{.*}} { +// CHECK-NEXT: _llgo_0: +// CHECK-NEXT: br i1 false, label %_llgo_1, label %_llgo_2 +// CHECK-EMPTY: +// CHECK-NEXT: _llgo_1: ; preds = %_llgo_0 +// CHECK-NEXT: ret i64 0 +// CHECK-EMPTY: +// CHECK-NEXT: _llgo_2: ; preds = %_llgo_0 +// CHECK-NEXT: ret i64 42 +// CHECK-NEXT: } + +// CHECK-LABEL: define { ptr, ptr } @main.zeroSizedPointerCapture(ptr %0){{.*}} { +// CHECK-NEXT: _llgo_0: +// CHECK-NEXT: %1 = call ptr @"{{.*}}/runtime/internal/runtime.AllocZ"(i64 8) +// CHECK-NEXT: store ptr %0, ptr %1, align 8 +// CHECK-NEXT: %2 = call ptr @"{{.*}}/runtime/internal/runtime.AllocU"(i64 8) +// CHECK-NEXT: %3 = getelementptr inbounds { ptr }, ptr %2, i32 0, i32 0 +// CHECK-NEXT: store ptr %1, ptr %3, align 8 +// CHECK-NEXT: %4 = insertvalue { ptr, ptr } { ptr @"main.zeroSizedPointerCapture$1", ptr undef }, ptr %2, 1 +// CHECK-NEXT: ret { ptr, ptr } %4 +// CHECK-NEXT: } + +// CHECK-LABEL: define i1 @"main.zeroSizedPointerCapture$1"(ptr {{(nest|swiftself)}} %0){{.*}} { +// CHECK-NEXT: _llgo_0: +// CHECK-NEXT: %1 = load { ptr }, ptr %0, align 8 +// CHECK-NEXT: %2 = extractvalue { ptr } %1, 0 +// CHECK-NEXT: %3 = load ptr, ptr %2, align 8 +// CHECK-NEXT: %4 = icmp eq ptr %3, null +// CHECK-NEXT: ret i1 %4 +// CHECK-NEXT: } + +// CHECK-LABEL: define i1 @"main.(*nilReceiver).IsNil$bound"(ptr {{(nest|swiftself)}} %0){{.*}} { +// CHECK-NEXT: _llgo_0: +// CHECK-NEXT: %1 = load { ptr }, ptr %0, align 8 +// CHECK-NEXT: %2 = extractvalue { ptr } %1, 0 +// CHECK-NEXT: %3 = call i1 @"main.(*nilReceiver).IsNil"(ptr %2) +// CHECK-NEXT: ret i1 %3 +// CHECK-NEXT: } + +// CHECK-LABEL: define i1 @"main.interface{IsNil() bool}.IsNil$bound"(ptr {{(nest|swiftself)}} %0){{.*}} { +// CHECK-NEXT: _llgo_0: +// CHECK-NEXT: %1 = load { %"{{.*}}/runtime/internal/runtime.iface" }, ptr %0, align 8 +// CHECK-NEXT: %2 = extractvalue { %"{{.*}}/runtime/internal/runtime.iface" } %1, 0 +// CHECK-NEXT: %3 = call ptr @"{{.*}}/runtime/internal/runtime.IfacePtrData"(%"{{.*}}/runtime/internal/runtime.iface" %2) +// CHECK-NEXT: %4 = extractvalue %"{{.*}}/runtime/internal/runtime.iface" %2, 0 +// CHECK-NEXT: %5 = getelementptr ptr, ptr %4, i64 3 +// CHECK-NEXT: %6 = load ptr, ptr %5, align 8 +// CHECK-NEXT: %7 = insertvalue { ptr, ptr } undef, ptr %6, 0 +// CHECK-NEXT: %8 = insertvalue { ptr, ptr } %7, ptr %3, 1 +// CHECK-NEXT: %9 = extractvalue { ptr, ptr } %8, 1 +// CHECK-NEXT: %10 = extractvalue { ptr, ptr } %8, 0 +// CHECK-NEXT: %11 = call i1 %10(ptr %9) +// CHECK-NEXT: ret i1 %11 +// CHECK-NEXT: } diff --git a/cl/_testgo/cursor/in.go b/cl/_testgo/cursor/in.go index d0a2fc24bf..3fa82f1704 100644 --- a/cl/_testgo/cursor/in.go +++ b/cl/_testgo/cursor/in.go @@ -66,7 +66,8 @@ func (c Cursor) Node() ast.Node { // CHECK-NEXT: %20 = insertvalue { ptr, ptr } { ptr @"main.Cursor.FindNode$1", ptr undef }, ptr %15, 1 // CHECK-NEXT: %21 = extractvalue %"iter.Seq[main.Cursor]" %13, 1 // CHECK-NEXT: %22 = extractvalue %"iter.Seq[main.Cursor]" %13, 0 -// CHECK-NEXT: call void %22(ptr %21, { ptr, ptr } %20) +// CHECK-NEXT: %__llgo_funcval_code = call ptr asm "", "=r,0"(ptr %22) +// CHECK-NEXT: call void %__llgo_funcval_code(ptr {{(nest|swiftself)}} %21, { ptr, ptr } %20) // CHECK-NEXT: %23 = load i64, ptr %14, align 8 // CHECK-NEXT: %24 = icmp eq i64 %23, -1 // CHECK-NEXT: br i1 %24, label %_llgo_4, label %_llgo_5 @@ -497,7 +498,7 @@ const ( nValueSpec ) -// CHECK-LABEL: define i1 @"main.Cursor.FindNode$1"(ptr %0, %main.Cursor %1){{.*}} { +// CHECK-LABEL: define i1 @"main.Cursor.FindNode$1"(ptr {{(nest|swiftself)}} %0, %main.Cursor %1){{.*}} { // CHECK-NEXT: _llgo_0: // CHECK-NEXT: %2 = load { ptr, ptr, ptr, ptr }, ptr %0, align 8 // CHECK-NEXT: %3 = extractvalue { ptr, ptr, ptr, ptr } %2, 0 @@ -596,7 +597,7 @@ const ( // CHECK-NEXT: ret %"iter.Seq[main.Cursor]" %10 // CHECK-NEXT: } -// CHECK-LABEL: define void @"main.Cursor.Preorder$1"(ptr %0, { ptr, ptr } %1){{.*}} { +// CHECK-LABEL: define void @"main.Cursor.Preorder$1"(ptr {{(nest|swiftself)}} %0, { ptr, ptr } %1){{.*}} { // CHECK-NEXT: _llgo_0: // CHECK-NEXT: %2 = load { ptr, ptr }, ptr %0, align 8 // CHECK-NEXT: %3 = extractvalue { ptr, ptr } %2, 0 @@ -683,7 +684,8 @@ const ( // CHECK-NEXT: %56 = load %main.Cursor, ptr %50, align 8 // CHECK-NEXT: %57 = extractvalue { ptr, ptr } %1, 1 // CHECK-NEXT: %58 = extractvalue { ptr, ptr } %1, 0 -// CHECK-NEXT: %59 = call i1 %58(ptr %57, %main.Cursor %56) +// CHECK-NEXT: %__llgo_funcval_code = call ptr asm "", "=r,0"(ptr %58) +// CHECK-NEXT: %59 = call i1 %__llgo_funcval_code(ptr {{(nest|swiftself)}} %57, %main.Cursor %56) // CHECK-NEXT: br i1 %59, label %_llgo_6, label %_llgo_3 // CHECK-EMPTY: // CHECK-NEXT: _llgo_8: ; preds = %_llgo_6 @@ -2157,27 +2159,3 @@ const ( // CHECK-NEXT: %456 = extractvalue { ptr, i1 } %454, 1 // CHECK-NEXT: br i1 %456, label %_llgo_113, label %_llgo_114 // CHECK-NEXT: } - -// CHECK-LABEL: define linkonce i1 @"__llgo_stub.{{.*}}/runtime/internal/runtime.memequal64"(ptr %0, ptr %1, ptr %2){{.*}} { -// CHECK-NEXT: _llgo_0: -// CHECK-NEXT: %3 = tail call i1 @"{{.*}}/runtime/internal/runtime.memequal64"(ptr %1, ptr %2) -// CHECK-NEXT: ret i1 %3 -// CHECK-NEXT: } - -// CHECK-LABEL: define linkonce i1 @"__llgo_stub.{{.*}}/runtime/internal/runtime.memequal8"(ptr %0, ptr %1, ptr %2){{.*}} { -// CHECK-NEXT: _llgo_0: -// CHECK-NEXT: %3 = tail call i1 @"{{.*}}/runtime/internal/runtime.memequal8"(ptr %1, ptr %2) -// CHECK-NEXT: ret i1 %3 -// CHECK-NEXT: } - -// CHECK-LABEL: define linkonce i1 @"__llgo_stub.{{.*}}/runtime/internal/runtime.nilinterequal"(ptr %0, ptr %1, ptr %2){{.*}} { -// CHECK-NEXT: _llgo_0: -// CHECK-NEXT: %3 = tail call i1 @"{{.*}}/runtime/internal/runtime.nilinterequal"(ptr %1, ptr %2) -// CHECK-NEXT: ret i1 %3 -// CHECK-NEXT: } - -// CHECK-LABEL: define linkonce i1 @"__llgo_stub.{{.*}}/runtime/internal/runtime.interequal"(ptr %0, ptr %1, ptr %2){{.*}} { -// CHECK-NEXT: _llgo_0: -// CHECK-NEXT: %3 = tail call i1 @"{{.*}}/runtime/internal/runtime.interequal"(ptr %1, ptr %2) -// CHECK-NEXT: ret i1 %3 -// CHECK-NEXT: } diff --git a/cl/_testgo/deferclosure/in.go b/cl/_testgo/deferclosure/in.go index 1ae41c8a26..4428ece8d6 100644 --- a/cl/_testgo/deferclosure/in.go +++ b/cl/_testgo/deferclosure/in.go @@ -1,6 +1,6 @@ package main -// Test for covering the closureStub branches in ssa/package.go +// Test deferred closure and method-value lowering. // Type for holding a function type Handler struct { diff --git a/cl/_testgo/deferiface/expect.txt b/cl/_testgo/deferiface/expect.txt new file mode 100644 index 0000000000..a7924147e5 --- /dev/null +++ b/cl/_testgo/deferiface/expect.txt @@ -0,0 +1,2 @@ +body +reset 42 diff --git a/cl/_testgo/deferiface/in.go b/cl/_testgo/deferiface/in.go new file mode 100644 index 0000000000..bcee22b9ae --- /dev/null +++ b/cl/_testgo/deferiface/in.go @@ -0,0 +1,148 @@ +// LITTEST +package main + +// CHECK: {{^}}@0 = private unnamed_addr constant [5 x i8] c"reset", align 1{{$}} +// CHECK: {{^}}@8 = private unnamed_addr constant [4 x i8] c"body", align 1{{$}} + +type resetter interface { + Reset() +} + +type item struct { + value int +} + +func (p *item) Reset() { + println("reset", p.value) +} + +func run(v resetter) { + defer v.Reset() + println("body") +} + +func main() { + run(&item{42}) +} + +// CHECK-LABEL: define void @main.init(){{.*}} { +// CHECK-NEXT: _llgo_0: +// CHECK-NEXT: %0 = load i1, ptr @"main.init$guard", align 1 +// CHECK-NEXT: br i1 %0, label %_llgo_2, label %_llgo_1 +// CHECK-EMPTY: +// CHECK-NEXT: _llgo_1: ; preds = %_llgo_0 +// CHECK-NEXT: store i1 true, ptr @"main.init$guard", align 1 +// CHECK-NEXT: br label %_llgo_2 +// CHECK-EMPTY: +// CHECK-NEXT: _llgo_2: ; preds = %_llgo_1, %_llgo_0 +// CHECK-NEXT: ret void +// CHECK-NEXT: } + +// CHECK-LABEL: define void @"main.(*item).Reset"(ptr %0){{.*}} { +// CHECK-NEXT: _llgo_0: +// CHECK-NEXT: %1 = getelementptr inbounds %main.item, ptr %0, i32 0, i32 0 +// CHECK-NEXT: %2 = load i64, ptr %1, align 8 +// CHECK-NEXT: call void @"{{.*}}/runtime/internal/runtime.PrintString"(%"{{.*}}/runtime/internal/runtime.String" { ptr @0, i64 5 }) +// CHECK-NEXT: call void @"{{.*}}/runtime/internal/runtime.PrintByte"(i8 32) +// CHECK-NEXT: call void @"{{.*}}/runtime/internal/runtime.PrintInt"(i64 %2) +// CHECK-NEXT: call void @"{{.*}}/runtime/internal/runtime.PrintByte"(i8 10) +// CHECK-NEXT: ret void +// CHECK-NEXT: } + +// CHECK-LABEL: define void @main.main(){{.*}} { +// CHECK-NEXT: _llgo_0: +// CHECK-NEXT: %0 = call ptr @"{{.*}}/runtime/internal/runtime.AllocZ"(i64 8) +// CHECK-NEXT: %1 = getelementptr inbounds %main.item, ptr %0, i32 0, i32 0 +// CHECK-NEXT: store i64 42, ptr %1, align 8 +// CHECK-NEXT: %2 = call ptr @"{{.*}}/runtime/internal/runtime.NewItab"(ptr @"_llgo_iface$yjH5fOWhYIH6Pv7ce-kmK-CVKIWOLvKPVzRvjwBotEM", ptr @"*_llgo_main.item") +// CHECK-NEXT: %3 = insertvalue %"{{.*}}/runtime/internal/runtime.iface" undef, ptr %2, 0 +// CHECK-NEXT: %4 = insertvalue %"{{.*}}/runtime/internal/runtime.iface" %3, ptr %0, 1 +// CHECK-NEXT: call void @main.run(%"{{.*}}/runtime/internal/runtime.iface" %4) +// CHECK-NEXT: ret void +// CHECK-NEXT: } + +// CHECK-LABEL: define void @main.run(%"{{.*}}/runtime/internal/runtime.iface" %0){{.*}} { +// CHECK-NEXT: _llgo_0: +// CHECK-NEXT: %1 = call ptr @"{{.*}}/runtime/internal/runtime.IfacePtrData"(%"{{.*}}/runtime/internal/runtime.iface" %0) +// CHECK-NEXT: %2 = extractvalue %"{{.*}}/runtime/internal/runtime.iface" %0, 0 +// CHECK-NEXT: %3 = getelementptr ptr, ptr %2, i64 3 +// CHECK-NEXT: %4 = load ptr, ptr %3, align 8 +// CHECK-NEXT: %5 = insertvalue { ptr, ptr } undef, ptr %4, 0 +// CHECK-NEXT: %6 = insertvalue { ptr, ptr } %5, ptr %1, 1 +// CHECK-NEXT: %7 = call ptr @"{{.*}}/runtime/internal/runtime.GetThreadDefer"() +// CHECK-NEXT: %8 = alloca i8, i64 {{.*}}, align 1 +// CHECK-NEXT: %9 = call ptr @"{{.*}}/runtime/internal/runtime.AllocU"(i64 48) +// CHECK-NEXT: %10 = getelementptr inbounds %"{{.*}}/runtime/internal/runtime.Defer", ptr %9, i32 0, i32 0 +// CHECK-NEXT: store ptr %8, ptr %10, align 8 +// CHECK-NEXT: %11 = getelementptr inbounds %"{{.*}}/runtime/internal/runtime.Defer", ptr %9, i32 0, i32 1 +// CHECK-NEXT: store i64 0, ptr %11, align 8 +// CHECK-NEXT: %12 = getelementptr inbounds %"{{.*}}/runtime/internal/runtime.Defer", ptr %9, i32 0, i32 2 +// CHECK-NEXT: store ptr %7, ptr %12, align 8 +// CHECK-NEXT: %13 = getelementptr inbounds %"{{.*}}/runtime/internal/runtime.Defer", ptr %9, i32 0, i32 3 +// CHECK-NEXT: store ptr blockaddress(@main.run, %_llgo_2), ptr %13, align 8 +// CHECK-NEXT: call void @"{{.*}}/runtime/internal/runtime.SetThreadDefer"(ptr %9) +// CHECK-NEXT: %14 = getelementptr inbounds %"{{.*}}/runtime/internal/runtime.Defer", ptr %9, i32 0, i32 1 +// CHECK-NEXT: %15 = getelementptr inbounds %"{{.*}}/runtime/internal/runtime.Defer", ptr %9, i32 0, i32 3 +// CHECK-NEXT: %16 = getelementptr inbounds %"{{.*}}/runtime/internal/runtime.Defer", ptr %9, i32 0, i32 4 +// CHECK-NEXT: %17 = getelementptr inbounds %"{{.*}}/runtime/internal/runtime.Defer", ptr %9, i32 0, i32 5 +// CHECK-NEXT: store ptr null, ptr %17, align 8 +// CHECK-NEXT: %18 = call i32 @{{.*}}sigsetjmp(ptr %8, i32 0) +// CHECK-NEXT: %19 = icmp eq i32 %18, 0 +// CHECK-NEXT: br i1 %19, label %_llgo_4, label %_llgo_5 +// CHECK-EMPTY: +// CHECK-NEXT: _llgo_1: ; preds = %_llgo_3 +// CHECK-NEXT: ret void +// CHECK-EMPTY: +// CHECK-NEXT: _llgo_2: ; preds = %_llgo_5, %_llgo_4 +// CHECK-NEXT: store ptr blockaddress(@main.run, %_llgo_3), ptr %15, align 8 +// CHECK-NEXT: %20 = load i64, ptr %14, align 8 +// CHECK-NEXT: %21 = load ptr, ptr %17, align 8 +// CHECK-NEXT: %22 = icmp ne ptr %21, null +// CHECK-NEXT: br i1 %22, label %_llgo_7, label %_llgo_8 +// CHECK-EMPTY: +// CHECK-NEXT: _llgo_3: ; preds = %_llgo_5, %_llgo_8 +// CHECK-NEXT: call void @"{{.*}}/runtime/internal/runtime.Rethrow"(ptr %7) +// CHECK-NEXT: br label %_llgo_1 +// CHECK-EMPTY: +// CHECK-NEXT: _llgo_4: ; preds = %_llgo_0 +// CHECK-NEXT: %23 = load ptr, ptr %17, align 8 +// CHECK-NEXT: %24 = call ptr @"{{.*}}/runtime/internal/runtime.AllocU"(i64 32) +// CHECK-NEXT: %25 = getelementptr inbounds { ptr, i64, { ptr, ptr } }, ptr %24, i32 0, i32 0 +// CHECK-NEXT: store ptr %23, ptr %25, align 8 +// CHECK-NEXT: %26 = getelementptr inbounds { ptr, i64, { ptr, ptr } }, ptr %24, i32 0, i32 1 +// CHECK-NEXT: store i64 0, ptr %26, align 8 +// CHECK-NEXT: %27 = getelementptr inbounds { ptr, i64, { ptr, ptr } }, ptr %24, i32 0, i32 2 +// CHECK-NEXT: store { ptr, ptr } %6, ptr %27, align 8 +// CHECK-NEXT: store ptr %24, ptr %17, align 8 +// CHECK-NEXT: call void @"{{.*}}/runtime/internal/runtime.PrintString"(%"{{.*}}/runtime/internal/runtime.String" { ptr @8, i64 4 }) +// CHECK-NEXT: call void @"{{.*}}/runtime/internal/runtime.PrintByte"(i8 10) +// CHECK-NEXT: store ptr blockaddress(@main.run, %_llgo_6), ptr %16, align 8 +// CHECK-NEXT: br label %_llgo_2 +// CHECK-EMPTY: +// CHECK-NEXT: _llgo_5: ; preds = %_llgo_0 +// CHECK-NEXT: store ptr blockaddress(@main.run, %_llgo_3), ptr %16, align 8 +// CHECK-NEXT: %28 = load ptr, ptr %15, align 8 +// CHECK-NEXT: indirectbr ptr %28, [label %_llgo_3, label %_llgo_2] +// CHECK-EMPTY: +// CHECK-NEXT: _llgo_6: ; preds = %_llgo_8 +// CHECK-NEXT: ret void +// CHECK-EMPTY: +// CHECK-NEXT: _llgo_7: ; preds = %_llgo_2 +// CHECK-NEXT: %29 = load ptr, ptr %17, align 8 +// CHECK-NEXT: %30 = load { ptr, i64, { ptr, ptr } }, ptr %29, align 8 +// CHECK-NEXT: %31 = extractvalue { ptr, i64, { ptr, ptr } } %30, 0 +// CHECK-NEXT: store ptr %31, ptr %17, align 8 +// CHECK-NEXT: %32 = extractvalue { ptr, i64, { ptr, ptr } } %30, 2 +// CHECK-NEXT: call void @"{{.*}}/runtime/internal/runtime.FreeDeferNode"(ptr %29) +// CHECK-NEXT: %33 = extractvalue { ptr, ptr } %32, 1 +// CHECK-NEXT: %34 = extractvalue { ptr, ptr } %32, 0 +// CHECK-NEXT: call void %34(ptr %33) +// CHECK-NEXT: br label %_llgo_8 +// CHECK-EMPTY: +// CHECK-NEXT: _llgo_8: ; preds = %_llgo_7, %_llgo_2 +// CHECK-NEXT: %35 = load %"{{.*}}/runtime/internal/runtime.Defer", ptr %9, align 8 +// CHECK-NEXT: %36 = extractvalue %"{{.*}}/runtime/internal/runtime.Defer" %35, 2 +// CHECK-NEXT: call void @"{{.*}}/runtime/internal/runtime.SetThreadDefer"(ptr %36) +// CHECK-NEXT: %37 = load ptr, ptr %16, align 8 +// CHECK-NEXT: indirectbr ptr %37, [label %_llgo_3, label %_llgo_6] +// CHECK-NEXT: } diff --git a/cl/_testgo/equal/in.go b/cl/_testgo/equal/in.go index 0a2347e2c4..b1b657132e 100644 --- a/cl/_testgo/equal/in.go +++ b/cl/_testgo/equal/in.go @@ -77,7 +77,7 @@ func init() { // CHECK-NEXT: } var n int fn3 := func() { println(n) } - // CHECK-LABEL: define void @"main.init#1$2"(ptr %0){{.*}} { + // CHECK-LABEL: define void @"main.init#1$2"(ptr {{(nest|swiftself)}} %0){{.*}} { // CHECK-NEXT: _llgo_0: // CHECK-NEXT: %1 = load { ptr }, ptr %0, align 8 // CHECK-NEXT: %2 = extractvalue { ptr } %1, 0 diff --git a/cl/_testgo/genericembediface/in.go b/cl/_testgo/genericembediface/in.go index 3ac1e4ccef..be2c2122ee 100644 --- a/cl/_testgo/genericembediface/in.go +++ b/cl/_testgo/genericembediface/in.go @@ -133,12 +133,6 @@ func main() { // CHECK-NEXT: ret %"{{.*}}/runtime/internal/runtime.String" %3 // CHECK-NEXT: } -// CHECK-LABEL: define linkonce i1 @"__llgo_stub.{{.*}}/runtime/internal/runtime.interequal"(ptr %0, ptr %1, ptr %2){{.*}} { -// CHECK-NEXT: _llgo_0: -// CHECK-NEXT: %3 = tail call i1 @"{{.*}}/runtime/internal/runtime.interequal"(ptr %1, ptr %2) -// CHECK-NEXT: ret i1 %3 -// CHECK-NEXT: } - // CHECK-LABEL: define linkonce %"{{.*}}/runtime/internal/runtime.String" @"{{.*}}/cl/_testgo/genericembediface/streamlib.(*GenericServerStream[main.Request,main.Response]).Context"(ptr %0){{.*}} { // CHECK-NEXT: _llgo_0: // CHECK-NEXT: %1 = getelementptr inbounds %"{{.*}}/cl/_testgo/genericembediface/streamlib.GenericServerStream[main.Request,main.Response]", ptr %0, i32 0, i32 0 @@ -173,45 +167,3 @@ func main() { // CHECK-NEXT: %12 = call %"{{.*}}/runtime/internal/runtime.String" %11(ptr %10) // CHECK-NEXT: ret %"{{.*}}/runtime/internal/runtime.String" %12 // CHECK-NEXT: } - -// CHECK-LABEL: define linkonce %"{{.*}}/runtime/internal/runtime.String" @"__llgo_stub.{{.*}}/cl/_testgo/genericembediface/streamlib.GenericServerStream[main.Request,main.Response].Context"(ptr %0, %"{{.*}}/cl/_testgo/genericembediface/streamlib.GenericServerStream[main.Request,main.Response]" %1){{.*}} { -// CHECK-NEXT: _llgo_0: -// CHECK-NEXT: %2 = tail call %"{{.*}}/runtime/internal/runtime.String" @"{{.*}}/cl/_testgo/genericembediface/streamlib.GenericServerStream[main.Request,main.Response].Context"(%"{{.*}}/cl/_testgo/genericembediface/streamlib.GenericServerStream[main.Request,main.Response]" %1) -// CHECK-NEXT: ret %"{{.*}}/runtime/internal/runtime.String" %2 -// CHECK-NEXT: } - -// CHECK-LABEL: define linkonce %"{{.*}}/runtime/internal/runtime.String" @"__llgo_stub.{{.*}}/cl/_testgo/genericembediface/streamlib.(*GenericServerStream[main.Request,main.Response]).Context"(ptr %0, ptr %1){{.*}} { -// CHECK-NEXT: _llgo_0: -// CHECK-NEXT: %2 = tail call %"{{.*}}/runtime/internal/runtime.String" @"{{.*}}/cl/_testgo/genericembediface/streamlib.(*GenericServerStream[main.Request,main.Response]).Context"(ptr %1) -// CHECK-NEXT: ret %"{{.*}}/runtime/internal/runtime.String" %2 -// CHECK-NEXT: } - -// CHECK-LABEL: define linkonce i1 @"__llgo_stub.{{.*}}/runtime/internal/runtime.memequal0"(ptr %0, ptr %1, ptr %2){{.*}} { -// CHECK-NEXT: _llgo_0: -// CHECK-NEXT: %3 = tail call i1 @"{{.*}}/runtime/internal/runtime.memequal0"(ptr %1, ptr %2) -// CHECK-NEXT: ret i1 %3 -// CHECK-NEXT: } - -// CHECK-LABEL: define linkonce %"{{.*}}/runtime/internal/runtime.iface" @"__llgo_stub.main.(*server).ServerReflectionInfo"(ptr %0, ptr %1, %"{{.*}}/runtime/internal/runtime.iface" %2){{.*}} { -// CHECK-NEXT: _llgo_0: -// CHECK-NEXT: %3 = tail call %"{{.*}}/runtime/internal/runtime.iface" @"main.(*server).ServerReflectionInfo"(ptr %1, %"{{.*}}/runtime/internal/runtime.iface" %2) -// CHECK-NEXT: ret %"{{.*}}/runtime/internal/runtime.iface" %3 -// CHECK-NEXT: } - -// CHECK-LABEL: define linkonce %"{{.*}}/runtime/internal/runtime.iface" @__llgo_stub.main.server.ServerReflectionInfo(ptr %0, %main.server %1, %"{{.*}}/runtime/internal/runtime.iface" %2){{.*}} { -// CHECK-NEXT: _llgo_0: -// CHECK-NEXT: %3 = tail call %"{{.*}}/runtime/internal/runtime.iface" @main.server.ServerReflectionInfo(%main.server %1, %"{{.*}}/runtime/internal/runtime.iface" %2) -// CHECK-NEXT: ret %"{{.*}}/runtime/internal/runtime.iface" %3 -// CHECK-NEXT: } - -// CHECK-LABEL: define linkonce %"{{.*}}/runtime/internal/runtime.String" @"__llgo_stub.main.(*stream).Context"(ptr %0, ptr %1){{.*}} { -// CHECK-NEXT: _llgo_0: -// CHECK-NEXT: %2 = tail call %"{{.*}}/runtime/internal/runtime.String" @"main.(*stream).Context"(ptr %1) -// CHECK-NEXT: ret %"{{.*}}/runtime/internal/runtime.String" %2 -// CHECK-NEXT: } - -// CHECK-LABEL: define linkonce %"{{.*}}/runtime/internal/runtime.String" @__llgo_stub.main.stream.Context(ptr %0, %main.stream %1){{.*}} { -// CHECK-NEXT: _llgo_0: -// CHECK-NEXT: %2 = tail call %"{{.*}}/runtime/internal/runtime.String" @main.stream.Context(%main.stream %1) -// CHECK-NEXT: ret %"{{.*}}/runtime/internal/runtime.String" %2 -// CHECK-NEXT: } diff --git a/cl/_testgo/genericiter/in.go b/cl/_testgo/genericiter/in.go index 14ea1f8284..7a3e4d9f7d 100644 --- a/cl/_testgo/genericiter/in.go +++ b/cl/_testgo/genericiter/in.go @@ -62,7 +62,7 @@ func (t *Tree) Ascend(iterator Iterator) { func main() { var got int tree := (*Tree)(new(TreeG[int])) - // CHECK-LABEL: define i1 @"main.main$1"(ptr %0, i64 %1){{.*}} { + // CHECK-LABEL: define i1 @"main.main$1"(ptr {{(nest|swiftself)}} %0, i64 %1){{.*}} { // CHECK-NEXT: _llgo_0: // CHECK-NEXT: %2 = add i64 %1, 1 // CHECK-NEXT: %3 = load { ptr }, ptr %0, align 8 @@ -85,6 +85,7 @@ func main() { // CHECK-NEXT: _llgo_0: // CHECK-NEXT: %2 = extractvalue %"main.IteratorG[int]" %1, 1 // CHECK-NEXT: %3 = extractvalue %"main.IteratorG[int]" %1, 0 -// CHECK-NEXT: %4 = call i1 %3(ptr %2, i64 0) +// CHECK-NEXT: %__llgo_funcval_code = call ptr asm "", "=r,0"(ptr %3) +// CHECK-NEXT: %4 = call i1 %__llgo_funcval_code(ptr {{(nest|swiftself)}} %2, i64 0) // CHECK-NEXT: ret void // CHECK-NEXT: } diff --git a/cl/_testgo/goroutine/in.go b/cl/_testgo/goroutine/in.go index 112e3c2906..0521c06343 100644 --- a/cl/_testgo/goroutine/in.go +++ b/cl/_testgo/goroutine/in.go @@ -16,7 +16,7 @@ func main() { // CHECK: call void @"{{.*}}NewProc"(ptr @"main._llgo_routine$2", ptr {{%[0-9]+}}, i64 0) // CHECK: call void @"{{.*}}PrintString"(%"{{.*}}String" { ptr @2, i64 1 }) // CHECK: ret void - // CHECK-LABEL: define void @"main.main$1"(ptr %0, %"{{.*}}String" %1){{.*}} { + // CHECK-LABEL: define void @"main.main$1"(ptr {{(nest|swiftself)}} %0, %"{{.*}}String" %1){{.*}} { // CHECK-NEXT: _llgo_0: // CHECK-NEXT: call void @"{{.*}}PrintString"(%"{{.*}}String" %1) // CHECK-NEXT: call void @"{{.*}}PrintByte"(i8 10) @@ -49,5 +49,6 @@ func main() { // CHECK-NEXT: call void @"{{.*}}FreeRoot"(ptr %0) // CHECK-NEXT: %4 = extractvalue { ptr, ptr } %2, 1 // CHECK-NEXT: %5 = extractvalue { ptr, ptr } %2, 0 -// CHECK-NEXT: call void %5(ptr %4, %"{{.*}}String" %3) +// CHECK-NEXT: %__llgo_funcval_code = call ptr asm "", "=r,0"(ptr %5) +// CHECK-NEXT: call void %__llgo_funcval_code(ptr {{(nest|swiftself)}} %4, %"{{.*}}String" %3) // CHECK-NEXT: ret ptr null diff --git a/cl/_testgo/ifaceconv/in.go b/cl/_testgo/ifaceconv/in.go index 2f1a83cd2b..b7b9ce6160 100644 --- a/cl/_testgo/ifaceconv/in.go +++ b/cl/_testgo/ifaceconv/in.go @@ -464,57 +464,3 @@ func main() { // CHECK-NEXT: %125 = extractvalue { %"{{.*}}/runtime/internal/runtime.iface", i1 } %123, 1 // CHECK-NEXT: br i1 %125, label %_llgo_18, label %_llgo_17 // CHECK-NEXT: } - -// CHECK-LABEL: define linkonce i1 @"__llgo_stub.{{.*}}/runtime/internal/runtime.nilinterequal"(ptr %0, ptr %1, ptr %2){{.*}} { -// CHECK-NEXT: _llgo_0: -// CHECK-NEXT: %3 = tail call i1 @"{{.*}}/runtime/internal/runtime.nilinterequal"(ptr %1, ptr %2) -// CHECK-NEXT: ret i1 %3 -// CHECK-NEXT: } - -// CHECK-LABEL: define linkonce i1 @"__llgo_stub.{{.*}}/runtime/internal/runtime.interequal"(ptr %0, ptr %1, ptr %2){{.*}} { -// CHECK-NEXT: _llgo_0: -// CHECK-NEXT: %3 = tail call i1 @"{{.*}}/runtime/internal/runtime.interequal"(ptr %1, ptr %2) -// CHECK-NEXT: ret i1 %3 -// CHECK-NEXT: } - -// CHECK-LABEL: define linkonce i1 @"__llgo_stub.{{.*}}/runtime/internal/runtime.memequal0"(ptr %0, ptr %1, ptr %2){{.*}} { -// CHECK-NEXT: _llgo_0: -// CHECK-NEXT: %3 = tail call i1 @"{{.*}}/runtime/internal/runtime.memequal0"(ptr %1, ptr %2) -// CHECK-NEXT: ret i1 %3 -// CHECK-NEXT: } - -// CHECK-LABEL: define linkonce void @"__llgo_stub.main.(*C1).f"(ptr %0, ptr %1){{.*}} { -// CHECK-NEXT: _llgo_0: -// CHECK-NEXT: tail call void @"main.(*C1).f"(ptr %1) -// CHECK-NEXT: ret void -// CHECK-NEXT: } - -// CHECK-LABEL: define linkonce void @__llgo_stub.main.C1.f(ptr %0, %main.C1 %1){{.*}} { -// CHECK-NEXT: _llgo_0: -// CHECK-NEXT: tail call void @main.C1.f(%main.C1 %1) -// CHECK-NEXT: ret void -// CHECK-NEXT: } - -// CHECK-LABEL: define linkonce void @"__llgo_stub.main.(*C2).f"(ptr %0, ptr %1){{.*}} { -// CHECK-NEXT: _llgo_0: -// CHECK-NEXT: tail call void @"main.(*C2).f"(ptr %1) -// CHECK-NEXT: ret void -// CHECK-NEXT: } - -// CHECK-LABEL: define linkonce void @"__llgo_stub.main.(*C2).g"(ptr %0, ptr %1){{.*}} { -// CHECK-NEXT: _llgo_0: -// CHECK-NEXT: tail call void @"main.(*C2).g"(ptr %1) -// CHECK-NEXT: ret void -// CHECK-NEXT: } - -// CHECK-LABEL: define linkonce void @__llgo_stub.main.C2.f(ptr %0, %main.C2 %1){{.*}} { -// CHECK-NEXT: _llgo_0: -// CHECK-NEXT: tail call void @main.C2.f(%main.C2 %1) -// CHECK-NEXT: ret void -// CHECK-NEXT: } - -// CHECK-LABEL: define linkonce void @__llgo_stub.main.C2.g(ptr %0, %main.C2 %1){{.*}} { -// CHECK-NEXT: _llgo_0: -// CHECK-NEXT: tail call void @main.C2.g(%main.C2 %1) -// CHECK-NEXT: ret void -// CHECK-NEXT: } diff --git a/cl/_testgo/ifaceprom/in.go b/cl/_testgo/ifaceprom/in.go index b75d561191..3dd49d6e04 100644 --- a/cl/_testgo/ifaceprom/in.go +++ b/cl/_testgo/ifaceprom/in.go @@ -347,7 +347,8 @@ func main() { // CHECK-NEXT: %90 = insertvalue { ptr, ptr } { ptr @"main.I.one$bound", ptr undef }, ptr %88, 1 // CHECK-NEXT: %91 = extractvalue { ptr, ptr } %90, 1 // CHECK-NEXT: %92 = extractvalue { ptr, ptr } %90, 0 -// CHECK-NEXT: %93 = call i64 %92(ptr %91) +// CHECK-NEXT: %__llgo_funcval_code = call ptr asm "", "=r,0"(ptr %92) +// CHECK-NEXT: %93 = call i64 %__llgo_funcval_code(ptr {{(nest|swiftself)}} %91) // CHECK-NEXT: %94 = icmp ne i64 %93, 1 // CHECK-NEXT: br i1 %94, label %_llgo_5, label %_llgo_6 // CHECK-EMPTY: @@ -362,7 +363,8 @@ func main() { // CHECK-NEXT: %97 = insertvalue { ptr, ptr } { ptr @"main.I.one$bound", ptr undef }, ptr %95, 1 // CHECK-NEXT: %98 = extractvalue { ptr, ptr } %97, 1 // CHECK-NEXT: %99 = extractvalue { ptr, ptr } %97, 0 -// CHECK-NEXT: %100 = call i64 %99(ptr %98) +// CHECK-NEXT: %__llgo_funcval_code1 = call ptr asm "", "=r,0"(ptr %99) +// CHECK-NEXT: %100 = call i64 %__llgo_funcval_code1(ptr {{(nest|swiftself)}} %98) // CHECK-NEXT: %101 = icmp ne i64 %100, 1 // CHECK-NEXT: br i1 %101, label %_llgo_7, label %_llgo_8 // CHECK-EMPTY: @@ -377,7 +379,8 @@ func main() { // CHECK-NEXT: %104 = insertvalue { ptr, ptr } { ptr @"main.I.two$bound", ptr undef }, ptr %102, 1 // CHECK-NEXT: %105 = extractvalue { ptr, ptr } %104, 1 // CHECK-NEXT: %106 = extractvalue { ptr, ptr } %104, 0 -// CHECK-NEXT: %107 = call %"{{.*}}/runtime/internal/runtime.String" %106(ptr %105) +// CHECK-NEXT: %__llgo_funcval_code2 = call ptr asm "", "=r,0"(ptr %106) +// CHECK-NEXT: %107 = call %"{{.*}}/runtime/internal/runtime.String" %__llgo_funcval_code2(ptr {{(nest|swiftself)}} %105) // CHECK-NEXT: %108 = call i1 @"{{.*}}/runtime/internal/runtime.StringEqual"(%"{{.*}}/runtime/internal/runtime.String" %107, %"{{.*}}/runtime/internal/runtime.String" { ptr @0, i64 3 }) // CHECK-NEXT: %109 = xor i1 %108, true // CHECK-NEXT: br i1 %109, label %_llgo_13, label %_llgo_14 @@ -393,7 +396,8 @@ func main() { // CHECK-NEXT: %112 = insertvalue { ptr, ptr } { ptr @"main.I.two$bound", ptr undef }, ptr %110, 1 // CHECK-NEXT: %113 = extractvalue { ptr, ptr } %112, 1 // CHECK-NEXT: %114 = extractvalue { ptr, ptr } %112, 0 -// CHECK-NEXT: %115 = call %"{{.*}}/runtime/internal/runtime.String" %114(ptr %113) +// CHECK-NEXT: %__llgo_funcval_code3 = call ptr asm "", "=r,0"(ptr %114) +// CHECK-NEXT: %115 = call %"{{.*}}/runtime/internal/runtime.String" %__llgo_funcval_code3(ptr {{(nest|swiftself)}} %113) // CHECK-NEXT: %116 = call i1 @"{{.*}}/runtime/internal/runtime.StringEqual"(%"{{.*}}/runtime/internal/runtime.String" %115, %"{{.*}}/runtime/internal/runtime.String" { ptr @0, i64 3 }) // CHECK-NEXT: %117 = xor i1 %116, true // CHECK-NEXT: br i1 %117, label %_llgo_15, label %_llgo_16 @@ -403,49 +407,7 @@ func main() { // CHECK-NEXT: unreachable // CHECK-NEXT: } -// CHECK-LABEL: define linkonce i1 @"__llgo_stub.{{.*}}/runtime/internal/runtime.memequal0"(ptr %0, ptr %1, ptr %2){{.*}} { -// CHECK-NEXT: _llgo_0: -// CHECK-NEXT: %3 = tail call i1 @"{{.*}}/runtime/internal/runtime.memequal0"(ptr %1, ptr %2) -// CHECK-NEXT: ret i1 %3 -// CHECK-NEXT: } - -// CHECK-LABEL: define linkonce i64 @"__llgo_stub.main.(*impl).one"(ptr %0, ptr %1){{.*}} { -// CHECK-NEXT: _llgo_0: -// CHECK-NEXT: %2 = tail call i64 @"main.(*impl).one"(ptr %1) -// CHECK-NEXT: ret i64 %2 -// CHECK-NEXT: } - -// CHECK-LABEL: define linkonce i1 @"__llgo_stub.{{.*}}/runtime/internal/runtime.memequal64"(ptr %0, ptr %1, ptr %2){{.*}} { -// CHECK-NEXT: _llgo_0: -// CHECK-NEXT: %3 = tail call i1 @"{{.*}}/runtime/internal/runtime.memequal64"(ptr %1, ptr %2) -// CHECK-NEXT: ret i1 %3 -// CHECK-NEXT: } - -// CHECK-LABEL: define linkonce %"{{.*}}/runtime/internal/runtime.String" @"__llgo_stub.main.(*impl).two"(ptr %0, ptr %1){{.*}} { -// CHECK-NEXT: _llgo_0: -// CHECK-NEXT: %2 = tail call %"{{.*}}/runtime/internal/runtime.String" @"main.(*impl).two"(ptr %1) -// CHECK-NEXT: ret %"{{.*}}/runtime/internal/runtime.String" %2 -// CHECK-NEXT: } - -// CHECK-LABEL: define linkonce i64 @__llgo_stub.main.impl.one(ptr %0, %main.impl %1){{.*}} { -// CHECK-NEXT: _llgo_0: -// CHECK-NEXT: %2 = tail call i64 @main.impl.one(%main.impl %1) -// CHECK-NEXT: ret i64 %2 -// CHECK-NEXT: } - -// CHECK-LABEL: define linkonce %"{{.*}}/runtime/internal/runtime.String" @__llgo_stub.main.impl.two(ptr %0, %main.impl %1){{.*}} { -// CHECK-NEXT: _llgo_0: -// CHECK-NEXT: %2 = tail call %"{{.*}}/runtime/internal/runtime.String" @main.impl.two(%main.impl %1) -// CHECK-NEXT: ret %"{{.*}}/runtime/internal/runtime.String" %2 -// CHECK-NEXT: } - -// CHECK-LABEL: define linkonce i1 @"__llgo_stub.{{.*}}/runtime/internal/runtime.interequal"(ptr %0, ptr %1, ptr %2){{.*}} { -// CHECK-NEXT: _llgo_0: -// CHECK-NEXT: %3 = tail call i1 @"{{.*}}/runtime/internal/runtime.interequal"(ptr %1, ptr %2) -// CHECK-NEXT: ret i1 %3 -// CHECK-NEXT: } - -// CHECK-LABEL: define i64 @"main.I.one$bound"(ptr %0){{.*}} { +// CHECK-LABEL: define i64 @"main.I.one$bound"(ptr {{(nest|swiftself)}} %0){{.*}} { // CHECK-NEXT: _llgo_0: // CHECK-NEXT: %1 = load { %"{{.*}}/runtime/internal/runtime.iface" }, ptr %0, align 8 // CHECK-NEXT: %2 = extractvalue { %"{{.*}}/runtime/internal/runtime.iface" } %1, 0 @@ -461,7 +423,7 @@ func main() { // CHECK-NEXT: ret i64 %11 // CHECK-NEXT: } -// CHECK-LABEL: define %"{{.*}}/runtime/internal/runtime.String" @"main.I.two$bound"(ptr %0){{.*}} { +// CHECK-LABEL: define %"{{.*}}/runtime/internal/runtime.String" @"main.I.two$bound"(ptr {{(nest|swiftself)}} %0){{.*}} { // CHECK-NEXT: _llgo_0: // CHECK-NEXT: %1 = load { %"{{.*}}/runtime/internal/runtime.iface" }, ptr %0, align 8 // CHECK-NEXT: %2 = extractvalue { %"{{.*}}/runtime/internal/runtime.iface" } %1, 0 diff --git a/cl/_testgo/invoke/in.go b/cl/_testgo/invoke/in.go index e48e4ea7f5..22cbccef4e 100644 --- a/cl/_testgo/invoke/in.go +++ b/cl/_testgo/invoke/in.go @@ -270,7 +270,8 @@ type M interface { // CHECK-NEXT: _llgo_0: // CHECK-NEXT: %1 = extractvalue %main.T6 %0, 1 // CHECK-NEXT: %2 = extractvalue %main.T6 %0, 0 -// CHECK-NEXT: %3 = call i64 %2(ptr %1) +// CHECK-NEXT: %__llgo_funcval_code = call ptr asm "", "=r,0"(ptr %2) +// CHECK-NEXT: %3 = call i64 %__llgo_funcval_code(ptr {{(nest|swiftself)}} %1) // CHECK-NEXT: call void @"{{.*}}/runtime/internal/runtime.PrintString"(%"{{.*}}/runtime/internal/runtime.String" { ptr @12, i64 7 }) // CHECK-NEXT: call void @"{{.*}}/runtime/internal/runtime.PrintByte"(i8 32) // CHECK-NEXT: call void @"{{.*}}/runtime/internal/runtime.PrintInt"(i64 %3) @@ -334,7 +335,7 @@ type M interface { // CHECK-NEXT: %8 = getelementptr inbounds %main.T5, ptr %7, i32 0, i32 0 // CHECK-NEXT: store i64 300, ptr %8, align 8 // CHECK-NEXT: %9 = call ptr @"{{.*}}/runtime/internal/runtime.AllocZ"(i64 16) -// CHECK-NEXT: store %main.T6 { ptr @"__llgo_stub.main.main$1", ptr null }, ptr %9, align 8 +// CHECK-NEXT: store %main.T6 { ptr @"main.main$1", ptr null }, ptr %9, align 8 // CHECK-NEXT: %10 = load %main.T, ptr %0, align 8 // CHECK-NEXT: %11 = call ptr @"{{.*}}/runtime/internal/runtime.AllocU"(i64 16) // CHECK-NEXT: store %main.T %10, ptr %11, align 8 @@ -474,123 +475,3 @@ type M interface { // CHECK-NEXT: _llgo_0: // CHECK-NEXT: ret i64 400 // CHECK-NEXT: } - -// CHECK-LABEL: define linkonce i64 @"__llgo_stub.main.main$1"(ptr %0){{.*}} { -// CHECK-NEXT: _llgo_0: -// CHECK-NEXT: %1 = tail call i64 @"main.main$1"() -// CHECK-NEXT: ret i64 %1 -// CHECK-NEXT: } - -// CHECK-LABEL: define linkonce i64 @"__llgo_stub.main.(*T).Invoke"(ptr %0, ptr %1){{.*}} { -// CHECK-NEXT: _llgo_0: -// CHECK-NEXT: %2 = tail call i64 @"main.(*T).Invoke"(ptr %1) -// CHECK-NEXT: ret i64 %2 -// CHECK-NEXT: } - -// CHECK-LABEL: define linkonce i1 @"__llgo_stub.{{.*}}/runtime/internal/runtime.memequal64"(ptr %0, ptr %1, ptr %2){{.*}} { -// CHECK-NEXT: _llgo_0: -// CHECK-NEXT: %3 = tail call i1 @"{{.*}}/runtime/internal/runtime.memequal64"(ptr %1, ptr %2) -// CHECK-NEXT: ret i1 %3 -// CHECK-NEXT: } - -// CHECK-LABEL: define linkonce void @"__llgo_stub.main.(*T).Method"(ptr %0, ptr %1){{.*}} { -// CHECK-NEXT: _llgo_0: -// CHECK-NEXT: tail call void @"main.(*T).Method"(ptr %1) -// CHECK-NEXT: ret void -// CHECK-NEXT: } - -// CHECK-LABEL: define linkonce i64 @__llgo_stub.main.T.Invoke(ptr %0, %main.T %1){{.*}} { -// CHECK-NEXT: _llgo_0: -// CHECK-NEXT: %2 = tail call i64 @main.T.Invoke(%main.T %1) -// CHECK-NEXT: ret i64 %2 -// CHECK-NEXT: } - -// CHECK-LABEL: define linkonce i1 @"__llgo_stub.{{.*}}/runtime/internal/runtime.interequal"(ptr %0, ptr %1, ptr %2){{.*}} { -// CHECK-NEXT: _llgo_0: -// CHECK-NEXT: %3 = tail call i1 @"{{.*}}/runtime/internal/runtime.interequal"(ptr %1, ptr %2) -// CHECK-NEXT: ret i1 %3 -// CHECK-NEXT: } - -// CHECK-LABEL: define linkonce i64 @"__llgo_stub.main.(*T1).Invoke"(ptr %0, ptr %1){{.*}} { -// CHECK-NEXT: _llgo_0: -// CHECK-NEXT: %2 = tail call i64 @"main.(*T1).Invoke"(ptr %1) -// CHECK-NEXT: ret i64 %2 -// CHECK-NEXT: } - -// CHECK-LABEL: define linkonce i64 @__llgo_stub.main.T1.Invoke(ptr %0, i64 %1){{.*}} { -// CHECK-NEXT: _llgo_0: -// CHECK-NEXT: %2 = tail call i64 @main.T1.Invoke(i64 %1) -// CHECK-NEXT: ret i64 %2 -// CHECK-NEXT: } - -// CHECK-LABEL: define linkonce i1 @"__llgo_stub.{{.*}}/runtime/internal/runtime.f64equal"(ptr %0, ptr %1, ptr %2){{.*}} { -// CHECK-NEXT: _llgo_0: -// CHECK-NEXT: %3 = tail call i1 @"{{.*}}/runtime/internal/runtime.f64equal"(ptr %1, ptr %2) -// CHECK-NEXT: ret i1 %3 -// CHECK-NEXT: } - -// CHECK-LABEL: define linkonce i64 @"__llgo_stub.main.(*T2).Invoke"(ptr %0, ptr %1){{.*}} { -// CHECK-NEXT: _llgo_0: -// CHECK-NEXT: %2 = tail call i64 @"main.(*T2).Invoke"(ptr %1) -// CHECK-NEXT: ret i64 %2 -// CHECK-NEXT: } - -// CHECK-LABEL: define linkonce i64 @__llgo_stub.main.T2.Invoke(ptr %0, double %1){{.*}} { -// CHECK-NEXT: _llgo_0: -// CHECK-NEXT: %2 = tail call i64 @main.T2.Invoke(double %1) -// CHECK-NEXT: ret i64 %2 -// CHECK-NEXT: } - -// CHECK-LABEL: define linkonce i1 @"__llgo_stub.{{.*}}/runtime/internal/runtime.memequal8"(ptr %0, ptr %1, ptr %2){{.*}} { -// CHECK-NEXT: _llgo_0: -// CHECK-NEXT: %3 = tail call i1 @"{{.*}}/runtime/internal/runtime.memequal8"(ptr %1, ptr %2) -// CHECK-NEXT: ret i1 %3 -// CHECK-NEXT: } - -// CHECK-LABEL: define linkonce i64 @"__llgo_stub.main.(*T3).Invoke"(ptr %0, ptr %1){{.*}} { -// CHECK-NEXT: _llgo_0: -// CHECK-NEXT: %2 = tail call i64 @"main.(*T3).Invoke"(ptr %1) -// CHECK-NEXT: ret i64 %2 -// CHECK-NEXT: } - -// CHECK-LABEL: define linkonce i64 @"__llgo_stub.main.(*T4).Invoke"(ptr %0, ptr %1){{.*}} { -// CHECK-NEXT: _llgo_0: -// CHECK-NEXT: %2 = tail call i64 @"main.(*T4).Invoke"(ptr %1) -// CHECK-NEXT: ret i64 %2 -// CHECK-NEXT: } - -// CHECK-LABEL: define linkonce i64 @__llgo_stub.main.T4.Invoke(ptr %0, [1 x i64] %1){{.*}} { -// CHECK-NEXT: _llgo_0: -// CHECK-NEXT: %2 = tail call i64 @main.T4.Invoke([1 x i64] %1) -// CHECK-NEXT: ret i64 %2 -// CHECK-NEXT: } - -// CHECK-LABEL: define linkonce i64 @"__llgo_stub.main.(*T5).Invoke"(ptr %0, ptr %1){{.*}} { -// CHECK-NEXT: _llgo_0: -// CHECK-NEXT: %2 = tail call i64 @"main.(*T5).Invoke"(ptr %1) -// CHECK-NEXT: ret i64 %2 -// CHECK-NEXT: } - -// CHECK-LABEL: define linkonce i64 @__llgo_stub.main.T5.Invoke(ptr %0, %main.T5 %1){{.*}} { -// CHECK-NEXT: _llgo_0: -// CHECK-NEXT: %2 = tail call i64 @main.T5.Invoke(%main.T5 %1) -// CHECK-NEXT: ret i64 %2 -// CHECK-NEXT: } - -// CHECK-LABEL: define linkonce i64 @"__llgo_stub.main.(*T6).Invoke"(ptr %0, ptr %1){{.*}} { -// CHECK-NEXT: _llgo_0: -// CHECK-NEXT: %2 = tail call i64 @"main.(*T6).Invoke"(ptr %1) -// CHECK-NEXT: ret i64 %2 -// CHECK-NEXT: } - -// CHECK-LABEL: define linkonce i64 @__llgo_stub.main.T6.Invoke(ptr %0, %main.T6 %1){{.*}} { -// CHECK-NEXT: _llgo_0: -// CHECK-NEXT: %2 = tail call i64 @main.T6.Invoke(%main.T6 %1) -// CHECK-NEXT: ret i64 %2 -// CHECK-NEXT: } - -// CHECK-LABEL: define linkonce i1 @"__llgo_stub.{{.*}}/runtime/internal/runtime.nilinterequal"(ptr %0, ptr %1, ptr %2){{.*}} { -// CHECK-NEXT: _llgo_0: -// CHECK-NEXT: %3 = tail call i1 @"{{.*}}/runtime/internal/runtime.nilinterequal"(ptr %1, ptr %2) -// CHECK-NEXT: ret i1 %3 -// CHECK-NEXT: } diff --git a/cl/_testgo/reader/in.go b/cl/_testgo/reader/in.go index bf9d1c0934..2fd463b8a6 100644 --- a/cl/_testgo/reader/in.go +++ b/cl/_testgo/reader/in.go @@ -1132,147 +1132,3 @@ func main() { // CHECK-NEXT: %39 = call i1 @"{{.*}}/runtime/internal/runtime.EfaceEqual"(%"{{.*}}/runtime/internal/runtime.eface" %35, %"{{.*}}/runtime/internal/runtime.eface" %38) // CHECK-NEXT: br i1 %39, label %_llgo_5, label %_llgo_6 // CHECK-NEXT: } - -// CHECK-LABEL: define linkonce i1 @"__llgo_stub.{{.*}}/runtime/internal/runtime.interequal"(ptr %0, ptr %1, ptr %2){{.*}} { -// CHECK-NEXT: _llgo_0: -// CHECK-NEXT: %3 = tail call i1 @"{{.*}}/runtime/internal/runtime.interequal"(ptr %1, ptr %2) -// CHECK-NEXT: ret i1 %3 -// CHECK-NEXT: } - -// CHECK-LABEL: define linkonce i1 @"__llgo_stub.{{.*}}/runtime/internal/runtime.memequal8"(ptr %0, ptr %1, ptr %2){{.*}} { -// CHECK-NEXT: _llgo_0: -// CHECK-NEXT: %3 = tail call i1 @"{{.*}}/runtime/internal/runtime.memequal8"(ptr %1, ptr %2) -// CHECK-NEXT: ret i1 %3 -// CHECK-NEXT: } - -// CHECK-LABEL: define linkonce i1 @"__llgo_stub.{{.*}}/runtime/internal/runtime.memequal64"(ptr %0, ptr %1, ptr %2){{.*}} { -// CHECK-NEXT: _llgo_0: -// CHECK-NEXT: %3 = tail call i1 @"{{.*}}/runtime/internal/runtime.memequal64"(ptr %1, ptr %2) -// CHECK-NEXT: ret i1 %3 -// CHECK-NEXT: } - -// CHECK-LABEL: define linkonce %"{{.*}}/runtime/internal/runtime.iface" @"__llgo_stub.main.(*nopCloserWriterTo).Close"(ptr %0, ptr %1){{.*}} { -// CHECK-NEXT: _llgo_0: -// CHECK-NEXT: %2 = tail call %"{{.*}}/runtime/internal/runtime.iface" @"main.(*nopCloserWriterTo).Close"(ptr %1) -// CHECK-NEXT: ret %"{{.*}}/runtime/internal/runtime.iface" %2 -// CHECK-NEXT: } - -// CHECK-LABEL: define linkonce { i64, %"{{.*}}/runtime/internal/runtime.iface" } @"__llgo_stub.main.(*nopCloserWriterTo).Read"(ptr %0, ptr %1, %"{{.*}}/runtime/internal/runtime.Slice" %2){{.*}} { -// CHECK-NEXT: _llgo_0: -// CHECK-NEXT: %3 = tail call { i64, %"{{.*}}/runtime/internal/runtime.iface" } @"main.(*nopCloserWriterTo).Read"(ptr %1, %"{{.*}}/runtime/internal/runtime.Slice" %2) -// CHECK-NEXT: ret { i64, %"{{.*}}/runtime/internal/runtime.iface" } %3 -// CHECK-NEXT: } - -// CHECK-LABEL: define linkonce { i64, %"{{.*}}/runtime/internal/runtime.iface" } @"__llgo_stub.main.(*nopCloserWriterTo).WriteTo"(ptr %0, ptr %1, %"{{.*}}/runtime/internal/runtime.iface" %2){{.*}} { -// CHECK-NEXT: _llgo_0: -// CHECK-NEXT: %3 = tail call { i64, %"{{.*}}/runtime/internal/runtime.iface" } @"main.(*nopCloserWriterTo).WriteTo"(ptr %1, %"{{.*}}/runtime/internal/runtime.iface" %2) -// CHECK-NEXT: ret { i64, %"{{.*}}/runtime/internal/runtime.iface" } %3 -// CHECK-NEXT: } - -// CHECK-LABEL: define linkonce %"{{.*}}/runtime/internal/runtime.iface" @__llgo_stub.main.nopCloserWriterTo.Close(ptr %0, %main.nopCloserWriterTo %1){{.*}} { -// CHECK-NEXT: _llgo_0: -// CHECK-NEXT: %2 = tail call %"{{.*}}/runtime/internal/runtime.iface" @main.nopCloserWriterTo.Close(%main.nopCloserWriterTo %1) -// CHECK-NEXT: ret %"{{.*}}/runtime/internal/runtime.iface" %2 -// CHECK-NEXT: } - -// CHECK-LABEL: define linkonce { i64, %"{{.*}}/runtime/internal/runtime.iface" } @__llgo_stub.main.nopCloserWriterTo.Read(ptr %0, %main.nopCloserWriterTo %1, %"{{.*}}/runtime/internal/runtime.Slice" %2){{.*}} { -// CHECK-NEXT: _llgo_0: -// CHECK-NEXT: %3 = tail call { i64, %"{{.*}}/runtime/internal/runtime.iface" } @main.nopCloserWriterTo.Read(%main.nopCloserWriterTo %1, %"{{.*}}/runtime/internal/runtime.Slice" %2) -// CHECK-NEXT: ret { i64, %"{{.*}}/runtime/internal/runtime.iface" } %3 -// CHECK-NEXT: } - -// CHECK-LABEL: define linkonce { i64, %"{{.*}}/runtime/internal/runtime.iface" } @__llgo_stub.main.nopCloserWriterTo.WriteTo(ptr %0, %main.nopCloserWriterTo %1, %"{{.*}}/runtime/internal/runtime.iface" %2){{.*}} { -// CHECK-NEXT: _llgo_0: -// CHECK-NEXT: %3 = tail call { i64, %"{{.*}}/runtime/internal/runtime.iface" } @main.nopCloserWriterTo.WriteTo(%main.nopCloserWriterTo %1, %"{{.*}}/runtime/internal/runtime.iface" %2) -// CHECK-NEXT: ret { i64, %"{{.*}}/runtime/internal/runtime.iface" } %3 -// CHECK-NEXT: } - -// CHECK-LABEL: define linkonce %"{{.*}}/runtime/internal/runtime.iface" @"__llgo_stub.main.(*nopCloser).Close"(ptr %0, ptr %1){{.*}} { -// CHECK-NEXT: _llgo_0: -// CHECK-NEXT: %2 = tail call %"{{.*}}/runtime/internal/runtime.iface" @"main.(*nopCloser).Close"(ptr %1) -// CHECK-NEXT: ret %"{{.*}}/runtime/internal/runtime.iface" %2 -// CHECK-NEXT: } - -// CHECK-LABEL: define linkonce { i64, %"{{.*}}/runtime/internal/runtime.iface" } @"__llgo_stub.main.(*nopCloser).Read"(ptr %0, ptr %1, %"{{.*}}/runtime/internal/runtime.Slice" %2){{.*}} { -// CHECK-NEXT: _llgo_0: -// CHECK-NEXT: %3 = tail call { i64, %"{{.*}}/runtime/internal/runtime.iface" } @"main.(*nopCloser).Read"(ptr %1, %"{{.*}}/runtime/internal/runtime.Slice" %2) -// CHECK-NEXT: ret { i64, %"{{.*}}/runtime/internal/runtime.iface" } %3 -// CHECK-NEXT: } - -// CHECK-LABEL: define linkonce %"{{.*}}/runtime/internal/runtime.iface" @__llgo_stub.main.nopCloser.Close(ptr %0, %main.nopCloser %1){{.*}} { -// CHECK-NEXT: _llgo_0: -// CHECK-NEXT: %2 = tail call %"{{.*}}/runtime/internal/runtime.iface" @main.nopCloser.Close(%main.nopCloser %1) -// CHECK-NEXT: ret %"{{.*}}/runtime/internal/runtime.iface" %2 -// CHECK-NEXT: } - -// CHECK-LABEL: define linkonce { i64, %"{{.*}}/runtime/internal/runtime.iface" } @__llgo_stub.main.nopCloser.Read(ptr %0, %main.nopCloser %1, %"{{.*}}/runtime/internal/runtime.Slice" %2){{.*}} { -// CHECK-NEXT: _llgo_0: -// CHECK-NEXT: %3 = tail call { i64, %"{{.*}}/runtime/internal/runtime.iface" } @main.nopCloser.Read(%main.nopCloser %1, %"{{.*}}/runtime/internal/runtime.Slice" %2) -// CHECK-NEXT: ret { i64, %"{{.*}}/runtime/internal/runtime.iface" } %3 -// CHECK-NEXT: } - -// CHECK-LABEL: define linkonce i64 @"__llgo_stub.main.(*stringReader).Len"(ptr %0, ptr %1){{.*}} { -// CHECK-NEXT: _llgo_0: -// CHECK-NEXT: %2 = tail call i64 @"main.(*stringReader).Len"(ptr %1) -// CHECK-NEXT: ret i64 %2 -// CHECK-NEXT: } - -// CHECK-LABEL: define linkonce { i64, %"{{.*}}/runtime/internal/runtime.iface" } @"__llgo_stub.main.(*stringReader).Read"(ptr %0, ptr %1, %"{{.*}}/runtime/internal/runtime.Slice" %2){{.*}} { -// CHECK-NEXT: _llgo_0: -// CHECK-NEXT: %3 = tail call { i64, %"{{.*}}/runtime/internal/runtime.iface" } @"main.(*stringReader).Read"(ptr %1, %"{{.*}}/runtime/internal/runtime.Slice" %2) -// CHECK-NEXT: ret { i64, %"{{.*}}/runtime/internal/runtime.iface" } %3 -// CHECK-NEXT: } - -// CHECK-LABEL: define linkonce { i64, %"{{.*}}/runtime/internal/runtime.iface" } @"__llgo_stub.main.(*stringReader).ReadAt"(ptr %0, ptr %1, %"{{.*}}/runtime/internal/runtime.Slice" %2, i64 %3){{.*}} { -// CHECK-NEXT: _llgo_0: -// CHECK-NEXT: %4 = tail call { i64, %"{{.*}}/runtime/internal/runtime.iface" } @"main.(*stringReader).ReadAt"(ptr %1, %"{{.*}}/runtime/internal/runtime.Slice" %2, i64 %3) -// CHECK-NEXT: ret { i64, %"{{.*}}/runtime/internal/runtime.iface" } %4 -// CHECK-NEXT: } - -// CHECK-LABEL: define linkonce { i8, %"{{.*}}/runtime/internal/runtime.iface" } @"__llgo_stub.main.(*stringReader).ReadByte"(ptr %0, ptr %1){{.*}} { -// CHECK-NEXT: _llgo_0: -// CHECK-NEXT: %2 = tail call { i8, %"{{.*}}/runtime/internal/runtime.iface" } @"main.(*stringReader).ReadByte"(ptr %1) -// CHECK-NEXT: ret { i8, %"{{.*}}/runtime/internal/runtime.iface" } %2 -// CHECK-NEXT: } - -// CHECK-LABEL: define linkonce { i32, i64, %"{{.*}}/runtime/internal/runtime.iface" } @"__llgo_stub.main.(*stringReader).ReadRune"(ptr %0, ptr %1){{.*}} { -// CHECK-NEXT: _llgo_0: -// CHECK-NEXT: %2 = tail call { i32, i64, %"{{.*}}/runtime/internal/runtime.iface" } @"main.(*stringReader).ReadRune"(ptr %1) -// CHECK-NEXT: ret { i32, i64, %"{{.*}}/runtime/internal/runtime.iface" } %2 -// CHECK-NEXT: } - -// CHECK-LABEL: define linkonce { i64, %"{{.*}}/runtime/internal/runtime.iface" } @"__llgo_stub.main.(*stringReader).Seek"(ptr %0, ptr %1, i64 %2, i64 %3){{.*}} { -// CHECK-NEXT: _llgo_0: -// CHECK-NEXT: %4 = tail call { i64, %"{{.*}}/runtime/internal/runtime.iface" } @"main.(*stringReader).Seek"(ptr %1, i64 %2, i64 %3) -// CHECK-NEXT: ret { i64, %"{{.*}}/runtime/internal/runtime.iface" } %4 -// CHECK-NEXT: } - -// CHECK-LABEL: define linkonce i64 @"__llgo_stub.main.(*stringReader).Size"(ptr %0, ptr %1){{.*}} { -// CHECK-NEXT: _llgo_0: -// CHECK-NEXT: %2 = tail call i64 @"main.(*stringReader).Size"(ptr %1) -// CHECK-NEXT: ret i64 %2 -// CHECK-NEXT: } - -// CHECK-LABEL: define linkonce %"{{.*}}/runtime/internal/runtime.iface" @"__llgo_stub.main.(*stringReader).UnreadByte"(ptr %0, ptr %1){{.*}} { -// CHECK-NEXT: _llgo_0: -// CHECK-NEXT: %2 = tail call %"{{.*}}/runtime/internal/runtime.iface" @"main.(*stringReader).UnreadByte"(ptr %1) -// CHECK-NEXT: ret %"{{.*}}/runtime/internal/runtime.iface" %2 -// CHECK-NEXT: } - -// CHECK-LABEL: define linkonce %"{{.*}}/runtime/internal/runtime.iface" @"__llgo_stub.main.(*stringReader).UnreadRune"(ptr %0, ptr %1){{.*}} { -// CHECK-NEXT: _llgo_0: -// CHECK-NEXT: %2 = tail call %"{{.*}}/runtime/internal/runtime.iface" @"main.(*stringReader).UnreadRune"(ptr %1) -// CHECK-NEXT: ret %"{{.*}}/runtime/internal/runtime.iface" %2 -// CHECK-NEXT: } - -// CHECK-LABEL: define linkonce { i64, %"{{.*}}/runtime/internal/runtime.iface" } @"__llgo_stub.main.(*stringReader).WriteTo"(ptr %0, ptr %1, %"{{.*}}/runtime/internal/runtime.iface" %2){{.*}} { -// CHECK-NEXT: _llgo_0: -// CHECK-NEXT: %3 = tail call { i64, %"{{.*}}/runtime/internal/runtime.iface" } @"main.(*stringReader).WriteTo"(ptr %1, %"{{.*}}/runtime/internal/runtime.iface" %2) -// CHECK-NEXT: ret { i64, %"{{.*}}/runtime/internal/runtime.iface" } %3 -// CHECK-NEXT: } - -// CHECK-LABEL: define linkonce %"{{.*}}/runtime/internal/runtime.String" @"__llgo_stub.main.(*errorString).Error"(ptr %0, ptr %1){{.*}} { -// CHECK-NEXT: _llgo_0: -// CHECK-NEXT: %2 = tail call %"{{.*}}/runtime/internal/runtime.String" @"main.(*errorString).Error"(ptr %1) -// CHECK-NEXT: ret %"{{.*}}/runtime/internal/runtime.String" %2 -// CHECK-NEXT: } diff --git a/cl/_testgo/reflect/in.go b/cl/_testgo/reflect/in.go index ea6dd78c61..8110cc7a0f 100644 --- a/cl/_testgo/reflect/in.go +++ b/cl/_testgo/reflect/in.go @@ -168,7 +168,8 @@ type T struct { // CHECK-NEXT: _llgo_2: ; preds = %_llgo_5 // CHECK-NEXT: %39 = extractvalue { ptr, ptr } %47, 1 // CHECK-NEXT: %40 = extractvalue { ptr, ptr } %47, 0 -// CHECK-NEXT: %41 = call i64 %40(ptr %39, i64 100) +// CHECK-NEXT: %__llgo_funcval_code = call ptr asm "", "=r,0"(ptr %40) +// CHECK-NEXT: %41 = call i64 %__llgo_funcval_code(ptr {{(nest|swiftself)}} %39, i64 100) // CHECK-NEXT: ret void // CHECK-EMPTY: // CHECK-NEXT: _llgo_3: ; preds = %_llgo_0 @@ -188,7 +189,7 @@ type T struct { // CHECK-NEXT: br i1 %48, label %_llgo_2, label %_llgo_1 // CHECK-NEXT: } -// CHECK-LABEL: define i64 @"main.callClosure$1"(ptr %0, i64 %1){{.*}} { +// CHECK-LABEL: define i64 @"main.callClosure$1"(ptr {{(nest|swiftself)}} %0, i64 %1){{.*}} { // CHECK-NEXT: _llgo_0: // CHECK-NEXT: call void @"{{.*}}/runtime/internal/runtime.PrintString"(%"{{.*}}/runtime/internal/runtime.String" { ptr @9, i64 12 }) // CHECK-NEXT: call void @"{{.*}}/runtime/internal/runtime.PrintByte"(i8 10) @@ -203,7 +204,7 @@ type T struct { // CHECK-LABEL: define void @main.callFunc(){{.*}} { // CHECK-NEXT: _llgo_0: // CHECK-NEXT: %0 = call ptr @"{{.*}}/runtime/internal/runtime.AllocU"(i64 16) -// CHECK-NEXT: store { ptr, ptr } { ptr @"__llgo_stub.main.callFunc$1", ptr null }, ptr %0, align 8 +// CHECK-NEXT: store { ptr, ptr } { ptr @"main.callFunc$1", ptr null }, ptr %0, align 8 // CHECK-NEXT: %1 = insertvalue %"{{.*}}/runtime/internal/runtime.eface" { ptr @"_llgo_closure${{[-A-Za-z0-9_]+}}", ptr undef }, ptr %0, 1 // CHECK-NEXT: %2 = call %reflect.Value @reflect.ValueOf(%"{{.*}}/runtime/internal/runtime.eface" %1) // CHECK-NEXT: %3 = call i64 @reflect.Value.Kind(%reflect.Value %2) @@ -259,7 +260,8 @@ type T struct { // CHECK-NEXT: _llgo_2: ; preds = %_llgo_5 // CHECK-NEXT: %35 = extractvalue { ptr, ptr } %43, 1 // CHECK-NEXT: %36 = extractvalue { ptr, ptr } %43, 0 -// CHECK-NEXT: %37 = call i64 %36(ptr %35, i64 100) +// CHECK-NEXT: %__llgo_funcval_code = call ptr asm "", "=r,0"(ptr %36) +// CHECK-NEXT: %37 = call i64 %__llgo_funcval_code(ptr {{(nest|swiftself)}} %35, i64 100) // CHECK-NEXT: ret void // CHECK-EMPTY: // CHECK-NEXT: _llgo_3: ; preds = %_llgo_0 @@ -386,7 +388,8 @@ func callMethod() { // CHECK-NEXT: _llgo_2: ; preds = %_llgo_5 // CHECK-NEXT: %43 = extractvalue { ptr, ptr } %69, 1 // CHECK-NEXT: %44 = extractvalue { ptr, ptr } %69, 0 -// CHECK-NEXT: %45 = call i64 %44(ptr %43, i64 1) +// CHECK-NEXT: %__llgo_funcval_code = call ptr asm "", "=r,0"(ptr %44) +// CHECK-NEXT: %45 = call i64 %__llgo_funcval_code(ptr {{(nest|swiftself)}} %43, i64 1) // CHECK-NEXT: %46 = call %"{{.*}}/runtime/internal/runtime.eface" @reflect.Value.Interface(%reflect.Value %10) // CHECK-NEXT: %47 = call %reflect.Value @reflect.ValueOf(%"{{.*}}/runtime/internal/runtime.eface" %46) // CHECK-NEXT: %48 = call ptr @"{{.*}}/runtime/internal/runtime.AllocZ"(i64 24) @@ -490,7 +493,8 @@ func callMethod() { // CHECK-NEXT: _llgo_2: ; preds = %_llgo_5 // CHECK-NEXT: %37 = extractvalue { ptr, ptr } %63, 1 // CHECK-NEXT: %38 = extractvalue { ptr, ptr } %63, 0 -// CHECK-NEXT: %39 = call i64 %38(ptr %37, i64 1) +// CHECK-NEXT: %__llgo_funcval_code = call ptr asm "", "=r,0"(ptr %38) +// CHECK-NEXT: %39 = call i64 %__llgo_funcval_code(ptr {{(nest|swiftself)}} %37, i64 1) // CHECK-NEXT: %40 = call %"{{.*}}/runtime/internal/runtime.eface" @reflect.Value.Interface(%reflect.Value %4) // CHECK-NEXT: %41 = call %reflect.Value @reflect.ValueOf(%"{{.*}}/runtime/internal/runtime.eface" %40) // CHECK-NEXT: %42 = call ptr @"{{.*}}/runtime/internal/runtime.AllocZ"(i64 24) @@ -536,7 +540,7 @@ func callMethod() { // CHECK-LABEL: define void @main.callSlice(){{.*}} { // CHECK-NEXT: _llgo_0: // CHECK-NEXT: %0 = call ptr @"{{.*}}/runtime/internal/runtime.AllocU"(i64 16) -// CHECK-NEXT: store { ptr, ptr } { ptr @__llgo_stub.main.demo, ptr null }, ptr %0, align 8 +// CHECK-NEXT: store { ptr, ptr } { ptr @main.demo, ptr null }, ptr %0, align 8 // CHECK-NEXT: %1 = insertvalue %"{{.*}}/runtime/internal/runtime.eface" { ptr @"_llgo_closure${{[-A-Za-z0-9_]+}}", ptr undef }, ptr %0, 1 // CHECK-NEXT: %2 = call %reflect.Value @reflect.ValueOf(%"{{.*}}/runtime/internal/runtime.eface" %1) // CHECK-NEXT: %3 = call ptr @"{{.*}}/runtime/internal/runtime.AllocU"(i64 8) @@ -1145,45 +1149,3 @@ func mapDemo2() { } } } - -// CHECK-LABEL: define linkonce i1 @"__llgo_stub.{{.*}}/runtime/internal/runtime.memequal64"(ptr %0, ptr %1, ptr %2){{.*}} { -// CHECK-NEXT: _llgo_0: -// CHECK-NEXT: %3 = tail call i1 @"{{.*}}/runtime/internal/runtime.memequal64"(ptr %1, ptr %2) -// CHECK-NEXT: ret i1 %3 -// CHECK-NEXT: } - -// CHECK-LABEL: define linkonce i64 @"__llgo_stub.main.callFunc$1"(ptr %0, i64 %1){{.*}} { -// CHECK-NEXT: _llgo_0: -// CHECK-NEXT: %2 = tail call i64 @"main.callFunc$1"(i64 %1) -// CHECK-NEXT: ret i64 %2 -// CHECK-NEXT: } - -// CHECK-LABEL: define linkonce i64 @"__llgo_stub.main.(*T).Add"(ptr %0, ptr %1, i64 %2){{.*}} { -// CHECK-NEXT: _llgo_0: -// CHECK-NEXT: %3 = tail call i64 @"main.(*T).Add"(ptr %1, i64 %2) -// CHECK-NEXT: ret i64 %3 -// CHECK-NEXT: } - -// CHECK-LABEL: define linkonce i1 @"__llgo_stub.{{.*}}/runtime/internal/runtime.interequal"(ptr %0, ptr %1, ptr %2){{.*}} { -// CHECK-NEXT: _llgo_0: -// CHECK-NEXT: %3 = tail call i1 @"{{.*}}/runtime/internal/runtime.interequal"(ptr %1, ptr %2) -// CHECK-NEXT: ret i1 %3 -// CHECK-NEXT: } - -// CHECK-LABEL: define linkonce { i64, i64 } @__llgo_stub.main.demo(ptr %0, i64 %1, i64 %2, i64 %3, i64 %4, i64 %5, i64 %6, i64 %7, i64 %8, i64 %9, %"{{.*}}/runtime/internal/runtime.Slice" %10){{.*}} { -// CHECK-NEXT: _llgo_0: -// CHECK-NEXT: %11 = tail call { i64, i64 } @main.demo(i64 %1, i64 %2, i64 %3, i64 %4, i64 %5, i64 %6, i64 %7, i64 %8, i64 %9, %"{{.*}}/runtime/internal/runtime.Slice" %10) -// CHECK-NEXT: ret { i64, i64 } %11 -// CHECK-NEXT: } - -// CHECK-LABEL: define linkonce i1 @"__llgo_stub.{{.*}}/runtime/internal/runtime.nilinterequal"(ptr %0, ptr %1, ptr %2){{.*}} { -// CHECK-NEXT: _llgo_0: -// CHECK-NEXT: %3 = tail call i1 @"{{.*}}/runtime/internal/runtime.nilinterequal"(ptr %1, ptr %2) -// CHECK-NEXT: ret i1 %3 -// CHECK-NEXT: } - -// CHECK-LABEL: define linkonce i1 @"__llgo_stub.{{.*}}/runtime/internal/runtime.memequal8"(ptr %0, ptr %1, ptr %2){{.*}} { -// CHECK-NEXT: _llgo_0: -// CHECK-NEXT: %3 = tail call i1 @"{{.*}}/runtime/internal/runtime.memequal8"(ptr %1, ptr %2) -// CHECK-NEXT: ret i1 %3 -// CHECK-NEXT: } diff --git a/cl/_testgo/reflectfn/in.go b/cl/_testgo/reflectfn/in.go index d61921ad6c..e535767eea 100644 --- a/cl/_testgo/reflectfn/in.go +++ b/cl/_testgo/reflectfn/in.go @@ -37,7 +37,7 @@ func demo() { // CHECK-NEXT: %12 = call ptr @"{{.*}}/runtime/internal/runtime.AllocZ"(i64 16) // CHECK-NEXT: %13 = getelementptr inbounds %"{{.*}}/runtime/internal/runtime.eface", ptr %12, i64 0 // CHECK-NEXT: %14 = call ptr @"{{.*}}/runtime/internal/runtime.AllocU"(i64 16) -// CHECK-NEXT: store { ptr, ptr } { ptr @__llgo_stub.main.demo, ptr null }, ptr %14, align 8 +// CHECK-NEXT: store { ptr, ptr } { ptr @main.demo, ptr null }, ptr %14, align 8 // CHECK-NEXT: %15 = insertvalue %"{{.*}}/runtime/internal/runtime.eface" { ptr @"_llgo_closure${{[-A-Za-z0-9_]+}}", ptr undef }, ptr %14, 1 // CHECK-NEXT: store %"{{.*}}/runtime/internal/runtime.eface" %15, ptr %13, align 8 // CHECK-NEXT: %16 = insertvalue %"{{.*}}/runtime/internal/runtime.Slice" undef, ptr %12, 0 @@ -47,7 +47,7 @@ func demo() { // CHECK-NEXT: %20 = call ptr @"{{.*}}/runtime/internal/runtime.AllocZ"(i64 16) // CHECK-NEXT: %21 = getelementptr inbounds %"{{.*}}/runtime/internal/runtime.eface", ptr %20, i64 0 // CHECK-NEXT: %22 = call ptr @"{{.*}}/runtime/internal/runtime.AllocU"(i64 16) -// CHECK-NEXT: store { ptr, ptr } { ptr @__llgo_stub.main.demo, ptr null }, ptr %22, align 8 +// CHECK-NEXT: store { ptr, ptr } { ptr @main.demo, ptr null }, ptr %22, align 8 // CHECK-NEXT: %23 = insertvalue %"{{.*}}/runtime/internal/runtime.eface" { ptr @"_llgo_closure${{[-A-Za-z0-9_]+}}", ptr undef }, ptr %22, 1 // CHECK-NEXT: store %"{{.*}}/runtime/internal/runtime.eface" %23, ptr %21, align 8 // CHECK-NEXT: %24 = insertvalue %"{{.*}}/runtime/internal/runtime.Slice" undef, ptr %20, 0 @@ -68,7 +68,7 @@ func demo() { // CHECK-NEXT: %37 = insertvalue %"{{.*}}/runtime/internal/runtime.Slice" %36, i64 1, 2 // CHECK-NEXT: %38 = call { i64, %"{{.*}}/runtime/internal/runtime.iface" } @fmt.Println(%"{{.*}}/runtime/internal/runtime.Slice" %37) // CHECK-NEXT: %39 = call ptr @"{{.*}}/runtime/internal/runtime.AllocU"(i64 16) -// CHECK-NEXT: store { ptr, ptr } { ptr @__llgo_stub.main.demo, ptr null }, ptr %39, align 8 +// CHECK-NEXT: store { ptr, ptr } { ptr @main.demo, ptr null }, ptr %39, align 8 // CHECK-NEXT: %40 = insertvalue %"{{.*}}/runtime/internal/runtime.eface" { ptr @"_llgo_closure${{[-A-Za-z0-9_]+}}", ptr undef }, ptr %39, 1 // CHECK-NEXT: %41 = call %reflect.Value @reflect.ValueOf(%"{{.*}}/runtime/internal/runtime.eface" %40) // CHECK-NEXT: %42 = call ptr @reflect.Value.UnsafePointer(%reflect.Value %41) @@ -81,7 +81,7 @@ func demo() { // CHECK-NEXT: %48 = insertvalue %"{{.*}}/runtime/internal/runtime.Slice" %47, i64 1, 2 // CHECK-NEXT: %49 = call { i64, %"{{.*}}/runtime/internal/runtime.iface" } @fmt.Println(%"{{.*}}/runtime/internal/runtime.Slice" %48) // CHECK-NEXT: %50 = call ptr @"{{.*}}/runtime/internal/runtime.AllocU"(i64 16) -// CHECK-NEXT: store { ptr, ptr } { ptr @__llgo_stub.main.demo, ptr null }, ptr %50, align 8 +// CHECK-NEXT: store { ptr, ptr } { ptr @main.demo, ptr null }, ptr %50, align 8 // CHECK-NEXT: %51 = insertvalue %"{{.*}}/runtime/internal/runtime.eface" { ptr @"_llgo_closure${{[-A-Za-z0-9_]+}}", ptr undef }, ptr %50, 1 // CHECK-NEXT: %52 = call %reflect.Value @reflect.ValueOf(%"{{.*}}/runtime/internal/runtime.eface" %51) // CHECK-NEXT: %53 = call ptr @reflect.Value.UnsafePointer(%reflect.Value %52) diff --git a/cl/_testgo/reflectmk/in.go b/cl/_testgo/reflectmk/in.go index 0e82f3c1db..46d854fbe2 100644 --- a/cl/_testgo/reflectmk/in.go +++ b/cl/_testgo/reflectmk/in.go @@ -621,9 +621,3 @@ func methodByName(name string) { // CHECK-NEXT: _llgo_2: ; preds = %_llgo_0 // CHECK-NEXT: ret void // CHECK-NEXT: } - -// CHECK-LABEL: define linkonce i1 @"__llgo_stub.{{.*}}/runtime/internal/runtime.memequal64"(ptr %0, ptr %1, ptr %2){{.*}} { -// CHECK-NEXT: _llgo_0: -// CHECK-NEXT: %3 = tail call i1 @"{{.*}}/runtime/internal/runtime.memequal64"(ptr %1, ptr %2) -// CHECK-NEXT: ret i1 %3 -// CHECK-NEXT: } diff --git a/cl/_testgo/reflectmkfn/in.go b/cl/_testgo/reflectmkfn/in.go index 5eb20a2d62..60d5c06c0e 100644 --- a/cl/_testgo/reflectmkfn/in.go +++ b/cl/_testgo/reflectmkfn/in.go @@ -11,7 +11,8 @@ import ( // CHECK: call %reflect.Value @reflect.MakeFunc( // CHECK: call %"g{{.*}}/runtime/internal/runtime.eface" @reflect.Value.Interface( // CHECK: call i1 @"g{{.*}}/runtime/internal/runtime.MatchesClosure"( -// CHECK: call %"g{{.*}}/runtime/internal/runtime.String" %{{.*}}(ptr %{{.*}}, %"g{{.*}}/runtime/internal/runtime.String" { ptr @{{.*}}, i64 3 }, i64 2) +// CHECK: call ptr asm "", "=r,0"(ptr %{{.*}}) +// CHECK-NEXT: call %"g{{.*}}/runtime/internal/runtime.String" %{{.*}}(ptr {{(nest|swiftself)}} %{{.*}}, %"g{{.*}}/runtime/internal/runtime.String" { ptr @{{.*}}, i64 3 }, i64 2) // CHECK: call i1 @"g{{.*}}/runtime/internal/runtime.StringEqual"( func main() { typ := reflect.FuncOf([]reflect.Type{reflect.TypeOf(""), reflect.TypeOf(0)}, []reflect.Type{reflect.TypeOf("")}, false) diff --git a/cl/_testgo/selects/in.go b/cl/_testgo/selects/in.go index 2f90335132..a271116251 100644 --- a/cl/_testgo/selects/in.go +++ b/cl/_testgo/selects/in.go @@ -149,7 +149,7 @@ func main() { // CHECK-NEXT: unreachable // CHECK-NEXT: } -// CHECK-LABEL: define void @"main.main$1"(ptr %0){{.*}} { +// CHECK-LABEL: define void @"main.main$1"(ptr {{(nest|swiftself)}} %0){{.*}} { // CHECK-NEXT: _llgo_0: // CHECK-NEXT: %1 = load { ptr, ptr, ptr }, ptr %0, align 8 // CHECK-NEXT: %2 = extractvalue { ptr, ptr, ptr } %1, 0 @@ -235,6 +235,7 @@ func main() { // CHECK-NEXT: call void @"{{.*}}/runtime/internal/runtime.FreeRoot"(ptr %0) // CHECK-NEXT: %3 = extractvalue { ptr, ptr } %2, 1 // CHECK-NEXT: %4 = extractvalue { ptr, ptr } %2, 0 -// CHECK-NEXT: call void %4(ptr %3) +// CHECK-NEXT: %__llgo_funcval_code = call ptr asm "", "=r,0"(ptr %4) +// CHECK-NEXT: call void %__llgo_funcval_code(ptr {{(nest|swiftself)}} %3) // CHECK-NEXT: ret ptr null // CHECK-NEXT: } diff --git a/cl/_testgo/tpinst/main.go b/cl/_testgo/tpinst/main.go index fdd41ff1f2..5dc3772151 100644 --- a/cl/_testgo/tpinst/main.go +++ b/cl/_testgo/tpinst/main.go @@ -168,30 +168,6 @@ func (pt *M[T]) value() T { // CHECK-NEXT: ret i64 %2 // CHECK-NEXT: } -// CHECK-LABEL: define linkonce i1 @"__llgo_stub.{{.*}}/runtime/internal/runtime.memequal64"(ptr %0, ptr %1, ptr %2){{.*}} { -// CHECK-NEXT: _llgo_0: -// CHECK-NEXT: %3 = tail call i1 @"{{.*}}/runtime/internal/runtime.memequal64"(ptr %1, ptr %2) -// CHECK-NEXT: ret i1 %3 -// CHECK-NEXT: } - -// CHECK-LABEL: define linkonce i64 @"__llgo_stub.main.(*M[int]).Value"(ptr %0, ptr %1){{.*}} { -// CHECK-NEXT: _llgo_0: -// CHECK-NEXT: %2 = tail call i64 @"main.(*M[int]).Value"(ptr %1) -// CHECK-NEXT: ret i64 %2 -// CHECK-NEXT: } - -// CHECK-LABEL: define linkonce i64 @"__llgo_stub.main.(*M[int]).value"(ptr %0, ptr %1){{.*}} { -// CHECK-NEXT: _llgo_0: -// CHECK-NEXT: %2 = tail call i64 @"main.(*M[int]).value"(ptr %1) -// CHECK-NEXT: ret i64 %2 -// CHECK-NEXT: } - -// CHECK-LABEL: define linkonce i1 @"__llgo_stub.{{.*}}/runtime/internal/runtime.interequal"(ptr %0, ptr %1, ptr %2){{.*}} { -// CHECK-NEXT: _llgo_0: -// CHECK-NEXT: %3 = tail call i1 @"{{.*}}/runtime/internal/runtime.interequal"(ptr %1, ptr %2) -// CHECK-NEXT: ret i1 %3 -// CHECK-NEXT: } - // CHECK-LABEL: define linkonce double @"main.(*M[float64]).Value"(ptr %0){{.*}} { // CHECK-NEXT: _llgo_0: // CHECK-NEXT: %1 = getelementptr inbounds %"main.M[float64]", ptr %0, i32 0, i32 0 @@ -205,21 +181,3 @@ func (pt *M[T]) value() T { // CHECK-NEXT: %2 = load double, ptr %1, align 8 // CHECK-NEXT: ret double %2 // CHECK-NEXT: } - -// CHECK-LABEL: define linkonce i1 @"__llgo_stub.{{.*}}/runtime/internal/runtime.f64equal"(ptr %0, ptr %1, ptr %2){{.*}} { -// CHECK-NEXT: _llgo_0: -// CHECK-NEXT: %3 = tail call i1 @"{{.*}}/runtime/internal/runtime.f64equal"(ptr %1, ptr %2) -// CHECK-NEXT: ret i1 %3 -// CHECK-NEXT: } - -// CHECK-LABEL: define linkonce double @"__llgo_stub.main.(*M[float64]).Value"(ptr %0, ptr %1){{.*}} { -// CHECK-NEXT: _llgo_0: -// CHECK-NEXT: %2 = tail call double @"main.(*M[float64]).Value"(ptr %1) -// CHECK-NEXT: ret double %2 -// CHECK-NEXT: } - -// CHECK-LABEL: define linkonce double @"__llgo_stub.main.(*M[float64]).value"(ptr %0, ptr %1){{.*}} { -// CHECK-NEXT: _llgo_0: -// CHECK-NEXT: %2 = tail call double @"main.(*M[float64]).value"(ptr %1) -// CHECK-NEXT: ret double %2 -// CHECK-NEXT: } diff --git a/cl/_testgo/tpnamed/in.go b/cl/_testgo/tpnamed/in.go index 856ab7ea4c..ca5a244a08 100644 --- a/cl/_testgo/tpnamed/in.go +++ b/cl/_testgo/tpnamed/in.go @@ -8,14 +8,14 @@ type IO[T any] func() Future[T] // CHECK-LABEL: define %"main.IO[error]" @main.WriteFile(%"{{.*}}/runtime/internal/runtime.String" %0){{.*}} { // CHECK-NEXT: _llgo_0: -// CHECK-NEXT: ret %"main.IO[error]" { ptr @"__llgo_stub.main.WriteFile$1", ptr null } +// CHECK-NEXT: ret %"main.IO[error]" { ptr @"main.WriteFile$1", ptr null } // CHECK-NEXT: } func WriteFile(fileName string) IO[error] { // CHECK-LABEL: define %"main.Future[error]" @"main.WriteFile$1"(){{.*}} { // CHECK-NEXT: _llgo_0: - // CHECK-NEXT: ret %"main.Future[error]" { ptr @"__llgo_stub.main.WriteFile$1$1", ptr null } + // CHECK-NEXT: ret %"main.Future[error]" { ptr @"main.WriteFile$1$1", ptr null } // CHECK-NEXT: } return func() Future[error] { @@ -46,7 +46,7 @@ func WriteFile(fileName string) IO[error] { // CHECK-LABEL: define void @main.main(){{.*}} { // CHECK-NEXT: _llgo_0: -// CHECK-NEXT: %0 = call [0 x i8] @"main.RunIO{{\[\[0\]byte\]}}"(%"main.IO{{\[\[0\]byte\]}}" { ptr @"__llgo_stub.main.main$1", ptr null }) +// CHECK-NEXT: %0 = call [0 x i8] @"main.RunIO{{\[\[0\]byte\]}}"(%"main.IO{{\[\[0\]byte\]}}" { ptr @"main.main$1", ptr null }) // CHECK-NEXT: ret void // CHECK-NEXT: } @@ -54,7 +54,7 @@ func main() { // CHECK-LABEL: define %"main.Future{{\[\[0\]byte\]}}" @"main.main$1"() // CHECK-NEXT: _llgo_0: - // CHECK-NEXT: ret %"main.Future{{\[\[0\]byte\]}}" { ptr @"__llgo_stub.main.main$1$1", ptr null } + // CHECK-NEXT: ret %"main.Future{{\[\[0\]byte\]}}" { ptr @"main.main$1$1", ptr null } // CHECK-NEXT: } RunIO[Void](func() Future[Void] { @@ -74,39 +74,17 @@ func RunIO[T any](call IO[T]) T { return call()() } -// CHECK-LABEL: define linkonce %"main.Future[error]" @"__llgo_stub.main.WriteFile$1"(ptr %0){{.*}} { -// CHECK-NEXT: _llgo_0: -// CHECK-NEXT: %1 = tail call %"main.Future[error]" @"main.WriteFile$1"() -// CHECK-NEXT: ret %"main.Future[error]" %1 -// CHECK-NEXT: } - -// CHECK-LABEL: define linkonce %"{{.*}}/runtime/internal/runtime.iface" @"__llgo_stub.main.WriteFile$1$1"(ptr %0){{.*}} { -// CHECK-NEXT: _llgo_0: -// CHECK-NEXT: %1 = tail call %"{{.*}}/runtime/internal/runtime.iface" @"main.WriteFile$1$1"() -// CHECK-NEXT: ret %"{{.*}}/runtime/internal/runtime.iface" %1 -// CHECK-NEXT: } - -// CHECK-LABEL: define linkonce %"main.Future{{\[\[0\]byte\]}}" @"__llgo_stub.main.main$1"(ptr %0){{.*}} { -// CHECK-NEXT: _llgo_0: -// CHECK-NEXT: %1 = tail call %"main.Future{{\[\[0\]byte\]}}" @"main.main$1"() -// CHECK-NEXT: ret %"main.Future{{\[\[0\]byte\]}}" %1 -// CHECK-NEXT: } - // CHECK-LABEL: define linkonce [0 x i8] @"main.RunIO{{\[\[0\]byte\]}}"(%"main.IO{{\[\[0\]byte\]}}" %0){{.*}} { // CHECK-NEXT: _llgo_0: // CHECK-NEXT: %1 = extractvalue %"main.IO{{\[\[0\]byte\]}}" %0, 1 // CHECK-NEXT: %2 = extractvalue %"main.IO{{\[\[0\]byte\]}}" %0, 0 -// CHECK-NEXT: %3 = call %"main.Future{{\[\[0\]byte\]}}" %2(ptr %1) +// CHECK-NEXT: %__llgo_funcval_code = call ptr asm "", "=r,0"(ptr %2) +// CHECK-NEXT: %3 = call %"main.Future{{\[\[0\]byte\]}}" %__llgo_funcval_code(ptr {{(nest|swiftself)}} %1) // CHECK-NEXT: %4 = extractvalue %"main.Future{{\[\[0\]byte\]}}" %3, 1 // CHECK-NEXT: %5 = extractvalue %"main.Future{{\[\[0\]byte\]}}" %3, 0 // CHECK-NEXT: %6 = icmp eq ptr %5, null // CHECK-NEXT: call void @"{{.*}}/runtime/internal/runtime.AssertNilDeref"(i1 %6) -// CHECK-NEXT: %7 = call [0 x i8] %5(ptr %4) +// CHECK-NEXT: %__llgo_funcval_code1 = call ptr asm "", "=r,0"(ptr %5) +// CHECK-NEXT: %7 = call [0 x i8] %__llgo_funcval_code1(ptr {{(nest|swiftself)}} %4) // CHECK-NEXT: ret [0 x i8] %7 // CHECK-NEXT: } - -// CHECK-LABEL: define linkonce [0 x i8] @"__llgo_stub.main.main$1$1"(ptr %0){{.*}} { -// CHECK-NEXT: _llgo_0: -// CHECK-NEXT: %1 = tail call [0 x i8] @"main.main$1$1"() -// CHECK-NEXT: ret [0 x i8] %1 -// CHECK-NEXT: } diff --git a/cl/_testgo/tprecur/out.ll b/cl/_testgo/tprecur/out.ll deleted file mode 100644 index 655ecdee11..0000000000 --- a/cl/_testgo/tprecur/out.ll +++ /dev/null @@ -1,147 +0,0 @@ -; ModuleID = 'github.com/goplus/llgo/cl/_testgo/tprecur' -source_filename = "github.com/goplus/llgo/cl/_testgo/tprecur" - -%"github.com/goplus/llgo/runtime/abi.Type" = type { i64, i64, i32, i8, i8, i8, i8, { ptr, ptr }, ptr, %"github.com/goplus/llgo/runtime/internal/runtime.String", ptr } -%"github.com/goplus/llgo/runtime/internal/runtime.String" = type { ptr, i64 } -%"github.com/goplus/llgo/runtime/abi.PtrType" = type { %"github.com/goplus/llgo/runtime/abi.Type", ptr } -%"github.com/goplus/llgo/runtime/internal/runtime.eface" = type { ptr, ptr } -%"github.com/goplus/llgo/runtime/internal/runtime.Slice" = type { ptr, i64, i64 } - -@"github.com/goplus/llgo/cl/_testgo/tprecur.init$guard" = global i1 false, align 1 -@0 = private unnamed_addr constant [5 x i8] c"error", align 1 -@_llgo_string = weak_odr constant %"github.com/goplus/llgo/runtime/abi.Type" { i64 16, i64 8, i32 1749264893, i8 4, i8 8, i8 8, i8 24, { ptr, ptr } { ptr @"__llgo_stub.github.com/goplus/llgo/runtime/internal/runtime.strequal", ptr null }, ptr null, %"github.com/goplus/llgo/runtime/internal/runtime.String" { ptr @1, i64 6 }, ptr @"*_llgo_string" }, align 8 -@1 = private unnamed_addr constant [6 x i8] c"string", align 1 -@"*_llgo_string" = weak_odr constant %"github.com/goplus/llgo/runtime/abi.PtrType" { %"github.com/goplus/llgo/runtime/abi.Type" { i64 8, i64 8, i32 -1323879264, i8 10, i8 8, i8 8, i8 54, { ptr, ptr } { ptr @"__llgo_stub.github.com/goplus/llgo/runtime/internal/runtime.memequalptr", ptr null }, ptr null, %"github.com/goplus/llgo/runtime/internal/runtime.String" { ptr @1, i64 6 }, ptr null }, ptr @_llgo_string }, align 8 - -define void @"github.com/goplus/llgo/cl/_testgo/tprecur.init"() { -_llgo_0: - %0 = load i1, ptr @"github.com/goplus/llgo/cl/_testgo/tprecur.init$guard", align 1 - br i1 %0, label %_llgo_2, label %_llgo_1 - -_llgo_1: ; preds = %_llgo_0 - store i1 true, ptr @"github.com/goplus/llgo/cl/_testgo/tprecur.init$guard", align 1 - br label %_llgo_2 - -_llgo_2: ; preds = %_llgo_1, %_llgo_0 - ret void -} - -define void @"github.com/goplus/llgo/cl/_testgo/tprecur.main"() { -_llgo_0: - call void @"github.com/goplus/llgo/cl/_testgo/tprecur.recursive"() - ret void -} - -define void @"github.com/goplus/llgo/cl/_testgo/tprecur.recursive"() { -_llgo_0: - %0 = call i64 @"github.com/goplus/llgo/cl/_testgo/tprecur.recur1[github.com/goplus/llgo/cl/_testgo/tprecur.T.1.0]"(i64 5) - %1 = icmp ne i64 %0, 110 - br i1 %1, label %_llgo_1, label %_llgo_2 - -_llgo_1: ; preds = %_llgo_0 - %2 = 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 %2, align 8 - %3 = insertvalue %"github.com/goplus/llgo/runtime/internal/runtime.eface" { ptr @_llgo_string, ptr undef }, ptr %2, 1 - call void @"github.com/goplus/llgo/runtime/internal/runtime.Panic"(%"github.com/goplus/llgo/runtime/internal/runtime.eface" %3) - unreachable - -_llgo_2: ; preds = %_llgo_0 - ret void -} - -define linkonce i64 @"github.com/goplus/llgo/cl/_testgo/tprecur.recur1[github.com/goplus/llgo/cl/_testgo/tprecur.T.1.0]"(i64 %0) { -_llgo_0: - %1 = icmp eq i64 %0, 0 - br i1 %1, label %_llgo_1, label %_llgo_3 - -_llgo_1: ; preds = %_llgo_3, %_llgo_0 - ret i64 1 - -_llgo_2: ; preds = %_llgo_3 - %2 = sub i64 %0, 1 - %3 = call i64 @"github.com/goplus/llgo/cl/_testgo/tprecur.recur2[github.com/goplus/llgo/cl/_testgo/tprecur.T.1.0]"(i64 %2) - %4 = mul i64 %0, %3 - ret i64 %4 - -_llgo_3: ; preds = %_llgo_0 - %5 = icmp eq i64 %0, 1 - br i1 %5, label %_llgo_1, label %_llgo_2 -} - -declare i1 @"github.com/goplus/llgo/runtime/internal/runtime.strequal"(ptr, ptr) - -define linkonce i1 @"__llgo_stub.github.com/goplus/llgo/runtime/internal/runtime.strequal"(ptr %0, ptr %1, ptr %2) { -_llgo_0: - %3 = tail call i1 @"github.com/goplus/llgo/runtime/internal/runtime.strequal"(ptr %1, ptr %2) - ret i1 %3 -} - -declare i1 @"github.com/goplus/llgo/runtime/internal/runtime.memequalptr"(ptr, ptr) - -define linkonce i1 @"__llgo_stub.github.com/goplus/llgo/runtime/internal/runtime.memequalptr"(ptr %0, ptr %1, ptr %2) { -_llgo_0: - %3 = tail call i1 @"github.com/goplus/llgo/runtime/internal/runtime.memequalptr"(ptr %1, ptr %2) - ret i1 %3 -} - -declare ptr @"github.com/goplus/llgo/runtime/internal/runtime.AllocU"(i64) - -declare void @"github.com/goplus/llgo/runtime/internal/runtime.Panic"(%"github.com/goplus/llgo/runtime/internal/runtime.eface") - -define linkonce i64 @"github.com/goplus/llgo/cl/_testgo/tprecur.recur2[github.com/goplus/llgo/cl/_testgo/tprecur.T.1.0]"(i64 %0) { -_llgo_0: - %1 = call %"github.com/goplus/llgo/runtime/internal/runtime.Slice" @"github.com/goplus/llgo/runtime/internal/runtime.MakeSlice"(i64 %0, i64 %0, i64 8) - %2 = extractvalue %"github.com/goplus/llgo/runtime/internal/runtime.Slice" %1, 1 - br label %_llgo_1 - -_llgo_1: ; preds = %_llgo_2, %_llgo_0 - %3 = phi i64 [ -1, %_llgo_0 ], [ %4, %_llgo_2 ] - %4 = add i64 %3, 1 - %5 = icmp slt i64 %4, %2 - br i1 %5, label %_llgo_2, label %_llgo_3 - -_llgo_2: ; preds = %_llgo_1 - %6 = add i64 %4, 1 - %7 = extractvalue %"github.com/goplus/llgo/runtime/internal/runtime.Slice" %1, 0 - %8 = extractvalue %"github.com/goplus/llgo/runtime/internal/runtime.Slice" %1, 1 - %9 = icmp slt i64 %4, 0 - %10 = icmp uge i64 %4, %8 - %11 = or i1 %10, %9 - call void @"github.com/goplus/llgo/runtime/internal/runtime.AssertIndexRange"(i1 %11) - %12 = getelementptr inbounds i64, ptr %7, i64 %4 - store i64 %6, ptr %12, align 4 - br label %_llgo_1 - -_llgo_3: ; preds = %_llgo_1 - %13 = extractvalue %"github.com/goplus/llgo/runtime/internal/runtime.Slice" %1, 1 - br label %_llgo_4 - -_llgo_4: ; preds = %_llgo_5, %_llgo_3 - %14 = phi i64 [ 0, %_llgo_3 ], [ %25, %_llgo_5 ] - %15 = phi i64 [ -1, %_llgo_3 ], [ %16, %_llgo_5 ] - %16 = add i64 %15, 1 - %17 = icmp slt i64 %16, %13 - br i1 %17, label %_llgo_5, label %_llgo_6 - -_llgo_5: ; preds = %_llgo_4 - %18 = extractvalue %"github.com/goplus/llgo/runtime/internal/runtime.Slice" %1, 0 - %19 = extractvalue %"github.com/goplus/llgo/runtime/internal/runtime.Slice" %1, 1 - %20 = icmp slt i64 %16, 0 - %21 = icmp uge i64 %16, %19 - %22 = or i1 %21, %20 - call void @"github.com/goplus/llgo/runtime/internal/runtime.AssertIndexRange"(i1 %22) - %23 = getelementptr inbounds i64, ptr %18, i64 %16 - %24 = load i64, ptr %23, align 4 - %25 = add i64 %14, %24 - br label %_llgo_4 - -_llgo_6: ; preds = %_llgo_4 - %26 = sub i64 %0, 1 - %27 = call i64 @"github.com/goplus/llgo/cl/_testgo/tprecur.recur1[github.com/goplus/llgo/cl/_testgo/tprecur.T.1.0]"(i64 %26) - %28 = add i64 %14, %27 - ret i64 %28 -} - -declare %"github.com/goplus/llgo/runtime/internal/runtime.Slice" @"github.com/goplus/llgo/runtime/internal/runtime.MakeSlice"(i64, i64, i64) - -declare void @"github.com/goplus/llgo/runtime/internal/runtime.AssertIndexRange"(i1) diff --git a/cl/_testgo/tprecurfn/in.go b/cl/_testgo/tprecurfn/in.go index de9928916d..c8e20a4707 100644 --- a/cl/_testgo/tprecurfn/in.go +++ b/cl/_testgo/tprecurfn/in.go @@ -12,7 +12,7 @@ func main() { // CHECK-NEXT: %1 = getelementptr inbounds %"main.My[int]", ptr %0, i32 0, i32 1 // CHECK-NEXT: %2 = call ptr @"{{.*}}/runtime/internal/runtime.AllocZ"(i64 24) // CHECK-NEXT: %3 = getelementptr inbounds %"main.My[int]", ptr %2, i32 0, i32 0 - // CHECK-NEXT: store { ptr, ptr } { ptr @"__llgo_stub.main.main$1", ptr null }, ptr %3, align 8 + // CHECK-NEXT: store { ptr, ptr } { ptr @"main.main$1", ptr null }, ptr %3, align 8 // CHECK-NEXT: store ptr %2, ptr %1, align 8 // CHECK-NEXT: %4 = getelementptr inbounds %"main.My[int]", ptr %0, i32 0, i32 1 // CHECK-NEXT: %5 = load ptr, ptr %4, align 8 @@ -20,7 +20,8 @@ func main() { // CHECK-NEXT: %7 = load { ptr, ptr }, ptr %6, align 8 // CHECK-NEXT: %8 = extractvalue { ptr, ptr } %7, 1 // CHECK-NEXT: %9 = extractvalue { ptr, ptr } %7, 0 - // CHECK-NEXT: call void %9(ptr %8, i64 100) + // CHECK-NEXT: %__llgo_funcval_code = call ptr asm "", "=r,0"(ptr %9) + // CHECK-NEXT: call void %__llgo_funcval_code(ptr {{(nest|swiftself)}} %8, i64 100) // CHECK-NEXT: ret void // CHECK-NEXT:} m := &My[int]{next: &My[int]{fn: func(n int) { println(n) }}} diff --git a/cl/_testgo/typerecur/in.go b/cl/_testgo/typerecur/in.go index 247cb793df..cd7492b2f9 100644 --- a/cl/_testgo/typerecur/in.go +++ b/cl/_testgo/typerecur/in.go @@ -20,7 +20,7 @@ type counter struct { // CHECK: call void @"{{.*}}PrintInt"(i64 %6) // CHECK: icmp sge i64 %8, %10 // CHECK: ret %main.stateFn zeroinitializer -// CHECK: ret %main.stateFn { ptr @__llgo_stub.main.countState, ptr null } +// CHECK: ret %main.stateFn { ptr @main.countState, ptr null } func countState(c *counter) stateFn { c.value++ println("count:", c.value) @@ -35,8 +35,9 @@ func countState(c *counter) stateFn { func main() { // CHECK: call ptr @"{{.*}}AllocZ"(i64 32) // CHECK: store i64 5, ptr %1, align 8 - // CHECK: store %main.stateFn { ptr @__llgo_stub.main.countState, ptr null }, ptr %2, align 8 - // CHECK: call %main.stateFn %6(ptr %5, ptr %0) + // CHECK: store %main.stateFn { ptr @main.countState, ptr null }, ptr %2, align 8 + // CHECK: %__llgo_funcval_code = call ptr asm "", "=r,0"(ptr %6) + // CHECK: call %main.stateFn %__llgo_funcval_code(ptr {{(nest|swiftself)}} %5, ptr %0) // CHECK: store %main.stateFn %7, ptr %8, align 8 // CHECK: icmp ne ptr %11, null // CHECK: br i1 %12, label %_llgo_1, label %_llgo_2 diff --git a/cl/_testlibgo/strings/in.go b/cl/_testlibgo/strings/in.go index 9c1d390e32..f7239b2229 100644 --- a/cl/_testlibgo/strings/in.go +++ b/cl/_testlibgo/strings/in.go @@ -28,10 +28,10 @@ func main() { // CHECK-NEXT: call void @"{{.*}}/runtime/internal/runtime.PrintByte"(i8 32) // CHECK-NEXT: call void @"{{.*}}/runtime/internal/runtime.PrintString"(%"{{.*}}/runtime/internal/runtime.String" %6) // CHECK-NEXT: call void @"{{.*}}/runtime/internal/runtime.PrintByte"(i8 10) - // CHECK-NEXT: %7 = call i64 @strings.IndexFunc(%"{{.*}}/runtime/internal/runtime.String" { ptr @5, i64 13 }, { ptr, ptr } { ptr @"__llgo_stub.main.main$1", ptr null }) + // CHECK-NEXT: %7 = call i64 @strings.IndexFunc(%"{{.*}}/runtime/internal/runtime.String" { ptr @5, i64 13 }, { ptr, ptr } { ptr @"main.main$1", ptr null }) // CHECK-NEXT: call void @"{{.*}}/runtime/internal/runtime.PrintInt"(i64 %7) // CHECK-NEXT: call void @"{{.*}}/runtime/internal/runtime.PrintByte"(i8 10) - // CHECK-NEXT: %8 = call i64 @strings.IndexFunc(%"{{.*}}/runtime/internal/runtime.String" { ptr @6, i64 12 }, { ptr, ptr } { ptr @"__llgo_stub.main.main$1", ptr null }) + // CHECK-NEXT: %8 = call i64 @strings.IndexFunc(%"{{.*}}/runtime/internal/runtime.String" { ptr @6, i64 12 }, { ptr, ptr } { ptr @"main.main$1", ptr null }) // CHECK-NEXT: call void @"{{.*}}/runtime/internal/runtime.PrintInt"(i64 %8) // CHECK-NEXT: call void @"{{.*}}/runtime/internal/runtime.PrintByte"(i8 10) // CHECK-NEXT: ret void diff --git a/cl/_testmeta/ifaceuse_basic/meta-expect.txt b/cl/_testmeta/ifaceuse_basic/meta-expect.txt index bb9606227c..cff8a1caf1 100644 --- a/cl/_testmeta/ifaceuse_basic/meta-expect.txt +++ b/cl/_testmeta/ifaceuse_basic/meta-expect.txt @@ -6,15 +6,11 @@ _llgo_main.T: [OrdinaryEdges] *_llgo_main.T: - __llgo_stub.github.com/goplus/llgo/runtime/internal/runtime.memequalptr _llgo_main.T -__llgo_stub.github.com/goplus/llgo/runtime/internal/runtime.memequal0: - github.com/goplus/llgo/runtime/internal/runtime.memequal0 -__llgo_stub.github.com/goplus/llgo/runtime/internal/runtime.memequalptr: github.com/goplus/llgo/runtime/internal/runtime.memequalptr _llgo_main.T: *_llgo_main.T - __llgo_stub.github.com/goplus/llgo/runtime/internal/runtime.memequal0 + github.com/goplus/llgo/runtime/internal/runtime.memequal0 main.init: main.init$guard main.main: diff --git a/cl/_testmeta/interface_anyonmous/meta-expect.txt b/cl/_testmeta/interface_anyonmous/meta-expect.txt index f8e21b08ca..eeeee403f9 100644 --- a/cl/_testmeta/interface_anyonmous/meta-expect.txt +++ b/cl/_testmeta/interface_anyonmous/meta-expect.txt @@ -12,39 +12,25 @@ _llgo_main.T: [OrdinaryEdges] *_llgo_func$2_iS07vIlF2_rZqWB5eU0IvP_9HviM4MYZNkXZDvbac: - __llgo_stub.github.com/goplus/llgo/runtime/internal/runtime.memequalptr _llgo_func$2_iS07vIlF2_rZqWB5eU0IvP_9HviM4MYZNkXZDvbac + github.com/goplus/llgo/runtime/internal/runtime.memequalptr *_llgo_iface$f14WsslTA1u5wwC83jLU0HU2u2mmAWxBVE38vPBbRAo: - __llgo_stub.github.com/goplus/llgo/runtime/internal/runtime.memequalptr _llgo_iface$f14WsslTA1u5wwC83jLU0HU2u2mmAWxBVE38vPBbRAo + github.com/goplus/llgo/runtime/internal/runtime.memequalptr *_llgo_main.T: - __llgo_stub.github.com/goplus/llgo/runtime/internal/runtime.memequalptr _llgo_main.T -__llgo_stub.github.com/goplus/llgo/runtime/internal/runtime.interequal: - github.com/goplus/llgo/runtime/internal/runtime.interequal -__llgo_stub.github.com/goplus/llgo/runtime/internal/runtime.memequal0: - github.com/goplus/llgo/runtime/internal/runtime.memequal0 -__llgo_stub.github.com/goplus/llgo/runtime/internal/runtime.memequalptr: github.com/goplus/llgo/runtime/internal/runtime.memequalptr -__llgo_stub.main.(*T).M: - main.(*T).M -__llgo_stub.main.(*T).N: - main.(*T).N -__llgo_stub.main.T.M: - main.T.M -__llgo_stub.main.T.N: - main.T.N _llgo_func$2_iS07vIlF2_rZqWB5eU0IvP_9HviM4MYZNkXZDvbac: *_llgo_func$2_iS07vIlF2_rZqWB5eU0IvP_9HviM4MYZNkXZDvbac _llgo_iface$f14WsslTA1u5wwC83jLU0HU2u2mmAWxBVE38vPBbRAo: *_llgo_iface$f14WsslTA1u5wwC83jLU0HU2u2mmAWxBVE38vPBbRAo - __llgo_stub.github.com/goplus/llgo/runtime/internal/runtime.interequal _llgo_iface$f14WsslTA1u5wwC83jLU0HU2u2mmAWxBVE38vPBbRAo$imethods + github.com/goplus/llgo/runtime/internal/runtime.interequal _llgo_iface$f14WsslTA1u5wwC83jLU0HU2u2mmAWxBVE38vPBbRAo$imethods: _llgo_func$2_iS07vIlF2_rZqWB5eU0IvP_9HviM4MYZNkXZDvbac _llgo_main.T: *_llgo_main.T - __llgo_stub.github.com/goplus/llgo/runtime/internal/runtime.memequal0 + github.com/goplus/llgo/runtime/internal/runtime.memequal0 main.(*T).M: github.com/goplus/llgo/runtime/internal/runtime.AssertNilDeref github.com/goplus/llgo/runtime/internal/runtime.PanicWrapNilPointer @@ -75,11 +61,11 @@ main.use: [MethodInfo] *_llgo_main.T: - 0 M _llgo_func$2_iS07vIlF2_rZqWB5eU0IvP_9HviM4MYZNkXZDvbac main.(*T).M __llgo_stub.main.(*T).M - 1 N _llgo_func$2_iS07vIlF2_rZqWB5eU0IvP_9HviM4MYZNkXZDvbac main.(*T).N __llgo_stub.main.(*T).N + 0 M _llgo_func$2_iS07vIlF2_rZqWB5eU0IvP_9HviM4MYZNkXZDvbac main.(*T).M main.(*T).M + 1 N _llgo_func$2_iS07vIlF2_rZqWB5eU0IvP_9HviM4MYZNkXZDvbac main.(*T).N main.(*T).N _llgo_main.T: - 0 M _llgo_func$2_iS07vIlF2_rZqWB5eU0IvP_9HviM4MYZNkXZDvbac main.(*T).M __llgo_stub.main.T.M - 1 N _llgo_func$2_iS07vIlF2_rZqWB5eU0IvP_9HviM4MYZNkXZDvbac main.(*T).N __llgo_stub.main.T.N + 0 M _llgo_func$2_iS07vIlF2_rZqWB5eU0IvP_9HviM4MYZNkXZDvbac main.(*T).M main.T.M + 1 N _llgo_func$2_iS07vIlF2_rZqWB5eU0IvP_9HviM4MYZNkXZDvbac main.(*T).N main.T.N [InterfaceInfo] _llgo_iface$f14WsslTA1u5wwC83jLU0HU2u2mmAWxBVE38vPBbRAo: diff --git a/cl/_testmeta/interface_exported_var/meta-expect.txt b/cl/_testmeta/interface_exported_var/meta-expect.txt index cc381a3fce..6343b52498 100644 --- a/cl/_testmeta/interface_exported_var/meta-expect.txt +++ b/cl/_testmeta/interface_exported_var/meta-expect.txt @@ -93,124 +93,64 @@ _llgo_uint8: [OrdinaryEdges] *[]_llgo_uint8: []_llgo_uint8 - __llgo_stub.github.com/goplus/llgo/runtime/internal/runtime.memequalptr + github.com/goplus/llgo/runtime/internal/runtime.memequalptr *_llgo_encoding/binary.littleEndian: - __llgo_stub.github.com/goplus/llgo/runtime/internal/runtime.memequalptr _llgo_encoding/binary.littleEndian + github.com/goplus/llgo/runtime/internal/runtime.memequalptr *_llgo_func$HQem8FNvPqrEVQ_c0XssBDFXIDOnET_Ex7o3PlV9bSs: - __llgo_stub.github.com/goplus/llgo/runtime/internal/runtime.memequalptr _llgo_func$HQem8FNvPqrEVQ_c0XssBDFXIDOnET_Ex7o3PlV9bSs + github.com/goplus/llgo/runtime/internal/runtime.memequalptr *_llgo_func$ICfGJV9Kp4o-2SMi1iuyC9xBBX1c5utHD63uVbyrfEc: - __llgo_stub.github.com/goplus/llgo/runtime/internal/runtime.memequalptr _llgo_func$ICfGJV9Kp4o-2SMi1iuyC9xBBX1c5utHD63uVbyrfEc + github.com/goplus/llgo/runtime/internal/runtime.memequalptr *_llgo_func$JXgl4jz35cOkksEkyj-ImVTqIDNL16JrZ25HHa-Yekw: - __llgo_stub.github.com/goplus/llgo/runtime/internal/runtime.memequalptr _llgo_func$JXgl4jz35cOkksEkyj-ImVTqIDNL16JrZ25HHa-Yekw + github.com/goplus/llgo/runtime/internal/runtime.memequalptr *_llgo_func$YjgNCugJxKXYLk39KOJyRyLtvcHU1d7KRz4inhHdVgg: - __llgo_stub.github.com/goplus/llgo/runtime/internal/runtime.memequalptr _llgo_func$YjgNCugJxKXYLk39KOJyRyLtvcHU1d7KRz4inhHdVgg + github.com/goplus/llgo/runtime/internal/runtime.memequalptr *_llgo_func$_JswjMs_mFNKWtFb56TJlZa479nBYWhoAxYBwUTwOyc: - __llgo_stub.github.com/goplus/llgo/runtime/internal/runtime.memequalptr _llgo_func$_JswjMs_mFNKWtFb56TJlZa479nBYWhoAxYBwUTwOyc + github.com/goplus/llgo/runtime/internal/runtime.memequalptr *_llgo_func$hV5ojfmZDe6MffI0ylemgDF5GZlZiYaJbQvka2A0Gus: - __llgo_stub.github.com/goplus/llgo/runtime/internal/runtime.memequalptr _llgo_func$hV5ojfmZDe6MffI0ylemgDF5GZlZiYaJbQvka2A0Gus + github.com/goplus/llgo/runtime/internal/runtime.memequalptr *_llgo_func$ibbVVENlZHDgol7ROnCbrRmXPuO818NXcpl5dfFoKhU: - __llgo_stub.github.com/goplus/llgo/runtime/internal/runtime.memequalptr _llgo_func$ibbVVENlZHDgol7ROnCbrRmXPuO818NXcpl5dfFoKhU + github.com/goplus/llgo/runtime/internal/runtime.memequalptr *_llgo_func$mBhSCdZCFK2IHVQVA73dFmon0gMcig2Q387khsbzmm8: - __llgo_stub.github.com/goplus/llgo/runtime/internal/runtime.memequalptr _llgo_func$mBhSCdZCFK2IHVQVA73dFmon0gMcig2Q387khsbzmm8 + github.com/goplus/llgo/runtime/internal/runtime.memequalptr *_llgo_func$mjkdaEUHPtpOYlUrWGfnskhhvdyc7k9Fk-vwWj3VftE: - __llgo_stub.github.com/goplus/llgo/runtime/internal/runtime.memequalptr _llgo_func$mjkdaEUHPtpOYlUrWGfnskhhvdyc7k9Fk-vwWj3VftE + github.com/goplus/llgo/runtime/internal/runtime.memequalptr *_llgo_func$zNDVRsWTIpUPKouNUS805RGX--IV9qVK8B31IZbg5to: - __llgo_stub.github.com/goplus/llgo/runtime/internal/runtime.memequalptr _llgo_func$zNDVRsWTIpUPKouNUS805RGX--IV9qVK8B31IZbg5to + github.com/goplus/llgo/runtime/internal/runtime.memequalptr *_llgo_iface$J1wM-rGcIPemx5jloXBmH7pUzUCSqpgNkOdb0QIFTxw: - __llgo_stub.github.com/goplus/llgo/runtime/internal/runtime.memequalptr _llgo_iface$J1wM-rGcIPemx5jloXBmH7pUzUCSqpgNkOdb0QIFTxw + github.com/goplus/llgo/runtime/internal/runtime.memequalptr *_llgo_string: - __llgo_stub.github.com/goplus/llgo/runtime/internal/runtime.memequalptr _llgo_string + github.com/goplus/llgo/runtime/internal/runtime.memequalptr *_llgo_uint16: - __llgo_stub.github.com/goplus/llgo/runtime/internal/runtime.memequalptr _llgo_uint16 + github.com/goplus/llgo/runtime/internal/runtime.memequalptr *_llgo_uint32: - __llgo_stub.github.com/goplus/llgo/runtime/internal/runtime.memequalptr _llgo_uint32 + github.com/goplus/llgo/runtime/internal/runtime.memequalptr *_llgo_uint64: - __llgo_stub.github.com/goplus/llgo/runtime/internal/runtime.memequalptr _llgo_uint64 + github.com/goplus/llgo/runtime/internal/runtime.memequalptr *_llgo_uint8: - __llgo_stub.github.com/goplus/llgo/runtime/internal/runtime.memequalptr _llgo_uint8 + github.com/goplus/llgo/runtime/internal/runtime.memequalptr []_llgo_uint8: *[]_llgo_uint8 _llgo_uint8 -__llgo_stub.encoding/binary.(*littleEndian).AppendUint16: - encoding/binary.(*littleEndian).AppendUint16 -__llgo_stub.encoding/binary.(*littleEndian).AppendUint32: - encoding/binary.(*littleEndian).AppendUint32 -__llgo_stub.encoding/binary.(*littleEndian).AppendUint64: - encoding/binary.(*littleEndian).AppendUint64 -__llgo_stub.encoding/binary.(*littleEndian).GoString: - encoding/binary.(*littleEndian).GoString -__llgo_stub.encoding/binary.(*littleEndian).PutUint16: - encoding/binary.(*littleEndian).PutUint16 -__llgo_stub.encoding/binary.(*littleEndian).PutUint32: - encoding/binary.(*littleEndian).PutUint32 -__llgo_stub.encoding/binary.(*littleEndian).PutUint64: - encoding/binary.(*littleEndian).PutUint64 -__llgo_stub.encoding/binary.(*littleEndian).String: - encoding/binary.(*littleEndian).String -__llgo_stub.encoding/binary.(*littleEndian).Uint16: - encoding/binary.(*littleEndian).Uint16 -__llgo_stub.encoding/binary.(*littleEndian).Uint32: - encoding/binary.(*littleEndian).Uint32 -__llgo_stub.encoding/binary.(*littleEndian).Uint64: - encoding/binary.(*littleEndian).Uint64 -__llgo_stub.encoding/binary.littleEndian.AppendUint16: - encoding/binary.littleEndian.AppendUint16 -__llgo_stub.encoding/binary.littleEndian.AppendUint32: - encoding/binary.littleEndian.AppendUint32 -__llgo_stub.encoding/binary.littleEndian.AppendUint64: - encoding/binary.littleEndian.AppendUint64 -__llgo_stub.encoding/binary.littleEndian.GoString: - encoding/binary.littleEndian.GoString -__llgo_stub.encoding/binary.littleEndian.PutUint16: - encoding/binary.littleEndian.PutUint16 -__llgo_stub.encoding/binary.littleEndian.PutUint32: - encoding/binary.littleEndian.PutUint32 -__llgo_stub.encoding/binary.littleEndian.PutUint64: - encoding/binary.littleEndian.PutUint64 -__llgo_stub.encoding/binary.littleEndian.String: - encoding/binary.littleEndian.String -__llgo_stub.encoding/binary.littleEndian.Uint16: - encoding/binary.littleEndian.Uint16 -__llgo_stub.encoding/binary.littleEndian.Uint32: - encoding/binary.littleEndian.Uint32 -__llgo_stub.encoding/binary.littleEndian.Uint64: - encoding/binary.littleEndian.Uint64 -__llgo_stub.github.com/goplus/llgo/runtime/internal/runtime.interequal: - github.com/goplus/llgo/runtime/internal/runtime.interequal -__llgo_stub.github.com/goplus/llgo/runtime/internal/runtime.memequal0: - github.com/goplus/llgo/runtime/internal/runtime.memequal0 -__llgo_stub.github.com/goplus/llgo/runtime/internal/runtime.memequal16: - github.com/goplus/llgo/runtime/internal/runtime.memequal16 -__llgo_stub.github.com/goplus/llgo/runtime/internal/runtime.memequal32: - github.com/goplus/llgo/runtime/internal/runtime.memequal32 -__llgo_stub.github.com/goplus/llgo/runtime/internal/runtime.memequal64: - github.com/goplus/llgo/runtime/internal/runtime.memequal64 -__llgo_stub.github.com/goplus/llgo/runtime/internal/runtime.memequal8: - github.com/goplus/llgo/runtime/internal/runtime.memequal8 -__llgo_stub.github.com/goplus/llgo/runtime/internal/runtime.memequalptr: - github.com/goplus/llgo/runtime/internal/runtime.memequalptr -__llgo_stub.github.com/goplus/llgo/runtime/internal/runtime.strequal: - github.com/goplus/llgo/runtime/internal/runtime.strequal _llgo_encoding/binary.littleEndian: *_llgo_encoding/binary.littleEndian - __llgo_stub.github.com/goplus/llgo/runtime/internal/runtime.memequal0 + github.com/goplus/llgo/runtime/internal/runtime.memequal0 _llgo_func$HQem8FNvPqrEVQ_c0XssBDFXIDOnET_Ex7o3PlV9bSs: *_llgo_func$HQem8FNvPqrEVQ_c0XssBDFXIDOnET_Ex7o3PlV9bSs _llgo_func$HQem8FNvPqrEVQ_c0XssBDFXIDOnET_Ex7o3PlV9bSs$in @@ -287,8 +227,8 @@ _llgo_func$zNDVRsWTIpUPKouNUS805RGX--IV9qVK8B31IZbg5to$out: _llgo_string _llgo_iface$J1wM-rGcIPemx5jloXBmH7pUzUCSqpgNkOdb0QIFTxw: *_llgo_iface$J1wM-rGcIPemx5jloXBmH7pUzUCSqpgNkOdb0QIFTxw - __llgo_stub.github.com/goplus/llgo/runtime/internal/runtime.interequal _llgo_iface$J1wM-rGcIPemx5jloXBmH7pUzUCSqpgNkOdb0QIFTxw$imethods + github.com/goplus/llgo/runtime/internal/runtime.interequal _llgo_iface$J1wM-rGcIPemx5jloXBmH7pUzUCSqpgNkOdb0QIFTxw$imethods: _llgo_func$ICfGJV9Kp4o-2SMi1iuyC9xBBX1c5utHD63uVbyrfEc _llgo_func$YjgNCugJxKXYLk39KOJyRyLtvcHU1d7KRz4inhHdVgg @@ -299,19 +239,19 @@ _llgo_iface$J1wM-rGcIPemx5jloXBmH7pUzUCSqpgNkOdb0QIFTxw$imethods: _llgo_func$zNDVRsWTIpUPKouNUS805RGX--IV9qVK8B31IZbg5to _llgo_string: *_llgo_string - __llgo_stub.github.com/goplus/llgo/runtime/internal/runtime.strequal + github.com/goplus/llgo/runtime/internal/runtime.strequal _llgo_uint16: *_llgo_uint16 - __llgo_stub.github.com/goplus/llgo/runtime/internal/runtime.memequal16 + github.com/goplus/llgo/runtime/internal/runtime.memequal16 _llgo_uint32: *_llgo_uint32 - __llgo_stub.github.com/goplus/llgo/runtime/internal/runtime.memequal32 + github.com/goplus/llgo/runtime/internal/runtime.memequal32 _llgo_uint64: *_llgo_uint64 - __llgo_stub.github.com/goplus/llgo/runtime/internal/runtime.memequal64 + github.com/goplus/llgo/runtime/internal/runtime.memequal64 _llgo_uint8: *_llgo_uint8 - __llgo_stub.github.com/goplus/llgo/runtime/internal/runtime.memequal8 + github.com/goplus/llgo/runtime/internal/runtime.memequal8 main.init: encoding/binary.init main.init$guard @@ -335,29 +275,29 @@ main.main: [MethodInfo] *_llgo_encoding/binary.littleEndian: - 0 AppendUint16 _llgo_func$JXgl4jz35cOkksEkyj-ImVTqIDNL16JrZ25HHa-Yekw encoding/binary.(*littleEndian).AppendUint16 __llgo_stub.encoding/binary.(*littleEndian).AppendUint16 - 1 AppendUint32 _llgo_func$_JswjMs_mFNKWtFb56TJlZa479nBYWhoAxYBwUTwOyc encoding/binary.(*littleEndian).AppendUint32 __llgo_stub.encoding/binary.(*littleEndian).AppendUint32 - 2 AppendUint64 _llgo_func$HQem8FNvPqrEVQ_c0XssBDFXIDOnET_Ex7o3PlV9bSs encoding/binary.(*littleEndian).AppendUint64 __llgo_stub.encoding/binary.(*littleEndian).AppendUint64 - 3 GoString _llgo_func$zNDVRsWTIpUPKouNUS805RGX--IV9qVK8B31IZbg5to encoding/binary.(*littleEndian).GoString __llgo_stub.encoding/binary.(*littleEndian).GoString - 4 PutUint16 _llgo_func$ibbVVENlZHDgol7ROnCbrRmXPuO818NXcpl5dfFoKhU encoding/binary.(*littleEndian).PutUint16 __llgo_stub.encoding/binary.(*littleEndian).PutUint16 - 5 PutUint32 _llgo_func$YjgNCugJxKXYLk39KOJyRyLtvcHU1d7KRz4inhHdVgg encoding/binary.(*littleEndian).PutUint32 __llgo_stub.encoding/binary.(*littleEndian).PutUint32 - 6 PutUint64 _llgo_func$mBhSCdZCFK2IHVQVA73dFmon0gMcig2Q387khsbzmm8 encoding/binary.(*littleEndian).PutUint64 __llgo_stub.encoding/binary.(*littleEndian).PutUint64 - 7 String _llgo_func$zNDVRsWTIpUPKouNUS805RGX--IV9qVK8B31IZbg5to encoding/binary.(*littleEndian).String __llgo_stub.encoding/binary.(*littleEndian).String - 8 Uint16 _llgo_func$hV5ojfmZDe6MffI0ylemgDF5GZlZiYaJbQvka2A0Gus encoding/binary.(*littleEndian).Uint16 __llgo_stub.encoding/binary.(*littleEndian).Uint16 - 9 Uint32 _llgo_func$ICfGJV9Kp4o-2SMi1iuyC9xBBX1c5utHD63uVbyrfEc encoding/binary.(*littleEndian).Uint32 __llgo_stub.encoding/binary.(*littleEndian).Uint32 - 10 Uint64 _llgo_func$mjkdaEUHPtpOYlUrWGfnskhhvdyc7k9Fk-vwWj3VftE encoding/binary.(*littleEndian).Uint64 __llgo_stub.encoding/binary.(*littleEndian).Uint64 + 0 AppendUint16 _llgo_func$JXgl4jz35cOkksEkyj-ImVTqIDNL16JrZ25HHa-Yekw encoding/binary.(*littleEndian).AppendUint16 encoding/binary.(*littleEndian).AppendUint16 + 1 AppendUint32 _llgo_func$_JswjMs_mFNKWtFb56TJlZa479nBYWhoAxYBwUTwOyc encoding/binary.(*littleEndian).AppendUint32 encoding/binary.(*littleEndian).AppendUint32 + 2 AppendUint64 _llgo_func$HQem8FNvPqrEVQ_c0XssBDFXIDOnET_Ex7o3PlV9bSs encoding/binary.(*littleEndian).AppendUint64 encoding/binary.(*littleEndian).AppendUint64 + 3 GoString _llgo_func$zNDVRsWTIpUPKouNUS805RGX--IV9qVK8B31IZbg5to encoding/binary.(*littleEndian).GoString encoding/binary.(*littleEndian).GoString + 4 PutUint16 _llgo_func$ibbVVENlZHDgol7ROnCbrRmXPuO818NXcpl5dfFoKhU encoding/binary.(*littleEndian).PutUint16 encoding/binary.(*littleEndian).PutUint16 + 5 PutUint32 _llgo_func$YjgNCugJxKXYLk39KOJyRyLtvcHU1d7KRz4inhHdVgg encoding/binary.(*littleEndian).PutUint32 encoding/binary.(*littleEndian).PutUint32 + 6 PutUint64 _llgo_func$mBhSCdZCFK2IHVQVA73dFmon0gMcig2Q387khsbzmm8 encoding/binary.(*littleEndian).PutUint64 encoding/binary.(*littleEndian).PutUint64 + 7 String _llgo_func$zNDVRsWTIpUPKouNUS805RGX--IV9qVK8B31IZbg5to encoding/binary.(*littleEndian).String encoding/binary.(*littleEndian).String + 8 Uint16 _llgo_func$hV5ojfmZDe6MffI0ylemgDF5GZlZiYaJbQvka2A0Gus encoding/binary.(*littleEndian).Uint16 encoding/binary.(*littleEndian).Uint16 + 9 Uint32 _llgo_func$ICfGJV9Kp4o-2SMi1iuyC9xBBX1c5utHD63uVbyrfEc encoding/binary.(*littleEndian).Uint32 encoding/binary.(*littleEndian).Uint32 + 10 Uint64 _llgo_func$mjkdaEUHPtpOYlUrWGfnskhhvdyc7k9Fk-vwWj3VftE encoding/binary.(*littleEndian).Uint64 encoding/binary.(*littleEndian).Uint64 _llgo_encoding/binary.littleEndian: - 0 AppendUint16 _llgo_func$JXgl4jz35cOkksEkyj-ImVTqIDNL16JrZ25HHa-Yekw encoding/binary.(*littleEndian).AppendUint16 __llgo_stub.encoding/binary.littleEndian.AppendUint16 - 1 AppendUint32 _llgo_func$_JswjMs_mFNKWtFb56TJlZa479nBYWhoAxYBwUTwOyc encoding/binary.(*littleEndian).AppendUint32 __llgo_stub.encoding/binary.littleEndian.AppendUint32 - 2 AppendUint64 _llgo_func$HQem8FNvPqrEVQ_c0XssBDFXIDOnET_Ex7o3PlV9bSs encoding/binary.(*littleEndian).AppendUint64 __llgo_stub.encoding/binary.littleEndian.AppendUint64 - 3 GoString _llgo_func$zNDVRsWTIpUPKouNUS805RGX--IV9qVK8B31IZbg5to encoding/binary.(*littleEndian).GoString __llgo_stub.encoding/binary.littleEndian.GoString - 4 PutUint16 _llgo_func$ibbVVENlZHDgol7ROnCbrRmXPuO818NXcpl5dfFoKhU encoding/binary.(*littleEndian).PutUint16 __llgo_stub.encoding/binary.littleEndian.PutUint16 - 5 PutUint32 _llgo_func$YjgNCugJxKXYLk39KOJyRyLtvcHU1d7KRz4inhHdVgg encoding/binary.(*littleEndian).PutUint32 __llgo_stub.encoding/binary.littleEndian.PutUint32 - 6 PutUint64 _llgo_func$mBhSCdZCFK2IHVQVA73dFmon0gMcig2Q387khsbzmm8 encoding/binary.(*littleEndian).PutUint64 __llgo_stub.encoding/binary.littleEndian.PutUint64 - 7 String _llgo_func$zNDVRsWTIpUPKouNUS805RGX--IV9qVK8B31IZbg5to encoding/binary.(*littleEndian).String __llgo_stub.encoding/binary.littleEndian.String - 8 Uint16 _llgo_func$hV5ojfmZDe6MffI0ylemgDF5GZlZiYaJbQvka2A0Gus encoding/binary.(*littleEndian).Uint16 __llgo_stub.encoding/binary.littleEndian.Uint16 - 9 Uint32 _llgo_func$ICfGJV9Kp4o-2SMi1iuyC9xBBX1c5utHD63uVbyrfEc encoding/binary.(*littleEndian).Uint32 __llgo_stub.encoding/binary.littleEndian.Uint32 - 10 Uint64 _llgo_func$mjkdaEUHPtpOYlUrWGfnskhhvdyc7k9Fk-vwWj3VftE encoding/binary.(*littleEndian).Uint64 __llgo_stub.encoding/binary.littleEndian.Uint64 + 0 AppendUint16 _llgo_func$JXgl4jz35cOkksEkyj-ImVTqIDNL16JrZ25HHa-Yekw encoding/binary.(*littleEndian).AppendUint16 encoding/binary.littleEndian.AppendUint16 + 1 AppendUint32 _llgo_func$_JswjMs_mFNKWtFb56TJlZa479nBYWhoAxYBwUTwOyc encoding/binary.(*littleEndian).AppendUint32 encoding/binary.littleEndian.AppendUint32 + 2 AppendUint64 _llgo_func$HQem8FNvPqrEVQ_c0XssBDFXIDOnET_Ex7o3PlV9bSs encoding/binary.(*littleEndian).AppendUint64 encoding/binary.littleEndian.AppendUint64 + 3 GoString _llgo_func$zNDVRsWTIpUPKouNUS805RGX--IV9qVK8B31IZbg5to encoding/binary.(*littleEndian).GoString encoding/binary.littleEndian.GoString + 4 PutUint16 _llgo_func$ibbVVENlZHDgol7ROnCbrRmXPuO818NXcpl5dfFoKhU encoding/binary.(*littleEndian).PutUint16 encoding/binary.littleEndian.PutUint16 + 5 PutUint32 _llgo_func$YjgNCugJxKXYLk39KOJyRyLtvcHU1d7KRz4inhHdVgg encoding/binary.(*littleEndian).PutUint32 encoding/binary.littleEndian.PutUint32 + 6 PutUint64 _llgo_func$mBhSCdZCFK2IHVQVA73dFmon0gMcig2Q387khsbzmm8 encoding/binary.(*littleEndian).PutUint64 encoding/binary.littleEndian.PutUint64 + 7 String _llgo_func$zNDVRsWTIpUPKouNUS805RGX--IV9qVK8B31IZbg5to encoding/binary.(*littleEndian).String encoding/binary.littleEndian.String + 8 Uint16 _llgo_func$hV5ojfmZDe6MffI0ylemgDF5GZlZiYaJbQvka2A0Gus encoding/binary.(*littleEndian).Uint16 encoding/binary.littleEndian.Uint16 + 9 Uint32 _llgo_func$ICfGJV9Kp4o-2SMi1iuyC9xBBX1c5utHD63uVbyrfEc encoding/binary.(*littleEndian).Uint32 encoding/binary.littleEndian.Uint32 + 10 Uint64 _llgo_func$mjkdaEUHPtpOYlUrWGfnskhhvdyc7k9Fk-vwWj3VftE encoding/binary.(*littleEndian).Uint64 encoding/binary.littleEndian.Uint64 [InterfaceInfo] _llgo_iface$J1wM-rGcIPemx5jloXBmH7pUzUCSqpgNkOdb0QIFTxw: diff --git a/cl/_testmeta/interface_generic/meta-expect.txt b/cl/_testmeta/interface_generic/meta-expect.txt index 31a14b57ce..5303bdf9f6 100644 --- a/cl/_testmeta/interface_generic/meta-expect.txt +++ b/cl/_testmeta/interface_generic/meta-expect.txt @@ -18,25 +18,17 @@ _llgo_main.Box[int]: [OrdinaryEdges] *_llgo_func$ETeB8WwW04JEq0ztcm-XPTJtuYvtpkjIsAc0-2NT9zA: - __llgo_stub.github.com/goplus/llgo/runtime/internal/runtime.memequalptr _llgo_func$ETeB8WwW04JEq0ztcm-XPTJtuYvtpkjIsAc0-2NT9zA + github.com/goplus/llgo/runtime/internal/runtime.memequalptr *_llgo_iface$Jvxc0PCI_drlfK7S5npMGdZkQLeRkQ_x2e2CifPE6w8: - __llgo_stub.github.com/goplus/llgo/runtime/internal/runtime.memequalptr _llgo_iface$Jvxc0PCI_drlfK7S5npMGdZkQLeRkQ_x2e2CifPE6w8 + github.com/goplus/llgo/runtime/internal/runtime.memequalptr *_llgo_int: - __llgo_stub.github.com/goplus/llgo/runtime/internal/runtime.memequalptr _llgo_int + github.com/goplus/llgo/runtime/internal/runtime.memequalptr *_llgo_main.Box[int]: - __llgo_stub.github.com/goplus/llgo/runtime/internal/runtime.memequalptr _llgo_main.Box[int] -__llgo_stub.github.com/goplus/llgo/runtime/internal/runtime.interequal: - github.com/goplus/llgo/runtime/internal/runtime.interequal -__llgo_stub.github.com/goplus/llgo/runtime/internal/runtime.memequal64: - github.com/goplus/llgo/runtime/internal/runtime.memequal64 -__llgo_stub.github.com/goplus/llgo/runtime/internal/runtime.memequalptr: github.com/goplus/llgo/runtime/internal/runtime.memequalptr -__llgo_stub.main.(*Box[int]).Value: - main.(*Box[int]).Value _llgo_func$ETeB8WwW04JEq0ztcm-XPTJtuYvtpkjIsAc0-2NT9zA: *_llgo_func$ETeB8WwW04JEq0ztcm-XPTJtuYvtpkjIsAc0-2NT9zA _llgo_func$ETeB8WwW04JEq0ztcm-XPTJtuYvtpkjIsAc0-2NT9zA$out @@ -44,13 +36,13 @@ _llgo_func$ETeB8WwW04JEq0ztcm-XPTJtuYvtpkjIsAc0-2NT9zA$out: _llgo_int _llgo_iface$Jvxc0PCI_drlfK7S5npMGdZkQLeRkQ_x2e2CifPE6w8: *_llgo_iface$Jvxc0PCI_drlfK7S5npMGdZkQLeRkQ_x2e2CifPE6w8 - __llgo_stub.github.com/goplus/llgo/runtime/internal/runtime.interequal _llgo_iface$Jvxc0PCI_drlfK7S5npMGdZkQLeRkQ_x2e2CifPE6w8$imethods + github.com/goplus/llgo/runtime/internal/runtime.interequal _llgo_iface$Jvxc0PCI_drlfK7S5npMGdZkQLeRkQ_x2e2CifPE6w8$imethods: _llgo_func$ETeB8WwW04JEq0ztcm-XPTJtuYvtpkjIsAc0-2NT9zA _llgo_int: *_llgo_int - __llgo_stub.github.com/goplus/llgo/runtime/internal/runtime.memequal64 + github.com/goplus/llgo/runtime/internal/runtime.memequal64 _llgo_main.Box[int]: *_llgo_main.Box[int] github.com/goplus/llgo/cl/_testmeta/interface_generic.struct$lOhriNu2BrWBR2Mh8k-KggMYlAw0Wx-2ftE2_gNyubg$fields @@ -78,7 +70,7 @@ main.useInt: [MethodInfo] *_llgo_main.Box[int]: - 0 Value _llgo_func$ETeB8WwW04JEq0ztcm-XPTJtuYvtpkjIsAc0-2NT9zA main.(*Box[int]).Value __llgo_stub.main.(*Box[int]).Value + 0 Value _llgo_func$ETeB8WwW04JEq0ztcm-XPTJtuYvtpkjIsAc0-2NT9zA main.(*Box[int]).Value main.(*Box[int]).Value [InterfaceInfo] _llgo_iface$Jvxc0PCI_drlfK7S5npMGdZkQLeRkQ_x2e2CifPE6w8: diff --git a/cl/_testmeta/interface_generic_crosspkg/meta-expect.txt b/cl/_testmeta/interface_generic_crosspkg/meta-expect.txt index 98c89794a5..37605e8c23 100644 --- a/cl/_testmeta/interface_generic_crosspkg/meta-expect.txt +++ b/cl/_testmeta/interface_generic_crosspkg/meta-expect.txt @@ -32,42 +32,26 @@ _llgo_string: [OrdinaryEdges] *_llgo_func$ETeB8WwW04JEq0ztcm-XPTJtuYvtpkjIsAc0-2NT9zA: - __llgo_stub.github.com/goplus/llgo/runtime/internal/runtime.memequalptr _llgo_func$ETeB8WwW04JEq0ztcm-XPTJtuYvtpkjIsAc0-2NT9zA + github.com/goplus/llgo/runtime/internal/runtime.memequalptr *_llgo_func$zNDVRsWTIpUPKouNUS805RGX--IV9qVK8B31IZbg5to: - __llgo_stub.github.com/goplus/llgo/runtime/internal/runtime.memequalptr _llgo_func$zNDVRsWTIpUPKouNUS805RGX--IV9qVK8B31IZbg5to + github.com/goplus/llgo/runtime/internal/runtime.memequalptr *_llgo_github.com/goplus/llgo/cl/_testmeta/interface_generic_crosspkg/model.Box[int]: - __llgo_stub.github.com/goplus/llgo/runtime/internal/runtime.memequalptr _llgo_github.com/goplus/llgo/cl/_testmeta/interface_generic_crosspkg/model.Box[int] + github.com/goplus/llgo/runtime/internal/runtime.memequalptr *_llgo_github.com/goplus/llgo/cl/_testmeta/interface_generic_crosspkg/model.Box[string]: - __llgo_stub.github.com/goplus/llgo/runtime/internal/runtime.memequalptr _llgo_github.com/goplus/llgo/cl/_testmeta/interface_generic_crosspkg/model.Box[string] + github.com/goplus/llgo/runtime/internal/runtime.memequalptr *_llgo_iface$Jvxc0PCI_drlfK7S5npMGdZkQLeRkQ_x2e2CifPE6w8: - __llgo_stub.github.com/goplus/llgo/runtime/internal/runtime.memequalptr _llgo_iface$Jvxc0PCI_drlfK7S5npMGdZkQLeRkQ_x2e2CifPE6w8 + github.com/goplus/llgo/runtime/internal/runtime.memequalptr *_llgo_int: - __llgo_stub.github.com/goplus/llgo/runtime/internal/runtime.memequalptr _llgo_int + github.com/goplus/llgo/runtime/internal/runtime.memequalptr *_llgo_string: - __llgo_stub.github.com/goplus/llgo/runtime/internal/runtime.memequalptr _llgo_string -__llgo_stub.github.com/goplus/llgo/cl/_testmeta/interface_generic_crosspkg/model.(*Box[int]).Drop: - github.com/goplus/llgo/cl/_testmeta/interface_generic_crosspkg/model.(*Box[int]).Drop -__llgo_stub.github.com/goplus/llgo/cl/_testmeta/interface_generic_crosspkg/model.(*Box[int]).Value: - github.com/goplus/llgo/cl/_testmeta/interface_generic_crosspkg/model.(*Box[int]).Value -__llgo_stub.github.com/goplus/llgo/cl/_testmeta/interface_generic_crosspkg/model.(*Box[string]).Drop: - github.com/goplus/llgo/cl/_testmeta/interface_generic_crosspkg/model.(*Box[string]).Drop -__llgo_stub.github.com/goplus/llgo/cl/_testmeta/interface_generic_crosspkg/model.(*Box[string]).Value: - github.com/goplus/llgo/cl/_testmeta/interface_generic_crosspkg/model.(*Box[string]).Value -__llgo_stub.github.com/goplus/llgo/runtime/internal/runtime.interequal: - github.com/goplus/llgo/runtime/internal/runtime.interequal -__llgo_stub.github.com/goplus/llgo/runtime/internal/runtime.memequal64: - github.com/goplus/llgo/runtime/internal/runtime.memequal64 -__llgo_stub.github.com/goplus/llgo/runtime/internal/runtime.memequalptr: github.com/goplus/llgo/runtime/internal/runtime.memequalptr -__llgo_stub.github.com/goplus/llgo/runtime/internal/runtime.strequal: - github.com/goplus/llgo/runtime/internal/runtime.strequal _llgo_func$ETeB8WwW04JEq0ztcm-XPTJtuYvtpkjIsAc0-2NT9zA: *_llgo_func$ETeB8WwW04JEq0ztcm-XPTJtuYvtpkjIsAc0-2NT9zA _llgo_func$ETeB8WwW04JEq0ztcm-XPTJtuYvtpkjIsAc0-2NT9zA$out @@ -88,16 +72,16 @@ _llgo_github.com/goplus/llgo/cl/_testmeta/interface_generic_crosspkg/model.Box[s github.com/goplus/llgo/runtime/internal/runtime.structequal _llgo_iface$Jvxc0PCI_drlfK7S5npMGdZkQLeRkQ_x2e2CifPE6w8: *_llgo_iface$Jvxc0PCI_drlfK7S5npMGdZkQLeRkQ_x2e2CifPE6w8 - __llgo_stub.github.com/goplus/llgo/runtime/internal/runtime.interequal _llgo_iface$Jvxc0PCI_drlfK7S5npMGdZkQLeRkQ_x2e2CifPE6w8$imethods + github.com/goplus/llgo/runtime/internal/runtime.interequal _llgo_iface$Jvxc0PCI_drlfK7S5npMGdZkQLeRkQ_x2e2CifPE6w8$imethods: _llgo_func$ETeB8WwW04JEq0ztcm-XPTJtuYvtpkjIsAc0-2NT9zA _llgo_int: *_llgo_int - __llgo_stub.github.com/goplus/llgo/runtime/internal/runtime.memequal64 + github.com/goplus/llgo/runtime/internal/runtime.memequal64 _llgo_string: *_llgo_string - __llgo_stub.github.com/goplus/llgo/runtime/internal/runtime.strequal + github.com/goplus/llgo/runtime/internal/runtime.strequal github.com/goplus/llgo/cl/_testmeta/interface_generic_crosspkg/model.(*Box[int]).Drop: _llgo_string github.com/goplus/llgo/runtime/internal/runtime.AllocU @@ -138,9 +122,9 @@ main.main: [MethodInfo] *_llgo_github.com/goplus/llgo/cl/_testmeta/interface_generic_crosspkg/model.Box[int]: - 0 Drop _llgo_func$ETeB8WwW04JEq0ztcm-XPTJtuYvtpkjIsAc0-2NT9zA github.com/goplus/llgo/cl/_testmeta/interface_generic_crosspkg/model.(*Box[int]).Drop __llgo_stub.github.com/goplus/llgo/cl/_testmeta/interface_generic_crosspkg/model.(*Box[int]).Drop - 1 Value _llgo_func$ETeB8WwW04JEq0ztcm-XPTJtuYvtpkjIsAc0-2NT9zA github.com/goplus/llgo/cl/_testmeta/interface_generic_crosspkg/model.(*Box[int]).Value __llgo_stub.github.com/goplus/llgo/cl/_testmeta/interface_generic_crosspkg/model.(*Box[int]).Value + 0 Drop _llgo_func$ETeB8WwW04JEq0ztcm-XPTJtuYvtpkjIsAc0-2NT9zA github.com/goplus/llgo/cl/_testmeta/interface_generic_crosspkg/model.(*Box[int]).Drop github.com/goplus/llgo/cl/_testmeta/interface_generic_crosspkg/model.(*Box[int]).Drop + 1 Value _llgo_func$ETeB8WwW04JEq0ztcm-XPTJtuYvtpkjIsAc0-2NT9zA github.com/goplus/llgo/cl/_testmeta/interface_generic_crosspkg/model.(*Box[int]).Value github.com/goplus/llgo/cl/_testmeta/interface_generic_crosspkg/model.(*Box[int]).Value *_llgo_github.com/goplus/llgo/cl/_testmeta/interface_generic_crosspkg/model.Box[string]: - 0 Drop _llgo_func$zNDVRsWTIpUPKouNUS805RGX--IV9qVK8B31IZbg5to github.com/goplus/llgo/cl/_testmeta/interface_generic_crosspkg/model.(*Box[string]).Drop __llgo_stub.github.com/goplus/llgo/cl/_testmeta/interface_generic_crosspkg/model.(*Box[string]).Drop - 1 Value _llgo_func$zNDVRsWTIpUPKouNUS805RGX--IV9qVK8B31IZbg5to github.com/goplus/llgo/cl/_testmeta/interface_generic_crosspkg/model.(*Box[string]).Value __llgo_stub.github.com/goplus/llgo/cl/_testmeta/interface_generic_crosspkg/model.(*Box[string]).Value + 0 Drop _llgo_func$zNDVRsWTIpUPKouNUS805RGX--IV9qVK8B31IZbg5to github.com/goplus/llgo/cl/_testmeta/interface_generic_crosspkg/model.(*Box[string]).Drop github.com/goplus/llgo/cl/_testmeta/interface_generic_crosspkg/model.(*Box[string]).Drop + 1 Value _llgo_func$zNDVRsWTIpUPKouNUS805RGX--IV9qVK8B31IZbg5to github.com/goplus/llgo/cl/_testmeta/interface_generic_crosspkg/model.(*Box[string]).Value github.com/goplus/llgo/cl/_testmeta/interface_generic_crosspkg/model.(*Box[string]).Value diff --git a/cl/_testmeta/interface_imported/meta-expect.txt b/cl/_testmeta/interface_imported/meta-expect.txt index 9c6bbe94ec..0d06c70bfc 100644 --- a/cl/_testmeta/interface_imported/meta-expect.txt +++ b/cl/_testmeta/interface_imported/meta-expect.txt @@ -45,61 +45,41 @@ _llgo_uint8: [OrdinaryEdges] *[]_llgo_uint8: []_llgo_uint8 - __llgo_stub.github.com/goplus/llgo/runtime/internal/runtime.memequalptr + github.com/goplus/llgo/runtime/internal/runtime.memequalptr *_llgo_error: - __llgo_stub.github.com/goplus/llgo/runtime/internal/runtime.memequalptr _llgo_error + github.com/goplus/llgo/runtime/internal/runtime.memequalptr *_llgo_func$8rsrSd_r3UHd_2DiYTyaOKR7BYkei4zw5ysG35KF38w: - __llgo_stub.github.com/goplus/llgo/runtime/internal/runtime.memequalptr _llgo_func$8rsrSd_r3UHd_2DiYTyaOKR7BYkei4zw5ysG35KF38w + github.com/goplus/llgo/runtime/internal/runtime.memequalptr *_llgo_func$G2hch9Iy9DrhKKsg70PbL54bK-XSl-1IUUORN17J2Dk: - __llgo_stub.github.com/goplus/llgo/runtime/internal/runtime.memequalptr _llgo_func$G2hch9Iy9DrhKKsg70PbL54bK-XSl-1IUUORN17J2Dk + github.com/goplus/llgo/runtime/internal/runtime.memequalptr *_llgo_func$zNDVRsWTIpUPKouNUS805RGX--IV9qVK8B31IZbg5to: - __llgo_stub.github.com/goplus/llgo/runtime/internal/runtime.memequalptr _llgo_func$zNDVRsWTIpUPKouNUS805RGX--IV9qVK8B31IZbg5to + github.com/goplus/llgo/runtime/internal/runtime.memequalptr *_llgo_github.com/goplus/llgo/cl/_testmeta/interface_imported/api.Source: - __llgo_stub.github.com/goplus/llgo/runtime/internal/runtime.memequalptr _llgo_github.com/goplus/llgo/cl/_testmeta/interface_imported/api.Source + github.com/goplus/llgo/runtime/internal/runtime.memequalptr *_llgo_iface$uycIKA3bbxRhudEjW1hHKWKdLqHQsCVy8NdW1bkQmNw: - __llgo_stub.github.com/goplus/llgo/runtime/internal/runtime.memequalptr _llgo_iface$uycIKA3bbxRhudEjW1hHKWKdLqHQsCVy8NdW1bkQmNw + github.com/goplus/llgo/runtime/internal/runtime.memequalptr *_llgo_int: - __llgo_stub.github.com/goplus/llgo/runtime/internal/runtime.memequalptr _llgo_int + github.com/goplus/llgo/runtime/internal/runtime.memequalptr *_llgo_string: - __llgo_stub.github.com/goplus/llgo/runtime/internal/runtime.memequalptr _llgo_string + github.com/goplus/llgo/runtime/internal/runtime.memequalptr *_llgo_uint8: - __llgo_stub.github.com/goplus/llgo/runtime/internal/runtime.memequalptr _llgo_uint8 + github.com/goplus/llgo/runtime/internal/runtime.memequalptr []_llgo_uint8: *[]_llgo_uint8 _llgo_uint8 -__llgo_stub.github.com/goplus/llgo/cl/_testmeta/interface_imported/api.(*Source).Close: - github.com/goplus/llgo/cl/_testmeta/interface_imported/api.(*Source).Close -__llgo_stub.github.com/goplus/llgo/cl/_testmeta/interface_imported/api.(*Source).Read: - github.com/goplus/llgo/cl/_testmeta/interface_imported/api.(*Source).Read -__llgo_stub.github.com/goplus/llgo/cl/_testmeta/interface_imported/api.Source.Close: - github.com/goplus/llgo/cl/_testmeta/interface_imported/api.Source.Close -__llgo_stub.github.com/goplus/llgo/cl/_testmeta/interface_imported/api.Source.Read: - github.com/goplus/llgo/cl/_testmeta/interface_imported/api.Source.Read -__llgo_stub.github.com/goplus/llgo/runtime/internal/runtime.interequal: - github.com/goplus/llgo/runtime/internal/runtime.interequal -__llgo_stub.github.com/goplus/llgo/runtime/internal/runtime.memequal0: - github.com/goplus/llgo/runtime/internal/runtime.memequal0 -__llgo_stub.github.com/goplus/llgo/runtime/internal/runtime.memequal64: - github.com/goplus/llgo/runtime/internal/runtime.memequal64 -__llgo_stub.github.com/goplus/llgo/runtime/internal/runtime.memequal8: - github.com/goplus/llgo/runtime/internal/runtime.memequal8 -__llgo_stub.github.com/goplus/llgo/runtime/internal/runtime.memequalptr: - github.com/goplus/llgo/runtime/internal/runtime.memequalptr -__llgo_stub.github.com/goplus/llgo/runtime/internal/runtime.strequal: - github.com/goplus/llgo/runtime/internal/runtime.strequal _llgo_error: *_llgo_error - __llgo_stub.github.com/goplus/llgo/runtime/internal/runtime.interequal _llgo_iface$Fh8eUJ-Gw4e6TYuajcFIOSCuqSPKAt5nS4ow7xeGXEU$imethods + github.com/goplus/llgo/runtime/internal/runtime.interequal _llgo_func$8rsrSd_r3UHd_2DiYTyaOKR7BYkei4zw5ysG35KF38w: *_llgo_func$8rsrSd_r3UHd_2DiYTyaOKR7BYkei4zw5ysG35KF38w _llgo_func$8rsrSd_r3UHd_2DiYTyaOKR7BYkei4zw5ysG35KF38w$out @@ -121,24 +101,24 @@ _llgo_func$zNDVRsWTIpUPKouNUS805RGX--IV9qVK8B31IZbg5to$out: _llgo_string _llgo_github.com/goplus/llgo/cl/_testmeta/interface_imported/api.Source: *_llgo_github.com/goplus/llgo/cl/_testmeta/interface_imported/api.Source - __llgo_stub.github.com/goplus/llgo/runtime/internal/runtime.memequal0 + github.com/goplus/llgo/runtime/internal/runtime.memequal0 _llgo_iface$Fh8eUJ-Gw4e6TYuajcFIOSCuqSPKAt5nS4ow7xeGXEU$imethods: _llgo_func$zNDVRsWTIpUPKouNUS805RGX--IV9qVK8B31IZbg5to _llgo_iface$uycIKA3bbxRhudEjW1hHKWKdLqHQsCVy8NdW1bkQmNw: *_llgo_iface$uycIKA3bbxRhudEjW1hHKWKdLqHQsCVy8NdW1bkQmNw - __llgo_stub.github.com/goplus/llgo/runtime/internal/runtime.interequal _llgo_iface$uycIKA3bbxRhudEjW1hHKWKdLqHQsCVy8NdW1bkQmNw$imethods + github.com/goplus/llgo/runtime/internal/runtime.interequal _llgo_iface$uycIKA3bbxRhudEjW1hHKWKdLqHQsCVy8NdW1bkQmNw$imethods: _llgo_func$G2hch9Iy9DrhKKsg70PbL54bK-XSl-1IUUORN17J2Dk _llgo_int: *_llgo_int - __llgo_stub.github.com/goplus/llgo/runtime/internal/runtime.memequal64 + github.com/goplus/llgo/runtime/internal/runtime.memequal64 _llgo_string: *_llgo_string - __llgo_stub.github.com/goplus/llgo/runtime/internal/runtime.strequal + github.com/goplus/llgo/runtime/internal/runtime.strequal _llgo_uint8: *_llgo_uint8 - __llgo_stub.github.com/goplus/llgo/runtime/internal/runtime.memequal8 + github.com/goplus/llgo/runtime/internal/runtime.memequal8 main.init: github.com/goplus/llgo/cl/_testmeta/interface_imported/api.init main.init$guard @@ -161,11 +141,11 @@ main.use: [MethodInfo] *_llgo_github.com/goplus/llgo/cl/_testmeta/interface_imported/api.Source: - 0 Close _llgo_func$8rsrSd_r3UHd_2DiYTyaOKR7BYkei4zw5ysG35KF38w github.com/goplus/llgo/cl/_testmeta/interface_imported/api.(*Source).Close __llgo_stub.github.com/goplus/llgo/cl/_testmeta/interface_imported/api.(*Source).Close - 1 Read _llgo_func$G2hch9Iy9DrhKKsg70PbL54bK-XSl-1IUUORN17J2Dk github.com/goplus/llgo/cl/_testmeta/interface_imported/api.(*Source).Read __llgo_stub.github.com/goplus/llgo/cl/_testmeta/interface_imported/api.(*Source).Read + 0 Close _llgo_func$8rsrSd_r3UHd_2DiYTyaOKR7BYkei4zw5ysG35KF38w github.com/goplus/llgo/cl/_testmeta/interface_imported/api.(*Source).Close github.com/goplus/llgo/cl/_testmeta/interface_imported/api.(*Source).Close + 1 Read _llgo_func$G2hch9Iy9DrhKKsg70PbL54bK-XSl-1IUUORN17J2Dk github.com/goplus/llgo/cl/_testmeta/interface_imported/api.(*Source).Read github.com/goplus/llgo/cl/_testmeta/interface_imported/api.(*Source).Read _llgo_github.com/goplus/llgo/cl/_testmeta/interface_imported/api.Source: - 0 Close _llgo_func$8rsrSd_r3UHd_2DiYTyaOKR7BYkei4zw5ysG35KF38w github.com/goplus/llgo/cl/_testmeta/interface_imported/api.(*Source).Close __llgo_stub.github.com/goplus/llgo/cl/_testmeta/interface_imported/api.Source.Close - 1 Read _llgo_func$G2hch9Iy9DrhKKsg70PbL54bK-XSl-1IUUORN17J2Dk github.com/goplus/llgo/cl/_testmeta/interface_imported/api.(*Source).Read __llgo_stub.github.com/goplus/llgo/cl/_testmeta/interface_imported/api.Source.Read + 0 Close _llgo_func$8rsrSd_r3UHd_2DiYTyaOKR7BYkei4zw5ysG35KF38w github.com/goplus/llgo/cl/_testmeta/interface_imported/api.(*Source).Close github.com/goplus/llgo/cl/_testmeta/interface_imported/api.Source.Close + 1 Read _llgo_func$G2hch9Iy9DrhKKsg70PbL54bK-XSl-1IUUORN17J2Dk github.com/goplus/llgo/cl/_testmeta/interface_imported/api.(*Source).Read github.com/goplus/llgo/cl/_testmeta/interface_imported/api.Source.Read [InterfaceInfo] _llgo_iface$uycIKA3bbxRhudEjW1hHKWKdLqHQsCVy8NdW1bkQmNw: diff --git a/cl/_testmeta/interface_named/meta-expect.txt b/cl/_testmeta/interface_named/meta-expect.txt index 156ce8ac43..1eca6ed529 100644 --- a/cl/_testmeta/interface_named/meta-expect.txt +++ b/cl/_testmeta/interface_named/meta-expect.txt @@ -12,35 +12,25 @@ _llgo_main.T: [OrdinaryEdges] *_llgo_func$2_iS07vIlF2_rZqWB5eU0IvP_9HviM4MYZNkXZDvbac: - __llgo_stub.github.com/goplus/llgo/runtime/internal/runtime.memequalptr _llgo_func$2_iS07vIlF2_rZqWB5eU0IvP_9HviM4MYZNkXZDvbac + github.com/goplus/llgo/runtime/internal/runtime.memequalptr *_llgo_iface$anEWstLioBmxcO9rxTXClbAzDIEQLw2tApwq0mcSt88: - __llgo_stub.github.com/goplus/llgo/runtime/internal/runtime.memequalptr _llgo_iface$anEWstLioBmxcO9rxTXClbAzDIEQLw2tApwq0mcSt88 + github.com/goplus/llgo/runtime/internal/runtime.memequalptr *_llgo_main.T: - __llgo_stub.github.com/goplus/llgo/runtime/internal/runtime.memequalptr _llgo_main.T -__llgo_stub.github.com/goplus/llgo/runtime/internal/runtime.interequal: - github.com/goplus/llgo/runtime/internal/runtime.interequal -__llgo_stub.github.com/goplus/llgo/runtime/internal/runtime.memequal0: - github.com/goplus/llgo/runtime/internal/runtime.memequal0 -__llgo_stub.github.com/goplus/llgo/runtime/internal/runtime.memequalptr: github.com/goplus/llgo/runtime/internal/runtime.memequalptr -__llgo_stub.main.(*T).M: - main.(*T).M -__llgo_stub.main.T.M: - main.T.M _llgo_func$2_iS07vIlF2_rZqWB5eU0IvP_9HviM4MYZNkXZDvbac: *_llgo_func$2_iS07vIlF2_rZqWB5eU0IvP_9HviM4MYZNkXZDvbac _llgo_iface$anEWstLioBmxcO9rxTXClbAzDIEQLw2tApwq0mcSt88: *_llgo_iface$anEWstLioBmxcO9rxTXClbAzDIEQLw2tApwq0mcSt88 - __llgo_stub.github.com/goplus/llgo/runtime/internal/runtime.interequal _llgo_iface$anEWstLioBmxcO9rxTXClbAzDIEQLw2tApwq0mcSt88$imethods + github.com/goplus/llgo/runtime/internal/runtime.interequal _llgo_iface$anEWstLioBmxcO9rxTXClbAzDIEQLw2tApwq0mcSt88$imethods: _llgo_func$2_iS07vIlF2_rZqWB5eU0IvP_9HviM4MYZNkXZDvbac _llgo_main.T: *_llgo_main.T - __llgo_stub.github.com/goplus/llgo/runtime/internal/runtime.memequal0 + github.com/goplus/llgo/runtime/internal/runtime.memequal0 main.(*T).M: github.com/goplus/llgo/runtime/internal/runtime.AssertNilDeref github.com/goplus/llgo/runtime/internal/runtime.PanicWrapNilPointer @@ -66,9 +56,9 @@ main.use: [MethodInfo] *_llgo_main.T: - 0 M _llgo_func$2_iS07vIlF2_rZqWB5eU0IvP_9HviM4MYZNkXZDvbac main.(*T).M __llgo_stub.main.(*T).M + 0 M _llgo_func$2_iS07vIlF2_rZqWB5eU0IvP_9HviM4MYZNkXZDvbac main.(*T).M main.(*T).M _llgo_main.T: - 0 M _llgo_func$2_iS07vIlF2_rZqWB5eU0IvP_9HviM4MYZNkXZDvbac main.(*T).M __llgo_stub.main.T.M + 0 M _llgo_func$2_iS07vIlF2_rZqWB5eU0IvP_9HviM4MYZNkXZDvbac main.(*T).M main.T.M [InterfaceInfo] _llgo_iface$anEWstLioBmxcO9rxTXClbAzDIEQLw2tApwq0mcSt88: diff --git a/cl/_testmeta/interface_unexported/meta-expect.txt b/cl/_testmeta/interface_unexported/meta-expect.txt index 343c0c4c81..ccdf02bfb2 100644 --- a/cl/_testmeta/interface_unexported/meta-expect.txt +++ b/cl/_testmeta/interface_unexported/meta-expect.txt @@ -12,33 +12,23 @@ _llgo_main.T: [OrdinaryEdges] *_llgo_func$2_iS07vIlF2_rZqWB5eU0IvP_9HviM4MYZNkXZDvbac: - __llgo_stub.github.com/goplus/llgo/runtime/internal/runtime.memequalptr _llgo_func$2_iS07vIlF2_rZqWB5eU0IvP_9HviM4MYZNkXZDvbac + github.com/goplus/llgo/runtime/internal/runtime.memequalptr *_llgo_main.T: - __llgo_stub.github.com/goplus/llgo/runtime/internal/runtime.memequalptr _llgo_main.T + github.com/goplus/llgo/runtime/internal/runtime.memequalptr *github.com/goplus/llgo/cl/_testmeta/interface_unexported.iface$SE5y-KS93u1u9p1qAf9LRB1hncS44rJIq27_JZbIQVo: - __llgo_stub.github.com/goplus/llgo/runtime/internal/runtime.memequalptr github.com/goplus/llgo/cl/_testmeta/interface_unexported.iface$SE5y-KS93u1u9p1qAf9LRB1hncS44rJIq27_JZbIQVo -__llgo_stub.github.com/goplus/llgo/runtime/internal/runtime.interequal: - github.com/goplus/llgo/runtime/internal/runtime.interequal -__llgo_stub.github.com/goplus/llgo/runtime/internal/runtime.memequal0: - github.com/goplus/llgo/runtime/internal/runtime.memequal0 -__llgo_stub.github.com/goplus/llgo/runtime/internal/runtime.memequalptr: github.com/goplus/llgo/runtime/internal/runtime.memequalptr -__llgo_stub.main.(*T).m: - main.(*T).m -__llgo_stub.main.T.m: - main.T.m _llgo_func$2_iS07vIlF2_rZqWB5eU0IvP_9HviM4MYZNkXZDvbac: *_llgo_func$2_iS07vIlF2_rZqWB5eU0IvP_9HviM4MYZNkXZDvbac _llgo_main.T: *_llgo_main.T - __llgo_stub.github.com/goplus/llgo/runtime/internal/runtime.memequal0 + github.com/goplus/llgo/runtime/internal/runtime.memequal0 github.com/goplus/llgo/cl/_testmeta/interface_unexported.iface$SE5y-KS93u1u9p1qAf9LRB1hncS44rJIq27_JZbIQVo: *github.com/goplus/llgo/cl/_testmeta/interface_unexported.iface$SE5y-KS93u1u9p1qAf9LRB1hncS44rJIq27_JZbIQVo - __llgo_stub.github.com/goplus/llgo/runtime/internal/runtime.interequal github.com/goplus/llgo/cl/_testmeta/interface_unexported.iface$SE5y-KS93u1u9p1qAf9LRB1hncS44rJIq27_JZbIQVo$imethods + github.com/goplus/llgo/runtime/internal/runtime.interequal github.com/goplus/llgo/cl/_testmeta/interface_unexported.iface$SE5y-KS93u1u9p1qAf9LRB1hncS44rJIq27_JZbIQVo$imethods: _llgo_func$2_iS07vIlF2_rZqWB5eU0IvP_9HviM4MYZNkXZDvbac main.(*T).m: @@ -66,9 +56,9 @@ main.use: [MethodInfo] *_llgo_main.T: - 0 main.m _llgo_func$2_iS07vIlF2_rZqWB5eU0IvP_9HviM4MYZNkXZDvbac main.(*T).m __llgo_stub.main.(*T).m + 0 main.m _llgo_func$2_iS07vIlF2_rZqWB5eU0IvP_9HviM4MYZNkXZDvbac main.(*T).m main.(*T).m _llgo_main.T: - 0 main.m _llgo_func$2_iS07vIlF2_rZqWB5eU0IvP_9HviM4MYZNkXZDvbac main.(*T).m __llgo_stub.main.T.m + 0 main.m _llgo_func$2_iS07vIlF2_rZqWB5eU0IvP_9HviM4MYZNkXZDvbac main.(*T).m main.T.m [InterfaceInfo] github.com/goplus/llgo/cl/_testmeta/interface_unexported.iface$SE5y-KS93u1u9p1qAf9LRB1hncS44rJIq27_JZbIQVo: diff --git a/cl/_testmeta/methodinfo_imported/meta-expect.txt b/cl/_testmeta/methodinfo_imported/meta-expect.txt index 85035b0228..3776000c2d 100644 --- a/cl/_testmeta/methodinfo_imported/meta-expect.txt +++ b/cl/_testmeta/methodinfo_imported/meta-expect.txt @@ -177,190 +177,122 @@ _llgo_uint8: [OrdinaryEdges] *[]_llgo_uint8: []_llgo_uint8 - __llgo_stub.github.com/goplus/llgo/runtime/internal/runtime.memequalptr + github.com/goplus/llgo/runtime/internal/runtime.memequalptr *_llgo_bool: - __llgo_stub.github.com/goplus/llgo/runtime/internal/runtime.memequalptr _llgo_bool + github.com/goplus/llgo/runtime/internal/runtime.memequalptr *_llgo_bytes.Buffer: - __llgo_stub.github.com/goplus/llgo/runtime/internal/runtime.memequalptr _llgo_bytes.Buffer + github.com/goplus/llgo/runtime/internal/runtime.memequalptr *_llgo_bytes.readOp: - __llgo_stub.github.com/goplus/llgo/runtime/internal/runtime.memequalptr _llgo_bytes.readOp + github.com/goplus/llgo/runtime/internal/runtime.memequalptr *_llgo_error: - __llgo_stub.github.com/goplus/llgo/runtime/internal/runtime.memequalptr _llgo_error + github.com/goplus/llgo/runtime/internal/runtime.memequalptr *_llgo_func$2_iS07vIlF2_rZqWB5eU0IvP_9HviM4MYZNkXZDvbac: - __llgo_stub.github.com/goplus/llgo/runtime/internal/runtime.memequalptr _llgo_func$2_iS07vIlF2_rZqWB5eU0IvP_9HviM4MYZNkXZDvbac + github.com/goplus/llgo/runtime/internal/runtime.memequalptr *_llgo_func$8rsrSd_r3UHd_2DiYTyaOKR7BYkei4zw5ysG35KF38w: - __llgo_stub.github.com/goplus/llgo/runtime/internal/runtime.memequalptr _llgo_func$8rsrSd_r3UHd_2DiYTyaOKR7BYkei4zw5ysG35KF38w + github.com/goplus/llgo/runtime/internal/runtime.memequalptr *_llgo_func$ETeB8WwW04JEq0ztcm-XPTJtuYvtpkjIsAc0-2NT9zA: - __llgo_stub.github.com/goplus/llgo/runtime/internal/runtime.memequalptr _llgo_func$ETeB8WwW04JEq0ztcm-XPTJtuYvtpkjIsAc0-2NT9zA + github.com/goplus/llgo/runtime/internal/runtime.memequalptr *_llgo_func$G2hch9Iy9DrhKKsg70PbL54bK-XSl-1IUUORN17J2Dk: - __llgo_stub.github.com/goplus/llgo/runtime/internal/runtime.memequalptr _llgo_func$G2hch9Iy9DrhKKsg70PbL54bK-XSl-1IUUORN17J2Dk + github.com/goplus/llgo/runtime/internal/runtime.memequalptr *_llgo_func$TBlCn7YTQdraI1HMiBWmkrqIGG-8UgD1UVyJy62Z_0o: - __llgo_stub.github.com/goplus/llgo/runtime/internal/runtime.memequalptr _llgo_func$TBlCn7YTQdraI1HMiBWmkrqIGG-8UgD1UVyJy62Z_0o + github.com/goplus/llgo/runtime/internal/runtime.memequalptr *_llgo_func$VZ-8VPNF1RaLICwxc1Ghn7BbgyFX3v762OCdx127EkA: - __llgo_stub.github.com/goplus/llgo/runtime/internal/runtime.memequalptr _llgo_func$VZ-8VPNF1RaLICwxc1Ghn7BbgyFX3v762OCdx127EkA + github.com/goplus/llgo/runtime/internal/runtime.memequalptr *_llgo_func$YHeRw3AOvQtzv982-ZO3Yn8vh3Fx89RM3VvI8E4iKVk: - __llgo_stub.github.com/goplus/llgo/runtime/internal/runtime.memequalptr _llgo_func$YHeRw3AOvQtzv982-ZO3Yn8vh3Fx89RM3VvI8E4iKVk + github.com/goplus/llgo/runtime/internal/runtime.memequalptr *_llgo_func$Z_-7GWzB37LCYRTQLsSYmEihg_hqBK8o_GbT88pqnPY: - __llgo_stub.github.com/goplus/llgo/runtime/internal/runtime.memequalptr _llgo_func$Z_-7GWzB37LCYRTQLsSYmEihg_hqBK8o_GbT88pqnPY + github.com/goplus/llgo/runtime/internal/runtime.memequalptr *_llgo_func$aJkaU3jhXr0Q2QraTe2_TTdupeMMW2MD66UwBxynRM0: - __llgo_stub.github.com/goplus/llgo/runtime/internal/runtime.memequalptr _llgo_func$aJkaU3jhXr0Q2QraTe2_TTdupeMMW2MD66UwBxynRM0 + github.com/goplus/llgo/runtime/internal/runtime.memequalptr *_llgo_func$c8Vvy7bpifdsF4PDKWnpU2KNuhLPRr7XBIDM-4p45sQ: - __llgo_stub.github.com/goplus/llgo/runtime/internal/runtime.memequalptr _llgo_func$c8Vvy7bpifdsF4PDKWnpU2KNuhLPRr7XBIDM-4p45sQ + github.com/goplus/llgo/runtime/internal/runtime.memequalptr *_llgo_func$d4kMA_oCkLwnd1j8nVlv1hwRarEVuCIrDCpnHhDz9UY: - __llgo_stub.github.com/goplus/llgo/runtime/internal/runtime.memequalptr _llgo_func$d4kMA_oCkLwnd1j8nVlv1hwRarEVuCIrDCpnHhDz9UY + github.com/goplus/llgo/runtime/internal/runtime.memequalptr *_llgo_func$ekGNsrYBSzltfAjxbl6T8H6Yq8j16wzqS3nDj2xxGMU: - __llgo_stub.github.com/goplus/llgo/runtime/internal/runtime.memequalptr _llgo_func$ekGNsrYBSzltfAjxbl6T8H6Yq8j16wzqS3nDj2xxGMU + github.com/goplus/llgo/runtime/internal/runtime.memequalptr *_llgo_func$lukqSsfDYBoIp_R8GMojGkZnrYDqaq2iHn8RkCjW7iQ: - __llgo_stub.github.com/goplus/llgo/runtime/internal/runtime.memequalptr _llgo_func$lukqSsfDYBoIp_R8GMojGkZnrYDqaq2iHn8RkCjW7iQ + github.com/goplus/llgo/runtime/internal/runtime.memequalptr *_llgo_func$q-bw-_pPYBCXnr1TXIF8sOD4fVVzzIlpHqD-A13AB4Y: - __llgo_stub.github.com/goplus/llgo/runtime/internal/runtime.memequalptr _llgo_func$q-bw-_pPYBCXnr1TXIF8sOD4fVVzzIlpHqD-A13AB4Y + github.com/goplus/llgo/runtime/internal/runtime.memequalptr *_llgo_func$qVJ5SH6qhXP_h0AM41vpBGzQEMp-fQIfvwQEJy5NI8M: - __llgo_stub.github.com/goplus/llgo/runtime/internal/runtime.memequalptr _llgo_func$qVJ5SH6qhXP_h0AM41vpBGzQEMp-fQIfvwQEJy5NI8M + github.com/goplus/llgo/runtime/internal/runtime.memequalptr *_llgo_func$thH5FBpdXzJNnCpSfiLU5ItTntFU6LWp0RJhDm2XJjw: - __llgo_stub.github.com/goplus/llgo/runtime/internal/runtime.memequalptr _llgo_func$thH5FBpdXzJNnCpSfiLU5ItTntFU6LWp0RJhDm2XJjw + github.com/goplus/llgo/runtime/internal/runtime.memequalptr *_llgo_func$uVmBDI0DMcrui3Q9y-g_hbtVN8JckQ18V2wmO5_G7A8: - __llgo_stub.github.com/goplus/llgo/runtime/internal/runtime.memequalptr _llgo_func$uVmBDI0DMcrui3Q9y-g_hbtVN8JckQ18V2wmO5_G7A8 + github.com/goplus/llgo/runtime/internal/runtime.memequalptr *_llgo_func$uf8yw1UkUdbDuCneSpNKIq_NThWIEVE7f1IYfJGz_bw: - __llgo_stub.github.com/goplus/llgo/runtime/internal/runtime.memequalptr _llgo_func$uf8yw1UkUdbDuCneSpNKIq_NThWIEVE7f1IYfJGz_bw + github.com/goplus/llgo/runtime/internal/runtime.memequalptr *_llgo_func$vSv85k0UY6JWccAc3T-lvdCx9J-4GM-oZC9zGLrxW1M: - __llgo_stub.github.com/goplus/llgo/runtime/internal/runtime.memequalptr _llgo_func$vSv85k0UY6JWccAc3T-lvdCx9J-4GM-oZC9zGLrxW1M + github.com/goplus/llgo/runtime/internal/runtime.memequalptr *_llgo_func$w4tN9iibS_UimF5vLUWoKP0uAk2tJZF26VqETo_8LVg: - __llgo_stub.github.com/goplus/llgo/runtime/internal/runtime.memequalptr _llgo_func$w4tN9iibS_UimF5vLUWoKP0uAk2tJZF26VqETo_8LVg + github.com/goplus/llgo/runtime/internal/runtime.memequalptr *_llgo_func$zNDVRsWTIpUPKouNUS805RGX--IV9qVK8B31IZbg5to: - __llgo_stub.github.com/goplus/llgo/runtime/internal/runtime.memequalptr _llgo_func$zNDVRsWTIpUPKouNUS805RGX--IV9qVK8B31IZbg5to + github.com/goplus/llgo/runtime/internal/runtime.memequalptr *_llgo_iface$uycIKA3bbxRhudEjW1hHKWKdLqHQsCVy8NdW1bkQmNw: - __llgo_stub.github.com/goplus/llgo/runtime/internal/runtime.memequalptr _llgo_iface$uycIKA3bbxRhudEjW1hHKWKdLqHQsCVy8NdW1bkQmNw + github.com/goplus/llgo/runtime/internal/runtime.memequalptr *_llgo_int: - __llgo_stub.github.com/goplus/llgo/runtime/internal/runtime.memequalptr _llgo_int + github.com/goplus/llgo/runtime/internal/runtime.memequalptr *_llgo_int32: - __llgo_stub.github.com/goplus/llgo/runtime/internal/runtime.memequalptr _llgo_int32 + github.com/goplus/llgo/runtime/internal/runtime.memequalptr *_llgo_int64: - __llgo_stub.github.com/goplus/llgo/runtime/internal/runtime.memequalptr _llgo_int64 + github.com/goplus/llgo/runtime/internal/runtime.memequalptr *_llgo_io.Reader: - __llgo_stub.github.com/goplus/llgo/runtime/internal/runtime.memequalptr _llgo_io.Reader + github.com/goplus/llgo/runtime/internal/runtime.memequalptr *_llgo_io.Writer: - __llgo_stub.github.com/goplus/llgo/runtime/internal/runtime.memequalptr _llgo_io.Writer + github.com/goplus/llgo/runtime/internal/runtime.memequalptr *_llgo_string: - __llgo_stub.github.com/goplus/llgo/runtime/internal/runtime.memequalptr _llgo_string + github.com/goplus/llgo/runtime/internal/runtime.memequalptr *_llgo_uint8: - __llgo_stub.github.com/goplus/llgo/runtime/internal/runtime.memequalptr _llgo_uint8 + github.com/goplus/llgo/runtime/internal/runtime.memequalptr []_llgo_uint8: *[]_llgo_uint8 _llgo_uint8 -__llgo_stub.bytes.(*Buffer).Available: - bytes.(*Buffer).Available -__llgo_stub.bytes.(*Buffer).AvailableBuffer: - bytes.(*Buffer).AvailableBuffer -__llgo_stub.bytes.(*Buffer).Bytes: - bytes.(*Buffer).Bytes -__llgo_stub.bytes.(*Buffer).Cap: - bytes.(*Buffer).Cap -__llgo_stub.bytes.(*Buffer).Grow: - bytes.(*Buffer).Grow -__llgo_stub.bytes.(*Buffer).Len: - bytes.(*Buffer).Len -__llgo_stub.bytes.(*Buffer).Next: - bytes.(*Buffer).Next -__llgo_stub.bytes.(*Buffer).Peek: - bytes.(*Buffer).Peek -__llgo_stub.bytes.(*Buffer).Read: - bytes.(*Buffer).Read -__llgo_stub.bytes.(*Buffer).ReadByte: - bytes.(*Buffer).ReadByte -__llgo_stub.bytes.(*Buffer).ReadBytes: - bytes.(*Buffer).ReadBytes -__llgo_stub.bytes.(*Buffer).ReadFrom: - bytes.(*Buffer).ReadFrom -__llgo_stub.bytes.(*Buffer).ReadRune: - bytes.(*Buffer).ReadRune -__llgo_stub.bytes.(*Buffer).ReadString: - bytes.(*Buffer).ReadString -__llgo_stub.bytes.(*Buffer).Reset: - bytes.(*Buffer).Reset -__llgo_stub.bytes.(*Buffer).String: - bytes.(*Buffer).String -__llgo_stub.bytes.(*Buffer).Truncate: - bytes.(*Buffer).Truncate -__llgo_stub.bytes.(*Buffer).UnreadByte: - bytes.(*Buffer).UnreadByte -__llgo_stub.bytes.(*Buffer).UnreadRune: - bytes.(*Buffer).UnreadRune -__llgo_stub.bytes.(*Buffer).Write: - bytes.(*Buffer).Write -__llgo_stub.bytes.(*Buffer).WriteByte: - bytes.(*Buffer).WriteByte -__llgo_stub.bytes.(*Buffer).WriteRune: - bytes.(*Buffer).WriteRune -__llgo_stub.bytes.(*Buffer).WriteString: - bytes.(*Buffer).WriteString -__llgo_stub.bytes.(*Buffer).WriteTo: - bytes.(*Buffer).WriteTo -__llgo_stub.bytes.(*Buffer).empty: - bytes.(*Buffer).empty -__llgo_stub.bytes.(*Buffer).grow: - bytes.(*Buffer).grow -__llgo_stub.bytes.(*Buffer).readSlice: - bytes.(*Buffer).readSlice -__llgo_stub.bytes.(*Buffer).tryGrowByReslice: - bytes.(*Buffer).tryGrowByReslice -__llgo_stub.github.com/goplus/llgo/runtime/internal/runtime.interequal: - github.com/goplus/llgo/runtime/internal/runtime.interequal -__llgo_stub.github.com/goplus/llgo/runtime/internal/runtime.memequal32: - github.com/goplus/llgo/runtime/internal/runtime.memequal32 -__llgo_stub.github.com/goplus/llgo/runtime/internal/runtime.memequal64: - github.com/goplus/llgo/runtime/internal/runtime.memequal64 -__llgo_stub.github.com/goplus/llgo/runtime/internal/runtime.memequal8: - github.com/goplus/llgo/runtime/internal/runtime.memequal8 -__llgo_stub.github.com/goplus/llgo/runtime/internal/runtime.memequalptr: - github.com/goplus/llgo/runtime/internal/runtime.memequalptr -__llgo_stub.github.com/goplus/llgo/runtime/internal/runtime.strequal: - github.com/goplus/llgo/runtime/internal/runtime.strequal _llgo_bool: *_llgo_bool - __llgo_stub.github.com/goplus/llgo/runtime/internal/runtime.memequal8 + github.com/goplus/llgo/runtime/internal/runtime.memequal8 _llgo_bytes.Buffer: *_llgo_bytes.Buffer bytes.struct$8M6lRFZ7Fk2XCr2laNI9Y7uQtk2A8VDBrezMuq2Fkuo$fields _llgo_bytes.readOp: *_llgo_bytes.readOp - __llgo_stub.github.com/goplus/llgo/runtime/internal/runtime.memequal8 + github.com/goplus/llgo/runtime/internal/runtime.memequal8 _llgo_error: *_llgo_error - __llgo_stub.github.com/goplus/llgo/runtime/internal/runtime.interequal _llgo_iface$Fh8eUJ-Gw4e6TYuajcFIOSCuqSPKAt5nS4ow7xeGXEU$imethods + github.com/goplus/llgo/runtime/internal/runtime.interequal _llgo_func$2_iS07vIlF2_rZqWB5eU0IvP_9HviM4MYZNkXZDvbac: *_llgo_func$2_iS07vIlF2_rZqWB5eU0IvP_9HviM4MYZNkXZDvbac _llgo_func$8rsrSd_r3UHd_2DiYTyaOKR7BYkei4zw5ysG35KF38w: @@ -517,33 +449,33 @@ _llgo_iface$kr1iSWwMezh0B9LdQN0MhEZUNZvBlHPhlst95jAyxE0$imethods: _llgo_func$G2hch9Iy9DrhKKsg70PbL54bK-XSl-1IUUORN17J2Dk _llgo_iface$uycIKA3bbxRhudEjW1hHKWKdLqHQsCVy8NdW1bkQmNw: *_llgo_iface$uycIKA3bbxRhudEjW1hHKWKdLqHQsCVy8NdW1bkQmNw - __llgo_stub.github.com/goplus/llgo/runtime/internal/runtime.interequal _llgo_iface$uycIKA3bbxRhudEjW1hHKWKdLqHQsCVy8NdW1bkQmNw$imethods + github.com/goplus/llgo/runtime/internal/runtime.interequal _llgo_iface$uycIKA3bbxRhudEjW1hHKWKdLqHQsCVy8NdW1bkQmNw$imethods: _llgo_func$G2hch9Iy9DrhKKsg70PbL54bK-XSl-1IUUORN17J2Dk _llgo_int: *_llgo_int - __llgo_stub.github.com/goplus/llgo/runtime/internal/runtime.memequal64 + github.com/goplus/llgo/runtime/internal/runtime.memequal64 _llgo_int32: *_llgo_int32 - __llgo_stub.github.com/goplus/llgo/runtime/internal/runtime.memequal32 + github.com/goplus/llgo/runtime/internal/runtime.memequal32 _llgo_int64: *_llgo_int64 - __llgo_stub.github.com/goplus/llgo/runtime/internal/runtime.memequal64 + github.com/goplus/llgo/runtime/internal/runtime.memequal64 _llgo_io.Reader: *_llgo_io.Reader - __llgo_stub.github.com/goplus/llgo/runtime/internal/runtime.interequal _llgo_iface$uycIKA3bbxRhudEjW1hHKWKdLqHQsCVy8NdW1bkQmNw$imethods + github.com/goplus/llgo/runtime/internal/runtime.interequal _llgo_io.Writer: *_llgo_io.Writer - __llgo_stub.github.com/goplus/llgo/runtime/internal/runtime.interequal _llgo_iface$kr1iSWwMezh0B9LdQN0MhEZUNZvBlHPhlst95jAyxE0$imethods + github.com/goplus/llgo/runtime/internal/runtime.interequal _llgo_string: *_llgo_string - __llgo_stub.github.com/goplus/llgo/runtime/internal/runtime.strequal + github.com/goplus/llgo/runtime/internal/runtime.strequal _llgo_uint8: *_llgo_uint8 - __llgo_stub.github.com/goplus/llgo/runtime/internal/runtime.memequal8 + github.com/goplus/llgo/runtime/internal/runtime.memequal8 bytes.struct$8M6lRFZ7Fk2XCr2laNI9Y7uQtk2A8VDBrezMuq2Fkuo$fields: []_llgo_uint8 _llgo_bytes.readOp @@ -569,34 +501,34 @@ main.main: [MethodInfo] *_llgo_bytes.Buffer: - 0 Available _llgo_func$ETeB8WwW04JEq0ztcm-XPTJtuYvtpkjIsAc0-2NT9zA bytes.(*Buffer).Available __llgo_stub.bytes.(*Buffer).Available - 1 AvailableBuffer _llgo_func$Z_-7GWzB37LCYRTQLsSYmEihg_hqBK8o_GbT88pqnPY bytes.(*Buffer).AvailableBuffer __llgo_stub.bytes.(*Buffer).AvailableBuffer - 2 Bytes _llgo_func$Z_-7GWzB37LCYRTQLsSYmEihg_hqBK8o_GbT88pqnPY bytes.(*Buffer).Bytes __llgo_stub.bytes.(*Buffer).Bytes - 3 Cap _llgo_func$ETeB8WwW04JEq0ztcm-XPTJtuYvtpkjIsAc0-2NT9zA bytes.(*Buffer).Cap __llgo_stub.bytes.(*Buffer).Cap - 4 Grow _llgo_func$VZ-8VPNF1RaLICwxc1Ghn7BbgyFX3v762OCdx127EkA bytes.(*Buffer).Grow __llgo_stub.bytes.(*Buffer).Grow - 5 Len _llgo_func$ETeB8WwW04JEq0ztcm-XPTJtuYvtpkjIsAc0-2NT9zA bytes.(*Buffer).Len __llgo_stub.bytes.(*Buffer).Len - 6 Next _llgo_func$d4kMA_oCkLwnd1j8nVlv1hwRarEVuCIrDCpnHhDz9UY bytes.(*Buffer).Next __llgo_stub.bytes.(*Buffer).Next - 7 Peek _llgo_func$c8Vvy7bpifdsF4PDKWnpU2KNuhLPRr7XBIDM-4p45sQ bytes.(*Buffer).Peek __llgo_stub.bytes.(*Buffer).Peek - 8 Read _llgo_func$G2hch9Iy9DrhKKsg70PbL54bK-XSl-1IUUORN17J2Dk bytes.(*Buffer).Read __llgo_stub.bytes.(*Buffer).Read - 9 ReadByte _llgo_func$lukqSsfDYBoIp_R8GMojGkZnrYDqaq2iHn8RkCjW7iQ bytes.(*Buffer).ReadByte __llgo_stub.bytes.(*Buffer).ReadByte - 10 ReadBytes _llgo_func$aJkaU3jhXr0Q2QraTe2_TTdupeMMW2MD66UwBxynRM0 bytes.(*Buffer).ReadBytes __llgo_stub.bytes.(*Buffer).ReadBytes - 11 ReadFrom _llgo_func$uVmBDI0DMcrui3Q9y-g_hbtVN8JckQ18V2wmO5_G7A8 bytes.(*Buffer).ReadFrom __llgo_stub.bytes.(*Buffer).ReadFrom - 12 ReadRune _llgo_func$q-bw-_pPYBCXnr1TXIF8sOD4fVVzzIlpHqD-A13AB4Y bytes.(*Buffer).ReadRune __llgo_stub.bytes.(*Buffer).ReadRune - 13 ReadString _llgo_func$TBlCn7YTQdraI1HMiBWmkrqIGG-8UgD1UVyJy62Z_0o bytes.(*Buffer).ReadString __llgo_stub.bytes.(*Buffer).ReadString - 14 Reset _llgo_func$2_iS07vIlF2_rZqWB5eU0IvP_9HviM4MYZNkXZDvbac bytes.(*Buffer).Reset __llgo_stub.bytes.(*Buffer).Reset - 15 String _llgo_func$zNDVRsWTIpUPKouNUS805RGX--IV9qVK8B31IZbg5to bytes.(*Buffer).String __llgo_stub.bytes.(*Buffer).String - 16 Truncate _llgo_func$VZ-8VPNF1RaLICwxc1Ghn7BbgyFX3v762OCdx127EkA bytes.(*Buffer).Truncate __llgo_stub.bytes.(*Buffer).Truncate - 17 UnreadByte _llgo_func$8rsrSd_r3UHd_2DiYTyaOKR7BYkei4zw5ysG35KF38w bytes.(*Buffer).UnreadByte __llgo_stub.bytes.(*Buffer).UnreadByte - 18 UnreadRune _llgo_func$8rsrSd_r3UHd_2DiYTyaOKR7BYkei4zw5ysG35KF38w bytes.(*Buffer).UnreadRune __llgo_stub.bytes.(*Buffer).UnreadRune - 19 Write _llgo_func$G2hch9Iy9DrhKKsg70PbL54bK-XSl-1IUUORN17J2Dk bytes.(*Buffer).Write __llgo_stub.bytes.(*Buffer).Write - 20 WriteByte _llgo_func$w4tN9iibS_UimF5vLUWoKP0uAk2tJZF26VqETo_8LVg bytes.(*Buffer).WriteByte __llgo_stub.bytes.(*Buffer).WriteByte - 21 WriteRune _llgo_func$uf8yw1UkUdbDuCneSpNKIq_NThWIEVE7f1IYfJGz_bw bytes.(*Buffer).WriteRune __llgo_stub.bytes.(*Buffer).WriteRune - 22 WriteString _llgo_func$thH5FBpdXzJNnCpSfiLU5ItTntFU6LWp0RJhDm2XJjw bytes.(*Buffer).WriteString __llgo_stub.bytes.(*Buffer).WriteString - 23 WriteTo _llgo_func$vSv85k0UY6JWccAc3T-lvdCx9J-4GM-oZC9zGLrxW1M bytes.(*Buffer).WriteTo __llgo_stub.bytes.(*Buffer).WriteTo - 24 bytes.empty _llgo_func$YHeRw3AOvQtzv982-ZO3Yn8vh3Fx89RM3VvI8E4iKVk bytes.(*Buffer).empty __llgo_stub.bytes.(*Buffer).empty - 25 bytes.grow _llgo_func$ekGNsrYBSzltfAjxbl6T8H6Yq8j16wzqS3nDj2xxGMU bytes.(*Buffer).grow __llgo_stub.bytes.(*Buffer).grow - 26 bytes.readSlice _llgo_func$aJkaU3jhXr0Q2QraTe2_TTdupeMMW2MD66UwBxynRM0 bytes.(*Buffer).readSlice __llgo_stub.bytes.(*Buffer).readSlice - 27 bytes.tryGrowByReslice _llgo_func$qVJ5SH6qhXP_h0AM41vpBGzQEMp-fQIfvwQEJy5NI8M bytes.(*Buffer).tryGrowByReslice __llgo_stub.bytes.(*Buffer).tryGrowByReslice + 0 Available _llgo_func$ETeB8WwW04JEq0ztcm-XPTJtuYvtpkjIsAc0-2NT9zA bytes.(*Buffer).Available bytes.(*Buffer).Available + 1 AvailableBuffer _llgo_func$Z_-7GWzB37LCYRTQLsSYmEihg_hqBK8o_GbT88pqnPY bytes.(*Buffer).AvailableBuffer bytes.(*Buffer).AvailableBuffer + 2 Bytes _llgo_func$Z_-7GWzB37LCYRTQLsSYmEihg_hqBK8o_GbT88pqnPY bytes.(*Buffer).Bytes bytes.(*Buffer).Bytes + 3 Cap _llgo_func$ETeB8WwW04JEq0ztcm-XPTJtuYvtpkjIsAc0-2NT9zA bytes.(*Buffer).Cap bytes.(*Buffer).Cap + 4 Grow _llgo_func$VZ-8VPNF1RaLICwxc1Ghn7BbgyFX3v762OCdx127EkA bytes.(*Buffer).Grow bytes.(*Buffer).Grow + 5 Len _llgo_func$ETeB8WwW04JEq0ztcm-XPTJtuYvtpkjIsAc0-2NT9zA bytes.(*Buffer).Len bytes.(*Buffer).Len + 6 Next _llgo_func$d4kMA_oCkLwnd1j8nVlv1hwRarEVuCIrDCpnHhDz9UY bytes.(*Buffer).Next bytes.(*Buffer).Next + 7 Peek _llgo_func$c8Vvy7bpifdsF4PDKWnpU2KNuhLPRr7XBIDM-4p45sQ bytes.(*Buffer).Peek bytes.(*Buffer).Peek + 8 Read _llgo_func$G2hch9Iy9DrhKKsg70PbL54bK-XSl-1IUUORN17J2Dk bytes.(*Buffer).Read bytes.(*Buffer).Read + 9 ReadByte _llgo_func$lukqSsfDYBoIp_R8GMojGkZnrYDqaq2iHn8RkCjW7iQ bytes.(*Buffer).ReadByte bytes.(*Buffer).ReadByte + 10 ReadBytes _llgo_func$aJkaU3jhXr0Q2QraTe2_TTdupeMMW2MD66UwBxynRM0 bytes.(*Buffer).ReadBytes bytes.(*Buffer).ReadBytes + 11 ReadFrom _llgo_func$uVmBDI0DMcrui3Q9y-g_hbtVN8JckQ18V2wmO5_G7A8 bytes.(*Buffer).ReadFrom bytes.(*Buffer).ReadFrom + 12 ReadRune _llgo_func$q-bw-_pPYBCXnr1TXIF8sOD4fVVzzIlpHqD-A13AB4Y bytes.(*Buffer).ReadRune bytes.(*Buffer).ReadRune + 13 ReadString _llgo_func$TBlCn7YTQdraI1HMiBWmkrqIGG-8UgD1UVyJy62Z_0o bytes.(*Buffer).ReadString bytes.(*Buffer).ReadString + 14 Reset _llgo_func$2_iS07vIlF2_rZqWB5eU0IvP_9HviM4MYZNkXZDvbac bytes.(*Buffer).Reset bytes.(*Buffer).Reset + 15 String _llgo_func$zNDVRsWTIpUPKouNUS805RGX--IV9qVK8B31IZbg5to bytes.(*Buffer).String bytes.(*Buffer).String + 16 Truncate _llgo_func$VZ-8VPNF1RaLICwxc1Ghn7BbgyFX3v762OCdx127EkA bytes.(*Buffer).Truncate bytes.(*Buffer).Truncate + 17 UnreadByte _llgo_func$8rsrSd_r3UHd_2DiYTyaOKR7BYkei4zw5ysG35KF38w bytes.(*Buffer).UnreadByte bytes.(*Buffer).UnreadByte + 18 UnreadRune _llgo_func$8rsrSd_r3UHd_2DiYTyaOKR7BYkei4zw5ysG35KF38w bytes.(*Buffer).UnreadRune bytes.(*Buffer).UnreadRune + 19 Write _llgo_func$G2hch9Iy9DrhKKsg70PbL54bK-XSl-1IUUORN17J2Dk bytes.(*Buffer).Write bytes.(*Buffer).Write + 20 WriteByte _llgo_func$w4tN9iibS_UimF5vLUWoKP0uAk2tJZF26VqETo_8LVg bytes.(*Buffer).WriteByte bytes.(*Buffer).WriteByte + 21 WriteRune _llgo_func$uf8yw1UkUdbDuCneSpNKIq_NThWIEVE7f1IYfJGz_bw bytes.(*Buffer).WriteRune bytes.(*Buffer).WriteRune + 22 WriteString _llgo_func$thH5FBpdXzJNnCpSfiLU5ItTntFU6LWp0RJhDm2XJjw bytes.(*Buffer).WriteString bytes.(*Buffer).WriteString + 23 WriteTo _llgo_func$vSv85k0UY6JWccAc3T-lvdCx9J-4GM-oZC9zGLrxW1M bytes.(*Buffer).WriteTo bytes.(*Buffer).WriteTo + 24 bytes.empty _llgo_func$YHeRw3AOvQtzv982-ZO3Yn8vh3Fx89RM3VvI8E4iKVk bytes.(*Buffer).empty bytes.(*Buffer).empty + 25 bytes.grow _llgo_func$ekGNsrYBSzltfAjxbl6T8H6Yq8j16wzqS3nDj2xxGMU bytes.(*Buffer).grow bytes.(*Buffer).grow + 26 bytes.readSlice _llgo_func$aJkaU3jhXr0Q2QraTe2_TTdupeMMW2MD66UwBxynRM0 bytes.(*Buffer).readSlice bytes.(*Buffer).readSlice + 27 bytes.tryGrowByReslice _llgo_func$qVJ5SH6qhXP_h0AM41vpBGzQEMp-fQIfvwQEJy5NI8M bytes.(*Buffer).tryGrowByReslice bytes.(*Buffer).tryGrowByReslice [InterfaceInfo] _llgo_iface$uycIKA3bbxRhudEjW1hHKWKdLqHQsCVy8NdW1bkQmNw: diff --git a/cl/_testmeta/reflect_dynamic/meta-expect.txt b/cl/_testmeta/reflect_dynamic/meta-expect.txt index cbf96a6272..628325a77c 100644 --- a/cl/_testmeta/reflect_dynamic/meta-expect.txt +++ b/cl/_testmeta/reflect_dynamic/meta-expect.txt @@ -10,24 +10,16 @@ _llgo_main.T: [OrdinaryEdges] *_llgo_func$2_iS07vIlF2_rZqWB5eU0IvP_9HviM4MYZNkXZDvbac: - __llgo_stub.github.com/goplus/llgo/runtime/internal/runtime.memequalptr _llgo_func$2_iS07vIlF2_rZqWB5eU0IvP_9HviM4MYZNkXZDvbac + github.com/goplus/llgo/runtime/internal/runtime.memequalptr *_llgo_main.T: - __llgo_stub.github.com/goplus/llgo/runtime/internal/runtime.memequalptr _llgo_main.T -__llgo_stub.github.com/goplus/llgo/runtime/internal/runtime.memequal0: - github.com/goplus/llgo/runtime/internal/runtime.memequal0 -__llgo_stub.github.com/goplus/llgo/runtime/internal/runtime.memequalptr: github.com/goplus/llgo/runtime/internal/runtime.memequalptr -__llgo_stub.main.(*T).M: - main.(*T).M -__llgo_stub.main.T.M: - main.T.M _llgo_func$2_iS07vIlF2_rZqWB5eU0IvP_9HviM4MYZNkXZDvbac: *_llgo_func$2_iS07vIlF2_rZqWB5eU0IvP_9HviM4MYZNkXZDvbac _llgo_main.T: *_llgo_main.T - __llgo_stub.github.com/goplus/llgo/runtime/internal/runtime.memequal0 + github.com/goplus/llgo/runtime/internal/runtime.memequal0 main.(*T).M: github.com/goplus/llgo/runtime/internal/runtime.AssertNilDeref github.com/goplus/llgo/runtime/internal/runtime.PanicWrapNilPointer @@ -49,9 +41,9 @@ main.use: [MethodInfo] *_llgo_main.T: - 0 M _llgo_func$2_iS07vIlF2_rZqWB5eU0IvP_9HviM4MYZNkXZDvbac main.(*T).M __llgo_stub.main.(*T).M + 0 M _llgo_func$2_iS07vIlF2_rZqWB5eU0IvP_9HviM4MYZNkXZDvbac main.(*T).M main.(*T).M _llgo_main.T: - 0 M _llgo_func$2_iS07vIlF2_rZqWB5eU0IvP_9HviM4MYZNkXZDvbac main.(*T).M __llgo_stub.main.T.M + 0 M _llgo_func$2_iS07vIlF2_rZqWB5eU0IvP_9HviM4MYZNkXZDvbac main.(*T).M main.T.M [Reflect] main.use diff --git a/cl/_testmeta/reflect_named/meta-expect.txt b/cl/_testmeta/reflect_named/meta-expect.txt index 77bc7b262b..c3093e6bcd 100644 --- a/cl/_testmeta/reflect_named/meta-expect.txt +++ b/cl/_testmeta/reflect_named/meta-expect.txt @@ -10,28 +10,16 @@ _llgo_main.T: [OrdinaryEdges] *_llgo_func$2_iS07vIlF2_rZqWB5eU0IvP_9HviM4MYZNkXZDvbac: - __llgo_stub.github.com/goplus/llgo/runtime/internal/runtime.memequalptr _llgo_func$2_iS07vIlF2_rZqWB5eU0IvP_9HviM4MYZNkXZDvbac + github.com/goplus/llgo/runtime/internal/runtime.memequalptr *_llgo_main.T: - __llgo_stub.github.com/goplus/llgo/runtime/internal/runtime.memequalptr _llgo_main.T -__llgo_stub.github.com/goplus/llgo/runtime/internal/runtime.memequal0: - github.com/goplus/llgo/runtime/internal/runtime.memequal0 -__llgo_stub.github.com/goplus/llgo/runtime/internal/runtime.memequalptr: github.com/goplus/llgo/runtime/internal/runtime.memequalptr -__llgo_stub.main.(*T).M: - main.(*T).M -__llgo_stub.main.(*T).m: - main.(*T).m -__llgo_stub.main.T.M: - main.T.M -__llgo_stub.main.T.m: - main.T.m _llgo_func$2_iS07vIlF2_rZqWB5eU0IvP_9HviM4MYZNkXZDvbac: *_llgo_func$2_iS07vIlF2_rZqWB5eU0IvP_9HviM4MYZNkXZDvbac _llgo_main.T: *_llgo_main.T - __llgo_stub.github.com/goplus/llgo/runtime/internal/runtime.memequal0 + github.com/goplus/llgo/runtime/internal/runtime.memequal0 main.(*T).M: github.com/goplus/llgo/runtime/internal/runtime.AssertNilDeref github.com/goplus/llgo/runtime/internal/runtime.PanicWrapNilPointer @@ -66,11 +54,11 @@ main.main: [MethodInfo] *_llgo_main.T: - 0 M _llgo_func$2_iS07vIlF2_rZqWB5eU0IvP_9HviM4MYZNkXZDvbac main.(*T).M __llgo_stub.main.(*T).M - 1 main.m _llgo_func$2_iS07vIlF2_rZqWB5eU0IvP_9HviM4MYZNkXZDvbac main.(*T).m __llgo_stub.main.(*T).m + 0 M _llgo_func$2_iS07vIlF2_rZqWB5eU0IvP_9HviM4MYZNkXZDvbac main.(*T).M main.(*T).M + 1 main.m _llgo_func$2_iS07vIlF2_rZqWB5eU0IvP_9HviM4MYZNkXZDvbac main.(*T).m main.(*T).m _llgo_main.T: - 0 M _llgo_func$2_iS07vIlF2_rZqWB5eU0IvP_9HviM4MYZNkXZDvbac main.(*T).M __llgo_stub.main.T.M - 1 main.m _llgo_func$2_iS07vIlF2_rZqWB5eU0IvP_9HviM4MYZNkXZDvbac main.(*T).m __llgo_stub.main.T.m + 0 M _llgo_func$2_iS07vIlF2_rZqWB5eU0IvP_9HviM4MYZNkXZDvbac main.(*T).M main.T.M + 1 main.m _llgo_func$2_iS07vIlF2_rZqWB5eU0IvP_9HviM4MYZNkXZDvbac main.(*T).m main.T.m [InterfaceInfo] github.com/goplus/llgo/runtime/internal/lib/reflect.iface$mD8cc0P9iPHqG1cgYNbFpshv9b41oJ45HmjD5KeBlWw: diff --git a/cl/_testmeta/typechildren_basic/meta-expect.txt b/cl/_testmeta/typechildren_basic/meta-expect.txt index 658704e3fe..e989a483dc 100644 --- a/cl/_testmeta/typechildren_basic/meta-expect.txt +++ b/cl/_testmeta/typechildren_basic/meta-expect.txt @@ -21,26 +21,20 @@ _llgo_string: [OrdinaryEdges] *_llgo_int: - __llgo_stub.github.com/goplus/llgo/runtime/internal/runtime.memequalptr _llgo_int + github.com/goplus/llgo/runtime/internal/runtime.memequalptr *_llgo_main.Inner: - __llgo_stub.github.com/goplus/llgo/runtime/internal/runtime.memequalptr _llgo_main.Inner + github.com/goplus/llgo/runtime/internal/runtime.memequalptr *_llgo_main.Outer: - __llgo_stub.github.com/goplus/llgo/runtime/internal/runtime.memequalptr _llgo_main.Outer + github.com/goplus/llgo/runtime/internal/runtime.memequalptr *_llgo_string: - __llgo_stub.github.com/goplus/llgo/runtime/internal/runtime.memequalptr _llgo_string -__llgo_stub.github.com/goplus/llgo/runtime/internal/runtime.memequal64: - github.com/goplus/llgo/runtime/internal/runtime.memequal64 -__llgo_stub.github.com/goplus/llgo/runtime/internal/runtime.memequalptr: github.com/goplus/llgo/runtime/internal/runtime.memequalptr -__llgo_stub.github.com/goplus/llgo/runtime/internal/runtime.strequal: - github.com/goplus/llgo/runtime/internal/runtime.strequal _llgo_int: *_llgo_int - __llgo_stub.github.com/goplus/llgo/runtime/internal/runtime.memequal64 + github.com/goplus/llgo/runtime/internal/runtime.memequal64 _llgo_main.Inner: *_llgo_main.Inner _llgo_struct$MTAKiWNMPODH0G9-y5PI3BUGLd6hRciSbX1QTpCDOZg$fields @@ -51,7 +45,7 @@ _llgo_main.Outer: github.com/goplus/llgo/runtime/internal/runtime.structequal _llgo_string: *_llgo_string - __llgo_stub.github.com/goplus/llgo/runtime/internal/runtime.strequal + github.com/goplus/llgo/runtime/internal/runtime.strequal _llgo_struct$MTAKiWNMPODH0G9-y5PI3BUGLd6hRciSbX1QTpCDOZg$fields: _llgo_string _llgo_struct$Z-8Mj1VAYg5xS_jUvJKfmUcA_2fP_OEHpanbgA_46rE$fields: diff --git a/cl/_testrt/any/in.go b/cl/_testrt/any/in.go index e96e33052d..e7a4412ac7 100644 --- a/cl/_testrt/any/in.go +++ b/cl/_testrt/any/in.go @@ -77,15 +77,3 @@ func main() { // CHECK-NEXT: %4 = call i32 (ptr, ...) @printf(ptr @3, ptr %0, i64 %3) // CHECK-NEXT: ret void // CHECK-NEXT: } - -// CHECK-LABEL: define linkonce i1 @"__llgo_stub.{{.*}}/runtime/internal/runtime.memequal8"(ptr %0, ptr %1, ptr %2){{.*}} { -// CHECK-NEXT: _llgo_0: -// CHECK-NEXT: %3 = tail call i1 @"{{.*}}/runtime/internal/runtime.memequal8"(ptr %1, ptr %2) -// CHECK-NEXT: ret i1 %3 -// CHECK-NEXT: } - -// CHECK-LABEL: define linkonce i1 @"__llgo_stub.{{.*}}/runtime/internal/runtime.memequal64"(ptr %0, ptr %1, ptr %2){{.*}} { -// CHECK-NEXT: _llgo_0: -// CHECK-NEXT: %3 = tail call i1 @"{{.*}}/runtime/internal/runtime.memequal64"(ptr %1, ptr %2) -// CHECK-NEXT: ret i1 %3 -// CHECK-NEXT: } diff --git a/cl/_testrt/builtin/in.go b/cl/_testrt/builtin/in.go index fdc7ff8da0..efa6b87f49 100644 --- a/cl/_testrt/builtin/in.go +++ b/cl/_testrt/builtin/in.go @@ -266,7 +266,7 @@ func demo() { // CHECK-NEXT: call void @"{{.*}}/runtime/internal/runtime.PrintByte"(i8 10) // CHECK-NEXT: %89 = call ptr @"{{.*}}/runtime/internal/runtime.AllocZ"(i64 16) // CHECK-NEXT: %90 = getelementptr inbounds { ptr, ptr }, ptr %89, i64 0 -// CHECK-NEXT: store { ptr, ptr } { ptr @"__llgo_stub.main.main$1", ptr null }, ptr %90, align 8 +// CHECK-NEXT: store { ptr, ptr } { ptr @"main.main$1", ptr null }, ptr %90, align 8 // CHECK-NEXT: %91 = insertvalue %"{{.*}}/runtime/internal/runtime.Slice" undef, ptr %89, 0 // CHECK-NEXT: %92 = insertvalue %"{{.*}}/runtime/internal/runtime.Slice" %91, i64 1, 1 // CHECK-NEXT: %93 = insertvalue %"{{.*}}/runtime/internal/runtime.Slice" %92, i64 1, 2 @@ -505,7 +505,7 @@ func main() { println("fn") } - // CHECK-LABEL: define void @"main.main$3"(ptr %0){{.*}} { + // CHECK-LABEL: define void @"main.main$3"(ptr {{(nest|swiftself)}} %0){{.*}} { // CHECK-NEXT: _llgo_0: // CHECK-NEXT: %1 = load { ptr }, ptr %0, align 8 // CHECK-NEXT: %2 = extractvalue { ptr } %1, 0 @@ -534,15 +534,3 @@ func main() { s2 := "abd" println(s1 == "abc", s1 == s2, s1 != s2, s1 < s2, s1 <= s2, s1 > s2, s1 >= s2) } - -// CHECK-LABEL: define linkonce void @"__llgo_stub.main.main$1"(ptr %0){{.*}} { -// CHECK-NEXT: _llgo_0: -// CHECK-NEXT: tail call void @"main.main$1"() -// CHECK-NEXT: ret void -// CHECK-NEXT: } - -// CHECK-LABEL: define linkonce i1 @"__llgo_stub.{{.*}}/runtime/internal/runtime.memequal64"(ptr %0, ptr %1, ptr %2){{.*}} { -// CHECK-NEXT: _llgo_0: -// CHECK-NEXT: %3 = tail call i1 @"{{.*}}/runtime/internal/runtime.memequal64"(ptr %1, ptr %2) -// CHECK-NEXT: ret i1 %3 -// CHECK-NEXT: } diff --git a/cl/_testrt/callback/in.go b/cl/_testrt/callback/in.go index ea178d22a0..60c5c12d30 100644 --- a/cl/_testrt/callback/in.go +++ b/cl/_testrt/callback/in.go @@ -9,7 +9,8 @@ import ( // CHECK-NEXT: _llgo_0: // CHECK-NEXT: %2 = extractvalue { ptr, ptr } %1, 1 // CHECK-NEXT: %3 = extractvalue { ptr, ptr } %1, 0 -// CHECK-NEXT: call void %3(ptr %2, ptr %0) +// CHECK-NEXT: %__llgo_funcval_code = call ptr asm "", "=r,0"(ptr %3) +// CHECK-NEXT: call void %__llgo_funcval_code(ptr {{(nest|swiftself)}} %2, ptr %0) // CHECK-NEXT: ret void // CHECK-NEXT: } func callback(msg *c.Char, f func(*c.Char)) { @@ -18,8 +19,8 @@ func callback(msg *c.Char, f func(*c.Char)) { // CHECK-LABEL: define void @main.main(){{.*}} { // CHECK-NEXT: _llgo_0: -// CHECK-NEXT: call void @main.callback(ptr @0, { ptr, ptr } { ptr @__llgo_stub.main.print, ptr null }) -// CHECK-NEXT: call void @main.callback(ptr @1, { ptr, ptr } { ptr @__llgo_stub.main.print, ptr null }) +// CHECK-NEXT: call void @main.callback(ptr @0, { ptr, ptr } { ptr @main.print, ptr null }) +// CHECK-NEXT: call void @main.callback(ptr @1, { ptr, ptr } { ptr @main.print, ptr null }) // CHECK-NEXT: ret void // CHECK-NEXT: } func main() { @@ -33,11 +34,6 @@ func main() { // CHECK-NEXT: ret void // CHECK-NEXT: } -// CHECK-LABEL: define linkonce void @__llgo_stub.main.print(ptr %0, ptr %1){{.*}} { -// CHECK-NEXT: _llgo_0: -// CHECK-NEXT: tail call void @main.print(ptr %1) -// CHECK-NEXT: ret void -// CHECK-NEXT: } func print(msg *c.Char) { c.Printf(msg) } diff --git a/cl/_testrt/closure/in.go b/cl/_testrt/closure/in.go index 9f9b3571ee..2fe0f79057 100644 --- a/cl/_testrt/closure/in.go +++ b/cl/_testrt/closure/in.go @@ -9,14 +9,15 @@ import ( // CHECK-NEXT: _llgo_0: // CHECK-NEXT: call void @"main.main$1"(i64 100, i64 200) // CHECK-NEXT: %0 = call ptr @"{{.*}}/runtime/internal/runtime.AllocZ"(i64 16) -// CHECK-NEXT: store { ptr, ptr } { ptr @"__llgo_stub.main.main$2", ptr null }, ptr %0, align 8 +// CHECK-NEXT: store { ptr, ptr } { ptr @"main.main$2", ptr null }, ptr %0, align 8 // CHECK-NEXT: %1 = call ptr @"{{.*}}/runtime/internal/runtime.AllocU"(i64 8) // CHECK-NEXT: %2 = getelementptr inbounds { ptr }, ptr %1, i32 0, i32 0 // CHECK-NEXT: store ptr %0, ptr %2, align 8 // CHECK-NEXT: %3 = insertvalue { ptr, ptr } { ptr @"main.main$3", ptr undef }, ptr %1, 1 // CHECK-NEXT: %4 = extractvalue { ptr, ptr } %3, 1 // CHECK-NEXT: %5 = extractvalue { ptr, ptr } %3, 0 -// CHECK-NEXT: call void %5(ptr %4) +// CHECK-NEXT: %__llgo_funcval_code = call ptr asm "", "=r,0"(ptr %5) +// CHECK-NEXT: call void %__llgo_funcval_code(ptr {{(nest|swiftself)}} %4) // CHECK-NEXT: ret void // CHECK-NEXT: } func main() { @@ -38,14 +39,15 @@ func main() { c.Printf(c.Str("%d %d\n"), n1, n2) } - // CHECK-LABEL: define void @"main.main$3"(ptr %0){{.*}} { + // CHECK-LABEL: define void @"main.main$3"(ptr {{(nest|swiftself)}} %0){{.*}} { // CHECK-NEXT: _llgo_0: // CHECK-NEXT: %1 = load { ptr }, ptr %0, align 8 // CHECK-NEXT: %2 = extractvalue { ptr } %1, 0 // CHECK-NEXT: %3 = load { ptr, ptr }, ptr %2, align 8 // CHECK-NEXT: %4 = extractvalue { ptr, ptr } %3, 1 // CHECK-NEXT: %5 = extractvalue { ptr, ptr } %3, 0 - // CHECK-NEXT: call void %5(ptr %4, i64 100, i64 200) + // CHECK-NEXT: %__llgo_funcval_code = call ptr asm "", "=r,0"(ptr %5) + // CHECK-NEXT: call void %__llgo_funcval_code(ptr {{(nest|swiftself)}} %4, i64 100, i64 200) // CHECK-NEXT: ret void // CHECK-NEXT: } fn2 := func() { @@ -53,9 +55,3 @@ func main() { } fn2() } - -// CHECK-LABEL: define linkonce void @"__llgo_stub.main.main$2"(ptr %0, i64 %1, i64 %2){{.*}} { -// CHECK-NEXT: _llgo_0: -// CHECK-NEXT: tail call void @"main.main$2"(i64 %1, i64 %2) -// CHECK-NEXT: ret void -// CHECK-NEXT: } diff --git a/cl/_testrt/closurebound/in.go b/cl/_testrt/closurebound/in.go index 0c0914df94..9e5364b6b5 100644 --- a/cl/_testrt/closurebound/in.go +++ b/cl/_testrt/closurebound/in.go @@ -67,11 +67,7 @@ func main() { // CHECK-EMPTY: // CHECK-NEXT: _llgo_1: ; preds = %_llgo_0 // CHECK-NEXT: store i1 true, ptr @"main.init$guard", align 1 -// CHECK-NEXT: %1 = call ptr @"{{.*}}/runtime/internal/runtime.AllocU"(i64 0) -// CHECK-NEXT: %2 = getelementptr inbounds { %main.demo2 }, ptr %1, i32 0, i32 0 -// CHECK-NEXT: store %main.demo2 zeroinitializer, ptr %2, align 1 -// CHECK-NEXT: %3 = insertvalue { ptr, ptr } { ptr @"main.demo2.encode$bound", ptr undef }, ptr %1, 1 -// CHECK-NEXT: store { ptr, ptr } %3, ptr @main.my, align 8 +// CHECK-NEXT: store { ptr, ptr } { ptr @"main.demo2.encode$bound", ptr @"__llgo.moduleZeroSizedAlloc$" }, ptr @main.my, align 8 // CHECK-NEXT: br label %_llgo_2 // CHECK-EMPTY: // CHECK-NEXT: _llgo_2: ; preds = %_llgo_1, %_llgo_0 @@ -80,28 +76,22 @@ func main() { // CHECK-LABEL: define void @main.main(){{.*}} { // CHECK-NEXT: _llgo_0: -// CHECK-NEXT: %0 = call ptr @"{{.*}}/runtime/internal/runtime.AllocU"(i64 0) -// CHECK-NEXT: %1 = getelementptr inbounds { %main.demo1 }, ptr %0, i32 0, i32 0 -// CHECK-NEXT: store %main.demo1 zeroinitializer, ptr %1, align 1 -// CHECK-NEXT: %2 = insertvalue { ptr, ptr } { ptr @"main.demo1.encode$bound", ptr undef }, ptr %0, 1 -// CHECK-NEXT: %3 = extractvalue { ptr, ptr } %2, 1 -// CHECK-NEXT: %4 = extractvalue { ptr, ptr } %2, 0 -// CHECK-NEXT: %5 = call i64 %4(ptr %3) -// CHECK-NEXT: %6 = icmp ne i64 %5, 1 -// CHECK-NEXT: br i1 %6, label %_llgo_1, label %_llgo_2 +// CHECK-NEXT: %0 = call i64 @"main.demo1.encode$bound"(ptr {{(nest|swiftself)}} @"__llgo.moduleZeroSizedAlloc$") +// CHECK-NEXT: %1 = icmp ne i64 %0, 1 +// CHECK-NEXT: br i1 %1, label %_llgo_1, label %_llgo_2 // CHECK-EMPTY: // CHECK-NEXT: _llgo_1: ; preds = %_llgo_0 -// CHECK-NEXT: %7 = call ptr @"{{.*}}/runtime/internal/runtime.AllocU"(i64 16) -// CHECK-NEXT: store %"{{.*}}/runtime/internal/runtime.String" { ptr @3, i64 5 }, ptr %7, align 8 -// CHECK-NEXT: %8 = insertvalue %"{{.*}}/runtime/internal/runtime.eface" { ptr @_llgo_string, ptr undef }, ptr %7, 1 -// CHECK-NEXT: call void @"{{.*}}/runtime/internal/runtime.Panic"(%"{{.*}}/runtime/internal/runtime.eface" %8) +// CHECK-NEXT: %2 = call ptr @"{{.*}}/runtime/internal/runtime.AllocU"(i64 16) +// CHECK-NEXT: store %"{{.*}}/runtime/internal/runtime.String" { ptr @3, i64 5 }, ptr %2, align 8 +// CHECK-NEXT: %3 = insertvalue %"{{.*}}/runtime/internal/runtime.eface" { ptr @_llgo_string, ptr undef }, ptr %2, 1 +// CHECK-NEXT: call void @"{{.*}}/runtime/internal/runtime.Panic"(%"{{.*}}/runtime/internal/runtime.eface" %3) // CHECK-NEXT: unreachable // CHECK-EMPTY: // CHECK-NEXT: _llgo_2: ; preds = %_llgo_0 // CHECK-NEXT: ret void // CHECK-NEXT: } -// CHECK-LABEL: define i64 @"main.demo2.encode$bound"(ptr %0){{.*}} { +// CHECK-LABEL: define i64 @"main.demo2.encode$bound"(ptr {{(nest|swiftself)}} %0){{.*}} { // CHECK-NEXT: _llgo_0: // CHECK-NEXT: %1 = icmp eq ptr %0, null // CHECK-NEXT: call void @"{{.*}}/runtime/internal/runtime.AssertNilDeref"(i1 %1) @@ -109,7 +99,7 @@ func main() { // CHECK-NEXT: ret i64 %2 // CHECK-NEXT: } -// CHECK-LABEL: define i64 @"main.demo1.encode$bound"(ptr %0){{.*}} { +// CHECK-LABEL: define i64 @"main.demo1.encode$bound"(ptr {{(nest|swiftself)}} %0){{.*}} { // CHECK-NEXT: _llgo_0: // CHECK-NEXT: %1 = icmp eq ptr %0, null // CHECK-NEXT: call void @"{{.*}}/runtime/internal/runtime.AssertNilDeref"(i1 %1) diff --git a/cl/_testrt/closureconv/in.go b/cl/_testrt/closureconv/in.go index 853b7da618..6d63cf3c07 100644 --- a/cl/_testrt/closureconv/in.go +++ b/cl/_testrt/closureconv/in.go @@ -74,7 +74,7 @@ func demo2() Func { // CHECK-LABEL: define %main.Func @main.demo3(){{.*}} { // CHECK-NEXT: _llgo_0: -// CHECK-NEXT: ret %main.Func { ptr @__llgo_stub.main.add, ptr null } +// CHECK-NEXT: ret %main.Func { ptr @main.add, ptr null } // CHECK-NEXT: } func demo3() Func { @@ -83,7 +83,7 @@ func demo3() Func { // CHECK-LABEL: define %main.Func @main.demo4(){{.*}} { // CHECK-NEXT: _llgo_0: -// CHECK-NEXT: ret %main.Func { ptr @"__llgo_stub.main.demo4$1", ptr null } +// CHECK-NEXT: ret %main.Func { ptr @"main.demo4$1", ptr null } // CHECK-NEXT: } // CHECK-LABEL: define i64 @"main.demo4$1"(i64 %0, i64 %1){{.*}} { @@ -109,7 +109,7 @@ func demo4() Func { // CHECK-NEXT: ret %main.Func %6 // CHECK-NEXT: } -// CHECK-LABEL: define i64 @"main.demo5$1"(ptr %0, i64 %1, i64 %2){{.*}} { +// CHECK-LABEL: define i64 @"main.demo5$1"(ptr {{(nest|swiftself)}} %0, i64 %1, i64 %2){{.*}} { // CHECK-NEXT: _llgo_0: // CHECK-NEXT: %3 = add i64 %1, %2 // CHECK-NEXT: %4 = load { ptr }, ptr %0, align 8 @@ -127,31 +127,36 @@ func demo5(n int) Func { // CHECK-NEXT: %0 = call %main.Func @main.demo1(i64 1) // CHECK-NEXT: %1 = extractvalue %main.Func %0, 1 // CHECK-NEXT: %2 = extractvalue %main.Func %0, 0 -// CHECK-NEXT: %3 = call i64 %2(ptr %1, i64 99, i64 200) +// CHECK-NEXT: %__llgo_funcval_code = call ptr asm "", "=r,0"(ptr %2) +// CHECK-NEXT: %3 = call i64 %__llgo_funcval_code(ptr {{(nest|swiftself)}} %1, i64 99, i64 200) // CHECK-NEXT: call void @"{{.*}}/runtime/internal/runtime.PrintInt"(i64 %3) // CHECK-NEXT: call void @"{{.*}}/runtime/internal/runtime.PrintByte"(i8 10) // CHECK-NEXT: %4 = call %main.Func @main.demo2() // CHECK-NEXT: %5 = extractvalue %main.Func %4, 1 // CHECK-NEXT: %6 = extractvalue %main.Func %4, 0 -// CHECK-NEXT: %7 = call i64 %6(ptr %5, i64 100, i64 200) +// CHECK-NEXT: %__llgo_funcval_code1 = call ptr asm "", "=r,0"(ptr %6) +// CHECK-NEXT: %7 = call i64 %__llgo_funcval_code1(ptr {{(nest|swiftself)}} %5, i64 100, i64 200) // CHECK-NEXT: call void @"{{.*}}/runtime/internal/runtime.PrintInt"(i64 %7) // CHECK-NEXT: call void @"{{.*}}/runtime/internal/runtime.PrintByte"(i8 10) // CHECK-NEXT: %8 = call %main.Func @main.demo3() // CHECK-NEXT: %9 = extractvalue %main.Func %8, 1 // CHECK-NEXT: %10 = extractvalue %main.Func %8, 0 -// CHECK-NEXT: %11 = call i64 %10(ptr %9, i64 100, i64 200) +// CHECK-NEXT: %__llgo_funcval_code2 = call ptr asm "", "=r,0"(ptr %10) +// CHECK-NEXT: %11 = call i64 %__llgo_funcval_code2(ptr {{(nest|swiftself)}} %9, i64 100, i64 200) // CHECK-NEXT: call void @"{{.*}}/runtime/internal/runtime.PrintInt"(i64 %11) // CHECK-NEXT: call void @"{{.*}}/runtime/internal/runtime.PrintByte"(i8 10) // CHECK-NEXT: %12 = call %main.Func @main.demo4() // CHECK-NEXT: %13 = extractvalue %main.Func %12, 1 // CHECK-NEXT: %14 = extractvalue %main.Func %12, 0 -// CHECK-NEXT: %15 = call i64 %14(ptr %13, i64 100, i64 200) +// CHECK-NEXT: %__llgo_funcval_code3 = call ptr asm "", "=r,0"(ptr %14) +// CHECK-NEXT: %15 = call i64 %__llgo_funcval_code3(ptr {{(nest|swiftself)}} %13, i64 100, i64 200) // CHECK-NEXT: call void @"{{.*}}/runtime/internal/runtime.PrintInt"(i64 %15) // CHECK-NEXT: call void @"{{.*}}/runtime/internal/runtime.PrintByte"(i8 10) // CHECK-NEXT: %16 = call %main.Func @main.demo5(i64 1) // CHECK-NEXT: %17 = extractvalue %main.Func %16, 1 // CHECK-NEXT: %18 = extractvalue %main.Func %16, 0 -// CHECK-NEXT: %19 = call i64 %18(ptr %17, i64 99, i64 200) +// CHECK-NEXT: %__llgo_funcval_code4 = call ptr asm "", "=r,0"(ptr %18) +// CHECK-NEXT: %19 = call i64 %__llgo_funcval_code4(ptr {{(nest|swiftself)}} %17, i64 99, i64 200) // CHECK-NEXT: call void @"{{.*}}/runtime/internal/runtime.PrintInt"(i64 %19) // CHECK-NEXT: call void @"{{.*}}/runtime/internal/runtime.PrintByte"(i8 10) // CHECK-NEXT: %20 = call %main.Func @main.demo5(i64 1) @@ -160,7 +165,8 @@ func demo5(n int) Func { // CHECK-NEXT: %22 = load { ptr, ptr }, ptr %21, align 8 // CHECK-NEXT: %23 = extractvalue { ptr, ptr } %22, 1 // CHECK-NEXT: %24 = extractvalue { ptr, ptr } %22, 0 -// CHECK-NEXT: %25 = call i64 %24(ptr %23, i64 99, i64 200) +// CHECK-NEXT: %__llgo_funcval_code5 = call ptr asm "", "=r,0"(ptr %24) +// CHECK-NEXT: %25 = call i64 %__llgo_funcval_code5(ptr {{(nest|swiftself)}} %23, i64 99, i64 200) // CHECK-NEXT: call void @"{{.*}}/runtime/internal/runtime.PrintInt"(i64 %25) // CHECK-NEXT: call void @"{{.*}}/runtime/internal/runtime.PrintByte"(i8 10) // CHECK-NEXT: %26 = call %main.Func @main.demo5(i64 1) @@ -170,7 +176,8 @@ func demo5(n int) Func { // CHECK-NEXT: %30 = insertvalue %main.Func2 %28, ptr %29, 1 // CHECK-NEXT: %31 = extractvalue %main.Func2 %30, 1 // CHECK-NEXT: %32 = extractvalue %main.Func2 %30, 0 -// CHECK-NEXT: %33 = call i64 %32(ptr %31, i64 99, i64 200) +// CHECK-NEXT: %__llgo_funcval_code6 = call ptr asm "", "=r,0"(ptr %32) +// CHECK-NEXT: %33 = call i64 %__llgo_funcval_code6(ptr {{(nest|swiftself)}} %31, i64 99, i64 200) // CHECK-NEXT: call void @"{{.*}}/runtime/internal/runtime.PrintInt"(i64 %33) // CHECK-NEXT: call void @"{{.*}}/runtime/internal/runtime.PrintByte"(i8 10) // CHECK-NEXT: ret void @@ -199,22 +206,10 @@ func main() { println(fn2(99, 200)) } -// CHECK-LABEL: define i64 @"main.(*Call).add$bound"(ptr %0, i64 %1, i64 %2){{.*}} { +// CHECK-LABEL: define i64 @"main.(*Call).add$bound"(ptr {{(nest|swiftself)}} %0, i64 %1, i64 %2){{.*}} { // CHECK-NEXT: _llgo_0: // CHECK-NEXT: %3 = load { ptr }, ptr %0, align 8 // CHECK-NEXT: %4 = extractvalue { ptr } %3, 0 // CHECK-NEXT: %5 = call i64 @"main.(*Call).add"(ptr %4, i64 %1, i64 %2) // CHECK-NEXT: ret i64 %5 // CHECK-NEXT: } - -// CHECK-LABEL: define linkonce i64 @__llgo_stub.main.add(ptr %0, i64 %1, i64 %2){{.*}} { -// CHECK-NEXT: _llgo_0: -// CHECK-NEXT: %3 = tail call i64 @main.add(i64 %1, i64 %2) -// CHECK-NEXT: ret i64 %3 -// CHECK-NEXT: } - -// CHECK-LABEL: define linkonce i64 @"__llgo_stub.main.demo4$1"(ptr %0, i64 %1, i64 %2){{.*}} { -// CHECK-NEXT: _llgo_0: -// CHECK-NEXT: %3 = tail call i64 @"main.demo4$1"(i64 %1, i64 %2) -// CHECK-NEXT: ret i64 %3 -// CHECK-NEXT: } diff --git a/cl/_testrt/closureiface/in.go b/cl/_testrt/closureiface/in.go index 3d6b9308c1..37f277e152 100644 --- a/cl/_testrt/closureiface/in.go +++ b/cl/_testrt/closureiface/in.go @@ -26,7 +26,8 @@ package main // CHECK-NEXT: _llgo_2: ; preds = %_llgo_5 // CHECK-NEXT: %10 = extractvalue { ptr, ptr } %18, 1 // CHECK-NEXT: %11 = extractvalue { ptr, ptr } %18, 0 -// CHECK-NEXT: %12 = call i64 %11(ptr %10, i64 100) +// CHECK-NEXT: %__llgo_funcval_code = call ptr asm "", "=r,0"(ptr %11) +// CHECK-NEXT: %12 = call i64 %__llgo_funcval_code(ptr {{(nest|swiftself)}} %10, i64 100) // CHECK-NEXT: call void @"{{.*}}/runtime/internal/runtime.PrintInt"(i64 %12) // CHECK-NEXT: call void @"{{.*}}/runtime/internal/runtime.PrintByte"(i8 10) // CHECK-NEXT: ret void @@ -49,7 +50,7 @@ package main // CHECK-NEXT: } func main() { var m int = 200 - // CHECK-LABEL: define i64 @"main.main$1"(ptr %0, i64 %1){{.*}} { + // CHECK-LABEL: define i64 @"main.main$1"(ptr {{(nest|swiftself)}} %0, i64 %1){{.*}} { // CHECK-NEXT: _llgo_0: // CHECK-NEXT: %2 = load { ptr }, ptr %0, align 8 // CHECK-NEXT: %3 = extractvalue { ptr } %2, 0 diff --git a/cl/_testrt/eface/in.go b/cl/_testrt/eface/in.go index 68b29347b3..ff3bcf7e9a 100644 --- a/cl/_testrt/eface/in.go +++ b/cl/_testrt/eface/in.go @@ -199,9 +199,3 @@ func main() { var t T dump(t) } - -// CHECK-LABEL: define linkonce void @"__llgo_stub.main.main$1"(ptr %0){{.*}} { -// CHECK-NEXT: _llgo_0: -// CHECK-NEXT: tail call void @"main.main$1"() -// CHECK-NEXT: ret void -// CHECK-NEXT: } diff --git a/cl/_testrt/freevars/in.go b/cl/_testrt/freevars/in.go index 0a717e8bf5..e5fd293f12 100644 --- a/cl/_testrt/freevars/in.go +++ b/cl/_testrt/freevars/in.go @@ -3,7 +3,7 @@ package main // CHECK-LABEL: define void @main.main(){{.*}} { // CHECK-NEXT: _llgo_0: -// CHECK-NEXT: call void @"main.main$1"({ ptr, ptr } { ptr @"__llgo_stub.main.main$2", ptr null }) +// CHECK-NEXT: call void @"main.main$1"({ ptr, ptr } { ptr @"main.main$2", ptr null }) // CHECK-NEXT: ret void // CHECK-NEXT: } func main() { @@ -17,12 +17,13 @@ func main() { // CHECK-NEXT: %4 = insertvalue { ptr, ptr } { ptr @"main.main$1$1", ptr undef }, ptr %2, 1 // CHECK-NEXT: %5 = extractvalue { ptr, ptr } %4, 1 // CHECK-NEXT: %6 = extractvalue { ptr, ptr } %4, 0 - // CHECK-NEXT: call void %6(ptr %5, %"{{.*}}/runtime/internal/runtime.iface" zeroinitializer) + // CHECK-NEXT: %__llgo_funcval_code = call ptr asm "", "=r,0"(ptr %6) + // CHECK-NEXT: call void %__llgo_funcval_code(ptr {{(nest|swiftself)}} %5, %"{{.*}}/runtime/internal/runtime.iface" zeroinitializer) // CHECK-NEXT: ret void // CHECK-NEXT: } func(resolve func(error)) { - // CHECK-LABEL: define void @"main.main$1$1"(ptr %0, %"{{.*}}/runtime/internal/runtime.iface" %1){{.*}} { + // CHECK-LABEL: define void @"main.main$1$1"(ptr {{(nest|swiftself)}} %0, %"{{.*}}/runtime/internal/runtime.iface" %1){{.*}} { // CHECK-NEXT: _llgo_0: // CHECK-NEXT: %2 = load { ptr }, ptr %0, align 8 // CHECK-NEXT: %3 = call ptr @"{{.*}}/runtime/internal/runtime.IfaceType"(%"{{.*}}/runtime/internal/runtime.iface" %1) @@ -41,7 +42,8 @@ func main() { // CHECK-NEXT: %13 = load { ptr, ptr }, ptr %12, align 8 // CHECK-NEXT: %14 = extractvalue { ptr, ptr } %13, 1 // CHECK-NEXT: %15 = extractvalue { ptr, ptr } %13, 0 - // CHECK-NEXT: call void %15(ptr %14, %"{{.*}}/runtime/internal/runtime.iface" %1) + // CHECK-NEXT: %__llgo_funcval_code = call ptr asm "", "=r,0"(ptr %15) + // CHECK-NEXT: call void %__llgo_funcval_code(ptr {{(nest|swiftself)}} %14, %"{{.*}}/runtime/internal/runtime.iface" %1) // CHECK-NEXT: ret void // CHECK-EMPTY: // CHECK-NEXT: _llgo_2: ; preds = %_llgo_0 @@ -49,7 +51,8 @@ func main() { // CHECK-NEXT: %17 = load { ptr, ptr }, ptr %16, align 8 // CHECK-NEXT: %18 = extractvalue { ptr, ptr } %17, 1 // CHECK-NEXT: %19 = extractvalue { ptr, ptr } %17, 0 - // CHECK-NEXT: call void %19(ptr %18, %"{{.*}}/runtime/internal/runtime.iface" zeroinitializer) + // CHECK-NEXT: %__llgo_funcval_code1 = call ptr asm "", "=r,0"(ptr %19) + // CHECK-NEXT: call void %__llgo_funcval_code1(ptr {{(nest|swiftself)}} %18, %"{{.*}}/runtime/internal/runtime.iface" zeroinitializer) // CHECK-NEXT: ret void // CHECK-NEXT: } @@ -67,9 +70,3 @@ func main() { }(func(err error) { }) } - -// CHECK-LABEL: define linkonce void @"__llgo_stub.main.main$2"(ptr %0, %"{{.*}}/runtime/internal/runtime.iface" %1){{.*}} { -// CHECK-NEXT: _llgo_0: -// CHECK-NEXT: tail call void @"main.main$2"(%"{{.*}}/runtime/internal/runtime.iface" %1) -// CHECK-NEXT: ret void -// CHECK-NEXT: } diff --git a/cl/_testrt/funcdecl/in.go b/cl/_testrt/funcdecl/in.go index 8efd3f4635..2bc82e1ee9 100644 --- a/cl/_testrt/funcdecl/in.go +++ b/cl/_testrt/funcdecl/in.go @@ -12,7 +12,7 @@ import ( // CHECK-LABEL: define void @main.check({ ptr, ptr } %0){{.*}} { // CHECK-NEXT: _llgo_0: // CHECK-NEXT: %1 = call ptr @"{{.*}}/runtime/internal/runtime.AllocU"(i64 16) -// CHECK-NEXT: store { ptr, ptr } { ptr @__llgo_stub.main.demo, ptr null }, ptr %1, align 8 +// CHECK-NEXT: store { ptr, ptr } { ptr @main.demo, ptr null }, ptr %1, align 8 // CHECK-NEXT: %2 = insertvalue %"{{.*}}/runtime/internal/runtime.eface" { ptr @"_llgo_closure$b7Su1hWaFih-M0M9hMk6nO_RD1K_GQu5WjIXQp6Q2e8", ptr undef }, ptr %1, 1 // CHECK-NEXT: %3 = call ptr @"{{.*}}/runtime/internal/runtime.AllocU"(i64 16) // CHECK-NEXT: store { ptr, ptr } %0, ptr %3, align 8 @@ -122,7 +122,7 @@ func demo() { // CHECK-NEXT: _llgo_0: // CHECK-NEXT: call void @"{{.*}}/runtime/internal/runtime.PrintString"(%"{{.*}}/runtime/internal/runtime.String" { ptr @6, i64 5 }) // CHECK-NEXT: call void @"{{.*}}/runtime/internal/runtime.PrintByte"(i8 10) -// CHECK-NEXT: call void @main.check({ ptr, ptr } { ptr @__llgo_stub.main.demo, ptr null }) +// CHECK-NEXT: call void @main.check({ ptr, ptr } { ptr @main.demo, ptr null }) // CHECK-NEXT: ret void // CHECK-NEXT: } @@ -130,9 +130,3 @@ func main() { println("hello") check(demo) } - -// CHECK-LABEL: define linkonce void @__llgo_stub.main.demo(ptr %0){{.*}} { -// CHECK-NEXT: _llgo_0: -// CHECK-NEXT: tail call void @main.demo() -// CHECK-NEXT: ret void -// CHECK-NEXT: } diff --git a/cl/_testrt/intgen/in.go b/cl/_testrt/intgen/in.go index cc8d1d42a3..40ee12c681 100644 --- a/cl/_testrt/intgen/in.go +++ b/cl/_testrt/intgen/in.go @@ -20,7 +20,8 @@ import ( // CHECK-NEXT: _llgo_2: ; preds = %_llgo_1 // CHECK-NEXT: %7 = extractvalue { ptr, ptr } %1, 1 // CHECK-NEXT: %8 = extractvalue { ptr, ptr } %1, 0 -// CHECK-NEXT: %9 = call i32 %8(ptr %7) +// CHECK-NEXT: %__llgo_funcval_code = call ptr asm "", "=r,0"(ptr %8) +// CHECK-NEXT: %9 = call i32 %__llgo_funcval_code(ptr {{(nest|swiftself)}} %7) // CHECK-NEXT: %10 = extractvalue %"{{.*}}/runtime/internal/runtime.Slice" %2, 0 // CHECK-NEXT: %11 = extractvalue %"{{.*}}/runtime/internal/runtime.Slice" %2, 1 // CHECK-NEXT: %12 = icmp slt i64 %5, 0 @@ -64,7 +65,7 @@ type generator struct { // CHECK-LABEL: define void @main.main(){{.*}} { // CHECK-NEXT: _llgo_0: -// CHECK-NEXT: %0 = call %"{{.*}}/runtime/internal/runtime.Slice" @main.genInts(i64 5, { ptr, ptr } { ptr @__llgo_stub.rand, ptr null }) +// CHECK-NEXT: %0 = call %"{{.*}}/runtime/internal/runtime.Slice" @main.genInts(i64 5, { ptr, ptr } { ptr @rand, ptr null }) // CHECK-NEXT: %1 = extractvalue %"{{.*}}/runtime/internal/runtime.Slice" %0, 1 // CHECK-NEXT: br label %_llgo_1 // CHECK-EMPTY: @@ -156,7 +157,7 @@ func main() { initVal := c.Int(1) ints := genInts(5, func() c.Int { - // CHECK-LABEL: define i32 @"main.main$1"(ptr %0){{.*}} { + // CHECK-LABEL: define i32 @"main.main$1"(ptr {{(nest|swiftself)}} %0){{.*}} { // CHECK-NEXT: _llgo_0: // CHECK-NEXT: %1 = load { ptr }, ptr %0, align 8 // CHECK-NEXT: %2 = extractvalue { ptr } %1, 0 @@ -179,14 +180,9 @@ func main() { for _, v := range genInts(5, g.next) { c.Printf(c.Str("%d\n"), v) } - // CHECK-LABEL: define linkonce i32 @__llgo_stub.rand(ptr %0){{.*}} { - // CHECK-NEXT: _llgo_0: - // CHECK-NEXT: %1 = tail call i32 @rand() - // CHECK-NEXT: ret i32 %1 - // CHECK-NEXT: } } -// CHECK-LABEL: define i32 @"main.(*generator).next$bound"(ptr %0){{.*}} { +// CHECK-LABEL: define i32 @"main.(*generator).next$bound"(ptr {{(nest|swiftself)}} %0){{.*}} { // CHECK-NEXT: _llgo_0: // CHECK-NEXT: %1 = load { ptr }, ptr %0, align 8 // CHECK-NEXT: %2 = extractvalue { ptr } %1, 0 diff --git a/cl/_testrt/makemap/in.go b/cl/_testrt/makemap/in.go index d3693bcb69..d7f35d1e62 100644 --- a/cl/_testrt/makemap/in.go +++ b/cl/_testrt/makemap/in.go @@ -853,21 +853,3 @@ func make7() { } println(m[1]) } - -// CHECK-LABEL: define linkonce i1 @"__llgo_stub.{{.*}}/runtime/internal/runtime.memequal64"(ptr %0, ptr %1, ptr %2){{.*}} { -// CHECK-NEXT: _llgo_0: -// CHECK-NEXT: %3 = tail call i1 @"{{.*}}/runtime/internal/runtime.memequal64"(ptr %1, ptr %2) -// CHECK-NEXT: ret i1 %3 -// CHECK-NEXT: } - -// CHECK-LABEL: define linkonce i1 @"__llgo_stub.{{.*}}/runtime/internal/runtime.memequal8"(ptr %0, ptr %1, ptr %2){{.*}} { -// CHECK-NEXT: _llgo_0: -// CHECK-NEXT: %3 = tail call i1 @"{{.*}}/runtime/internal/runtime.memequal8"(ptr %1, ptr %2) -// CHECK-NEXT: ret i1 %3 -// CHECK-NEXT: } - -// CHECK-LABEL: define linkonce i1 @"__llgo_stub.{{.*}}/runtime/internal/runtime.nilinterequal"(ptr %0, ptr %1, ptr %2){{.*}} { -// CHECK-NEXT: _llgo_0: -// CHECK-NEXT: %3 = tail call i1 @"{{.*}}/runtime/internal/runtime.nilinterequal"(ptr %1, ptr %2) -// CHECK-NEXT: ret i1 %3 -// CHECK-NEXT: } diff --git a/cl/_testrt/mapclosure/in.go b/cl/_testrt/mapclosure/in.go index a866b94a17..1347fded25 100644 --- a/cl/_testrt/mapclosure/in.go +++ b/cl/_testrt/mapclosure/in.go @@ -55,13 +55,15 @@ var ( // CHECK-NEXT: %14 = insertvalue %"{{.*}}/runtime/internal/runtime.iface" %13, ptr %0, 1 // CHECK-NEXT: %15 = extractvalue { ptr, ptr } %5, 1 // CHECK-NEXT: %16 = extractvalue { ptr, ptr } %5, 0 -// CHECK-NEXT: %17 = call %"{{.*}}/runtime/internal/runtime.String" %16(ptr %15, %"{{.*}}/runtime/internal/runtime.iface" %14) +// CHECK-NEXT: %__llgo_funcval_code = call ptr asm "", "=r,0"(ptr %16) +// CHECK-NEXT: %17 = call %"{{.*}}/runtime/internal/runtime.String" %__llgo_funcval_code(ptr {{(nest|swiftself)}} %15, %"{{.*}}/runtime/internal/runtime.iface" %14) // CHECK-NEXT: %18 = call ptr @"{{.*}}/runtime/internal/runtime.NewItab"(ptr @"_llgo_iface$O6rEVxIuA5O1E0KWpQBCgGx26X5gYhJ_nnJnHVL8_7U", ptr @"*_llgo_main.typ") // CHECK-NEXT: %19 = insertvalue %"{{.*}}/runtime/internal/runtime.iface" undef, ptr %18, 0 // CHECK-NEXT: %20 = insertvalue %"{{.*}}/runtime/internal/runtime.iface" %19, ptr %0, 1 // CHECK-NEXT: %21 = extractvalue { ptr, ptr } %11, 1 // CHECK-NEXT: %22 = extractvalue { ptr, ptr } %11, 0 -// CHECK-NEXT: %23 = call %"{{.*}}/runtime/internal/runtime.String" %22(ptr %21, %"{{.*}}/runtime/internal/runtime.iface" %20) +// CHECK-NEXT: %__llgo_funcval_code1 = call ptr asm "", "=r,0"(ptr %22) +// CHECK-NEXT: %23 = call %"{{.*}}/runtime/internal/runtime.String" %__llgo_funcval_code1(ptr {{(nest|swiftself)}} %21, %"{{.*}}/runtime/internal/runtime.iface" %20) // CHECK-NEXT: %24 = call i1 @"{{.*}}/runtime/internal/runtime.StringEqual"(%"{{.*}}/runtime/internal/runtime.String" %17, %"{{.*}}/runtime/internal/runtime.String" %23) // CHECK-NEXT: %25 = xor i1 %24, true // CHECK-NEXT: br i1 %25, label %_llgo_1, label %_llgo_2 @@ -95,9 +97,3 @@ func main() { func (t *typ) String() string { return t.s } - -// CHECK-LABEL: define linkonce %"{{.*}}/runtime/internal/runtime.String" @__llgo_stub.main.demo(ptr %0, %"{{.*}}/runtime/internal/runtime.iface" %1){{.*}} { -// CHECK-NEXT: _llgo_0: -// CHECK-NEXT: %2 = tail call %"{{.*}}/runtime/internal/runtime.String" @main.demo(%"{{.*}}/runtime/internal/runtime.iface" %1) -// CHECK-NEXT: ret %"{{.*}}/runtime/internal/runtime.String" %2 -// CHECK-NEXT: } diff --git a/cl/_testrt/methodthunk/in.go b/cl/_testrt/methodthunk/in.go index afe1ec56b3..95e01b60f8 100644 --- a/cl/_testrt/methodthunk/in.go +++ b/cl/_testrt/methodthunk/in.go @@ -40,10 +40,10 @@ func (i *InnerInt) M() int { // CHECK-LABEL: define void @main.main(){{.*}} { // CHECK-NEXT: _llgo_0: // CHECK-NEXT: %0 = call ptr @"{{.*}}/runtime/internal/runtime.AllocU"(i64 16) -// CHECK-NEXT: store { ptr, ptr } { ptr @"__llgo_stub.main.(*outer).M$thunk", ptr null }, ptr %0, align 8 +// CHECK-NEXT: store { ptr, ptr } { ptr @"main.(*outer).M$thunk", ptr null }, ptr %0, align 8 // CHECK-NEXT: %1 = insertvalue %"{{.*}}/runtime/internal/runtime.eface" { ptr @"_llgo_closure${{[-A-Za-z0-9_]+}}", ptr undef }, ptr %0, 1 // CHECK-NEXT: %2 = call ptr @"{{.*}}/runtime/internal/runtime.AllocU"(i64 16) -// CHECK-NEXT: store { ptr, ptr } { ptr @"__llgo_stub.main.(*InnerInt).M$thunk", ptr null }, ptr %2, align 8 +// CHECK-NEXT: store { ptr, ptr } { ptr @"main.(*InnerInt).M$thunk", ptr null }, ptr %2, align 8 // CHECK-NEXT: %3 = insertvalue %"{{.*}}/runtime/internal/runtime.eface" { ptr @"_llgo_closure${{[-A-Za-z0-9_]+}}", ptr undef }, ptr %2, 1 // CHECK-NEXT: %4 = extractvalue %"{{.*}}/runtime/internal/runtime.eface" %1, 0 // CHECK-NEXT: %5 = call i1 @"{{.*}}/runtime/internal/runtime.MatchesClosure"(ptr @"_llgo_closure${{[-A-Za-z0-9_]+}}", ptr %4) @@ -127,26 +127,8 @@ func (m *outer) M() {} // CHECK-NEXT: ret void // CHECK-NEXT: } -// CHECK-LABEL: define linkonce void @"__llgo_stub.main.(*outer).M$thunk"(ptr %0, ptr %1){{.*}} { -// CHECK-NEXT: _llgo_0: -// CHECK-NEXT: tail call void @"main.(*outer).M$thunk"(ptr %1) -// CHECK-NEXT: ret void -// CHECK-NEXT: } - -// CHECK-LABEL: define linkonce i1 @"__llgo_stub.github.com/goplus/llgo/runtime/internal/runtime.memequal64"(ptr %0, ptr %1, ptr %2){{.*}} { -// CHECK-NEXT: _llgo_0: -// CHECK-NEXT: %3 = tail call i1 @"{{.*}}/runtime/internal/runtime.memequal64"(ptr %1, ptr %2) -// CHECK-NEXT: ret i1 %3 -// CHECK-NEXT: } - // CHECK-LABEL: define i64 @"main.(*InnerInt).M$thunk"(ptr %0){{.*}} { // CHECK-NEXT: _llgo_0: // CHECK-NEXT: %1 = call i64 @"main.(*InnerInt).M"(ptr %0) // CHECK-NEXT: ret i64 %1 // CHECK-NEXT: } - -// CHECK-LABEL: define linkonce i64 @"__llgo_stub.main.(*InnerInt).M$thunk"(ptr %0, ptr %1){{.*}} { -// CHECK-NEXT: _llgo_0: -// CHECK-NEXT: %2 = tail call i64 @"main.(*InnerInt).M$thunk"(ptr %1) -// CHECK-NEXT: ret i64 %2 -// CHECK-NEXT: } diff --git a/cl/_testrt/named/in.go b/cl/_testrt/named/in.go index 07d435287a..540e414d5b 100644 --- a/cl/_testrt/named/in.go +++ b/cl/_testrt/named/in.go @@ -99,7 +99,8 @@ type mspan struct { // CHECK-NEXT: %61 = load { ptr, ptr }, ptr %60, align 8 // CHECK-NEXT: %62 = extractvalue { ptr, ptr } %61, 1 // CHECK-NEXT: %63 = extractvalue { ptr, ptr } %61, 0 -// CHECK-NEXT: %64 = call i64 %63(ptr %62, i64 -2) +// CHECK-NEXT: %__llgo_funcval_code = call ptr asm "", "=r,0"(ptr %63) +// CHECK-NEXT: %64 = call i64 %__llgo_funcval_code(ptr {{(nest|swiftself)}} %62, i64 -2) // CHECK-NEXT: %65 = load ptr, ptr %0, align 8 // CHECK-NEXT: %66 = getelementptr inbounds %main.mspan, ptr %65, i32 0, i32 3 // CHECK-NEXT: %67 = getelementptr inbounds %main.minfo, ptr %66, i32 0, i32 0 @@ -108,7 +109,8 @@ type mspan struct { // CHECK-NEXT: %70 = load { ptr, ptr }, ptr %69, align 8 // CHECK-NEXT: %71 = extractvalue { ptr, ptr } %70, 1 // CHECK-NEXT: %72 = extractvalue { ptr, ptr } %70, 0 -// CHECK-NEXT: %73 = call i64 %72(ptr %71, i64 -3) +// CHECK-NEXT: %__llgo_funcval_code1 = call ptr asm "", "=r,0"(ptr %72) +// CHECK-NEXT: %73 = call i64 %__llgo_funcval_code1(ptr {{(nest|swiftself)}} %71, i64 -3) // CHECK-NEXT: %74 = call i32 (ptr, ...) @printf(ptr @0, i64 %41, i64 %48, i64 %52, i64 %58, i64 %64, i64 %73) // CHECK-NEXT: ret void // CHECK-NEXT: } @@ -125,7 +127,7 @@ func main() { m.check = func(n int) int { return m.value * n } - // CHECK-LABEL: define i64 @"main.main$1"(ptr %0, i64 %1){{.*}} { + // CHECK-LABEL: define i64 @"main.main$1"(ptr {{(nest|swiftself)}} %0, i64 %1){{.*}} { // CHECK-NEXT: _llgo_0: // CHECK-NEXT: %2 = load { ptr }, ptr %0, align 8 // CHECK-NEXT: %3 = extractvalue { ptr } %2, 0 diff --git a/cl/_testrt/reflectclosureenv/expect.txt b/cl/_testrt/reflectclosureenv/expect.txt new file mode 100644 index 0000000000..9766475a41 --- /dev/null +++ b/cl/_testrt/reflectclosureenv/expect.txt @@ -0,0 +1 @@ +ok diff --git a/cl/_testrt/reflectclosureenv/in.go b/cl/_testrt/reflectclosureenv/in.go new file mode 100644 index 0000000000..690a5b03d7 --- /dev/null +++ b/cl/_testrt/reflectclosureenv/in.go @@ -0,0 +1,89 @@ +// LITTEST +package main + +import "reflect" + +type receiver struct { + base int +} + +func (r receiver) Sum(a, b, c, d, e, f, g, h, i int) int { + return r.base + a + b + c + d + e + f + g + h + i +} + +// CHECK-LABEL: define double @"main.makeFloatSum$1"(ptr {{(nest|swiftself)}} %0, double %1, double %2, double %3, double %4, double %5, double %6, double %7, double %8, double %9){{.*}} { + +// CHECK-LABEL: define i64 @"main.makeSum$1"(ptr {{(nest|swiftself)}} %0, i64 %1, i64 %2, i64 %3, i64 %4, i64 %5, i64 %6, i64 %7, i64 %8, i64 %9){{.*}} { + +func makeSum(base int) func(int, int, int, int, int, int, int, int, int) int { + return func(a, b, c, d, e, f, g, h, i int) int { + return base + a + b + c + d + e + f + g + h + i + } +} + +func makeFloatSum(base float64) func(float64, float64, float64, float64, float64, float64, float64, float64, float64) float64 { + return func(a, b, c, d, e, f, g, h, i float64) float64 { + return base + a + b + c + d + e + f + g + h + i + } +} + +func makeNestedSum(base int) func(int, int, int, int, int, int, int, int, int) int { + return func(a, b, c, d, e, f, g, h, i int) int { + args := []reflect.Value{ + reflect.ValueOf(a), reflect.ValueOf(b), reflect.ValueOf(c), + reflect.ValueOf(d), reflect.ValueOf(e), reflect.ValueOf(f), + reflect.ValueOf(g), reflect.ValueOf(h), reflect.ValueOf(i), + } + return int(reflect.ValueOf(makeSum(base)).Call(args)[0].Int()) + } +} + +func intArgs() []reflect.Value { + args := make([]reflect.Value, 9) + for i := range args { + args[i] = reflect.ValueOf(i + 1) + } + return args +} + +func floatArgs() []reflect.Value { + args := make([]reflect.Value, 9) + for i := range args { + args[i] = reflect.ValueOf(float64(i + 1)) + } + return args +} + +func checkInt(value reflect.Value, args []reflect.Value) { + if got := value.Call(args)[0].Int(); got != 55 { + panic(got) + } +} + +func main() { + ints := intArgs() + checkInt(reflect.ValueOf(makeSum(10)), ints) + checkInt(reflect.ValueOf(makeNestedSum(10)), ints) + + ft := reflect.TypeOf(func(int, int, int, int, int, int, int, int, int) int { return 0 }) + made := reflect.MakeFunc(ft, func(args []reflect.Value) []reflect.Value { + var sum int64 = 10 + for _, arg := range args { + sum += arg.Int() + } + return []reflect.Value{reflect.ValueOf(int(sum))} + }) + checkInt(made, ints) + + method := reflect.ValueOf(receiver{base: 10}).MethodByName("Sum") + checkInt(method, ints) + bound := method.Interface().(func(int, int, int, int, int, int, int, int, int) int) + if got := bound(1, 2, 3, 4, 5, 6, 7, 8, 9); got != 55 { + panic(got) + } + + if got := reflect.ValueOf(makeFloatSum(10)).Call(floatArgs())[0].Float(); got != 55 { + panic(got) + } + println("ok") +} diff --git a/cl/_testrt/result/in.go b/cl/_testrt/result/in.go index 34fdd508d5..9caa844bf0 100644 --- a/cl/_testrt/result/in.go +++ b/cl/_testrt/result/in.go @@ -18,7 +18,7 @@ func add() func(int, int) int { // CHECK-LABEL: define { { ptr, ptr }, i64 } @main.add2(){{.*}} { // CHECK-NEXT: _llgo_0: -// CHECK-NEXT: ret { { ptr, ptr }, i64 } { { ptr, ptr } { ptr @"__llgo_stub.main.add2$1", ptr null }, i64 1 } +// CHECK-NEXT: ret { { ptr, ptr }, i64 } { { ptr, ptr } { ptr @"main.add2$1", ptr null }, i64 1 } // CHECK-NEXT: } func add2() (func(int, int) int, int) { // CHECK-LABEL: define i64 @"main.add2$1"(i64 %0, i64 %1){{.*}} { @@ -36,12 +36,14 @@ func add2() (func(int, int) int, int) { // CHECK-NEXT: %0 = call { ptr, ptr } @"main.main$1"() // CHECK-NEXT: %1 = extractvalue { ptr, ptr } %0, 1 // CHECK-NEXT: %2 = extractvalue { ptr, ptr } %0, 0 -// CHECK-NEXT: %3 = call i64 %2(ptr %1, i64 100, i64 200) +// CHECK-NEXT: %__llgo_funcval_code = call ptr asm "", "=r,0"(ptr %2) +// CHECK-NEXT: %3 = call i64 %__llgo_funcval_code(ptr {{(nest|swiftself)}} %1, i64 100, i64 200) // CHECK-NEXT: %4 = call i32 (ptr, ...) @printf(ptr @0, i64 %3) // CHECK-NEXT: %5 = call { ptr, ptr } @main.add() // CHECK-NEXT: %6 = extractvalue { ptr, ptr } %5, 1 // CHECK-NEXT: %7 = extractvalue { ptr, ptr } %5, 0 -// CHECK-NEXT: %8 = call i64 %7(ptr %6, i64 100, i64 200) +// CHECK-NEXT: %__llgo_funcval_code1 = call ptr asm "", "=r,0"(ptr %7) +// CHECK-NEXT: %8 = call i64 %__llgo_funcval_code1(ptr {{(nest|swiftself)}} %6, i64 100, i64 200) // CHECK-NEXT: %9 = call i32 (ptr, ...) @printf(ptr @1, i64 %8) // CHECK-NEXT: %10 = call { { ptr, ptr }, i64 } @main.add2() // CHECK-NEXT: %11 = extractvalue { { ptr, ptr }, i64 } %10, 0 @@ -49,14 +51,15 @@ func add2() (func(int, int) int, int) { // CHECK-NEXT: %13 = call { ptr, ptr } @main.add() // CHECK-NEXT: %14 = extractvalue { ptr, ptr } %13, 1 // CHECK-NEXT: %15 = extractvalue { ptr, ptr } %13, 0 -// CHECK-NEXT: %16 = call i64 %15(ptr %14, i64 100, i64 200) +// CHECK-NEXT: %__llgo_funcval_code2 = call ptr asm "", "=r,0"(ptr %15) +// CHECK-NEXT: %16 = call i64 %__llgo_funcval_code2(ptr {{(nest|swiftself)}} %14, i64 100, i64 200) // CHECK-NEXT: %17 = call i32 (ptr, ...) @printf(ptr @2, i64 %16, i64 %12) // CHECK-NEXT: ret void // CHECK-NEXT: } func main() { // CHECK-LABEL: define { ptr, ptr } @"main.main$1"(){{.*}} { // CHECK-NEXT: _llgo_0: - // CHECK-NEXT: ret { ptr, ptr } { ptr @"__llgo_stub.main.main$1$1", ptr null } + // CHECK-NEXT: ret { ptr, ptr } { ptr @"main.main$1$1", ptr null } // CHECK-NEXT: } fn := func() func(int, int) int { // CHECK-LABEL: define i64 @"main.main$1$1"(i64 %0, i64 %1){{.*}} { @@ -73,21 +76,3 @@ func main() { fn, n := add2() c.Printf(c.Str("%d %d\n"), add()(100, 200), n) } - -// CHECK-LABEL: define linkonce i64 @"__llgo_stub.main.add$1"(ptr %0, i64 %1, i64 %2){{.*}} { -// CHECK-NEXT: _llgo_0: -// CHECK-NEXT: %3 = tail call i64 @"main.add$1"(i64 %1, i64 %2) -// CHECK-NEXT: ret i64 %3 -// CHECK-NEXT: } - -// CHECK-LABEL: define linkonce i64 @"__llgo_stub.main.add2$1"(ptr %0, i64 %1, i64 %2){{.*}} { -// CHECK-NEXT: _llgo_0: -// CHECK-NEXT: %3 = tail call i64 @"main.add2$1"(i64 %1, i64 %2) -// CHECK-NEXT: ret i64 %3 -// CHECK-NEXT: } - -// CHECK-LABEL: define linkonce i64 @"__llgo_stub.main.main$1$1"(ptr %0, i64 %1, i64 %2){{.*}} { -// CHECK-NEXT: _llgo_0: -// CHECK-NEXT: %3 = tail call i64 @"main.main$1$1"(i64 %1, i64 %2) -// CHECK-NEXT: ret i64 %3 -// CHECK-NEXT: } diff --git a/cl/_testrt/tpabi/in.go b/cl/_testrt/tpabi/in.go index 287b027664..76493e4b8a 100644 --- a/cl/_testrt/tpabi/in.go +++ b/cl/_testrt/tpabi/in.go @@ -154,33 +154,3 @@ func main() { // CHECK-NEXT: call void @"main.T[string,int].Info"(%"main.T[string,int]" %2) // CHECK-NEXT: ret void // CHECK-NEXT: } - -// CHECK-LABEL: define linkonce void @"__llgo_stub.main.(*T[string,int]).Demo"(ptr %0, ptr %1){{.*}} { -// CHECK-NEXT: _llgo_0: -// CHECK-NEXT: tail call void @"main.(*T[string,int]).Demo"(ptr %1) -// CHECK-NEXT: ret void -// CHECK-NEXT: } - -// CHECK-LABEL: define linkonce void @"__llgo_stub.main.(*T[string,int]).Info"(ptr %0, ptr %1){{.*}} { -// CHECK-NEXT: _llgo_0: -// CHECK-NEXT: tail call void @"main.(*T[string,int]).Info"(ptr %1) -// CHECK-NEXT: ret void -// CHECK-NEXT: } - -// CHECK-LABEL: define linkonce i1 @"__llgo_stub.{{.*}}/runtime/internal/runtime.memequal64"(ptr %0, ptr %1, ptr %2){{.*}} { -// CHECK-NEXT: _llgo_0: -// CHECK-NEXT: %3 = tail call i1 @"{{.*}}/runtime/internal/runtime.memequal64"(ptr %1, ptr %2) -// CHECK-NEXT: ret i1 %3 -// CHECK-NEXT: } - -// CHECK-LABEL: define linkonce void @"__llgo_stub.main.T[string,int].Info"(ptr %0, %"main.T[string,int]" %1){{.*}} { -// CHECK-NEXT: _llgo_0: -// CHECK-NEXT: tail call void @"main.T[string,int].Info"(%"main.T[string,int]" %1) -// CHECK-NEXT: ret void -// CHECK-NEXT: } - -// CHECK-LABEL: define linkonce i1 @"__llgo_stub.{{.*}}/runtime/internal/runtime.interequal"(ptr %0, ptr %1, ptr %2){{.*}} { -// CHECK-NEXT: _llgo_0: -// CHECK-NEXT: %3 = tail call i1 @"{{.*}}/runtime/internal/runtime.interequal"(ptr %1, ptr %2) -// CHECK-NEXT: ret i1 %3 -// CHECK-NEXT: } diff --git a/cl/_testrt/tpfunc/in.go b/cl/_testrt/tpfunc/in.go index 3612acfe9e..cb39d77b28 100644 --- a/cl/_testrt/tpfunc/in.go +++ b/cl/_testrt/tpfunc/in.go @@ -81,9 +81,3 @@ func main() { } println(unsafe.Sizeof(fn1), unsafe.Sizeof(fn2), unsafe.Sizeof(fn3)) } - -// CHECK-LABEL: define linkonce void @"__llgo_stub.main.main$1"(ptr %0, ptr %1){{.*}} { -// CHECK-NEXT: _llgo_0: -// CHECK-NEXT: tail call void @"main.main$1"(ptr %1) -// CHECK-NEXT: ret void -// CHECK-NEXT: } diff --git a/cl/_testrt/tpmethod/in.go b/cl/_testrt/tpmethod/in.go index 501cbaa649..3e379e2198 100644 --- a/cl/_testrt/tpmethod/in.go +++ b/cl/_testrt/tpmethod/in.go @@ -31,7 +31,7 @@ func Async[T any](fn func(func(T))) Future[T] { // CHECK-LABEL: define %"{{.*}}/runtime/internal/runtime.iface" @main.ReadFile(%"{{.*}}/runtime/internal/runtime.String" %0){{.*}} { // CHECK-NEXT: _llgo_0: -// CHECK-NEXT: %1 = call %"{{.*}}/runtime/internal/runtime.iface" @"main.Async[main.Tuple[error]]"({ ptr, ptr } { ptr @"__llgo_stub.main.ReadFile$1", ptr null }) +// CHECK-NEXT: %1 = call %"{{.*}}/runtime/internal/runtime.iface" @"main.Async[main.Tuple[error]]"({ ptr, ptr } { ptr @"main.ReadFile$1", ptr null }) // CHECK-NEXT: ret %"{{.*}}/runtime/internal/runtime.iface" %1 // CHECK-NEXT: } @@ -45,7 +45,8 @@ func ReadFile(fileName string) Future[Tuple[error]] { // CHECK-NEXT: %3 = load %"main.Tuple[error]", ptr %1, align 8 // CHECK-NEXT: %4 = extractvalue { ptr, ptr } %0, 1 // CHECK-NEXT: %5 = extractvalue { ptr, ptr } %0, 0 - // CHECK-NEXT: call void %5(ptr %4, %"main.Tuple[error]" %3) + // CHECK-NEXT: %__llgo_funcval_code = call ptr asm "", "=r,0"(ptr %5) + // CHECK-NEXT: call void %__llgo_funcval_code(ptr {{(nest|swiftself)}} %4, %"main.Tuple[error]" %3) // CHECK-NEXT: ret void // CHECK-NEXT: } @@ -78,7 +79,7 @@ func ReadFile(fileName string) Future[Tuple[error]] { // CHECK-NEXT: %6 = insertvalue { ptr, ptr } %5, ptr %1, 1 // CHECK-NEXT: %7 = extractvalue { ptr, ptr } %6, 1 // CHECK-NEXT: %8 = extractvalue { ptr, ptr } %6, 0 -// CHECK-NEXT: call void %8(ptr %7, { ptr, ptr } { ptr @"__llgo_stub.main.main$1", ptr null }) +// CHECK-NEXT: call void %8(ptr %7, { ptr, ptr } { ptr @"main.main$1", ptr null }) // CHECK-NEXT: ret void // CHECK-NEXT: } @@ -107,18 +108,6 @@ func main() { // CHECK-NEXT: ret %"{{.*}}/runtime/internal/runtime.iface" %5 // CHECK-NEXT: } -// CHECK-LABEL: define linkonce void @"__llgo_stub.main.ReadFile$1"(ptr %0, { ptr, ptr } %1){{.*}} { -// CHECK-NEXT: _llgo_0: -// CHECK-NEXT: tail call void @"main.ReadFile$1"({ ptr, ptr } %1) -// CHECK-NEXT: ret void -// CHECK-NEXT: } - -// CHECK-LABEL: define linkonce void @"__llgo_stub.main.main$1"(ptr %0, %"main.Tuple[error]" %1){{.*}} { -// CHECK-NEXT: _llgo_0: -// CHECK-NEXT: tail call void @"main.main$1"(%"main.Tuple[error]" %1) -// CHECK-NEXT: ret void -// CHECK-NEXT: } - // CHECK-LABEL: define linkonce %"{{.*}}/runtime/internal/runtime.iface" @"main.Tuple[error].Get"(%"main.Tuple[error]" %0){{.*}} { // CHECK-NEXT: _llgo_0: // CHECK-NEXT: %1 = alloca %"main.Tuple[error]", align 8 @@ -135,7 +124,8 @@ func main() { // CHECK-NEXT: %3 = load { ptr, ptr }, ptr %2, align 8 // CHECK-NEXT: %4 = extractvalue { ptr, ptr } %3, 1 // CHECK-NEXT: %5 = extractvalue { ptr, ptr } %3, 0 -// CHECK-NEXT: call void %5(ptr %4, { ptr, ptr } %1) +// CHECK-NEXT: %__llgo_funcval_code = call ptr asm "", "=r,0"(ptr %5) +// CHECK-NEXT: call void %__llgo_funcval_code(ptr {{(nest|swiftself)}} %4, { ptr, ptr } %1) // CHECK-NEXT: ret void // CHECK-NEXT: } @@ -147,9 +137,3 @@ func main() { // CHECK-NEXT: %3 = call %"{{.*}}/runtime/internal/runtime.iface" @"main.Tuple[error].Get"(%"main.Tuple[error]" %2) // CHECK-NEXT: ret %"{{.*}}/runtime/internal/runtime.iface" %3 // CHECK-NEXT: } - -// CHECK-LABEL: define linkonce i1 @"__llgo_stub.{{.*}}/runtime/internal/runtime.interequal"(ptr %0, ptr %1, ptr %2){{.*}} { -// CHECK-NEXT: _llgo_0: -// CHECK-NEXT: %3 = tail call i1 @"{{.*}}/runtime/internal/runtime.interequal"(ptr %1, ptr %2) -// CHECK-NEXT: ret i1 %3 -// CHECK-NEXT: } diff --git a/cl/_testrt/typed/in.go b/cl/_testrt/typed/in.go index 6a8326097b..7eefecc701 100644 --- a/cl/_testrt/typed/in.go +++ b/cl/_testrt/typed/in.go @@ -114,9 +114,3 @@ func main() { ar, ok := a.(A) println(ar[0], ar[1], ok) } - -// CHECK-LABEL: define linkonce i1 @"__llgo_stub.{{.*}}/runtime/internal/runtime.memequal64"(ptr %0, ptr %1, ptr %2){{.*}} { -// CHECK-NEXT: _llgo_0: -// CHECK-NEXT: %3 = tail call i1 @"{{.*}}/runtime/internal/runtime.memequal64"(ptr %1, ptr %2) -// CHECK-NEXT: ret i1 %3 -// CHECK-NEXT: } diff --git a/cl/compile.go b/cl/compile.go index 9032deb02b..d15422e878 100644 --- a/cl/compile.go +++ b/cl/compile.go @@ -463,7 +463,40 @@ func makeClosureCtx(pkg *types.Package, vars []*ssa.FreeVar) *types.Var { flds[i] = types.NewField(token.NoPos, pkg, name, v.Type(), false) } t := types.NewPointer(types.NewStruct(flds, nil)) - return types.NewParam(token.NoPos, pkg, "__llgo_ctx", t) + return types.NewParam(token.NoPos, pkg, "$env", t) +} + +// canElideZeroSizedClosureEnv reports whether a source closure can recreate +// all of its captured variables from the module's zero-sized sentinel. Go SSA +// represents a lexical capture as a pointer to the captured variable. Captured +// zero-sized variables are heap allocated, and LLGo already gives every such +// allocation the same permitted non-nil sentinel address. +// +// A non-synthetic function with a lexical parent is a source closure. +// Synthetic wrappers are deliberately excluded: a zero-sized method receiver +// can still carry a semantically significant nil/non-nil pointer value. +func (p *context) canElideZeroSizedClosureEnv(f *ssa.Function) bool { + if f == nil || f.Parent() == nil || f.Synthetic != "" || len(f.FreeVars) == 0 { + return false + } + for _, freeVar := range f.FreeVars { + if !p.isElidableZeroSizedFreeVar(freeVar) { + return false + } + } + return true +} + +func (p *context) isElidableZeroSizedFreeVar(freeVar *ssa.FreeVar) bool { + ptr, ok := types.Unalias(p.patchType(freeVar.Type())).Underlying().(*types.Pointer) + return ok && p.prog.SizeOf(p.type_(ptr.Elem(), llssa.InGo)) == 0 +} + +func (p *context) elidedZeroSizedFreeVar(b llssa.Builder, freeVar *ssa.FreeVar) llssa.Expr { + typ := p.type_(freeVar.Type(), llssa.InGo) + ptr := types.Unalias(p.patchType(freeVar.Type())).Underlying().(*types.Pointer) + addr := b.Alloc(p.type_(ptr.Elem(), llssa.InGo), true) + return b.Convert(typ, addr) } func isCgoExternSymbol(f *ssa.Function) bool { @@ -582,20 +615,42 @@ func (p *context) compileFuncDecl(pkg llssa.Package, f *ssa.Function) (llssa.Fun } fn := pkg.FuncOf(name) - if fn != nil && fn.HasBody() { - return fn, nil, goFunc - } - - var hasCtx = len(f.FreeVars) > 0 - if hasCtx { + hasFreeVars := len(f.FreeVars) > 0 + elideFreeVarEnv := p.canElideZeroSizedClosureEnv(f) + hasExplicitEnv := false + // ParsePkgSyntax is the sole //llgo:env extractor. Lowering only consumes + // its source-declaration cache; imported env entries use NewEnvFunc. + if decl, ok := f.Syntax().(*ast.FuncDecl); ok { + fullName, _ := astFuncName(llssa.PathOf(pkgTypes), decl) + hasExplicitEnv = p.prog.HasClosureEnvDirective(p.goProg.Fset, fullName, decl.Pos()) + } + hasCtx := hasFreeVars && !elideFreeVarEnv || hasExplicitEnv + var ctx *types.Var + if elideFreeVarEnv { + dbgInstrln("==> NewZeroSizedClosure", name, "type:", sig) + } else if hasFreeVars { dbgInstrln("==> NewClosure", name, "type:", sig) - ctx := makeClosureCtx(pkgTypes, f.FreeVars) - sig = llssa.FuncAddCtx(ctx, sig) + ctx = makeClosureCtx(pkgTypes, f.FreeVars) + } else if hasExplicitEnv { + dbgInstrln("==> NewEnvFunc", name, "type:", sig) + ctx = types.NewVar(token.NoPos, nil, "$env", types.Typ[types.UnsafePointer]) } else { dbgInstrln("==> NewFunc", name, "type:", sig.Recv(), sig, "ftype:", ftype) } + if fn != nil { + if fn.NeedsEnv() != hasCtx { + panic("conflicting closure environment ABI for " + name) + } + if fn.HasBody() { + return fn, nil, goFunc + } + } if fn == nil { - fn = pkg.NewFuncEx(name, sig, llssa.Background(ftype), hasCtx, p.needsLinkOnce(f)) + if hasCtx { + fn = pkg.NewEnvFunc(name, sig, llssa.Background(ftype), ctx, p.needsLinkOnce(f)) + } else { + fn = pkg.NewFuncEx(name, sig, llssa.Background(ftype), false, p.needsLinkOnce(f)) + } } noInlineDirective := hasNoInlineDirective(f) runtimeStackNoInline := needsRuntimeStackNoInline(pkgTypes, f) @@ -1481,7 +1536,11 @@ func (p *context) compileInstrOrValue(b llssa.Builder, iv instrOrValue, asValue ret = b.MakeMap(t, nReserve) case *ssa.MakeClosure: fn := p.compileValue(b, v.Fn) - bindings := p.compileValues(b, v.Bindings, 0) + var bindings []llssa.Expr + goFn, _ := v.Fn.(*ssa.Function) + if !p.canElideZeroSizedClosureEnv(goFn) { + bindings = p.compileValues(b, v.Bindings, 0) + } ret = b.MakeClosure(fn, bindings) case *ssa.TypeAssert: x := p.compileValue(b, v.X) @@ -1873,6 +1932,9 @@ func (p *context) compileValue(b llssa.Builder, v ssa.Value) llssa.Expr { fn := v.Parent() for idx, freeVar := range fn.FreeVars { if freeVar == v { + if p.canElideZeroSizedClosureEnv(fn) { + return p.elidedZeroSizedFreeVar(b, v) + } return p.fn.FreeVar(b, idx) } } diff --git a/cl/compile_test.go b/cl/compile_test.go index 2e61753a50..5eecf6cbd5 100644 --- a/cl/compile_test.go +++ b/cl/compile_test.go @@ -113,6 +113,8 @@ var embedTargetConfigs = []embedTargetConfig{ "./_testrt/tpfunc", // unexpected output: type size mismatch (got 8 4 4, expected 16 8 8) "./_testrt/typalias", // fast fail: build constraints exclude all Go files "./_testrt/unreachable", // timeout: emulator panic (Instruction access fault), no auto-exit + + "./_testrt/reflectclosureenv", // baseline embedded runtime cannot build this reflect path }, "./_testdata": { "./_testdata/debug", // llgo panic: unsatisfied import internal/runtime/sys @@ -155,6 +157,8 @@ var embedTargetConfigs = []embedTargetConfig{ "./_testrt/struct", // panic: runtime index out of range "./_testrt/tpfunc", // unexpected output "./_testrt/typalias", // panic: runtime index out of range + + "./_testrt/reflectclosureenv", // baseline embedded runtime cannot build this reflect path }, "./_testdata": { "./_testdata/cpkgimp", // unexpected output diff --git a/cl/import.go b/cl/import.go index 85e4cfc9fd..728d162049 100644 --- a/cl/import.go +++ b/cl/import.go @@ -276,19 +276,33 @@ func (p *context) collectSkip(line string, prefix int) { } } -func collectLinknameByDoc(prog llssa.Program, doc *ast.CommentGroup, fullName, inPkgName string) { +// collectDeclarationDirectives caches source metadata needed after the syntax +// pass. funcPos is token.NoPos for non-function declarations. +func collectDeclarationDirectives(prog llssa.Program, fset *token.FileSet, doc *ast.CommentGroup, fullName, inPkgName string, funcPos token.Pos) { directives := directive.ParseGroup(doc) + linkCollected := false + hasClosureEnv := false for n := len(directives) - 1; n >= 0; n-- { - directive := directives[n] - if directive.Name != "go:linkname" && directive.Name != "llgo:link" { - continue - } - fields := strings.Fields(directive.Args) - if len(fields) >= 2 && fields[0] == inPkgName { - prog.SetLinkname(fullName, strings.Join(fields[1:], " ")) - return + item := directives[n] + switch item.Name { + case "go:linkname", "llgo:link": + if linkCollected { + continue + } + fields := strings.Fields(item.Args) + if len(fields) >= 2 && fields[0] == inPkgName { + prog.SetLinkname(fullName, strings.Join(fields[1:], " ")) + linkCollected = true + } + case "llgo:env": + if funcPos.IsValid() { + hasClosureEnv = true + } } } + if hasClosureEnv { + prog.SetClosureEnvDirective(fset, fullName, funcPos) + } } func (p *context) processLinknameByDoc(doc *ast.CommentGroup, fullName, inPkgName string, isVar, allowExport bool) bool { @@ -563,6 +577,7 @@ const ( llgoAtomicCmpXchgOK = llgoInstrBase + 0x45 llgoAtomicAddReturnNew = llgoInstrBase + 0x46 llgoBoolToUint8 = llgoInstrBase + 0x47 + llgoClosureEnv = llgoInstrBase + 0x48 llgoAtomicOpLast = llgoAtomicOpBase + int(llssa.OpUMin) ) @@ -773,14 +788,14 @@ func ParsePkgSyntax(prog llssa.Program, fset *token.FileSet, pkg *types.Package, return err } fullName, inPkgName := astFuncName(pkgPath, decl) - collectLinknameByDoc(prog, decl.Doc, fullName, inPkgName) + collectDeclarationDirectives(prog, fset, decl.Doc, fullName, inPkgName, decl.Pos()) ctx.processNoInterfaceByDoc(decl.Doc, fullName) case *ast.GenDecl: if decl.Tok == token.VAR { if len(decl.Specs) == 1 { if names := decl.Specs[0].(*ast.ValueSpec).Names; len(names) == 1 { inPkgName := names[0].Name - collectLinknameByDoc(prog, decl.Doc, pkgPath+"."+inPkgName, inPkgName) + collectDeclarationDirectives(prog, fset, decl.Doc, pkgPath+"."+inPkgName, inPkgName, token.NoPos) } } vars, err := locality.ScanPackageVar(fset, decl) diff --git a/cl/import_coverage_test.go b/cl/import_coverage_test.go index 4afa5b0110..ce11dbf1b8 100644 --- a/cl/import_coverage_test.go +++ b/cl/import_coverage_test.go @@ -251,20 +251,59 @@ func TestParsePkgSyntaxCollectsLinknames(t *testing.T) { }) } prog := llssa.NewProgram(nil) - collectLinknameByDoc(prog, &ast.CommentGroup{List: []*ast.Comment{{Text: "//go:linkname Other C.other"}}}, llssa.PkgRuntime+".Sigsetjmp", "Sigsetjmp") + collectDeclarationDirectives(prog, nil, &ast.CommentGroup{List: []*ast.Comment{{Text: "//go:linkname Other C.other"}}}, llssa.PkgRuntime+".Sigsetjmp", "Sigsetjmp", token.NoPos) if _, ok := prog.Linkname(llssa.PkgRuntime + ".Sigsetjmp"); ok { t.Fatal("mismatched linkname was collected") } } -func TestCollectLinknameByDocIgnoresOtherDirectives(t *testing.T) { +func TestParsePkgSyntaxCollectsClosureEnvDirectives(t *testing.T) { + const src = `package p +//go:linkname env C.old +//llgo:env +//go:linkname env C.new +func env() {} + +// llgo:env +func spaced() {} + +func plain() {} +` + fset := token.NewFileSet() + file, err := parser.ParseFile(fset, "p.go", src, parser.ParseComments) + if err != nil { + t.Fatal(err) + } + prog := llssa.NewProgram(nil) + pkg := types.NewPackage("example.com/p", "p") + if err := ParsePkgSyntax(prog, fset, pkg, []*ast.File{file}); err != nil { + t.Fatal(err) + } + if link, ok := prog.Linkname("example.com/p.env"); !ok || link != "C.new" { + t.Fatalf("combined declaration linkname = (%q, %v), want (C.new, true)", link, ok) + } + want := map[string]bool{"env": true, "spaced": true, "plain": false} + for _, node := range file.Decls { + decl := node.(*ast.FuncDecl) + fullName, _ := astFuncName(pkg.Path(), decl) + got := prog.HasClosureEnvDirective(fset, fullName, decl.Pos()) + if got != want[decl.Name.Name] { + t.Fatalf("HasClosureEnvDirective(%s) = %v, want %v", decl.Name.Name, got, want[decl.Name.Name]) + } + } + if prog.HasClosureEnvDirective(fset, "example.com/p.missing", token.NoPos) { + t.Fatal("missing declaration unexpectedly has cached directives") + } +} + +func TestCollectDeclarationDirectivesIgnoresOtherDirectives(t *testing.T) { prog := llssa.NewProgram(nil) doc := &ast.CommentGroup{List: []*ast.Comment{ {Text: "//go:noinline"}, {Text: "//llgo:tls"}, }} const fullName = "example.com/p.Value" - collectLinknameByDoc(prog, doc, fullName, "Value") + collectDeclarationDirectives(prog, nil, doc, fullName, "Value", token.NoPos) if _, ok := prog.Linkname(fullName); ok { t.Fatal("non-link directives installed a linkname") } diff --git a/cl/instr.go b/cl/instr.go index 7e091eee82..4b52624f1b 100644 --- a/cl/instr.go +++ b/cl/instr.go @@ -599,6 +599,7 @@ var llgoInstrs = map[string]int{ "skip": llgoSkip, "syscall": llgoSyscall, "boolToUint8": llgoBoolToUint8, + "closureEnv": llgoClosureEnv, "pystr": llgoPyStr, "pyList": llgoPyList, "pyTuple": llgoPyTuple, @@ -665,6 +666,8 @@ func (p *context) funcOf(fn *ssa.Function) (aFn llssa.Function, pyFn llssa.PyObj return nil, nil, ignoredFunc } sig := p.patchType(fn.Signature).(*types.Signature) + // Source env-bearing bodies are created by compileFuncDecl before + // lowering. Imported declarations cannot reconstruct //llgo:env. aFn = pkg.NewFuncEx(name, sig, llssa.Background(ftype), false, p.needsLinkOnce(fn)) if disableInline { aFn.Inline(llssa.NoInline) @@ -2072,6 +2075,11 @@ func (p *context) callEx(b llssa.Builder, act llssa.DoAction, call *ssa.CallComm ret = b.Do(act, llssa.Nil, func(b llssa.Builder, _ llssa.Expr, args ...llssa.Expr) llssa.Expr { return p.boolToUint8(b, args) }, args...) + case llgoClosureEnv: + if len(args) != 0 || p.fn == nil || !p.fn.NeedsEnv() { + panic("closureEnv(): called outside an env-bearing function") + } + ret = p.fn.Env() case llgoUnreachable: // func unreachable() b.Unreachable() case llgoAtomicLoad: @@ -2111,12 +2119,34 @@ func (p *context) callEx(b llssa.Builder, act llssa.DoAction, call *ssa.CallComm } default: fn := p.compileValue(b, cv) - args := p.compileValues(b, args, kind) + args := p.compileDynamicCallValues(b, call, kind) ret = p.emitDo(b, act, ds, fn, llssa.Builder.Call, args...) } return } +func (p *context) compileDynamicCallValues(b llssa.Builder, call *ssa.CallCommon, hasVArg int) []llssa.Expr { + args := p.compileValues(b, call.Args, hasVArg) + params := call.Signature().Params() + n := min(len(call.Args)-hasVArg, params.Len()) + for i, arg := range call.Args[:n] { + want := params.At(i).Type() + if needsNamedClosureChange(arg.Type(), want) { + args[i] = b.ChangeType(p.type_(want, llssa.InGo), args[i]) + } + } + return args +} + +func needsNamedClosureChange(got, want types.Type) bool { + if types.Identical(got, want) { + return false + } + _, gotIsFunc := got.Underlying().(*types.Signature) + _, wantIsFunc := want.Underlying().(*types.Signature) + return gotIsFunc && wantIsFunc && types.Identical(got.Underlying(), want.Underlying()) +} + func (p *context) reflectTypeMethodCheck(call *ssa.CallCommon, method *types.Func) (check llssa.ReflectMethodCheck) { if !isReflectType(call.Value.Type()) { return diff --git a/cl/named_closure_internal_test.go b/cl/named_closure_internal_test.go new file mode 100644 index 0000000000..bfc106fa3c --- /dev/null +++ b/cl/named_closure_internal_test.go @@ -0,0 +1,72 @@ +//go:build !llgo + +package cl + +import ( + "go/token" + "go/types" + "testing" + + "github.com/xgo-dev/llvm" +) + +func TestNeedsNamedClosureChange(t *testing.T) { + pkg := types.NewPackage("example.com/p", "p") + params := types.NewTuple(types.NewParam(token.NoPos, pkg, "value", types.Typ[types.Int])) + results := types.NewTuple(types.NewParam(token.NoPos, pkg, "", types.Typ[types.Bool])) + sig := types.NewSignatureType(nil, nil, nil, params, results, false) + named := types.NewNamed(types.NewTypeName(token.NoPos, pkg, "Func", nil), sig, nil) + different := types.NewSignatureType(nil, nil, nil, nil, results, false) + + tests := []struct { + name string + got types.Type + want types.Type + ok bool + }{ + {name: "anonymous to named", got: sig, want: named, ok: true}, + {name: "named to anonymous", got: named, want: sig, ok: true}, + {name: "identical named", got: named, want: named}, + {name: "different signatures", got: different, want: named}, + {name: "non functions", got: types.Typ[types.Int], want: types.Typ[types.Int64]}, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + if got := needsNamedClosureChange(tt.got, tt.want); got != tt.ok { + t.Fatalf("needsNamedClosureChange(%v, %v) = %v, want %v", tt.got, tt.want, got, tt.ok) + } + }) + } +} + +func TestNamedClosureValuesKeepTheirDeclaredType(t *testing.T) { + const source = `package main + +type Func func(int) bool + +func call(fn Func) bool { return fn(1) } + +func direct() bool { + want := 1 + return call(func(got int) bool { return got == want }) +} + +func iterator() func(Func) { + return func(yield Func) { _ = yield(1) } +} + +func ranged() int { + n := 0 + for range iterator() { n++ } + return n +} + +func main() { + if !direct() || ranged() != 1 { panic("named closure conversion failed") } +} +` + _, module := mustCompileLLPkgFromSrc(t, source) + if err := llvm.VerifyModule(module, llvm.ReturnStatusAction); err != nil { + t.Fatalf("named closure module is invalid: %v\n%s", err, module.String()) + } +} diff --git a/cl/rewrite_internal_test.go b/cl/rewrite_internal_test.go index ce5d370d33..235de50269 100644 --- a/cl/rewrite_internal_test.go +++ b/cl/rewrite_internal_test.go @@ -27,6 +27,10 @@ func init() { } func compileWithRewrites(t *testing.T, src string, rewrites map[string]string) string { + return compileWithRewritesTarget(t, src, rewrites, nil) +} + +func compileWithRewritesTarget(t *testing.T, src string, rewrites map[string]string, target *llssa.Target) string { t.Helper() fset := token.NewFileSet() file, err := parser.ParseFile(fset, "rewrite.go", src, parser.ParseComments) @@ -40,8 +44,12 @@ func compileWithRewrites(t *testing.T, src string, rewrites map[string]string) s if err != nil { t.Fatalf("build package failed: %v", err) } - prog := ssatest.NewProgramEx(t, nil, importer) - prog.TypeSizes(types.SizesFor("gc", runtime.GOARCH)) + prog := ssatest.NewProgramEx(t, target, importer) + goarch := runtime.GOARCH + if target != nil && target.GOARCH != "" { + goarch = target.GOARCH + } + prog.TypeSizes(types.SizesFor("gc", goarch)) ret, _, err := NewPackageEx(prog, nil, rewrites, pkg, []*ast.File{file}) if err != nil { t.Fatalf("NewPackageEx failed: %v", err) @@ -49,6 +57,77 @@ func compileWithRewrites(t *testing.T, src string, rewrites map[string]string) s return ret.String() } +func TestClosureEnvIntrinsicRequiresEnvBearingEntry(t *testing.T) { + valid := `package closureenv + +import "unsafe" + +//go:linkname closureEnv llgo.closureEnv +func closureEnv() unsafe.Pointer + +DIRECTIVE +func use() unsafe.Pointer { return closureEnv() } +` + for _, spelling := range []string{"//llgo:env", "// llgo:env"} { + t.Run(spelling, func(t *testing.T) { + ir := compileWithRewrites(t, strings.Replace(valid, "DIRECTIVE", spelling, 1), nil) + if !strings.Contains(ir, `define ptr @closureenv.use(ptr `) || + !strings.Contains(ir, `ret ptr %0`) || + (!strings.Contains(ir, `ptr nest %0`) && !strings.Contains(ir, `ptr swiftself %0`)) { + t.Fatalf("closureEnv intrinsic did not return the physical environment:\n%s", ir) + } + }) + } + + for _, test := range []struct { + name string + src string + }{ + { + name: "plain entry", + src: `package closureenv +import "unsafe" +//go:linkname closureEnv llgo.closureEnv +func closureEnv() unsafe.Pointer +func use() unsafe.Pointer { return closureEnv() } +`, + }, + { + name: "arguments", + src: `package closureenv +import "unsafe" +//go:linkname closureEnv llgo.closureEnv +func closureEnv(int) unsafe.Pointer +//llgo:env +func use() unsafe.Pointer { return closureEnv(1) } +`, + }, + } { + t.Run(test.name, func(t *testing.T) { + mustPanic(t, "invalid closureEnv intrinsic", func() { + compileWithRewrites(t, test.src, nil) + }) + }) + } +} + +func TestClosureEnvRejectsConflictingEntryABI(t *testing.T) { + const src = `package closureenv + +import _ "unsafe" + +//go:linkname plain closureenv.entry +func plain() {} + +//go:linkname withEnv closureenv.entry +//llgo:env +func withEnv() {} +` + mustPanic(t, "conflicting closure environment ABI", func() { + compileWithRewrites(t, src, nil) + }) +} + func assertNoStoreToGlobal(t *testing.T, ir, global string) { t.Helper() for _, line := range strings.Split(ir, "\n") { diff --git a/cl/zero_size_deref_test.go b/cl/zero_size_deref_test.go index 6ece9780ea..48de2b8d67 100644 --- a/cl/zero_size_deref_test.go +++ b/cl/zero_size_deref_test.go @@ -6,6 +6,8 @@ package cl import ( "strings" "testing" + + llssa "github.com/goplus/llgo/ssa" ) func TestZeroSizedFieldDerefEmitsBaseNilGuard(t *testing.T) { @@ -23,3 +25,49 @@ func Eq(p, q *T) bool { t.Fatalf("zero-sized field comparison should guard field bases and loads, got %d guards:\n%s", got, ir) } } + +func TestZeroSizedSourceClosureElidesEnvironment(t *testing.T) { + const src = `package zeroclosure + +func makeValue() (func() *struct{}, *struct{}) { + value := struct{}{} + return func() *struct{} { return &value }, &value +} + +func compareLocal() bool { + value := struct{}{} + closure := func() *struct{} { return &value } + return closure() == &value +} + +func keepPointer(pointer *struct{}) func() bool { + return func() bool { return pointer == nil } +} +` + targets := []struct { + name string + target *llssa.Target + }{ + {name: "native"}, + {name: "wasm-explicit", target: &llssa.Target{GOOS: "wasip1", GOARCH: "wasm"}}, + } + for _, target := range targets { + t.Run(target.name, func(t *testing.T) { + ir := compileWithRewritesTarget(t, src, nil, target.target) + for _, want := range []string{ + `{ ptr @"zeroclosure.makeValue$1", ptr null }`, + `define ptr @"zeroclosure.makeValue$1"()`, + `define ptr @"zeroclosure.compareLocal$1"()`, + `ret ptr @"__llgo.moduleZeroSizedAlloc$"`, + } { + if !strings.Contains(ir, want) { + t.Fatalf("zero-sized source closure did not elide its environment; missing %q:\n%s", want, ir) + } + } + if !strings.Contains(ir, `define i1 @"zeroclosure.keepPointer$1"(ptr `) || + !strings.Contains(ir, `@"zeroclosure.keepPointer$1", ptr undef`) { + t.Fatalf("captured pointer value incorrectly lost its environment:\n%s", ir) + } + }) + } +} diff --git a/doc/_readme/scripts/install_ubuntu.sh b/doc/_readme/scripts/install_ubuntu.sh index d909bca527..62476e355e 100644 --- a/doc/_readme/scripts/install_ubuntu.sh +++ b/doc/_readme/scripts/install_ubuntu.sh @@ -2,7 +2,7 @@ echo "deb http://apt.llvm.org/$(lsb_release -cs)/ llvm-toolchain-$(lsb_release -cs)-19 main" | sudo tee /etc/apt/sources.list.d/llvm.list wget -O - https://apt.llvm.org/llvm-snapshot.gpg.key | sudo apt-key add - sudo apt-get update -sudo apt-get install -y llvm-19-dev clang-19 libclang-19-dev lld-19 libunwind-19-dev libc++-19-dev pkg-config libgc-dev libssl-dev zlib1g-dev libcjson-dev libsqlite3-dev libuv1-dev +sudo apt-get install -y llvm-19-dev clang-19 libclang-19-dev lld-19 libunwind-19-dev libc++-19-dev pkg-config libgc-dev libssl-dev zlib1g-dev libffi-dev libcjson-dev libsqlite3-dev libuv1-dev sudo apt-get install -y python3.12-dev # optional #curl https://raw.githubusercontent.com/xgo-dev/llgo/refs/heads/main/install.sh | bash ./install.sh diff --git a/doc/closure.md b/doc/closure.md index 3191b7ce8c..50ae7d842f 100644 --- a/doc/closure.md +++ b/doc/closure.md @@ -1,84 +1,132 @@ -# Closure Implementation Notes - -This document describes the current LLGo SSA closure implementation. - -## Goals - -- Keep function values pointing to **real symbols** (no global stub for every - closure). For non-ctx functions, a thin `__llgo_stub` wrapper is used as the - callable symbol. -- Preserve a `funcval`-like layout: `{fn, data}`. -- Use an explicit `ctx` parameter in the call ABI (no runtime branching); - adaptation happens at conversion time via wrappers. - -## Representation - -Closures are lowered to a 2-field struct: - -``` -{ fn: *func, data: unsafe.Pointer } -``` - -- `fn` is always a function whose signature **includes** a `__llgo_ctx` - parameter. -- `data` is: - - `nil` for plain functions or wrappers that ignore ctx. - - a pointer to a heap-allocated context for free variables. - - a pointer to a heap cell that stores a function pointer (for `func` values - represented as raw function pointers). - -## Calling a Closure - -Calls to **closure values** always emit: - +# Closure ABI + +This document records the phase-one design from +[proposal #2170](https://github.com/xgo-dev/llgo/issues/2170). + +## Decisions + +- Keep the existing two-word function value: `{fn, env}`. This change does not + add flags or switch to Go's one-pointer funcval layout. +- A Go/go-types function signature never contains an environment parameter. + `llssa.Function` records independently whether its physical entry needs env. +- Plain Go functions and C functions use `{real entry, nil}`. Closures and + bound method wrappers use `{real entry, non-nil env}`. +- `env == nil` means that the physical entry has no env parameter. A source + closure whose captures are all zero-sized is reclassified as a no-env entry; + it recreates their permitted shared non-nil address from the module sentinel. + Other required environments never use nil. A nil pointer receiver method + value is represented by an allocated environment cell, and an interface + method value captures the complete interface state. +- A statically known call uses the entry's `NeedsEnv` property. An + explicit-context dynamic funcval call (including WebAssembly) branches once + on `env != nil` and emits two exact LLVM call edges: `fn(args...)` and + `fn(env, args...)`. +- Native hidden env parameters use LLVM `nest` or `swiftself` parameter + attributes. WebAssembly and architectures without a validated LLVM + hidden-register mapping use an explicit physical env parameter, but only on + env-bearing entries. +- Direct interface invocation remains a transient `(method entry, receiver)` + operation. Its receiver is an ordinary ABI argument; first-class interface + method values are lowered through the normal bound-wrapper closure path. +- Function values point directly at their physical entries; closure calls do + not add a generated adapter layer. C function values point directly at the C + entry. +- PCLN metadata remains function-centric. A compiler-generated wrapper or + adapter, if one is needed for another purpose, is an ordinary function with + its own function record; closure environment transport is not part of PCLN. + +Native dynamic calls always use one hidden-env call edge, including when env is +nil. An optimizer barrier keeps the indirect code pointer opaque: LLVM IR +considers `R(ptr nest, args...)` and `R(args...)` different prototypes and must +not devirtualize a plain entry into the hidden-env call edge. The barrier emits +no machine instruction. + +The backend selects this ABI from the resolved LLVM target triple, not from +`GOARCH`. `GOOS/GOARCH` select Go source files and type sizes, but named targets +may intentionally reuse a compatible Go architecture: for example, +`wasm-unknown`, `wasip2`, Xtensa, AVR, and some RISC-V targets use `GOARCH=arm` +while emitting a different physical architecture. The triple is what LLVM uses +to assign `nest`/`swiftself` registers. + +## Physical entry ABI + +An env-bearing entry is created from the semantic signature plus one backend +parameter: + +```text +semantic: R func(A, B) +physical: R entry(env, A, B) ``` -fn(ctx, args...) -``` - -There is no runtime `ctx==nil` check and no sentinel. Any function value that -does not naturally accept a ctx is adapted at conversion time (see below). - -## Function Value -> Closure Wrappers - -To keep the explicit-ctx ABI while avoiding mismatched calls: - -- **Function declarations** without ctx are wrapped by a thin adapter: - - Name: `__llgo_stub.` - - Signature: `func(__llgo_ctx unsafe.Pointer, args...)` - - Body: ignores ctx, calls the original function. - - Linkage: `linkonce` -- **Function pointers** use a generic wrapper: - - Name: `__llgo_stub._llgo_func$` - - Signature: `func(__llgo_ctx unsafe.Pointer, args...)` - - Body: treats `__llgo_ctx` as a pointer to a stored function pointer, loads - it, and calls it. - - Linkage: `linkonce` - - Note: the ctx pointer is guaranteed non-nil for this wrapper; we do not - emit runtime null checks. - -This is the only remaining use of the `__llgo_stub.` prefix; it is no longer -used to generate a global stub for every closure. - -## Interface Method Values - -Interface method signatures in `go/types` include a receiver. When turning an -interface method into a closure: - -- The receiver parameter is dropped from the closure signature. -- The resulting closure is built with `{fn, data}` and will be wrapped if it - does not already accept `__llgo_ctx`. - -## Covered Scenarios - -- Plain functions (no free variables). -- Closures with captured variables (`__llgo_ctx`). -- Method values / method expressions. -- Interface method values (receiver dropped). -- Variadic functions (`__llgo_va_list`). -- `go:linkname` to C (`C.xxx`) and `llgo:type C` callback parameters. -- `defer` / `go` invocation of closure values. -- `FuncPCABI0` points at the real symbol (wrappers only for ctx adaptation). - -## Notes / Limitations -- Python closures are intentionally out of scope for now. +The physical env parameter is: + +- `nest` on validated x86, RISC-V, and AArch64 platforms where X18 is + available; +- `swiftself` on ARM and platforms where AArch64 X18 is reserved; +- an ordinary leading parameter on the explicit fallback. + +Windows follows the architecture-selected ABI even though LLGo does not yet +support the OS: x86 uses `nest`, while ARM/AArch64 use `swiftself`. The x86 +libffi Go ABI already matches LLVM `nest`; the Windows ARM/AArch64 public-FFI +final hop remains a TODO. This keeps compiled closure entries independent of +when runtime support is added. + +WebAssembly remains explicit because it has no compatible hidden-register +transport. Adding one in the future is a deliberate target ABI upgrade. + +LLVM parameter attributes are preserved when LLGo rewrites large aggregate +returns or lowers its C ABI. + +## FFI and reflection + +`reflect.Value.Call` starts from the semantic libffi signature: + +- explicit env target: add the env type/value only when `env != nil`; otherwise + use the semantic signature. This is the only `env != nil` decision in the + reflection/FFI path; +- native hidden env target: x86, RISC-V, and AArch64 targets where X18 is + available use libffi's `ffi_call_go` directly when libffi exposes that API, + because its static-chain register is LLGo's `nest` register. ARM also uses + `ffi_call_go`; a short final-hop bridge moves libffi's IP/R12 context to + `swiftself`/R10 without saving argument registers or using TLS. LLVM lowers + ARM32 `nest` as an ordinary leading argument rather than a hidden static + chain, so it cannot replace this `swiftself` bridge. +- x86 libffi builds without `FFI_GO_CLOSURES`, including Apple SDK libffi, use + stock `ffi_call` plus the TLS final-hop trampoline, which installs LLVM's + `nest` register before entering the real target. +- Apple/Android AArch64 use stock `ffi_call` plus the TLS final-hop trampoline: + libffi's Go ABI uses X18 while LLGo's entry ABI uses `swiftself`/X20, so the + public `ffi_call` path needs TLS to carry `{fn, env}` to its final target. + +The build obtains both headers and linker flags from `pkg-config libffi`; no +Homebrew-specific libffi path is required. Apple AArch64 remains on the X20 TLS +trampoline because libffi's Go ABI uses X18 while LLGo's selected entry ABI +uses `swiftself`/X20 there. + +Every architecture that selects a hidden env must select exactly one native +FFI final hop: direct `ffi_call_go`, `ffi_call_go` plus a register bridge, or +public `ffi_call` plus a TLS trampoline. The wrapper rejects missing or +ambiguous selections at compile time. + +Bridge calls are balanced: their targets must return normally through the +final hop so saved registers and, where used, the prior TLS context are +restored. + +Although libffi's C implementation of `ffi_call_go` is a thin wrapper, it calls +an architecture-private `ffi_call_int(..., closure)` and matching assembly; it +cannot be reproduced outside libffi by wrapping public `ffi_call` alone. The +compile-time direct path and the public-API fallback require neither a patched +libffi nor rebuilding it. AArch64 libffi's Go ABI writes X18, so Apple/Android +`swiftself`/X20 deliberately uses the public-call fallback. `reflect.MakeFunc` +remains a normal libffi C closure: its funcval has `env == nil`, while libffi +userdata owns the callback state separately. + +## Scope + +This phase includes closure creation/calls, method values, C function values, +ABI rewriting, reflection, FFI, and direct-entry function values. + +It deliberately excludes: + +- a WebAssembly TLS/mutable-global optimization for `g.ctxt`; +- flags or a future one-pointer funcval representation. diff --git a/doc/design/pclntab-linkphase.md b/doc/design/pclntab-linkphase.md index cbbbaf776e..d426ad15bd 100644 --- a/doc/design/pclntab-linkphase.md +++ b/doc/design/pclntab-linkphase.md @@ -36,12 +36,20 @@ clang/lld and a plugin would need to be maintained per linker flavor (ld64.lld, ld.lld) and per LTO mode. Editing the linked artifact is linker-agnostic. +### Function identity contract + +PCLN is indexed by physical text functions, following Go's linker model. +Source functions and compiler-generated wrappers or adapters all contribute +ordinary function records and entry sites. The symbol names the physical +function; its display name may describe the corresponding Go operation. +Calling conventions, closure environments, and their transport mechanism are +not PCLN properties and must not introduce function-class-specific sections. + ### Data flow 1. **Parse** the linked binary's metadata sections (`debug/elf`, `debug/macho` from the Go stdlib — the tool runs on the host): - `llgo_funcinfo_entry` / `__DATA,__llgo_fie`: `{pc, symbolID}` records. - - `llgo_funcinfo_stubsite` / `__DATA,__llgo_stub`: same layout. - Zero records are skipped, as in the runtime today. 2. **Dedup by symbolID**: LTO inline copies register the same symbolID at several PCs. The true entry is the record whose PC lies inside the text @@ -55,24 +63,19 @@ linker-agnostic. faithful port of `cmd/link`'s algorithm that has been sitting unwired since #2012. Delta overflow is a hard error here, mirroring Go's linker; if it ever fires, fall back to leaving the prebuilt table absent. -5. **Write back** into a reserved section: - - The main module already emits `__llgo_funcinfo_*` globals; add a - `__llgo_pclntab_prebuilt` global sized from the collected package data - (entry-record count is known at main-module emission time; LTO can only - shrink it after dedup) plus a header {magic, version, count, anchorOff}. - - The tool rewrites the section contents in place (same size or smaller; - unused tail is zeroed) and flips the header magic to "valid". +5. **Write back** into the entry-site section: + - The tool replaces the raw entry records in place with a versioned prebuilt + functab/findfunctab blob; unused tail bytes are zeroed. + - If the blob does not fit, the binary is left unchanged and the runtime + uses its first-use construction fallback. No other class of function is + used as overflow storage. ### ASLR -Stored PCs must survive load-time slide. Store **offsets relative to an -anchor symbol** (`__llgo_pclntab_anchor`, placed in the same section). At -startup the runtime computes `slide = &anchor_runtime - anchorOff_stored` -and adds it during lookup (one add on the hot path, same as Go's -`datap.text` bias). Note the entry-site records themselves are already -rebased by the loader (they hold absolute pointers with relocations); the -prebuilt table deliberately holds offsets so the tool does not need to -emit relocations. +Stored table entries are offsets from the first function PC. The header keeps +that base as a runtime address: Mach-O rewrites its slot into the dyld chained +fixup chain, while supported non-PIE ELF outputs already use their runtime +address. The lookup hot path therefore only adds the stored entry offset. ### Runtime integration @@ -93,9 +96,8 @@ change is strictly additive and safe to land incrementally. platforms; assert `llgo funcinfo: ... entries= prebuilt` via LLGO_FUNCINFO_DEBUG. - **P3** (done) Mach-O bind-record resolution: pointer slots naming exported - functions — every `__llgo_stub.*` and any exported Go function — are - chained-fixup BIND nodes, not rebases; without decoding them through the - imports table, all stub records miss the prebuilt ftab and function-value + Go functions are chained-fixup BIND nodes, not rebases; without decoding + them through the imports table, exported records miss the prebuilt ftab and `FuncForPC` silently pays a dladdr per fresh pc (~6µs). Also: the prebuilt header's base slot is spliced back into the fixup chain as a live rebase node, so the runtime reads a dyld-slid runtime PC directly (no slide diff --git a/doc/design/pclntab-packaging.md b/doc/design/pclntab-packaging.md index 8fea3325be..782c13e31a 100644 --- a/doc/design/pclntab-packaging.md +++ b/doc/design/pclntab-packaging.md @@ -169,6 +169,7 @@ the filesystem is never probed repeatedly. The initial implementation uses one bounded read, capped at 512 MiB, instead of `mmap`; read-only mapping remains a possible follow-up optimization. -The initial format is intentionally private to LLGo and versioned. It may grow -additional independently removable symbol classes after the PCLN path has -proved stable on ELF and Mach-O. +The format is intentionally private to LLGo and versioned. Its unit is a +physical function: compiler-generated wrappers and adapters use ordinary +function records, while calling conventions and closure environment transport +remain outside PCLN. diff --git a/doc/size-report.md b/doc/size-report.md index 2cb9799d49..451004ceea 100644 --- a/doc/size-report.md +++ b/doc/size-report.md @@ -28,9 +28,9 @@ document captures the parsing strategy and new aggregation controls. | `module`* | Default. Groups by `pkg.Module.Path` (or `pkg.PkgPath` if the module is nil). | Matching is performed by checking whether the demangled symbol name begins with -`pkg.PkgPath + "."`. Symbols that do not match any package and contain `llgo` are -bucketed into `llgo-stubs`; other unmatched entries keep their original owner -names so we can inspect them later. +`pkg.PkgPath + "."`. Unmatched entries keep the owner derived from their symbol +name so compiler-generated functions remain visible as ordinary functions +rather than being grouped by an implementation-specific category. Defaults: diff --git a/internal/abi/large.go b/internal/abi/large.go index b1da090581..63548276d3 100644 --- a/internal/abi/large.go +++ b/internal/abi/large.go @@ -86,6 +86,7 @@ func (l largeAggregateLowerer) transformCall(m llvm.Module, call llvm.Value) { } newCall := llvm.CreateCall(b, newType, call.CalledValue(), params) newCall.AddCallSiteAttribute(1, sretAttribute(ctx, retType)) + copyClosureEnvCallAttrs(call, newCall, 1) if !reflectMethodByName.IsNil() { newCall.AddCallSiteAttribute(-1, reflectMethodByName) } @@ -239,6 +240,17 @@ func sretAttribute(ctx llvm.Context, typ llvm.Type) llvm.Attribute { return ctx.CreateTypeAttribute(llvm.AttributeKindID("sret"), typ) } +func copyClosureEnvCallAttrs(from, to llvm.Value, paramOffset int) { + for i := 0; i < from.CalledFunctionType().ParamTypesCount(); i++ { + for _, name := range []string{"nest", "swiftself"} { + kind := llvm.AttributeKindID(name) + if attr := from.GetCallSiteEnumAttribute(i+1, kind); !attr.IsNil() { + to.AddCallSiteAttribute(i+1+paramOffset, attr) + } + } + } +} + func hasSingleUse(value, user llvm.Value) bool { use := value.FirstUse() return !use.IsNil() && use.User() == user && use.NextUse().IsNil() diff --git a/internal/abi/large_test.go b/internal/abi/large_test.go index 0f2df71ffe..0a9373dfcb 100644 --- a/internal/abi/large_test.go +++ b/internal/abi/large_test.go @@ -154,3 +154,86 @@ attributes #1 = { noinline } t.Fatalf("transformed module is invalid: %v\n%s", err, mod.String()) } } + +func TestLowerLargeAggregatePreservesClosureEnvAttribute(t *testing.T) { + const testIR = ` +%Large = type [65537 x i8] + +define %Large @callee(ptr nest %env) { +entry: + ret %Large zeroinitializer +} + +define %Large @calleeSwift(ptr swiftself %env) { +entry: + ret %Large zeroinitializer +} + +define void @caller(ptr %env) { +entry: + %unused = call %Large @callee(ptr nest %env) + %unusedSwift = call %Large @calleeSwift(ptr swiftself %env) + ret void +} +` + ctx := llvm.NewContext() + defer ctx.Dispose() + path := filepath.Join(t.TempDir(), "large_closure_env.ll") + if err := os.WriteFile(path, []byte(testIR), 0o644); err != nil { + t.Fatal(err) + } + buf, err := llvm.NewMemoryBufferFromFile(path) + if err != nil { + t.Fatal(err) + } + mod, err := ctx.ParseIR(buf) + if err != nil { + t.Fatal(err) + } + defer mod.Dispose() + td := llvm.NewTargetData("e-m:o-i64:64-i128:128-n32:64-S128") + defer td.Dispose() + + LowerLargeAggregates(td, mod) + + nest := llvm.AttributeKindID("nest") + callee := mod.NamedFunction("callee") + if attr := callee.GetEnumAttributeAtIndex(2, nest); attr.IsNil() { + t.Fatalf("large return lowering lost nest after inserting sret:\n%s", callee.String()) + } + if attr := callee.GetEnumAttributeAtIndex(1, nest); !attr.IsNil() { + t.Fatalf("large return lowering left nest on the new sret parameter:\n%s", callee.String()) + } + swiftself := llvm.AttributeKindID("swiftself") + calleeSwift := mod.NamedFunction("calleeSwift") + if attr := calleeSwift.GetEnumAttributeAtIndex(2, swiftself); attr.IsNil() { + t.Fatalf("large return lowering lost swiftself after inserting sret:\n%s", calleeSwift.String()) + } + + caller := mod.NamedFunction("caller") + var nestedCall, swiftselfCall llvm.Value + for block := caller.FirstBasicBlock(); !block.IsNil(); block = llvm.NextBasicBlock(block) { + for instruction := block.FirstInstruction(); !instruction.IsNil(); instruction = llvm.NextInstruction(instruction) { + if call := instruction.IsACallInst(); !call.IsNil() { + switch call.CalledValue().Name() { + case "callee": + nestedCall = call + case "calleeSwift": + swiftselfCall = call + } + } + } + } + if nestedCall.IsNil() { + t.Fatalf("large return lowering removed the callee call:\n%s", caller.String()) + } + if attr := nestedCall.GetCallSiteEnumAttribute(2, nest); attr.IsNil() { + t.Fatalf("large return call lowering lost nest after inserting sret:\n%s", caller.String()) + } + if swiftselfCall.IsNil() || swiftselfCall.GetCallSiteEnumAttribute(2, swiftself).IsNil() { + t.Fatalf("large return call lowering lost swiftself after inserting sret:\n%s", caller.String()) + } + if err := llvm.VerifyModule(mod, llvm.ReturnStatusAction); err != nil { + t.Fatalf("large-return closure-env module is invalid: %v\n%s", err, mod.String()) + } +} diff --git a/internal/build/build.go b/internal/build/build.go index 9607c9d00a..4e261c5c3f 100644 --- a/internal/build/build.go +++ b/internal/build/build.go @@ -397,7 +397,14 @@ func Build(inv Invocation) ([]Package, error) { } verbose := conf.Verbose patterns := slices.Clone(inv.Args) - tags := defaultBuildTags(conf.Goarch, conf.Target) + target := &llssa.Target{ + GOOS: conf.Goos, + GOARCH: conf.Goarch, + Target: conf.Target, + LLVMTarget: export.LLVMTarget, + OptLevel: conf.OptLevel, + } + tags := defaultBuildTags(conf.Goarch, conf.Target) + "," + target.ClosureEnvBuildTag() if conf.PCLNMode == PCLNExternal { // Select the optional runtime loader as part of the normal package // cache key. Embedded and none builds do not compile any loader or @@ -438,13 +445,6 @@ func Build(inv Invocation) ([]Package, error) { llssa.Initialize(llssa.InitAll) }) - target := &llssa.Target{ - GOOS: conf.Goos, - GOARCH: conf.Goarch, - Target: conf.Target, - OptLevel: conf.OptLevel, - } - prog := llssa.NewProgram(target) prog.DisableBoundsChecks(conf.DisableBoundsChecks) if conf.Mode != ModeGen { @@ -1368,11 +1368,9 @@ func linkMainPkg(ctx *context, pkg *packages.Package, pkgs []*aPackage, outputPa // Use a stable synthetic name to avoid confusing it with the real main package in traces/logs. var funcInfo []funcInfoRecord var pcLineInfo []pcLineRecord - var funcInfoStubs []funcInfoStubRecord if ctx.buildConf.PCLNMode != PCLNNone { funcInfo = prepareFuncInfoTableRecords(collectFuncInfo(linkedOrder), nil) pcLineInfo = collectPCLineInfo(linkedOrder) - funcInfoStubs = collectFuncInfoStubRecords(linkedOrder, funcInfo) } entryPkg := genMainModule(ctx, llssa.PkgRuntime, pkg, &genConfig{ rtInit: needRuntime, @@ -1383,7 +1381,6 @@ func linkMainPkg(ctx *context, pkg *packages.Package, pkgs []*aPackage, outputPa abiSymbols: linkedModuleGlobals(linkedOrder), funcInfo: funcInfo, pcLineInfo: pcLineInfo, - funcInfoStubs: funcInfoStubs, }) if ctx.buildConf.deadcodeDropEnabled() { if err := applyDeadcodeDropOverrides(linkedOrder, entryPkg, needRuntime, verbose); err != nil { @@ -1852,7 +1849,6 @@ func buildPkg(ctx *context, aPkg *aPackage, verbose bool) error { } } emitFuncInfoEntrySites(ctx, ret) - emitFuncInfoStubSites(ctx, ret) printCmds := ctx.shouldPrintCommands(verbose) cgoLLFiles, cgoLdflags, err := buildCgo(ctx, aPkg, aPkg.Package.Syntax, externs, printCmds) @@ -2459,7 +2455,7 @@ func IsFuncInfoEnabled() bool { // IsFuncInfoSitesEnabled controls the body-embedded site records // independently of the funcinfo tables (LLGO_FUNCINFO_SITES=0 keeps the -// metadata but drops entry/stub/pc-line inline-asm sites). Useful for +// metadata but drops entry and PC-line inline-asm sites). Useful for // isolating codegen perturbation caused by the in-body asm anchors. func IsFuncInfoSitesEnabled() bool { return isEnvOn(llgoFuncInfoSites, true) diff --git a/internal/build/funcinfo_table.go b/internal/build/funcinfo_table.go index b36aa29654..754f610455 100644 --- a/internal/build/funcinfo_table.go +++ b/internal/build/funcinfo_table.go @@ -37,12 +37,8 @@ const ( funcInfoHashMaskSymbol = "__llgo_funcinfo_hash_mask" funcInfoSymbolIndexSymbol = "__llgo_funcinfo_symbol_index" funcInfoSymbolIndexCountSymbol = "__llgo_funcinfo_symbol_index_count" - funcInfoStubIndexesSymbol = "__llgo_funcinfo_stub_indexes" - funcInfoStubCountSymbol = "__llgo_funcinfo_stub_count" funcInfoEntryStartPtrSymbol = "__llgo_funcinfo_entry_start" funcInfoEntryEndPtrSymbol = "__llgo_funcinfo_entry_end" - funcInfoStubSiteStartPtrSymbol = "__llgo_funcinfo_stubsite_start" - funcInfoStubSiteEndPtrSymbol = "__llgo_funcinfo_stubsite_end" pcLineTableSymbol = "__llgo_pcline_table" pcLineCountSymbol = "__llgo_pcline_count" pcSiteStartPtrSymbol = "__llgo_pcsite_start" @@ -55,8 +51,6 @@ const ( funcInfoStringOffsetsDataSymbol = "__llgo_funcinfo_string_offsets$data" funcInfoHashDataSymbol = "__llgo_funcinfo_hash$data" funcInfoSymbolIndexDataSymbol = "__llgo_funcinfo_symbol_index$data" - funcInfoStubIndexesDataSymbol = "__llgo_funcinfo_stub_indexes$data" - closureStubPrefix = "__llgo_stub." ) type funcInfoRecord struct { @@ -75,11 +69,6 @@ type pcLineRecord struct { column uint32 } -type funcInfoStubRecord struct { - symbol string - funcIndex uint32 -} - type funcInfoSymbolIndexRecord struct { symbolID uint64 funcIndex uint32 @@ -143,49 +132,6 @@ func collectPCLineInfo(pkgs []Package) []pcLineRecord { return out } -func collectFuncInfoStubRecords(pkgs []Package, records []funcInfoRecord) []funcInfoStubRecord { - if len(records) == 0 { - return nil - } - recordBySymbol := make(map[string]uint32, len(records)) - for i, rec := range records { - if rec.symbol != "" { - recordBySymbol[rec.symbol] = uint32(i + 1) - } - } - seen := make(map[string]funcInfoStubRecord) - for _, pkg := range pkgs { - if pkg == nil || pkg.LPkg == nil { - continue - } - fn := pkg.LPkg.Module().FirstFunction() - for !fn.IsNil() { - if fn.IsDeclaration() || fn.BasicBlocksCount() == 0 { - fn = llvm.NextFunction(fn) - continue - } - name := fn.Name() - if target, ok := strings.CutPrefix(name, closureStubPrefix); ok { - if idx := recordBySymbol[target]; idx != 0 { - seen[name] = funcInfoStubRecord{symbol: name, funcIndex: idx} - } - } - fn = llvm.NextFunction(fn) - } - } - if len(seen) == 0 { - return nil - } - out := make([]funcInfoStubRecord, 0, len(seen)) - for _, rec := range seen { - out = append(out, rec) - } - sort.Slice(out, func(i, j int) bool { - return out[i].symbol < out[j].symbol - }) - return out -} - func collectFuncInfoSymbolIndexRecords(records []funcInfoRecord) []funcInfoSymbolIndexRecord { if len(records) == 0 { return nil @@ -293,7 +239,7 @@ func readPCLineInfo(mod llvm.Module) []pcLineRecord { return out } -func emitFuncInfoTable(ctx *context, pkg llssa.Package, records []funcInfoRecord, pcLines []pcLineRecord, stubRecords []funcInfoStubRecord) { +func emitFuncInfoTable(ctx *context, pkg llssa.Package, records []funcInfoRecord, pcLines []pcLineRecord) { mod := pkg.Module() llvmCtx := mod.Context() i8Type := llvmCtx.Int8Type() @@ -325,10 +271,6 @@ func emitFuncInfoTable(ctx *context, pkg llssa.Package, records []funcInfoRecord llvm.PointerType(i8Type, 0), i64Type, }, false) - stubSiteRecordType := llvmCtx.StructType([]llvm.Type{ - llvm.PointerType(i8Type, 0), - i64Type, - }, false) pcSiteRecordType := llvmCtx.StructType([]llvm.Type{ llvm.PointerType(i8Type, 0), i64Type, @@ -340,8 +282,6 @@ func emitFuncInfoTable(ctx *context, pkg llssa.Package, records []funcInfoRecord pcSiteEndPtr := llvm.AddGlobal(mod, llvm.PointerType(pcSiteRecordType, 0), pcSiteEndPtrSymbol) entryStartPtr := llvm.AddGlobal(mod, llvm.PointerType(funcEntryRecordType, 0), funcInfoEntryStartPtrSymbol) entryEndPtr := llvm.AddGlobal(mod, llvm.PointerType(funcEntryRecordType, 0), funcInfoEntryEndPtrSymbol) - stubSiteStartPtr := llvm.AddGlobal(mod, llvm.PointerType(stubSiteRecordType, 0), funcInfoStubSiteStartPtrSymbol) - stubSiteEndPtr := llvm.AddGlobal(mod, llvm.PointerType(stubSiteRecordType, 0), funcInfoStubSiteEndPtrSymbol) stringsPtr := llvm.AddGlobal(mod, llvm.PointerType(i8Type, 0), funcInfoStringsSymbol) stringOffsetsPtr := llvm.AddGlobal(mod, llvm.PointerType(i32Type, 0), funcInfoStringOffsetsSymbol) stringCount := llvm.AddGlobal(mod, countType, funcInfoStringCountSymbol) @@ -354,8 +294,6 @@ func emitFuncInfoTable(ctx *context, pkg llssa.Package, records []funcInfoRecord // to relative dynamic relocations in the writable metadata section. symbolIndexPtr.SetVisibility(llvm.HiddenVisibility) symbolIndexCount.SetVisibility(llvm.HiddenVisibility) - stubIndexesPtr := llvm.AddGlobal(mod, llvm.PointerType(i32Type, 0), funcInfoStubIndexesSymbol) - stubCount := llvm.AddGlobal(mod, countType, funcInfoStubCountSymbol) pcLineCount := llvm.AddGlobal(mod, countType, pcLineCountSymbol) hashMask := llvm.AddGlobal(mod, countType, funcInfoHashMaskSymbol) // One byte per binary telling the runtime whether Go functions were @@ -368,19 +306,18 @@ func emitFuncInfoTable(ctx *context, pkg llssa.Package, records []funcInfoRecord } fpChain.SetInitializer(llvm.ConstInt(i8Type, fpChainVal, false)) if ctx.buildConf.PCLNMode == PCLNExternal { - emitExternalFuncInfoTable(ctx, mod, records, pcLines, stubRecords, externalFuncInfoGlobals{ + emitExternalFuncInfoTable(ctx, mod, records, pcLines, externalFuncInfoGlobals{ tablePtr: tablePtr, pcLinePtr: pcLinePtr, pcSiteStartPtr: pcSiteStartPtr, pcSiteEndPtr: pcSiteEndPtr, entryStartPtr: entryStartPtr, entryEndPtr: entryEndPtr, - stubSiteStartPtr: stubSiteStartPtr, stubSiteEndPtr: stubSiteEndPtr, stringsPtr: stringsPtr, stringOffsetsPtr: stringOffsetsPtr, stringCount: stringCount, hashPtr: hashPtr, hashMask: hashMask, symbolIndexPtr: symbolIndexPtr, symbolIndexCount: symbolIndexCount, - count: count, stubIndexesPtr: stubIndexesPtr, stubCount: stubCount, + count: count, pcLineCount: pcLineCount, }, externalFuncInfoTypes{ i8: i8Type, count: countType, - entryRecord: funcEntryRecordType, stubRecord: stubSiteRecordType, + entryRecord: funcEntryRecordType, pcSiteRecord: pcSiteRecordType, }) return @@ -392,8 +329,6 @@ func emitFuncInfoTable(ctx *context, pkg llssa.Package, records []funcInfoRecord pcSiteEndPtr.SetInitializer(llvm.ConstPointerNull(pcSiteEndPtr.GlobalValueType())) entryStartPtr.SetInitializer(llvm.ConstPointerNull(entryStartPtr.GlobalValueType())) entryEndPtr.SetInitializer(llvm.ConstPointerNull(entryEndPtr.GlobalValueType())) - stubSiteStartPtr.SetInitializer(llvm.ConstPointerNull(stubSiteStartPtr.GlobalValueType())) - stubSiteEndPtr.SetInitializer(llvm.ConstPointerNull(stubSiteEndPtr.GlobalValueType())) stringsPtr.SetInitializer(llvm.ConstPointerNull(stringsPtr.GlobalValueType())) stringOffsetsPtr.SetInitializer(llvm.ConstPointerNull(stringOffsetsPtr.GlobalValueType())) stringCount.SetInitializer(llvm.ConstInt(countType, 0, false)) @@ -401,8 +336,6 @@ func emitFuncInfoTable(ctx *context, pkg llssa.Package, records []funcInfoRecord symbolIndexPtr.SetInitializer(llvm.ConstPointerNull(symbolIndexPtr.GlobalValueType())) count.SetInitializer(llvm.ConstInt(countType, 0, false)) symbolIndexCount.SetInitializer(llvm.ConstInt(countType, 0, false)) - stubIndexesPtr.SetInitializer(llvm.ConstPointerNull(stubIndexesPtr.GlobalValueType())) - stubCount.SetInitializer(llvm.ConstInt(countType, 0, false)) pcLineCount.SetInitializer(llvm.ConstInt(countType, 0, false)) hashMask.SetInitializer(llvm.ConstInt(countType, 0, false)) return @@ -419,8 +352,6 @@ func emitFuncInfoTable(ctx *context, pkg llssa.Package, records []funcInfoRecord pcSiteEndPtr.SetInitializer(llvm.ConstPointerNull(pcSiteEndPtr.GlobalValueType())) entryStartPtr.SetInitializer(llvm.ConstPointerNull(entryStartPtr.GlobalValueType())) entryEndPtr.SetInitializer(llvm.ConstPointerNull(entryEndPtr.GlobalValueType())) - stubSiteStartPtr.SetInitializer(llvm.ConstPointerNull(stubSiteStartPtr.GlobalValueType())) - stubSiteEndPtr.SetInitializer(llvm.ConstPointerNull(stubSiteEndPtr.GlobalValueType())) stringsPtr.SetInitializer(llvm.ConstPointerNull(stringsPtr.GlobalValueType())) stringOffsetsPtr.SetInitializer(llvm.ConstPointerNull(stringOffsetsPtr.GlobalValueType())) stringCount.SetInitializer(llvm.ConstInt(countType, 0, false)) @@ -428,8 +359,6 @@ func emitFuncInfoTable(ctx *context, pkg llssa.Package, records []funcInfoRecord symbolIndexPtr.SetInitializer(llvm.ConstPointerNull(symbolIndexPtr.GlobalValueType())) count.SetInitializer(llvm.ConstInt(countType, 0, false)) symbolIndexCount.SetInitializer(llvm.ConstInt(countType, 0, false)) - stubIndexesPtr.SetInitializer(llvm.ConstPointerNull(stubIndexesPtr.GlobalValueType())) - stubCount.SetInitializer(llvm.ConstInt(countType, 0, false)) pcLineCount.SetInitializer(llvm.ConstInt(countType, 0, false)) hashMask.SetInitializer(llvm.ConstInt(countType, 0, false)) return @@ -497,8 +426,7 @@ func emitFuncInfoTable(ctx *context, pkg llssa.Package, records []funcInfoRecord machOSites := shouldEmitRuntimeMachOSites(ctx) emitSites := shouldEmitRuntimeSites(ctx) emitEntrySites := shouldEmitRuntimeEntryELFSites(ctx) && len(encoded.Records) != 0 - emitStubSites := shouldEmitRuntimeStubELFSites(ctx) - emitRuntimeFuncInfoSites(mod, ctx.prog.PointerSize(), machOSites, emitSites && len(pcLineValues) != 0, emitEntrySites, emitStubSites && len(stubRecords) != 0) + emitRuntimeFuncInfoSites(mod, ctx.prog.PointerSize(), machOSites, emitSites && len(pcLineValues) != 0, emitEntrySites) if emitEntrySites { startName, endName := entrySiteSectionInfo.boundary(machOSites) entryStart := llvm.AddGlobal(mod, funcEntryRecordType, startName) @@ -509,16 +437,6 @@ func emitFuncInfoTable(ctx *context, pkg llssa.Package, records []funcInfoRecord entryStartPtr.SetInitializer(llvm.ConstPointerNull(entryStartPtr.GlobalValueType())) entryEndPtr.SetInitializer(llvm.ConstPointerNull(entryEndPtr.GlobalValueType())) } - if emitStubSites && len(stubRecords) != 0 { - startName, endName := stubSiteSectionInfo.boundary(machOSites) - stubSiteStart := llvm.AddGlobal(mod, stubSiteRecordType, startName) - stubSiteEnd := llvm.AddGlobal(mod, stubSiteRecordType, endName) - stubSiteStartPtr.SetInitializer(stubSiteStart) - stubSiteEndPtr.SetInitializer(stubSiteEnd) - } else { - stubSiteStartPtr.SetInitializer(llvm.ConstPointerNull(stubSiteStartPtr.GlobalValueType())) - stubSiteEndPtr.SetInitializer(llvm.ConstPointerNull(stubSiteEndPtr.GlobalValueType())) - } stringArrayType := llvm.ArrayType(i8Type, len(encoded.Strings)) stringData := llvm.AddGlobal(mod, stringArrayType, funcInfoStringsDataSymbol) @@ -603,65 +521,34 @@ func emitFuncInfoTable(ctx *context, pkg llssa.Package, records []funcInfoRecord })) symbolIndexCount.SetInitializer(llvm.ConstInt(countType, uint64(len(symbolIndexValues)), false)) } - stubIndexSeen := make(map[uint32]none, len(stubRecords)) - stubIndexValues := make([]llvm.Value, 0, len(stubRecords)) - for _, stub := range stubRecords { - idx := stub.funcIndex - if idx == 0 || int(idx) > len(encoded.Records) { - continue - } - if _, ok := stubIndexSeen[idx]; ok { - continue - } - stubIndexSeen[idx] = none{} - stubIndexValues = append(stubIndexValues, llvm.ConstInt(i32Type, uint64(idx), false)) - } - if len(stubIndexValues) == 0 { - stubIndexesPtr.SetInitializer(llvm.ConstPointerNull(stubIndexesPtr.GlobalValueType())) - stubCount.SetInitializer(llvm.ConstInt(countType, 0, false)) - } else { - stubIndexArrayType := llvm.ArrayType(i32Type, len(stubIndexValues)) - stubIndexData := llvm.AddGlobal(mod, stubIndexArrayType, funcInfoStubIndexesDataSymbol) - stubIndexData.SetInitializer(llvm.ConstArray(i32Type, stubIndexValues)) - stubIndexData.SetLinkage(llvm.PrivateLinkage) - stubIndexData.SetGlobalConstant(true) - stubIndexData.SetUnnamedAddr(true) - stubIndexData.SetAlignment(4) - stubIndexesPtr.SetInitializer(llvm.ConstInBoundsGEP(stubIndexArrayType, stubIndexData, []llvm.Value{ - llvm.ConstInt(countType, 0, false), - llvm.ConstInt(countType, 0, false), - })) - stubCount.SetInitializer(llvm.ConstInt(countType, uint64(len(stubIndexValues)), false)) - } } type externalFuncInfoGlobals struct { tablePtr, pcLinePtr llvm.Value pcSiteStartPtr, pcSiteEndPtr llvm.Value entryStartPtr, entryEndPtr llvm.Value - stubSiteStartPtr, stubSiteEndPtr llvm.Value stringsPtr, stringOffsetsPtr, stringCount llvm.Value hashPtr, hashMask llvm.Value symbolIndexPtr, symbolIndexCount llvm.Value - count, stubIndexesPtr, stubCount llvm.Value + count llvm.Value pcLineCount llvm.Value } type externalFuncInfoTypes struct { - i8, count llvm.Type - entryRecord, stubRecord, pcSiteRecord llvm.Type + i8, count llvm.Type + entryRecord, pcSiteRecord llvm.Type } func initExternalFuncInfoGlobals(g externalFuncInfoGlobals, countType llvm.Type) { for _, ptr := range []llvm.Value{ g.tablePtr, g.pcLinePtr, g.pcSiteStartPtr, g.pcSiteEndPtr, - g.entryStartPtr, g.entryEndPtr, g.stubSiteStartPtr, g.stubSiteEndPtr, - g.stringsPtr, g.stringOffsetsPtr, g.hashPtr, g.symbolIndexPtr, g.stubIndexesPtr, + g.entryStartPtr, g.entryEndPtr, + g.stringsPtr, g.stringOffsetsPtr, g.hashPtr, g.symbolIndexPtr, } { ptr.SetInitializer(llvm.ConstPointerNull(ptr.GlobalValueType())) } for _, count := range []llvm.Value{ - g.stringCount, g.hashMask, g.symbolIndexCount, g.count, g.stubCount, g.pcLineCount, + g.stringCount, g.hashMask, g.symbolIndexCount, g.count, g.pcLineCount, } { count.SetInitializer(llvm.ConstInt(countType, 0, false)) } @@ -671,7 +558,7 @@ func initExternalFuncInfoGlobals(g externalFuncInfoGlobals, countType llvm.Type) // site boundaries and a post-link identity slot. The table payload is kept in // the build context and serialized beside the linked executable; it is never // materialized as LLVM constants in the executable. -func emitExternalFuncInfoTable(ctx *context, mod llvm.Module, records []funcInfoRecord, pcLines []pcLineRecord, stubRecords []funcInfoStubRecord, g externalFuncInfoGlobals, typ externalFuncInfoTypes) { +func emitExternalFuncInfoTable(ctx *context, mod llvm.Module, records []funcInfoRecord, pcLines []pcLineRecord, g externalFuncInfoGlobals, typ externalFuncInfoTypes) { initExternalFuncInfoGlobals(g, typ.count) encoded, err := buildfuncinfo.EncodeWithPCLines(toFuncInfoRecords(records), toPCLineRecords(pcLines)) if err != nil { @@ -717,8 +604,7 @@ func emitExternalFuncInfoTable(ctx *context, mod llvm.Module, records []funcInfo emitSites := shouldEmitRuntimeSites(ctx) emitPCSites := emitSites && len(encoded.PCLines) != 0 emitEntrySites := shouldEmitRuntimeEntryELFSites(ctx) && len(encoded.Records) != 0 - emitStubSites := shouldEmitRuntimeStubELFSites(ctx) && len(stubRecords) != 0 - emitRuntimeFuncInfoSites(mod, ctx.prog.PointerSize(), machO, emitPCSites, emitEntrySites, emitStubSites) + emitRuntimeFuncInfoSites(mod, ctx.prog.PointerSize(), machO, emitPCSites, emitEntrySites) if emitPCSites { start, end := pcLineSiteSectionInfo.boundary(machO) startGlobal := llvm.AddGlobal(mod, typ.pcSiteRecord, start) @@ -733,13 +619,6 @@ func emitExternalFuncInfoTable(ctx *context, mod llvm.Module, records []funcInfo g.entryStartPtr.SetInitializer(startGlobal) g.entryEndPtr.SetInitializer(endGlobal) } - if emitStubSites { - start, end := stubSiteSectionInfo.boundary(machO) - startGlobal := llvm.AddGlobal(mod, typ.stubRecord, start) - endGlobal := llvm.AddGlobal(mod, typ.stubRecord, end) - g.stubSiteStartPtr.SetInitializer(startGlobal) - g.stubSiteEndPtr.SetInitializer(endGlobal) - } } func shouldEmitRuntimeELFSites(ctx *context) bool { @@ -773,10 +652,6 @@ func shouldEmitRuntimeSites(ctx *context) bool { return shouldEmitRuntimeELFSites(ctx) || shouldEmitRuntimeMachOSites(ctx) } -func shouldEmitRuntimeStubELFSites(ctx *context) bool { - return shouldEmitRuntimeSites(ctx) -} - func shouldEmitRuntimeEntryELFSites(ctx *context) bool { return shouldEmitRuntimeSites(ctx) } @@ -790,7 +665,6 @@ type siteSectionInfo struct { var ( entrySiteSectionInfo = siteSectionInfo{elf: "llgo_funcinfo_entry", machO: "__DATA,__llgo_fie"} - stubSiteSectionInfo = siteSectionInfo{elf: "llgo_funcinfo_stubsite", machO: "__DATA,__llgo_stub"} pcLineSiteSectionInfo = siteSectionInfo{elf: "llgo_pcline", machO: "__DATA,__llgo_pcl"} ) @@ -874,6 +748,9 @@ func emitFuncInfoEntrySites(ctx *context, pkg llssa.Package) { // linker has while building pclntab. The inline-asm fragment lives in a // section tied to the function body (SHF_LINK_ORDER on ELF; live_support // on Mach-O), so dead functions do not leave stale entry records behind. + // Compiler-generated wrappers and adapters participate through their own + // ordinary funcinfo record; this path never classifies functions by their + // lowering role or calling convention. // Runtime still sorts these final PCs before building the Go-style // findfunc bucket index, because LLVM IR generation does not know final // linked text order. @@ -932,54 +809,6 @@ func emitFuncInfoEntrySites(ctx *context, pkg llssa.Package) { } } -func emitFuncInfoStubSites(ctx *context, pkg llssa.Package) { - if !shouldEmitRuntimeStubELFSites(ctx) || pkg == nil || !ctx.prog.FuncInfoMetadataEnabled() { - return - } - machO := shouldEmitRuntimeMachOSites(ctx) - mod := pkg.Module() - llvmCtx := mod.Context() - builder := llvmCtx.NewBuilder() - defer builder.Dispose() - asmType := llvm.FunctionType(llvmCtx.VoidType(), nil, false) - ptrDirective := ".quad" - align := "3" - if ctx.prog.PointerSize() == 4 { - ptrDirective = ".long" - align = "2" - } - for fn := mod.FirstFunction(); !fn.IsNil(); fn = llvm.NextFunction(fn) { - if fn.IsDeclaration() || fn.BasicBlocksCount() == 0 { - continue - } - symbol := fn.Name() - target, ok := strings.CutPrefix(symbol, closureStubPrefix) - if !ok || target == "" { - continue - } - entry := fn.EntryBasicBlock() - if entry.IsNil() { - continue - } - first := entry.FirstInstruction() - if first.IsNil() { - builder.SetInsertPointAtEnd(entry) - } else { - builder.SetInsertPointBefore(first) - } - anchor := siteAnchorLabel(machO, "funcinfo_stubsite") - instruction := anchor + ":\n" + - stubSiteSectionInfo.push(machO, anchor) + "\n" + - ".p2align " + align + "\n" + - stubSiteSectionInfo.recordSymbol(machO, "funcinfo_stubsite") + - ptrDirective + " " + anchor + "\n" + - ".quad " + uint64Hex(funcInfoSymbolID(target)) + "\n" + - ".popsection" - asm := llvm.InlineAsm(asmType, instruction, "", true, false, llvm.InlineAsmDialectATT, false) - builder.CreateCall(asmType, asm, nil, "") - } -} - func funcInfoSymbolID(symbol string) uint64 { const ( offset = uint64(14695981039346656037) @@ -1015,8 +844,8 @@ func uint64Hex(v uint64) string { // internal/pclnpost ("LLGOMET1" little-endian). const funcInfoMetaRecordMagic = uint64(0x3154454D4F474C4C) -func emitRuntimeFuncInfoSites(mod llvm.Module, pointerSize int, machO bool, pcSite bool, entrySite bool, stubSite bool) { - if !pcSite && !entrySite && !stubSite { +func emitRuntimeFuncInfoSites(mod llvm.Module, pointerSize int, machO bool, pcSite bool, entrySite bool) { + if !pcSite && !entrySite { return } ptrDirective := ".quad" @@ -1055,9 +884,6 @@ func emitRuntimeFuncInfoSites(mod llvm.Module, pointerSize int, machO bool, pcSi asm.WriteString(ptrDirective + " " + cntSym + "\n") asm.WriteString(".quad 0\n") } - if stubSite { - writeZeroRecord(stubSiteSectionInfo, "funcinfo_stubsite") - } mod.SetInlineAsm(asm.String()) } diff --git a/internal/build/funcinfo_table_test.go b/internal/build/funcinfo_table_test.go index d606f0549f..5677448837 100644 --- a/internal/build/funcinfo_table_test.go +++ b/internal/build/funcinfo_table_test.go @@ -74,8 +74,6 @@ func TestFuncInfoTableMaterializesMetadataWithoutFunctionPointers(t *testing.T) "@__llgo_funcinfo_symbol_index_count = hidden global i64 1", "@__llgo_funcinfo_entry_start = global ptr @__start_llgo_funcinfo_entry", "@__llgo_funcinfo_entry_end = global ptr @__stop_llgo_funcinfo_entry", - "@__llgo_funcinfo_stub_indexes = global ptr null", - "@__llgo_funcinfo_stub_count = global i64 0", "@__llgo_pcline_count = global i64 0", "@__llgo_funcinfo_hash_mask = global i64 1", "module asm \".section llgo_funcinfo_entry", @@ -102,9 +100,14 @@ func TestFuncInfoTableMaterializesEntrySites(t *testing.T) { prog := llssa.NewProgram(nil) src := prog.NewPackage("example.com/p", "example.com/p") src.EmitFuncInfo("example.com/p.live", "example.com/p.Live", "live.go", 17, 3) + // cl/ssawrap.MakeCallWrapper uses this suffix when an intrinsic is used as + // a function value. It is a physical function, not a separate PCLN class. + src.EmitFuncInfo("example.com/p.intrinsic$wrapper", "example.com/p.Live", "live.go", 17, 3) src.EmitFuncInfo("example.com/p.missing", "example.com/p.Missing", "missing.go", 19, 1) liveFn := src.NewFunc("example.com/p.live", llssa.NoArgsNoRet, llssa.InC) liveFn.MakeBody(1).Return() + intrinsicWrapper := src.NewFunc("example.com/p.intrinsic$wrapper", llssa.NoArgsNoRet, llssa.InC) + intrinsicWrapper.MakeBody(1).Return() otherFn := src.NewFunc("example.com/p.other", llssa.NoArgsNoRet, llssa.InC) otherFn.MakeBody(1).Return() ctx := &context{ @@ -132,6 +135,7 @@ func TestFuncInfoTableMaterializesEntrySites(t *testing.T) { } for _, bad := range []string{ `.quad \22example.com/p.live\22`, + `.quad \22example.com/p.intrinsic$wrapper\22`, `.quad \22example.com/p.other\22`, `.quad \22example.com/p.missing\22`, } { @@ -139,6 +143,14 @@ func TestFuncInfoTableMaterializesEntrySites(t *testing.T) { t.Fatalf("package entry site IR should not contain %q:\n%s", bad, srcIR) } } + if got := strings.Count(srcIR, ".pushsection llgo_funcinfo_entry"); got != 2 { + t.Fatalf("entry site count = %d, want one per physical function with funcinfo:\n%s", got, srcIR) + } + for _, symbol := range []string{"example.com/p.live", "example.com/p.intrinsic$wrapper"} { + if id := uint64Hex(funcInfoSymbolID(symbol)); !strings.Contains(srcIR, ".quad "+id) { + t.Fatalf("entry site IR missing physical function %q (id %s):\n%s", symbol, id, srcIR) + } + } records := collectFuncInfo([]Package{{LPkg: src}}) entry := genMainModule(ctx, llssa.PkgRuntime, &packages.Package{ @@ -200,9 +212,8 @@ func TestFuncInfoTableSitesDisabledKeepsTables(t *testing.T) { prog.EnableFuncInfoSites(false) emitFuncInfoEntrySites(ctx, src) - emitFuncInfoStubSites(ctx, src) srcIR := src.String() - for _, bad := range []string{"llgo_funcinfo_entry", "llgo_funcinfo_stubsite", "call void asm sideeffect"} { + for _, bad := range []string{"llgo_funcinfo_entry", "call void asm sideeffect"} { if strings.Contains(srcIR, bad) { t.Fatalf("sites disabled: package IR should not contain %q:\n%s", bad, srcIR) } @@ -228,7 +239,6 @@ func TestFuncInfoTableSitesDisabledKeepsTables(t *testing.T) { // ...while the site sections and their boundary symbols must not. for _, bad := range []string{ "@__start_llgo_funcinfo_entry", - "@__start_llgo_funcinfo_stubsite", "@__start_llgo_pcline", "module asm \".section llgo_", } { @@ -238,97 +248,6 @@ func TestFuncInfoTableSitesDisabledKeepsTables(t *testing.T) { } } -func TestFuncInfoTableMaterializesClosureStubIndexes(t *testing.T) { - prog := llssa.NewProgram(nil) - src := prog.NewPackage("example.com/p", "example.com/p") - src.EmitFuncInfo("example.com/p.live", "example.com/p.Live", "live.go", 17, 3) - src.EmitFuncInfo("example.com/p.other", "example.com/p.Other", "other.go", 23, 1) - stubFn := src.NewFunc(closureStubPrefix+"example.com/p.live", llssa.NoArgsNoRet, llssa.InC) - stubFn.MakeBody(1).Return() - ctx := &context{ - prog: prog, - buildConf: &Config{ - BuildMode: BuildModeExe, - Goos: "linux", - Goarch: "amd64", - }, - } - prog.EnableFuncInfoMetadata(true) - prog.EnableFuncInfoSites(true) - emitFuncInfoStubSites(ctx, src) - srcIR := src.String() - for _, want := range []string{ - "call void asm sideeffect", - ".pushsection llgo_funcinfo_stubsite", - ".Lllgo_funcinfo_stubsite_anchor_", - ".quad .Lllgo_funcinfo_stubsite_anchor_", - ".quad 0x", - } { - if !strings.Contains(srcIR, want) { - t.Fatalf("package stub site IR missing %q:\n%s", want, srcIR) - } - } - if strings.Contains(srcIR, `.quad \22__llgo_stub.example.com/p.live\22`) { - t.Fatalf("package stub site must not reference stub function symbols:\n%s", srcIR) - } - - records := collectFuncInfo([]Package{{LPkg: src}}) - stubs := collectFuncInfoStubRecords([]Package{{LPkg: src}}, records) - if len(stubs) != 1 || records[stubs[0].funcIndex-1].symbol != "example.com/p.live" || - stubs[0].symbol != closureStubPrefix+"example.com/p.live" { - t.Fatalf("stub indexes = %+v for records %+v, want live", stubs, records) - } - - entry := genMainModule(ctx, llssa.PkgRuntime, &packages.Package{ - PkgPath: "example.com/main", - ExportFile: "main.a", - }, &genConfig{funcInfo: records, funcInfoStubs: stubs}) - ir := entry.LPkg.String() - for _, want := range []string{ - "@__llgo_funcinfo_stub_indexes = global ptr", - "@__llgo_funcinfo_stub_count = global i64 1", - "@__llgo_funcinfo_symbol_index = hidden global ptr", - "@__llgo_funcinfo_symbol_index_count = hidden global i64 2", - "@__llgo_funcinfo_stubsite_start = global ptr @__start_llgo_funcinfo_stubsite", - "@__llgo_funcinfo_stubsite_end = global ptr @__stop_llgo_funcinfo_stubsite", - `@"__llgo_funcinfo_stub_indexes$data" = private unnamed_addr constant [1 x i32]`, - "@__llgo_funcinfo_count = global i64 2", - "module asm \".section llgo_funcinfo_stubsite", - ".quad 0", - } { - if !strings.Contains(ir, want) { - t.Fatalf("funcinfo stub index table IR missing %q:\n%s", want, ir) - } - } - if strings.Contains(ir, closureStubPrefix+"example.com/p.live\\00") { - t.Fatalf("stub index table should not add stub symbol strings:\n%s", ir) - } - - ltoCtx := &context{ - prog: prog, - buildConf: &Config{ - BuildMode: BuildModeExe, - Goos: "linux", - Goarch: "amd64", - LTO: lto.Full, - }, - } - ltoEntry := genMainModule(ltoCtx, llssa.PkgRuntime, &packages.Package{ - PkgPath: "example.com/main", - ExportFile: "main.a", - }, &genConfig{funcInfo: records, funcInfoStubs: stubs}) - ltoIR := ltoEntry.LPkg.String() - for _, want := range []string{ - "@__llgo_funcinfo_stubsite_start = global ptr @__start_llgo_funcinfo_stubsite", - "@__llgo_funcinfo_stubsite_end = global ptr @__stop_llgo_funcinfo_stubsite", - "module asm \".section llgo_funcinfo_stubsite", - } { - if !strings.Contains(ltoIR, want) { - t.Fatalf("full LTO funcinfo stub site table IR missing %q:\n%s", want, ltoIR) - } - } -} - func TestFuncInfoTableMaterializesPCLineMetadata(t *testing.T) { prog := llssa.NewProgram(nil) prog.EnableFuncInfoSites(true) @@ -455,8 +374,6 @@ func TestFuncInfoTableEmptyDefinitions(t *testing.T) { "@__llgo_funcinfo_symbol_index_count = hidden global i64 0", "@__llgo_funcinfo_entry_start = global ptr null", "@__llgo_funcinfo_entry_end = global ptr null", - "@__llgo_funcinfo_stub_indexes = global ptr null", - "@__llgo_funcinfo_stub_count = global i64 0", "@__llgo_pcline_count = global i64 0", "@__llgo_funcinfo_hash_mask = global i64 0", } { @@ -530,8 +447,6 @@ func TestFuncInfoTableEmissionMatrix(t *testing.T) { src.EmitPCLineInfo(0x1234, `example.com/p.we$ird"sym`, "call.go", 23, 5) fn := src.NewFunc(`example.com/p.we$ird"sym`, llssa.NoArgsNoRet, llssa.InGo) fn.MakeBody(1).Return() - stub := src.NewFunc(`__llgo_stub.example.com/p.we$ird"sym`, llssa.NoArgsNoRet, llssa.InGo) - stub.MakeBody(1).Return() } ctx := &context{ prog: prog, @@ -543,10 +458,8 @@ func TestFuncInfoTableEmissionMatrix(t *testing.T) { } records := collectFuncInfo([]Package{{LPkg: src}}) pcLines := collectPCLineInfo([]Package{{LPkg: src}}) - stubs := collectFuncInfoStubRecords([]Package{{LPkg: src}}, records) - emitFuncInfoTable(ctx, src, records, pcLines, stubs) + emitFuncInfoTable(ctx, src, records, pcLines) emitFuncInfoEntrySites(ctx, src) - emitFuncInfoStubSites(ctx, src) ir := src.String() if c.empty { if !strings.Contains(ir, "__llgo_funcinfo_count") { @@ -617,7 +530,7 @@ func TestELFFuncInfoMetadataLinksIntoSharedLibrary(t *testing.T) { emitFuncInfoEntrySites(ctx, src) metadata := prog.NewPackage("example.com/runtime", "example.com/runtime") - emitFuncInfoTable(ctx, metadata, records, nil, nil) + emitFuncInfoTable(ctx, metadata, records, nil) dir := t.TempDir() writeObject := func(name string, mod llvm.Module) string { @@ -728,7 +641,7 @@ func TestFuncInfoTableEmptyEncodedInitializers(t *testing.T) { Goarch: "amd64", }, } - emitFuncInfoTable(ctx, src, nil, nil, nil) + emitFuncInfoTable(ctx, src, nil, nil) ir := src.String() for _, want := range []string{ "@__llgo_funcinfo_table = global ptr null", @@ -771,7 +684,7 @@ func TestExternalFuncInfoTableKeepsPayloadOutOfIR(t *testing.T) { } records := collectFuncInfo([]Package{{LPkg: src}}) pcLines := collectPCLineInfo([]Package{{LPkg: src}}) - emitFuncInfoTable(ctx, src, records, pcLines, nil) + emitFuncInfoTable(ctx, src, records, pcLines) if ctx.pclnExternal == nil || len(ctx.pclnExternal.Table.Records) != 1 || len(ctx.pclnExternal.Table.PCLines) != 1 || len(ctx.pclnExternal.SymbolIndex) != 1 { t.Fatalf("external payload = %+v", ctx.pclnExternal) } @@ -816,7 +729,7 @@ func TestFuncInfoTableFPChainOff(t *testing.T) { Goarch: "amd64", }, } - emitFuncInfoTable(ctx, src, nil, nil, nil) + emitFuncInfoTable(ctx, src, nil, nil) if ir := src.String(); !strings.Contains(ir, "@__llgo_fp_chain = global i8 0") { t.Fatalf("missing fp_chain=0 in:\n%s", ir) } diff --git a/internal/build/main_module.go b/internal/build/main_module.go index eb57ee8b49..2ff9d54d0a 100644 --- a/internal/build/main_module.go +++ b/internal/build/main_module.go @@ -44,7 +44,6 @@ type genConfig struct { abiSymbols map[string]none funcInfo []funcInfoRecord pcLineInfo []pcLineRecord - funcInfoStubs []funcInfoStubRecord } // genMainModule generates the main entry module for an llgo program. @@ -62,7 +61,7 @@ func genMainModule(ctx *context, rtPkgPath string, pkg *packages.Package, cfg *g argvValueType := prog.Pointer(prog.CStr()) argvVar := mainPkg.NewVarEx("__llgo_argv", prog.Pointer(argvValueType)) argvVar.InitNil() - emitFuncInfoTable(ctx, mainPkg, cfg.funcInfo, cfg.pcLineInfo, cfg.funcInfoStubs) + emitFuncInfoTable(ctx, mainPkg, cfg.funcInfo, cfg.pcLineInfo) exportFile := pkg.ExportFile if exportFile == "" { diff --git a/internal/build/pcln_mode_test.go b/internal/build/pcln_mode_test.go index 2f6f939906..57e56de42b 100644 --- a/internal/build/pcln_mode_test.go +++ b/internal/build/pcln_mode_test.go @@ -235,7 +235,7 @@ func TestFinalizeRuntimePCLNRemovesStaleSidecar(t *testing.T) { } } -func TestFilterExternalPCLNJoinsKeepsEntryAndStubKindsSeparate(t *testing.T) { +func TestFilterExternalPCLNJoins(t *testing.T) { idA := funcInfoSymbolID("example.com/p.A") idB := funcInfoSymbolID("example.com/p.B") data := pclnmap.Data{ @@ -253,10 +253,6 @@ func TestFilterExternalPCLNJoinsKeepsEntryAndStubKindsSeparate(t *testing.T) { {PCOffset: 0x100, ID: idB}, // same-PC alias is deterministically dropped {PCOffset: 0x200, ID: 99}, // missing funcinfo join }, - StubSites: []pclnmap.Site{ - {PCOffset: 0x80, ID: idA}, - {PCOffset: 0x90, ID: 99}, // missing funcinfo join - }, PCSites: []pclnmap.Site{ {PCOffset: 0x110, ID: 101}, {PCOffset: 0x120, ID: 101}, // A's pcline copied into B @@ -269,9 +265,6 @@ func TestFilterExternalPCLNJoinsKeepsEntryAndStubKindsSeparate(t *testing.T) { if len(data.EntrySites) != 1 || data.EntrySites[0] != (pclnmap.Site{PCOffset: 0x100, ID: idA}) { t.Fatalf("entry sites = %#v", data.EntrySites) } - if len(data.StubSites) != 1 || data.StubSites[0] != (pclnmap.Site{PCOffset: 0x80, ID: idA}) { - t.Fatalf("stub sites = %#v", data.StubSites) - } wantPCSites := []pclnmap.Site{{PCOffset: 0x110, ID: 101}, {PCOffset: 0x130, ID: 202}} if !reflect.DeepEqual(data.PCSites, wantPCSites) { t.Fatalf("pcline sites = %#v, want %#v", data.PCSites, wantPCSites) diff --git a/internal/build/pclntab_external.go b/internal/build/pclntab_external.go index c463156ae4..8cd59ce933 100644 --- a/internal/build/pclntab_external.go +++ b/internal/build/pclntab_external.go @@ -70,10 +70,6 @@ func writeExternalPCLN(ctx *context, out *OutFmtDetails, verbose bool) (err erro for i, site := range analysis.EntrySites { data.EntrySites[i] = pclnmap.Site{PCOffset: site.PCOffset, ID: site.ID} } - data.StubSites = make([]pclnmap.Site, len(analysis.StubSites)) - for i, site := range analysis.StubSites { - data.StubSites[i] = pclnmap.Site{PCOffset: site.PCOffset, ID: site.ID} - } data.PCSites = make([]pclnmap.Site, len(analysis.PCLineSites)) pcSiteOwners := make([]string, len(analysis.PCLineSites)) for i, site := range analysis.PCLineSites { @@ -122,8 +118,8 @@ func writeExternalPCLN(ctx *context, out *OutFmtDetails, verbose bool) (err erro return err } if verbose { - fmt.Fprintf(os.Stderr, "llgo: external pclntab: %d entries, %d stubs, %d pcline sites (%d bytes) -> %s\n", - len(data.EntrySites), len(data.StubSites), len(data.PCSites), len(raw), out.PCLN) + fmt.Fprintf(os.Stderr, "llgo: external pclntab: %d entries, %d pcline sites (%d bytes) -> %s\n", + len(data.EntrySites), len(data.PCSites), len(raw), out.PCLN) } return nil } @@ -145,7 +141,6 @@ func filterExternalPCLNJoins(data *pclnmap.Data, pcSiteOwners []string) error { return filtered } data.EntrySites = filterSymbolSites(data.EntrySites) - data.StubSites = filterSymbolSites(data.StubSites) if len(data.EntrySites) == 0 { return fmt.Errorf("external pclntab has no entry sites joined to funcinfo") } diff --git a/internal/build/pclntab_modes_integration_test.go b/internal/build/pclntab_modes_integration_test.go index 641ae39367..b7c3b6ae79 100644 --- a/internal/build/pclntab_modes_integration_test.go +++ b/internal/build/pclntab_modes_integration_test.go @@ -37,9 +37,9 @@ import ( "github.com/goplus/llgo/internal/pclnmap" ) -// The fixture obtains both a closure ABI stub entry PC and a real target -// mid-function PC. Together those lookups and the stack APIs exercise the -// full metadata contract, including its deliberate absence in pclntab=none. +// The fixture obtains both a function-value entry PC and a target mid-function +// PC. Together those lookups and the stack APIs exercise the full metadata +// contract, including its deliberate absence in pclntab=none. const pclntabModesFixture = `package main import ( @@ -60,8 +60,7 @@ func pclnTarget() uintptr { } // Keep the target body comfortably larger than the entry-anchor slack. // This makes the returned mid-function PC unambiguously belong to the - // target on both fixed-width arm64 and byte-aligned amd64, while the - // function value below still exposes the separate closure ABI stub. + // target on both fixed-width arm64 and byte-aligned amd64. value := pc for i := uintptr(0); i < 64; i++ { value = value*33 + i @@ -101,16 +100,16 @@ func pclnClosurePCState(fn *runtime.Func, pc uintptr) string { } func pclnClosureState() string { - stubPC := reflect.ValueOf(pclnTarget).Pointer() + funcvalPC := reflect.ValueOf(pclnTarget).Pointer() targetPC := pclnTarget() - stubFn := runtime.FuncForPC(stubPC) + funcvalFn := runtime.FuncForPC(funcvalPC) targetFn := runtime.FuncForPC(targetPC) - separate := stubFn != nil && targetFn != nil && - stubFn.Name() == targetFn.Name() && - stubFn.Entry() == stubPC && targetFn.Entry() != 0 && - targetFn.Entry() != stubFn.Entry() && targetFn.Entry() <= targetPC - return fmt.Sprintf("target=%s stub=%s separate=%t", - pclnClosurePCState(targetFn, targetPC), pclnClosurePCState(stubFn, stubPC), separate) + sameEntry := funcvalFn != nil && targetFn != nil && + funcvalFn.Name() == targetFn.Name() && + funcvalFn.Entry() == funcvalPC && targetFn.Entry() == funcvalFn.Entry() && + targetFn.Entry() <= targetPC + return fmt.Sprintf("target=%s funcval=%s same-entry=%t", + pclnClosurePCState(targetFn, targetPC), pclnClosurePCState(funcvalFn, funcvalPC), sameEntry) } //go:noinline @@ -269,7 +268,7 @@ func TestPCLNModeNativeIntegration(t *testing.T) { } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - bin := buildPCLNIntegrationBinaryAt(t, source, tt.mode, LinkOptions{}, filepath.Join(packagingDir, "pclntab-modes-"+tt.name)) + bin := buildPCLNIntegrationBinaryAt(t, source, tt.mode, LinkOptions{}, filepath.Join(packagingDir, "pclntab-modes-"+tt.name), false) binaries[tt.mode] = bin if tt.mode == PCLNExternal { verifyPCLNIntegrationSignature(t, bin) @@ -317,8 +316,8 @@ func TestPCLNModeNativeIntegration(t *testing.T) { if got := runPCLNIntegrationBinary(t, bin, "once"); got != "FULL\n" { t.Fatalf("runtime metadata state = %q, want FULL", got) } - if got := runPCLNIntegrationBinary(t, bin, "closure"); got != "target=FULL stub=FULL separate=true\n" { - t.Fatalf("closure target/stub metadata = %q", got) + if got := runPCLNIntegrationBinary(t, bin, "closure"); got != "target=FULL funcval=FULL same-entry=true\n" { + t.Fatalf("closure target/funcval metadata = %q", got) } }) @@ -361,7 +360,7 @@ func TestPCLNModeNativeIntegration(t *testing.T) { {name: "wrong-ABI", mutate: mismatchPCLNIntegrationABI}, {name: "wrong-architecture", mutate: mismatchPCLNIntegrationArchitecture}, {name: "overlapping-sections", mutate: overlapPCLNIntegrationSections}, - {name: "misaligned-stub-section", mutate: misalignPCLNIntegrationStubSection}, + {name: "misaligned-pc-site-section", mutate: misalignPCLNIntegrationPCSiteSection}, {name: "unterminated-string-pool", mutate: unterminatePCLNIntegrationStringPool}, } for _, failure := range failures { @@ -398,7 +397,11 @@ func TestPCLNExternalPureCLibraryIdentityRetentionIntegration(t *testing.T) { requireNativePCLNSidecars(t) setPCLNIntegrationEnv(t) source := writePCLNIntegrationSource(t, pclntabPureCLibraryFixture) - bin := buildPCLNIntegrationBinary(t, source, PCLNExternal, LinkOptions{}) + // Exercise the external-sidecar summary as part of a real detach rather + // than mocking the final publication path. + bin := buildPCLNIntegrationBinaryAt( + t, source, PCLNExternal, LinkOptions{}, filepath.Join(t.TempDir(), "pclntab-pure-c"), true, + ) verifyPCLNIntegrationSignature(t, bin) if got := runPCLNIntegrationBinary(t, bin); got != "pure-c-pclntab\n" { t.Fatalf("pure lib/c output = %q", got) @@ -584,10 +587,10 @@ func pclnIntegrationBinaryIdentity(t *testing.T, path string) [32]byte { func buildPCLNIntegrationBinary(t *testing.T, source string, mode PCLNMode, options LinkOptions) string { t.Helper() - return buildPCLNIntegrationBinaryAt(t, source, mode, options, filepath.Join(t.TempDir(), "pclntab-modes")) + return buildPCLNIntegrationBinaryAt(t, source, mode, options, filepath.Join(t.TempDir(), "pclntab-modes"), false) } -func buildPCLNIntegrationBinaryAt(t *testing.T, source string, mode PCLNMode, options LinkOptions, bin string) string { +func buildPCLNIntegrationBinaryAt(t *testing.T, source string, mode PCLNMode, options LinkOptions, bin string, verbose bool) string { t.Helper() started := time.Now() conf := &Config{ @@ -597,6 +600,7 @@ func buildPCLNIntegrationBinaryAt(t *testing.T, source string, mode PCLNMode, op PCLNMode: mode, PCLNModeSet: true, LinkOptions: options, + Verbose: verbose, } if _, err := Do([]string{source}, conf); err != nil { t.Fatalf("build %s PCLN fixture with LinkOptions %+v: %v", mode, options, err) @@ -778,14 +782,14 @@ func overlapPCLNIntegrationSections(t *testing.T, path string) { }) } -func misalignPCLNIntegrationStubSection(t *testing.T, path string) { +func misalignPCLNIntegrationPCSiteSection(t *testing.T, path string) { t.Helper() mutatePCLNIntegrationHeader(t, path, func(raw []byte) { - // v3 descriptor order: records, pclines, strings, string offsets, - // hash, symbol index, entries, stubs, pc sites. - stub := pclnIntegrationHeaderSections + 7*pclnIntegrationSectionSize - off := binary.LittleEndian.Uint64(raw[stub:]) - binary.LittleEndian.PutUint64(raw[stub:], off+1) + // v4 descriptor order: records, pclines, strings, string offsets, + // hash, symbol index, entries, pc sites. + pcSites := pclnIntegrationHeaderSections + 7*pclnIntegrationSectionSize + off := binary.LittleEndian.Uint64(raw[pcSites:]) + binary.LittleEndian.PutUint64(raw[pcSites:], off+1) }) } diff --git a/internal/build/resolver.go b/internal/build/resolver.go index 16de393720..96f5152a35 100644 --- a/internal/build/resolver.go +++ b/internal/build/resolver.go @@ -2,11 +2,6 @@ package build import "strings" -const ( - llgoStubsCategory = "llgo-stubs" - llgoPrefix = "llgo" -) - // nameResolver maps symbol names to aggregation buckets based on the requested level. type nameResolver struct { level string @@ -54,9 +49,6 @@ func (r *nameResolver) resolve(sym string) string { return mod } } - if strings.Contains(symbol, llgoPrefix) { - return llgoStubsCategory - } return base } diff --git a/internal/build/size_report_test.go b/internal/build/size_report_test.go index a47ad60370..085f7d401a 100644 --- a/internal/build/size_report_test.go +++ b/internal/build/size_report_test.go @@ -185,8 +185,8 @@ func TestNameResolver(t *testing.T) { if full != symbol { t.Fatalf("full level unexpected: %q", full) } - if got := newNameResolver("package", nil).resolve("_llgo_stub.foo"); got != "llgo-stubs" { - t.Fatalf("llgo default grouping failed: %q", got) + if got := newNameResolver("package", nil).resolve("_llgo_helper.foo"); got != "llgo_helper" { + t.Fatalf("unmatched symbol grouping failed: %q", got) } generic := "_slices.SortFunc[[]io/fs.DirEntry,io/fs.DirEntry]" if got := newNameResolver("module", nil).resolve(generic); got != "slices" { diff --git a/internal/cabi/cabi.go b/internal/cabi/cabi.go index 2e37b6bc99..df72a7267a 100644 --- a/internal/cabi/cabi.go +++ b/internal/cabi/cabi.go @@ -319,10 +319,15 @@ func (p *Transformer) GetFuncInfo(ctx llvm.Context, typ llvm.Type) (info FuncInf return } -func (p *Transformer) transformFuncType(ctx llvm.Context, info *FuncInfo) (llvm.Type, map[int]llvm.Attribute) { +func (p *Transformer) transformFuncType( + ctx llvm.Context, info *FuncInfo, +) (llvm.Type, map[int]llvm.Attribute, []int) { var paramTypes []llvm.Type var returnType llvm.Type attrs := make(map[int]llvm.Attribute) + // paramMap maps each zero-based source parameter to its one-based + // transformed LLVM attribute index. Zero means the parameter was elided. + paramMap := make([]int, len(info.Params)) switch info.Return.Kind { case AttrPointer: returnType = ctx.VoidType() @@ -336,7 +341,10 @@ func (p *Transformer) transformFuncType(ctx llvm.Context, info *FuncInfo) (llvm. returnType = info.Return.Type1 } - for _, ti := range info.Params { + for i, ti := range info.Params { + if ti.Kind != AttrVoid { + paramMap[i] = len(paramTypes) + 1 + } switch ti.Kind { case AttrVoid: // skip @@ -354,7 +362,7 @@ func (p *Transformer) transformFuncType(ctx llvm.Context, info *FuncInfo) (llvm. paramTypes = append(paramTypes, subs...) } } - return llvm.FunctionType(returnType, paramTypes, info.Type.IsFunctionVarArg()), attrs + return llvm.FunctionType(returnType, paramTypes, info.Type.IsFunctionVarArg()), attrs, paramMap } func (p *Transformer) transformFunc(m llvm.Module, fn llvm.Value) bool { @@ -366,7 +374,7 @@ func (p *Transformer) transformFunc(m llvm.Module, fn llvm.Value) bool { if !info.HasWrap() { return false } - nft, attrs := p.transformFuncType(ctx, &info) + nft, attrs, paramMap := p.transformFuncType(ctx, &info) preloweredSRet := fn.GetEnumAttributeAtIndex(1, llvm.AttributeKindID("sret")) fname := fn.Name() fn.SetName("") @@ -374,6 +382,7 @@ func (p *Transformer) transformFunc(m llvm.Module, fn llvm.Value) bool { for i, attr := range attrs { nfn.AddAttributeAtIndex(i, attr) } + copyClosureEnvFunctionAttrs(fn, nfn, paramMap) if !preloweredSRet.IsNil() { nfn.AddAttributeAtIndex(1, preloweredSRet) } @@ -540,7 +549,7 @@ func (p *Transformer) transformCallInstr(m llvm.Module, ctx llvm.Context, call l if !info.HasWrap() { return false } - nft, attrs := p.transformFuncType(ctx, &info) + nft, attrs, paramMap := p.transformFuncType(ctx, &info) preloweredSRet := call.GetCallSiteEnumAttribute(1, llvm.AttributeKindID("sret")) reflectMethodByNameAttr := call.GetCallSiteStringAttribute(-1, "llgo.reflect.methodbyname") b := ctx.NewBuilder() @@ -599,21 +608,22 @@ func (p *Transformer) transformCallInstr(m llvm.Module, ctx llvm.Context, call l } } - updateCallAttr := func(call llvm.Value) { + updateCallAttr := func(replacement llvm.Value) { for i, attr := range attrs { - call.AddCallSiteAttribute(i, attr) + replacement.AddCallSiteAttribute(i, attr) } if !preloweredSRet.IsNil() { - call.AddCallSiteAttribute(1, preloweredSRet) + replacement.AddCallSiteAttribute(1, preloweredSRet) } if !reflectMethodByNameAttr.IsNil() { - call.AddCallSiteAttribute(-1, reflectMethodByNameAttr) + replacement.AddCallSiteAttribute(-1, reflectMethodByNameAttr) } if remappedReflectMethodByNameArgAttrIndex >= 0 { - call.AddCallSiteAttribute(remappedReflectMethodByNameArgAttrIndex, ctx.CreateStringAttribute( + replacement.AddCallSiteAttribute(remappedReflectMethodByNameArgAttrIndex, ctx.CreateStringAttribute( "llgo.reflect.methodbyname.name", "1", )) } + copyClosureEnvCallAttrs(call, replacement, paramMap) } var instr llvm.Value @@ -678,7 +688,7 @@ func (p *Transformer) transformCallbackFunc(m llvm.Module, fn llvm.Value) (wrap return fn, false } - nft, attrs := p.transformFuncType(ctx, &info) + nft, attrs, paramMap := p.transformFuncType(ctx, &info) fname := fn.Name() wrapName := "__llgo_cdecl$" + fname @@ -692,6 +702,7 @@ func (p *Transformer) transformCallbackFunc(m llvm.Module, fn llvm.Value) (wrap for i, attr := range attrs { wrapFunc.AddAttributeAtIndex(i, attr) } + copyClosureEnvFunctionAttrs(fn, wrapFunc, paramMap) b := ctx.NewBuilder() block := ctx.AddBasicBlock(wrapFunc, "entry") @@ -706,6 +717,7 @@ func (p *Transformer) transformCallbackFunc(m llvm.Module, fn llvm.Value) (wrap for _, ti := range info.Params { switch ti.Kind { default: + nparams = append(nparams, params[index]) case AttrVoid: // none case AttrPointer: @@ -738,14 +750,17 @@ func (p *Transformer) transformCallbackFunc(m llvm.Module, fn llvm.Value) (wrap switch info.Return.Kind { case AttrVoid: - llvm.CreateCall(b, info.Type, fn, nparams) + call := llvm.CreateCall(b, info.Type, fn, nparams) + copyClosureEnvFunctionAttrsToCall(fn, call) b.CreateRetVoid() case AttrPointer: ret := llvm.CreateCall(b, info.Type, fn, nparams) + copyClosureEnvFunctionAttrsToCall(fn, ret) b.CreateStore(ret, params[0]) b.CreateRetVoid() case AttrWidthType, AttrWidthType2: ret := llvm.CreateCall(b, info.Type, fn, nparams) + copyClosureEnvFunctionAttrsToCall(fn, ret) ptr := llvm.CreateAlloca(b, info.Return.Type) b.CreateStore(ret, ptr) returnType := nft.ReturnType() @@ -753,11 +768,53 @@ func (p *Transformer) transformCallbackFunc(m llvm.Module, fn llvm.Value) (wrap b.CreateRet(b.CreateLoad(returnType, iptr, "")) default: ret := llvm.CreateCall(b, info.Type, fn, nparams) + copyClosureEnvFunctionAttrsToCall(fn, ret) b.CreateRet(ret) } return wrapFunc, true } +var closureEnvAttributeKinds = []uint{ + llvm.AttributeKindID("nest"), + llvm.AttributeKindID("swiftself"), +} + +func copyClosureEnvFunctionAttrs(from, to llvm.Value, paramMap []int) { + for oldIndex, newIndex := range paramMap { + if newIndex == 0 { + continue + } + for _, kind := range closureEnvAttributeKinds { + if attr := from.GetEnumAttributeAtIndex(oldIndex+1, kind); !attr.IsNil() { + to.AddAttributeAtIndex(newIndex, attr) + } + } + } +} + +func copyClosureEnvCallAttrs(from, to llvm.Value, paramMap []int) { + for oldIndex, newIndex := range paramMap { + if newIndex == 0 { + continue + } + for _, kind := range closureEnvAttributeKinds { + if attr := from.GetCallSiteEnumAttribute(oldIndex+1, kind); !attr.IsNil() { + to.AddCallSiteAttribute(newIndex, attr) + } + } + } +} + +func copyClosureEnvFunctionAttrsToCall(from, to llvm.Value) { + for i := 0; i < from.GlobalValueType().ParamTypesCount(); i++ { + for _, kind := range closureEnvAttributeKinds { + if attr := from.GetEnumAttributeAtIndex(i+1, kind); !attr.IsNil() { + to.AddCallSiteAttribute(i+1, attr) + } + } + } +} + func (p *Transformer) callMemcpy(_ llvm.Module, ctx llvm.Context, b llvm.Builder, dst llvm.Value, src llvm.Value, size int) llvm.Value { sz := llvm.ConstInt(ctx.IntType(p.prog.PointerSize()*8), uint64(size), false) return b.CreateIntrinsic(ctx.VoidType(), llvm.LookupIntrinsicID("llvm.memcpy"), []llvm.Value{ diff --git a/internal/cabi/cabi_patch_test.go b/internal/cabi/cabi_patch_test.go index 7254459e37..228fbbc501 100644 --- a/internal/cabi/cabi_patch_test.go +++ b/internal/cabi/cabi_patch_test.go @@ -76,6 +76,165 @@ func TestDevLTOGlobalDCEFuncNoUnwindCreatesNounwindAttribute(t *testing.T) { } } +func TestClosureEnvAttributeRemappedByCABI(t *testing.T) { + llvm.InitializeAllTargets() + llvm.InitializeAllTargetMCs() + llvm.InitializeAllTargetInfos() + + const testIR = ` +%Value = type { ptr, ptr, i64 } + +define %Value @callee(ptr %g, ptr %out, ptr nest %env, %Value %value) { +entry: + ret %Value %value +} + +define %Value @caller(ptr %g, ptr %out, ptr nest %env, %Value %value) { +entry: + %result = call %Value @callee(ptr %g, ptr %out, ptr nest %env, %Value %value) + ret %Value %result +} +` + ctx := llvm.NewContext() + defer ctx.Dispose() + path := filepath.Join(t.TempDir(), "closure_env.ll") + if err := os.WriteFile(path, []byte(testIR), 0o644); err != nil { + t.Fatal(err) + } + buf, err := llvm.NewMemoryBufferFromFile(path) + if err != nil { + t.Fatal(err) + } + mod, err := ctx.ParseIR(buf) + if err != nil { + t.Fatal(err) + } + defer mod.Dispose() + + prog := llssa.NewProgram(&llssa.Target{GOOS: "linux", GOARCH: "amd64"}) + defer prog.Dispose() + tr := NewTransformer(prog, "amd64-unknown-linux-gnu", "", ModeAllFunc, true) + tr.TransformModule("test", mod) + + nest := llvm.AttributeKindID("nest") + callee := mod.NamedFunction("callee") + if attr := callee.GetEnumAttributeAtIndex(4, nest); attr.IsNil() { + t.Fatalf("C ABI lowering lost/remapped nest on the definition:\n%s", callee.String()) + } + if attr := callee.GetEnumAttributeAtIndex(3, nest); !attr.IsNil() { + t.Fatalf("C ABI lowering left nest on the old definition parameter:\n%s", callee.String()) + } + + caller := mod.NamedFunction("caller") + var nestedCall llvm.Value + for block := caller.FirstBasicBlock(); !block.IsNil(); block = llvm.NextBasicBlock(block) { + for instruction := block.FirstInstruction(); !instruction.IsNil(); instruction = llvm.NextInstruction(instruction) { + if call := instruction.IsACallInst(); !call.IsNil() && call.CalledValue().Name() == "callee" { + nestedCall = call + } + } + } + if nestedCall.IsNil() { + t.Fatalf("transformed caller has no callee call:\n%s", caller.String()) + } + if attr := nestedCall.GetCallSiteEnumAttribute(4, nest); attr.IsNil() { + t.Fatalf("C ABI lowering lost/remapped nest on the call:\n%s", caller.String()) + } + if attr := nestedCall.GetCallSiteEnumAttribute(3, nest); !attr.IsNil() { + t.Fatalf("C ABI lowering left nest on the old call parameter:\n%s", caller.String()) + } + if err := llvm.VerifyModule(mod, llvm.ReturnStatusAction); err != nil { + t.Fatalf("C ABI closure-env module is invalid: %v\n%s", err, mod.String()) + } +} + +func TestClosureEnvAttributePreservedByCallbackWrapper(t *testing.T) { + llvm.InitializeAllTargets() + llvm.InitializeAllTargetMCs() + llvm.InitializeAllTargetInfos() + + const testIR = ` +%Value = type { ptr, ptr, i64 } + +define RETURN @callback(ptr ATTR %env, %Value %value) { +entry: + RET +} +` + returnCases := []struct { + name string + typ string + ret string + }{ + {name: "aggregate", typ: "%Value", ret: "ret %Value %value"}, + {name: "void", typ: "void", ret: "ret void"}, + {name: "scalar", typ: "i64", ret: "ret i64 7"}, + } + for _, returnCase := range returnCases { + t.Run(returnCase.name, func(t *testing.T) { + for _, attrName := range []string{"nest", "swiftself"} { + t.Run(attrName, func(t *testing.T) { + ctx := llvm.NewContext() + defer ctx.Dispose() + path := filepath.Join(t.TempDir(), "closure_env_callback.ll") + ir := strings.NewReplacer( + "RETURN", returnCase.typ, + "RET", returnCase.ret, + "ATTR", attrName, + ).Replace(testIR) + if err := os.WriteFile(path, []byte(ir), 0o644); err != nil { + t.Fatal(err) + } + buf, err := llvm.NewMemoryBufferFromFile(path) + if err != nil { + t.Fatal(err) + } + mod, err := ctx.ParseIR(buf) + if err != nil { + t.Fatal(err) + } + defer mod.Dispose() + + prog := llssa.NewProgram(&llssa.Target{GOOS: "linux", GOARCH: "amd64"}) + defer prog.Dispose() + tr := NewTransformer(prog, "amd64-unknown-linux-gnu", "", ModeAllFunc, true) + callback := mod.NamedFunction("callback") + wrapper, ok := tr.transformCallbackFunc(mod, callback) + if !ok { + t.Fatalf("callback wrapper was not required:\n%s", mod.String()) + } + + kind := llvm.AttributeKindID(attrName) + var wrapperHasAttr bool + for i := 1; i <= wrapper.GlobalValueType().ParamTypesCount(); i++ { + if !wrapper.GetEnumAttributeAtIndex(i, kind).IsNil() { + wrapperHasAttr = true + break + } + } + if !wrapperHasAttr { + t.Fatalf("callback wrapper lost/remapped %s:\n%s", attrName, wrapper.String()) + } + var callbackCall llvm.Value + for block := wrapper.FirstBasicBlock(); !block.IsNil(); block = llvm.NextBasicBlock(block) { + for instruction := block.FirstInstruction(); !instruction.IsNil(); instruction = llvm.NextInstruction(instruction) { + if call := instruction.IsACallInst(); !call.IsNil() && call.CalledValue() == callback { + callbackCall = call + } + } + } + if callbackCall.IsNil() || callbackCall.GetCallSiteEnumAttribute(1, kind).IsNil() { + t.Fatalf("callback wrapper call lost %s:\n%s", attrName, wrapper.String()) + } + if err := llvm.VerifyModule(mod, llvm.ReturnStatusAction); err != nil { + t.Fatalf("C ABI callback closure-env module is invalid: %v\n%s", err, mod.String()) + } + }) + } + }) + } +} + func TestSetSkipFuncsAndShouldSkipCall(t *testing.T) { tr := &Transformer{} tr.SetSkipFuncs([]string{" foo ", "", "bar"}) diff --git a/internal/dcepass/testdata/method_slots/expect.ll b/internal/dcepass/testdata/method_slots/expect.ll index b57057c77e..f8aa19371a 100644 --- a/internal/dcepass/testdata/method_slots/expect.ll +++ b/internal/dcepass/testdata/method_slots/expect.ll @@ -11,9 +11,9 @@ source_filename = "dst" %"runtime/abi.FuncType" = type { %"runtime/abi.Type", %runtime.Slice, %runtime.Slice } %Task = type {} -@_llgo_main.Task = constant { %"runtime/abi.StructType", %"runtime/abi.UncommonType", [2 x %"github.com/goplus/llgo/runtime/abi.Method"] } { %"runtime/abi.StructType" { %"runtime/abi.Type" { i64 0, i64 0, i32 1, i8 13, i8 1, i8 1, i8 25, { ptr, ptr } { ptr @memequal0, ptr @_llgo_main.Task }, ptr null, %runtime.String { ptr @0, i64 9 }, ptr @"*_llgo_main.Task" }, %runtime.String zeroinitializer, %runtime.Slice zeroinitializer }, %"runtime/abi.UncommonType" { %runtime.String { ptr @1, i64 4 }, i16 2, i16 2, i32 24 }, [2 x %"github.com/goplus/llgo/runtime/abi.Method"] [%"github.com/goplus/llgo/runtime/abi.Method" { %runtime.String { ptr @2, i64 4 }, ptr @"_llgo_func$run", ptr @"github.com/goplus/llgo/runtime/internal/runtime.unreachableMethod", ptr @"github.com/goplus/llgo/runtime/internal/runtime.unreachableMethod" }, %"github.com/goplus/llgo/runtime/abi.Method" { %runtime.String { ptr @3, i64 3 }, ptr @"_llgo_func$run", ptr @"main.(*Task).Run", ptr @__llgo_stub.main.Task.Run }] }, align 8 +@_llgo_main.Task = constant { %"runtime/abi.StructType", %"runtime/abi.UncommonType", [2 x %"github.com/goplus/llgo/runtime/abi.Method"] } { %"runtime/abi.StructType" { %"runtime/abi.Type" { i64 0, i64 0, i32 1, i8 13, i8 1, i8 1, i8 25, { ptr, ptr } { ptr @memequal0, ptr @_llgo_main.Task }, ptr null, %runtime.String { ptr @0, i64 9 }, ptr @"*_llgo_main.Task" }, %runtime.String zeroinitializer, %runtime.Slice zeroinitializer }, %"runtime/abi.UncommonType" { %runtime.String { ptr @1, i64 4 }, i16 2, i16 2, i32 24 }, [2 x %"github.com/goplus/llgo/runtime/abi.Method"] [%"github.com/goplus/llgo/runtime/abi.Method" { %runtime.String { ptr @2, i64 4 }, ptr @"_llgo_func$run", ptr @"github.com/goplus/llgo/runtime/internal/runtime.unreachableMethod", ptr @"github.com/goplus/llgo/runtime/internal/runtime.unreachableMethod" }, %"github.com/goplus/llgo/runtime/abi.Method" { %runtime.String { ptr @3, i64 3 }, ptr @"_llgo_func$run", ptr @"main.(*Task).Run", ptr @main.Task.Run }] }, align 8 @0 = private constant [9 x i8] c"main.Task", align 1 -@"*_llgo_main.Task" = constant { %"runtime/abi.PtrType", %"runtime/abi.UncommonType", [2 x %"github.com/goplus/llgo/runtime/abi.Method"] } { %"runtime/abi.PtrType" { %"runtime/abi.Type" { i64 8, i64 8, i32 2, i8 11, i8 8, i8 8, i8 54, { ptr, ptr } { ptr @memequalptr, ptr null }, ptr null, %runtime.String { ptr @0, i64 9 }, ptr null }, ptr @_llgo_main.Task }, %"runtime/abi.UncommonType" { %runtime.String { ptr @1, i64 4 }, i16 2, i16 2, i32 24 }, [2 x %"github.com/goplus/llgo/runtime/abi.Method"] [%"github.com/goplus/llgo/runtime/abi.Method" { %runtime.String { ptr @2, i64 4 }, ptr @"_llgo_func$run", ptr @"github.com/goplus/llgo/runtime/internal/runtime.unreachableMethod", ptr @"github.com/goplus/llgo/runtime/internal/runtime.unreachableMethod" }, %"github.com/goplus/llgo/runtime/abi.Method" { %runtime.String { ptr @3, i64 3 }, ptr @"_llgo_func$run", ptr @"main.(*Task).Run", ptr @"__llgo_stub.main.(*Task).Run" }] }, align 8 +@"*_llgo_main.Task" = constant { %"runtime/abi.PtrType", %"runtime/abi.UncommonType", [2 x %"github.com/goplus/llgo/runtime/abi.Method"] } { %"runtime/abi.PtrType" { %"runtime/abi.Type" { i64 8, i64 8, i32 2, i8 11, i8 8, i8 8, i8 54, { ptr, ptr } { ptr @memequalptr, ptr null }, ptr null, %runtime.String { ptr @0, i64 9 }, ptr null }, ptr @_llgo_main.Task }, %"runtime/abi.UncommonType" { %runtime.String { ptr @1, i64 4 }, i16 2, i16 2, i32 24 }, [2 x %"github.com/goplus/llgo/runtime/abi.Method"] [%"github.com/goplus/llgo/runtime/abi.Method" { %runtime.String { ptr @2, i64 4 }, ptr @"_llgo_func$run", ptr @"github.com/goplus/llgo/runtime/internal/runtime.unreachableMethod", ptr @"github.com/goplus/llgo/runtime/internal/runtime.unreachableMethod" }, %"github.com/goplus/llgo/runtime/abi.Method" { %runtime.String { ptr @3, i64 3 }, ptr @"_llgo_func$run", ptr @"main.(*Task).Run", ptr @"main.(*Task).Run" }] }, align 8 @1 = private constant [4 x i8] c"main", align 1 @2 = private constant [4 x i8] c"Drop", align 1 @"_llgo_func$run" = external global %"runtime/abi.FuncType" @@ -25,8 +25,6 @@ declare void @"github.com/goplus/llgo/runtime/internal/runtime.unreachableMethod declare i64 @"main.(*Task).Run"(ptr) -declare i64 @__llgo_stub.main.Task.Run(ptr, %Task) +declare i64 @main.Task.Run(%Task) declare i1 @memequalptr(ptr, ptr, ptr) - -declare i64 @"__llgo_stub.main.(*Task).Run"(ptr, ptr) diff --git a/internal/dcepass/testdata/method_slots/in.ll b/internal/dcepass/testdata/method_slots/in.ll index 9826dc82da..3608b71952 100644 --- a/internal/dcepass/testdata/method_slots/in.ll +++ b/internal/dcepass/testdata/method_slots/in.ll @@ -26,8 +26,8 @@ }, %"runtime/abi.UncommonType" { %"runtime.String" { ptr @task.pkg, i64 4 }, i16 2, i16 2, i32 24 }, [2 x %"github.com/goplus/llgo/runtime/abi.Method"] [ - %"github.com/goplus/llgo/runtime/abi.Method" { %"runtime.String" { ptr @method.drop, i64 4 }, ptr @_llgo_func$run, ptr @"main.(*Task).Drop", ptr @"__llgo_stub.main.Task.Drop" }, - %"github.com/goplus/llgo/runtime/abi.Method" { %"runtime.String" { ptr @method.run, i64 3 }, ptr @_llgo_func$run, ptr @"main.(*Task).Run", ptr @"__llgo_stub.main.Task.Run" } + %"github.com/goplus/llgo/runtime/abi.Method" { %"runtime.String" { ptr @method.drop, i64 4 }, ptr @_llgo_func$run, ptr @"main.(*Task).Drop", ptr @"main.Task.Drop" }, + %"github.com/goplus/llgo/runtime/abi.Method" { %"runtime.String" { ptr @method.run, i64 3 }, ptr @_llgo_func$run, ptr @"main.(*Task).Run", ptr @"main.Task.Run" } ] }, align 8 @@ -38,8 +38,8 @@ }, %"runtime/abi.UncommonType" { %"runtime.String" { ptr @task.pkg, i64 4 }, i16 2, i16 2, i32 24 }, [2 x %"github.com/goplus/llgo/runtime/abi.Method"] [ - %"github.com/goplus/llgo/runtime/abi.Method" { %"runtime.String" { ptr @method.drop, i64 4 }, ptr @_llgo_func$run, ptr @"main.(*Task).Drop", ptr @"__llgo_stub.main.(*Task).Drop" }, - %"github.com/goplus/llgo/runtime/abi.Method" { %"runtime.String" { ptr @method.run, i64 3 }, ptr @_llgo_func$run, ptr @"main.(*Task).Run", ptr @"__llgo_stub.main.(*Task).Run" } + %"github.com/goplus/llgo/runtime/abi.Method" { %"runtime.String" { ptr @method.drop, i64 4 }, ptr @_llgo_func$run, ptr @"main.(*Task).Drop", ptr @"main.(*Task).Drop" }, + %"github.com/goplus/llgo/runtime/abi.Method" { %"runtime.String" { ptr @method.run, i64 3 }, ptr @_llgo_func$run, ptr @"main.(*Task).Run", ptr @"main.(*Task).Run" } ] }, align 8 @@ -76,9 +76,7 @@ declare i1 @memequal0(ptr, ptr, ptr) declare i1 @memequalptr(ptr, ptr, ptr) declare i1 @memequal64(ptr, ptr, ptr) declare i1 @interequal(ptr, ptr, ptr) +declare i64 @"main.Task.Drop"(%Task) +declare i64 @"main.Task.Run"(%Task) declare i64 @"main.(*Task).Drop"(ptr) declare i64 @"main.(*Task).Run"(ptr) -declare i64 @"__llgo_stub.main.Task.Drop"(ptr, %Task) -declare i64 @"__llgo_stub.main.Task.Run"(ptr, %Task) -declare i64 @"__llgo_stub.main.(*Task).Drop"(ptr, ptr) -declare i64 @"__llgo_stub.main.(*Task).Run"(ptr, ptr) diff --git a/internal/pclnmap/pclnmap.go b/internal/pclnmap/pclnmap.go index e9e9d8da6d..7ff619571e 100644 --- a/internal/pclnmap/pclnmap.go +++ b/internal/pclnmap/pclnmap.go @@ -31,7 +31,7 @@ import ( const ( Magic = "LLGOPCL1" - Version = uint32(3) + Version = uint32(4) ABIVersion = uint32(1) HeaderSize = uint32(256) @@ -70,7 +70,6 @@ const ( descHash descSymbolIndex descEntrySites - descStubSites descPCSites descCount ) @@ -92,17 +91,17 @@ type SymbolIndexEntry struct { } // Site is a final linked PC expressed relative to the image base. ID is a -// symbol ID for EntrySites and StubSites, and a pcline record ID for PCSites. +// symbol ID for EntrySites and a pcline record ID for PCSites. type Site struct { PCOffset uint64 ID uint64 } // Data is the complete immutable payload needed by the external runtime -// loader. EntrySites and StubSites have each been normalized and -// LTO-deduplicated by the post-link analyzer. Keeping them distinct preserves -// the target function's canonical entry while still making closure ABI stubs -// independently symbolizable. +// loader. EntrySites are physical function entries normalized and +// LTO-deduplicated by the post-link analyzer. Compiler-generated wrappers and +// adapters use ordinary function records and entry sites; calling conventions +// and closure environment transport are deliberately not represented here. type Data struct { GOOS string GOARCH string @@ -114,7 +113,6 @@ type Data struct { Table funcinfo.Table SymbolIndex []SymbolIndexEntry EntrySites []Site - StubSites []Site PCSites []Site } @@ -200,7 +198,6 @@ func Encode(data Data) ([]byte, error) { {uint64(len(data.Table.Hash)), hashSize, 2}, {uint64(len(data.SymbolIndex)), symbolIndexSize, 8}, {uint64(len(data.EntrySites)), siteSize, 8}, - {uint64(len(data.StubSites)), siteSize, 8}, {uint64(len(data.PCSites)), siteSize, 8}, } @@ -284,7 +281,6 @@ func Encode(data Data) ([]byte, error) { } } writeSites(sections[descEntrySites], data.EntrySites) - writeSites(sections[descStubSites], data.StubSites) writeSites(sections[descPCSites], data.PCSites) binary.LittleEndian.PutUint64(out[headerPayloadHash:], fnv64(out[HeaderSize:])) return out, nil @@ -317,7 +313,7 @@ func descriptorSize(index int) uint64 { return hashSize case descSymbolIndex: return symbolIndexSize - case descEntrySites, descStubSites, descPCSites: + case descEntrySites, descPCSites: return siteSize default: return 0 @@ -328,7 +324,7 @@ func descriptorAlignment(index int) uint64 { switch index { case descRecords, descStringOffsets: return 4 - case descPCLines, descSymbolIndex, descEntrySites, descStubSites, descPCSites: + case descPCLines, descSymbolIndex, descEntrySites, descPCSites: return 8 case descHash: return 2 diff --git a/internal/pclnmap/pclnmap_test.go b/internal/pclnmap/pclnmap_test.go index e47efe7133..5bb96a2be5 100644 --- a/internal/pclnmap/pclnmap_test.go +++ b/internal/pclnmap/pclnmap_test.go @@ -31,7 +31,6 @@ func sampleData(t *testing.T) Data { Table: table, SymbolIndex: []SymbolIndexEntry{{SymbolID: 11, FuncIndex: 1}}, EntrySites: []Site{{PCOffset: 0x1010, ID: 11}}, - StubSites: []Site{{PCOffset: 0x1008, ID: 11}}, PCSites: []Site{{PCOffset: 0x1020, ID: 7}}, } } @@ -57,13 +56,6 @@ func TestEncodeParse(t *testing.T) { if got := view.Sections[descPCSites].Count; got != 1 { t.Fatalf("pcsite count = %d", got) } - if got := view.Sections[descStubSites].Count; got != 1 { - t.Fatalf("stub-site count = %d", got) - } - stub := raw[view.Sections[descStubSites].Offset:] - if pc, id := binary.LittleEndian.Uint64(stub), binary.LittleEndian.Uint64(stub[8:]); pc != 0x1008 || id != 11 { - t.Fatalf("stub site = {%#x, %d}, want {%#x, %d}", pc, id, uint64(0x1008), 11) - } raw2, err := Encode(sampleData(t)) if err != nil { t.Fatal(err) @@ -73,6 +65,19 @@ func TestEncodeParse(t *testing.T) { } } +func TestVersion4FunctionCentricDescriptorLayout(t *testing.T) { + if Version != 4 { + t.Fatalf("format version = %d, want 4", Version) + } + if descRecords != 0 || descPCLines != 1 || descStrings != 2 || + descStringOffsets != 3 || descHash != 4 || descSymbolIndex != 5 || + descEntrySites != 6 || descPCSites != 7 || descCount != 8 { + t.Fatalf("unexpected v4 descriptor layout: records=%d pclines=%d strings=%d offsets=%d hash=%d symbols=%d entries=%d pcsites=%d count=%d", + descRecords, descPCLines, descStrings, descStringOffsets, descHash, + descSymbolIndex, descEntrySites, descPCSites, descCount) + } +} + func TestEncodePreservesUint32StringIDs(t *testing.T) { data := sampleData(t) const ( @@ -147,29 +152,6 @@ func TestParseRejectsMisalignedSections(t *testing.T) { } } -func TestParseRejectsInvalidStubSection(t *testing.T) { - raw, err := Encode(sampleData(t)) - if err != nil { - t.Fatal(err) - } - stubDescriptor := headerDescriptors + descStubSites*16 - offset := binary.LittleEndian.Uint64(raw[stubDescriptor:]) - binary.LittleEndian.PutUint64(raw[stubDescriptor:], offset+1) - if _, err := Parse(raw); err == nil { - t.Fatal("Parse accepted a misaligned stub-site section") - } - - raw, err = Encode(sampleData(t)) - if err != nil { - t.Fatal(err) - } - binary.LittleEndian.PutUint64(raw[stubDescriptor:], uint64(len(raw))) - binary.LittleEndian.PutUint64(raw[stubDescriptor+8:], 1) - if _, err := Parse(raw); err == nil { - t.Fatal("Parse accepted an out-of-bounds stub-site section") - } -} - func TestEncodeRejectsUnsupportedTarget(t *testing.T) { data := sampleData(t) data.GOOS = "windows" diff --git a/internal/pclnpost/binary.go b/internal/pclnpost/binary.go index 7a5ec61572..36dd4e9091 100644 --- a/internal/pclnpost/binary.go +++ b/internal/pclnpost/binary.go @@ -16,7 +16,7 @@ // Package pclnpost implements the P1/P2 prototype of link-phase ftab/findfunctab // generation (doc/design/pclntab-linkphase.md). It parses a linked LLGo -// binary's funcinfo site sections, deduplicates LTO inline copies against the +// binary's funcinfo site section, deduplicates LTO inline copies against the // symbol table, sorts the entries, builds the Go-layout findfunctab via // internal/pclntab, and prints what the P2 build integration would write // back. It performs no writes; its purpose is to prove the risky steps on @@ -55,7 +55,6 @@ type binaryInfo struct { format string raw []byte entrySec []byte - stubSec []byte pcLineSec []byte textStart uint64 textEnd uint64 @@ -71,7 +70,6 @@ type binaryInfo struct { bindTargets []uint64 entryVMAddr, entryVMSize, entryFileOff uint64 - stubVMAddr, stubVMSize, stubFileOff uint64 pcLineVMSize, pcLineFileOff uint64 identityVMSize, identityFileOff uint64 hasCodeSignature bool @@ -122,13 +120,6 @@ func load(path string) (*binaryInfo, error) { } info.entryVMAddr, info.entryVMSize, info.entryFileOff = s.Addr, s.Size, uint64(s.Offset) } - if s := mf.Section("__llgo_stub"); s != nil { - info.stubSec, err = sectionBytes(info.raw, uint64(s.Offset), s.Size) - if err != nil { - return nil, fmt.Errorf("Mach-O __llgo_stub: %w", err) - } - info.stubVMAddr, info.stubVMSize, info.stubFileOff = s.Addr, s.Size, uint64(s.Offset) - } if s := mf.Section("__llgo_pcl"); s != nil { info.pcLineSec, err = sectionBytes(info.raw, uint64(s.Offset), s.Size) if err != nil { @@ -212,13 +203,6 @@ func load(path string) (*binaryInfo, error) { } info.entryVMAddr, info.entryVMSize, info.entryFileOff = s.Addr, s.Size, s.Offset } - if s := ef.Section("llgo_funcinfo_stubsite"); s != nil { - info.stubSec, err = sectionBytes(info.raw, s.Offset, s.Size) - if err != nil { - return nil, fmt.Errorf("ELF llgo_funcinfo_stubsite: %w", err) - } - info.stubVMAddr, info.stubVMSize, info.stubFileOff = s.Addr, s.Size, s.Offset - } if s := ef.Section("llgo_pcline"); s != nil { info.pcLineSec, err = sectionBytes(info.raw, s.Offset, s.Size) if err != nil { @@ -291,8 +275,7 @@ func parseRecords(info *binaryInfo, sec []byte) []siteRecord { // Mach-O pointer slots in the on-disk file hold dyld chained-fixup // encodings; dyld rewrites them at load. Rebase nodes // (DYLD_CHAINED_PTR_64) carry the target in the low 36 bits. Anchors - // naming *exported* functions — every `__llgo_stub.*` and any - // exported Go function — are emitted as BIND nodes instead (bit 63 + // naming exported functions are emitted as BIND nodes instead (bit 63 // set, import ordinal in the low 24 bits, addend above), even though // they bind back into this same image, so those resolve through the // imports table. The P2 write-back avoids the problem entirely by @@ -342,23 +325,15 @@ func fnv64(name string) uint64 { return h } -const stubPrefix = "__llgo_stub." - // canonicalOwner reports whether owner symbol `name` is the function the -// record's symbolID names, or that function's `__llgo_stub.` wrapper. +// record's symbolID names. // Mach-O symbol names carry a C-mangling underscore, and debug/macho's // suffix-shared string table can surface one underscore more or less than // the source-level name, so try each plausible normalization — matching a // specific 64-bit FNV makes a false positive practically impossible. func canonicalOwner(info *binaryInfo, name string, symbolID uint64) bool { for { - cand := name - if len(cand) > len(stubPrefix) { - if i := stringIndex(cand, stubPrefix); i >= 0 { - cand = cand[i+len(stubPrefix):] - } - } - if fnv64(cand) == symbolID { + if fnv64(name) == symbolID { return true } if info.format == "macho" && len(name) > 1 && name[0] == '_' { @@ -369,25 +344,13 @@ func canonicalOwner(info *binaryInfo, name string, symbolID uint64) bool { } } -func stringIndex(s, prefix string) int { - // prefix at the start, allowing for leading mangling underscores only - for i := 0; i+len(prefix) <= len(s) && i <= 2; i++ { - if s[i:i+len(prefix)] == prefix { - return i - } - if s[i] != '_' { - break - } - } - return -1 -} - // dedupe keeps exactly the canonical record per emitting function: a record // is canonical when the symbol that owns its anchor PC is the function the -// symbolID names (id == fnv64(owner)) or that function's closure stub -// (owner "__llgo_stub.X" with id == fnv64(X) — stubs share the target's -// symbolID by design). Everything else with a known owner is an LTO inline -// copy: inlining duplicated the body-embedded record into a host function. +// symbolID names (id == fnv64(owner)). Everything else with a known owner is +// an LTO inline copy: inlining duplicated the body-embedded record into a host +// function. A compiler-generated wrapper or adapter is therefore represented +// by its own funcinfo symbol and follows exactly the same path as any other +// function. // Kept records are normalized to their owner's true entry address. Records // whose owner cannot be determined are dropped conservatively. func dedupe(info *binaryInfo, recs []siteRecord, verbose bool) (kept []siteRecord, droppedInline, droppedUnknown int) { diff --git a/internal/pclnpost/binary_test.go b/internal/pclnpost/binary_test.go index b1b185cc8d..4d2ed130e0 100644 --- a/internal/pclnpost/binary_test.go +++ b/internal/pclnpost/binary_test.go @@ -34,17 +34,13 @@ func TestCanonicalOwner(t *testing.T) { }{ // ELF: symbol names are source-level. {elf, "example.com/p.F", true}, - {elf, "__llgo_stub.example.com/p.F", true}, {elf, "example.com/p.G", false}, // Mach-O: one C-mangling underscore, and debug/macho's suffix-shared // string table can surface one underscore more or less. {macho, "_example.com/p.F", true}, {macho, "example.com/p.F", true}, - {macho, "___llgo_stub.example.com/p.F", true}, - {macho, "__llgo_stub.example.com/p.F", true}, // An LTO inline copy: record id names F but the owner is the host. {macho, "_example.com/p.Host", false}, - {macho, "___llgo_stub.example.com/p.G", false}, } for _, c := range cases { if got := canonicalOwner(c.info, c.name, id); got != c.want { diff --git a/internal/pclnpost/elf_fixture_test.go b/internal/pclnpost/elf_fixture_test.go index ab11abba2e..2549499531 100644 --- a/internal/pclnpost/elf_fixture_test.go +++ b/internal/pclnpost/elf_fixture_test.go @@ -24,19 +24,19 @@ import ( "testing" ) -// buildELF fabricates the minimal ELF load() understands: .text, the two -// funcinfo site sections, a data section holding the symbol index, .symtab +// buildELF fabricates the minimal ELF load() understands: .text, the funcinfo +// entry-site section, a data section holding the symbol index, .symtab // and .strtab. Layout is one flat file segment; vmaddr == file offset + 0x10000. type elfFn struct { name string size uint64 } -func buildELF(t *testing.T, fns []elfFn, entryRecs, stubRecs func(addrOf func(string) uint64) []byte, entryPad, stubPad int) string { - return buildELFExternal(t, fns, entryRecs, stubRecs, entryPad, stubPad, nil, nil) +func buildELF(t *testing.T, fns []elfFn, entryRecs func(addrOf func(string) uint64) []byte, entryPad int) string { + return buildELFExternal(t, fns, entryRecs, entryPad, nil, nil) } -func buildELFExternal(t *testing.T, fns []elfFn, entryRecs, stubRecs func(addrOf func(string) uint64) []byte, entryPad, stubPad int, pcLine, identity []byte) string { +func buildELFExternal(t *testing.T, fns []elfFn, entryRecs func(addrOf func(string) uint64) []byte, entryPad int, pcLine, identity []byte) string { t.Helper() const base = uint64(0x10000) var text bytes.Buffer @@ -48,8 +48,6 @@ func buildELFExternal(t *testing.T, fns []elfFn, entryRecs, stubRecs func(addrOf addrOf := func(n string) uint64 { return addr[n] } entry := entryRecs(addrOf) entry = append(entry, make([]byte, entryPad)...) - stub := stubRecs(addrOf) - stub = append(stub, make([]byte, stubPad)...) // Symbol index: sorted {u64 fnv(name), u32 funcIndex, u32 pad}. type sie struct { @@ -102,7 +100,7 @@ func buildELFExternal(t *testing.T, fns []elfFn, entryRecs, stubRecs func(addrOf binary.Write(&symtab, binary.LittleEndian, fn.size) } - sectionNames := []string{".text", "llgo_funcinfo_entry", "llgo_funcinfo_stubsite"} + sectionNames := []string{".text", "llgo_funcinfo_entry"} if pcLine != nil { sectionNames = append(sectionNames, "llgo_pcline") } @@ -129,7 +127,6 @@ func buildELFExternal(t *testing.T, fns []elfFn, entryRecs, stubRecs func(addrOf secs := []sec{ {".text", 1, base, text.Bytes(), 0, 0}, {"llgo_funcinfo_entry", 1, base + 0x4000, entry, 0, 0}, - {"llgo_funcinfo_stubsite", 1, base + 0x6000, stub, 0, 0}, } if pcLine != nil { secs = append(secs, sec{"llgo_pcline", 1, base + 0x7000, pcLine, 0, 0}) @@ -195,7 +192,6 @@ func fixtureFns() []elfFn { return []elfFn{ {"example.com/p.A", 64}, {"example.com/p.B", 64}, - {"__llgo_stub.example.com/p.A", 16}, } } @@ -204,17 +200,13 @@ func fixtureEntry(addrOf func(string) uint64) []byte { return append(out, rec(addrOf("example.com/p.B")+4, fnv64("example.com/p.B"))...) } -func fixtureStub(addrOf func(string) uint64) []byte { - return rec(addrOf("__llgo_stub.example.com/p.A")+4, fnv64("example.com/p.A")) -} - func TestRewriteELFInPlace(t *testing.T) { - path := buildELF(t, fixtureFns(), fixtureEntry, fixtureStub, 4096, 256) + path := buildELF(t, fixtureFns(), fixtureEntry, 4096) st, err := Rewrite(path) if err != nil { t.Fatal(err) } - if st.FtabEntries != 4 { // A, B, stub, sentinel + if st.FtabEntries != 3 { // A, B, sentinel t.Fatalf("stats %+v", st) } // Idempotence guard. @@ -233,42 +225,10 @@ func TestRewriteELFInPlace(t *testing.T) { if base != 0x10000 { // first function entry t.Fatalf("base %#x", base) } - // Stub section voided. - for _, b := range info.stubSec { - if b != 0 { - t.Fatal("stub section not zeroed") - } - } -} - -func TestRewriteELFSpillsToStubSection(t *testing.T) { - // Entry section too small for the blob, stub section large enough. - path := buildELF(t, fixtureFns(), fixtureEntry, fixtureStub, 0, 8192) - st, err := Rewrite(path) - if err != nil { - t.Fatal(err) - } - if st.FtabEntries != 4 { - t.Fatalf("stats %+v", st) - } - info, err := load(path) - if err != nil { - t.Fatal(err) - } - if got := binary.LittleEndian.Uint64(info.entrySec[0:]); got != redirectMagic { - t.Fatalf("entry magic %#x", got) - } - if got := binary.LittleEndian.Uint64(info.stubSec[0:]); got != prebuiltMagic { - t.Fatalf("stub magic %#x", got) - } - if ptr := binary.LittleEndian.Uint64(info.entrySec[16:]); ptr != info.stubVMAddr { - t.Fatalf("redirect ptr %#x want %#x", ptr, info.stubVMAddr) - } } func TestRewriteELFOverflowFallsBack(t *testing.T) { - // Neither section fits: Rewrite must fail (no gap-y table). - path := buildELF(t, fixtureFns(), fixtureEntry, fixtureStub, 0, 0) + path := buildELF(t, fixtureFns(), fixtureEntry, 0) before, _ := os.ReadFile(path) if _, err := Rewrite(path); err == nil { t.Fatal("expected overflow error") @@ -282,7 +242,7 @@ func TestRewriteELFOverflowFallsBack(t *testing.T) { func TestRewriteErrorPaths(t *testing.T) { // No entry records at all. empty := func(addrOf func(string) uint64) []byte { return nil } - path := buildELF(t, fixtureFns(), empty, empty, 4096, 256) + path := buildELF(t, fixtureFns(), empty, 4096) if _, err := Rewrite(path); err == nil { t.Fatal("expected no-entry-records error") } @@ -290,7 +250,7 @@ func TestRewriteErrorPaths(t *testing.T) { orphan := func(addrOf func(string) uint64) []byte { return rec(0xdead0000, 42) } - path = buildELF(t, fixtureFns(), orphan, empty, 4096, 256) + path = buildELF(t, fixtureFns(), orphan, 4096) if _, err := Rewrite(path); err == nil { t.Fatal("expected no-survivors error") } diff --git a/internal/pclnpost/external.go b/internal/pclnpost/external.go index 136e66e70a..12bace90ff 100644 --- a/internal/pclnpost/external.go +++ b/internal/pclnpost/external.go @@ -47,8 +47,7 @@ type ExternalSite struct { // ExternalAnalysis is the immutable input for an external pclntab sidecar. // TextStart and TextEnd are link-time virtual addresses; sites are expressed -// relative to ImageBase. EntrySites and StubSites retain their distinct -// runtime meanings after LTO-copy deduplication against the final symbol +// relative to ImageBase after LTO-copy deduplication against the final symbol // table. Identity is SHA-256 of the complete, unmodified linked binary. type ExternalAnalysis struct { Format string @@ -59,18 +58,16 @@ type ExternalAnalysis struct { Identity [sha256.Size]byte EntrySites []ExternalSite - StubSites []ExternalSite PCLineSites []ExternalSite EntryRecords int - StubRecords int PCLineRecords int InlineCopies int NoSymbol int } // AnalyzeExternal reads a linked ELF or Mach-O executable without modifying -// it. It resolves Mach-O chained pointer slots, deduplicates function/stub +// it. It resolves Mach-O chained pointer slots, deduplicates function // records against final text symbols, and returns deterministic image-base- // relative site lists suitable for an external sidecar. func AnalyzeExternal(path string) (ExternalAnalysis, error) { @@ -83,29 +80,22 @@ func AnalyzeExternal(path string) (ExternalAnalysis, error) { return out, err } if len(info.entrySec) >= 8 { - if magic := binary.LittleEndian.Uint64(info.entrySec); magic == prebuiltMagic || magic == redirectMagic { + if magic := binary.LittleEndian.Uint64(info.entrySec); magic == prebuiltMagic { return out, fmt.Errorf("entry sites have already been rewritten") } } entries := parseRecords(info, info.entrySec) - stubs := parseRecords(info, info.stubSec) pcLines := parseRecords(info, info.pcLineSec) out.EntryRecords = len(entries) - out.StubRecords = len(stubs) out.PCLineRecords = len(pcLines) if len(entries) == 0 { return out, fmt.Errorf("no entry records") } - kept, inline, noSymbol := dedupe(info, append(entries, stubs...), false) + kept, inline, noSymbol := dedupe(info, entries, false) if len(kept) == 0 { return out, fmt.Errorf("no records survived dedup") } - keptEntries, keptStubs := partitionExternalEntries(info, kept) - if len(keptEntries) == 0 { - return out, fmt.Errorf("no entry records survived dedup") - } - out.Format = info.format out.PointerSize = info.pointerSize out.ImageBase = info.imageBase @@ -114,34 +104,11 @@ func AnalyzeExternal(path string) (ExternalAnalysis, error) { out.Identity = sha256.Sum256(info.raw) out.InlineCopies = inline out.NoSymbol = noSymbol - out.EntrySites = externalSites(info, keptEntries) - out.StubSites = externalSites(info, keptStubs) + out.EntrySites = externalSites(info, kept) out.PCLineSites = externalPCLineSites(info, pcLines) return out, nil } -// partitionExternalEntries classifies normalized records by their final -// linked owner, not by the input section that carried the anchor. LTO can -// inline a target body (and its entry anchor) into the target's closure stub, -// or retain a stub anchor in the target. In either case the final owner kind -// is authoritative for the runtime's canonical-entry semantics. -func partitionExternalEntries(info *binaryInfo, kept []siteRecord) (entries, stubs []siteRecord) { - entries = make([]siteRecord, 0, len(kept)) - stubs = make([]siteRecord, 0, len(kept)) - for _, record := range kept { - owner, ok := owner(info, record.pc) - if !ok { - continue - } - if stringIndex(owner.name, stubPrefix) >= 0 { - stubs = append(stubs, record) - } else { - entries = append(entries, record) - } - } - return entries, stubs -} - func validateExternalLayout(info *binaryInfo) error { if info.format != ExternalFormatELF && info.format != ExternalFormatMachO { return fmt.Errorf("unsupported binary format %q", info.format) @@ -209,7 +176,7 @@ func externalPCLineSites(info *binaryInfo, records []siteRecord) []ExternalSite sites = append(sites, ExternalSite{ PCOffset: record.pc - info.imageBase, ID: record.symbolID, - OwnerSymbol: externalOwnerSymbolName(sym.name), + OwnerSymbol: sym.name, }) } sort.Slice(sites, func(i, j int) bool { @@ -235,16 +202,9 @@ func externalPCLineSites(info *binaryInfo, records []siteRecord) []ExternalSite return out } -func externalOwnerSymbolName(name string) string { - if i := stringIndex(name, stubPrefix); i >= 0 { - return name[i+len(stubPrefix):] - } - return name -} - // DetachExternal verifies that identity still names the unmodified binary, // writes it into the dedicated 32-byte identity section, and clears all -// link-only entry, stub, and PC-line site sections. Mach-O chained fixups in +// link-only entry and PC-line site sections. Mach-O chained fixups in // those ranges are removed before the bytes are cleared. A signed Mach-O is // ad-hoc re-signed once, after all mutations, before the replacement is // published atomically. @@ -287,9 +247,6 @@ func DetachExternal(path string, identity [sha256.Size]byte) error { if err := addRange("entry-site", info.entryFileOff, info.entryVMSize); err != nil { return err } - if err := addRange("stub-site", info.stubFileOff, info.stubVMSize); err != nil { - return err - } if err := addRange("pcline-site", info.pcLineFileOff, info.pcLineVMSize); err != nil { return err } diff --git a/internal/pclnpost/external_test.go b/internal/pclnpost/external_test.go index 7eb85ab49a..5ee3636787 100644 --- a/internal/pclnpost/external_test.go +++ b/internal/pclnpost/external_test.go @@ -34,15 +34,7 @@ func externalELFFixture(t *testing.T, identitySize int) string { // LTO-style copy of A's body record in B: AnalyzeExternal must drop it. out = append(out, rec(addrOf("example.com/p.B")+8, idA)...) out = append(out, rec(addrOf("example.com/p.B")+4, fnv64("example.com/p.B"))...) - // LTO may also copy a target's entry-section anchor into its closure - // stub. Final-owner classification must keep this only as a stub site. - return append(out, rec(addrOf("__llgo_stub.example.com/p.A")+8, idA)...) - } - stub := func(addrOf func(string) uint64) []byte { - out := fixtureStub(addrOf) - // Conversely, a stub-section anchor retained in its real target must - // remain an ordinary entry and must not create a duplicate stub site. - return append(out, rec(addrOf("example.com/p.B")+12, fnv64("example.com/p.B"))...) + return out } const imageBase = uint64(0x10000) pcLine := rec(imageBase+8, 101) @@ -50,7 +42,7 @@ func externalELFFixture(t *testing.T, identitySize int) string { pcLine = append(pcLine, rec(imageBase+72, 202)...) pcLine = append(pcLine, rec(imageBase+76, 101)...) // A's pcline copied into B pcLine = append(pcLine, rec(0xdead0000, 303)...) // outside text - path := buildELFExternal(t, fixtureFns(), entry, stub, 256, 64, + path := buildELFExternal(t, fixtureFns(), entry, 256, pcLine, make([]byte, identitySize)) addELFLoadSegments(t, path, imageBase) return path @@ -99,13 +91,13 @@ func TestAnalyzeExternalELF(t *testing.T) { if analysis.Format != ExternalFormatELF || analysis.PointerSize != 8 { t.Fatalf("target = %s/%d", analysis.Format, analysis.PointerSize) } - if analysis.ImageBase != 0x10000 || analysis.TextStart != 0x10000 || analysis.TextEnd != 0x10090 { + if analysis.ImageBase != 0x10000 || analysis.TextStart != 0x10000 || analysis.TextEnd != 0x10080 { t.Fatalf("layout base=%#x text=[%#x,%#x)", analysis.ImageBase, analysis.TextStart, analysis.TextEnd) } if analysis.Identity != sha256.Sum256(before) { t.Fatal("identity is not the pre-mutation binary SHA-256") } - if analysis.EntryRecords != 4 || analysis.StubRecords != 2 || analysis.InlineCopies != 1 || analysis.NoSymbol != 0 { + if analysis.EntryRecords != 3 || analysis.InlineCopies != 1 || analysis.NoSymbol != 0 { t.Fatalf("analysis stats: %+v", analysis) } wantEntries := []ExternalSite{ @@ -115,10 +107,6 @@ func TestAnalyzeExternalELF(t *testing.T) { if !reflect.DeepEqual(analysis.EntrySites, wantEntries) { t.Fatalf("entry sites = %#v, want %#v", analysis.EntrySites, wantEntries) } - wantStubs := []ExternalSite{{PCOffset: 128, ID: fnv64("example.com/p.A")}} - if !reflect.DeepEqual(analysis.StubSites, wantStubs) { - t.Fatalf("stub sites = %#v, want %#v", analysis.StubSites, wantStubs) - } wantPCLines := []ExternalSite{ {PCOffset: 8, ID: 101, OwnerSymbol: "example.com/p.A"}, {PCOffset: 72, ID: 202, OwnerSymbol: "example.com/p.B"}, @@ -140,21 +128,6 @@ func TestAnalyzeExternalELF(t *testing.T) { } } -func TestExternalOwnerSymbolNameNormalizesStubs(t *testing.T) { - for _, name := range []string{ - "__llgo_stub.example.com/p.F", - "___llgo_stub.example.com/p.F", - "____llgo_stub.example.com/p.F", - } { - if got := externalOwnerSymbolName(name); got != "example.com/p.F" { - t.Fatalf("externalOwnerSymbolName(%q) = %q", name, got) - } - } - if got := externalOwnerSymbolName("__example.com/p.F"); got != "__example.com/p.F" { - t.Fatalf("ordinary owner was changed to %q", got) - } -} - func TestDetachExternalELF(t *testing.T) { path := externalELFFixture(t, sha256.Size) analysis, err := AnalyzeExternal(path) @@ -170,7 +143,6 @@ func TestDetachExternalELF(t *testing.T) { } for name, section := range map[string][]byte{ "entry": info.entrySec, - "stub": info.stubSec, "pcline": info.pcLineSec, } { if !bytes.Equal(section, make([]byte, len(section))) { @@ -232,20 +204,16 @@ func TestAnalyzeAndDetachExternalMachO(t *testing.T) { fns := []elfFn{ {name: "example.com/p.A", size: 0x10}, {name: "example.com/p.B", size: 0x40}, - {name: "__llgo_stub.example.com/p.A", size: 0x80}, } addr := func(off uint64) uint64 { return imageBase + 0x1000 + off } idA, idB := fnv64("example.com/p.A"), fnv64("example.com/p.B") entry := rec(addr(0x10)+4, idA) entry = append(entry, rec(addr(0x40)+8, idA)...) // inline A copy in B entry = append(entry, rec(addr(0x40)+4, idB)...) - entry = append(entry, rec(addr(0x80)+8, idA)...) // entry anchor copied into stub - stub := rec(addr(0x80)+4, idA) - stub = append(stub, rec(addr(0x40)+12, idB)...) // stub anchor retained in target pcLine := rec(addr(0x10)+8, 11) pcLine = append(pcLine, rec(addr(0x40)+8, 22)...) pcLine = append(pcLine, rec(addr(0x40)+12, 11)...) // A's pcline copied into B - path := buildMachOExternal(t, entry, stub, pcLine, make([]byte, sha256.Size), fns) + path := buildMachOExternal(t, entry, pcLine, make([]byte, sha256.Size), fns) pageStartOff := chainMachOSitePointers(t, path) analysis, err := AnalyzeExternal(path) @@ -262,10 +230,6 @@ func TestAnalyzeAndDetachExternalMachO(t *testing.T) { if !reflect.DeepEqual(analysis.EntrySites, wantEntries) || analysis.InlineCopies != 1 { t.Fatalf("entry analysis = %#v inline=%d", analysis.EntrySites, analysis.InlineCopies) } - wantStubs := []ExternalSite{{PCOffset: 0x1080, ID: idA}} - if !reflect.DeepEqual(analysis.StubSites, wantStubs) { - t.Fatalf("stub analysis = %#v, want %#v", analysis.StubSites, wantStubs) - } wantPCLines := []ExternalSite{ {PCOffset: 0x1018, ID: 11, OwnerSymbol: "example.com/p.A"}, {PCOffset: 0x1048, ID: 22, OwnerSymbol: "example.com/p.B"}, @@ -283,7 +247,6 @@ func TestAnalyzeAndDetachExternalMachO(t *testing.T) { } for name, section := range map[string][]byte{ "entry": info.entrySec, - "stub": info.stubSec, "pcline": info.pcLineSec, } { if !bytes.Equal(section, make([]byte, len(section))) { @@ -341,7 +304,7 @@ func TestExternalSitesFilterSortAndDedupe(t *testing.T) { textEnd: 0x1200, syms: []textSym{ {addr: 0x1100, size: 0x40, name: "example.com/p.A"}, - {addr: 0x1140, size: 0x40, name: "__llgo_stub.example.com/p.B"}, + {addr: 0x1140, size: 0x40, name: "example.com/p.B"}, }, } records := []siteRecord{ @@ -378,14 +341,6 @@ func TestExternalSitesFilterSortAndDedupe(t *testing.T) { t.Fatalf("singleton pcline sites = %#v", got) } - entries, stubs := partitionExternalEntries(info, []siteRecord{ - {pc: 0x1100, symbolID: 1}, - {pc: 0x1140, symbolID: 2}, - {pc: 0x1190, symbolID: 3}, - }) - if len(entries) != 1 || len(stubs) != 1 { - t.Fatalf("partition = (%#v, %#v)", entries, stubs) - } } func TestAnalyzeExternalRejectsInvalidRecordStates(t *testing.T) { @@ -394,13 +349,10 @@ func TestAnalyzeExternalRejectsInvalidRecordStates(t *testing.T) { inlineOnly := func(addrOf func(string) uint64) []byte { return rec(addrOf("example.com/p.A")+4, fnv64("example.com/p.B")) } - validStub := func(addrOf func(string) uint64) []byte { - return rec(addrOf("__llgo_stub.example.com/p.A")+4, fnv64("example.com/p.A")) - } tests := map[string]string{ - "no records": buildELFExternal(t, fixtureFns(), noRecords, noRecords, 0, 0, nil, make([]byte, sha256.Size)), - "no survivors": buildELFExternal(t, fixtureFns(), unknownRecord, noRecords, 0, 0, nil, make([]byte, sha256.Size)), - "stub only": buildELFExternal(t, fixtureFns(), inlineOnly, validStub, 0, 0, nil, make([]byte, sha256.Size)), + "no records": buildELFExternal(t, fixtureFns(), noRecords, 0, nil, make([]byte, sha256.Size)), + "no survivors": buildELFExternal(t, fixtureFns(), unknownRecord, 0, nil, make([]byte, sha256.Size)), + "inline only": buildELFExternal(t, fixtureFns(), inlineOnly, 0, nil, make([]byte, sha256.Size)), } for name, path := range tests { t.Run(name, func(t *testing.T) { @@ -457,7 +409,6 @@ func chainMachOSitePointers(t *testing.T, path string) uint64 { data []byte }{ {info.entryFileOff, info.entrySec}, - {info.stubFileOff, info.stubSec}, {info.pcLineFileOff, info.pcLineSec}, } { for off := 0; off+16 <= len(section.data); off += 16 { diff --git a/internal/pclnpost/logic_test.go b/internal/pclnpost/logic_test.go index 16b68da0e5..cd4cebef36 100644 --- a/internal/pclnpost/logic_test.go +++ b/internal/pclnpost/logic_test.go @@ -65,22 +65,20 @@ func TestDedupeCanonicalAndInline(t *testing.T) { info := &binaryInfo{format: "elf", textStart: 0x1000, textEnd: 0x4000, syms: []textSym{ {addr: 0x1000, size: 0x100, name: fn}, {addr: 0x1100, size: 0x100, name: host}, - {addr: 0x1200, size: 0x10, name: "__llgo_stub." + fn}, }} id := fnv64(fn) recs := []siteRecord{ {pc: 0x1004, symbolID: id}, // canonical, inside F {pc: 0x1104, symbolID: id}, // inline copy inside Host - {pc: 0x1204, symbolID: id}, // stub wrapper, canonical {pc: 0x1008, symbolID: id}, // duplicate owner, collapsed {pc: 0x9999, symbolID: id}, // no owner } kept, inline, nosym := dedupe(info, recs, false) - if len(kept) != 2 || inline != 1 || nosym != 1 { + if len(kept) != 1 || inline != 1 || nosym != 1 { t.Fatalf("kept=%d inline=%d nosym=%d", len(kept), inline, nosym) } - if kept[0].pc != 0x1000 || kept[1].pc != 0x1200 { - t.Fatalf("normalized pcs %#x %#x", kept[0].pc, kept[1].pc) + if kept[0].pc != 0x1000 { + t.Fatalf("normalized pc %#x", kept[0].pc) } } @@ -116,14 +114,14 @@ func TestFnv64NonZero(t *testing.T) { } func TestSymbolAddrBothFormats(t *testing.T) { - elfPath := buildELF(t, fixtureFns(), fixtureEntry, fixtureStub, 4096, 256) + elfPath := buildELF(t, fixtureFns(), fixtureEntry, 4096) if addr, err := symbolAddr(elfPath, "example.com/p.A"); err != nil || addr != 0x10000 { t.Fatalf("elf symbolAddr = %#x, %v", addr, err) } if _, err := symbolAddr(elfPath, "no.such.symbol"); err == nil { t.Fatal("expected missing-symbol error on elf") } - machoPath := buildMachO(t, rec(0, 0), rec(0, 0), + machoPath := buildMachO(t, rec(0, 0), []elfFn{{name: "example.com/p.M", size: 0x10}}) if addr, err := symbolAddr(machoPath, "example.com/p.M"); err != nil || addr == 0 { t.Fatalf("macho symbolAddr = %#x, %v", addr, err) diff --git a/internal/pclnpost/macho_fixture_test.go b/internal/pclnpost/macho_fixture_test.go index dcbdf67744..9200e11828 100644 --- a/internal/pclnpost/macho_fixture_test.go +++ b/internal/pclnpost/macho_fixture_test.go @@ -26,13 +26,13 @@ import ( // buildMachO fabricates a minimal 64-bit Mach-O that debug/macho can Open: // one __TEXT segment (__text) and one __DATA segment carrying __llgo_fie / -// __llgo_stub, plus LC_SYMTAB and an LC_DYLD_CHAINED_FIXUPS whose imports +// optional pcline data, plus LC_SYMTAB and an LC_DYLD_CHAINED_FIXUPS whose imports // table binds ordinal 1 to a local symbol. -func buildMachO(t *testing.T, entry, stub []byte, syms []elfFn) string { - return buildMachOExternal(t, entry, stub, nil, nil, syms) +func buildMachO(t *testing.T, entry []byte, syms []elfFn) string { + return buildMachOExternal(t, entry, nil, nil, syms) } -func buildMachOExternal(t *testing.T, entry, stub, pcLine, identity []byte, syms []elfFn) string { +func buildMachOExternal(t *testing.T, entry, pcLine, identity []byte, syms []elfFn) string { t.Helper() const base = uint64(0x100000000) text := make([]byte, 0x40000) // big enough that findfunctab buckets outgrow a tiny entry section @@ -68,8 +68,7 @@ func buildMachOExternal(t *testing.T, entry, stub, pcLine, identity []byte, syms // File layout (fixed offsets, one page apart). const textOff = uint64(0x1000) const entryOff = uint64(0x2000) - stubOff := entryOff + uint64(len(entry)) - dataEnd := stubOff + uint64(len(stub)) + dataEnd := entryOff + uint64(len(entry)) pcLineOff := dataEnd if pcLine != nil { dataEnd += uint64(len(pcLine)) @@ -89,7 +88,6 @@ func buildMachOExternal(t *testing.T, entry, stub, pcLine, identity []byte, syms })}) dataSections := [][]byte{ sect("__llgo_fie", "__DATA", base+entryOff, entryOff, uint64(len(entry))), - sect("__llgo_stub", "__DATA", base+stubOff, stubOff, uint64(len(stub))), } if pcLine != nil { dataSections = append(dataSections, sect("__llgo_pcl", "__DATA", base+pcLineOff, pcLineOff, uint64(len(pcLine)))) @@ -192,7 +190,6 @@ func buildMachOExternal(t *testing.T, entry, stub, pcLine, identity []byte, syms copy(raw[32:], cmdBytes) copy(raw[textOff:], text) copy(raw[entryOff:], entry) - copy(raw[stubOff:], stub) if pcLine != nil { copy(raw[pcLineOff:], pcLine) } @@ -221,9 +218,7 @@ func TestLoadMachOFixture(t *testing.T) { badBind := uint64(1) << 63 entry := append(rec(rebase, fnv64("example.com/p.B")), rec(bind, fnv64("example.com/p.A"))...) entry = append(entry, rec(badBind, 99)...) - stub := rec(0, 0) - - path := buildMachO(t, entry, stub, fns) + path := buildMachO(t, entry, fns) info, err := load(path) if err != nil { t.Fatal(err) @@ -252,7 +247,7 @@ func TestLoadMachOFixture(t *testing.T) { // machoRewriteFixture: records anchored inside real text symbols so dedupe // keeps them, plus a meta record advertising the symbol index inside the // entry section (readVM resolves it through the __DATA section). -func machoRewriteFixture(t *testing.T, entryPad, stubPad int) string { +func machoRewriteFixture(t *testing.T, entryPad int) string { t.Helper() const base = uint64(0x100000000) fns := []elfFn{{name: "example.com/p.A", size: 0x10}, {name: "example.com/p.B", size: 0x3F000}} // far apart: findfunctab spans many buckets @@ -298,12 +293,11 @@ func machoRewriteFixture(t *testing.T, entryPad, stubPad int) string { binary.LittleEndian.PutUint64(entry[16:], ptrAddr) binary.LittleEndian.PutUint64(entry[32:], cntAddr) entry = append(entry, make([]byte, entryPad)...) - stub := append(rec(0, 0), make([]byte, stubPad)...) - return buildMachO(t, entry, stub, fns) + return buildMachO(t, entry, fns) } func TestRewriteMachOInPlace(t *testing.T) { - path := machoRewriteFixture(t, 4096, 512) + path := machoRewriteFixture(t, 4096) st, err := Rewrite(path) if err != nil { t.Fatal(err) @@ -319,24 +313,3 @@ func TestRewriteMachOInPlace(t *testing.T) { t.Fatalf("magic %#x", got) } } - -func TestRewriteMachOSpill(t *testing.T) { - path := machoRewriteFixture(t, 0, 8192) - st, err := Rewrite(path) - if err != nil { - t.Fatal(err) - } - if st.FtabEntries != 3 { - t.Fatalf("stats %+v", st) - } - info, err := load(path) - if err != nil { - t.Fatal(err) - } - if got := binary.LittleEndian.Uint64(info.entrySec[0:]); got != redirectMagic { - t.Fatalf("entry magic %#x", got) - } - if got := binary.LittleEndian.Uint64(info.stubSec[0:]); got != prebuiltMagic { - t.Fatalf("stub magic %#x", got) - } -} diff --git a/internal/pclnpost/pclnpost.go b/internal/pclnpost/pclnpost.go index 053c9ed5fe..91bc59b802 100644 --- a/internal/pclnpost/pclnpost.go +++ b/internal/pclnpost/pclnpost.go @@ -25,7 +25,6 @@ import ( type Stats struct { Format string EntryRecords int - StubRecords int Kept int InlineCopies int NoSymbol int @@ -35,7 +34,7 @@ type Stats struct { // Rewrite parses the linked binary's funcinfo site sections, deduplicates // LTO inline copies against the symbol table, builds the Go-layout prebuilt -// table and rewrites the entry section in place (voiding the stub section). +// table and rewrites the entry section in place. // The runtime adopts the table when it sees the magic header and falls back // to first-use construction otherwise, so failures here leave a fully // functional binary. @@ -47,29 +46,22 @@ func Rewrite(path string) (Stats, error) { } st.Format = info.format if len(info.entrySec) >= 8 { - if m := binary.LittleEndian.Uint64(info.entrySec); m == prebuiltMagic || m == redirectMagic { + if m := binary.LittleEndian.Uint64(info.entrySec); m == prebuiltMagic { return st, fmt.Errorf("already rewritten") } } entries := parseRecords(info, info.entrySec) - stubs := parseRecords(info, info.stubSec) - st.EntryRecords, st.StubRecords = len(entries), len(stubs) + st.EntryRecords = len(entries) if len(entries) == 0 { return st, fmt.Errorf("no entry records") } - kept, inline, nosym := dedupe(info, append(entries, stubs...), false) + kept, inline, nosym := dedupe(info, entries, false) st.Kept, st.InlineCopies, st.NoSymbol = len(kept), inline, nosym if len(kept) == 0 { return st, fmt.Errorf("no records survived dedup") } ftab, buckets, err := writeBack(path, info, kept) if err != nil { - // Includes errBlobOverflow when the blob fits neither the entry nor - // the stub section. Never drop stub rows to squeeze in: a table with - // gaps attributes pcs inside a gap to the previous function - // (nearest-below), which silently returns wrong names on platforms - // where dladdr cannot rescue (non-PIE ELF). First-use construction - // is slower but correct. return st, err } st.FtabEntries, st.Buckets = ftab, buckets diff --git a/internal/pclnpost/write.go b/internal/pclnpost/write.go index def30eed2e..413f4048a0 100644 --- a/internal/pclnpost/write.go +++ b/internal/pclnpost/write.go @@ -20,7 +20,6 @@ import ( "debug/elf" "debug/macho" "encoding/binary" - "errors" "fmt" "os" "os/exec" @@ -41,19 +40,6 @@ import ( // on non-PIE ELF the link-time value already equals the runtime address. const prebuiltMagic = uint64(0x314254464F474C4C) -// errBlobOverflow reports that the prebuilt blob fits neither the entry -// section nor the (larger) stub section; the caller retries without stub -// rows before giving up. -var errBlobOverflow = errors.New("prebuilt blob does not fit entry or stub section") - -// redirectMagic ("LLGOFTB2" little-endian) marks a 32-byte entry-section -// header whose third word points at the real blob, written into the stub -// section when the table outgrows the entry section (stub rows can double -// the count). The pointer slot is a live relocation like the in-place base -// slot: dyld rebases it on Mach-O, and non-PIE ELF link addresses already -// equal runtime addresses. -const redirectMagic = uint64(0x324254464F474C4C) - const ( bucketSize = 4096 subbucketCnt = 16 @@ -66,8 +52,7 @@ type symIndexEntry struct { idx uint32 } -// writeBack rewrites the entry-site section in place with the prebuilt table -// and voids the stub section (its records are merged into the table). +// writeBack rewrites the entry-site section in place with the prebuilt table. func writeBack(path string, info *binaryInfo, kept []siteRecord) (ftabCount, bucketCount int, err error) { symIdx, err := loadSymbolIndex(path, info) if err != nil { @@ -131,22 +116,12 @@ func writeBack(path string, info *binaryInfo, kept []siteRecord) (ftabCount, buc } need := 32 + count*8 + len(buckets) - entrySize := int(info.entryVMSize) - spill := need > entrySize - if spill && need > int(info.stubVMSize) { - return 0, 0, errBlobOverflow - } - blobSect := int(info.entryVMSize) - blobFileOff := info.entryFileOff - blobVMAddr := info.entryVMAddr - if spill { - blobSect = int(info.stubVMSize) - blobFileOff = info.stubFileOff - blobVMAddr = info.stubVMAddr + if need > int(info.entryVMSize) { + return 0, 0, fmt.Errorf("prebuilt blob needs %d bytes; entry section has %d", need, info.entryVMSize) } - blob := make([]byte, blobSect) // zero tail + blob := make([]byte, int(info.entryVMSize)) // zero tail binary.LittleEndian.PutUint64(blob[0:], prebuiltMagic) - binary.LittleEndian.PutUint64(blob[8:], blobVMAddr) + binary.LittleEndian.PutUint64(blob[8:], info.entryVMAddr) binary.LittleEndian.PutUint64(blob[16:], base) binary.LittleEndian.PutUint32(blob[24:], uint32(count)) binary.LittleEndian.PutUint32(blob[28:], uint32(len(buckets)/bucketBytes)) @@ -165,51 +140,23 @@ func writeBack(path string, info *binaryInfo, kept []siteRecord) (ftabCount, buc copy(raw, info.raw) var pending []pendingWrite if info.format == "macho" { - // Remove the rewritten sections' pointer slots from dyld's chained + // Remove the rewritten section's pointer slots from dyld's chained // fixup page chains first: otherwise dyld rebases 8-byte slots - // inside the new table at load time, and a chain terminating early - // inside the zeroed stub section would skip unrelated fixups later - // in the same page. + // inside the new table at load time. ranges := [][2]uint64{{info.entryFileOff, info.entryFileOff + info.entryVMSize}} - if info.stubVMSize > 0 { - ranges = append(ranges, [2]uint64{info.stubFileOff, info.stubFileOff + info.stubVMSize}) - } // Pointer slots are spliced back into the chain as live rebase // nodes: dyld writes *slid* addresses at load, so the runtime reads // ready runtime pointers with no slide arithmetic. - inserts := []fixupInsert{{fileOff: blobFileOff + 16, targetVM: base}} - if spill { - inserts = append(inserts, fixupInsert{fileOff: info.entryFileOff + 16, targetVM: info.stubVMAddr}) - } + inserts := []fixupInsert{{fileOff: info.entryFileOff + 16, targetVM: base}} pending, err = unchainRanges(raw, ranges, inserts) if err != nil { return 0, 0, fmt.Errorf("chained fixups: %w", err) } } - if spill { - // Entry section: zero + 32-byte redirect header to the stub-section - // blob. Zeroed records keep the runtime's fallback scans empty. - zero := raw[info.entryFileOff : info.entryFileOff+info.entryVMSize] - for i := range zero { - zero[i] = 0 - } - binary.LittleEndian.PutUint64(zero[0:], redirectMagic) - binary.LittleEndian.PutUint64(zero[8:], info.entryVMAddr) - binary.LittleEndian.PutUint64(zero[16:], info.stubVMAddr) - } - copy(raw[blobFileOff:], blob) + copy(raw[info.entryFileOff:], blob) for _, pw := range pending { binary.LittleEndian.PutUint64(raw[pw.fileOff:], pw.val) } - // Void the stub section when the blob lives in the entry section: zero - // its records so the runtime's fallback scan finds nothing (stub entries - // are already merged into the table above). - if !spill && info.stubVMSize > 0 { - zero := raw[info.stubFileOff : info.stubFileOff+info.stubVMSize] - for i := range zero { - zero[i] = 0 - } - } st, err := os.Stat(path) if err != nil { return 0, 0, err diff --git a/runtime/internal/clite/ffi/_wrap/libffi.c b/runtime/internal/clite/ffi/_wrap/libffi.c index 016a74ec3d..32bdf00522 100644 --- a/runtime/internal/clite/ffi/_wrap/libffi.c +++ b/runtime/internal/clite/ffi/_wrap/libffi.c @@ -3,3 +3,244 @@ void *llgo_ffi_closure_alloc(void **code) { return ffi_closure_alloc(sizeof(ffi_closure), code); } + +/* + * Use libffi's Go ABI directly when its static-chain register is LLGo's nest + * register. ARM32 needs only a final register bridge from libffi's IP/R12 to + * swiftself/R10. Use the public-ffi_call trampoline when libffi does not + * expose its Go ABI on x86, and on AArch64 Apple/Android where X18 is reserved + * and LLGo uses swiftself/X20 instead. + * + * Windows follows the same architecture-selected closure ABI even though LLGo + * does not support the OS yet. x86 can use the direct path below. TODO: add and + * validate the Windows ARM/AArch64 FFI final hop without changing that ABI. + */ +#if defined(__x86_64__) || defined(__i386__) || defined(__riscv) || \ + defined(__riscv__) || defined(__arm__) || defined(__aarch64__) +#define LLGO_FFI_HIDDEN_ENV_TARGET 1 +#endif + +#if defined(FFI_GO_CLOSURES) && \ + (defined(__x86_64__) || defined(__i386__) || defined(__riscv) || \ + defined(__riscv__) || \ + (defined(__aarch64__) && !defined(__APPLE__) && !defined(__ANDROID__) && \ + !defined(_WIN32))) +#define LLGO_FFI_CALL_GO_DIRECT 1 +#elif !defined(_WIN32) && defined(__arm__) +#define LLGO_FFI_CALL_GO_ARM_BRIDGE 1 +#elif !defined(_WIN32) && \ + (((defined(__x86_64__) || defined(__i386__)) && \ + !defined(FFI_GO_CLOSURES)) || \ + (defined(__aarch64__) && \ + (defined(__APPLE__) || defined(__ANDROID__)))) +#define LLGO_FFI_CALL_PUBLIC_TRAMPOLINE 1 +#endif + +#if defined(LLGO_FFI_CALL_GO_ARM_BRIDGE) && !defined(FFI_GO_CLOSURES) +#error "LLGo hidden closure environments require libffi Go closures on ARM" +#elif !defined(_WIN32) && !defined(FFI_GO_CLOSURES) && \ + (defined(__riscv) || defined(__riscv__) || \ + (defined(__aarch64__) && !defined(__APPLE__) && !defined(__ANDROID__) && \ + !defined(_WIN32))) +#error "LLGo hidden closure environments require libffi Go closures on this target" +#elif defined(_WIN32) && (defined(__arm__) || defined(__aarch64__)) +#error "LLGo Windows ARM hidden-env FFI final hop is not implemented" +#elif defined(LLGO_FFI_HIDDEN_ENV_TARGET) && \ + (defined(LLGO_FFI_CALL_GO_DIRECT) + \ + defined(LLGO_FFI_CALL_GO_ARM_BRIDGE) + \ + defined(LLGO_FFI_CALL_PUBLIC_TRAMPOLINE) != \ + 1) +#error "LLGo hidden-env target must select exactly one libffi final-hop path" +#endif + +#if defined(LLGO_FFI_CALL_GO_DIRECT) + +void llgo_ffi_call_with_env(ffi_cif *cif, void (*fn)(void), void *rvalue, + void **avalue, void *env) { + ffi_call_go(cif, fn, rvalue, avalue, env); +} + +#elif defined(LLGO_FFI_CALL_GO_ARM_BRIDGE) + +struct llgo_ffi_call_context { + void (*target)(void); + void *env; + void *saved_callee; + void *saved_self; + void *saved_return; +}; + +/* The target must return normally through this bridge so its callee-saved + * registers and return address can be restored. */ + +/* + * ffi_call_go enters this function with the context in IP/R12 and all real + * arguments already marshalled. Preserve the callee-saved registers used by + * the continuation, install swiftself/R10, and enter the target without + * changing SP or any argument register. + */ +__attribute__((naked)) static void llgo_ffi_env_trampoline(void) { + __asm__ volatile( + "str r4, [r12, #8]\n\t" + "str r10, [r12, #12]\n\t" + "str lr, [r12, #16]\n\t" + "mov r4, r12\n\t" + "ldr r10, [r12, #4]\n\t" + "ldr r12, [r12, #0]\n\t" + "blx r12\n\t" + "ldr r12, [r4, #8]\n\t" + "ldr r10, [r4, #12]\n\t" + "ldr lr, [r4, #16]\n\t" + "mov r4, r12\n\t" + "bx lr"); +} + +void llgo_ffi_call_with_env(ffi_cif *cif, void (*fn)(void), void *rvalue, + void **avalue, void *env) { + struct llgo_ffi_call_context call = { + .target = fn, + .env = env, + }; + ffi_call_go(cif, llgo_ffi_env_trampoline, rvalue, avalue, &call); +} + +#elif defined(LLGO_FFI_CALL_PUBLIC_TRAMPOLINE) + +/* + * Public ffi_call cannot transport the hidden environment register. Keep the + * real target and env in per-thread state while libffi marshals the arguments. + * Its final target saves those arguments, obtains the state, installs the + * target register, and enters the real entry with the original SP. + */ +struct llgo_ffi_call_context { + void (*target)(void); + void *env; + void *saved_callee; + void *saved_self; + void *saved_return; +}; + +/* Targets must return normally through ffi_call. A non-local exit would skip + * both the trampoline's register restore and the prior TLS-context restore. */ + +static _Thread_local struct llgo_ffi_call_context llgo_ffi_call_current; + +__attribute__((noinline, used)) static struct llgo_ffi_call_context * +llgo_ffi_current_call(void) { + return &llgo_ffi_call_current; +} + +#if defined(__APPLE__) +#define LLGO_ASM_CSYM(name) "_" #name +#else +#define LLGO_ASM_CSYM(name) #name +#endif + +#if defined(__x86_64__) + +__attribute__((naked)) static void llgo_ffi_env_trampoline(void) { + __asm__ volatile( + "subq $200, %rsp\n\t" + "movq %rdi, 0(%rsp)\n\t" + "movq %rsi, 8(%rsp)\n\t" + "movq %rdx, 16(%rsp)\n\t" + "movq %rcx, 24(%rsp)\n\t" + "movq %r8, 32(%rsp)\n\t" + "movq %r9, 40(%rsp)\n\t" + "movq %rax, 48(%rsp)\n\t" + "movdqu %xmm0, 64(%rsp)\n\t" + "movdqu %xmm1, 80(%rsp)\n\t" + "movdqu %xmm2, 96(%rsp)\n\t" + "movdqu %xmm3, 112(%rsp)\n\t" + "movdqu %xmm4, 128(%rsp)\n\t" + "movdqu %xmm5, 144(%rsp)\n\t" + "movdqu %xmm6, 160(%rsp)\n\t" + "movdqu %xmm7, 176(%rsp)\n\t" + "callq " LLGO_ASM_CSYM(llgo_ffi_current_call) "\n\t" + "movq 0(%rax), %r11\n\t" + "movq 8(%rax), %r10\n\t" + "movdqu 64(%rsp), %xmm0\n\t" + "movdqu 80(%rsp), %xmm1\n\t" + "movdqu 96(%rsp), %xmm2\n\t" + "movdqu 112(%rsp), %xmm3\n\t" + "movdqu 128(%rsp), %xmm4\n\t" + "movdqu 144(%rsp), %xmm5\n\t" + "movdqu 160(%rsp), %xmm6\n\t" + "movdqu 176(%rsp), %xmm7\n\t" + "movq 0(%rsp), %rdi\n\t" + "movq 8(%rsp), %rsi\n\t" + "movq 16(%rsp), %rdx\n\t" + "movq 24(%rsp), %rcx\n\t" + "movq 32(%rsp), %r8\n\t" + "movq 40(%rsp), %r9\n\t" + "movq 48(%rsp), %rax\n\t" + "addq $200, %rsp\n\t" + "jmpq *%r11"); +} + +#elif defined(__i386__) + +__attribute__((naked)) static void llgo_ffi_env_trampoline(void) { + __asm__ volatile( + "subl $12, %esp\n\t" + "calll " LLGO_ASM_CSYM(llgo_ffi_current_call) "\n\t" + "movl 0(%eax), %edx\n\t" + "movl 4(%eax), %ecx\n\t" + "addl $12, %esp\n\t" + "jmpl *%edx"); +} + +#elif defined(__aarch64__) + +__attribute__((naked)) static void llgo_ffi_env_trampoline(void) { + __asm__ volatile( + "sub sp, sp, #224\n\t" + "stp x0, x1, [sp, #0]\n\t" + "stp x2, x3, [sp, #16]\n\t" + "stp x4, x5, [sp, #32]\n\t" + "stp x6, x7, [sp, #48]\n\t" + "str x8, [sp, #64]\n\t" + "str x30, [sp, #72]\n\t" + "stp q0, q1, [sp, #80]\n\t" + "stp q2, q3, [sp, #112]\n\t" + "stp q4, q5, [sp, #144]\n\t" + "stp q6, q7, [sp, #176]\n\t" + "bl " LLGO_ASM_CSYM(llgo_ffi_current_call) "\n\t" + "mov x16, x0\n\t" + "ldr x17, [x16, #0]\n\t" + "str x19, [x16, #16]\n\t" + "str x20, [x16, #24]\n\t" + "ldr x15, [sp, #72]\n\t" + "str x15, [x16, #32]\n\t" + "mov x19, x16\n\t" + "ldr x20, [x16, #8]\n\t" + "ldp q0, q1, [sp, #80]\n\t" + "ldp q2, q3, [sp, #112]\n\t" + "ldp q4, q5, [sp, #144]\n\t" + "ldp q6, q7, [sp, #176]\n\t" + "ldr x8, [sp, #64]\n\t" + "ldp x0, x1, [sp, #0]\n\t" + "ldp x2, x3, [sp, #16]\n\t" + "ldp x4, x5, [sp, #32]\n\t" + "ldp x6, x7, [sp, #48]\n\t" + "add sp, sp, #224\n\t" + "blr x17\n\t" + "ldr x16, [x19, #16]\n\t" + "ldr x20, [x19, #24]\n\t" + "ldr x30, [x19, #32]\n\t" + "mov x19, x16\n\t" + "ret"); +} + +#endif + +void llgo_ffi_call_with_env(ffi_cif *cif, void (*fn)(void), void *rvalue, + void **avalue, void *env) { + struct llgo_ffi_call_context previous = llgo_ffi_call_current; + llgo_ffi_call_current.target = fn; + llgo_ffi_call_current.env = env; + ffi_call(cif, llgo_ffi_env_trampoline, rvalue, avalue); + llgo_ffi_call_current = previous; +} + +#endif diff --git a/runtime/internal/clite/ffi/ffi_link.go b/runtime/internal/clite/ffi/ffi_link.go index b3a908641d..12fb9e2fe5 100644 --- a/runtime/internal/clite/ffi/ffi_link.go +++ b/runtime/internal/clite/ffi/ffi_link.go @@ -42,6 +42,12 @@ void ffi_call(ffi_cif *cif, //go:linkname Call C.ffi_call func Call(cif *Cif, fn unsafe.Pointer, rvalue unsafe.Pointer, avalue *unsafe.Pointer) +// CallWithEnv calls a native hidden-env entry. cif and avalue contain only the +// semantic arguments; env is installed by the architecture-specific final hop. +// +//go:linkname CallWithEnv C.llgo_ffi_call_with_env +func CallWithEnv(cif *Cif, fn unsafe.Pointer, rvalue unsafe.Pointer, avalue *unsafe.Pointer, env unsafe.Pointer) + // void *ffi_closure_alloc (size_t size, void **code); // //go:linkname ClosureAlloc C.llgo_ffi_closure_alloc diff --git a/runtime/internal/ffi/call_llgo_explicit.go b/runtime/internal/ffi/call_llgo_explicit.go new file mode 100644 index 0000000000..b96cc1aca8 --- /dev/null +++ b/runtime/internal/ffi/call_llgo_explicit.go @@ -0,0 +1,15 @@ +//go:build !llgo || llgo_closure_env_explicit || (llgo && !llgo_closure_env_nest && !llgo_closure_env_swiftself) + +package ffi + +import "unsafe" + +// ClosureEnvExplicit is a compile-time target property. +const ClosureEnvExplicit = true + +// CallWithEnv calls fn through ordinary libffi on an explicit-context target. +// When env is required, the caller has already prepended its type and value to +// cif and args; the separately supplied env is therefore intentionally unused. +func CallWithEnv(cif *Signature, fn, _ unsafe.Pointer, ret unsafe.Pointer, args ...unsafe.Pointer) { + Call(cif, fn, ret, args...) +} diff --git a/runtime/internal/ffi/call_llgo_nest.go b/runtime/internal/ffi/call_llgo_nest.go new file mode 100644 index 0000000000..b71fe79fc4 --- /dev/null +++ b/runtime/internal/ffi/call_llgo_nest.go @@ -0,0 +1,22 @@ +//go:build llgo && llgo_closure_env_nest + +package ffi + +import ( + "unsafe" + + "github.com/goplus/llgo/runtime/internal/clite/ffi" +) + +const ClosureEnvExplicit = false + +// CallWithEnv invokes fn with a semantic CIF that does not contain env. The +// native final hop passes env separately in LLVM's nest register, using +// ffi_call_go directly when libffi selects the same physical register. +func CallWithEnv(cif *Signature, fn, env, ret unsafe.Pointer, args ...unsafe.Pointer) { + var avalues *unsafe.Pointer + if len(args) > 0 { + avalues = &args[0] + } + ffi.CallWithEnv(cif, fn, ret, avalues, env) +} diff --git a/runtime/internal/ffi/call_llgo_swiftself.go b/runtime/internal/ffi/call_llgo_swiftself.go new file mode 100644 index 0000000000..3ebc0a3e10 --- /dev/null +++ b/runtime/internal/ffi/call_llgo_swiftself.go @@ -0,0 +1,24 @@ +//go:build llgo && llgo_closure_env_swiftself + +package ffi + +import ( + "unsafe" + + "github.com/goplus/llgo/runtime/internal/clite/ffi" +) + +const ClosureEnvExplicit = false + +// CallWithEnv invokes fn with a semantic CIF that does not contain env. The +// native final hop passes env separately in LLVM's swiftself register: ARM32 +// bridges libffi's R12 static chain to R10, while AArch64 targets that reserve +// X18 use a TLS trampoline to install X20. Nil is installed as well so native +// dynamic calls keep one uniform path. +func CallWithEnv(cif *Signature, fn, env, ret unsafe.Pointer, args ...unsafe.Pointer) { + var avalues *unsafe.Pointer + if len(args) > 0 { + avalues = &args[0] + } + ffi.CallWithEnv(cif, fn, ret, avalues, env) +} diff --git a/runtime/internal/lib/reflect/makefunc.go b/runtime/internal/lib/reflect/makefunc.go index e0ea7e2103..09fd3d0f8d 100644 --- a/runtime/internal/lib/reflect/makefunc.go +++ b/runtime/internal/lib/reflect/makefunc.go @@ -36,35 +36,23 @@ type funcData struct { tout []*abi.Type fn func(args []Value) (results []Value) nin int - off int } func MakeFunc(typ Type, fn func(args []Value) (results []Value)) Value { - return makeFunc(typ, false, fn) -} - -func makeFunc(typ Type, method bool, fn func(args []Value) (results []Value)) Value { if typ.Kind() != Func { panic("reflect: call of MakeFunc with non-Func type") } t := typ.common() ftyp := (*funcType)(unsafe.Pointer(t)) - var ins []*abi.Type - var off int - if method { - ins = ftyp.In - } else { - ins = append([]*abi.Type{unsafePointerType}, ftyp.In...) - off = 1 - } + ins := ftyp.In sig, err := toFFISig(ins, ftyp.Out) if err != nil { panic(err) } outs := toRuntimeTypes(ftyp.Out) closure := ffi.NewClosure() - userdata := &funcData{ftyp: ftyp, fn: fn, nin: len(ftyp.In), off: off, tout: outs} + userdata := &funcData{ftyp: ftyp, fn: fn, nin: len(ftyp.In), tout: outs} switch len(ftyp.Out) { case 0: @@ -79,14 +67,14 @@ func makeFunc(typ Type, method bool, fn func(args []Value) (results []Value)) Va } // keep alive for bdw-gc keepMutex.Lock() - keepAlive = append(keepAlive, &closure.Fn, sig, userdata) + keepAlive = append(keepAlive, closure, sig, userdata) keepMutex.Unlock() styp := closureOf(ftyp) fv := &struct { fn unsafe.Pointer env unsafe.Pointer - }{closure.Fn, unsafe.Pointer(&fn)} + }{closure.Fn, nil} return Value{styp, unsafe.Pointer(fv), flagIndir | flag(Func)} } @@ -99,7 +87,7 @@ func bind0(cif *ffi.Signature, ret unsafe.Pointer, args *unsafe.Pointer, userdat fd := (*funcData)(userdata) ins := make([]Value, fd.nin) for i := 0; i < fd.nin; i++ { - ins[i] = ffiToValue(ffi.Index(args, uintptr(i+fd.off)), fd.ftyp.In[i]) + ins[i] = ffiToValue(ffi.Index(args, uintptr(i)), fd.ftyp.In[i]) } fd.fn(ins) } @@ -108,7 +96,7 @@ func bind1(cif *ffi.Signature, ret unsafe.Pointer, args *unsafe.Pointer, userdat fd := (*funcData)(userdata) ins := make([]Value, fd.nin) for i := 0; i < fd.nin; i++ { - ins[i] = ffiToValue(ffi.Index(args, uintptr(i+fd.off)), fd.ftyp.In[i]) + ins[i] = ffiToValue(ffi.Index(args, uintptr(i)), fd.ftyp.In[i]) } out := validateMakeFuncResults(fd.fn(ins), fd.ftyp, fd.tout) storeMakeFuncResult(ret, out[0], fd.tout[0]) @@ -118,7 +106,7 @@ func bindn(cif *ffi.Signature, ret unsafe.Pointer, args *unsafe.Pointer, userdat fd := (*funcData)(userdata) ins := make([]Value, fd.nin) for i := 0; i < fd.nin; i++ { - ins[i] = ffiToValue(ffi.Index(args, uintptr(i+fd.off)), fd.ftyp.In[i]) + ins[i] = ffiToValue(ffi.Index(args, uintptr(i)), fd.ftyp.In[i]) } outs := validateMakeFuncResults(fd.fn(ins), fd.ftyp, fd.tout) var offset uintptr = 0 @@ -276,20 +264,25 @@ func makeMethodValue(op string, v Value) Value { fl |= flag(v.typ().Kind()) rcvr := Value{v.typ(), v.ptr, fl} - // v.Type returns the actual type of the method value. - _, _, fn := methodReceiver(op, rcvr, int(v.flag)>>flagMethodShift) - var ptr unsafe.Pointer - storeRcvr(v, unsafe.Pointer(&ptr)) - fv := &struct { - fn unsafe.Pointer - env unsafe.Pointer - }{fn, ptr} - ftyp := (*funcType)(unsafe.Pointer(v.Type().(*rtype))) - typ := closureOf(ftyp) + // Validate the method now so Interface and Convert keep their eager panic + // behavior. The resulting libffi closure is a true no-env C entry; its + // userdata owns the receiver state. Pointing a hidden-env funcval directly + // at Ifn would be invalid because Ifn expects the receiver as an ordinary + // first ABI argument. + methodReceiver(op, rcvr, int(v.flag)>>flagMethodShift) + method := v + callOp := "Call" + if method.Type().(*rtype).t.FuncType().Variadic() { + callOp = "CallSlice" + } + ret := MakeFunc(v.Type(), func(args []Value) []Value { + return method.call(callOp, args) + }) // Cause panic if method is not appropriate. // The panic would still happen during the call if we omit this, // but we want Interface() and other operations to fail early. - return Value{typ, unsafe.Pointer(fv), v.flag&flagRO | flagIndir | flag(Func)} + ret.flag |= v.flag & flagRO + return ret } var unsafePointerType = rtypeOf(unsafe.Pointer(nil)) diff --git a/runtime/internal/lib/reflect/value.go b/runtime/internal/lib/reflect/value.go index a17ca0374a..a1d169644c 100644 --- a/runtime/internal/lib/reflect/value.go +++ b/runtime/internal/lib/reflect/value.go @@ -2458,19 +2458,24 @@ func (v Value) call(op string, in []Value) (out []Value) { tin []*abi.Type args []unsafe.Pointer fn unsafe.Pointer + env unsafe.Pointer ret unsafe.Pointer ioff int ) if v.typ_.IsClosure() && v.flag&flagMethod == 0 { ft = v.typ_.StructType().Fields[0].Typ.FuncType() - tin = append([]*abi.Type{rtypeOf(unsafe.Pointer(nil))}, ft.In...) c := (*struct { fn unsafe.Pointer env unsafe.Pointer })(v.ptr) fn = c.fn - ioff = 1 - args = append(args, unsafe.Pointer(&c.env)) + env = c.env + tin = ft.In + if env != nil && ffi.ClosureEnvExplicit { + tin = append([]*abi.Type{rtypeOf(unsafe.Pointer(nil))}, tin...) + ioff = 1 + args = append(args, unsafe.Pointer(&env)) + } } else { if v.flag&flagMethod != 0 { var ( @@ -2579,7 +2584,7 @@ func (v Value) call(op string, in []Value) (out []Value) { ret = unsafe.Pointer(&v) } - ffi.Call(sig, fn, ret, args...) + ffi.CallWithEnv(sig, fn, env, ret, args...) tout := toRuntimeTypes(ft.Out) switch n := len(tout); n { case 0: @@ -3414,7 +3419,7 @@ func mapiternext(it *hiter) //go:linkname mapclear github.com/goplus/llgo/runtime/internal/runtime.mapclear func mapclear(t *abi.Type, m unsafe.Pointer) -//go:linkname typehash github.com/goplus/llgo/runtime/internal/runtime.typehash +//go:linkname typehash github.com/goplus/llgo/runtime/internal/runtime.typehashImpl func typehash(t *abi.Type, p unsafe.Pointer, h uintptr) uintptr //go:linkname makechan github.com/goplus/llgo/runtime/internal/runtime.NewChan diff --git a/runtime/internal/lib/runtime/pclntab_external.go b/runtime/internal/lib/runtime/pclntab_external.go index 9a065e415a..307a8ff0c7 100644 --- a/runtime/internal/lib/runtime/pclntab_external.go +++ b/runtime/internal/lib/runtime/pclntab_external.go @@ -13,7 +13,7 @@ import ( const ( externalPCLNMagic = "LLGOPCL1" - externalPCLNVersion = uint32(3) + externalPCLNVersion = uint32(4) externalPCLNABIVersion = uint32(1) externalPCLNHeaderSize = uintptr(256) externalPCLNMaxSize = int64(512 << 20) @@ -43,7 +43,6 @@ const ( externalDescHash externalDescSymbolIndex externalDescEntrySites - externalDescStubSites externalDescPCSites externalDescCount ) @@ -193,7 +192,7 @@ func externalSectionSize(index int) uintptr { return externalHashSize case externalDescSymbolIndex: return externalSymbolIndexSize - case externalDescEntrySites, externalDescStubSites, externalDescPCSites: + case externalDescEntrySites, externalDescPCSites: return externalSiteSize } return 0 @@ -266,7 +265,7 @@ func externalSectionAlignment(index int) uintptr { switch index { case externalDescRecords, externalDescStringOffsets: return 4 - case externalDescPCLines, externalDescSymbolIndex, externalDescEntrySites, externalDescStubSites, externalDescPCSites: + case externalDescPCLines, externalDescSymbolIndex, externalDescEntrySites, externalDescPCSites: return 8 case externalDescHash: return 2 @@ -310,13 +309,12 @@ func installExternalPCLN(raw []byte, view externalPCLNView, loadBase uintptr) bo hash := view.sections[externalDescHash] symbols := view.sections[externalDescSymbolIndex] entries := view.sections[externalDescEntrySites] - stubs := view.sections[externalDescStubSites] pcsites := view.sections[externalDescPCSites] // String IDs are uint32. The offset section and sidecar size bound their // count now, rather than the old uint16 ID limit. if records.count == 0 || records.count > 1<<20 || offsets.count == 0 || stringsSec.count == 0 || stringsSec.count > 1<<30 || pclines.count > 1<<22 || - symbols.count > records.count || entries.count > records.count*16 || stubs.count > records.count*16 || pcsites.count > 1<<24 { + symbols.count > records.count || entries.count > records.count*16 || pcsites.count > 1<<24 { return false } // Validate every string ID before any runtime pointer is published. @@ -384,7 +382,7 @@ func installExternalPCLN(raw []byte, view externalPCLNView, loadBase uintptr) bo } return true } - if !relocateSites(entries) || !relocateSites(stubs) || !relocateSites(pcsites) { + if !relocateSites(entries) || !relocateSites(pcsites) { return false } @@ -401,8 +399,6 @@ func installExternalPCLN(raw []byte, view externalPCLNView, loadBase uintptr) bo } runtimeFuncInfoSymbolIndex = (*runtimeFuncInfoSymbolIndexRecord)(symbolBase) runtimeFuncInfoSymbolIndexCount = symbols.count - runtimeFuncInfoStubIndexes = nil - runtimeFuncInfoStubCount = 0 runtimePCLineTable = (*runtimePCLineRecord)(pclineBase) runtimePCLineCount = pclines.count runtimeFuncInfoEntryStart = (*runtimeFuncInfoEntryRecord)(externalSectionPtr(raw, entries)) @@ -411,12 +407,6 @@ func installExternalPCLN(raw []byte, view externalPCLNView, loadBase uintptr) bo } else { runtimeFuncInfoEntryEnd = nil } - runtimeFuncInfoStubSiteStart = (*runtimeFuncInfoStubSiteRecord)(externalSectionPtr(raw, stubs)) - if stubs.count != 0 { - runtimeFuncInfoStubSiteEnd = (*runtimeFuncInfoStubSiteRecord)(unsafe.Add(externalSectionPtr(raw, stubs), stubs.count*externalSiteSize)) - } else { - runtimeFuncInfoStubSiteEnd = nil - } runtimePCSiteStart = (*runtimePCSiteRecord)(externalSectionPtr(raw, pcsites)) if pcsites.count != 0 { runtimePCSiteEnd = (*runtimePCSiteRecord)(unsafe.Add(externalSectionPtr(raw, pcsites), pcsites.count*externalSiteSize)) diff --git a/runtime/internal/lib/runtime/symtab.go b/runtime/internal/lib/runtime/symtab.go index 75854a9434..f21b22fbba 100644 --- a/runtime/internal/lib/runtime/symtab.go +++ b/runtime/internal/lib/runtime/symtab.go @@ -182,12 +182,6 @@ var runtimeFuncInfoSymbolIndex *runtimeFuncInfoSymbolIndexRecord //go:linkname runtimeFuncInfoSymbolIndexCount __llgo_funcinfo_symbol_index_count var runtimeFuncInfoSymbolIndexCount uintptr -//go:linkname runtimeFuncInfoStubIndexes __llgo_funcinfo_stub_indexes -var runtimeFuncInfoStubIndexes *uint32 - -//go:linkname runtimeFuncInfoStubCount __llgo_funcinfo_stub_count -var runtimeFuncInfoStubCount uintptr - type runtimeFuncInfoEntryRecord struct { pc uintptr symbolID uint64 @@ -199,17 +193,6 @@ var runtimeFuncInfoEntryStart *runtimeFuncInfoEntryRecord //go:linkname runtimeFuncInfoEntryEnd __llgo_funcinfo_entry_end var runtimeFuncInfoEntryEnd *runtimeFuncInfoEntryRecord -type runtimeFuncInfoStubSiteRecord struct { - pc uintptr - symbolID uint64 -} - -//go:linkname runtimeFuncInfoStubSiteStart __llgo_funcinfo_stubsite_start -var runtimeFuncInfoStubSiteStart *runtimeFuncInfoStubSiteRecord - -//go:linkname runtimeFuncInfoStubSiteEnd __llgo_funcinfo_stubsite_end -var runtimeFuncInfoStubSiteEnd *runtimeFuncInfoStubSiteRecord - type runtimePCLineRecord struct { id uint64 funcIndex uint32 @@ -289,8 +272,6 @@ const ( runtimeFuncInfoInitUninit uint32 = iota runtimeFuncInfoInitDone runtimeFuncInfoInitBusy - runtimeClosureStubPrefix = "__llgo_stub." - runtimePublicClosureStubPrefix = "_llgo_stub." ) func hasStringPrefix(s, prefix string) bool { @@ -398,11 +379,6 @@ func pcLineAt(i uintptr) *runtimePCLineRecord { return (*runtimePCLineRecord)(unsafe.Add(unsafe.Pointer(runtimePCLineTable), i*size)) } -func funcInfoStubIndexAt(i uintptr) uint32 { - size := unsafe.Sizeof(*runtimeFuncInfoStubIndexes) - return *(*uint32)(unsafe.Add(unsafe.Pointer(runtimeFuncInfoStubIndexes), i*size)) -} - func funcInfoHashString(s string) uintptr { const ( offset = uint32(2166136261) @@ -520,12 +496,6 @@ func symbolPCFuncInfoName(buf []byte, pkgID, nameID uint32) uintptr { return symbolPCBytes(name) } -func symbolPCPrefixedFuncInfoName(buf []byte, prefix string, pkgID, nameID uint32) uintptr { - name := append(buf[:0], prefix...) - name = appendFuncInfoName(name, pkgID, nameID) - return symbolPCBytes(name) -} - func funcInfoFunctionName(fn *runtimeFuncInfoRecord) string { if fn == nil { return "" @@ -577,16 +547,7 @@ func funcInfoForSymbol(symbol string) *runtimeFuncInfoRecord { } func funcInfoForRuntimeSymbol(symbol string) *runtimeFuncInfoRecord { - if rec := funcInfoForSymbol(symbol); rec != nil { - return rec - } - if hasStringPrefix(symbol, runtimeClosureStubPrefix) { - return funcInfoForSymbol(symbol[len(runtimeClosureStubPrefix):]) - } - if hasStringPrefix(symbol, runtimePublicClosureStubPrefix) { - return funcInfoForSymbol(symbol[len(runtimePublicClosureStubPrefix):]) - } - return nil + return funcInfoForSymbol(symbol) } func applyFuncInfo(sym *pcSymbol, rawFunction string) { @@ -682,7 +643,6 @@ func runtimeFuncPCFramesBuilt() bool { var runtimeFuncInfoDebugState uint32 var runtimeFuncPCFramesFromSites bool -var runtimeFuncPCStubsFromSites bool func runtimeFuncInfoDebugEnabled() bool { state := latomic.LoadUint32(&runtimeFuncInfoDebugState) @@ -717,10 +677,8 @@ func reportRuntimeFuncPCDebug() { return } entrySrc := runtimeFuncInfoDebugSource(runtimeFuncPCFramesFromSites) - stubSrc := runtimeFuncInfoDebugSource(runtimeFuncPCStubsFromSites) if runtimeFuncPCFramesPrebuilt { entrySrc = "prebuilt" - stubSrc = "prebuilt" } frameCount := len(runtimeFuncPCFrames) if runtimeFuncPCFramesPrebuilt { @@ -729,8 +687,7 @@ func reportRuntimeFuncPCDebug() { println("llgo funcinfo: func table frames=", frameCount, " buckets=", len(runtimeFuncPCIndex.buckets), " index=", runtimeFuncInfoDebugIndex(runtimeFuncPCIndex), - " entries=", entrySrc, - " stubs=", stubSrc) + " entries=", entrySrc) } func reportRuntimePCLineDebug() { @@ -780,12 +737,8 @@ func initRuntimeFuncPCFramesSlow() { // // The tool sorts, deduplicates LTO inline copies against the symbol table, // and normalizes entries to true symbol starts, so adopting the table also -// retires first-use sorting and the dlsym/stub fallbacks. +// retires first-use sorting and the dlsym fallback. const runtimePrebuiltMagic = uint64(0x314254464F474C4C) // "LLGOFTB1" little-endian -// "LLGOFTB2": the entry section holds only a 32-byte redirect whose third -// word is the runtime address of the real blob, written into the (larger) -// stub section when the table outgrew the entry section. -const runtimePrebuiltRedirectMagic = uint64(0x324254464F474C4C) const runtimePrebuiltHeaderSize = 8 + 8 + 8 + 4 + 4 type runtimePrebuiltFtabEntry struct { @@ -845,20 +798,6 @@ func adoptPrebuiltFuncPCTable() bool { if end < start+runtimePrebuiltHeaderSize { return false } - if *(*uint64)(unsafe.Pointer(start)) == runtimePrebuiltRedirectMagic { - // Blob spilled into the stub section; the pointer slot is a live - // relocation, so it already holds the runtime address. - blob := uintptr(*(*uint64)(unsafe.Pointer(start + 16))) - if blob == 0 || runtimeFuncInfoStubSiteStart == nil || runtimeFuncInfoStubSiteEnd == nil { - return false - } - stubStart := uintptr(unsafe.Pointer(runtimeFuncInfoStubSiteStart)) - stubEnd := uintptr(unsafe.Pointer(runtimeFuncInfoStubSiteEnd)) - if blob != stubStart || stubEnd < stubStart { - return false - } - start, end = blob, stubEnd - } if *(*uint64)(unsafe.Pointer(start)) != runtimePrebuiltMagic { return false } @@ -878,7 +817,6 @@ func adoptPrebuiltFuncPCTable() bool { } runtimeFuncPCFramesPrebuilt = true runtimeFuncPCFramesFromSites = true - runtimeFuncPCStubsFromSites = true runtimePrebuiltFuncs = make([]unsafe.Pointer, count) return true } @@ -951,7 +889,7 @@ func initRuntimeFuncPCFramesOnce() { frameSize := unsafe.Sizeof(frames[0]) entryBase := unsafe.Pointer(&entries[0]) nframes := 0 - symbolBuf = make([]byte, 0, maxFuncInfoSymbolLen()+len(runtimeClosureStubPrefix)+1) + symbolBuf = make([]byte, 0, maxFuncInfoSymbolLen()+1) for i := uintptr(0); i < runtimeFuncInfoCount; i++ { fn := funcInfoAt(i) pc := symbolPCFuncInfoName(symbolBuf, fn.symbolPkg, fn.symbolName) @@ -971,49 +909,12 @@ func initRuntimeFuncPCFramesOnce() { } frames = frames[:nframes] } - frames, usedStubSites := appendRuntimeFuncInfoStubSiteFrames(frames) - // Closure stubs are an ABI adapter and may go away in a future closure - // lowering. Keep the fallback compatibility table light: it stores only - // target funcinfo record indexes. When the stub-site section is present it - // is authoritative (linkers do not expose local stubs through dlsym), and - // skipping the dlsym loop below matters: each dlsym is a dynamic-loader - // query, and one query per stub used to dominate first-use latency. - if !usedStubSites && runtimeFuncInfoStubIndexes != nil && runtimeFuncInfoStubCount != 0 && runtimeFuncInfoStubCount <= runtimeFuncInfoCount { - if symbolBuf == nil { - symbolBuf = make([]byte, 0, maxFuncInfoSymbolLen()+len(runtimeClosureStubPrefix)+1) - } - base := len(frames) - grown := make([]runtimeFuncPCFrame, base+int(runtimeFuncInfoStubCount)) - copy(grown, frames) - frames = grown - frameBase := unsafe.Pointer(&frames[0]) - frameSize := unsafe.Sizeof(frames[0]) - nframes := base - for i := uintptr(0); i < runtimeFuncInfoStubCount; i++ { - index := funcInfoStubIndexAt(i) - if index == 0 || uintptr(index) > runtimeFuncInfoCount { - continue - } - fn := funcInfoAt(uintptr(index) - 1) - pc := symbolPCPrefixedFuncInfoName(symbolBuf, runtimeClosureStubPrefix, fn.symbolPkg, fn.symbolName) - if pc == 0 { - continue - } - *(*runtimeFuncPCFrame)(unsafe.Add(frameBase, uintptr(nframes)*frameSize)) = runtimeFuncPCFrame{ - entry: pc, - funcIndex: index, - } - nframes++ - } - frames = frames[:nframes] - } sortRuntimeFuncPCFrames(frames) frames = uniqueRuntimeFuncPCFrames(frames) runtimeFuncPCFrames = frames runtimeFuncPCEntries = entries runtimeFuncPCIndex = buildRuntimeFuncPCIndex(frames) runtimeFuncPCFramesFromSites = usedEntrySites - runtimeFuncPCStubsFromSites = usedStubSites } func appendRuntimeFuncInfoEntryFrames(frames []runtimeFuncPCFrame, entries []uintptr) ([]runtimeFuncPCFrame, bool) { @@ -1065,50 +966,6 @@ func appendRuntimeFuncInfoEntryFrames(frames []runtimeFuncPCFrame, entries []uin return frames[:nframes], used } -func appendRuntimeFuncInfoStubSiteFrames(frames []runtimeFuncPCFrame) ([]runtimeFuncPCFrame, bool) { - if runtimeFuncInfoStubSiteStart == nil || runtimeFuncInfoStubSiteEnd == nil { - return frames, false - } - start := uintptr(unsafe.Pointer(runtimeFuncInfoStubSiteStart)) - end := uintptr(unsafe.Pointer(runtimeFuncInfoStubSiteEnd)) - size := unsafe.Sizeof(*runtimeFuncInfoStubSiteStart) - if end <= start || size == 0 || (end-start)%size != 0 { - return frames, false - } - nsite := (end - start) / size - if nsite > runtimeFuncInfoCount*16 || nsite > 1<<20 { - return frames, false - } - if nsite == 0 { - return frames, false - } - base := len(frames) - grown := make([]runtimeFuncPCFrame, base+int(nsite)) - copy(grown, frames) - frames = grown - frameBase := unsafe.Pointer(&frames[0]) - frameSize := unsafe.Sizeof(frames[0]) - nframes := base - used := false - for i := uintptr(0); i < nsite; i++ { - site := (*runtimeFuncInfoStubSiteRecord)(unsafe.Pointer(start + i*size)) - if site == nil || site.pc == 0 || site.symbolID == 0 { - continue - } - funcIndex := funcInfoIndexForSymbolID(site.symbolID) - if funcIndex == 0 || uintptr(funcIndex) > runtimeFuncInfoCount { - continue - } - *(*runtimeFuncPCFrame)(unsafe.Add(frameBase, uintptr(nframes)*frameSize)) = runtimeFuncPCFrame{ - entry: site.pc, - funcIndex: funcIndex, - } - nframes++ - used = true - } - return frames[:nframes], used -} - func funcInfoIndexForSymbolID(symbolID uint64) uint32 { if symbolID == 0 || runtimeFuncInfoSymbolIndex == nil || runtimeFuncInfoSymbolIndexCount == 0 { return 0 @@ -1432,11 +1289,9 @@ func funcEntryForIndex(index uint32) uintptr { } // coldFuncInfoEntryLookup resolves an exact function-entry PC by scanning the -// raw entry-site and stub-site sections, without building the sorted frame -// table and without any dynamic-loader query. Function values can point at -// either a real function entry or its closure stub, so both sections are -// scanned. The scan is linear, so it is capped: for larger binaries the -// dladdr cold path is cheaper than streaming the whole section. +// raw entry-site section, without building the sorted frame table and without +// any dynamic-loader query. The scan is linear, so it is capped: for larger +// binaries the dladdr cold path is cheaper than streaming the whole section. const coldFuncInfoEntryScanLimit = 4096 // coldFuncInfoScanRange scans one {pc, symbolID} record section for the @@ -1502,7 +1357,7 @@ func prebuiltFuncPCTablePresent() bool { return false } m := *(*uint64)(unsafe.Pointer(start)) - return m == runtimePrebuiltMagic || m == runtimePrebuiltRedirectMagic + return m == runtimePrebuiltMagic } // runtimeFuncInfoWarmSink keeps the warm-up loads observable. @@ -1539,8 +1394,7 @@ func init() { sink += *(*byte)(unsafe.Pointer(p + n - 1)) runtimeFuncInfoWarmSink = sink } - // The adopted blob may live in the entry section or (spilled) in the - // stub section; derive its range from the adopted views. + // Derive the adopted blob's range from its zero-copy views. if n := len(runtimePrebuiltFtab); n > 0 { touch(unsafe.Pointer(&runtimePrebuiltFtab[0]), uintptr(n)*8) } @@ -1590,14 +1444,6 @@ func coldFuncInfoEntryLookup(pc uintptr) (pcSymbol, bool) { uintptr(unsafe.Pointer(runtimeFuncInfoEntryEnd)), unsafe.Sizeof(*runtimeFuncInfoEntryStart), pc, bestDelta) } - if bestDelta != 0 && runtimeFuncInfoStubSiteStart != nil && runtimeFuncInfoStubSiteEnd != nil { - if idx, _ := coldFuncInfoScanRange( - uintptr(unsafe.Pointer(runtimeFuncInfoStubSiteStart)), - uintptr(unsafe.Pointer(runtimeFuncInfoStubSiteEnd)), - unsafe.Sizeof(*runtimeFuncInfoStubSiteStart), pc, bestDelta); idx != 0 { - bestIndex = idx - } - } if bestIndex == 0 { return pcSymbol{}, false } diff --git a/runtime/internal/runtime/alg.go b/runtime/internal/runtime/alg.go index 1abeadcb48..dd6f79fff7 100644 --- a/runtime/internal/runtime/alg.go +++ b/runtime/internal/runtime/alg.go @@ -11,6 +11,9 @@ import ( "github.com/goplus/llgo/runtime/internal/runtime/goarch" ) +//go:linkname closureEnv llgo.closureEnv +func closureEnv() unsafe.Pointer + const ( c0 = uintptr((8-goarch.PtrSize)/4*2860486313 + (goarch.PtrSize-4)/4*33054211828000289) c1 = uintptr((8-goarch.PtrSize)/4*3267000013 + (goarch.PtrSize-4)/4*23344194077549503) @@ -104,9 +107,9 @@ func interhash(p unsafe.Pointer, h uintptr) uintptr { panic(errorString("hash of unhashable type " + t.String())) } if isDirectIface(t) { - return c1 * typehash(t, unsafe.Pointer(&a.data), h^c0) + return c1 * typehashImpl(t, unsafe.Pointer(&a.data), h^c0) } else { - return c1 * typehash(t, a.data, h^c0) + return c1 * typehashImpl(t, a.data, h^c0) } } @@ -121,9 +124,9 @@ func nilinterhash(p unsafe.Pointer, h uintptr) uintptr { panic(errorString("hash of unhashable type " + t.String())) } if isDirectIface(t) { - return c1 * typehash(t, unsafe.Pointer(&a.data), h^c0) + return c1 * typehashImpl(t, unsafe.Pointer(&a.data), h^c0) } else { - return c1 * typehash(t, a.data, h^c0) + return c1 * typehashImpl(t, a.data, h^c0) } } @@ -137,7 +140,7 @@ func nilinterhash(p unsafe.Pointer, h uintptr) uintptr { // maps generated by reflect.MapOf (reflect_typehash, below). // Note: this function must match the compiler generated // functions exactly. See issue 37716. -func typehash(t *_type, p unsafe.Pointer, h uintptr) uintptr { +func typehashImpl(t *_type, p unsafe.Pointer, h uintptr) uintptr { if t.TFlag&abi.TFlagRegularMemory != 0 { // Handle ptr sizes specially, see issue 37086. switch t.Size_ { @@ -169,7 +172,7 @@ func typehash(t *_type, p unsafe.Pointer, h uintptr) uintptr { case abi.Array: a := (*arraytype)(unsafe.Pointer(t)) for i := uintptr(0); i < a.Len; i++ { - h = typehash(a.Elem, add(p, i*a.Elem.Size_), h) + h = typehashImpl(a.Elem, add(p, i*a.Elem.Size_), h) } return h case abi.Struct: @@ -178,7 +181,7 @@ func typehash(t *_type, p unsafe.Pointer, h uintptr) uintptr { if f.Name_ == "_" { continue } - h = typehash(f.Typ, add(p, f.Offset), h) + h = typehashImpl(f.Typ, add(p, f.Offset), h) } return h default: @@ -188,6 +191,11 @@ func typehash(t *_type, p unsafe.Pointer, h uintptr) uintptr { } } +//llgo:env +func typehash(p unsafe.Pointer, h uintptr) uintptr { + return typehashImpl((*_type)(closureEnv()), p, h) +} + func memequalptr(p, q unsafe.Pointer) bool { return *(*uintptr)(p) == *(*uintptr)(q) } @@ -323,8 +331,9 @@ func typeEqualMayPanic(t *_type) bool { return false } -func structequal(t, p, q unsafe.Pointer) bool { - x := (*structtype)(t) +//llgo:env +func structequal(p, q unsafe.Pointer) bool { + x := (*structtype)(closureEnv()) fields := x.Fields segmentStart := 0 for i, ft := range fields { @@ -365,8 +374,9 @@ func structequal(t, p, q unsafe.Pointer) bool { return true } -func arrayequal(t, p, q unsafe.Pointer) bool { - x := (*arraytype)(t) +//llgo:env +func arrayequal(p, q unsafe.Pointer) bool { + x := (*arraytype)(closureEnv()) elem := x.Elem for i := uintptr(0); i < x.Len; i++ { pi := add(p, i*elem.Size_) diff --git a/ssa/abitype.go b/ssa/abitype.go index 4cc1cb8c6d..7c6c1eebfa 100644 --- a/ssa/abitype.go +++ b/ssa/abitype.go @@ -115,7 +115,7 @@ func (b Builder) abiCommonFields(t types.Type, name string, hasUncommon bool, gl case "": equal = prog.Nil(prog.Type(equalFunc, InGo)) case "structequal", "arrayequal": - equal = b.Pkg.rtFunc(name) + equal = b.Pkg.rtEnvFunc(name) b.Pkg.recordAbiTypeFakeUse(global, equal.impl) env := b.abiType(t) equal = b.aggregateValue(prog.Type(equalFunc, InGo), equal.impl, env.impl) @@ -293,7 +293,7 @@ func (b Builder) abiExtendedFields(t types.Type, name string, global llvm.Value) case *types.Map: bucket := prog.abi.MapBucket(t) flags := prog.abi.MapFlags(t) - hash := b.Pkg.rtFunc("typehash") + hash := b.Pkg.rtEnvFunc("typehash") b.Pkg.recordAbiTypeFakeUse(global, hash.impl) env := b.abiType(t.Key()) hasher := b.aggregateValue(prog.Type(hashFunc, InGo), hash.impl, env.impl) @@ -516,8 +516,9 @@ func (b Builder) abiUncommonMethods(t types.Type, methods []*types.Selection) ll mSig := m.Type().(*types.Signature) var tfn, ifn llvm.Value tfnFn := b.abiMethodFunc(anonymous, pkg, mName, mSig) - tfnSig := funcType(prog, methodExprSignature(mSig)).(*types.Signature) - tfn = b.Pkg.closureWrapDecl(tfnFn.Expr, tfnSig).impl + // Tfn is used as a method-expression funcval. Its explicit receiver is + // already part of that semantic signature, so it is a no-env entry. + tfn = tfnFn.impl ifn = tfnFn.impl if _, ok := m.Recv().Underlying().(*types.Pointer); !ok { pRecv := types.NewVar(token.NoPos, pkg, "", types.NewPointer(mSig.Recv().Type())) diff --git a/ssa/closure_abi.go b/ssa/closure_abi.go new file mode 100644 index 0000000000..bdb4fbe52c --- /dev/null +++ b/ssa/closure_abi.go @@ -0,0 +1,132 @@ +package ssa + +import ( + "strings" + + "github.com/xgo-dev/llvm" +) + +// closureEnvABI describes only the physical transport of an environment +// parameter. The environment is not part of a Go or go/types signature. +type closureEnvABI uint8 + +const ( + // closureEnvExplicit is the typed fallback used by WebAssembly and targets + // for which no hidden parameter transport has been validated. + closureEnvExplicit closureEnvABI = iota + closureEnvNest + closureEnvSwiftSelf +) + +func closureEnvABIForTarget(triple string) closureEnvABI { + triple = strings.ToLower(triple) + arch, _, _ := strings.Cut(triple, "-") + // Select the long-term machine ABI by physical target even when LLGo does + // not yet support the target OS. FFI final-hop support may follow later + // without changing compiled closure entries. + switch { + case arch == "arm64", arch == "arm64_32", arch == "aarch64", arch == "aarch64_be": + // Keep a stable runtime ABI across LLVM versions on platforms which + // reserve X18. swiftself uses the callee-saved X20 register and is also + // usable by the libffi bridge without rebuilding libffi. + if aarch64UsesSwiftSelf(triple) { + return closureEnvSwiftSelf + } + return closureEnvNest + case strings.HasPrefix(arch, "arm"), strings.HasPrefix(arch, "thumb"): + // LLVM lowers swiftself through the platform's dedicated self register. + // This keeps the ordinary C arguments in their normal ABI locations. + return closureEnvSwiftSelf + case arch == "x86_64", arch == "amd64", + arch == "x86", arch == "386", + arch == "i386", arch == "i486", arch == "i586", arch == "i686": + return closureEnvNest + case arch == "riscv32", arch == "riscv64": + // LLVM and libffi both lower the RISC-V static chain through t2 (x7), + // allowing the direct ffi_call_go path. The ESP32-C3 suite exercises + // this transport on riscv32. + return closureEnvNest + default: + return closureEnvExplicit + } +} + +func aarch64UsesSwiftSelf(triple string) bool { + // Apple, Android, and Windows reserve X18, so LLGo uses LLVM's + // swiftself/X20 transport there. + return strings.Contains(triple, "apple") || + strings.Contains(triple, "darwin") || + strings.Contains(triple, "android") || + strings.Contains(triple, "windows") || + strings.Contains(triple, "win32") || + strings.Contains(triple, "mingw") +} + +func (p *Target) closureEnvABI() closureEnvABI { + triple := p.LLVMTarget + if triple == "" { + triple = p.Spec().Triple + } + return closureEnvABIForTarget(triple) +} + +// ClosureEnvBuildTag selects the runtime half of the same physical ABI used +// by the backend. It must be added after a named target has resolved its real +// LLVM triple; GOARCH may only be a package-selection compatibility value. +func (p *Target) ClosureEnvBuildTag() string { + switch p.closureEnvABI() { + case closureEnvNest: + return "llgo_closure_env_nest" + case closureEnvSwiftSelf: + return "llgo_closure_env_swiftself" + default: + return "llgo_closure_env_explicit" + } +} + +func (p Program) closureEnvABI() closureEnvABI { + return p.Target().closureEnvABI() +} + +func (p Program) closureEnvAttribute() llvm.Attribute { + var name string + switch p.closureEnvABI() { + case closureEnvNest: + name = "nest" + case closureEnvSwiftSelf: + name = "swiftself" + default: + return llvm.Attribute{} + } + return p.ctx.CreateEnumAttribute(llvm.AttributeKindID(name), 0) +} + +func (p Program) markClosureEnvFunction(fn llvm.Value, physicalIndex int) { + attr := p.closureEnvAttribute() + if attr.IsNil() { + return + } + fn.AddAttributeAtIndex(physicalIndex+1, attr) +} + +func (p Program) markClosureEnvCall(call llvm.Value, physicalIndex int) { + attr := p.closureEnvAttribute() + if attr.IsNil() { + return + } + call.AddCallSiteAttribute(physicalIndex+1, attr) +} + +// hideClosureCodeIdentity keeps LLVM from devirtualizing a native funcval call +// across the intentionally different IR prototypes of env and no-env entries. +// The empty tied-register asm is a machine-code no-op: it returns the same code +// pointer, but LLVM can no longer reinterpret a known no-env body as though the +// hidden environment were an ordinary first argument. +func (b Builder) hideClosureCodeIdentity(fn Expr) Expr { + ftype := llvm.FunctionType(fn.Type.ll, []llvm.Type{fn.Type.ll}, false) + asm := llvm.InlineAsm(ftype, "", "=r,0", false, false, llvm.InlineAsmDialectATT, false) + return Expr{ + b.impl.CreateCall(ftype, asm, []llvm.Value{fn.impl}, "__llgo_funcval_code"), + fn.Type, + } +} diff --git a/ssa/closure_env_test.go b/ssa/closure_env_test.go new file mode 100644 index 0000000000..541be822e6 --- /dev/null +++ b/ssa/closure_env_test.go @@ -0,0 +1,674 @@ +//go:build !llgo + +package ssa + +import ( + "go/token" + "go/types" + "strings" + "testing" + + "github.com/goplus/gogen/packages" + "github.com/xgo-dev/llvm" +) + +func TestClosureEnvDirectiveCacheUsesSourceIdentity(t *testing.T) { + prog := NewProgram(nil) + defer prog.Dispose() + fset := token.NewFileSet() + otherFset := token.NewFileSet() + const ( + name = "example.com/p.entry" + pos = token.Pos(7) + ) + prog.SetClosureEnvDirective(fset, name, pos) + if !prog.HasClosureEnvDirective(fset, name, pos) { + t.Fatal("HasClosureEnvDirective() = false, want true") + } + for _, key := range []struct { + fset *token.FileSet + name string + pos token.Pos + }{ + {otherFset, name, pos}, + {fset, "example.com/p.alias", pos}, + {fset, name, pos + 1}, + } { + if prog.HasClosureEnvDirective(key.fset, key.name, key.pos) { + t.Fatalf("distinct source declaration (%p, %q, %d) shared cached directives", key.fset, key.name, key.pos) + } + } +} + +func TestClosureEnvABIForTarget(t *testing.T) { + tests := []struct { + triple string + want closureEnvABI + }{ + {"wasm32-unknown-wasip1", closureEnvExplicit}, + {"x86_64-unknown-linux", closureEnvNest}, + {"amd64-unknown-linux", closureEnvNest}, + {"riscv64-unknown-linux", closureEnvNest}, + {"armv7-unknown-linux-gnueabihf", closureEnvSwiftSelf}, + {"aarch64-unknown-linux", closureEnvNest}, + {"arm64-apple-macosx", closureEnvSwiftSelf}, + {"x86_64-pc-windows-gnu", closureEnvNest}, + {"x86_64-pc-windows-msvc", closureEnvNest}, + {"x86_64-w64-mingw32", closureEnvNest}, + {"aarch64-pc-windows-msvc", closureEnvSwiftSelf}, + {"mips64-unknown-linux", closureEnvExplicit}, + } + for _, test := range tests { + if got := closureEnvABIForTarget(test.triple); got != test.want { + t.Errorf( + "closureEnvABIForTarget(%q) = %d, want %d", + test.triple, got, test.want, + ) + } + } +} + +func TestClosureEnvBuildTag(t *testing.T) { + tests := []struct { + target *Target + want string + }{ + {&Target{LLVMTarget: "x86_64-unknown-linux"}, "llgo_closure_env_nest"}, + {&Target{LLVMTarget: "arm64-apple-macosx"}, "llgo_closure_env_swiftself"}, + {&Target{GOOS: "linux", GOARCH: "arm", LLVMTarget: "wasm32-unknown-unknown"}, "llgo_closure_env_explicit"}, + } + for _, test := range tests { + if got := test.target.ClosureEnvBuildTag(); got != test.want { + t.Errorf("ClosureEnvBuildTag() = %q, want %q", got, test.want) + } + } +} + +func TestClosureEnvABIUsesPhysicalTarget(t *testing.T) { + tests := []struct { + name string + llvmTarget string + want closureEnvABI + }{ + {"esp32", "xtensa", closureEnvExplicit}, + {"esp32c3", "riscv32-esp-elf", closureEnvNest}, + } + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + // Embedded target configurations use GOARCH=arm for Go package + // selection, while code generation uses a different physical ISA. + prog := NewProgram(&Target{ + GOOS: "linux", + GOARCH: "arm", + Target: test.name, + LLVMTarget: test.llvmTarget, + }) + defer prog.Dispose() + if got := prog.closureEnvABI(); got != test.want { + t.Fatalf("closureEnvABI() = %d, want %d", got, test.want) + } + }) + } +} + +func TestEnvFunctionKeepsSemanticSignatureAndZeroEnvNonNil(t *testing.T) { + prog := NewProgram(nil) + defer prog.Dispose() + pkg := prog.NewPackage("p", "example.com/p") + + sig := types.NewSignatureType(nil, nil, nil, nil, nil, false) + empty := types.NewStruct(nil, nil) + env := types.NewParam(token.NoPos, nil, "$env", types.NewPointer(empty)) + entry := pkg.NewEnvFunc("example.com/p.entry", sig, InGo, env, false) + if !entry.NeedsEnv() || entry.EnvType() == nil { + t.Fatal("environment-bearing entry lost its separate env metadata") + } + if got := entry.Expr.raw.Type.(*types.Signature).Params().Len(); got != 0 { + t.Fatalf("semantic entry signature has %d params, want 0", got) + } + eb := entry.MakeBody(1) + eb.Return() + + out := types.NewTuple(types.NewVar(token.NoPos, nil, "", sig)) + makerSig := types.NewSignatureType(nil, nil, nil, nil, out, false) + maker := pkg.NewFunc("example.com/p.make", makerSig, InGo) + mb := maker.MakeBody(1) + mb.Return(mb.MakeClosure(entry.Expr, nil)) + + ir := pkg.String() + if !strings.Contains(ir, `@"__llgo.moduleZeroSizedAlloc$"`) { + t.Fatalf("zero-sized required env did not use the non-nil sentinel:\n%s", ir) + } + if strings.Contains(ir, "{ ptr @example.com/p.entry, ptr null }") { + t.Fatalf("environment-bearing entry was represented with a nil env:\n%s", ir) + } + if err := llvm.VerifyModule(pkg.Module(), llvm.ReturnStatusAction); err != nil { + t.Fatalf("closure-env module is invalid: %v\n%s", err, ir) + } +} + +func TestClosureEnvMetadataRejectsInvalidUses(t *testing.T) { + prog := NewProgram(nil) + defer prog.Dispose() + pkg := prog.NewPackage("p", "example.com/p") + sig := types.NewSignatureType(nil, nil, nil, nil, nil, false) + env := types.NewParam(token.NoPos, nil, "$env", types.NewPointer(types.NewStruct(nil, nil))) + envEntry := pkg.NewEnvFunc("binding-mismatch", sig, InGo, env, false) + plainEntry := pkg.NewFunc("plain-binding", sig, InGo) + caller := pkg.NewFunc("binding-validation", sig, InGo) + b := caller.MakeBody(1) + + tests := []struct { + name string + fn func() + }{ + { + name: "legacy hasFreeVars flag", + fn: func() { + pkg.NewFuncEx("legacy", sig, InGo, true, false) + }, + }, + { + name: "nil environment metadata", + fn: func() { + pkg.NewEnvFunc("nil-env", sig, InGo, nil, false) + }, + }, + { + name: "conflicting entry metadata", + fn: func() { + pkg.NewFunc("conflict", sig, InGo) + pkg.NewEnvFunc("conflict", sig, InGo, env, false) + }, + }, + { + name: "environment from plain entry", + fn: func() { + pkg.NewFunc("plain-env", sig, InGo).Env() + }, + }, + { + name: "environment binding count mismatch", + fn: func() { + b.MakeClosure(envEntry.Expr, []Expr{prog.Val(1)}) + }, + }, + { + name: "binding on plain entry", + fn: func() { + b.MakeClosure(plainEntry.Expr, []Expr{prog.Val(1)}) + }, + }, + } + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + defer func() { + if recover() == nil { + t.Fatal("expected panic") + } + }() + test.fn() + }) + } +} + +func TestWasmDynamicClosureUsesTwoExplicitTypedEdges(t *testing.T) { + Initialize(InitAllTargets | InitAllTargetInfos | InitAllTargetMCs) + prog := NewProgram(&Target{GOOS: "wasip1", GOARCH: "wasm"}) + defer prog.Dispose() + pkg := prog.NewPackage("p", "example.com/p") + + params := types.NewTuple(types.NewVar(token.NoPos, nil, "x", types.Typ[types.Int])) + results := types.NewTuple(types.NewVar(token.NoPos, nil, "", types.Typ[types.Int])) + sig := types.NewSignatureType(nil, nil, nil, params, results, false) + callerParams := types.NewTuple( + types.NewVar(token.NoPos, nil, "fn", sig), + types.NewVar(token.NoPos, nil, "x", types.Typ[types.Int]), + ) + caller := pkg.NewFunc( + "example.com/p.call", + types.NewSignatureType(nil, nil, nil, callerParams, results, false), + InGo, + ) + b := caller.MakeBody(1) + b.Return(b.Call(caller.Param(0), caller.Param(1))) + + ir := pkg.String() + for _, want := range []string{ + "icmp ne ptr", + "phi i32", + } { + if !strings.Contains(ir, want) { + t.Fatalf("Wasm dynamic closure call missing %q:\n%s", want, ir) + } + } + paramCounts := make(map[int]int) + for block := caller.impl.FirstBasicBlock(); !block.IsNil(); block = llvm.NextBasicBlock(block) { + for instruction := block.FirstInstruction(); !instruction.IsNil(); instruction = llvm.NextInstruction(instruction) { + if call := instruction.IsACallInst(); !call.IsNil() && call.CalledValue().IsAFunction().IsNil() { + paramCounts[call.CalledFunctionType().ParamTypesCount()]++ + } + } + } + if paramCounts[1] != 1 || paramCounts[2] != 1 { + t.Fatalf("Wasm dynamic closure edges have parameter counts %v, want one 1-param and one 2-param call:\n%s", paramCounts, ir) + } + if strings.Contains(ir, " nest ") || strings.Contains(ir, " swiftself ") { + t.Fatalf("Wasm dynamic closure call unexpectedly used a native env attribute:\n%s", ir) + } + if err := llvm.VerifyModule(pkg.Module(), llvm.ReturnStatusAction); err != nil { + t.Fatalf("Wasm dynamic closure module is invalid: %v\n%s", err, ir) + } +} + +func TestNativeDynamicClosureIdentityBarrierSurvivesO2(t *testing.T) { + for _, pipeline := range []string{"default", "lto"} { + t.Run(pipeline, func(t *testing.T) { + testNativeDynamicClosureIdentityBarrier(t, pipeline) + }) + } +} + +func testNativeDynamicClosureIdentityBarrier(t *testing.T, pipeline string) { + Initialize(InitAllTargets | InitAllTargetInfos | InitAllTargetMCs | InitAllAsmPrinters) + prog := NewProgram(&Target{GOOS: "linux", GOARCH: "amd64"}) + defer prog.Dispose() + setTestRuntime(t, prog) + pkg := prog.NewPackage("p", "example.com/p") + + params := types.NewTuple(types.NewVar(token.NoPos, nil, "x", types.Typ[types.Int])) + results := types.NewTuple(types.NewVar(token.NoPos, nil, "", types.Typ[types.Int])) + sig := types.NewSignatureType(nil, nil, nil, params, results, false) + plain := pkg.NewFunc("plain", sig, InGo) + pb := plain.MakeBody(1) + pb.Return(plain.Param(0)) + caller := newMatrixCaller(pkg, "callPlain", sig, func(b Builder) Expr { + return b.MakeClosure(plain.Expr, nil) + }) + + mod := pkg.Module() + pbo := llvm.NewPassBuilderOptions() + defer pbo.Dispose() + if err := mod.RunPasses(pipeline, prog.TargetMachine(), pbo); err != nil { + t.Fatalf("run %s pipeline: %v", pipeline, err) + } + if err := llvm.VerifyModule(mod, llvm.ReturnStatusAction); err != nil { + t.Fatalf("verify optimized module: %v\n%s", err, mod.String()) + } + + barriers, hiddenCalls := 0, 0 + for block := caller.impl.FirstBasicBlock(); !block.IsNil(); block = llvm.NextBasicBlock(block) { + for instruction := block.FirstInstruction(); !instruction.IsNil(); instruction = llvm.NextInstruction(instruction) { + call := instruction.IsACallInst() + if call.IsNil() { + if instruction.InstructionOpcode() == llvm.ICmp { + t.Fatalf("optimized native call retained an env == nil check:\n%s", mod.String()) + } + continue + } + if !call.CalledValue().IsAInlineAsm().IsNil() { + barriers++ + continue + } + if call.GetCallSiteEnumAttribute(1, llvm.AttributeKindID("nest")).IsNil() { + continue + } + hiddenCalls++ + if !call.CalledValue().IsAFunction().IsNil() { + t.Fatalf("O2 devirtualized hidden-env call to no-env entry:\n%s", mod.String()) + } + } + } + if barriers != 1 || hiddenCalls != 1 { + t.Fatalf("optimized native call has %d barriers and %d hidden calls, want one each:\n%s", barriers, hiddenCalls, mod.String()) + } +} + +func TestClosureObjectCallMatrixAcrossTransports(t *testing.T) { + Initialize(InitAllTargets | InitAllTargetInfos | InitAllTargetMCs) + tests := []struct { + name string + tgt *Target + abi closureEnvABI + attr string + }{ + { + name: "nest", + tgt: &Target{GOOS: "linux", GOARCH: "amd64"}, + abi: closureEnvNest, + attr: "nest", + }, + { + name: "swiftself", + tgt: &Target{GOOS: "darwin", GOARCH: "arm64"}, + abi: closureEnvSwiftSelf, + attr: "swiftself", + }, + { + name: "windows-nest", + tgt: &Target{ + GOOS: "windows", GOARCH: "amd64", LLVMTarget: "x86_64-pc-windows-msvc", + }, + abi: closureEnvNest, + attr: "nest", + }, + { + name: "windows-swiftself", + tgt: &Target{ + GOOS: "windows", GOARCH: "arm64", LLVMTarget: "aarch64-pc-windows-msvc", + }, + abi: closureEnvSwiftSelf, + attr: "swiftself", + }, + { + name: "wasm-explicit", + tgt: &Target{GOOS: "wasip1", GOARCH: "wasm"}, + abi: closureEnvExplicit, + }, + { + name: "xtensa-explicit", + tgt: &Target{ + GOOS: "linux", GOARCH: "arm", Target: "esp32", LLVMTarget: "xtensa", + }, + abi: closureEnvExplicit, + }, + } + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + prog := NewProgram(test.tgt) + defer prog.Dispose() + if got := prog.closureEnvABI(); got != test.abi { + t.Fatalf("closure transport = %d, want %d", got, test.abi) + } + setTestRuntime(t, prog) + pkg := prog.NewPackage("p", "example.com/p") + + params := types.NewTuple(types.NewVar(token.NoPos, nil, "x", types.Typ[types.Int])) + results := types.NewTuple(types.NewVar(token.NoPos, nil, "", types.Typ[types.Int])) + sig := types.NewSignatureType(nil, nil, nil, params, results, false) + + plain := pkg.NewFunc("plainGo", sig, InGo) + pb := plain.MakeBody(1) + pb.Return(plain.Param(0)) + + cfn := pkg.NewFunc("plainC", sig, InC) + cb := cfn.MakeBody(1) + cb.Return(cfn.Param(0)) + + captured := newMatrixEnvEntry(pkg, "capturedClosure", sig, + types.NewStruct( + []*types.Var{types.NewField(token.NoPos, nil, "capture", types.Typ[types.Int], false)}, + nil, + ), + ) + empty := newMatrixEnvEntry(pkg, "emptyClosure", sig, types.NewStruct(nil, nil)) + nilMethod := newMatrixEnvEntry(pkg, "nilReceiverMethodValue", sig, + types.NewStruct( + []*types.Var{types.NewField( + token.NoPos, nil, "receiver", types.NewPointer(types.Typ[types.Int]), false, + )}, + nil, + ), + ) + + rawMethod := types.NewFunc(token.NoPos, nil, "M", + types.NewSignatureType(nil, nil, nil, params, results, false), + ) + rawIface := types.NewInterfaceType([]*types.Func{rawMethod}, nil).Complete() + ifaceMethodValue := newMatrixEnvEntry(pkg, "interfaceMethodValue", sig, + types.NewStruct( + []*types.Var{types.NewField(token.NoPos, nil, "receiver", rawIface, false)}, + nil, + ), + ) + + type callCase struct { + caller Function + entry Function + } + callers := map[string]callCase{} + callers["plain-go"] = callCase{ + caller: newMatrixCaller(pkg, "callPlainGo", sig, func(b Builder) Expr { + return checkExpr(plain.Expr, prog.Type(sig, InGo).RawType(), b) + }), + entry: plain, + } + callers["plain-c"] = callCase{ + caller: newMatrixCaller(pkg, "callPlainC", sig, func(b Builder) Expr { + return checkExpr(cfn.Expr, prog.Type(sig, InGo).RawType(), b) + }), + entry: cfn, + } + callers["captured-closure"] = callCase{ + caller: newMatrixCaller(pkg, "callCapturedClosure", sig, func(b Builder) Expr { + return b.MakeClosure(captured.Expr, []Expr{prog.Val(7)}) + }), + entry: captured, + } + callers["zero-sized-closure"] = callCase{ + caller: newMatrixCaller(pkg, "callEmptyClosure", sig, func(b Builder) Expr { + return b.MakeClosure(empty.Expr, nil) + }), + entry: empty, + } + callers["nil-receiver-method-value"] = callCase{ + caller: newMatrixCaller(pkg, "callNilReceiverMethodValue", sig, func(b Builder) Expr { + return b.MakeClosure(nilMethod.Expr, []Expr{prog.Nil(prog.Pointer(prog.Int()))}) + }), + entry: nilMethod, + } + callers["interface-method-value"] = callCase{ + caller: newMatrixCaller(pkg, "callInterfaceMethodValue", sig, func(b Builder) Expr { + return b.MakeClosure(ifaceMethodValue.Expr, []Expr{prog.Zero(prog.Type(rawIface, InGo))}) + }), + entry: ifaceMethodValue, + } + + for name, call := range callers { + assertDynamicMatrixCall(t, call.caller, call.entry, name, test.attr) + } + assertMatrixEntryAttribute(t, plain, "", test.attr) + assertMatrixEntryAttribute(t, cfn, "", test.attr) + for _, entry := range []Function{captured, empty, nilMethod, ifaceMethodValue} { + assertMatrixEntryAttribute(t, entry, entry.Name(), test.attr) + } + + // Direct interface invocation is not a funcval. Its receiver is one + // ordinary ABI argument, with no env branch or hidden attribute. + ifaceCaller := newMatrixInterfaceCaller(t, prog, pkg, rawIface) + assertDirectInterfaceMatrixEdge(t, ifaceCaller, test.attr) + ifaceRoutine := newMatrixInterfaceRoutine(t, prog, pkg, rawIface) + assertDirectInterfaceMatrixEdge(t, ifaceRoutine, test.attr) + + ir := pkg.String() + for _, want := range []string{ + "{ ptr @plainGo, ptr null }", + "{ ptr @plainC, ptr null }", + `@"__llgo.moduleZeroSizedAlloc$"`, + } { + if !strings.Contains(ir, want) { + t.Fatalf("%s matrix missing %q:\n%s", test.name, want, ir) + } + } + if err := llvm.VerifyModule(pkg.Module(), llvm.ReturnStatusAction); err != nil { + t.Fatalf("%s matrix module is invalid: %v\n%s", test.name, err, ir) + } + }) + } +} + +func setTestRuntime(t *testing.T, prog Program) { + t.Helper() + fset := token.NewFileSet() + imp := packages.NewImporter(fset) + runtimePkg, err := imp.Import(PkgRuntime) + if err != nil { + t.Fatal(err) + } + prog.SetRuntime(runtimePkg) +} + +func newMatrixEnvEntry(pkg Package, name string, sig *types.Signature, envStruct *types.Struct) Function { + env := types.NewParam(token.NoPos, nil, "$env", types.NewPointer(envStruct)) + entry := pkg.NewEnvFunc(name, sig, InGo, env, false) + b := entry.MakeBody(1) + b.Return(entry.Param(0)) + return entry +} + +func newMatrixCaller(pkg Package, name string, sig *types.Signature, value func(Builder) Expr) Function { + caller := pkg.NewFunc(name, sig, InGo) + b := caller.MakeBody(1) + funcval := value(b) + slot := b.AllocaT(funcval.Type) + b.Store(slot, funcval) + b.Return(b.Call(b.Load(slot), caller.Param(0))) + return caller +} + +func assertDynamicMatrixCall(t *testing.T, caller, entry Function, name, attrName string) { + t.Helper() + paramCounts := make(map[int]int) + barrierCalls := 0 + var envCall llvm.Value + for block := caller.impl.FirstBasicBlock(); !block.IsNil(); block = llvm.NextBasicBlock(block) { + for instruction := block.FirstInstruction(); !instruction.IsNil(); instruction = llvm.NextInstruction(instruction) { + call := instruction.IsACallInst() + if call.IsNil() { + continue + } + called := call.CalledValue() + if !called.IsAInlineAsm().IsNil() { + barrierCalls++ + continue + } + if !called.IsAFunction().IsNil() && called.Name() != entry.impl.Name() { + continue + } + count := call.CalledFunctionType().ParamTypesCount() + paramCounts[count]++ + if count == 2 { + envCall = call + } + } + } + if attrName == "" { + if barrierCalls != 0 { + t.Fatalf("%s explicit call has %d native identity barriers, want none", name, barrierCalls) + } + if paramCounts[1] != 1 || paramCounts[2] != 1 { + t.Fatalf("%s explicit edges have parameter counts %v, want one no-env and one env edge", name, paramCounts) + } + entry := caller.impl.FirstBasicBlock() + if term := entry.LastInstruction(); term.IsNil() || term.InstructionOpcode() != llvm.Br || term.OperandsCount() != 3 { + t.Fatalf("%s explicit call has no env != nil branch", name) + } + } else { + if barrierCalls != 1 { + t.Fatalf("%s native call has %d identity barriers, want one", name, barrierCalls) + } + if paramCounts[1] != 0 || paramCounts[2] != 1 { + t.Fatalf("%s native calls have parameter counts %v, want one hidden-env edge", name, paramCounts) + } + for block := caller.impl.FirstBasicBlock(); !block.IsNil(); block = llvm.NextBasicBlock(block) { + for instruction := block.FirstInstruction(); !instruction.IsNil(); instruction = llvm.NextInstruction(instruction) { + if instruction.InstructionOpcode() == llvm.ICmp { + t.Fatalf("%s native call retained an env == nil check", name) + } + } + } + } + for _, candidate := range []string{"nest", "swiftself"} { + kind := llvm.AttributeKindID(candidate) + got := !envCall.GetCallSiteEnumAttribute(1, kind).IsNil() + if got != (candidate == attrName) { + t.Fatalf("%s env edge %s attribute = %v, want %v", name, candidate, got, candidate == attrName) + } + } +} + +func assertMatrixEntryAttribute(t *testing.T, fn Function, name, attrName string) { + t.Helper() + for _, candidate := range []string{"nest", "swiftself"} { + kind := llvm.AttributeKindID(candidate) + got := !fn.impl.GetEnumAttributeAtIndex(1, kind).IsNil() + want := name != "" && candidate == attrName + if got != want { + t.Fatalf("%s definition %s attribute = %v, want %v", fn.Name(), candidate, got, want) + } + } +} + +func newMatrixInterfaceCaller(t *testing.T, prog Program, pkg Package, rawIface *types.Interface) Function { + t.Helper() + namedIface := types.NewNamed(types.NewTypeName(token.NoPos, nil, "MatrixIface", nil), rawIface, nil) + recv := types.NewVar(token.NoPos, nil, "recv", namedIface) + method := rawIface.Method(0) + recvMethod := types.NewFunc( + token.NoPos, + nil, + method.Name(), + types.NewSignatureType(recv, nil, nil, method.Type().(*types.Signature).Params(), + method.Type().(*types.Signature).Results(), false), + ) + params := types.NewTuple( + types.NewVar(token.NoPos, nil, "recv", namedIface), + types.NewVar(token.NoPos, nil, "x", types.Typ[types.Int]), + ) + results := types.NewTuple(types.NewVar(token.NoPos, nil, "", types.Typ[types.Int])) + caller := pkg.NewFunc("callInterfaceDirect", + types.NewSignatureType(nil, nil, nil, params, results, false), InGo, + ) + b := caller.MakeBody(1) + b.Return(b.Call(b.Imethod(caller.Param(0), recvMethod), caller.Param(1))) + return caller +} + +func newMatrixInterfaceRoutine(t *testing.T, prog Program, pkg Package, rawIface *types.Interface) Function { + t.Helper() + namedIface := types.NewNamed(types.NewTypeName(token.NoPos, nil, "RoutineIface", nil), rawIface, nil) + recv := types.NewVar(token.NoPos, nil, "recv", namedIface) + method := rawIface.Method(0) + recvMethod := types.NewFunc( + token.NoPos, + nil, + method.Name(), + types.NewSignatureType(recv, nil, nil, method.Type().(*types.Signature).Params(), + method.Type().(*types.Signature).Results(), false), + ) + params := types.NewTuple( + types.NewVar(token.NoPos, nil, "recv", namedIface), + types.NewVar(token.NoPos, nil, "x", types.Typ[types.Int]), + ) + owner := pkg.NewFunc("startInterfaceRoutine", + types.NewSignatureType(nil, nil, nil, params, nil, false), InGo, + ) + b := owner.MakeBody(1) + invoke := b.Imethod(owner.Param(0), recvMethod) + startRecord := prog.Struct(invoke.Type, prog.Int()) + routineExpr := pkg.routine(startRecord, invoke, Builder.Call, 1) + b.Return() + return pkg.FuncOf(routineExpr.Name()) +} + +func assertDirectInterfaceMatrixEdge(t *testing.T, caller Function, attrName string) { + t.Helper() + var indirect []llvm.Value + for block := caller.impl.FirstBasicBlock(); !block.IsNil(); block = llvm.NextBasicBlock(block) { + for instruction := block.FirstInstruction(); !instruction.IsNil(); instruction = llvm.NextInstruction(instruction) { + call := instruction.IsACallInst() + if !call.IsNil() && call.CalledValue().IsAFunction().IsNil() { + indirect = append(indirect, call) + } + } + } + if len(indirect) != 1 || indirect[0].CalledFunctionType().ParamTypesCount() != 2 { + t.Fatalf("direct interface invocation has %d indirect edges, want one receiver+arg edge", len(indirect)) + } + for _, candidate := range []string{"nest", "swiftself"} { + kind := llvm.AttributeKindID(candidate) + if attr := indirect[0].GetCallSiteEnumAttribute(1, kind); !attr.IsNil() { + t.Fatalf("direct interface invocation incorrectly carries %s (transport %q)", candidate, attrName) + } + } +} diff --git a/ssa/closure_wrap.go b/ssa/closure_wrap.go deleted file mode 100644 index 470a299caf..0000000000 --- a/ssa/closure_wrap.go +++ /dev/null @@ -1,111 +0,0 @@ -package ssa - -import ( - "go/token" - "go/types" - - "github.com/xgo-dev/llvm" -) - -// removeCtx drops the leading __llgo_ctx parameter, if present. -func removeCtx(sig *types.Signature) *types.Signature { - if closureCtxParam(sig) == nil { - return sig - } - params := sig.Params() - n := params.Len() - args := make([]*types.Var, n-1) - for i := 0; i < n-1; i++ { - args[i] = params.At(i + 1) - } - return types.NewSignature(sig.Recv(), types.NewTuple(args...), sig.Results(), sig.Variadic()) -} - -// closureCtxParam returns the leading __llgo_ctx parameter if present. -func closureCtxParam(sig *types.Signature) *types.Var { - if sig == nil { - return nil - } - params := sig.Params() - if params.Len() == 0 { - return nil - } - first := params.At(0) - if first.Name() != closureCtx { - return nil - } - if _, ok := first.Type().Underlying().(*types.Pointer); !ok { - return nil - } - return first -} - -// closureWrapArgs returns wrapper arguments excluding the ctx parameter. -func closureWrapArgs(fn Function) []Expr { - n := len(fn.params) - if n <= 1 { - return nil - } - args := make([]Expr, n-1) - for i := 1; i < n; i++ { - args[i-1] = fn.Param(i) - } - return args -} - -// closureWrapReturn returns from wrapper, preserving tail-call eligibility. -func closureWrapReturn(b Builder, sig *types.Signature, ret Expr) { - n := sig.Results().Len() - if n == 0 { - if !ret.impl.IsNil() { - ret.impl.SetTailCall(true) - } - b.impl.CreateRetVoid() - return - } - ret.impl.SetTailCall(true) - b.impl.CreateRet(ret.impl) -} - -// closureWrapDecl wraps a function declaration that lacks __llgo_ctx. -// It directly calls the target symbol and ignores the ctx parameter. -func (p Package) closureWrapDecl(fn Expr, sig *types.Signature) Function { - name := closureStub + fn.impl.Name() - if wrap := p.FuncOf(name); wrap != nil { - return wrap - } - ctx := types.NewParam(token.NoPos, nil, closureCtx, types.Typ[types.UnsafePointer]) - sigCtx := FuncAddCtx(ctx, sig) - wrap := p.NewFunc(name, sigCtx, InC) - wrap.impl.SetLinkage(llvm.LinkOnceAnyLinkage) - b := wrap.MakeBody(1) - args := closureWrapArgs(wrap) - ret := b.Call(fn, args...) - closureWrapReturn(b, sig, ret) - return wrap -} - -// closureWrapPtr wraps a raw function pointer by loading it from ctx. -// The ctx parameter is treated as a pointer to a stored function pointer cell. -func (p Package) closureWrapPtr(sig *types.Signature) Function { - name := closureStub + p.Prog.abi.FuncName(sig) - if wrap := p.FuncOf(name); wrap != nil { - return wrap - } - ctx := types.NewParam(token.NoPos, nil, closureCtx, types.Typ[types.UnsafePointer]) - sigCtx := FuncAddCtx(ctx, sig) - wrap := p.NewFunc(name, sigCtx, InC) - wrap.impl.SetLinkage(llvm.LinkOnceAnyLinkage) - b := wrap.MakeBody(1) - ctxArg := wrap.Param(0) - fnType := p.Prog.rawType(sig) - fnPtrType := p.Prog.Pointer(fnType) - // ctxArg is expected to be a non-nil pointer to a stored function pointer cell. - // We intentionally avoid runtime null checks here; invalid ctx is a compiler/user error. - fnPtr := b.Convert(fnPtrType, ctxArg) - fnVal := b.Load(fnPtr) - args := closureWrapArgs(wrap) - ret := b.Call(fnVal, args...) - closureWrapReturn(b, sig, ret) - return wrap -} diff --git a/ssa/decl.go b/ssa/decl.go index a575dd1bee..68087f4380 100644 --- a/ssa/decl.go +++ b/ssa/decl.go @@ -248,7 +248,7 @@ type aFunction struct { params []Type freeVars Expr - base int // base = 1 if hasFreeVars; base = 0 otherwise + env Type hasVArg bool fakeUses []llvm.Value @@ -267,12 +267,45 @@ func (p Package) NewFunc(name string, sig *types.Signature, bg Background) Funct // NewFuncEx creates a new function. func (p Package) NewFuncEx(name string, sig *types.Signature, bg Background, hasFreeVars bool, instantiated bool) Function { + if hasFreeVars { + panic("ssa: NewFuncEx cannot represent an environment; use NewEnvFunc") + } + return p.newFunc(name, sig, bg, nil, instantiated) +} + +// NewEnvFunc creates a function whose Go signature is sig and whose physical +// LLVM entry has an additional compiler-owned environment parameter. +func (p Package) NewEnvFunc( + name string, sig *types.Signature, bg Background, env *types.Var, instantiated bool, +) Function { + if env == nil { + panic("ssa: nil closure environment") + } + return p.newFunc(name, sig, bg, env, instantiated) +} + +func (p Package) newFunc( + name string, sig *types.Signature, bg Background, env *types.Var, instantiated bool, +) Function { if v, ok := p.fns[name]; ok { + if v.NeedsEnv() != (env != nil) { + panic("ssa: conflicting closure environment ABI for " + name) + } return v } t := p.Prog.FuncDecl(sig, bg) - dbgInstrln("NewFunc", name, t.raw.Type, "hasFreeVars:", hasFreeVars) + var envType Type + if env != nil { + envType = p.Prog.Type(env.Type(), InGo) + rawEnv := types.NewParam(env.Pos(), env.Pkg(), env.Name(), envType.raw.Type) + entrySig := FuncAddCtx(rawEnv, t.raw.Type.(*types.Signature)) + t = &aType{p.Prog.toLLVMFunc(entrySig), t.raw, vkFuncDecl} + } + dbgInstrln("NewFunc", name, t.raw.Type, "needsEnv:", envType != nil) fn := llvm.AddFunction(p.mod, name, t.ll) + if envType != nil { + p.Prog.markClosureEnvFunction(fn, 0) + } if bg == InGo { fn.AddFunctionAttr(p.nullPointerIsValidAttr) // Keep frame pointers so the runtime can walk real stacks (FP chain) @@ -290,7 +323,7 @@ func (p Package) NewFuncEx(name string, sig *types.Signature, bg Background, has if p.isPreservedName(name) { p.markLLVMUsed(fn) } - ret := newFunction(fn, t, p, p.Prog, hasFreeVars) + ret := newFunction(fn, t, p, p.Prog, envType) p.fns[name] = ret return ret } @@ -300,18 +333,14 @@ func (p Package) FuncOf(name string) Function { return p.fns[name] } -func newFunction(fn llvm.Value, t Type, pkg Package, prog Program, hasFreeVars bool) Function { +func newFunction(fn llvm.Value, t Type, pkg Package, prog Program, env Type) Function { params, hasVArg := newParams(t, prog) - base := 0 - if hasFreeVars { - base = 1 - } return &aFunction{ Expr: Expr{fn, t}, Pkg: pkg, Prog: prog, params: params, - base: base, + env: env, hasVArg: hasVArg, fakeUses: make([]llvm.Value, 0, 4), fakeUseSet: make(map[llvm.Value]struct{}), @@ -340,16 +369,38 @@ func (p Function) Name() string { // Params returns the function's ith parameter. func (p Function) Param(i int) Expr { - i += p.base // skip if hasFreeVars - return Expr{p.impl.Param(i), p.params[i]} + physical := i + if p.env != nil { + physical++ + } + return Expr{p.impl.Param(physical), p.params[i]} +} + +// NeedsEnv reports whether the physical function entry takes a compiler-owned +// closure environment parameter. +func (p Function) NeedsEnv() bool { + return p.env != nil +} + +// EnvType returns the physical closure environment pointer type, or nil. +func (p Function) EnvType() Type { + return p.env +} + +// Env returns the physical closure environment parameter. +func (p Function) Env() Expr { + if p.env == nil { + panic("ssa: function has no closure environment") + } + return Expr{p.impl.Param(0), p.env} } func (p Function) closureCtx(b Builder) Expr { if p.freeVars.IsNil() { - if p.base == 0 { + if p.env == nil { panic("ssa: function has no free variables") } - ptr := Expr{p.impl.Param(0), p.params[0]} + ptr := p.Env() if b.blk.Index() != 0 { blk := b.impl.GetInsertBlock() b.SetBlockEx(p.blks[0], AtStart, false) diff --git a/ssa/eh.go b/ssa/eh.go index b8ead4eb64..104b8e04af 100644 --- a/ssa/eh.go +++ b/ssa/eh.go @@ -484,12 +484,13 @@ func (b Builder) saveDeferArgs(self *aDefer, kind DoAction, id Expr, fn Expr, ar } func (b Builder) saveDeferArgsTo(argsPtr Expr, kind DoAction, id Expr, fn Expr, args []Expr) Type { - if kind != DeferInLoop && fn != Nil && fn.kind != vkClosure && len(args) == 0 { + saveFn := fn != Nil && (fn.kind == vkClosure || fn.kind == vkIfaceMethod) + if kind != DeferInLoop && fn != Nil && !saveFn && len(args) == 0 { return nil } prog := b.Prog offset := 2 // prev + id - if fn != Nil && fn.kind == vkClosure { + if saveFn { offset++ } typs := make([]Type, len(args)+offset) @@ -498,7 +499,7 @@ func (b Builder) saveDeferArgsTo(argsPtr Expr, kind DoAction, id Expr, fn Expr, flds[0] = b.Load(argsPtr).impl typs[1] = prog.Uintptr() flds[1] = id.impl - if fn != Nil && fn.kind == vkClosure { + if saveFn { typs[2] = fn.Type flds[2] = fn.impl } @@ -529,8 +530,16 @@ func (b Builder) callDefer(self *aDefer, typ Type, buildCall func(Builder, Expr, data := b.Load(Expr{ptr.impl, prog.Pointer(typ)}) offset := 2 // prev + id b.Store(self.argsPtr, Expr{b.getField(data, 0).impl, prog.VoidPtr()}) - if fn != Nil && fn.kind == vkClosure { + if fn != Nil && (fn.kind == vkClosure || fn.kind == vkIfaceMethod) { + savedType := fn.Type fn = b.getField(data, 2) + // A transient interface invocation has the same physical pair as a + // funcval, so aggregate field reconstruction sees vkClosure. Keep + // its call semantics: the saved data word is an ordinary receiver, + // not a hidden closure environment. + if savedType.kind == vkIfaceMethod { + fn.Type = savedType + } offset++ } for i := 0; i < len(args); i++ { diff --git a/ssa/expr.go b/ssa/expr.go index 6f476c9eac..dce7fb24c6 100644 --- a/ssa/expr.go +++ b/ssa/expr.go @@ -705,14 +705,14 @@ func (b Builder) BinOp(op token.Token, x, y Expr) Expr { ret.impl = llvm.CreateNot(b.impl, ret.impl) return ret } - case vkClosure: + case vkClosure, vkIfaceMethod: x = b.Field(x, 0) - if y.kind == vkClosure { + if y.kind == vkClosure || y.kind == vkIfaceMethod { y = b.Field(y, 0) } fallthrough case vkFuncPtr, vkFuncDecl, vkChan, vkMap: - if y.kind == vkClosure { + if y.kind == vkClosure || y.kind == vkIfaceMethod { y = b.Field(y, 0) } switch op { @@ -1194,15 +1194,26 @@ func (b Builder) PtrCast(t Type, x Expr) Expr { func (b Builder) MakeClosure(fn Expr, bindings []Expr) Expr { dbgInstrf("MakeClosure %v, %v\n", fn, bindings) prog := b.Prog - tfn := fn.Type - sig := tfn.raw.Type.(*types.Signature) + sig := fn.raw.Type.(*types.Signature) data := prog.Nil(prog.VoidPtr()).impl - if ctxParam := closureCtxParam(sig); ctxParam != nil { - tctx := ctxParam.Type().Underlying().(*types.Pointer).Elem().(*types.Struct) - ptr := b.aggregateAllocU(prog.rawType(tctx), llvmFields(bindings, tctx, b)...) - data = ptr + if entry := b.Pkg.FuncOf(fn.impl.Name()); entry != nil && entry.NeedsEnv() { + tctx := prog.Elem(entry.EnvType()) + rawCtx := tctx.raw.Type.Underlying().(*types.Struct) + if len(bindings) != rawCtx.NumFields() { + panic("ssa: closure environment binding count mismatch") + } + if prog.SizeOf(tctx) == 0 { + // A required environment must remain distinguishable from a no-env + // entry. Heap zero-sized allocations use the module-wide non-nil + // sentinel. + data = b.Alloc(tctx, true).impl + } else { + data = b.aggregateAllocU(tctx, llvmFields(bindings, rawCtx, b)...) + } + } else if len(bindings) != 0 { + panic("ssa: closure bindings supplied to a no-env function") } - return b.aggregateValue(prog.Closure(removeCtx(sig)), fn.impl, data) + return b.aggregateValue(prog.Closure(sig), fn.impl, data) } // ----------------------------------------------------------------------------- @@ -1237,14 +1248,20 @@ func (b Builder) Call(fn Expr, args ...Expr) (ret Expr) { data = b.Field(fn, 1) fn = b.Field(fn, 0) sig = fn.raw.Type.(*types.Signature) - ctx := types.NewParam(token.NoPos, nil, closureCtx, types.Typ[types.UnsafePointer]) - sigCtx := FuncAddCtx(ctx, sig) + return b.callClosure(fn, data, sig, args) + case vkIfaceMethod: + data = b.Field(fn, 1) + fn = b.Field(fn, 0) + sig = fn.raw.Type.(*types.Signature) + recv := types.NewParam(token.NoPos, nil, "$recv", types.Typ[types.UnsafePointer]) + entrySig := FuncAddCtx(recv, sig) ret.Type = b.Prog.retType(sig) - if sig.Results().Len() == 1 && b.Prog.SizeOf(ret.Type) == 0 { - b.AssertNilDeref(fn) - } - ll = b.Prog.FuncDecl(sigCtx, InC).ll - ret.impl = llvm.CreateCall(b.impl, ll, fn.impl, llvmParamsEx(data, args, sigCtx.Params(), b)) + ret.impl = llvm.CreateCall( + b.impl, + b.Prog.FuncDecl(entrySig, InC).ll, + fn.impl, + llvmParamsEx(data, args, entrySig.Params(), b), + ) return ret case vkFuncPtr: sig = raw.Underlying().(*types.Signature) @@ -1275,6 +1292,96 @@ func (b Builder) Call(fn Expr, args ...Expr) (ret Expr) { return } +func (b Builder) callClosure(fn, data Expr, sig *types.Signature, args []Expr) (ret Expr) { + prog := b.Prog + ret.Type = prog.retType(sig) + if sig.Results().Len() == 1 && prog.SizeOf(ret.Type) == 0 { + b.AssertNilDeref(fn) + } + + // Convert arguments once before splitting the dynamic call edge. Conversion + // may itself emit code and must not be duplicated into both successors. + params := llvmParams(0, args, sig.Params(), b) + envParams := make([]llvm.Value, len(params)+1) + envParams[0] = data.impl + copy(envParams[1:], params) + + noEnvType := prog.FuncDecl(sig, InC).ll + envParam := types.NewParam(token.NoPos, nil, "$env", types.Typ[types.UnsafePointer]) + envSig := FuncAddCtx(envParam, sig) + envType := prog.FuncDecl(envSig, InC).ll + + // A known code pointer uses the entry metadata directly. This preserves the + // exact prototype and avoids the identity barrier needed by dynamic native + // funcval calls. + if direct := fn.impl.IsAFunction(); !direct.IsNil() { + entry := b.Pkg.FuncOf(direct.Name()) + if entry == nil || !entry.NeedsEnv() { + ret.impl = llvm.CreateCall(b.impl, noEnvType, fn.impl, params) + return + } + ret.impl = llvm.CreateCall(b.impl, envType, fn.impl, envParams) + prog.markClosureEnvCall(ret.impl, 0) + return + } + + // On native hidden-context ABIs, the environment occupies a dedicated + // register even when it is nil. Ordinary Go and C entries simply ignore + // that register, so every dynamic funcval call can use the same hot path. + // Explicit-context targets cannot do this: their environment is an + // ordinary leading ABI argument and pure C entries do not accept it. + if prog.closureEnvABI() != closureEnvExplicit { + // The env and no-env LLVM prototypes intentionally differ even though the + // native machine ABI reserves a register for the hidden environment. Hide + // the dynamic code pointer's identity before the call so optimization cannot + // devirtualize a no-env target under the env-bearing IR prototype. + fn = b.hideClosureCodeIdentity(fn) + ret.impl = llvm.CreateCall(b.impl, envType, fn.impl, envParams) + prog.markClosureEnvCall(ret.impl, 0) + return + } + + logicalBlock := b.blk + entryBlock := b.impl.GetInsertBlock() + blks := b.Func.MakeBlocks(3) + hasEnv := Expr{ + llvm.CreateICmp(b.impl, llvm.IntNE, data.impl, prog.Nil(prog.VoidPtr()).impl), + prog.Bool(), + } + b.If(hasEnv, blks[0], blks[1]) + + b.SetBlockEx(blks[0], AtEnd, false) + envCall := llvm.CreateCall(b.impl, envType, fn.impl, envParams) + prog.markClosureEnvCall(envCall, 0) + b.Jump(blks[2]) + + b.SetBlockEx(blks[1], AtEnd, false) + noEnvCall := llvm.CreateCall(b.impl, noEnvType, fn.impl, params) + b.Jump(blks[2]) + + b.SetBlockEx(blks[2], AtEnd, false) + if sig.Results().Len() != 0 { + phi := b.Phi(ret.Type) + phi.impl.AddIncoming( + []llvm.Value{envCall, noEnvCall}, + []llvm.BasicBlock{blks[0].last, blks[1].last}, + ) + ret.impl = phi.impl + } + + // The extra LLVM blocks are an implementation detail inside the current Go + // SSA block. Only explicit-context targets retain this split; native hidden + // context has the uniform dynamic call edge above. + // A closure call may itself be emitted while another lowering helper has + // temporarily selected a synthetic LLVM predecessor with SetBlockEx(..., + // false). Only replace the logical Go block's tail when this split started + // at that tail; otherwise the enclosing helper owns the eventual merge. + if logicalBlock.last == entryBlock { + logicalBlock.last = blks[2].last + } + return +} + const ( ReflectArrayOf = 1 << iota ReflectChanOf @@ -1308,7 +1415,7 @@ func (b Builder) checkReflect(fn Expr, args []Expr) (check ReflectMethodCheck) { reflectKind = ReflectMapOf case "reflect.PointerTo", "reflect.PtrTo": reflectKind = ReflectPointerTo - case "reflect.SliceOf", "reflect.Value.Slice": + case "reflect.SliceOf", "reflect.SliceAt", "reflect.Value.Slice": reflectKind = ReflectSliceOf case "reflect.StructOf": reflectKind = ReflectStructOf @@ -1727,7 +1834,6 @@ func checkExpr(v Expr, t types.Type, b Builder) Expr { return v } prog := b.Prog - origKind := v.kind tclosure := prog.rawType(t) fnType := prog.Field(tclosure, 0) if v.Type != fnType { @@ -1739,11 +1845,6 @@ func checkExpr(v Expr, t types.Type, b Builder) Expr { } } data := prog.Nil(prog.VoidPtr()) - if origKind == vkFuncDecl || origKind == vkFuncPtr { - if sig, ok := fnType.raw.Type.(*types.Signature); ok && closureCtxParam(sig) == nil { - v, data = b.Pkg.closureStub(b, v, sig, origKind) - } - } return b.aggregateValue(tclosure, v.impl, data.impl) } if types.Identical(v.raw.Type, t) || !types.AssignableTo(v.raw.Type, t) { diff --git a/ssa/funcinfo.go b/ssa/funcinfo.go index 25e792b6c3..f09f3bd3e8 100644 --- a/ssa/funcinfo.go +++ b/ssa/funcinfo.go @@ -38,7 +38,7 @@ func (p Program) FuncInfoMetadataEnabled() bool { } // EnableFuncInfoSites controls emission of the per-function site records -// (entry/stub/pc-line inline-asm fragments inside function bodies). They are +// (entry and PC-line inline-asm fragments inside function bodies). They are // gated separately from the funcinfo metadata tables because the // body-embedded anchors shift instruction/scope layout enough to confuse // debuggers; debug builds keep the tables (FuncForPC name/FileLine fidelity diff --git a/ssa/goroutine.go b/ssa/goroutine.go index 398a5ee376..f8f7c344fb 100644 --- a/ssa/goroutine.go +++ b/ssa/goroutine.go @@ -95,7 +95,14 @@ func (p Package) routine(t Type, fn Expr, buildCall func(Builder, Expr, ...Expr) args := make([]Expr, n) var offset int if fn != Nil && fn.kind != vkBuiltin { + savedType := fn.Type fn = b.getField(data, 0) + // Interface invocation pairs are structurally funcvals, but their data + // word remains an ordinary receiver argument after crossing the + // goroutine startup record. + if savedType.kind == vkIfaceMethod { + fn.Type = savedType + } offset = 1 } for i := 0; i < n; i++ { diff --git a/ssa/goroutine_patch_test.go b/ssa/goroutine_patch_test.go index 53d704dd42..c6db16005d 100644 --- a/ssa/goroutine_patch_test.go +++ b/ssa/goroutine_patch_test.go @@ -21,9 +21,8 @@ func TestGoClosureStartupUsesGCManagedMemory(t *testing.T) { types.NewField(0, nil, "x", types.Typ[types.Int], false), } ctxStruct := types.NewStruct(ctxFields, nil) - ctxParam := types.NewParam(0, nil, "__llgo_ctx", types.NewPointer(ctxStruct)) - innerSig := types.NewSignatureType(nil, nil, nil, types.NewTuple(ctxParam), nil, false) - inner := pkg.NewFunc("inner", innerSig, ssa.InGo) + ctxParam := types.NewParam(0, nil, "$env", types.NewPointer(ctxStruct)) + inner := pkg.NewEnvFunc("inner", ssa.NoArgsNoRet, ssa.InGo, ctxParam, false) ib := inner.MakeBody(1) ib.Return() diff --git a/ssa/interface.go b/ssa/interface.go index 253df5c64b..556bf23baf 100644 --- a/ssa/interface.go +++ b/ssa/interface.go @@ -97,7 +97,10 @@ func (b Builder) Imethod(intf Expr, method *types.Func) Expr { } else { fn = b.Load(pfn) } - ret := b.aggregateValue(tclosure, fn.impl, data.impl) + // This is a transient interface invocation pair, not a first-class + // funcval. The method receiver remains an ordinary ABI parameter. + tmethod := &aType{tclosure.ll, tclosure.raw, vkIfaceMethod} + ret := b.aggregateValue(tmethod, fn.impl, data.impl) return ret } diff --git a/ssa/package.go b/ssa/package.go index db41bae4ab..498bbaf942 100644 --- a/ssa/package.go +++ b/ssa/package.go @@ -221,12 +221,13 @@ type aProgram struct { printfTy *types.Signature - paramObjPtr_ *types.Var - linknameMu sync.RWMutex - linkname map[string]string // pkgPath.nameInPkg => linkname - localities *localityInfos - noInterface map[string]none // pkgPath.T.method or pkgPath.(*T).method - abiSymbol map[string]*AbiSymbol // abi symbol name => AbiSymbol + paramObjPtr_ *types.Var + linknameMu sync.RWMutex + linkname map[string]string // pkgPath.nameInPkg => linkname + closureEnvDirectives sync.Map // closureEnvDirectiveKey => none + localities *localityInfos + noInterface map[string]none // pkgPath.T.method or pkgPath.(*T).method + abiSymbol map[string]*AbiSymbol // abi symbol name => AbiSymbol ptrSize int @@ -425,6 +426,28 @@ func (p Program) Linkname(name string) (link string, ok bool) { return } +type closureEnvDirectiveKey struct { + fset *token.FileSet + name string + pos token.Pos +} + +// SetClosureEnvDirective records that a source function declaration has the +// llgo:env directive. name and pos identify the source declaration rather +// than its resolved linker symbol, so aliases retain independent ABI metadata. +func (p Program) SetClosureEnvDirective(fset *token.FileSet, name string, pos token.Pos) { + key := closureEnvDirectiveKey{fset: fset, name: name, pos: pos} + p.closureEnvDirectives.Store(key, none{}) +} + +// HasClosureEnvDirective reports whether a source function declaration has the +// cached llgo:env directive. +func (p Program) HasClosureEnvDirective(fset *token.FileSet, name string, pos token.Pos) bool { + key := closureEnvDirectiveKey{fset: fset, name: name, pos: pos} + _, ok := p.closureEnvDirectives.Load(key) + return ok +} + func (p Program) runtime() *types.Package { if p.rt == nil { p.rt = p.rtget() @@ -900,6 +923,21 @@ func (p Package) rtFunc(fnName string) Expr { return p.NewFunc(name, sig, InGo).Expr } +// rtEnvFunc returns a runtime entry whose source-level signature excludes its +// compiler-owned environment. Runtime type algorithms use this form when a +// type descriptor supplies the hidden type context. +func (p Package) rtEnvFunc(fnName string) Expr { + p.NeedRuntime = true + fn := p.Prog.runtime().Scope().Lookup(fnName).(*types.Func) + name := FullName(fn.Pkg(), fnName) + if p.fnlink != nil { + name = p.fnlink(name) + } + sig := fn.Type().(*types.Signature) + env := types.NewVar(token.NoPos, nil, "$env", types.Typ[types.UnsafePointer]) + return p.NewEnvFunc(name, sig, InGo, env, false).Expr +} + // RuntimeFunc returns a declaration for a function in LLGo's internal runtime. func (p Package) RuntimeFunc(fnName string) Expr { return p.rtFunc(fnName) @@ -909,30 +947,6 @@ func (p Package) cFunc(fullName string, sig *types.Signature) Expr { return p.NewFunc(fullName, sig, InC).Expr } -const ( - closureCtx = "__llgo_ctx" - closureStub = "__llgo_stub." -) - -// closureStub creates or reuses a wrapper for function values that lack closure ctx. -// It stays on Package to match the original placement of closure stubs. -func (p Package) closureStub(b Builder, fn Expr, sig *types.Signature, origKind valueKind) (Expr, Expr) { - prog := b.Prog - switch origKind { - case vkFuncDecl: - wrap := p.closureWrapDecl(fn, sig) - return wrap.Expr, prog.Nil(prog.VoidPtr()) - case vkFuncPtr: - wrap := p.closureWrapPtr(sig) - ptr := b.AllocU(prog.rawType(sig)) - b.Store(ptr, fn) - data := b.Convert(prog.VoidPtr(), ptr) - return wrap.Expr, data - default: - return fn, prog.Nil(prog.VoidPtr()) - } -} - // ----------------------------------------------------------------------------- // Path returns the package path. diff --git a/ssa/ssa_test.go b/ssa/ssa_test.go index 36ba6b46e7..05f998fae0 100644 --- a/ssa/ssa_test.go +++ b/ssa/ssa_test.go @@ -980,9 +980,9 @@ _llgo_func$2_iS07vIlF2_rZqWB5eU0IvP_9HviM4MYZNkXZDvbac: [MethodInfo] *_llgo_example.com/pkg.T: - 0 M _llgo_func$2_iS07vIlF2_rZqWB5eU0IvP_9HviM4MYZNkXZDvbac example.com/pkg.(*T).M __llgo_stub.example.com/pkg.(*T).M + 0 M _llgo_func$2_iS07vIlF2_rZqWB5eU0IvP_9HviM4MYZNkXZDvbac example.com/pkg.(*T).M example.com/pkg.(*T).M _llgo_example.com/pkg.T: - 0 M _llgo_func$2_iS07vIlF2_rZqWB5eU0IvP_9HviM4MYZNkXZDvbac example.com/pkg.(*T).M __llgo_stub.example.com/pkg.T.M + 0 M _llgo_func$2_iS07vIlF2_rZqWB5eU0IvP_9HviM4MYZNkXZDvbac example.com/pkg.(*T).M example.com/pkg.T.M ` if got := pm.String(); got != want { @@ -1016,6 +1016,21 @@ pkg.named: } } +func TestReflectSliceAtDemandsSliceTypeInit(t *testing.T) { + prog := NewProgram(nil) + defer prog.Dispose() + pkg := prog.NewPackage("pkg", "pkg") + sliceAt := pkg.NewFunc("reflect.SliceAt", NoArgsNoRet, InGo) + caller := pkg.NewFunc("pkg.callSliceAt", NoArgsNoRet, InGo) + b := caller.MakeBody(1) + b.Call(sliceAt.Expr) + b.Return() + + if got := pkg.NeedAbiInit & ReflectSliceOf; got == 0 { + t.Fatal("reflect.SliceAt did not retain slice type-construction metadata") + } +} + func TestRecordUseIface(t *testing.T) { prog := NewProgram(nil) defer prog.Dispose() @@ -1229,16 +1244,10 @@ _llgo_0: define void @holder() #0 { _llgo_0: %0 = alloca { ptr, ptr }, align 8 - store { ptr, ptr } { ptr @__llgo_stub.fn, ptr null }, ptr %0, align 8 + store { ptr, ptr } { ptr @fn, ptr null }, ptr %0, align 8 ret void } -define linkonce i64 @__llgo_stub.fn(ptr %0, i64 %1) { -_llgo_0: - %2 = tail call i64 @fn(i64 %1) - ret i64 %2 -} - attributes #0 = { null_pointer_is_valid "frame-pointer"="non-leaf" } `) } @@ -1270,43 +1279,25 @@ func TestClosureFuncPtrValue(t *testing.T) { hb.Store(ptr, fnPtr) hb.Return() - wrapName := "__llgo_stub." + prog.abi.FuncName(sig) - wrapRef := wrapName - if strings.Contains(wrapName, "$") { - wrapRef = fmt.Sprintf("\"%s\"", wrapName) - } - expected := fmt.Sprintf(`; ModuleID = 'foo/bar' + expected := `; ModuleID = 'foo/bar' source_filename = "foo/bar" ; Function Attrs: null_pointer_is_valid -define i64 @fn(i64 %%0) #0 { +define i64 @fn(i64 %0) #0 { _llgo_0: - ret i64 %%0 + ret i64 %0 } ; Function Attrs: null_pointer_is_valid define void @holder() #0 { _llgo_0: - %%0 = alloca { ptr, ptr }, align 8 - %%1 = call ptr @"github.com/goplus/llgo/runtime/internal/runtime.AllocU"(i64 8) - store ptr @fn, ptr %%1, align 8 - %%2 = insertvalue { ptr, ptr } { ptr @%s, ptr undef }, ptr %%1, 1 - store { ptr, ptr } %%2, ptr %%0, align 8 + %0 = alloca { ptr, ptr }, align 8 + store { ptr, ptr } { ptr @fn, ptr null }, ptr %0, align 8 ret void } -define linkonce i64 @%s(ptr %%0, i64 %%1) { -_llgo_0: - %%2 = load ptr, ptr %%0, align 8 - %%3 = tail call i64 %%2(i64 %%1) - ret i64 %%3 -} - -; Function Attrs: null_pointer_is_valid -declare ptr @"github.com/goplus/llgo/runtime/internal/runtime.AllocU"(i64) #0 - attributes #0 = { null_pointer_is_valid "frame-pointer"="non-leaf" } -`, wrapRef, wrapRef) +` assertPkg(t, pkg, expected) } @@ -1447,7 +1438,8 @@ func TestConvertStringFromWideIntegers(t *testing.T) { } func TestCallClosureDynamic(t *testing.T) { - prog := NewProgram(nil) + prog := NewProgram(&Target{GOOS: "wasip1", GOARCH: "wasm"}) + defer prog.Dispose() pkg := prog.NewPackage("bar", "foo/bar") params := types.NewTuple(types.NewVar(0, nil, "x", types.Typ[types.Int])) @@ -1462,20 +1454,17 @@ func TestCallClosureDynamic(t *testing.T) { b := caller.MakeBody(1) b.Return(b.Call(caller.Param(0), caller.Param(1))) - assertPkg(t, pkg, `; ModuleID = 'foo/bar' -source_filename = "foo/bar" - -; Function Attrs: null_pointer_is_valid -define i64 @caller({ ptr, ptr } %0, i64 %1) #0 { -_llgo_0: - %2 = extractvalue { ptr, ptr } %0, 1 - %3 = extractvalue { ptr, ptr } %0, 0 - %4 = call i64 %3(ptr %2, i64 %1) - ret i64 %4 -} - -attributes #0 = { null_pointer_is_valid "frame-pointer"="non-leaf" } -`) + ir := pkg.String() + for _, want := range []string{ + "icmp ne ptr %2, null", + "call i32 %3(ptr ", + "call i32 %3(i32 %1)", + "phi i32", + } { + if !strings.Contains(ir, want) { + t.Fatalf("dynamic closure call missing %q:\n%s", want, ir) + } + } } func TestMakeClosureWithCtx(t *testing.T) { @@ -1490,13 +1479,13 @@ func TestMakeClosureWithCtx(t *testing.T) { ctxFields := []*types.Var{types.NewField(0, nil, "x", types.Typ[types.Int], false)} ctxStruct := types.NewStruct(ctxFields, nil) ctxPtr := types.NewPointer(ctxStruct) - ctxParam := types.NewParam(0, nil, "__llgo_ctx", ctxPtr) - innerParams := types.NewTuple(ctxParam, types.NewVar(0, nil, "y", types.Typ[types.Int])) + ctxParam := types.NewParam(0, nil, "$env", ctxPtr) + innerParams := types.NewTuple(types.NewVar(0, nil, "y", types.Typ[types.Int])) innerRets := types.NewTuple(types.NewVar(0, nil, "", types.Typ[types.Int])) innerSig := types.NewSignatureType(nil, nil, nil, innerParams, innerRets, false) - inner := pkg.NewFunc("inner", innerSig, InGo) + inner := pkg.NewEnvFunc("inner", innerSig, InGo, ctxParam, false) ib := inner.MakeBody(1) - ib.Return(inner.Param(1)) + ib.Return(inner.Param(0)) outerParams := types.NewTuple(types.NewVar(0, nil, "x", types.Typ[types.Int])) outerRetSig := types.NewSignatureType(nil, nil, nil, @@ -1509,30 +1498,20 @@ func TestMakeClosureWithCtx(t *testing.T) { closure := ob.MakeClosure(inner.Expr, []Expr{outer.Param(0)}) ob.Return(closure) - assertPkg(t, pkg, `; ModuleID = 'foo/bar' -source_filename = "foo/bar" - -; Function Attrs: null_pointer_is_valid -define i64 @inner(ptr %0, i64 %1) #0 { -_llgo_0: - ret i64 %1 -} - -; Function Attrs: null_pointer_is_valid -define { ptr, ptr } @outer(i64 %0) #0 { -_llgo_0: - %1 = call ptr @"github.com/goplus/llgo/runtime/internal/runtime.AllocU"(i64 8) - %2 = getelementptr inbounds { i64 }, ptr %1, i32 0, i32 0 - store i64 %0, ptr %2, align 8 - %3 = insertvalue { ptr, ptr } { ptr @inner, ptr undef }, ptr %1, 1 - ret { ptr, ptr } %3 -} - -; Function Attrs: null_pointer_is_valid -declare ptr @"github.com/goplus/llgo/runtime/internal/runtime.AllocU"(i64) #0 - -attributes #0 = { null_pointer_is_valid "frame-pointer"="non-leaf" } -`) + if got := inner.Expr.raw.Type.(*types.Signature).Params().Len(); got != 1 { + t.Fatalf("semantic closure entry signature has %d params, want 1", got) + } + ir := pkg.String() + for _, want := range []string{ + "define i64 @inner(ptr ", + "i64 %1)", + `call ptr @"github.com/goplus/llgo/runtime/internal/runtime.AllocU"(i64 8)`, + "insertvalue { ptr, ptr } { ptr @inner, ptr undef }", + } { + if !strings.Contains(ir, want) { + t.Fatalf("closure environment IR missing %q:\n%s", want, ir) + } + } } func TestCvtClosureDropsRecv(t *testing.T) { @@ -1644,79 +1623,6 @@ attributes #0 = { null_pointer_is_valid "frame-pointer"="non-leaf" } `) } -func TestClosureCtxHelpers(t *testing.T) { - if closureCtxParam(nil) != nil { - t.Fatal("closureCtxParam should be nil for nil signature") - } - params := types.NewTuple() - rets := types.NewTuple() - sig := types.NewSignatureType(nil, nil, nil, params, rets, false) - if closureCtxParam(sig) != nil { - t.Fatal("closureCtxParam should be nil for empty params") - } - if removeCtx(sig) != sig { - t.Fatal("removeCtx should return original signature when no ctx param") - } - - badCtx := types.NewParam(0, nil, closureCtx, types.Typ[types.Int]) - badSig := types.NewSignatureType(nil, nil, nil, types.NewTuple(badCtx), rets, false) - if closureCtxParam(badSig) != nil { - t.Fatal("closureCtxParam should ignore non-pointer ctx param") - } - - ctxStruct := types.NewStruct([]*types.Var{ - types.NewVar(0, nil, "v", types.Typ[types.Int]), - }, nil) - goodCtx := types.NewParam(0, nil, closureCtx, types.NewPointer(ctxStruct)) - arg := types.NewParam(0, nil, "x", types.Typ[types.Int]) - goodSig := types.NewSignatureType(nil, nil, nil, types.NewTuple(goodCtx, arg), rets, false) - if closureCtxParam(goodSig) == nil { - t.Fatal("closureCtxParam should detect ctx param") - } - noCtx := removeCtx(goodSig) - if noCtx.Params().Len() != 1 || noCtx.Params().At(0).Name() != "x" { - t.Fatalf("removeCtx result mismatch: params=%v", noCtx.Params().Len()) - } -} - -func TestClosureWrapHelpers(t *testing.T) { - prog := NewProgram(nil) - pkg := prog.NewPackage("bar", "foo/bar") - ctx := types.NewParam(0, nil, closureCtx, types.Typ[types.UnsafePointer]) - sig := types.NewSignatureType(nil, nil, nil, types.NewTuple(), types.NewTuple(), false) - sigCtx := FuncAddCtx(ctx, sig) - wrap := pkg.NewFunc("wrap", sigCtx, InGo) - b := wrap.MakeBody(1) - if args := closureWrapArgs(wrap); len(args) != 0 { - t.Fatalf("closureWrapArgs should return 0 args, got %d", len(args)) - } - closureWrapReturn(b, sig, Expr{}) -} - -func TestClosureWrapCache(t *testing.T) { - prog := NewProgram(nil) - pkg := prog.NewPackage("bar", "foo/bar") - - params := types.NewTuple(types.NewVar(0, nil, "x", types.Typ[types.Int])) - rets := types.NewTuple(types.NewVar(0, nil, "", types.Typ[types.Int])) - sig := types.NewSignatureType(nil, nil, nil, params, rets, false) - fn := pkg.NewFunc("fn", sig, InGo) - b := fn.MakeBody(1) - b.Return(fn.Param(0)) - - w1 := pkg.closureWrapDecl(fn.Expr, sig) - w2 := pkg.closureWrapDecl(fn.Expr, sig) - if w1 != w2 { - t.Fatal("closureWrapDecl should reuse existing wrapper") - } - - p1 := pkg.closureWrapPtr(sig) - p2 := pkg.closureWrapPtr(sig) - if p1 != p2 { - t.Fatal("closureWrapPtr should reuse existing wrapper") - } -} - func TestMakeInterfaceKinds(t *testing.T) { prog := NewProgram(nil) prog.sizes = types.SizesFor("gc", runtime.GOARCH) @@ -1989,14 +1895,8 @@ func TestPackageCoverageHelpers(t *testing.T) { t.Fatal("ExportFuncs should be empty for new package") } - // cover closureStub default branch fn := pkg.NewFunc("noop", NoArgsNoRet, InGo) b := fn.MakeBody(1) - expr := prog.Val(1) - got, data := pkg.closureStub(b, expr, nil, vkString) - if got.impl.IsNil() || !data.impl.IsNull() { - t.Fatal("closureStub default branch should return expr and nil data") - } b.Return() } diff --git a/ssa/target.go b/ssa/target.go index a352b477fd..e9317f669c 100644 --- a/ssa/target.go +++ b/ssa/target.go @@ -27,11 +27,12 @@ import ( // ----------------------------------------------------------------------------- type Target struct { - GOOS string - GOARCH string - GOARM string // "5", "6", "7" (default) - Target string // target name from -target flag (e.g., "esp32", "arm7tdmi", "wasi") - OptLevel optlevel.Level + GOOS string + GOARCH string + GOARM string // "5", "6", "7" (default) + Target string // target name from -target flag (e.g., "esp32", "arm7tdmi", "wasi") + LLVMTarget string // physical LLVM target selected by a target configuration + OptLevel optlevel.Level } func (p *Target) targetInfo() (llvm.TargetData, llvm.TargetMachine) { diff --git a/ssa/type.go b/ssa/type.go index 98c9fc4848..c635cf16e9 100644 --- a/ssa/type.go +++ b/ssa/type.go @@ -47,6 +47,7 @@ const ( vkFuncDecl vkFuncPtr vkClosure + vkIfaceMethod vkBuiltin vkPyFuncRef vkPyVarRef diff --git a/test/goroot/xfail.yaml b/test/goroot/xfail.yaml index cee4671e72..7912d20eb8 100644 --- a/test/goroot/xfail.yaml +++ b/test/goroot/xfail.yaml @@ -2444,10 +2444,6 @@ xfails: directive: run case: nilptr2.go reason: address-of a dereferenced nil pointer does not panic and the run hangs on darwin/arm64 - - platform: darwin/arm64 - directive: run - case: range4.go - reason: range-over-function build exits successfully without producing a binary on darwin/arm64 - platform: darwin/arm64 directive: run case: fixedbugs/issue31546.go