TestFuncCall
This commit is contained in:
@@ -42,11 +42,7 @@ func (b Builder) Return(results ...Expr) Builder {
|
||||
case 1:
|
||||
b.impl.CreateRet(results[0].impl)
|
||||
default:
|
||||
rets := make([]llvm.Value, n)
|
||||
for i, v := range results {
|
||||
rets[i] = v.impl
|
||||
}
|
||||
b.impl.CreateAggregateRet(rets)
|
||||
b.impl.CreateAggregateRet(llvmValues(results))
|
||||
}
|
||||
return b
|
||||
}
|
||||
|
||||
34
ssa/decl.go
34
ssa/decl.go
@@ -103,29 +103,39 @@ type Global = *aGlobal
|
||||
// the generic method. TypeArgs() refers to [string,U] or [string,int],
|
||||
// respectively, and is nil in the generic method.
|
||||
type aFunction struct {
|
||||
impl llvm.Value
|
||||
Type
|
||||
|
||||
Expr
|
||||
prog Program
|
||||
|
||||
params []Type
|
||||
ret Type
|
||||
}
|
||||
|
||||
type Function = *aFunction
|
||||
|
||||
func newFunction(fn llvm.Value, t Type, prog Program) Function {
|
||||
ret := &aFunction{fn, t, prog, newParams(t, prog)}
|
||||
return ret
|
||||
params, ret := newParamsAndRet(t, prog)
|
||||
return &aFunction{Expr{fn, t}, prog, params, ret}
|
||||
}
|
||||
|
||||
func newParams(fn Type, prog Program) []Type {
|
||||
in := fn.t.(*types.Signature).Params()
|
||||
n := in.Len()
|
||||
ret := make([]Type, n)
|
||||
for i := 0; i < n; i++ {
|
||||
ret[i] = prog.llvmType(in.At(i).Type())
|
||||
func newParamsAndRet(fn Type, prog Program) (params []Type, ret Type) {
|
||||
sig := fn.t.(*types.Signature)
|
||||
in := sig.Params()
|
||||
if n := in.Len(); n > 0 {
|
||||
params = make([]Type, n)
|
||||
for i := 0; i < n; i++ {
|
||||
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 {
|
||||
|
||||
63
ssa/expr.go
63
ssa/expr.go
@@ -18,37 +18,51 @@ package ssa
|
||||
|
||||
import (
|
||||
"go/token"
|
||||
"go/types"
|
||||
|
||||
"github.com/goplus/llvm"
|
||||
)
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
type valueKind = int
|
||||
|
||||
type Expr struct {
|
||||
impl llvm.Value
|
||||
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 (
|
||||
mathOpBase = token.ADD
|
||||
mathOpLast = token.REM
|
||||
)
|
||||
|
||||
const (
|
||||
vkInvalid valueKind = iota
|
||||
vkSigned
|
||||
vkUnsigned
|
||||
vkFloat
|
||||
vkComplex
|
||||
vkString
|
||||
vkBool
|
||||
vkFunc
|
||||
)
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
var mathOpToLLVM = []llvm.Opcode{
|
||||
int(token.ADD-mathOpBase)<<2 | vkSigned: 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 {
|
||||
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}
|
||||
func (b Builder) Call(fn Expr, args ...Expr) (ret Expr) {
|
||||
switch t := fn.t.(type) {
|
||||
case *types.Signature:
|
||||
ret.Type = b.prog.retType(t)
|
||||
default:
|
||||
panic("todo")
|
||||
}
|
||||
panic("todo")
|
||||
ret.impl = llvm.CreateCall(b.impl, fn.ll, fn.impl, llvmValues(args))
|
||||
return
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
@@ -24,6 +24,51 @@ import (
|
||||
"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.
|
||||
type aProgram struct {
|
||||
ctx llvm.Context
|
||||
@@ -42,6 +87,7 @@ type aProgram struct {
|
||||
voidType llvm.Type
|
||||
voidPtrTy llvm.Type
|
||||
|
||||
voidTy Type
|
||||
boolTy Type
|
||||
intTy Type
|
||||
f64Ty Type
|
||||
@@ -65,6 +111,13 @@ func (p Program) NewPackage(name, pkgPath string) Package {
|
||||
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 {
|
||||
if p.boolTy == nil {
|
||||
p.boolTy = p.llvmType(types.Typ[types.Bool])
|
||||
@@ -86,6 +139,8 @@ func (p Program) Float64() Type {
|
||||
return p.f64Ty
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
// A Package is a single analyzed Go package containing Members for
|
||||
// all package-level functions, variables, constants and types it
|
||||
// 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)
|
||||
}
|
||||
*/
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
@@ -22,6 +22,10 @@ import (
|
||||
"testing"
|
||||
)
|
||||
|
||||
func init() {
|
||||
Initialize(InitAll)
|
||||
}
|
||||
|
||||
/*
|
||||
func asmPkg(t *testing.T, p *Package) {
|
||||
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) {
|
||||
prog := NewProgram(nil)
|
||||
pkg := prog.NewPackage("bar", "foo/bar")
|
||||
|
||||
@@ -16,17 +16,7 @@
|
||||
|
||||
package ssa
|
||||
|
||||
import (
|
||||
"github.com/goplus/llvm"
|
||||
)
|
||||
|
||||
func init() {
|
||||
llvm.InitializeAllTargetInfos()
|
||||
llvm.InitializeAllTargets()
|
||||
llvm.InitializeAllTargetMCs()
|
||||
llvm.InitializeAllAsmParsers()
|
||||
llvm.InitializeAllAsmPrinters()
|
||||
}
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
type Target struct {
|
||||
GOOS string
|
||||
@@ -150,3 +140,5 @@ func (p *Target) toSpec() (spec targetSpec) {
|
||||
return
|
||||
}
|
||||
*/
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
36
ssa/type.go
36
ssa/type.go
@@ -24,6 +24,22 @@ import (
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
type valueKind = int
|
||||
|
||||
const (
|
||||
vkInvalid valueKind = iota
|
||||
vkSigned
|
||||
vkUnsigned
|
||||
vkFloat
|
||||
vkComplex
|
||||
vkString
|
||||
vkBool
|
||||
vkFunc
|
||||
vkTuple
|
||||
)
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
type aType struct {
|
||||
ll llvm.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 {
|
||||
params := p.toLLVMTypes(sig.Params())
|
||||
results := sig.Results()
|
||||
out := sig.Results()
|
||||
var ret llvm.Type
|
||||
switch nret := results.Len(); nret {
|
||||
switch nret := out.Len(); nret {
|
||||
case 0:
|
||||
ret = p.tyVoid()
|
||||
case 1:
|
||||
ret = p.llvmType(results.At(0).Type()).ll
|
||||
ret = p.llvmType(out.At(0).Type()).ll
|
||||
default:
|
||||
ret = p.toLLVMTuple(results)
|
||||
ret = p.toLLVMTuple(out)
|
||||
}
|
||||
ft := llvm.FunctionType(ret, params, sig.Variadic())
|
||||
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 {
|
||||
name := typ.Obj().Name()
|
||||
switch typ := typ.Underlying().(type) {
|
||||
|
||||
Reference in New Issue
Block a user