From 0b7713dbdb8adbf4f96f7137e73193a34726a17a Mon Sep 17 00:00:00 2001 From: xushiwei Date: Mon, 22 Apr 2024 00:03:49 +0800 Subject: [PATCH] llgo/x/llgen --- .gitignore | 1 + chore/llgen/llgen.go | 45 ++--------------------- cl/_testdata/fncall/out.ll | 1 + cl/_testdata/printf/out.ll | 1 + cl/_testdata/varinit/out.ll | 1 + cl/compile.go | 15 ++++++-- x/llgen/llgen.go | 71 +++++++++++++++++++++++++++++++++++++ 7 files changed, 90 insertions(+), 45 deletions(-) create mode 100644 x/llgen/llgen.go diff --git a/.gitignore b/.gitignore index 238d50fe..f96bd258 100644 --- a/.gitignore +++ b/.gitignore @@ -15,6 +15,7 @@ _tinygo/ # Output of the go coverage tool, specifically when used with LiteIDE *.out +*.swp # Dependency directories (remove the comment below to include it) # vendor/ diff --git a/chore/llgen/llgen.go b/chore/llgen/llgen.go index 850a70da..d648b39e 100644 --- a/chore/llgen/llgen.go +++ b/chore/llgen/llgen.go @@ -18,19 +18,10 @@ 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" + "github.com/goplus/llgo/x/llgen" ) func main() { @@ -40,40 +31,10 @@ func main() { } 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) - } + llgen.Init() + llgen.Do(inFile, outFile) } diff --git a/cl/_testdata/fncall/out.ll b/cl/_testdata/fncall/out.ll index 6fa9a5b7..56abe836 100644 --- a/cl/_testdata/fncall/out.ll +++ b/cl/_testdata/fncall/out.ll @@ -30,6 +30,7 @@ _llgo_2: ; preds = %_llgo_0 define void @main() { _llgo_0: + call void @init() %0 = call i64 @max(i64 1, i64 2) ret void } diff --git a/cl/_testdata/printf/out.ll b/cl/_testdata/printf/out.ll index fbe0e69e..98881961 100644 --- a/cl/_testdata/printf/out.ll +++ b/cl/_testdata/printf/out.ll @@ -28,6 +28,7 @@ declare void @printf(ptr, ...) define void @main() { _llgo_0: + call void @init() call void (ptr, ...) @printf(ptr @hello) ret void } diff --git a/cl/_testdata/varinit/out.ll b/cl/_testdata/varinit/out.ll index aa7eaef4..5a045a52 100644 --- a/cl/_testdata/varinit/out.ll +++ b/cl/_testdata/varinit/out.ll @@ -20,6 +20,7 @@ _llgo_2: ; preds = %_llgo_1, %_llgo_0 define void @main() { _llgo_0: + call void @init() %0 = load i64, ptr @a, align 4 %1 = add i64 %0, 1 store i64 %1, ptr @a, align 4 diff --git a/cl/compile.go b/cl/compile.go index f4648cf0..7974d9a3 100644 --- a/cl/compile.go +++ b/cl/compile.go @@ -73,6 +73,10 @@ func funcKind(vfn ssa.Value) int { return fnNormal } +func isMainFunc(fn *ssa.Function) bool { + return fn.Name() == "main" && fn.Pkg.Pkg.Path() == "main" +} + // ----------------------------------------------------------------------------- type instrAndValue interface { @@ -126,16 +130,21 @@ func (p *context) compileFunc(pkg llssa.Package, f *ssa.Function) { } fn.MakeBlocks(nblk) b := fn.NewBuilder() - for _, block := range f.Blocks { - p.compileBlock(b, block) + isMain := isMainFunc(f) + for i, block := range f.Blocks { + p.compileBlock(b, block, isMain && i == 0) } }) } -func (p *context) compileBlock(b llssa.Builder, block *ssa.BasicBlock) llssa.BasicBlock { +func (p *context) compileBlock(b llssa.Builder, block *ssa.BasicBlock, doInit bool) llssa.BasicBlock { ret := p.fn.Block(block.Index) b.SetBlock(ret) p.bvals = make(map[ssa.Value]llssa.Expr) + if doInit { + fn := p.pkg.FuncOf("init") + b.Call(fn.Expr) + } for _, instr := range block.Instrs { p.compileInstr(b, instr) } diff --git a/x/llgen/llgen.go b/x/llgen/llgen.go new file mode 100644 index 00000000..ae89e26a --- /dev/null +++ b/x/llgen/llgen.go @@ -0,0 +1,71 @@ +/* + * 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 ( + "go/ast" + "go/importer" + "go/parser" + "go/token" + "go/types" + "os" + + "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 Init() { + llssa.Initialize(llssa.InitAll) + llssa.SetDebug(llssa.DbgFlagAll) + cl.SetDebug(cl.DbgFlagAll) +} + +func Do(inFile, outFile string) { + ret := Gen(inFile, nil) + err := os.WriteFile(outFile, []byte(ret), 0644) + check(err) +} + +func Gen(inFile string, src any) string { + fset := token.NewFileSet() + f, err := parser.ParseFile(fset, inFile, src, parser.ParseComments) + check(err) + + files := []*ast.File{f} + name := f.Name.Name + pkg := types.NewPackage(name, name) + ssaPkg, _, err := ssautil.BuildPackage( + &types.Config{Importer: importer.Default()}, fset, pkg, files, ssa.SanityCheckFunctions) + check(err) + + ssaPkg.WriteTo(os.Stderr) + + prog := llssa.NewProgram(nil) + ret, err := cl.NewPackage(prog, ssaPkg, nil) + check(err) + + return ret.String() +} + +func check(err error) { + if err != nil { + panic(err) + } +}