@@ -35,13 +35,10 @@ func main() {
|
|||||||
dir, _ := filepath.Split(inFile)
|
dir, _ := filepath.Split(inFile)
|
||||||
outFile := dir + "out.ll"
|
outFile := dir + "out.ll"
|
||||||
|
|
||||||
pkgPath := ""
|
|
||||||
if len(os.Args) == 3 {
|
|
||||||
pkgPath = os.Args[2]
|
|
||||||
} else {
|
|
||||||
pkgPath = llgen.PkgPath(dir)
|
|
||||||
}
|
|
||||||
|
|
||||||
llgen.Init()
|
llgen.Init()
|
||||||
llgen.Do(pkgPath, inFile, outFile)
|
if len(os.Args) >= 3 {
|
||||||
|
llgen.Do(os.Args[2], inFile, outFile)
|
||||||
|
} else {
|
||||||
|
llgen.DoFile(inFile, outFile)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
17
cl/_testcgo/strlen/in.go
Normal file
17
cl/_testcgo/strlen/in.go
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import "C"
|
||||||
|
import _ "unsafe"
|
||||||
|
|
||||||
|
//go:linkname printf printf
|
||||||
|
func printf(format *int8, __llgo_va_list ...any)
|
||||||
|
|
||||||
|
//go:linkname strlen strlen
|
||||||
|
func strlen(str *int8) C.int
|
||||||
|
|
||||||
|
var format = [...]int8{'H', 'e', 'l', 'l', 'o', ' ', '%', 'd', '\n', 0}
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
sfmt := &format[0]
|
||||||
|
printf(sfmt, strlen(sfmt))
|
||||||
|
}
|
||||||
41
cl/_testcgo/strlen/out.ll
Normal file
41
cl/_testcgo/strlen/out.ll
Normal file
@@ -0,0 +1,41 @@
|
|||||||
|
; ModuleID = 'main'
|
||||||
|
source_filename = "main"
|
||||||
|
|
||||||
|
@main._Cgo_always_false = global ptr null
|
||||||
|
@main.format = global ptr null
|
||||||
|
@"main.init$guard" = global ptr null
|
||||||
|
|
||||||
|
define void @main.init() {
|
||||||
|
_llgo_0:
|
||||||
|
%0 = load i1, ptr @"main.init$guard", align 1
|
||||||
|
br i1 %0, label %_llgo_2, label %_llgo_1
|
||||||
|
|
||||||
|
_llgo_1: ; preds = %_llgo_0
|
||||||
|
store i1 true, ptr @"main.init$guard", align 1
|
||||||
|
store i8 72, ptr @main.format, align 1
|
||||||
|
store i8 101, ptr getelementptr inbounds (i8, ptr @main.format, i64 1), align 1
|
||||||
|
store i8 108, ptr getelementptr inbounds (i8, ptr @main.format, i64 2), align 1
|
||||||
|
store i8 108, ptr getelementptr inbounds (i8, ptr @main.format, i64 3), align 1
|
||||||
|
store i8 111, ptr getelementptr inbounds (i8, ptr @main.format, i64 4), align 1
|
||||||
|
store i8 32, ptr getelementptr inbounds (i8, ptr @main.format, i64 5), align 1
|
||||||
|
store i8 37, ptr getelementptr inbounds (i8, ptr @main.format, i64 6), align 1
|
||||||
|
store i8 100, ptr getelementptr inbounds (i8, ptr @main.format, i64 7), align 1
|
||||||
|
store i8 10, ptr getelementptr inbounds (i8, ptr @main.format, i64 8), align 1
|
||||||
|
store i8 0, ptr getelementptr inbounds (i8, ptr @main.format, i64 9), align 1
|
||||||
|
br label %_llgo_2
|
||||||
|
|
||||||
|
_llgo_2: ; preds = %_llgo_1, %_llgo_0
|
||||||
|
ret void
|
||||||
|
}
|
||||||
|
|
||||||
|
define void @main() {
|
||||||
|
_llgo_0:
|
||||||
|
call void @main.init()
|
||||||
|
%0 = call i32 @strlen(ptr @main.format)
|
||||||
|
call void (ptr, ...) @printf(ptr @main.format, i32 %0)
|
||||||
|
ret void
|
||||||
|
}
|
||||||
|
|
||||||
|
declare void @printf(ptr, ...)
|
||||||
|
|
||||||
|
declare i32 @strlen(ptr)
|
||||||
@@ -3,6 +3,18 @@ source_filename = "apkg"
|
|||||||
|
|
||||||
@"apkg.init$guard" = global ptr null
|
@"apkg.init$guard" = global ptr null
|
||||||
|
|
||||||
|
define double @apkg.Max(double %0, double %1) {
|
||||||
|
_llgo_0:
|
||||||
|
%2 = fcmp ogt double %0, %1
|
||||||
|
br i1 %2, label %_llgo_1, label %_llgo_2
|
||||||
|
|
||||||
|
_llgo_1: ; preds = %_llgo_0
|
||||||
|
ret double %0
|
||||||
|
|
||||||
|
_llgo_2: ; preds = %_llgo_0
|
||||||
|
ret double %1
|
||||||
|
}
|
||||||
|
|
||||||
define void @apkg.init() {
|
define void @apkg.init() {
|
||||||
_llgo_0:
|
_llgo_0:
|
||||||
%0 = load i1, ptr @"apkg.init$guard", align 1
|
%0 = load i1, ptr @"apkg.init$guard", align 1
|
||||||
@@ -15,15 +27,3 @@ _llgo_1: ; preds = %_llgo_0
|
|||||||
_llgo_2: ; preds = %_llgo_1, %_llgo_0
|
_llgo_2: ; preds = %_llgo_1, %_llgo_0
|
||||||
ret void
|
ret void
|
||||||
}
|
}
|
||||||
|
|
||||||
define double @apkg.Max(double %0, double %1) {
|
|
||||||
_llgo_0:
|
|
||||||
%2 = fcmp ogt double %0, %1
|
|
||||||
br i1 %2, label %_llgo_1, label %_llgo_2
|
|
||||||
|
|
||||||
_llgo_1: ; preds = %_llgo_0
|
|
||||||
ret double %0
|
|
||||||
|
|
||||||
_llgo_2: ; preds = %_llgo_0
|
|
||||||
ret double %1
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -16,6 +16,13 @@ _llgo_2: ; preds = %_llgo_1, %_llgo_0
|
|||||||
ret void
|
ret void
|
||||||
}
|
}
|
||||||
|
|
||||||
|
define void @main() {
|
||||||
|
_llgo_0:
|
||||||
|
call void @main.init()
|
||||||
|
%0 = call i64 @main.max(i64 1, i64 2)
|
||||||
|
ret void
|
||||||
|
}
|
||||||
|
|
||||||
define i64 @main.max(i64 %0, i64 %1) {
|
define i64 @main.max(i64 %0, i64 %1) {
|
||||||
_llgo_0:
|
_llgo_0:
|
||||||
%2 = icmp sgt i64 %0, %1
|
%2 = icmp sgt i64 %0, %1
|
||||||
@@ -27,10 +34,3 @@ _llgo_1: ; preds = %_llgo_0
|
|||||||
_llgo_2: ; preds = %_llgo_0
|
_llgo_2: ; preds = %_llgo_0
|
||||||
ret i64 %1
|
ret i64 %1
|
||||||
}
|
}
|
||||||
|
|
||||||
define void @main() {
|
|
||||||
_llgo_0:
|
|
||||||
call void @main.init()
|
|
||||||
%0 = call i64 @main.max(i64 1, i64 2)
|
|
||||||
ret void
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
; ModuleID = 'main'
|
; ModuleID = 'main'
|
||||||
source_filename = "main"
|
source_filename = "main"
|
||||||
|
|
||||||
@"main.init$guard" = global ptr null
|
|
||||||
@main.hello = global ptr null
|
@main.hello = global ptr null
|
||||||
|
@"main.init$guard" = global ptr null
|
||||||
|
|
||||||
define void @main.init() {
|
define void @main.init() {
|
||||||
_llgo_0:
|
_llgo_0:
|
||||||
|
|||||||
@@ -1,8 +1,21 @@
|
|||||||
; ModuleID = 'main'
|
; ModuleID = 'main'
|
||||||
source_filename = "main"
|
source_filename = "main"
|
||||||
|
|
||||||
@"main.init$guard" = global ptr null
|
|
||||||
@main.format = global ptr null
|
@main.format = global ptr null
|
||||||
|
@"main.init$guard" = global ptr null
|
||||||
|
|
||||||
|
define i64 @"(T).Add"(i64 %0, i64 %1) {
|
||||||
|
_llgo_0:
|
||||||
|
%2 = add i64 %0, %1
|
||||||
|
ret i64 %2
|
||||||
|
}
|
||||||
|
|
||||||
|
define i64 @"(*T).Add"(ptr %0, i64 %1) {
|
||||||
|
_llgo_0:
|
||||||
|
%2 = load i64, ptr %0, align 4
|
||||||
|
%3 = call i64 @"(T).Add"(i64 %2, i64 %1)
|
||||||
|
ret i64 %3
|
||||||
|
}
|
||||||
|
|
||||||
define void @main.init() {
|
define void @main.init() {
|
||||||
_llgo_0:
|
_llgo_0:
|
||||||
@@ -27,25 +40,12 @@ _llgo_2: ; preds = %_llgo_1, %_llgo_0
|
|||||||
ret void
|
ret void
|
||||||
}
|
}
|
||||||
|
|
||||||
define i64 @"(main.T).Add"(i64 %0, i64 %1) {
|
|
||||||
_llgo_0:
|
|
||||||
%2 = add i64 %0, %1
|
|
||||||
ret i64 %2
|
|
||||||
}
|
|
||||||
|
|
||||||
define i64 @"(*main.T).Add"(ptr %0, i64 %1) {
|
|
||||||
_llgo_0:
|
|
||||||
%2 = load i64, ptr %0, align 4
|
|
||||||
%3 = call i64 @"(main.T).Add"(i64 %2, i64 %1)
|
|
||||||
ret i64 %3
|
|
||||||
}
|
|
||||||
|
|
||||||
declare void @printf(ptr, ...)
|
|
||||||
|
|
||||||
define void @main() {
|
define void @main() {
|
||||||
_llgo_0:
|
_llgo_0:
|
||||||
call void @main.init()
|
call void @main.init()
|
||||||
%0 = call i64 @"(main.T).Add"(i64 1, i64 2)
|
%0 = call i64 @"(T).Add"(i64 1, i64 2)
|
||||||
call void (ptr, ...) @printf(ptr @main.format, i64 %0)
|
call void (ptr, ...) @printf(ptr @main.format, i64 %0)
|
||||||
ret void
|
ret void
|
||||||
}
|
}
|
||||||
|
|
||||||
|
declare void @printf(ptr, ...)
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
; ModuleID = 'main'
|
; ModuleID = 'main'
|
||||||
source_filename = "main"
|
source_filename = "main"
|
||||||
|
|
||||||
@"main.init$guard" = global ptr null
|
|
||||||
@main.hello = global ptr null
|
@main.hello = global ptr null
|
||||||
|
@"main.init$guard" = global ptr null
|
||||||
|
|
||||||
define void @main.init() {
|
define void @main.init() {
|
||||||
_llgo_0:
|
_llgo_0:
|
||||||
@@ -24,11 +24,11 @@ _llgo_2: ; preds = %_llgo_1, %_llgo_0
|
|||||||
ret void
|
ret void
|
||||||
}
|
}
|
||||||
|
|
||||||
declare void @printf(ptr, ...)
|
|
||||||
|
|
||||||
define void @main() {
|
define void @main() {
|
||||||
_llgo_0:
|
_llgo_0:
|
||||||
call void @main.init()
|
call void @main.init()
|
||||||
call void (ptr, ...) @printf(ptr @main.hello)
|
call void (ptr, ...) @printf(ptr @main.hello)
|
||||||
ret void
|
ret void
|
||||||
}
|
}
|
||||||
|
|
||||||
|
declare void @printf(ptr, ...)
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
; ModuleID = 'main'
|
; ModuleID = 'main'
|
||||||
source_filename = "main"
|
source_filename = "main"
|
||||||
|
|
||||||
@"main.init$guard" = global ptr null
|
|
||||||
@main.format = global ptr null
|
@main.format = global ptr null
|
||||||
|
@"main.init$guard" = global ptr null
|
||||||
|
|
||||||
define void @main.init() {
|
define void @main.init() {
|
||||||
_llgo_0:
|
_llgo_0:
|
||||||
@@ -27,11 +27,11 @@ _llgo_2: ; preds = %_llgo_1, %_llgo_0
|
|||||||
ret void
|
ret void
|
||||||
}
|
}
|
||||||
|
|
||||||
declare void @printf(ptr, ...)
|
|
||||||
|
|
||||||
define void @main() {
|
define void @main() {
|
||||||
_llgo_0:
|
_llgo_0:
|
||||||
call void @main.init()
|
call void @main.init()
|
||||||
call void (ptr, ...) @printf(ptr @main.format, i64 100)
|
call void (ptr, ...) @printf(ptr @main.format, i64 100)
|
||||||
ret void
|
ret void
|
||||||
}
|
}
|
||||||
|
|
||||||
|
declare void @printf(ptr, ...)
|
||||||
|
|||||||
@@ -1,8 +1,14 @@
|
|||||||
; ModuleID = 'main'
|
; ModuleID = 'main'
|
||||||
source_filename = "main"
|
source_filename = "main"
|
||||||
|
|
||||||
@"main.init$guard" = global ptr null
|
|
||||||
@main.format = global ptr null
|
@main.format = global ptr null
|
||||||
|
@"main.init$guard" = global ptr null
|
||||||
|
|
||||||
|
define void @"(*T).Print"(ptr %0, i64 %1) {
|
||||||
|
_llgo_0:
|
||||||
|
call void (ptr, ...) @printf(ptr %0, i64 %1)
|
||||||
|
ret void
|
||||||
|
}
|
||||||
|
|
||||||
define void @main.init() {
|
define void @main.init() {
|
||||||
_llgo_0:
|
_llgo_0:
|
||||||
@@ -27,17 +33,11 @@ _llgo_2: ; preds = %_llgo_1, %_llgo_0
|
|||||||
ret void
|
ret void
|
||||||
}
|
}
|
||||||
|
|
||||||
declare void @printf(ptr, ...)
|
|
||||||
|
|
||||||
define void @"(*main.T).Print"(ptr %0, i64 %1) {
|
|
||||||
_llgo_0:
|
|
||||||
call void (ptr, ...) @printf(ptr %0, i64 %1)
|
|
||||||
ret void
|
|
||||||
}
|
|
||||||
|
|
||||||
define void @main() {
|
define void @main() {
|
||||||
_llgo_0:
|
_llgo_0:
|
||||||
call void @main.init()
|
call void @main.init()
|
||||||
call void @"(*main.T).Print"(ptr @main.format, i64 100)
|
call void @"(*T).Print"(ptr @main.format, i64 100)
|
||||||
ret void
|
ret void
|
||||||
}
|
}
|
||||||
|
|
||||||
|
declare void @printf(ptr, ...)
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
; ModuleID = 'main'
|
; ModuleID = 'main'
|
||||||
source_filename = "main"
|
source_filename = "main"
|
||||||
|
|
||||||
@"main.init$guard" = global ptr null
|
|
||||||
@main.a = global ptr null
|
@main.a = global ptr null
|
||||||
|
@"main.init$guard" = global ptr null
|
||||||
|
|
||||||
define void @main.init() {
|
define void @main.init() {
|
||||||
_llgo_0:
|
_llgo_0:
|
||||||
|
|||||||
@@ -29,6 +29,7 @@ import (
|
|||||||
|
|
||||||
"github.com/goplus/gogen/packages"
|
"github.com/goplus/gogen/packages"
|
||||||
"github.com/goplus/llgo/cl"
|
"github.com/goplus/llgo/cl"
|
||||||
|
"github.com/goplus/llgo/internal/llgen"
|
||||||
"golang.org/x/tools/go/ssa"
|
"golang.org/x/tools/go/ssa"
|
||||||
"golang.org/x/tools/go/ssa/ssautil"
|
"golang.org/x/tools/go/ssa/ssautil"
|
||||||
|
|
||||||
@@ -41,7 +42,7 @@ func init() {
|
|||||||
llssa.SetDebug(llssa.DbgFlagAll)
|
llssa.SetDebug(llssa.DbgFlagAll)
|
||||||
}
|
}
|
||||||
|
|
||||||
func FromDir(t *testing.T, sel, relDir string) {
|
func FromDir(t *testing.T, sel, relDir string, byLLGen bool) {
|
||||||
dir, err := os.Getwd()
|
dir, err := os.Getwd()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal("Getwd failed:", err)
|
t.Fatal("Getwd failed:", err)
|
||||||
@@ -57,23 +58,30 @@ func FromDir(t *testing.T, sel, relDir string) {
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
t.Run(name, func(t *testing.T) {
|
t.Run(name, func(t *testing.T) {
|
||||||
testFrom(t, dir+"/"+name, sel)
|
testFrom(t, dir+"/"+name, sel, byLLGen)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func testFrom(t *testing.T, pkgDir, sel string) {
|
func testFrom(t *testing.T, pkgDir, sel string, byLLGen bool) {
|
||||||
if sel != "" && !strings.Contains(pkgDir, sel) {
|
if sel != "" && !strings.Contains(pkgDir, sel) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
log.Println("Parsing", pkgDir)
|
log.Println("Parsing", pkgDir)
|
||||||
in := pkgDir + "/in.go"
|
in := pkgDir + "/in.go"
|
||||||
out := pkgDir + "/out.ll"
|
out := pkgDir + "/out.ll"
|
||||||
expected, err := os.ReadFile(out)
|
b, err := os.ReadFile(out)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal("ReadFile failed:", err)
|
t.Fatal("ReadFile failed:", err)
|
||||||
}
|
}
|
||||||
TestCompileEx(t, nil, in, string(expected))
|
expected := string(b)
|
||||||
|
if byLLGen {
|
||||||
|
if v := llgen.GenFromFile(in); v != expected {
|
||||||
|
t.Fatalf("\n==> got:\n%s\n==> expected:\n%s\n", v, expected)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
TestCompileEx(t, nil, in, expected)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestCompileEx(t *testing.T, src any, fname, expected string) {
|
func TestCompileEx(t *testing.T, src any, fname, expected string) {
|
||||||
|
|||||||
@@ -25,6 +25,7 @@ import (
|
|||||||
"log"
|
"log"
|
||||||
"os"
|
"os"
|
||||||
"sort"
|
"sort"
|
||||||
|
"strings"
|
||||||
|
|
||||||
llssa "github.com/goplus/llgo/ssa"
|
llssa "github.com/goplus/llgo/ssa"
|
||||||
"golang.org/x/tools/go/ssa"
|
"golang.org/x/tools/go/ssa"
|
||||||
@@ -57,7 +58,7 @@ func SetDebug(dbgFlags dbgFlags) {
|
|||||||
const (
|
const (
|
||||||
fnNormal = iota
|
fnNormal = iota
|
||||||
fnHasVArg
|
fnHasVArg
|
||||||
fnUnsafeInit
|
fnIgnore
|
||||||
)
|
)
|
||||||
|
|
||||||
func funcKind(vfn ssa.Value) int {
|
func funcKind(vfn ssa.Value) int {
|
||||||
@@ -65,8 +66,8 @@ func funcKind(vfn ssa.Value) int {
|
|||||||
params := fn.Signature.Params()
|
params := fn.Signature.Params()
|
||||||
n := params.Len()
|
n := params.Len()
|
||||||
if n == 0 {
|
if n == 0 {
|
||||||
if fn.Name() == "init" && fn.Pkg.Pkg.Path() == "unsafe" {
|
if fn.Name() == "init" && ignorePkgInit(fn.Pkg.Pkg.Path()) {
|
||||||
return fnUnsafeInit
|
return fnIgnore
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
last := params.At(n - 1)
|
last := params.At(n - 1)
|
||||||
@@ -78,6 +79,32 @@ func funcKind(vfn ssa.Value) int {
|
|||||||
return fnNormal
|
return fnNormal
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func ignorePkgInit(pkgPath string) bool {
|
||||||
|
switch pkgPath {
|
||||||
|
case "unsafe", "syscall", "runtime/cgo":
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
func ignoreFunc(name string, fn *ssa.Function) bool {
|
||||||
|
/* TODO(xsw): confirm this is not needed more
|
||||||
|
if name == "unsafe.init" {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
fnName := fn.Name()
|
||||||
|
if strings.HasPrefix(fnName, "_Cgo_") {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
const runtime = "runtime"
|
||||||
|
if strings.HasPrefix(name, runtime) {
|
||||||
|
left := name[len(runtime):]
|
||||||
|
return strings.HasPrefix(left, ".cgo") || strings.HasPrefix(left, "/cgo")
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
// -----------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------
|
||||||
|
|
||||||
type none = struct{}
|
type none = struct{}
|
||||||
@@ -137,14 +164,12 @@ func (p *context) compileGlobal(pkg llssa.Package, gbl *ssa.Global) {
|
|||||||
func (p *context) compileFunc(pkg llssa.Package, pkgTypes *types.Package, f *ssa.Function) {
|
func (p *context) compileFunc(pkg llssa.Package, pkgTypes *types.Package, f *ssa.Function) {
|
||||||
sig := f.Signature
|
sig := f.Signature
|
||||||
name := p.funcName(pkgTypes, f)
|
name := p.funcName(pkgTypes, f)
|
||||||
/* TODO(xsw): confirm this is not needed more
|
|
||||||
if name == "unsafe.init" {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
if debugInstr {
|
if debugInstr {
|
||||||
log.Println("==> NewFunc", name, "type:", sig.Recv(), sig)
|
log.Println("==> NewFunc", name, "type:", sig.Recv(), sig)
|
||||||
}
|
}
|
||||||
|
if ignoreFunc(name, f) {
|
||||||
|
return
|
||||||
|
}
|
||||||
fn := pkg.NewFunc(name, sig)
|
fn := pkg.NewFunc(name, sig)
|
||||||
p.inits = append(p.inits, func() {
|
p.inits = append(p.inits, func() {
|
||||||
p.fn = fn
|
p.fn = fn
|
||||||
@@ -229,7 +254,7 @@ func (p *context) compileInstrAndValue(b llssa.Builder, iv instrAndValue) (ret l
|
|||||||
call := v.Call
|
call := v.Call
|
||||||
cv := call.Value
|
cv := call.Value
|
||||||
kind := funcKind(cv)
|
kind := funcKind(cv)
|
||||||
if kind == fnUnsafeInit {
|
if kind == fnIgnore {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if debugGoSSA {
|
if debugGoSSA {
|
||||||
@@ -403,17 +428,12 @@ func NewPackage(prog llssa.Program, pkg *ssa.Package, files []*ast.File) (ret ll
|
|||||||
val ssa.Member
|
val ssa.Member
|
||||||
}
|
}
|
||||||
|
|
||||||
// Sort by position, so that the order of the functions in the IR matches
|
members := make([]*namedMember, 0, len(pkg.Members))
|
||||||
// the order of functions in the source file. This is useful for testing,
|
|
||||||
// for example.
|
|
||||||
var members []*namedMember
|
|
||||||
for name, v := range pkg.Members {
|
for name, v := range pkg.Members {
|
||||||
members = append(members, &namedMember{name, v})
|
members = append(members, &namedMember{name, v})
|
||||||
}
|
}
|
||||||
sort.Slice(members, func(i, j int) bool {
|
sort.Slice(members, func(i, j int) bool {
|
||||||
iPos := members[i].val.Pos()
|
return members[i].name < members[j].name
|
||||||
jPos := members[j].val.Pos()
|
|
||||||
return iPos < jPos
|
|
||||||
})
|
})
|
||||||
|
|
||||||
pkgProg := pkg.Prog
|
pkgProg := pkg.Prog
|
||||||
|
|||||||
@@ -27,8 +27,12 @@ func testCompile(t *testing.T, src, expected string) {
|
|||||||
cltest.TestCompileEx(t, src, "foo.go", expected)
|
cltest.TestCompileEx(t, src, "foo.go", expected)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestFromTestcgo(t *testing.T) {
|
||||||
|
cltest.FromDir(t, "", "./_testcgo", true)
|
||||||
|
}
|
||||||
|
|
||||||
func TestFromTestdata(t *testing.T) {
|
func TestFromTestdata(t *testing.T) {
|
||||||
cltest.FromDir(t, "", "./_testdata")
|
cltest.FromDir(t, "", "./_testdata", false)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestVar(t *testing.T) {
|
func TestVar(t *testing.T) {
|
||||||
@@ -38,8 +42,8 @@ var a int
|
|||||||
`, `; ModuleID = 'foo'
|
`, `; ModuleID = 'foo'
|
||||||
source_filename = "foo"
|
source_filename = "foo"
|
||||||
|
|
||||||
@"foo.init$guard" = global ptr null
|
|
||||||
@foo.a = global ptr null
|
@foo.a = global ptr null
|
||||||
|
@"foo.init$guard" = global ptr null
|
||||||
|
|
||||||
define void @foo.init() {
|
define void @foo.init() {
|
||||||
_llgo_0:
|
_llgo_0:
|
||||||
@@ -67,6 +71,11 @@ source_filename = "foo"
|
|||||||
|
|
||||||
@"foo.init$guard" = global ptr null
|
@"foo.init$guard" = global ptr null
|
||||||
|
|
||||||
|
define i64 @foo.fn(i64 %0, double %1) {
|
||||||
|
_llgo_0:
|
||||||
|
ret i64 1
|
||||||
|
}
|
||||||
|
|
||||||
define void @foo.init() {
|
define void @foo.init() {
|
||||||
_llgo_0:
|
_llgo_0:
|
||||||
%0 = load i1, ptr @"foo.init$guard", align 1
|
%0 = load i1, ptr @"foo.init$guard", align 1
|
||||||
@@ -79,10 +88,5 @@ _llgo_1: ; preds = %_llgo_0
|
|||||||
_llgo_2: ; preds = %_llgo_1, %_llgo_0
|
_llgo_2: ; preds = %_llgo_1, %_llgo_0
|
||||||
ret void
|
ret void
|
||||||
}
|
}
|
||||||
|
|
||||||
define i64 @foo.fn(i64 %0, double %1) {
|
|
||||||
_llgo_0:
|
|
||||||
ret i64 1
|
|
||||||
}
|
|
||||||
`)
|
`)
|
||||||
}
|
}
|
||||||
|
|||||||
13
cl/import.go
13
cl/import.go
@@ -117,13 +117,20 @@ func fullName(pkg *types.Package, name string) string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// func: pkg.name
|
// func: pkg.name
|
||||||
// method: (pkg.T).name
|
// method: (pkg.T).name, (*pkg.T).name
|
||||||
func funcName(pkg *types.Package, fn *ssa.Function) string {
|
func funcName(pkg *types.Package, fn *ssa.Function) string {
|
||||||
sig := fn.Signature
|
sig := fn.Signature
|
||||||
|
name := fn.Name()
|
||||||
if recv := sig.Recv(); recv != nil {
|
if recv := sig.Recv(); recv != nil {
|
||||||
return "(" + recv.Type().String() + ")." + fn.Name()
|
var tName string
|
||||||
|
t := recv.Type()
|
||||||
|
if tp, ok := t.(*types.Pointer); ok {
|
||||||
|
t, tName = tp.Elem(), "*"
|
||||||
|
}
|
||||||
|
tName += t.(*types.Named).Obj().Name()
|
||||||
|
return "(" + tName + ")." + name
|
||||||
}
|
}
|
||||||
ret := fullName(pkg, fn.Name())
|
ret := fullName(pkg, name)
|
||||||
if ret == "main.main" {
|
if ret == "main.main" {
|
||||||
ret = "main"
|
ret = "main"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -133,7 +133,7 @@ func linkMainPkg(pkg *packages.Package, conf *Config, mode Mode) {
|
|||||||
args[0] = "-o"
|
args[0] = "-o"
|
||||||
args[1] = app
|
args[1] = app
|
||||||
packages.Visit([]*packages.Package{pkg}, nil, func(p *packages.Package) {
|
packages.Visit([]*packages.Package{pkg}, nil, func(p *packages.Package) {
|
||||||
if p.PkgPath != "unsafe" { // TODO(xsw): remove this special case
|
if p.PkgPath != "unsafe" { // TODO(xsw): maybe can remove this special case
|
||||||
args = append(args, p.ExportFile+".ll")
|
args = append(args, p.ExportFile+".ll")
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
@@ -159,7 +159,7 @@ func buildPkg(prog llssa.Program, aPkg aPackage, mode Mode) {
|
|||||||
if mode != ModeRun {
|
if mode != ModeRun {
|
||||||
fmt.Fprintln(os.Stderr, pkgPath)
|
fmt.Fprintln(os.Stderr, pkgPath)
|
||||||
}
|
}
|
||||||
if pkgPath == "unsafe" { // TODO(xsw): remove this special case
|
if pkgPath == "unsafe" { // TODO(xsw): maybe can remove this special case
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
ret, err := cl.NewPackage(prog, aPkg.SSA, pkg.Syntax)
|
ret, err := cl.NewPackage(prog, aPkg.SSA, pkg.Syntax)
|
||||||
|
|||||||
61
internal/llgen/llgenf.go
Normal file
61
internal/llgen/llgenf.go
Normal file
@@ -0,0 +1,61 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2024 The GoPlus Authors (goplus.org). All rights reserved.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package llgen
|
||||||
|
|
||||||
|
import (
|
||||||
|
"os"
|
||||||
|
|
||||||
|
"github.com/goplus/llgo/cl"
|
||||||
|
"golang.org/x/tools/go/packages"
|
||||||
|
"golang.org/x/tools/go/ssa"
|
||||||
|
"golang.org/x/tools/go/ssa/ssautil"
|
||||||
|
|
||||||
|
llssa "github.com/goplus/llgo/ssa"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
loadFiles = packages.NeedName | packages.NeedFiles | packages.NeedCompiledGoFiles
|
||||||
|
loadImports = loadFiles | packages.NeedImports
|
||||||
|
loadTypes = loadImports | packages.NeedTypes | packages.NeedTypesSizes
|
||||||
|
loadSyntax = loadTypes | packages.NeedSyntax | packages.NeedTypesInfo
|
||||||
|
)
|
||||||
|
|
||||||
|
func GenFromFile(inFile string) string {
|
||||||
|
cfg := &packages.Config{
|
||||||
|
Mode: loadSyntax,
|
||||||
|
}
|
||||||
|
initial, err := packages.Load(cfg, inFile)
|
||||||
|
check(err)
|
||||||
|
|
||||||
|
_, pkgs := ssautil.AllPackages(initial, ssa.SanityCheckFunctions)
|
||||||
|
|
||||||
|
pkg := initial[0]
|
||||||
|
ssaPkg := pkgs[0]
|
||||||
|
ssaPkg.Build()
|
||||||
|
|
||||||
|
prog := llssa.NewProgram(nil)
|
||||||
|
ret, err := cl.NewPackage(prog, ssaPkg, pkg.Syntax)
|
||||||
|
check(err)
|
||||||
|
|
||||||
|
return ret.String()
|
||||||
|
}
|
||||||
|
|
||||||
|
func DoFile(inFile, outFile string) {
|
||||||
|
ret := GenFromFile(inFile)
|
||||||
|
err := os.WriteFile(outFile, []byte(ret), 0644)
|
||||||
|
check(err)
|
||||||
|
}
|
||||||
@@ -22,6 +22,10 @@ import (
|
|||||||
"github.com/goplus/llgo/cl/cltest"
|
"github.com/goplus/llgo/cl/cltest"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestFromTestdata(t *testing.T) {
|
func TestFromTestcgo(t *testing.T) {
|
||||||
cltest.FromDir(t, "", "../cl/_testdata")
|
cltest.FromDir(t, "", "../cl/_testcgo", true)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestFromTestdata(t *testing.T) {
|
||||||
|
cltest.FromDir(t, "", "../cl/_testdata", false)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -145,7 +145,8 @@ func (p Function) Param(i int) Expr {
|
|||||||
func (p Function) NewBuilder() Builder {
|
func (p Function) NewBuilder() Builder {
|
||||||
prog := p.prog
|
prog := p.prog
|
||||||
b := prog.ctx.NewBuilder()
|
b := prog.ctx.NewBuilder()
|
||||||
b.Finalize()
|
// TODO(xsw): Finalize may cause panic, so comment it.
|
||||||
|
// b.Finalize()
|
||||||
return &aBuilder{b, p, prog}
|
return &aBuilder{b, p, prog}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -122,7 +122,8 @@ func NewProgram(target *Target) Program {
|
|||||||
target = &Target{}
|
target = &Target{}
|
||||||
}
|
}
|
||||||
ctx := llvm.NewContext()
|
ctx := llvm.NewContext()
|
||||||
ctx.Finalize()
|
// TODO(xsw): Finalize may cause panic, so comment it.
|
||||||
|
// ctx.Finalize()
|
||||||
td := llvm.NewTargetData("") // TODO(xsw): target config
|
td := llvm.NewTargetData("") // TODO(xsw): target config
|
||||||
return &aProgram{ctx: ctx, target: target, td: td}
|
return &aProgram{ctx: ctx, target: target, td: td}
|
||||||
}
|
}
|
||||||
@@ -130,7 +131,8 @@ func NewProgram(target *Target) Program {
|
|||||||
// NewPackage creates a new package.
|
// NewPackage creates a new package.
|
||||||
func (p Program) NewPackage(name, pkgPath string) Package {
|
func (p Program) NewPackage(name, pkgPath string) Package {
|
||||||
mod := p.ctx.NewModule(pkgPath)
|
mod := p.ctx.NewModule(pkgPath)
|
||||||
mod.Finalize()
|
// TODO(xsw): Finalize may cause panic, so comment it.
|
||||||
|
// mod.Finalize()
|
||||||
fns := make(map[string]Function)
|
fns := make(map[string]Function)
|
||||||
gbls := make(map[string]Global)
|
gbls := make(map[string]Global)
|
||||||
return &aPackage{mod, fns, gbls, p}
|
return &aPackage{mod, fns, gbls, p}
|
||||||
|
|||||||
Reference in New Issue
Block a user