Browse Source

реализовал несколько выражений, добрался до операций

kpmy 9 years ago
parent
commit
40de16c1cb
8 changed files with 295 additions and 28 deletions
  1. 1 0
      .gitignore
  2. 5 4
      README.md
  3. BIN
      TODO.odc
  4. 4 12
      ir/ast.go
  5. 91 6
      ir/code.go
  6. 166 0
      ir/ops/op.go
  7. 10 0
      ir/types/types.go
  8. 18 6
      tiss_test.go

+ 1 - 0
.gitignore

@@ -74,3 +74,4 @@ $RECYCLE.BIN/
 # Windows shortcuts
 *.lnk
 *.wasm
+*.wast

+ 5 - 4
README.md

@@ -2,9 +2,9 @@
 
 For the good.
 
-* [wasm specs](https://github.com/WebAssembly/spec/tree/master/ml-proto)
+* [wasm specs](https://github.com/WebAssembly/spec/blob/master/ml-proto/README.md)
 
-````
+```
 ;; golang wasm generator github.com/kpmy/tiss
 (module
 	(type $t0
@@ -20,5 +20,6 @@ For the good.
 		(call $fib
 			(i64.const 0)))
 	(start $start))
-````
-**not so pretty :(*
+```
+
+*not so pretty :(*

BIN
TODO.odc


+ 4 - 12
ir/ast.go

@@ -3,19 +3,11 @@ package ir //import "github.com/kpmy/tiss/ir"
 import (
 	"reflect"
 
+	"github.com/kpmy/tiss/ir/types"
 	"github.com/kpmy/ypk/fn"
 	. "github.com/kpmy/ypk/tc"
 )
 
-type Type string
-
-const (
-	Ti32 Type = "i32"
-	Ti64 Type = "i64"
-	Tf32 Type = "f32"
-	Tf64 Type = "f64"
-)
-
 type Expression interface {
 	Validate() error
 }
@@ -148,7 +140,7 @@ func (t *TypeRef) Children() (ret []interface{}) {
 
 type ResultExpr struct {
 	ns     `sexpr:"result"`
-	Result Type
+	Result types.Type
 }
 
 func (r *ResultExpr) Validate() error {
@@ -199,10 +191,10 @@ type Local struct {
 
 type object struct {
 	named
-	typ Type
+	typ types.Type
 }
 
-func (o *object) Type(t ...Type) Type {
+func (o *object) Type(t ...types.Type) types.Type {
 	if len(t) > 0 {
 		o.typ = t[0]
 	}

+ 91 - 6
ir/code.go

@@ -1,6 +1,7 @@
 package ir
 
 import (
+	"github.com/kpmy/tiss/ir/types"
 	"github.com/kpmy/ypk/fn"
 	. "github.com/kpmy/ypk/tc"
 )
@@ -17,7 +18,7 @@ func (r *ReturnExpr) Children() (ret []interface{}) {
 }
 
 type ConstExpr struct {
-	Type  Type
+	Type  types.Type
 	Value interface{}
 }
 
@@ -43,22 +44,21 @@ func (c *ConstExpr) Children() (ret []interface{}) {
 	return append(ret, c.Value)
 }
 
-type CallExpr struct {
-	ns     `sexpr:"call"`
+type call struct {
 	Var    Variable
 	Params []CodeExpr
 }
 
-func (c *CallExpr) Validate() error {
+func (c *call) Validate() error {
 	if c.Var.IsEmpty() {
 		return Error("empty call var")
 	}
 	return nil
 }
 
-func (c *CallExpr) Eval() {}
+func (c *call) Eval() {}
 
-func (c *CallExpr) Children() (ret []interface{}) {
+func (c *call) Children() (ret []interface{}) {
 	ret = append(ret, c.Var)
 
 	for _, p := range c.Params {
@@ -67,3 +67,88 @@ func (c *CallExpr) Children() (ret []interface{}) {
 
 	return
 }
+
+type CallExpr struct {
+	ns `sexpr:"call"`
+	call
+}
+
+type CallImportExpr struct {
+	ns `sexpr:"call_import"`
+	call
+}
+
+type CallIndirect struct {
+	ns `sexpr:"call_indirect"`
+	call
+	//Var is TypeDef variable
+	//Params are params
+	Link CodeExpr //Link expr containing adr in table
+}
+
+func (c *CallIndirect) Validate() (err error) {
+	if err = c.call.Validate(); err == nil {
+		if fn.IsNil(c.Link) {
+			err = Error("empty link expr of indirect")
+		}
+	}
+	return
+}
+
+func (c *CallIndirect) Children() (ret []interface{}) {
+	tmp := c.call.Children()
+	ret = append(ret, tmp[0])
+	ret = append(ret, c.Link)
+	for i := 1; i < len(tmp); i++ {
+		ret = append(ret, tmp[i])
+	}
+	return
+}
+
+type NopExpr struct {
+	ns `sexpr:"nop"`
+}
+
+func (n *NopExpr) Validate() error { return nil }
+
+func (n *NopExpr) Eval() {}
+
+type GetLocalExpr struct {
+	ns  `sexpr:"get_local"`
+	Var Variable
+}
+
+func (g *GetLocalExpr) Validate() error {
+	if g.Var.IsEmpty() {
+		return Error("empty local variable")
+	}
+	return nil
+}
+
+func (g *GetLocalExpr) Children() (ret []interface{}) {
+	return append(ret, g.Var)
+}
+
+func (*GetLocalExpr) Eval() {}
+
+type SetLocalExpr struct {
+	ns   `sexpr:"set_local"`
+	Var  Variable
+	Expr CodeExpr
+}
+
+func (s *SetLocalExpr) Validate() error {
+	if s.Var.IsEmpty() {
+		return Error("empty local variable")
+	}
+	if fn.IsNil(s.Expr) {
+		return Error("no expr for local varible")
+	}
+	return nil
+}
+
+func (s *SetLocalExpr) Children() (ret []interface{}) {
+	return append(ret, s.Var, s.Expr)
+}
+
+func (*SetLocalExpr) Eval() {}

+ 166 - 0
ir/ops/op.go

@@ -0,0 +1,166 @@
+package ops
+
+import (
+	"fmt"
+	"strings"
+
+	"github.com/kpmy/tiss/ir/types"
+	. "github.com/kpmy/ypk/tc"
+)
+
+type Op string
+
+//monadic int
+const Clz Op = "clz"
+const Ctz Op = "ctz"
+const PopCnt Op = "popcnt"
+const Eqz Op = "eqz"
+
+//monadic float
+const Neg Op = "neg"
+const Abs Op = "abs"
+const Sqrt Op = "sqrt"
+const Ceil Op = "ceil"
+const Floor Op = "floor"
+const Nearest Op = "nearest"
+const Trunc Op = "trunc"
+
+//dyadic int
+const Add Op = "add"
+const Sub Op = "sub"
+const Mul Op = "mul"
+
+//const DivS Op = "div_s"
+//const DivU Op = "div_u"
+const Div Op = "div"
+
+//const RemS Op = "rem_s"
+//const RemU Op = "rem_u"
+const Rem Op = "rem"
+const And Op = "and"
+const Or Op = "or"
+const Xor Op = "xor"
+const Shl Op = "shl"
+
+//const ShrS Op = "shr_s"
+//const ShrU Op = "shr_u"
+const Shr Op = "shr"
+const RotL Op = "rotl"
+const RotR Op = "rotr"
+
+//dyadic float
+//const Add Op = "add"
+//const Sub Op = "sub"
+//const Mul Op = "mul"
+//const Div Op = "div"
+const Min Op = "min"
+const Max Op = "max"
+const CopySign Op = "copysign"
+
+//compare int
+const Eq Op = "eq"
+const Ne Op = "ne"
+
+//const LtS Op = "lt_s"
+//const LtU Op = "lt_u"
+//const LeS Op = "le_s"
+//const LeU Op = "le_u"
+//const GtS Op = "gt_s"
+//const GtU Op = "gt_u"
+//const GeS Op = "ge_s"
+//const GeU Op = "ge_u"
+const Lt Op = "lt"
+const Le Op = "le"
+const Gt Op = "gt"
+const Ge Op = "ge"
+
+//compare float
+//const Eq Op = "eq"
+//const Ne Op = "ne"
+//const Lt Op = "lt"
+//const Le Op = "le"
+//const Gt Op = "gt"
+//const Ge Op = "ge"
+
+//conversion
+const Wrap Op = "wrap" // i32_ /i64
+//const Trunc Op = "trunc"             // i32_, i64_ * _s, _u * /f32, /f64
+const Extend Op = "extend"           // i64_ * _s, _u * /i32
+const Convert Op = "convert"         // f32_, f64_ * _s, _u * /i32, /i64
+const Demote Op = "demote"           // f32_ /f64
+const Promote Op = "promote"         // f64_ /f32
+const Reinterpret Op = "reinterpret" // i32_, i64_ * /f32, /f64
+
+type MonadicOpCode struct {
+	typ types.Type
+	op  Op
+}
+
+func (m MonadicOpCode) String() string {
+	return fmt.Sprint(m.typ, ".", m.op)
+}
+
+var i_ops = fmt.Sprint(Clz, Ctz, PopCnt, Eqz)
+var f_ops = fmt.Sprint(Neg, Abs, Sqrt, Floor, Trunc, Ceil, Nearest)
+
+func Monadic(typ types.Type, op Op) (ret MonadicOpCode) {
+	switch typ {
+	case types.I32, types.I64:
+		Assert(strings.Contains(i_ops, string(op)), 20)
+	case types.F32, types.F64:
+		Assert(strings.Contains(f_ops, string(op)), 20)
+	default:
+		Halt(100)
+	}
+	ret.typ = typ
+	ret.op = op
+	return
+}
+
+type DyadicOpCode struct {
+	l, r   types.Type
+	op     Op
+	signed bool
+}
+
+var ii_ops = fmt.Sprint(Add, Sub, Mul, Div, Rem, And, Or, Xor, Shl, Shr, RotL, RotR, Eq, Ne, Le, Lt, Ge, Gt)
+var ii_sign = fmt.Sprint(Div, Rem, Shr, Le, Lt, Ge, Gt)
+
+func (d DyadicOpCode) String() (ret string) {
+	if d.l == d.r {
+		ret = fmt.Sprint(d.l, ".", d.op)
+		if strings.Contains(ii_sign, string(d.op)) {
+			if d.signed {
+				ret = fmt.Sprint(ret, "_s")
+			} else {
+				ret = fmt.Sprint(ret, "_u")
+			}
+		}
+	} else {
+		return "unsupported"
+	}
+	return
+}
+
+func Dyadic(l, r types.Type, op Op, signed ...bool) (ret DyadicOpCode) {
+	if l == r {
+		switch l {
+		case types.I32, types.I64:
+			Assert(strings.Contains(ii_ops, string(op)), 21)
+			if strings.Contains(ii_sign, string(op)) {
+				Assert(len(signed) > 0, 21)
+			}
+		default:
+			Halt(100)
+		}
+	} else {
+		Halt(100)
+	}
+	ret.l = l
+	ret.r = r
+	ret.op = op
+	if len(signed) > 0 {
+		ret.signed = signed[0]
+	}
+	return
+}

+ 10 - 0
ir/types/types.go

@@ -0,0 +1,10 @@
+package types
+
+type Type string
+
+const (
+	I32 Type = "i32"
+	I64 Type = "i64"
+	F32 Type = "f32"
+	F64 Type = "f64"
+)

+ 18 - 6
tiss_test.go

@@ -8,10 +8,12 @@ import (
 
 	"github.com/kpmy/tiss/gen"
 	"github.com/kpmy/tiss/ir"
+	"github.com/kpmy/tiss/ir/ops"
+	"github.com/kpmy/tiss/ir/types"
 )
 
 func TestDump(t *testing.T) {
-	if f, err := os.Create("dump.wasm"); err == nil {
+	if f, err := os.Create("dump.wast"); err == nil {
 		defer f.Close()
 
 		m := &ir.Module{}
@@ -24,21 +26,23 @@ func TestDump(t *testing.T) {
 		f0.Name("$fib")
 		par := &ir.Param{}
 		par.Name("$x")
-		par.Type(ir.Ti64)
+		par.Type(types.I64)
 		l0 := &ir.Local{}
 		l0.Name("$i")
-		l0.Type(ir.Ti64)
+		l0.Type(types.I64)
 		f0.Params = append(f0.Params, par)
 		f0.Locals = append(f0.Locals, l0)
-		f0.Result = &ir.ResultExpr{Result: ir.Ti64}
+		f0.Result = &ir.ResultExpr{Result: types.I64}
 		ret := &ir.ReturnExpr{}
-		ret.Expr = &ir.ConstExpr{Type: ir.Ti64, Value: 0}
+		ret.Expr = &ir.ConstExpr{Type: types.I64, Value: 0}
 		f0.Code = append(f0.Code, ret)
 
 		fn := &ir.FuncExpr{}
 		fn.Name("$start")
 		fn.Type = &ir.TypeRef{Type: ir.ThisVariable("$t0")}
-		call := &ir.CallExpr{Var: ir.ThisVariable("$fib"), Params: []ir.CodeExpr{&ir.ConstExpr{Type: ir.Ti64, Value: 0}}}
+		call := &ir.CallExpr{}
+		call.Var = ir.ThisVariable("$fib")
+		call.Params = []ir.CodeExpr{&ir.ConstExpr{Type: types.I64, Value: 0}}
 		fn.Code = append(fn.Code, call)
 		m.Func = append(m.Func, f0, fn)
 		m.Start = &ir.StartExpr{Var: ir.ThisVariable("$start")}
@@ -54,3 +58,11 @@ func TestDump(t *testing.T) {
 		t.Error(err)
 	}
 }
+
+func TestOp(t *testing.T) {
+	t.Log(ops.Monadic(types.I32, ops.Clz))
+	t.Log(ops.Monadic(types.F32, ops.Nearest))
+
+	t.Log(ops.Dyadic(types.I64, types.I64, ops.Add, true))
+	t.Log(ops.Dyadic(types.I32, types.I32, ops.Ge, true))
+}