TestFromTestdata: fncall
This commit is contained in:
12
cl/_testdata/fncall/in.go
Normal file
12
cl/_testdata/fncall/in.go
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
package fncall
|
||||||
|
|
||||||
|
func max(a, b int) int {
|
||||||
|
if a > b {
|
||||||
|
return a
|
||||||
|
}
|
||||||
|
return b
|
||||||
|
}
|
||||||
|
|
||||||
|
func Foo() int {
|
||||||
|
return max(1, 2)
|
||||||
|
}
|
||||||
35
cl/_testdata/fncall/out.ll
Normal file
35
cl/_testdata/fncall/out.ll
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
; ModuleID = 'fncall'
|
||||||
|
source_filename = "fncall"
|
||||||
|
|
||||||
|
@"init$guard" = external global ptr
|
||||||
|
|
||||||
|
define void @init() {
|
||||||
|
_llgo_0:
|
||||||
|
%0 = load i1, ptr @"init$guard", align 1
|
||||||
|
br i1 %0, label %_llgo_2, label %_llgo_1
|
||||||
|
|
||||||
|
_llgo_1: ; preds = %_llgo_0
|
||||||
|
store i1 true, ptr @"init$guard", align 1
|
||||||
|
br label %_llgo_2
|
||||||
|
|
||||||
|
_llgo_2: ; preds = %_llgo_1, %_llgo_0
|
||||||
|
ret void
|
||||||
|
}
|
||||||
|
|
||||||
|
define i64 @max(i64 %0, i64 %1) {
|
||||||
|
_llgo_0:
|
||||||
|
%2 = icmp sgt i64 %0, %1
|
||||||
|
br i1 %2, label %_llgo_1, label %_llgo_2
|
||||||
|
|
||||||
|
_llgo_1: ; preds = %_llgo_0
|
||||||
|
ret i64 %0
|
||||||
|
|
||||||
|
_llgo_2: ; preds = %_llgo_0
|
||||||
|
ret i64 %1
|
||||||
|
}
|
||||||
|
|
||||||
|
define i64 @Foo() {
|
||||||
|
_llgo_0:
|
||||||
|
%0 = call i64 @max(i64 1, i64 2)
|
||||||
|
ret i64 %0
|
||||||
|
}
|
||||||
@@ -35,11 +35,16 @@ type instrAndValue interface {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type context struct {
|
type context struct {
|
||||||
prog llssa.Program
|
prog llssa.Program
|
||||||
pkg llssa.Package
|
pkg llssa.Package
|
||||||
fn llssa.Function
|
fn llssa.Function
|
||||||
glbs map[*ssa.Global]llssa.Global
|
fns map[*ssa.Function]llssa.Function
|
||||||
vals map[ssa.Value]llssa.Expr
|
glbs map[*ssa.Global]llssa.Global
|
||||||
|
bvals map[ssa.Value]llssa.Expr // block values
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *context) compileType(pkg llssa.Package, member *ssa.Type) {
|
||||||
|
panic("todo")
|
||||||
}
|
}
|
||||||
|
|
||||||
// Global variable.
|
// Global variable.
|
||||||
@@ -52,12 +57,17 @@ func (p *context) compileGlobal(pkg llssa.Package, gbl *ssa.Global) llssa.Global
|
|||||||
return g
|
return g
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *context) compileType(pkg llssa.Package, member *ssa.Type) {
|
func (p *context) compileFunc(pkg llssa.Package, f *ssa.Function) llssa.Function {
|
||||||
panic("todo")
|
if fn, ok := p.fns[f]; ok {
|
||||||
|
return fn
|
||||||
|
}
|
||||||
|
fn := p.doCompileFunc(pkg, f)
|
||||||
|
p.fns[f] = fn
|
||||||
|
return fn
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *context) compileFunc(pkg llssa.Package, f *ssa.Function) {
|
func (p *context) doCompileFunc(pkg llssa.Package, f *ssa.Function) (fn llssa.Function) {
|
||||||
fn := pkg.NewFunc(f.Name(), f.Signature)
|
fn = pkg.NewFunc(f.Name(), f.Signature)
|
||||||
p.fn = fn
|
p.fn = fn
|
||||||
defer func() {
|
defer func() {
|
||||||
p.fn = nil
|
p.fn = nil
|
||||||
@@ -71,12 +81,13 @@ func (p *context) compileFunc(pkg llssa.Package, f *ssa.Function) {
|
|||||||
for _, block := range f.Blocks {
|
for _, block := range f.Blocks {
|
||||||
p.compileBlock(b, block)
|
p.compileBlock(b, block)
|
||||||
}
|
}
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *context) compileBlock(b llssa.Builder, block *ssa.BasicBlock) llssa.BasicBlock {
|
func (p *context) compileBlock(b llssa.Builder, block *ssa.BasicBlock) llssa.BasicBlock {
|
||||||
ret := p.fn.Block(block.Index)
|
ret := p.fn.Block(block.Index)
|
||||||
b.SetBlock(ret)
|
b.SetBlock(ret)
|
||||||
p.vals = make(map[ssa.Value]llssa.Expr)
|
p.bvals = make(map[ssa.Value]llssa.Expr)
|
||||||
for _, instr := range block.Instrs {
|
for _, instr := range block.Instrs {
|
||||||
p.compileInstr(b, instr)
|
p.compileInstr(b, instr)
|
||||||
}
|
}
|
||||||
@@ -84,17 +95,26 @@ func (p *context) compileBlock(b llssa.Builder, block *ssa.BasicBlock) llssa.Bas
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (p *context) compileInstrAndValue(b llssa.Builder, iv instrAndValue) (ret llssa.Expr) {
|
func (p *context) compileInstrAndValue(b llssa.Builder, iv instrAndValue) (ret llssa.Expr) {
|
||||||
if v, ok := p.vals[iv]; ok {
|
if v, ok := p.bvals[iv]; ok {
|
||||||
return v
|
return v
|
||||||
}
|
}
|
||||||
switch v := iv.(type) {
|
switch v := iv.(type) {
|
||||||
|
case *ssa.Call:
|
||||||
|
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)
|
||||||
|
ret = b.BinOp(v.Op, x, y)
|
||||||
case *ssa.UnOp:
|
case *ssa.UnOp:
|
||||||
x := p.compileValue(b, v.X)
|
x := p.compileValue(b, v.X)
|
||||||
ret = b.UnOp(v.Op, x)
|
ret = b.UnOp(v.Op, x)
|
||||||
default:
|
default:
|
||||||
panic(fmt.Sprintf("compileInstrAndValue: unknown instr - %T\n", iv))
|
panic(fmt.Sprintf("compileInstrAndValue: unknown instr - %T\n", iv))
|
||||||
}
|
}
|
||||||
p.vals[iv] = ret
|
p.bvals[iv] = ret
|
||||||
return ret
|
return ret
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -139,14 +159,31 @@ func (p *context) compileValue(b llssa.Builder, v ssa.Value) llssa.Expr {
|
|||||||
return p.compileInstrAndValue(b, iv)
|
return p.compileInstrAndValue(b, iv)
|
||||||
}
|
}
|
||||||
switch v := v.(type) {
|
switch v := v.(type) {
|
||||||
|
case *ssa.Parameter:
|
||||||
|
fn := v.Parent()
|
||||||
|
for idx, param := range fn.Params {
|
||||||
|
if param == v {
|
||||||
|
return p.fn.Param(idx)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
case *ssa.Function:
|
||||||
|
fn := p.compileFunc(p.pkg, v)
|
||||||
|
return fn.Expr
|
||||||
case *ssa.Global:
|
case *ssa.Global:
|
||||||
g := p.compileGlobal(p.pkg, v)
|
g := p.compileGlobal(p.pkg, v)
|
||||||
return g.Expr
|
return g.Expr
|
||||||
case *ssa.Const:
|
case *ssa.Const:
|
||||||
return b.Const(v.Value, v.Type())
|
return b.Const(v.Value, v.Type())
|
||||||
default:
|
|
||||||
panic(fmt.Sprintf("compileValue: unknown value - %T\n", v))
|
|
||||||
}
|
}
|
||||||
|
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)
|
||||||
|
}
|
||||||
|
return ret
|
||||||
}
|
}
|
||||||
|
|
||||||
// -----------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------
|
||||||
@@ -177,6 +214,7 @@ func NewPackage(prog llssa.Program, pkg *ssa.Package, conf *Config) (ret llssa.P
|
|||||||
ctx := &context{
|
ctx := &context{
|
||||||
prog: prog,
|
prog: prog,
|
||||||
pkg: ret,
|
pkg: ret,
|
||||||
|
fns: make(map[*ssa.Function]llssa.Function),
|
||||||
glbs: make(map[*ssa.Global]llssa.Global),
|
glbs: make(map[*ssa.Global]llssa.Global),
|
||||||
}
|
}
|
||||||
for _, m := range members {
|
for _, m := range members {
|
||||||
|
|||||||
@@ -22,7 +22,10 @@ import (
|
|||||||
"go/parser"
|
"go/parser"
|
||||||
"go/token"
|
"go/token"
|
||||||
"go/types"
|
"go/types"
|
||||||
|
"log"
|
||||||
"os"
|
"os"
|
||||||
|
"path"
|
||||||
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
llssa "github.com/goplus/llgo/ssa"
|
llssa "github.com/goplus/llgo/ssa"
|
||||||
@@ -30,14 +33,55 @@ import (
|
|||||||
"golang.org/x/tools/go/ssa/ssautil"
|
"golang.org/x/tools/go/ssa/ssautil"
|
||||||
)
|
)
|
||||||
|
|
||||||
func testCompile(t *testing.T, src, expected string) {
|
func TestFromTestdata(t *testing.T) {
|
||||||
|
testFromDir(t, "", "./_testdata")
|
||||||
|
}
|
||||||
|
|
||||||
|
func testFromDir(t *testing.T, sel, relDir string) {
|
||||||
|
dir, err := os.Getwd()
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal("Getwd failed:", err)
|
||||||
|
}
|
||||||
|
dir = path.Join(dir, relDir)
|
||||||
|
fis, err := os.ReadDir(dir)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal("ReadDir failed:", err)
|
||||||
|
}
|
||||||
|
for _, fi := range fis {
|
||||||
|
name := fi.Name()
|
||||||
|
if !fi.IsDir() || strings.HasPrefix(name, "_") {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
t.Run(name, func(t *testing.T) {
|
||||||
|
testFrom(t, dir+"/"+name, sel)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func testFrom(t *testing.T, pkgDir, sel string) {
|
||||||
|
if sel != "" && !strings.Contains(pkgDir, sel) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
log.Println("Parsing", pkgDir)
|
||||||
|
in := pkgDir + "/in.go"
|
||||||
|
out := pkgDir + "/out.ll"
|
||||||
|
expected, err := os.ReadFile(out)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal("ReadFile failed:", err)
|
||||||
|
}
|
||||||
|
testCompileEx(t, nil, in, string(expected))
|
||||||
|
}
|
||||||
|
|
||||||
|
func testCompileEx(t *testing.T, src any, fname, expected string) {
|
||||||
|
t.Helper()
|
||||||
fset := token.NewFileSet()
|
fset := token.NewFileSet()
|
||||||
f, err := parser.ParseFile(fset, "foo.go", src, parser.ParseComments)
|
f, err := parser.ParseFile(fset, fname, src, parser.ParseComments)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal("ParseFile failed:", err)
|
t.Fatal("ParseFile failed:", err)
|
||||||
}
|
}
|
||||||
files := []*ast.File{f}
|
files := []*ast.File{f}
|
||||||
pkg := types.NewPackage("foo", "foo")
|
name := f.Name.Name
|
||||||
|
pkg := types.NewPackage(name, name)
|
||||||
foo, _, err := ssautil.BuildPackage(
|
foo, _, err := ssautil.BuildPackage(
|
||||||
&types.Config{Importer: importer.Default()}, fset, pkg, files, ssa.SanityCheckFunctions)
|
&types.Config{Importer: importer.Default()}, fset, pkg, files, ssa.SanityCheckFunctions)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -59,6 +103,11 @@ func testCompile(t *testing.T, src, expected string) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func testCompile(t *testing.T, src, expected string) {
|
||||||
|
t.Helper()
|
||||||
|
testCompileEx(t, src, "foo.go", expected)
|
||||||
|
}
|
||||||
|
|
||||||
func TestVar(t *testing.T) {
|
func TestVar(t *testing.T) {
|
||||||
testCompile(t, `package foo
|
testCompile(t, `package foo
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user