TestFuncCall
This commit is contained in:
@@ -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
|
||||||
}
|
}
|
||||||
|
|||||||
32
ssa/decl.go
32
ssa/decl.go
@@ -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 {
|
||||||
|
|||||||
63
ssa/expr.go
63
ssa/expr.go
@@ -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
|
||||||
|
}
|
||||||
|
|
||||||
// -----------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------
|
||||||
|
|||||||
@@ -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)
|
||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
// -----------------------------------------------------------------------------
|
||||||
|
|||||||
@@ -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")
|
||||||
|
|||||||
@@ -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
|
||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
// -----------------------------------------------------------------------------
|
||||||
|
|||||||
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 {
|
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) {
|
||||||
|
|||||||
Reference in New Issue
Block a user