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:
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
}

View File

@@ -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 {

View File

@@ -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
}
// -----------------------------------------------------------------------------

View File

@@ -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)
}
*/
// -----------------------------------------------------------------------------

View File

@@ -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")

View File

@@ -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
}
*/
// -----------------------------------------------------------------------------

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 {
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) {