diff --git a/chore/llgen/llgen.go b/chore/llgen/llgen.go new file mode 100644 index 00000000..850a70da --- /dev/null +++ b/chore/llgen/llgen.go @@ -0,0 +1,79 @@ +/* + * 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 main + +import ( + "fmt" + "go/ast" + "go/importer" + "go/parser" + "go/token" + "go/types" + "os" + "path/filepath" + + "github.com/goplus/llgo/cl" + "golang.org/x/tools/go/ssa" + "golang.org/x/tools/go/ssa/ssautil" + + llssa "github.com/goplus/llgo/ssa" +) + +func main() { + if len(os.Args) != 2 { + fmt.Fprintln(os.Stderr, "Usage: llgen xxx.go") + return + } + + inFile := os.Args[1] + fset := token.NewFileSet() + f, err := parser.ParseFile(fset, inFile, nil, parser.ParseComments) + check(err) + + files := []*ast.File{f} + name := f.Name.Name + pkg := types.NewPackage(name, name) + foo, _, err := ssautil.BuildPackage( + &types.Config{Importer: importer.Default()}, fset, pkg, files, ssa.SanityCheckFunctions) + check(err) + + foo.WriteTo(os.Stderr) + for _, m := range foo.Members { + if f, ok := m.(*ssa.Function); ok { + f.WriteTo(os.Stderr) + } + } + + llssa.Initialize(llssa.InitAll) + llssa.SetDebug(llssa.DbgFlagAll) + cl.SetDebug(cl.DbgFlagAll) + + prog := llssa.NewProgram(nil) + ret, err := cl.NewPackage(prog, foo, nil) + check(err) + + dir, _ := filepath.Split(inFile) + outFile := dir + "out.ll" + err = os.WriteFile(outFile, []byte(ret.String()), 0644) + check(err) +} + +func check(err error) { + if err != nil { + panic(err) + } +} diff --git a/cl/compile.go b/cl/compile.go index c1934f5f..7d795e9e 100644 --- a/cl/compile.go +++ b/cl/compile.go @@ -18,13 +18,30 @@ package cl import ( "fmt" + "log" "sort" llssa "github.com/goplus/llgo/ssa" "golang.org/x/tools/go/ssa" ) -type Config struct { +// ----------------------------------------------------------------------------- + +type dbgFlags = int + +const ( + DbgFlagInstruction dbgFlags = 1 << iota + + DbgFlagAll = DbgFlagInstruction +) + +var ( + debugInstr bool +) + +// SetDebug sets debug flags. +func SetDebug(dbgFlags dbgFlags) { + debugInstr = (dbgFlags & DbgFlagInstruction) != 0 } // ----------------------------------------------------------------------------- @@ -48,12 +65,20 @@ func (p *context) compileType(pkg llssa.Package, member *ssa.Type) { // Global variable. func (p *context) compileGlobal(pkg llssa.Package, gbl *ssa.Global) { - g := pkg.NewVar(gbl.Name(), gbl.Type()) + name, typ := gbl.Name(), gbl.Type() + if debugInstr { + log.Println("==> NewVar", name, typ) + } + g := pkg.NewVar(name, typ) g.Init(p.prog.Null(g.Type)) } func (p *context) compileFunc(pkg llssa.Package, f *ssa.Function) { - fn := pkg.NewFunc(f.Name(), f.Signature) + name := f.Name() + if debugInstr { + log.Println("==> NewFunc", name) + } + fn := pkg.NewFunc(name, f.Signature) p.inits = append(p.inits, func() { p.fn = fn defer func() { @@ -63,6 +88,9 @@ func (p *context) compileFunc(pkg llssa.Package, f *ssa.Function) { if nblk == 0 { // external function return } + if debugInstr { + log.Println("==> FuncBody", name) + } fn.MakeBlocks(nblk) b := fn.NewBuilder() for _, block := range f.Blocks { @@ -87,12 +115,10 @@ func (p *context) compileInstrAndValue(b llssa.Builder, iv instrAndValue) (ret l } switch v := iv.(type) { case *ssa.Call: - if false { - call := v.Call - fn := p.compileValue(b, call.Value) - args := p.compileValues(b, call.Args) - ret = b.Call(fn, args...) - } + call := v.Call + fn := p.compileValue(b, call.Value) + args := p.compileValues(b, call.Args) + ret = b.Call(fn, args...) case *ssa.BinOp: x := p.compileValue(b, v.X) y := p.compileValue(b, v.Y) @@ -185,6 +211,9 @@ func (p *context) compileValues(b llssa.Builder, vals []ssa.Value) []llssa.Expr // ----------------------------------------------------------------------------- +type Config struct { +} + // NewPackage compiles a Go package to LLVM IR package. func NewPackage(prog llssa.Program, pkg *ssa.Package, conf *Config) (ret llssa.Package, err error) { type namedMember struct { diff --git a/cl/compile_test.go b/cl/compile_test.go index 303e0cbe..150ddc6e 100644 --- a/cl/compile_test.go +++ b/cl/compile_test.go @@ -38,6 +38,7 @@ func TestFromTestdata(t *testing.T) { } func init() { + SetDebug(DbgFlagAll) llssa.Initialize(llssa.InitAll) llssa.SetDebug(llssa.DbgFlagAll) } diff --git a/ssa/package.go b/ssa/package.go index ce3969e0..7d040420 100644 --- a/ssa/package.go +++ b/ssa/package.go @@ -19,12 +19,13 @@ package ssa import ( "go/constant" "go/types" - "log" "github.com/goplus/llvm" "golang.org/x/tools/go/types/typeutil" ) +// ----------------------------------------------------------------------------- + type dbgFlags = int const ( @@ -192,9 +193,6 @@ func (p Package) NewConst(name string, val constant.Value) NamedConst { // NewVar creates a new global variable. func (p Package) NewVar(name string, typ types.Type) Global { - if debugInstr { - log.Println("==> NewVar", name, typ) - } t := p.prog.Type(typ) gbl := llvm.AddGlobal(p.mod, t.ll, name) ret := &aGlobal{Expr{gbl, t}} @@ -204,9 +202,6 @@ func (p Package) NewVar(name string, typ types.Type) Global { // NewFunc creates a new function. func (p Package) NewFunc(name string, sig *types.Signature) Function { - if debugInstr { - log.Println("==> NewFunc", name) - } t := p.prog.llvmSignature(sig) fn := llvm.AddFunction(p.mod, name, t.ll) ret := newFunction(fn, t, p.prog)