TestFuncCall

This commit is contained in:
xushiwei
2024-04-19 00:05:57 +08:00
parent a966e02273
commit c784a2e63b
7 changed files with 188 additions and 58 deletions

View File

@@ -42,11 +42,7 @@ func (b Builder) Return(results ...Expr) Builder {
case 1: case 1:
b.impl.CreateRet(results[0].impl) b.impl.CreateRet(results[0].impl)
default: default:
rets := make([]llvm.Value, n) b.impl.CreateAggregateRet(llvmValues(results))
for i, v := range results {
rets[i] = v.impl
}
b.impl.CreateAggregateRet(rets)
} }
return b return b
} }

View File

@@ -103,29 +103,39 @@ type Global = *aGlobal
// the generic method. TypeArgs() refers to [string,U] or [string,int], // the generic method. TypeArgs() refers to [string,U] or [string,int],
// respectively, and is nil in the generic method. // respectively, and is nil in the generic method.
type aFunction struct { type aFunction struct {
impl llvm.Value Expr
Type
prog Program prog Program
params []Type params []Type
ret Type
} }
type Function = *aFunction type Function = *aFunction
func newFunction(fn llvm.Value, t Type, prog Program) Function { func newFunction(fn llvm.Value, t Type, prog Program) Function {
ret := &aFunction{fn, t, prog, newParams(t, prog)} params, ret := newParamsAndRet(t, prog)
return ret return &aFunction{Expr{fn, t}, prog, params, ret}
} }
func newParams(fn Type, prog Program) []Type { func newParamsAndRet(fn Type, prog Program) (params []Type, ret Type) {
in := fn.t.(*types.Signature).Params() sig := fn.t.(*types.Signature)
n := in.Len() in := sig.Params()
ret := make([]Type, n) if n := in.Len(); n > 0 {
params = make([]Type, n)
for i := 0; i < n; i++ { for i := 0; i < n; i++ {
ret[i] = prog.llvmType(in.At(i).Type()) params[i] = prog.llvmType(in.At(i).Type())
} }
return ret }
out := sig.Results()
switch n := out.Len(); n {
case 0:
ret = prog.Void()
case 1:
ret = prog.llvmType(out.At(0).Type())
default:
ret = &aType{prog.toLLVMTuple(out), out, vkTuple}
}
return
} }
func (p Function) Param(i int) Expr { func (p Function) Param(i int) Expr {

View File

@@ -18,37 +18,51 @@ package ssa
import ( import (
"go/token" "go/token"
"go/types"
"github.com/goplus/llvm" "github.com/goplus/llvm"
) )
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
type valueKind = int
type Expr struct { type Expr struct {
impl llvm.Value impl llvm.Value
Type Type
} }
// -----------------------------------------------------------------------------
func llvmValues(vals []Expr) []llvm.Value {
ret := make([]llvm.Value, len(vals))
for i, v := range vals {
ret[i] = v.impl
}
return ret
}
// -----------------------------------------------------------------------------
func (p Program) Val(v interface{}) Expr {
switch v := v.(type) {
case int:
t := p.Int()
ret := llvm.ConstInt(t.ll, uint64(v), false)
return Expr{ret, t}
case float64:
t := p.Float64()
ret := llvm.ConstFloat(t.ll, v)
return Expr{ret, t}
}
panic("todo")
}
// -----------------------------------------------------------------------------
const ( const (
mathOpBase = token.ADD mathOpBase = token.ADD
mathOpLast = token.REM mathOpLast = token.REM
) )
const (
vkInvalid valueKind = iota
vkSigned
vkUnsigned
vkFloat
vkComplex
vkString
vkBool
vkFunc
)
// -----------------------------------------------------------------------------
var mathOpToLLVM = []llvm.Opcode{ var mathOpToLLVM = []llvm.Opcode{
int(token.ADD-mathOpBase)<<2 | vkSigned: llvm.Add, int(token.ADD-mathOpBase)<<2 | vkSigned: llvm.Add,
int(token.ADD-mathOpBase)<<2 | vkUnsigned: llvm.Add, int(token.ADD-mathOpBase)<<2 | vkUnsigned: llvm.Add,
@@ -183,18 +197,15 @@ func (b Builder) BinOp(op token.Token, x, y Expr) Expr {
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
func (p Program) Val(v interface{}) Expr { func (b Builder) Call(fn Expr, args ...Expr) (ret Expr) {
switch v := v.(type) { switch t := fn.t.(type) {
case int: case *types.Signature:
t := p.Int() ret.Type = b.prog.retType(t)
ret := llvm.ConstInt(t.ll, uint64(v), false) default:
return Expr{ret, t}
case float64:
t := p.Float64()
ret := llvm.ConstFloat(t.ll, v)
return Expr{ret, t}
}
panic("todo") panic("todo")
} }
ret.impl = llvm.CreateCall(b.impl, fn.ll, fn.impl, llvmValues(args))
return
}
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------

View File

@@ -24,6 +24,51 @@ import (
"golang.org/x/tools/go/types/typeutil" "golang.org/x/tools/go/types/typeutil"
) )
// -----------------------------------------------------------------------------
type InitFlags int
const (
InitNativeTarget InitFlags = 1 << iota
InitAllTargets
InitAllTargetInfos
InitAllTargetMCs
InitNativeAsmPrinter
InitAllAsmPrinters
InitAllAsmParsers
InitNative = InitNativeTarget | InitNativeAsmPrinter
InitAll = InitAllTargets | InitAllAsmParsers | InitAllAsmPrinters | InitAllTargetInfos | InitAllTargetMCs
)
func Initialize(flags InitFlags) {
if flags&InitAllTargetInfos != 0 {
llvm.InitializeAllTargetInfos()
}
if flags&InitAllTargets != 0 {
llvm.InitializeAllTargets()
}
if flags&InitAllTargetMCs != 0 {
llvm.InitializeAllTargetMCs()
}
if flags&InitAllAsmParsers != 0 {
llvm.InitializeAllAsmParsers()
}
if flags&InitAllAsmPrinters != 0 {
llvm.InitializeAllAsmPrinters()
}
if flags&InitNativeTarget != 0 {
llvm.InitializeNativeTarget()
}
if flags&InitNativeAsmPrinter != 0 {
llvm.InitializeNativeAsmPrinter()
}
}
// -----------------------------------------------------------------------------
// A Program is a partial or complete Go program converted to SSA form. // A Program is a partial or complete Go program converted to SSA form.
type aProgram struct { type aProgram struct {
ctx llvm.Context ctx llvm.Context
@@ -42,6 +87,7 @@ type aProgram struct {
voidType llvm.Type voidType llvm.Type
voidPtrTy llvm.Type voidPtrTy llvm.Type
voidTy Type
boolTy Type boolTy Type
intTy Type intTy Type
f64Ty Type f64Ty Type
@@ -65,6 +111,13 @@ func (p Program) NewPackage(name, pkgPath string) Package {
return &aPackage{mod, p} return &aPackage{mod, p}
} }
func (p Program) Void() Type {
if p.voidTy == nil {
p.voidTy = &aType{p.tyVoid(), types.Typ[types.Invalid], vkInvalid}
}
return p.voidTy
}
func (p Program) Bool() Type { func (p Program) Bool() Type {
if p.boolTy == nil { if p.boolTy == nil {
p.boolTy = p.llvmType(types.Typ[types.Bool]) p.boolTy = p.llvmType(types.Typ[types.Bool])
@@ -86,6 +139,8 @@ func (p Program) Float64() Type {
return p.f64Ty return p.f64Ty
} }
// -----------------------------------------------------------------------------
// A Package is a single analyzed Go package containing Members for // A Package is a single analyzed Go package containing Members for
// all package-level functions, variables, constants and types it // all package-level functions, variables, constants and types it
// declares. These may be accessed directly via Members, or via the // declares. These may be accessed directly via Members, or via the
@@ -160,3 +215,5 @@ func (p *Package) WriteFile(file string) (err error) {
return llvm.WriteBitcodeToFile(p.mod, f) return llvm.WriteBitcodeToFile(p.mod, f)
} }
*/ */
// -----------------------------------------------------------------------------

View File

@@ -22,6 +22,10 @@ import (
"testing" "testing"
) )
func init() {
Initialize(InitAll)
}
/* /*
func asmPkg(t *testing.T, p *Package) { func asmPkg(t *testing.T, p *Package) {
b, err := p.CodeGen(AssemblyFile) b, err := p.CodeGen(AssemblyFile)
@@ -131,6 +135,38 @@ define i64 @fn(i64 %0, double %1) {
`) `)
} }
func TestFuncCall(t *testing.T) {
prog := NewProgram(nil)
pkg := prog.NewPackage("bar", "foo/bar")
params := types.NewTuple(
types.NewVar(0, nil, "a", types.Typ[types.Int]),
types.NewVar(0, nil, "b", types.Typ[types.Float64]))
rets := types.NewTuple(types.NewVar(0, nil, "", types.Typ[types.Int]))
sig := types.NewSignatureType(nil, nil, nil, params, rets, false)
fn := pkg.NewFunc("fn", sig)
fn.MakeBody("").
Return(prog.Val(1))
sigMain := types.NewSignatureType(nil, nil, nil, nil, nil, false)
b := pkg.NewFunc("main", sigMain).MakeBody("")
b.Call(fn.Expr, prog.Val(1), prog.Val(1.2))
b.Return()
assertPkg(t, pkg, `; ModuleID = 'foo/bar'
source_filename = "foo/bar"
define i64 @fn(i64 %0, double %1) {
ret i64 1
}
define void @main() {
%1 = call i64 @fn(i64 1, double 1.200000e+00)
ret void
}
`)
}
func TestBinOp(t *testing.T) { func TestBinOp(t *testing.T) {
prog := NewProgram(nil) prog := NewProgram(nil)
pkg := prog.NewPackage("bar", "foo/bar") pkg := prog.NewPackage("bar", "foo/bar")

View File

@@ -16,17 +16,7 @@
package ssa package ssa
import ( // -----------------------------------------------------------------------------
"github.com/goplus/llvm"
)
func init() {
llvm.InitializeAllTargetInfos()
llvm.InitializeAllTargets()
llvm.InitializeAllTargetMCs()
llvm.InitializeAllAsmParsers()
llvm.InitializeAllAsmPrinters()
}
type Target struct { type Target struct {
GOOS string GOOS string
@@ -150,3 +140,5 @@ func (p *Target) toSpec() (spec targetSpec) {
return return
} }
*/ */
// -----------------------------------------------------------------------------

View File

@@ -24,6 +24,22 @@ import (
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
type valueKind = int
const (
vkInvalid valueKind = iota
vkSigned
vkUnsigned
vkFloat
vkComplex
vkString
vkBool
vkFunc
vkTuple
)
// -----------------------------------------------------------------------------
type aType struct { type aType struct {
ll llvm.Type ll llvm.Type
t types.Type t types.Type
@@ -204,20 +220,32 @@ func (p Program) toLLVMTypes(t *types.Tuple) []llvm.Type {
func (p Program) toLLVMFunc(sig *types.Signature) Type { func (p Program) toLLVMFunc(sig *types.Signature) Type {
params := p.toLLVMTypes(sig.Params()) params := p.toLLVMTypes(sig.Params())
results := sig.Results() out := sig.Results()
var ret llvm.Type var ret llvm.Type
switch nret := results.Len(); nret { switch nret := out.Len(); nret {
case 0: case 0:
ret = p.tyVoid() ret = p.tyVoid()
case 1: case 1:
ret = p.llvmType(results.At(0).Type()).ll ret = p.llvmType(out.At(0).Type()).ll
default: default:
ret = p.toLLVMTuple(results) ret = p.toLLVMTuple(out)
} }
ft := llvm.FunctionType(ret, params, sig.Variadic()) ft := llvm.FunctionType(ret, params, sig.Variadic())
return &aType{ft, sig, vkFunc} return &aType{ft, sig, vkFunc}
} }
func (p Program) retType(sig *types.Signature) Type {
out := sig.Results()
switch n := out.Len(); n {
case 0:
return p.Void()
case 1:
return p.llvmType(out.At(0).Type())
default:
return &aType{p.toLLVMTuple(out), out, vkTuple}
}
}
func (p Program) toLLVMNamed(typ *types.Named) Type { func (p Program) toLLVMNamed(typ *types.Named) Type {
name := typ.Obj().Name() name := typ.Obj().Name()
switch typ := typ.Underlying().(type) { switch typ := typ.Underlying().(type) {