提交 5ba98d1a 编写于 作者: 3 3dgen

Merge branch 'backend_wasm'

// 版权 @2021 凹语言 作者。保留所有权利。
package compiler_wasm
import (
"github.com/wa-lang/wa/internal/backends/compiler_wasm/wir"
"github.com/wa-lang/wa/internal/backends/compiler_wasm/wir/wtypes"
"github.com/wa-lang/wa/internal/loader"
"github.com/wa-lang/wa/internal/ssa"
)
type Compiler struct {
ssaPkg *ssa.Package
module wir.Module
}
func New() *Compiler {
p := new(Compiler)
return p
}
func (p *Compiler) Compile(prog *loader.Program) (output string, err error) {
p.CompilePackage(prog.SSAMainPkg)
return p.String(), nil
}
func (p *Compiler) CompilePackage(ssaPkg *ssa.Package) {
p.ssaPkg = ssaPkg
var ts []*ssa.Type
var cs []*ssa.NamedConst
var gs []*ssa.Global
var fns []*ssa.Function
{
var sig wir.FuncSig
sig.Params = append(sig.Params, wtypes.Int32{})
p.module.Imports = append(p.module.Imports, wir.NewImpFunc("js", "print_i32", "$$print_i32", sig))
p.module.Imports = append(p.module.Imports, wir.NewImpFunc("js", "print_char", "$$print_char", sig))
}
for _, m := range p.ssaPkg.Members {
switch member := m.(type) {
case *ssa.Type:
ts = append(ts, member)
case *ssa.NamedConst:
cs = append(cs, member)
case *ssa.Global:
gs = append(gs, member)
case *ssa.Function:
//fns = append(fns, member)
default:
panic("Unreachable")
}
}
for _, v := range ts {
p.compileType(v)
}
for _, v := range cs {
p.compileConst(v)
}
for _, v := range gs {
p.compileGlobal(v)
}
for _, v := range ssaPkg.GetValues() {
if f, ok := v.(*ssa.Function); ok {
found := false
for _, m := range fns {
if m.Object() == f.Object() {
found = true
}
}
if found {
continue
}
fns = append(fns, f)
}
}
for _, v := range fns {
p.module.Funcs = append(p.module.Funcs, newFunctionGenerator(p).genFunction(v))
}
println(p.module.String())
}
func (p *Compiler) String() string {
return ""
}
// 版权 @2021 凹语言 作者。保留所有权利。
package compiler_wasm
import (
"github.com/wa-lang/wa/internal/logger"
"github.com/wa-lang/wa/internal/ssa"
)
func (p *Compiler) compileConst(c *ssa.NamedConst) {
logger.Fatal("Todo")
}
// 版权 @2021 凹语言 作者。保留所有权利。
package compiler_wasm
import (
"strconv"
"github.com/wa-lang/wa/internal/constant"
"github.com/wa-lang/wa/internal/token"
"github.com/wa-lang/wa/internal/types"
"github.com/wa-lang/wa/internal/backends/compiler_wasm/wir"
"github.com/wa-lang/wa/internal/backends/compiler_wasm/wir/wtypes"
"github.com/wa-lang/wa/internal/logger"
"github.com/wa-lang/wa/internal/ssa"
)
type functionGenerator struct {
module *wir.Module
locals_map map[ssa.Value]wir.Value
registers []wir.Value
cur_local_id int
var_block_selector wir.Value
var_current_block wir.Value
var_ret wir.Value
}
func newFunctionGenerator(p *Compiler) *functionGenerator {
return &functionGenerator{module: &p.module, locals_map: make(map[ssa.Value]wir.Value)}
}
func (g *functionGenerator) getValue(i ssa.Value) wir.Value {
if i == nil {
return nil
}
if v, ok := g.locals_map[i]; ok {
return v
}
switch v := i.(type) {
case *ssa.Const:
switch t := v.Type().(type) {
case *types.Basic:
switch t.Kind() {
case types.Bool:
logger.Fatalf("Todo:%T", t)
case types.Int:
val, _ := constant.Int64Val(v.Value)
return wir.NewConstI32(int32(val))
case types.Float32:
logger.Fatalf("Todo:%T", t)
case types.Float64:
logger.Fatalf("Todo:%T", t)
case types.String, types.UntypedString:
logger.Fatalf("Todo:%T", t)
default:
logger.Fatalf("Todo:%T", t)
}
case *types.Slice:
logger.Fatalf("Todo:%T", t)
default:
logger.Fatalf("Todo:%T", t)
}
case ssa.Instruction:
nv := g.addRegister(wir.ToWType(i.Type()))
g.locals_map[i] = nv
return nv
}
logger.Fatal("Value not found:", i)
return nil
}
func (g *functionGenerator) genFunction(f *ssa.Function) *wir.Function {
var wir_fn wir.Function
wir_fn.Name = f.Name()
rets := f.Signature.Results()
wir_fn.Result = wir.ToWType(rets)
if rets.Len() > 1 {
logger.Fatal("Todo")
}
for _, i := range f.Params {
pa := wir.NewVar(i.Name(), wir.ValueKindLocal, wir.ToWType(i.Type()))
wir_fn.Params = append(wir_fn.Params, pa)
g.locals_map[i] = pa
}
g.var_block_selector = wir.NewVar("$$block_selector", wir.ValueKindLocal, wtypes.Int32{})
g.registers = append(g.registers, g.var_block_selector)
wir_fn.Insts = append(wir_fn.Insts, wir.EmitAssginValue(g.var_block_selector, nil)...)
g.var_current_block = wir.NewVar("$$current_block", wir.ValueKindLocal, wtypes.Int32{})
g.registers = append(g.registers, g.var_current_block)
wir_fn.Insts = append(wir_fn.Insts, wir.EmitAssginValue(g.var_current_block, nil)...)
if !wir_fn.Result.Equal(wtypes.Void{}) {
g.var_ret = wir.NewVar("$$ret", wir.ValueKindLocal, wir_fn.Result)
g.registers = append(g.registers, g.var_ret)
wir_fn.Insts = append(wir_fn.Insts, wir.EmitAssginValue(g.var_ret, nil)...)
}
var block_temp wir.Instruction
//BlockSel:
{
inst := wir.NewInstBlock("$$BlockSel")
inst.Insts = append(inst.Insts, wir.EmitPushValue(g.var_block_selector)...)
t := make([]int, len(f.Blocks)+1)
for i := range f.Blocks {
t[i] = i
}
t[len(f.Blocks)] = 0
inst.Insts = append(inst.Insts, wir.NewInstBrTable(t))
block_temp = inst
}
for i, b := range f.Blocks {
block := wir.NewInstBlock("$$Block_" + strconv.Itoa(i))
block.Insts = append(block.Insts, block_temp)
block.Insts = append(block.Insts, g.genBlock(b)...)
block_temp = block
}
//BlockDisp
{
inst := wir.NewInstLoop("$$BlockDisp")
inst.Insts = append(inst.Insts, block_temp)
block_temp = inst
}
//BlockFnBody
{
inst := wir.NewInstBlock("$$BlockFnBody")
inst.Insts = append(inst.Insts, block_temp)
block_temp = inst
}
wir_fn.Insts = append(wir_fn.Insts, block_temp)
wir_fn.Locals = g.registers
return &wir_fn
}
func (g *functionGenerator) genBlock(block *ssa.BasicBlock) []wir.Instruction {
if len(block.Instrs) == 0 {
logger.Fatalf("Block:%s is empty", block)
}
cur_block_assigned := false
var b []wir.Instruction
for _, inst := range block.Instrs {
if _, ok := inst.(*ssa.Phi); !ok {
if !cur_block_assigned {
b = append(b, wir.EmitAssginValue(g.var_current_block, wir.NewConstI32(int32(block.Index)))...)
cur_block_assigned = true
}
}
b = append(b, g.genInstruction(inst)...)
}
return b
}
func (g *functionGenerator) genInstruction(inst ssa.Instruction) []wir.Instruction {
switch inst := inst.(type) {
case *ssa.Alloc:
logger.Fatalf("Todo:%T", inst)
case *ssa.If:
return g.genIf(inst)
case *ssa.Store:
logger.Fatalf("Todo:%T", inst)
case *ssa.Jump:
return g.genJump(inst)
case *ssa.Return:
return g.genReturn(inst)
case *ssa.Extract:
logger.Fatalf("Todo:%T", inst)
case *ssa.Field:
logger.Fatalf("Todo:%T", inst)
case ssa.Value:
s, t := g.genValue(inst)
if !t.Equal(wtypes.Void{}) {
v := g.getValue(inst)
s = append(s, wir.EmitPopValue(v)...)
g.locals_map[inst] = v
}
return s
default:
logger.Fatal("Todo:", inst.String())
}
return nil
}
func (g *functionGenerator) genValue(v ssa.Value) ([]wir.Instruction, wtypes.ValueType) {
if _, ok := g.locals_map[v]; ok {
logger.Printf("Instruction already exist:%s\n", v)
}
switch v := v.(type) {
case *ssa.UnOp:
logger.Fatalf("Todo: %v, type: %T", v, v)
case *ssa.BinOp:
return g.genBinOp(v)
case *ssa.Call:
return g.genCall(v)
case *ssa.Phi:
return g.genPhi(v)
case *ssa.FieldAddr:
logger.Fatalf("Todo: %v, type: %T", v, v)
case *ssa.IndexAddr:
logger.Fatalf("Todo: %v, type: %T", v, v)
case *ssa.Slice:
logger.Fatalf("Todo: %v, type: %T", v, v)
}
logger.Fatalf("Todo: %v, type: %T", v, v)
return nil, nil
}
func (g *functionGenerator) genBinOp(inst *ssa.BinOp) ([]wir.Instruction, wtypes.ValueType) {
x := g.getValue(inst.X)
y := g.getValue(inst.Y)
switch inst.X.Type().Underlying().(type) {
case *types.Basic:
switch inst.Op {
case token.ADD:
return wir.EmitBinOp(x, y, wir.OpCodeAdd)
case token.SUB:
return wir.EmitBinOp(x, y, wir.OpCodeSub)
case token.MUL:
return wir.EmitBinOp(x, y, wir.OpCodeMul)
case token.QUO:
return wir.EmitBinOp(x, y, wir.OpCodeQuo)
case token.REM:
return wir.EmitBinOp(x, y, wir.OpCodeRem)
case token.EQL:
return wir.EmitBinOp(x, y, wir.OpCodeEql)
case token.NEQ:
return wir.EmitBinOp(x, y, wir.OpCodeNe)
case token.LSS:
return wir.EmitBinOp(x, y, wir.OpCodeLt)
case token.GTR:
return wir.EmitBinOp(x, y, wir.OpCodeGt)
case token.LEQ:
return wir.EmitBinOp(x, y, wir.OpCodeLe)
case token.GEQ:
return wir.EmitBinOp(x, y, wir.OpCodeGe)
}
default:
logger.Fatalf("Todo: %v, type: %T, token:%v", inst, inst, inst.Op)
}
logger.Fatalf("Todo: %v, type: %T, token:%v", inst, inst, inst.Op)
return nil, nil
}
func (g *functionGenerator) genCall(inst *ssa.Call) ([]wir.Instruction, wtypes.ValueType) {
if inst.Call.IsInvoke() {
logger.Fatal("Todo: genCall(), Invoke")
}
switch inst.Call.Value.(type) {
case *ssa.Function:
ret_type := wir.ToWType(inst.Call.Signature().Results())
var insts []wir.Instruction
for _, v := range inst.Call.Args {
insts = append(insts, wir.EmitPushValue(g.getValue(v))...)
}
insts = append(insts, wir.NewInstCall(inst.Call.StaticCallee().Name()))
return insts, ret_type
case *ssa.Builtin:
return g.genBuiltin(inst.Common())
case *ssa.MakeClosure:
logger.Fatal("Todo: genCall(), MakeClosure")
default:
logger.Fatalf("Todo: type:%T", inst.Call.Value)
}
logger.Fatal("Todo")
return nil, nil
}
func (g *functionGenerator) genBuiltin(call *ssa.CallCommon) ([]wir.Instruction, wtypes.ValueType) {
switch call.Value.Name() {
case "print", "println":
var insts []wir.Instruction
for _, arg := range call.Args {
arg := g.getValue(arg)
switch arg.Type().(type) {
case wtypes.Int32:
insts = append(insts, wir.EmitPushValue(arg)...)
insts = append(insts, wir.NewInstCall("$$print_i32"))
default:
logger.Fatalf("Todo: print(%s)", arg.Type().Name())
}
}
if call.Value.Name() == "println" {
insts = append(insts, wir.EmitPushValue(wir.NewConstI32('\n'))...)
insts = append(insts, wir.NewInstCall("$$print_char"))
}
return insts, wtypes.Void{}
}
logger.Fatal("Todo:", call.Value)
return nil, nil
}
func (g *functionGenerator) genPhiIter(preds []int, values []wir.Value) []wir.Instruction {
var insts []wir.Instruction
cond, _ := wir.EmitBinOp(g.var_current_block, wir.NewConstI32(int32(preds[0])), wir.OpCodeEql)
insts = append(insts, cond...)
trueInsts := append([]wir.Instruction(nil), wir.EmitPushValue(values[0])...)
var falseInsts []wir.Instruction
if len(preds) == 2 {
falseInsts = append([]wir.Instruction(nil), wir.EmitPushValue(values[1])...)
} else {
falseInsts = append([]wir.Instruction(nil), g.genPhiIter(preds[1:], values[1:])...)
}
insts = append(insts, wir.NewInstIf(trueInsts, falseInsts, values[0].Type()))
return insts
}
func (g *functionGenerator) genPhi(inst *ssa.Phi) ([]wir.Instruction, wtypes.ValueType) {
var preds []int
var values []wir.Value
for i, v := range inst.Edges {
preds = append(preds, inst.Block().Preds[i].Index)
values = append(values, g.getValue(v))
}
return g.genPhiIter(preds, values), wir.ToWType(inst.Type())
}
func (g *functionGenerator) genReturn(inst *ssa.Return) []wir.Instruction {
var insts []wir.Instruction
switch len(inst.Results) {
case 0:
break
case 1:
insts = append(insts, wir.EmitAssginValue(g.var_ret, g.getValue(inst.Results[0]))...)
default:
logger.Fatal("Todo")
}
insts = append(insts, wir.NewInstBr("$$BlockFnBody"))
return insts
}
func (g *functionGenerator) genIf(inst *ssa.If) []wir.Instruction {
cond := g.getValue(inst.Cond)
if !cond.Type().Equal(wtypes.Int32{}) {
logger.Fatal("cond.type() != i32")
}
insts := wir.EmitPushValue(cond)
instsTrue := g.genJumpID(inst.Block().Index, inst.Block().Succs[0].Index)
instsFalse := g.genJumpID(inst.Block().Index, inst.Block().Succs[1].Index)
insts = append(insts, wir.NewInstIf(instsTrue, instsFalse, wtypes.Void{}))
return insts
}
func (g *functionGenerator) genJump(inst *ssa.Jump) []wir.Instruction {
return g.genJumpID(inst.Block().Index, inst.Block().Succs[0].Index)
}
func (g *functionGenerator) genJumpID(cur, dest int) []wir.Instruction {
var insts []wir.Instruction
if cur >= dest {
insts = wir.EmitAssginValue(g.var_block_selector, wir.NewConstI32(int32(dest)))
insts = append(insts, wir.NewInstBr("$$BlockDisp"))
} else {
insts = append(insts, wir.NewInstBr("$$Block_"+strconv.Itoa(dest-1)))
}
return insts
}
func (g *functionGenerator) addRegister(typ wtypes.ValueType) wir.Value {
defer func() { g.cur_local_id++ }()
name := "$$T_" + strconv.Itoa(g.cur_local_id)
v := wir.NewVar(name, wir.ValueKindLocal, typ)
g.registers = append(g.registers, v)
return v
}
// 版权 @2021 凹语言 作者。保留所有权利。
package compiler_wasm
import (
"github.com/wa-lang/wa/internal/ssa"
)
func (p *Compiler) compileGlobal(g *ssa.Global) {
//logger.Fatal("Todo")
}
// 版权 @2021 凹语言 作者。保留所有权利。
package compiler_wasm
import (
"github.com/wa-lang/wa/internal/logger"
"github.com/wa-lang/wa/internal/ssa"
)
func (p *Compiler) compileType(t *ssa.Type) {
logger.Fatal("Todo")
}
package wir
import "github.com/wa-lang/wa/internal/backends/compiler_wasm/wir/wtypes"
func (f *Function) Format(indent string) string {
s := indent + "(func $" + f.Name + " (export \"" + f.Name + "\")"
for _, param := range f.Params {
rps := param.Raw()
for _, rp := range rps {
s += " (param " + rp.Name() + " " + rp.Type().Name() + ")"
}
}
if !f.Result.Equal(wtypes.Void{}) {
s += " (result"
rrs := f.Result.Raw()
for _, rr := range rrs {
s += " " + rr.Name()
}
s += ")"
}
s += "\n"
for _, local := range f.Locals {
rls := local.Raw()
s += indent + " "
for _, rl := range rls {
s += " (local " + rl.Name() + " " + rl.Type().Name() + ")"
}
s += "\n"
}
for _, inst := range f.Insts {
s += inst.Format(indent+" ") + "\n"
}
s += indent + ") ;;" + f.Name
return s
}
func (sig *FuncSig) String() string {
str := ""
for _, param := range sig.Params {
rps := param.Raw()
for _, rp := range rps {
str += " (param " + rp.Name() + ")"
}
}
for _, ret := range sig.Results {
rrs := ret.Raw()
for _, rp := range rrs {
str += " (result " + rp.Name() + ")"
}
}
return str
}
package wir
/**************************************
ImpObj:
**************************************/
type ImpObj struct {
moduleName string
objName string
}
func (o *ImpObj) ModuleName() string { return o.moduleName }
func (o *ImpObj) ObjName() string { return o.objName }
/**************************************
ImpFunc:
**************************************/
type ImpFunc struct {
ImpObj
funcName string
sig FuncSig
}
func NewImpFunc(moduleName string, objName string, funcName string, sig FuncSig) *ImpFunc {
return &ImpFunc{ImpObj: ImpObj{moduleName: moduleName, objName: objName}, funcName: funcName, sig: sig}
}
func (o *ImpFunc) Type() ObjType { return ObjTypeFunc }
func (o *ImpFunc) Format(indent string) string {
return "(import \"" + o.moduleName + "\" \"" + o.objName + "\" (func " + o.funcName + o.sig.String() + "))"
}
package wir
import (
"strconv"
"github.com/wa-lang/wa/internal/backends/compiler_wasm/wir/wtypes"
"github.com/wa-lang/wa/internal/logger"
)
type anInstruction struct {
}
func (i *anInstruction) isInstruction() {}
/**************************************
InstConst:
**************************************/
type InstConst struct {
anInstruction
value Value
}
func NewInstConst(v Value) *InstConst {
if v.Kind() != ValueKindConst {
logger.Fatal("newInstructionConst()只能接受常数")
}
return &InstConst{value: v}
}
func (i *InstConst) Format(indent string) string {
switch i.value.Type().(type) {
case wtypes.Int32:
return indent + "i32.const " + i.value.Name()
case wtypes.Int64:
return indent + "i64.const " + i.value.Name()
}
logger.Fatalf("Todo %T", i.value.Type())
return ""
}
/**************************************
InstGetLocal:
**************************************/
type InstGetLocal struct {
anInstruction
name string
}
func NewInstGetLocal(name string) *InstGetLocal { return &InstGetLocal{name: name} }
func (i *InstGetLocal) Format(indent string) string { return indent + "local.get " + i.name }
/**************************************
instSetLocal:
**************************************/
type InstSetLocal struct {
anInstruction
name string
}
func NewInstSetLocal(name string) *InstSetLocal { return &InstSetLocal{name: name} }
func (i *InstSetLocal) Format(indent string) string { return indent + "local.set " + i.name }
/**************************************
InstAdd:
**************************************/
type InstAdd struct {
anInstruction
typ wtypes.ValueType
}
func NewInstAdd(t wtypes.ValueType) *InstAdd { return &InstAdd{typ: t} }
func (i *InstAdd) Format(indent string) string { return indent + i.typ.String() + ".add" }
/**************************************
InstSub:
**************************************/
type InstSub struct {
anInstruction
typ wtypes.ValueType
}
func NewInstSub(t wtypes.ValueType) *InstSub { return &InstSub{typ: t} }
func (i *InstSub) Format(indent string) string { return indent + i.typ.String() + ".sub" }
/**************************************
InstMul:
**************************************/
type InstMul struct {
anInstruction
typ wtypes.ValueType
}
func NewInstMul(t wtypes.ValueType) *InstMul { return &InstMul{typ: t} }
func (i *InstMul) Format(indent string) string { return indent + i.typ.String() + ".mul" }
/**************************************
InstDiv:
**************************************/
type InstDiv struct {
anInstruction
typ wtypes.ValueType
}
func NewInstDiv(t wtypes.ValueType) *InstDiv { return &InstDiv{typ: t} }
func (i *InstDiv) Format(indent string) string {
switch i.typ.(type) {
case wtypes.Int32:
return indent + "i32.div_s"
}
logger.Fatal("Todo")
return ""
}
/**************************************
InstRem:
**************************************/
type InstRem struct {
anInstruction
typ wtypes.ValueType
}
func NewInstRem(t wtypes.ValueType) *InstRem { return &InstRem{typ: t} }
func (i *InstRem) Format(indent string) string {
switch i.typ.(type) {
case wtypes.Int32:
return indent + "i32.rem_s"
}
logger.Fatal("Todo")
return ""
}
/**************************************
InstEq:
**************************************/
type InstEq struct {
anInstruction
typ wtypes.ValueType
}
func NewInstEq(t wtypes.ValueType) *InstEq { return &InstEq{typ: t} }
func (i *InstEq) Format(indent string) string { return indent + i.typ.String() + ".eq" }
/**************************************
InstNe:
**************************************/
type InstNe struct {
anInstruction
typ wtypes.ValueType
}
func NewInstNe(t wtypes.ValueType) *InstNe { return &InstNe{typ: t} }
func (i *InstNe) Format(indent string) string { return indent + i.typ.String() + ".ne" }
/**************************************
InstLt:
**************************************/
type InstLt struct {
anInstruction
typ wtypes.ValueType
}
func NewInstLt(t wtypes.ValueType) *InstLt { return &InstLt{typ: t} }
func (i *InstLt) Format(indent string) string {
switch i.typ.(type) {
case wtypes.Int32:
return indent + "i32.lt_s"
}
logger.Fatal("Todo")
return ""
}
/**************************************
InstGt:
**************************************/
type InstGt struct {
anInstruction
typ wtypes.ValueType
}
func NewInstGt(t wtypes.ValueType) *InstGt { return &InstGt{typ: t} }
func (i *InstGt) Format(indent string) string {
switch i.typ.(type) {
case wtypes.Int32:
return indent + "i32.gt_s"
}
logger.Fatal("Todo")
return ""
}
/**************************************
InstLe:
**************************************/
type InstLe struct {
anInstruction
typ wtypes.ValueType
}
func NewInstLe(t wtypes.ValueType) *InstLe { return &InstLe{typ: t} }
func (i *InstLe) Format(indent string) string {
switch i.typ.(type) {
case wtypes.Int32:
return indent + "i32.le_s"
}
logger.Fatal("Todo")
return ""
}
/**************************************
InstGe:
**************************************/
type InstGe struct {
anInstruction
typ wtypes.ValueType
}
func NewInstGe(t wtypes.ValueType) *InstGe { return &InstGe{typ: t} }
func (i *InstGe) Format(indent string) string {
switch i.typ.(type) {
case wtypes.Int32:
return indent + "i32.ge_s"
}
logger.Fatal("Todo")
return ""
}
/**************************************
InstCall:
**************************************/
type InstCall struct {
anInstruction
name string
}
func NewInstCall(name string) *InstCall { return &InstCall{name: name} }
func (i *InstCall) Format(indent string) string { return indent + "call " + i.name }
/**************************************
InstBlock:
**************************************/
type InstBlock struct {
anInstruction
name string
Insts []Instruction
}
func NewInstBlock(name string) *InstBlock { return &InstBlock{name: name} }
func (i *InstBlock) Format(indent string) string {
s := indent + "(block "
s += i.name + "\n"
for _, v := range i.Insts {
s += v.Format(indent+" ") + "\n"
}
s += indent + ") ;;" + i.name
return s
}
/**************************************
InstLoop:
**************************************/
type InstLoop struct {
anInstruction
name string
Insts []Instruction
}
func NewInstLoop(name string) *InstLoop { return &InstLoop{name: name} }
func (i *InstLoop) Format(indent string) string {
s := indent + "(loop "
s += i.name + "\n"
for _, v := range i.Insts {
s += v.Format(indent+" ") + "\n"
}
s += indent + ") ;;" + i.name
return s
}
/**************************************
InstBr:
**************************************/
type InstBr struct {
anInstruction
Name string
}
func NewInstBr(name string) *InstBr { return &InstBr{Name: name} }
func (i *InstBr) Format(indent string) string { return indent + "br " + i.Name }
/**************************************
InstBrTable:
**************************************/
type InstBrTable struct {
anInstruction
Table []int
}
func NewInstBrTable(t []int) *InstBrTable { return &InstBrTable{Table: t} }
func (i *InstBrTable) Format(indent string) string {
s := indent + "br_table"
for _, v := range i.Table {
s += " " + strconv.Itoa(v)
}
return s
}
/**************************************
InstIf:
**************************************/
type InstIf struct {
anInstruction
True []Instruction
False []Instruction
Ret wtypes.ValueType
}
func NewInstIf(instsTrue, instsFalse []Instruction, ret wtypes.ValueType) *InstIf {
return &InstIf{True: instsTrue, False: instsFalse, Ret: ret}
}
func (i *InstIf) Format(indent string) string {
s := indent + "if"
if !i.Ret.Equal(wtypes.Void{}) {
s += " (result"
rrs := i.Ret.Raw()
for _, rr := range rrs {
s += " " + rr.Name()
}
s += ")"
}
s += "\n"
for _, v := range i.True {
s += v.Format(indent+" ") + "\n"
}
s += indent + "else\n"
for _, v := range i.False {
s += v.Format(indent+" ") + "\n"
}
s += indent + "end"
return s
}
/**************************************
InstReturn:
**************************************/
type InstReturn struct {
anInstruction
}
func NewInstReturn() *InstReturn { return &InstReturn{} }
func (i *InstReturn) Format(indent string) string { return indent + "return" }
package wir
import (
"github.com/wa-lang/wa/internal/backends/compiler_wasm/wir/wtypes"
"github.com/wa-lang/wa/internal/logger"
)
func EmitPushValue(x Value) []Instruction {
var insts []Instruction
vs := x.Raw()
if len(vs) > 1 {
for _, v := range vs {
insts = append(insts, EmitPushValue(v)...)
}
}
switch x.Kind() {
case ValueKindConst:
insts = append(insts, NewInstConst(x))
case ValueKindLocal:
insts = append(insts, NewInstGetLocal(x.Name()))
case ValueKindGlobal:
logger.Fatal("Todo")
}
return insts
}
func EmitPopValue(x Value) []Instruction {
var insts []Instruction
vs := x.Raw()
if len(vs) > 1 {
for _, v := range vs {
insts = append(insts, EmitPopValue(v)...)
}
}
switch x.Kind() {
case ValueKindConst:
logger.Fatal("不可Pop至常数")
case ValueKindLocal:
insts = append(insts, NewInstSetLocal(x.Name()))
case ValueKindGlobal:
logger.Fatal("Todo")
}
return insts
}
func EmitAssginValue(lh, rh Value) []Instruction {
var insts []Instruction
if rh == nil {
ls := lh.Raw()
for _, v := range ls {
c := NewConst(v.Type(), nil)
insts = append(insts, EmitPushValue(c)...)
insts = append(insts, EmitPopValue(v)...)
}
} else {
if !lh.Type().Equal(rh.Type()) {
logger.Fatal("x.Type() != y.Type()")
}
ls := lh.Raw()
rs := rh.Raw()
for i := range ls {
insts = append(insts, EmitPushValue(rs[i])...)
insts = append(insts, EmitPopValue(ls[i])...)
}
}
return insts
}
func EmitConvertValueType(from, to wtypes.ValueType) {
logger.Fatal("Todo")
}
func EmitBinOp(x, y Value, op OpCode) ([]Instruction, wtypes.ValueType) {
var insts []Instruction
rtype := binOpMatchType(x.Type(), y.Type())
insts = append(insts, EmitPushValue(x)...)
insts = append(insts, EmitPushValue(y)...)
switch op {
case OpCodeAdd:
insts = append(insts, NewInstAdd(rtype))
case OpCodeSub:
insts = append(insts, NewInstSub(rtype))
case OpCodeMul:
insts = append(insts, NewInstMul(rtype))
case OpCodeQuo:
insts = append(insts, NewInstDiv(rtype))
case OpCodeRem:
insts = append(insts, NewInstRem(rtype))
case OpCodeEql:
insts = append(insts, NewInstEq(rtype))
case OpCodeNe:
insts = append(insts, NewInstNe(rtype))
case OpCodeLt:
insts = append(insts, NewInstLt(rtype))
case OpCodeGt:
insts = append(insts, NewInstGt(rtype))
case OpCodeLe:
insts = append(insts, NewInstLe(rtype))
case OpCodeGe:
insts = append(insts, NewInstGe(rtype))
default:
logger.Fatal("Todo")
}
return insts, rtype
}
func binOpMatchType(x, y wtypes.ValueType) wtypes.ValueType {
if x.Equal(y) {
return x
}
logger.Fatalf("Todo %T %T", x, y)
return nil
}
package wir
func (m *Module) String() string {
s := "(module\n"
for _, i := range m.Imports {
s += i.Format(" ") + "\n"
}
for _, f := range m.Funcs {
s += f.Format(" ") + "\n"
}
s += ") ;;module"
return s
}
package wir
import (
"github.com/wa-lang/wa/internal/types"
"github.com/wa-lang/wa/internal/backends/compiler_wasm/wir/wtypes"
"github.com/wa-lang/wa/internal/logger"
)
func ToWType(from types.Type) wtypes.ValueType {
switch t := from.(type) {
case *types.Basic:
switch t.Kind() {
case types.Bool:
return wtypes.Int32{}
case types.Int8, types.UntypedBool:
logger.Fatalf("ToWType Todo:%T", t)
case types.Uint8:
logger.Fatalf("ToWType Todo:%T", t)
case types.Int16:
logger.Fatalf("ToWType Todo:%T", t)
case types.Uint16:
logger.Fatalf("ToWType Todo:%T", t)
case types.Int, types.Int32, types.UntypedInt:
return wtypes.Int32{}
case types.Uint, types.Uint32:
logger.Fatalf("ToWType Todo:%T", t)
case types.Int64:
logger.Fatalf("ToWType Todo:%T", t)
case types.Uint64:
logger.Fatalf("ToWType Todo:%T", t)
case types.Float32, types.UntypedFloat:
logger.Fatalf("ToWType Todo:%T", t)
case types.Float64:
logger.Fatalf("ToWType Todo:%T", t)
case types.String:
logger.Fatalf("ToWType Todo:%T", t)
default:
logger.Fatalf("Unknown type:%s", t)
return nil
}
case *types.Tuple:
switch t.Len() {
case 0:
return wtypes.Void{}
case 1:
return ToWType(t.At(0).Type())
default:
logger.Fatalf("Todo type:%s", t)
}
default:
logger.Fatalf("Todo:%T", t)
}
return nil
}
package wir
import (
"strconv"
"github.com/wa-lang/wa/internal/backends/compiler_wasm/wir/wtypes"
"github.com/wa-lang/wa/internal/logger"
)
type Const interface {
Value
}
/**************************************
ConstZero:
**************************************/
/*type ConstZero struct {
}
func NewConstZero() *ConstZero { return &ConstZero{} }
func (c *ConstZero) Name() string { return "0" }
func (c *ConstZero) Kind() ValueKind { return ValueKindConst }
func (c *ConstZero) Type() wtypes.ValueType { return wtypes.Void{} }
func (c *ConstZero) Raw() []Value { return append([]Value(nil), c) }
//*/
func NewConst(t wtypes.ValueType, v interface{}) Const {
switch t.(type) {
case wtypes.Int32:
if v == nil {
return NewConstI32(0)
}
if c, ok := v.(int); ok {
return NewConstI32(int32(c))
}
logger.Fatal("Todo")
case wtypes.Int64:
if v == nil {
return NewConstI64(0)
}
if c, ok := v.(int); ok {
return NewConstI64(int64(c))
}
logger.Fatal("Todo")
default:
logger.Fatal("Todo")
}
return nil
}
/**************************************
ConstInt32:
**************************************/
type ConstI32 struct {
x int32
}
func NewConstI32(x int32) *ConstI32 { return &ConstI32{x: x} }
func (c *ConstI32) Name() string { return strconv.FormatInt(int64(c.x), 10) }
func (c *ConstI32) Kind() ValueKind { return ValueKindConst }
func (c *ConstI32) Type() wtypes.ValueType { return wtypes.Int32{} }
func (c *ConstI32) Raw() []Value { return append([]Value(nil), c) }
/**************************************
ConstInt64:
**************************************/
type ConstI64 struct {
x int64
}
func NewConstI64(x int64) *ConstI64 { return &ConstI64{x: x} }
func (c *ConstI64) Name() string { return strconv.FormatInt(c.x, 10) }
func (c *ConstI64) Kind() ValueKind { return ValueKindConst }
func (c *ConstI64) Type() wtypes.ValueType { return wtypes.Int64{} }
func (c *ConstI64) Raw() []Value { return append([]Value(nil), c) }
package wir
import (
"github.com/wa-lang/wa/internal/backends/compiler_wasm/wir/wtypes"
"github.com/wa-lang/wa/internal/logger"
)
func NewVar(name string, kind ValueKind, typ wtypes.ValueType) Value {
switch typ.(type) {
case wtypes.Int32:
return &VarI32{name: name, kind: kind, typ: typ}
default:
logger.Fatalf("Todo: %T", typ)
}
return nil
}
/**************************************
VarI32:
**************************************/
type VarI32 struct {
name string
kind ValueKind
typ wtypes.ValueType
}
func (v *VarI32) Name() string { return v.name }
func (v *VarI32) Kind() ValueKind { return v.kind }
func (v *VarI32) Type() wtypes.ValueType { return v.typ }
func (v *VarI32) Raw() []Value { return append([]Value(nil), v) }
package wir
import (
"github.com/wa-lang/wa/internal/backends/compiler_wasm/wir/wtypes"
)
type Module struct {
Imports []Import
Funcs []*Function
}
/**************************************
Import:
**************************************/
type Import interface {
Format(indent string) string
ModuleName() string
ObjName() string
Type() ObjType
}
/**************************************
Function:
**************************************/
type Function struct {
Name string
Result wtypes.ValueType
Params []Value
Locals []Value
Insts []Instruction
}
/**************************************
FuncSig:
**************************************/
type FuncSig struct {
Params []wtypes.ValueType
Results []wtypes.ValueType
}
/**************************************
Instruction:
**************************************/
type Instruction interface {
Format(indent string) string
isInstruction()
}
type ValueKind uint8
const (
ValueKindLocal ValueKind = iota
ValueKindGlobal
ValueKindConst
)
/**************************************
Value:
**************************************/
type Value interface {
Name() string
Kind() ValueKind
Type() wtypes.ValueType
Raw() []Value
}
/**************************************
OpCode:
**************************************/
type OpCode int32
const (
OpCodeAdd OpCode = iota
OpCodeSub
OpCodeMul
OpCodeQuo
OpCodeRem
OpCodeEql
OpCodeNe
OpCodeLt
OpCodeGt
OpCodeLe
OpCodeGe
)
/**************************************
ObjType:
**************************************/
type ObjType int32
const (
ObjTypeFunc ObjType = iota
ObjTypeMem
ObjTypeTable
ObjTypeGlobal
)
package wtypes
import "fmt"
type ValueType interface {
fmt.Stringer
Name() string
GetByteSize() int
Raw() []ValueType
Equal(ValueType) bool
}
/**************************************
Void:
**************************************/
type Void struct {
}
func (t Void) String() string { return t.Name() }
func (t Void) Name() string { return "void" }
func (t Void) GetByteSize() int { return 0 }
func (t Void) Raw() []ValueType { return append([]ValueType(nil), t) }
func (t Void) Equal(u ValueType) bool {
if _, ok := u.(Void); ok {
return true
}
return false
}
/**************************************
Int32:
**************************************/
type Int32 struct {
}
func (t Int32) String() string { return t.Name() }
func (t Int32) Name() string { return "i32" }
func (t Int32) GetByteSize() int { return 4 }
func (t Int32) Raw() []ValueType { return append([]ValueType(nil), t) }
func (t Int32) Equal(u ValueType) bool {
if _, ok := u.(Int32); ok {
return true
}
return false
}
/**************************************
Int64:
**************************************/
type Int64 struct {
}
func (t Int64) String() string { return t.Name() }
func (t Int64) Name() string { return "i64" }
func (t Int64) GetByteSize() int { return 8 }
func (t Int64) Raw() []ValueType { return append([]ValueType(nil), t) }
func (t Int64) Equal(u ValueType) bool {
if _, ok := u.(Int64); ok {
return true
}
return false
}
/**************************************
Pointer:
**************************************/
type Pointer struct {
Base ValueType
}
func NewPointer(base ValueType) Pointer { return Pointer{Base: base} }
func (t Pointer) String() string { return "*" + t.Base.Name() }
func (t Pointer) Name() string { return "Todo" }
func (t Pointer) GetByteSize() int { return 4 }
func (t Pointer) Raw() []ValueType { return append([]ValueType(nil), Int32{}) }
func (t Pointer) Equal(u ValueType) bool {
if ut, ok := u.(Pointer); ok {
return t.Base.Equal(ut.Base)
}
return false
}
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册