From 7ffedc2da71a748ee5be7342fdc6cb01d56e5b87 Mon Sep 17 00:00:00 2001 From: xushiwei Date: Sun, 21 Apr 2024 17:54:51 +0800 Subject: [PATCH] cl: _testdata/printf --- cl/_testdata/printf/out.ll | 1 + cl/compile.go | 78 ++++++++++++++++++++++++++++++++++---- cl/compile_test.go | 7 +--- ssa/expr.go | 4 +- ssa/type.go | 6 +-- 5 files changed, 77 insertions(+), 19 deletions(-) diff --git a/cl/_testdata/printf/out.ll b/cl/_testdata/printf/out.ll index 693d1261..fbe0e69e 100644 --- a/cl/_testdata/printf/out.ll +++ b/cl/_testdata/printf/out.ll @@ -28,5 +28,6 @@ declare void @printf(ptr, ...) define void @main() { _llgo_0: + call void (ptr, ...) @printf(ptr @hello) ret void } diff --git a/cl/compile.go b/cl/compile.go index 7d795e9e..f4648cf0 100644 --- a/cl/compile.go +++ b/cl/compile.go @@ -19,6 +19,7 @@ package cl import ( "fmt" "log" + "os" "sort" llssa "github.com/goplus/llgo/ssa" @@ -31,17 +32,45 @@ type dbgFlags = int const ( DbgFlagInstruction dbgFlags = 1 << iota + DbgFlagGoSSA - DbgFlagAll = DbgFlagInstruction + DbgFlagAll = DbgFlagInstruction | DbgFlagGoSSA ) var ( debugInstr bool + debugGoSSA bool ) // SetDebug sets debug flags. func SetDebug(dbgFlags dbgFlags) { debugInstr = (dbgFlags & DbgFlagInstruction) != 0 + debugGoSSA = (dbgFlags & DbgFlagGoSSA) != 0 +} + +// ----------------------------------------------------------------------------- + +const ( + fnNormal = iota + fnHasVArg + fnUnsafeInit +) + +func funcKind(vfn ssa.Value) int { + if fn, ok := vfn.(*ssa.Function); ok { + n := len(fn.Params) + if n == 0 { + if fn.Name() == "init" && fn.Pkg.Pkg.Path() == "unsafe" { + return fnUnsafeInit + } + } else { + last := fn.Params[n-1] + if last.Name() == llssa.NameValist { + return fnHasVArg + } + } + } + return fnNormal } // ----------------------------------------------------------------------------- @@ -55,6 +84,7 @@ type context struct { prog llssa.Program pkg llssa.Package fn llssa.Function + goPkg *ssa.Package bvals map[ssa.Value]llssa.Expr // block values inits []func() } @@ -88,6 +118,9 @@ func (p *context) compileFunc(pkg llssa.Package, f *ssa.Function) { if nblk == 0 { // external function return } + if debugGoSSA { + f.WriteTo(os.Stderr) + } if debugInstr { log.Println("==> FuncBody", name) } @@ -116,8 +149,15 @@ func (p *context) compileInstrAndValue(b llssa.Builder, iv instrAndValue) (ret l switch v := iv.(type) { case *ssa.Call: call := v.Call + kind := funcKind(call.Value) + if kind == fnUnsafeInit { + return + } + if debugGoSSA { + log.Println(">>> Call", call.Value, call.Args) + } fn := p.compileValue(b, call.Value) - args := p.compileValues(b, call.Args) + args := p.compileValues(b, call.Args, kind) ret = b.Call(fn, args...) case *ssa.BinOp: x := p.compileValue(b, v.X) @@ -189,9 +229,15 @@ func (p *context) compileValue(b llssa.Builder, v ssa.Value) llssa.Expr { } } case *ssa.Function: + if v.Pkg != p.goPkg { + panic("todo") + } fn := p.pkg.FuncOf(v.Name()) return fn.Expr case *ssa.Global: + if v.Pkg != p.goPkg { + panic("todo") + } g := p.pkg.VarOf(v.Name()) return g.Expr case *ssa.Const: @@ -201,10 +247,25 @@ func (p *context) compileValue(b llssa.Builder, v ssa.Value) llssa.Expr { panic(fmt.Sprintf("compileValue: unknown value - %T\n", v)) } -func (p *context) compileValues(b llssa.Builder, vals []ssa.Value) []llssa.Expr { - ret := make([]llssa.Expr, len(vals)) - for i, v := range vals { - ret[i] = p.compileValue(b, v) +func (p *context) compileVArg(ret []llssa.Expr, b llssa.Builder, v ssa.Value) []llssa.Expr { + _ = b + switch v := v.(type) { + case *ssa.Const: + if v.Value == nil { + return ret + } + } + panic("todo") +} + +func (p *context) compileValues(b llssa.Builder, vals []ssa.Value, hasVArg int) []llssa.Expr { + n := len(vals) - hasVArg + ret := make([]llssa.Expr, n) + for i := 0; i < n; i++ { + ret[i] = p.compileValue(b, vals[i]) + } + if hasVArg > 0 { + ret = p.compileVArg(ret, b, vals[n]) } return ret } @@ -238,8 +299,9 @@ func NewPackage(prog llssa.Program, pkg *ssa.Package, conf *Config) (ret llssa.P ret = prog.NewPackage(pkgTypes.Name(), pkgTypes.Path()) ctx := &context{ - prog: prog, - pkg: ret, + prog: prog, + pkg: ret, + goPkg: pkg, } for _, m := range members { member := m.val diff --git a/cl/compile_test.go b/cl/compile_test.go index 150ddc6e..aac37468 100644 --- a/cl/compile_test.go +++ b/cl/compile_test.go @@ -34,7 +34,7 @@ import ( ) func TestFromTestdata(t *testing.T) { - testFromDir(t, "printf", "./_testdata") + testFromDir(t, "", "./_testdata") } func init() { @@ -94,11 +94,6 @@ func testCompileEx(t *testing.T, src any, fname, expected string) { t.Fatal("BuildPackage failed:", err) } foo.WriteTo(os.Stderr) - for _, m := range foo.Members { - if f, ok := m.(*ssa.Function); ok { - f.WriteTo(os.Stderr) - } - } prog := llssa.NewProgram(nil) ret, err := NewPackage(prog, foo, nil) if err != nil { diff --git a/ssa/expr.go b/ssa/expr.go index 8c6ce9ae..4787e404 100644 --- a/ssa/expr.go +++ b/ssa/expr.go @@ -258,7 +258,7 @@ func (b Builder) UnOp(op token.Token, x Expr) Expr { // Load returns the value at the pointer ptr. func (b Builder) Load(ptr Expr) Expr { if debugInstr { - log.Printf("Load @%v\n", ptr.impl.Name()) + log.Printf("Load %v\n", ptr.impl.Name()) } telem := b.prog.Elem(ptr.Type) return Expr{llvm.CreateLoad(b.impl, telem.ll, ptr.impl), telem} @@ -267,7 +267,7 @@ func (b Builder) Load(ptr Expr) Expr { // Store stores val at the pointer ptr. func (b Builder) Store(ptr, val Expr) Builder { if debugInstr { - log.Printf("Store @%v, %v\n", ptr.impl.Name(), val.impl) + log.Printf("Store %v, %v\n", ptr.impl.Name(), val.impl) } b.impl.CreateStore(val.impl, ptr.impl) return b diff --git a/ssa/type.go b/ssa/type.go index c6cc8c28..cb35a885 100644 --- a/ssa/type.go +++ b/ssa/type.go @@ -42,15 +42,15 @@ const ( // ----------------------------------------------------------------------------- const ( - nameValist = "__llgo_va_list" + NameValist = "__llgo_va_list" ) func VArg() *types.Var { - return types.NewParam(0, nil, nameValist, types.Typ[types.Invalid]) + return types.NewParam(0, nil, NameValist, types.Typ[types.Invalid]) } func IsVArg(arg *types.Var) bool { - return arg.Name() == nameValist + return arg.Name() == NameValist } func HasVArg(t *types.Tuple, n int) bool {