Skip to content
Draft
3 changes: 3 additions & 0 deletions chore/litgen/litgen.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,11 @@ import (
"github.com/goplus/llgo/xtool/env/llvm"
)

var escapeChecks bool

func main() {
llvm.SetupPath()
flag.BoolVar(&escapeChecks, "escape", false, "generate checks after escape analysis")
flag.Usage = func() {
fmt.Fprintf(flag.CommandLine.Output(), "Usage: %s <file-or-dir> [<file-or-dir>...]\n", filepath.Base(os.Args[0]))
flag.PrintDefaults()
Expand Down
3 changes: 3 additions & 0 deletions chore/litgen/rewrite.go
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,9 @@ func genIR(target string) (ret string, err error) {
}
}
}()
if escapeChecks {
return llgen.GenFromWithEscape(target), nil
}
return llgen.GenFrom(target), nil
}

Expand Down
23 changes: 23 additions & 0 deletions cl/_testdata/print/in.go
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,29 @@ type stringStruct struct {
// CHECK-NEXT: ret %"{{.*}}/runtime/internal/runtime.Slice" %13
// CHECK-NEXT: }

// ESCAPE-LABEL: define %"{{.*}}/runtime/internal/runtime.Slice" @main.bytes(%"{{.*}}/runtime/internal/runtime.String" %0){{.*}} {
// ESCAPE-NEXT: _llgo_0:
// ESCAPE-NEXT: %1 = call ptr @"{{.*}}/runtime/internal/runtime.AllocZ"(i64 16)
// ESCAPE-NEXT: store %"{{.*}}/runtime/internal/runtime.String" %0, ptr %1, align 8
// ESCAPE-NEXT: %.stack = alloca i8, i64 24, align 8
// ESCAPE-NEXT: call void @llvm.memset.p0.i64(ptr %.stack, i8 0, i64 24, i1 false)
// ESCAPE-NEXT: %2 = call ptr @main.stringStructOf(ptr %1)
// ESCAPE-NEXT: %3 = getelementptr inbounds %main.stringStruct, ptr %2, i32 0, i32 0
// ESCAPE-NEXT: %4 = load ptr, ptr %3, align 8
// ESCAPE-NEXT: %5 = getelementptr inbounds %main.slice, ptr %.stack, i32 0, i32 0
// ESCAPE-NEXT: store ptr %4, ptr %5, align 8
// ESCAPE-NEXT: %6 = getelementptr inbounds %main.stringStruct, ptr %2, i32 0, i32 1
// ESCAPE-NEXT: %7 = load i64, ptr %6, align 8
// ESCAPE-NEXT: %8 = getelementptr inbounds %main.slice, ptr %.stack, i32 0, i32 1
// ESCAPE-NEXT: store i64 %7, ptr %8, align 8
// ESCAPE-NEXT: %9 = getelementptr inbounds %main.stringStruct, ptr %2, i32 0, i32 1
// ESCAPE-NEXT: %10 = load i64, ptr %9, align 8
// ESCAPE-NEXT: %11 = getelementptr inbounds %main.slice, ptr %.stack, i32 0, i32 2
// ESCAPE-NEXT: store i64 %10, ptr %11, align 8
// ESCAPE-NEXT: %12 = load %"{{.*}}/runtime/internal/runtime.Slice", ptr %.stack, align 8
// ESCAPE-NEXT: ret %"{{.*}}/runtime/internal/runtime.Slice" %12
// ESCAPE-NEXT: }

func bytes(s string) (ret []byte) {
rp := (*slice)(unsafe.Pointer(&ret))
sp := stringStructOf(&s)
Expand Down
21 changes: 21 additions & 0 deletions cl/_testgo/alias/in.go
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,27 @@ func (p *Point) Scale(factor float64) {
p.y *= factor
}

// ESCAPE-LABEL: define void @main.main(){{.*}} {
// ESCAPE-NEXT: _llgo_0:
// ESCAPE-NEXT: %.stack = alloca i8, i64 16, align 8
// ESCAPE-NEXT: call void @llvm.memset.p0.i64(ptr %.stack, i8 0, i64 16, i1 false)
// ESCAPE-NEXT: %0 = getelementptr inbounds %main.Point, ptr %.stack, i32 0, i32 0
// ESCAPE-NEXT: %1 = getelementptr inbounds %main.Point, ptr %.stack, i32 0, i32 1
// ESCAPE-NEXT: store double 1.000000e+00, ptr %0, align 8
// ESCAPE-NEXT: store double 2.000000e+00, ptr %1, align 8
// ESCAPE-NEXT: call void @"main.(*Point).Scale"(ptr %.stack, double 2.000000e+00)
// ESCAPE-NEXT: call void @"main.(*Point).Move"(ptr %.stack, double 3.000000e+00, double 4.000000e+00)
// ESCAPE-NEXT: %2 = getelementptr inbounds %main.Point, ptr %.stack, i32 0, i32 0
// ESCAPE-NEXT: %3 = load double, ptr %2, align 8
// ESCAPE-NEXT: %4 = getelementptr inbounds %main.Point, ptr %.stack, i32 0, i32 1
// ESCAPE-NEXT: %5 = load double, ptr %4, align 8
// ESCAPE-NEXT: call void @"{{.*}}/runtime/internal/runtime.PrintFloat"(double %3)
// ESCAPE-NEXT: call void @"{{.*}}/runtime/internal/runtime.PrintByte"(i8 32)
// ESCAPE-NEXT: call void @"{{.*}}/runtime/internal/runtime.PrintFloat"(double %5)
// ESCAPE-NEXT: call void @"{{.*}}/runtime/internal/runtime.PrintByte"(i8 10)
// ESCAPE-NEXT: ret void
// ESCAPE-NEXT: }

// CHECK-LABEL: define void @main.main(){{.*}} {
func main() {
// CHECK: call ptr @"{{.*}}AllocZ"(i64 16)
Expand Down
60 changes: 60 additions & 0 deletions cl/_testgo/cgobasic/cgobasic.go
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,66 @@ import (
// CHECK-NEXT: ret double %4
// CHECK-NEXT: }

// ESCAPE-LABEL: define double @main._Cfunc_cos(double %0){{.*}} {
// ESCAPE-NEXT: _llgo_0:
// ESCAPE-NEXT: %.stack = alloca i8, i64 8, align 1
// ESCAPE-NEXT: call void @llvm.memset.p0.i64(ptr %.stack, i8 0, i64 8, i1 false)
// ESCAPE-NEXT: %1 = load ptr, ptr @main._cgo_{{.*}}_Cfunc_cos, align 8
// ESCAPE-NEXT: %2 = load ptr, ptr %1, align 8
// ESCAPE-NEXT: %3 = call double %2(double %0)
// ESCAPE-NEXT: ret double %3
// ESCAPE-NEXT: }

// ESCAPE-LABEL: define [0 x i8] @main._Cfunc_free(ptr %0){{.*}} {
// ESCAPE-NEXT: _llgo_0:
// ESCAPE-NEXT: %.stack = alloca i8, i64 8, align 1
// ESCAPE-NEXT: call void @llvm.memset.p0.i64(ptr %.stack, i8 0, i64 8, i1 false)
// ESCAPE-NEXT: %1 = load ptr, ptr @main._cgo_{{.*}}_Cfunc_free, align 8
// ESCAPE-NEXT: %2 = load ptr, ptr %1, align 8
// ESCAPE-NEXT: %3 = call [0 x i8] %2(ptr %0)
// ESCAPE-NEXT: ret [0 x i8] %3
// ESCAPE-NEXT: }

// ESCAPE-LABEL: define double @main._Cfunc_log(double %0){{.*}} {
// ESCAPE-NEXT: _llgo_0:
// ESCAPE-NEXT: %.stack = alloca i8, i64 8, align 1
// ESCAPE-NEXT: call void @llvm.memset.p0.i64(ptr %.stack, i8 0, i64 8, i1 false)
// ESCAPE-NEXT: %1 = load ptr, ptr @main._cgo_{{.*}}_Cfunc_log, align 8
// ESCAPE-NEXT: %2 = load ptr, ptr %1, align 8
// ESCAPE-NEXT: %3 = call double %2(double %0)
// ESCAPE-NEXT: ret double %3
// ESCAPE-NEXT: }

// ESCAPE-LABEL: define i32 @main._Cfunc_puts(ptr %0){{.*}} {
// ESCAPE-NEXT: _llgo_0:
// ESCAPE-NEXT: %.stack = alloca i8, i64 8, align 1
// ESCAPE-NEXT: call void @llvm.memset.p0.i64(ptr %.stack, i8 0, i64 8, i1 false)
// ESCAPE-NEXT: %1 = load ptr, ptr @main._cgo_{{.*}}_Cfunc_puts, align 8
// ESCAPE-NEXT: %2 = load ptr, ptr %1, align 8
// ESCAPE-NEXT: %3 = call i32 %2(ptr %0)
// ESCAPE-NEXT: ret i32 %3
// ESCAPE-NEXT: }

// ESCAPE-LABEL: define double @main._Cfunc_sin(double %0){{.*}} {
// ESCAPE-NEXT: _llgo_0:
// ESCAPE-NEXT: %.stack = alloca i8, i64 8, align 1
// ESCAPE-NEXT: call void @llvm.memset.p0.i64(ptr %.stack, i8 0, i64 8, i1 false)
// ESCAPE-NEXT: %1 = load ptr, ptr @main._cgo_{{.*}}_Cfunc_sin, align 8
// ESCAPE-NEXT: %2 = load ptr, ptr %1, align 8
// ESCAPE-NEXT: %3 = call double %2(double %0)
// ESCAPE-NEXT: ret double %3
// ESCAPE-NEXT: }

// ESCAPE-LABEL: define double @main._Cfunc_sqrt(double %0){{.*}} {
// ESCAPE-NEXT: _llgo_0:
// ESCAPE-NEXT: %.stack = alloca i8, i64 8, align 1
// ESCAPE-NEXT: call void @llvm.memset.p0.i64(ptr %.stack, i8 0, i64 8, i1 false)
// ESCAPE-NEXT: %1 = load ptr, ptr @main._cgo_{{.*}}_Cfunc_sqrt, align 8
// ESCAPE-NEXT: %2 = load ptr, ptr %1, align 8
// ESCAPE-NEXT: %3 = call double %2(double %0)
// ESCAPE-NEXT: ret double %3
// ESCAPE-NEXT: }

// CHECK-LABEL: define void @main.init(){{.*}} {
// CHECK-NEXT: _llgo_0:
// CHECK-NEXT: %0 = load i1, ptr @"main.init$guard", align 1
Expand Down
10 changes: 10 additions & 0 deletions cl/_testgo/cgocfiles/cgocfiles.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,16 @@ import "fmt"
// CHECK-NEXT: ret i32 %8
// CHECK-NEXT: }

// ESCAPE-LABEL: define i32 @main._Cfunc_test_structs(ptr %0, ptr %1, ptr %2, ptr %3, ptr %4){{.*}} {
// ESCAPE-NEXT: _llgo_0:
// ESCAPE-NEXT: %.stack = alloca i8, i64 8, align 1
// ESCAPE-NEXT: call void @llvm.memset.p0.i64(ptr %.stack, i8 0, i64 8, i1 false)
// ESCAPE-NEXT: %5 = load ptr, ptr @main._cgo_{{.*}}_Cfunc_test_structs, align 8
// ESCAPE-NEXT: %6 = load ptr, ptr %5, align 8
// ESCAPE-NEXT: %7 = call i32 %6(ptr %0, ptr %1, ptr %2, ptr %3, ptr %4)
// ESCAPE-NEXT: ret i32 %7
// ESCAPE-NEXT: }

// CHECK-LABEL: define void @main.main(){{.*}} {
// CHECK-NEXT: _llgo_0:
// CHECK-NEXT: %0 = call ptr @"{{.*}}/runtime/internal/runtime.AllocZ"(i64 4)
Expand Down
10 changes: 10 additions & 0 deletions cl/_testgo/cgodefer/cgodefer.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,16 @@ import "C"
// CHECK-NEXT: ret [0 x i8] %4
// CHECK-NEXT: }

// ESCAPE-LABEL: define [0 x i8] @main._Cfunc_free(ptr %0){{.*}} {
// ESCAPE-NEXT: _llgo_0:
// ESCAPE-NEXT: %.stack = alloca i8, i64 8, align 1
// ESCAPE-NEXT: call void @llvm.memset.p0.i64(ptr %.stack, i8 0, i64 8, i1 false)
// ESCAPE-NEXT: %1 = load ptr, ptr @main._cgo_{{.*}}_Cfunc_free, align 8
// ESCAPE-NEXT: %2 = load ptr, ptr %1, align 8
// ESCAPE-NEXT: %3 = call [0 x i8] %2(ptr %0)
// ESCAPE-NEXT: ret [0 x i8] %3
// ESCAPE-NEXT: }

// CHECK-LABEL: define void @main.main(){{.*}} {
// CHECK-NEXT: _llgo_0:
// CHECK-NEXT: %0 = call ptr @"{{.*}}/runtime/internal/runtime.AllocZ"(i64 8)
Expand Down
56 changes: 56 additions & 0 deletions cl/_testgo/cgomacro/cgomacro.go
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,62 @@ import (
// CHECK-NEXT: ret ptr %2
// CHECK-NEXT: }

// ESCAPE-LABEL: define i32 @main._Cfunc_PyObject_Print(ptr %0, ptr %1, i32 %2){{.*}} {
// ESCAPE-NEXT: _llgo_0:
// ESCAPE-NEXT: %.stack = alloca i8, i64 8, align 1
// ESCAPE-NEXT: call void @llvm.memset.p0.i64(ptr %.stack, i8 0, i64 8, i1 false)
// ESCAPE-NEXT: %3 = load ptr, ptr @main._cgo_{{.*}}_Cfunc_PyObject_Print, align 8
// ESCAPE-NEXT: %4 = load ptr, ptr %3, align 8
// ESCAPE-NEXT: %5 = call i32 %4(ptr %0, ptr %1, i32 %2)
// ESCAPE-NEXT: ret i32 %5
// ESCAPE-NEXT: }

// ESCAPE-LABEL: define i32 @main._Cfunc_fputs(ptr %0, ptr %1){{.*}} {
// ESCAPE-NEXT: _llgo_0:
// ESCAPE-NEXT: %.stack = alloca i8, i64 8, align 1
// ESCAPE-NEXT: call void @llvm.memset.p0.i64(ptr %.stack, i8 0, i64 8, i1 false)
// ESCAPE-NEXT: %2 = load ptr, ptr @main._cgo_{{.*}}_Cfunc_fputs, align 8
// ESCAPE-NEXT: %3 = load ptr, ptr %2, align 8
// ESCAPE-NEXT: %4 = call i32 %3(ptr %0, ptr %1)
// ESCAPE-NEXT: ret i32 %4
// ESCAPE-NEXT: }

// ESCAPE-LABEL: define ptr @main._Cmacro_Py_False(){{.*}} {
// ESCAPE-NEXT: _llgo_0:
// ESCAPE-NEXT: %.stack = alloca i8, i64 8, align 1
// ESCAPE-NEXT: call void @llvm.memset.p0.i64(ptr %.stack, i8 0, i64 8, i1 false)
// ESCAPE-NEXT: %0 = load ptr, ptr @main._cgo_{{.*}}_Cmacro_Py_False, align 8
// ESCAPE-NEXT: %1 = load ptr, ptr %0, align 8
// ESCAPE-NEXT: ret ptr %1
// ESCAPE-NEXT: }

// ESCAPE-LABEL: define ptr @main._Cmacro_Py_None(){{.*}} {
// ESCAPE-NEXT: _llgo_0:
// ESCAPE-NEXT: %.stack = alloca i8, i64 8, align 1
// ESCAPE-NEXT: call void @llvm.memset.p0.i64(ptr %.stack, i8 0, i64 8, i1 false)
// ESCAPE-NEXT: %0 = load ptr, ptr @main._cgo_{{.*}}_Cmacro_Py_None, align 8
// ESCAPE-NEXT: %1 = load ptr, ptr %0, align 8
// ESCAPE-NEXT: ret ptr %1
// ESCAPE-NEXT: }

// ESCAPE-LABEL: define ptr @main._Cmacro_Py_True(){{.*}} {
// ESCAPE-NEXT: _llgo_0:
// ESCAPE-NEXT: %.stack = alloca i8, i64 8, align 1
// ESCAPE-NEXT: call void @llvm.memset.p0.i64(ptr %.stack, i8 0, i64 8, i1 false)
// ESCAPE-NEXT: %0 = load ptr, ptr @main._cgo_{{.*}}_Cmacro_Py_True, align 8
// ESCAPE-NEXT: %1 = load ptr, ptr %0, align 8
// ESCAPE-NEXT: ret ptr %1
// ESCAPE-NEXT: }

// ESCAPE-LABEL: define ptr @main._Cmacro_stdout(){{.*}} {
// ESCAPE-NEXT: _llgo_0:
// ESCAPE-NEXT: %.stack = alloca i8, i64 8, align 1
// ESCAPE-NEXT: call void @llvm.memset.p0.i64(ptr %.stack, i8 0, i64 8, i1 false)
// ESCAPE-NEXT: %0 = load ptr, ptr @main._cgo_{{.*}}_Cmacro_stdout, align 8
// ESCAPE-NEXT: %1 = load ptr, ptr %0, align 8
// ESCAPE-NEXT: ret ptr %1
// ESCAPE-NEXT: }

// CHECK-LABEL: define void @main.init(){{.*}} {
// CHECK-NEXT: _llgo_0:
// CHECK-NEXT: %0 = load i1, ptr @"main.init$guard", align 1
Expand Down
10 changes: 10 additions & 0 deletions cl/_testgo/cgopython/cgopython.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,16 @@ import "C"
// CHECK-NEXT: ret i32 %4
// CHECK-NEXT: }

// ESCAPE-LABEL: define i32 @main._Cfunc_PyRun_SimpleString(ptr %0){{.*}} {
// ESCAPE-NEXT: _llgo_0:
// ESCAPE-NEXT: %.stack = alloca i8, i64 8, align 1
// ESCAPE-NEXT: call void @llvm.memset.p0.i64(ptr %.stack, i8 0, i64 8, i1 false)
// ESCAPE-NEXT: %1 = load ptr, ptr @main._cgo_{{.*}}_Cfunc_PyRun_SimpleString, align 8
// ESCAPE-NEXT: %2 = load ptr, ptr %1, align 8
// ESCAPE-NEXT: %3 = call i32 %2(ptr %0)
// ESCAPE-NEXT: ret i32 %3
// ESCAPE-NEXT: }

// CHECK-LABEL: define [0 x i8] @main._Cfunc_Py_Finalize(){{.*}} {
// CHECK-NEXT: _llgo_0:
// CHECK-NEXT: %0 = load ptr, ptr @main._cgo_{{.*}}_Cfunc_Py_Finalize, align 8
Expand Down
10 changes: 10 additions & 0 deletions cl/_testgo/cursor/in.go
Original file line number Diff line number Diff line change
Expand Up @@ -805,6 +805,16 @@ const (
// CHECK-NEXT: ret void
// CHECK-NEXT: }

// ESCAPE-LABEL: define void @main.main(){{.*}} {
// ESCAPE-NEXT: _llgo_0:
// ESCAPE-NEXT: %.stack = alloca i8, i64 16, align 8
// ESCAPE-NEXT: call void @llvm.memset.p0.i64(ptr %.stack, i8 0, i64 16, i1 false)
// ESCAPE-NEXT: %0 = getelementptr inbounds %main.Cursor, ptr %.stack, i32 0, i32 0
// ESCAPE-NEXT: %1 = call ptr @"{{.*}}/runtime/internal/runtime.AllocZ"(i64 24)
// ESCAPE-NEXT: store ptr %1, ptr %0, align 8
// ESCAPE-NEXT: ret void
// ESCAPE-NEXT: }

// CHECK-LABEL: define i64 @main.maskOf(%"{{.*}}/runtime/internal/runtime.Slice" %0){{.*}} {
// CHECK-NEXT: _llgo_0:
// CHECK-NEXT: %1 = extractvalue %"{{.*}}/runtime/internal/runtime.Slice" %0, 1
Expand Down
12 changes: 12 additions & 0 deletions cl/_testgo/returnorder/in.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,18 @@ func main() {
// CHECK-NEXT: %4 = insertvalue { %main.state, i64 } undef, %main.state %3, 0
// CHECK-NEXT: %5 = insertvalue { %main.state, i64 } %4, i64 %2, 1
// CHECK-NEXT: ret { %main.state, i64 } %5
// ESCAPE-LABEL: define { %main.state, i64 } @main.returnStateAndMut(){{.*}} {
// ESCAPE-NEXT: _llgo_0:
// ESCAPE-NEXT: %.stack = alloca i8, i64 8, align 8
// ESCAPE-NEXT: call void @llvm.memset.p0.i64(ptr %.stack, i8 0, i64 8, i1 false)
// ESCAPE-NEXT: %0 = getelementptr inbounds %main.state, ptr %.stack, i32 0, i32 0
// ESCAPE-NEXT: store i64 1, ptr %0, align 8
// ESCAPE-NEXT: %1 = call i64 @"main.(*state).mutate"(ptr %.stack, i64 2)
// ESCAPE-NEXT: %2 = load %main.state, ptr %.stack, align 8
// ESCAPE-NEXT: %3 = insertvalue { %main.state, i64 } undef, %main.state %2, 0
// ESCAPE-NEXT: %4 = insertvalue { %main.state, i64 } %3, i64 %1, 1
// ESCAPE-NEXT: ret { %main.state, i64 } %4
// ESCAPE-NEXT: }
func returnStateAndMut() (state, int) {
x := state{v: 1}
return x, x.mutate(2)
Expand Down
19 changes: 19 additions & 0 deletions cl/_testgo/tprecurfn/in.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,25 @@ type My[T any] struct {
next *My[T]
}

// ESCAPE-LABEL: define void @main.main(){{.*}} {
// ESCAPE-NEXT: _llgo_0:
// ESCAPE-NEXT: %.stack = alloca i8, i64 24, align 8
// ESCAPE-NEXT: call void @llvm.memset.p0.i64(ptr %.stack, i8 0, i64 24, i1 false)
// ESCAPE-NEXT: %0 = getelementptr inbounds %"main.My[int]", ptr %.stack, i32 0, i32 1
// ESCAPE-NEXT: %1 = call ptr @"{{.*}}/runtime/internal/runtime.AllocZ"(i64 24)
// ESCAPE-NEXT: %2 = getelementptr inbounds %"main.My[int]", ptr %1, i32 0, i32 0
// ESCAPE-NEXT: store { ptr, ptr } { ptr @"__llgo_stub.main.main$1", ptr null }, ptr %2, align 8
// ESCAPE-NEXT: store ptr %1, ptr %0, align 8
// ESCAPE-NEXT: %3 = getelementptr inbounds %"main.My[int]", ptr %.stack, i32 0, i32 1
// ESCAPE-NEXT: %4 = load ptr, ptr %3, align 8
// ESCAPE-NEXT: %5 = getelementptr inbounds %"main.My[int]", ptr %4, i32 0, i32 0
// ESCAPE-NEXT: %6 = load { ptr, ptr }, ptr %5, align 8
// ESCAPE-NEXT: %7 = extractvalue { ptr, ptr } %6, 1
// ESCAPE-NEXT: %8 = extractvalue { ptr, ptr } %6, 0
// ESCAPE-NEXT: call void %8(ptr %7, i64 100)
// ESCAPE-NEXT: ret void
// ESCAPE-NEXT: }

// CHECK-LABEL: define void @main.main(){{.*}} {
func main() {
// CHECK: %0 = call ptr @"{{.*}}/runtime/internal/runtime.AllocZ"(i64 24)
Expand Down
Loading
Loading