Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
c828325
compiler: add standalone locality directive analysis
cpunion Jul 13, 2026
9a8afa0
runtime: add stack-rooted locality contexts
cpunion Jul 14, 2026
5bda69c
compiler: lower TLS and GLS package variables
cpunion Jul 14, 2026
08fca6f
build: key local context mode in package cache
cpunion Jul 14, 2026
9aded28
test: cover TLS and GLS runtime behavior
cpunion Jul 14, 2026
ebac891
runtime: split local package fast path
cpunion Jul 14, 2026
bbfea02
runtime: return local package data from hot block
cpunion Jul 14, 2026
99f32a6
test: cover locality debug metadata lowering
cpunion Jul 14, 2026
809726c
compiler: inline local package fast path
cpunion Jul 15, 2026
97ad68e
runtime: publish FuncForPC cache entries atomically
cpunion Jul 15, 2026
e0d2542
compiler/runtime: use direct package locality caches
cpunion Jul 15, 2026
99eadfc
cl: cover locality validation and import lowering
cpunion Jul 15, 2026
69c2fc0
compiler/runtime: address locality review feedback
cpunion Jul 23, 2026
193b85c
runtime: store goroutine state in GLS
cpunion Jul 14, 2026
642c241
build: avoid runtime linkage for pure C programs
cpunion Jul 19, 2026
867b062
runtime: initialize GLS context for C libraries
cpunion Jul 20, 2026
59a616e
build: document library locality context
cpunion Jul 23, 2026
06d1e2e
ssa,runtime: tighten recover to direct deferred calls (Defer-node model)
cpunion Jul 6, 2026
b7b7898
ssa,runtime: real runtime.Error values for type asserts, fault signal…
cpunion Jul 6, 2026
5ee4bd8
style: gofmt golden in.go files under _testrt
cpunion Jul 6, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 12 additions & 4 deletions cl/_testdata/cpkg/in.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,17 +5,25 @@ package C

// CHECK-LABEL: define double @Double(double %0){{.*}} {
// CHECK-NEXT: _llgo_0:
// CHECK-NEXT: %1 = fmul double 2.000000e+00, %0
// CHECK-NEXT: ret double %1
// CHECK-NEXT: %1 = alloca %"{{.*}}LocalContext", align 8
// CHECK-NEXT: call void @llvm.memset.p0.i64(ptr %1, i8 0, i64 8, i1 false)
// CHECK-NEXT: %2 = call i64 @"{{.*}}EnterLocalContext"(ptr %1)
// CHECK-NEXT: %3 = fmul double 2.000000e+00, %0
// CHECK-NEXT: call void @"{{.*}}LeaveLocalContext"(ptr %1, i64 %2)
// CHECK-NEXT: ret double %3
// CHECK-NEXT: }
func Double(x float64) float64 {
return 2 * x
}

// CHECK-LABEL: define i64 @add(i64 %0, i64 %1){{.*}} {
// CHECK-NEXT: _llgo_0:
// CHECK-NEXT: %2 = call i64 @"{{.*}}.add"(i64 %0, i64 %1)
// CHECK-NEXT: ret i64 %2
// CHECK-NEXT: %2 = alloca %"{{.*}}LocalContext", align 8
// CHECK-NEXT: call void @llvm.memset.p0.i64(ptr %2, i8 0, i64 8, i1 false)
// CHECK-NEXT: %3 = call i64 @"{{.*}}EnterLocalContext"(ptr %2)
// CHECK-NEXT: %4 = call i64 @"{{.*}}.add"(i64 %0, i64 %1)
// CHECK-NEXT: call void @"{{.*}}LeaveLocalContext"(ptr %2, i64 %3)
// CHECK-NEXT: ret i64 %4
// CHECK-NEXT: }
func Xadd(a, b int) int {
return add(a, b)
Expand Down
4 changes: 2 additions & 2 deletions cl/_testdata/vargs/in.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ package main

import "github.com/goplus/lib/c"

// CHECK: @0 = private unnamed_addr constant [3 x i8] c"int", align 1
// CHECK: @1 = private unnamed_addr constant [4 x i8] c"%d\0A\00", align 1

func main() {
Expand Down Expand Up @@ -88,7 +87,8 @@ func test(a ...any) {
// CHECK-NEXT: br label %_llgo_1
// CHECK-EMPTY:
// CHECK-NEXT: _llgo_5: ; preds = %_llgo_2
// 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: %17 = call %"{{.*}}/runtime/internal/runtime.eface" @"{{.*}}/runtime/internal/runtime.TypeAssertError"(ptr %12, ptr @_llgo_int, ptr null)
// CHECK-NEXT: call void @"{{.*}}/runtime/internal/runtime.Panic"(%"{{.*}}/runtime/internal/runtime.eface" %17)
// CHECK-NEXT: unreachable
// CHECK-NEXT: }

Expand Down
3 changes: 2 additions & 1 deletion cl/_testgo/abimethod/in.go
Original file line number Diff line number Diff line change
Expand Up @@ -736,7 +736,8 @@ type I2 interface {
// CHECK-NEXT: br i1 %29, label %_llgo_1, label %_llgo_2
// CHECK-EMPTY:
// CHECK-NEXT: _llgo_4: ; preds = %_llgo_0
// CHECK-NEXT: call void @"{{.*}}/runtime/internal/runtime.PanicTypeAssert"(ptr %23, %"{{.*}}/runtime/internal/runtime.String" { ptr @5, i64 3 }, %"{{.*}}/runtime/internal/runtime.String" zeroinitializer)
// CHECK-NEXT: %30 = call %"{{.*}}/runtime/internal/runtime.eface" @"{{.*}}/runtime/internal/runtime.TypeAssertError"(ptr %23, ptr @_llgo_int, ptr null)
// CHECK-NEXT: call void @"{{.*}}/runtime/internal/runtime.Panic"(%"{{.*}}/runtime/internal/runtime.eface" %30)
// CHECK-NEXT: unreachable
// CHECK-NEXT: }

Expand Down
19 changes: 11 additions & 8 deletions cl/_testgo/cgodefer/cgodefer.go
Original file line number Diff line number Diff line change
Expand Up @@ -90,17 +90,20 @@ import "C"
// CHECK-NEXT: store ptr %32, ptr %18, align 8
// CHECK-NEXT: %33 = extractvalue { ptr, i64, { ptr, ptr } } %31, 2
// 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: %34 = extractvalue { ptr, ptr } %33, 0
// CHECK-NEXT: %35 = call ptr @"{{.*}}/runtime/internal/runtime.StartRecoverFrame"(ptr %34)
// CHECK-NEXT: %36 = extractvalue { ptr, ptr } %33, 1
// CHECK-NEXT: %37 = extractvalue { ptr, ptr } %33, 0
// CHECK-NEXT: call void %37(ptr %36)
// CHECK-NEXT: call void @"{{.*}}/runtime/internal/runtime.EndRecoverFrame"(ptr %35)
// CHECK-NEXT: br label %_llgo_8
// CHECK-EMPTY:
// CHECK-NEXT: _llgo_8: ; preds = %_llgo_7, %_llgo_2
// CHECK-NEXT: %36 = load %"{{.*}}/runtime/internal/runtime.Defer", ptr %10, align 8
// CHECK-NEXT: %37 = extractvalue %"{{.*}}/runtime/internal/runtime.Defer" %36, 2
// CHECK-NEXT: call void @"{{.*}}/runtime/internal/runtime.SetThreadDefer"(ptr %37)
// CHECK-NEXT: %38 = load ptr, ptr %17, align 8
// CHECK-NEXT: indirectbr ptr %38, [label %_llgo_3, label %_llgo_6]
// CHECK-NEXT: %38 = load %"{{.*}}/runtime/internal/runtime.Defer", ptr %10, align 8
// CHECK-NEXT: %39 = extractvalue %"{{.*}}/runtime/internal/runtime.Defer" %38, 2
// CHECK-NEXT: call void @"{{.*}}/runtime/internal/runtime.SetThreadDefer"(ptr %39)
// CHECK-NEXT: %40 = load ptr, ptr %17, align 8
// CHECK-NEXT: indirectbr ptr %40, [label %_llgo_3, label %_llgo_6]
// CHECK-NEXT: }
func main() {
// CHECK-LABEL: define { ptr, ptr } @"{{.*}}/cl/_testgo/cgodefer.main$1"(ptr %0){{.*}} {
Expand Down
5 changes: 2 additions & 3 deletions cl/_testgo/closureall/in.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,6 @@ import "github.com/goplus/lib/c"

// CHECK: @0 = private unnamed_addr constant [46 x i8] c"{{.*}}/cl/_testgo/closureall.S", align 1
// CHECK: @1 = private unnamed_addr constant [3 x i8] c"Inc", align 1
// CHECK: @7 = private unnamed_addr constant [3 x i8] c"Add", align 1
// CHECK: @9 = private unnamed_addr constant [23 x i8] c"interface{Add(int) int}", align 1

//go:linkname cSqrt C.sqrt
func cSqrt(x c.Double) c.Double
Expand Down Expand Up @@ -173,7 +171,8 @@ func makeWithFree(base int) Fn {
// CHECK-NEXT: ret void
// CHECK-EMPTY:
// CHECK-NEXT: _llgo_2: ; preds = %_llgo_0
// CHECK-NEXT: call void @"{{.*}}/runtime/internal/runtime.PanicTypeAssert"(ptr %21, %"{{.*}}/runtime/internal/runtime.String" { ptr @9, i64 23 }, %"{{.*}}/runtime/internal/runtime.String" { ptr @7, i64 3 })
// CHECK-NEXT: %32 = call %"{{.*}}/runtime/internal/runtime.eface" @"{{.*}}/runtime/internal/runtime.TypeAssertError"(ptr %21, ptr @"_llgo_iface$VdBKYV8-gcMjZtZfcf-u2oKoj9Lu3VXwuG8TGCW2S4A", ptr null)
// CHECK-NEXT: call void @"{{.*}}/runtime/internal/runtime.Panic"(%"{{.*}}/runtime/internal/runtime.eface" %32)
// CHECK-NEXT: unreachable
// CHECK-NEXT: }

Expand Down
16 changes: 8 additions & 8 deletions cl/_testgo/genericembediface/in.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,9 @@ import (

// CHECK: {{^}}@2 = private unnamed_addr constant [20 x i8] c"ServerReflectionInfo", align 1{{$}}
// CHECK: {{^}}@5 = private unnamed_addr constant [7 x i8] c"Context", align 1{{$}}
// CHECK: {{^}}@11 = private unnamed_addr constant [68 x i8] c"{{.*}}/cl/_testgo/genericembediface.ReflectionServer", align 1{{$}}
// CHECK: {{^}}@19 = private unnamed_addr constant [4 x i8] c"pass", align 1{{$}}
// CHECK: {{^}}@20 = private unnamed_addr constant [58 x i8] c"{{.*}}/cl/_testgo/genericembediface.server", align 1{{$}}
// CHECK: {{^}}@21 = private unnamed_addr constant [58 x i8] c"{{.*}}/cl/_testgo/genericembediface.stream", align 1{{$}}
// CHECK: {{^}}@18 = private unnamed_addr constant [4 x i8] c"pass", align 1{{$}}
// CHECK: {{^}}@19 = private unnamed_addr constant [58 x i8] c"{{.*}}/cl/_testgo/genericembediface.server", align 1{{$}}
// CHECK: {{^}}@20 = private unnamed_addr constant [58 x i8] c"{{.*}}/cl/_testgo/genericembediface.stream", align 1{{$}}

type Request struct{}
type Response struct{}
Expand Down Expand Up @@ -48,7 +47,8 @@ type ReflectionServer interface {
// CHECK-NEXT: ret %"{{.*}}/runtime/internal/runtime.iface" %21
// CHECK-EMPTY:
// CHECK-NEXT: _llgo_2: ; preds = %_llgo_0
// CHECK-NEXT: call void @"{{.*}}/runtime/internal/runtime.PanicTypeAssert"(ptr %2, %"{{.*}}/runtime/internal/runtime.String" { ptr @11, i64 68 }, %"{{.*}}/runtime/internal/runtime.String" { ptr @2, i64 20 })
// CHECK-NEXT: %22 = call %"{{.*}}/runtime/internal/runtime.eface" @"{{.*}}/runtime/internal/runtime.TypeAssertError"(ptr %2, ptr @"_llgo_{{.*}}/cl/_testgo/genericembediface.ReflectionServer", ptr null)
// CHECK-NEXT: call void @"{{.*}}/runtime/internal/runtime.Panic"(%"{{.*}}/runtime/internal/runtime.eface" %22)
// CHECK-NEXT: unreachable
// CHECK-NEXT: }

Expand Down Expand Up @@ -93,7 +93,7 @@ func (stream) Context() string {
// CHECK-NEXT: %4 = insertvalue %"{{.*}}/runtime/internal/runtime.iface" undef, ptr %3, 0
// CHECK-NEXT: %5 = insertvalue %"{{.*}}/runtime/internal/runtime.iface" %4, ptr %2, 1
// CHECK-NEXT: %6 = call %"{{.*}}/runtime/internal/runtime.iface" @"{{.*}}/cl/_testgo/genericembediface.handler"(%"{{.*}}/runtime/internal/runtime.eface" %1, %"{{.*}}/runtime/internal/runtime.iface" %5)
// CHECK-NEXT: call void @"{{.*}}/runtime/internal/runtime.PrintString"(%"{{.*}}/runtime/internal/runtime.String" { ptr @19, i64 4 })
// CHECK-NEXT: call void @"{{.*}}/runtime/internal/runtime.PrintString"(%"{{.*}}/runtime/internal/runtime.String" { ptr @18, i64 4 })
// CHECK-NEXT: call void @"{{.*}}/runtime/internal/runtime.PrintByte"(i8 10)
// CHECK-NEXT: ret void
// CHECK-NEXT: }
Expand All @@ -111,7 +111,7 @@ func main() {
// CHECK-LABEL: define %"{{.*}}/runtime/internal/runtime.iface" @"{{.*}}/cl/_testgo/genericembediface.(*server).ServerReflectionInfo"(ptr %0, %"{{.*}}/runtime/internal/runtime.iface" %1){{.*}} {
// CHECK-NEXT: _llgo_0:
// CHECK-NEXT: %2 = icmp eq ptr %0, null
// CHECK-NEXT: call void @"{{.*}}/runtime/internal/runtime.PanicWrapNilPointer"(i1 %2, %"{{.*}}/runtime/internal/runtime.String" { ptr @20, i64 58 }, %"{{.*}}/runtime/internal/runtime.String" { ptr @2, i64 20 })
// CHECK-NEXT: call void @"{{.*}}/runtime/internal/runtime.PanicWrapNilPointer"(i1 %2, %"{{.*}}/runtime/internal/runtime.String" { ptr @19, i64 58 }, %"{{.*}}/runtime/internal/runtime.String" { ptr @2, i64 20 })
// CHECK-NEXT: %3 = icmp eq ptr %0, null
// CHECK-NEXT: call void @"{{.*}}/runtime/internal/runtime.AssertNilDeref"(i1 %3)
// CHECK-NEXT: %4 = call %"{{.*}}/runtime/internal/runtime.iface" @"{{.*}}/cl/_testgo/genericembediface.server.ServerReflectionInfo"(%"{{.*}}/cl/_testgo/genericembediface.server" zeroinitializer, %"{{.*}}/runtime/internal/runtime.iface" %1)
Expand All @@ -126,7 +126,7 @@ func main() {
// CHECK-LABEL: define %"{{.*}}/runtime/internal/runtime.String" @"{{.*}}/cl/_testgo/genericembediface.(*stream).Context"(ptr %0){{.*}} {
// CHECK-NEXT: _llgo_0:
// CHECK-NEXT: %1 = icmp eq ptr %0, null
// CHECK-NEXT: call void @"{{.*}}/runtime/internal/runtime.PanicWrapNilPointer"(i1 %1, %"{{.*}}/runtime/internal/runtime.String" { ptr @21, i64 58 }, %"{{.*}}/runtime/internal/runtime.String" { ptr @5, i64 7 })
// CHECK-NEXT: call void @"{{.*}}/runtime/internal/runtime.PanicWrapNilPointer"(i1 %1, %"{{.*}}/runtime/internal/runtime.String" { ptr @20, i64 58 }, %"{{.*}}/runtime/internal/runtime.String" { ptr @5, i64 7 })
// CHECK-NEXT: %2 = icmp eq ptr %0, null
// CHECK-NEXT: call void @"{{.*}}/runtime/internal/runtime.AssertNilDeref"(i1 %2)
// CHECK-NEXT: %3 = call %"{{.*}}/runtime/internal/runtime.String" @"{{.*}}/cl/_testgo/genericembediface.stream.Context"(%"{{.*}}/cl/_testgo/genericembediface.stream" zeroinitializer)
Expand Down
26 changes: 17 additions & 9 deletions cl/_testgo/goroutine/in.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,20 +40,28 @@ func main() {

// CHECK-LABEL: define ptr @"{{.*}}goroutine._llgo_routine$1"(ptr %0){{.*}} {
// CHECK-NEXT: _llgo_0:
// CHECK-NEXT: %1 = load { %"{{.*}}String" }, ptr %0, align 8
// CHECK-NEXT: %2 = extractvalue { %"{{.*}}String" } %1, 0
// CHECK-NEXT: %1 = alloca %"{{.*}}LocalContext", align 8
// CHECK-NEXT: call void @llvm.memset.p0.i64(ptr %1, i8 0, i64 8, i1 false)
// CHECK-NEXT: %2 = call i64 @"{{.*}}EnterLocalContext"(ptr %1)
// CHECK-NEXT: %3 = load { %"{{.*}}String" }, ptr %0, align 8
// CHECK-NEXT: %4 = extractvalue { %"{{.*}}String" } %3, 0
// CHECK-NEXT: call void @"{{.*}}FreeRoot"(ptr %0)
// CHECK-NEXT: call void @"{{.*}}PrintString"(%"{{.*}}String" %2)
// CHECK-NEXT: call void @"{{.*}}PrintString"(%"{{.*}}String" %4)
// CHECK-NEXT: call void @"{{.*}}PrintByte"(i8 10)
// CHECK-NEXT: call void @"{{.*}}LeaveLocalContext"(ptr %1, i64 %2)
// CHECK-NEXT: ret ptr null

// CHECK-LABEL: define ptr @"{{.*}}goroutine._llgo_routine$2"(ptr %0){{.*}} {
// CHECK-NEXT: _llgo_0:
// CHECK-NEXT: %1 = load { { ptr, ptr }, %"{{.*}}String" }, ptr %0, align 8
// CHECK-NEXT: %2 = extractvalue { { ptr, ptr }, %"{{.*}}String" } %1, 0
// CHECK-NEXT: %3 = extractvalue { { ptr, ptr }, %"{{.*}}String" } %1, 1
// CHECK-NEXT: %1 = alloca %"{{.*}}LocalContext", align 8
// CHECK-NEXT: call void @llvm.memset.p0.i64(ptr %1, i8 0, i64 8, i1 false)
// CHECK-NEXT: %2 = call i64 @"{{.*}}EnterLocalContext"(ptr %1)
// CHECK-NEXT: %3 = load { { ptr, ptr }, %"{{.*}}String" }, ptr %0, align 8
// CHECK-NEXT: %4 = extractvalue { { ptr, ptr }, %"{{.*}}String" } %3, 0
// CHECK-NEXT: %5 = extractvalue { { ptr, ptr }, %"{{.*}}String" } %3, 1
// 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: %6 = extractvalue { ptr, ptr } %4, 1
// CHECK-NEXT: %7 = extractvalue { ptr, ptr } %4, 0
// CHECK-NEXT: call void %7(ptr %6, %"{{.*}}String" %5)
// CHECK-NEXT: call void @"{{.*}}LeaveLocalContext"(ptr %1, i64 %2)
// CHECK-NEXT: ret ptr null
Loading
Loading