diff --git a/backend_wat.go b/backend_wat.go index 2204128..8370115 100644 --- a/backend_wat.go +++ b/backend_wat.go @@ -91,6 +91,14 @@ func (c *Compiler) getAddressWATType() string { } } +func (c *Compiler) getEffectiveAddressType() PrimitiveType { + if c.Wasm64 { + return Primitive_U64 + } else { + return Primitive_U32 + } +} + func (c *Compiler) getWATType(t Type) string { switch t.Type { case Type_Primitive: @@ -212,6 +220,83 @@ func (c *Compiler) compileAssignmentExpressionWAT(assignment AssignmentExpressio panic("assignment expr not implemented") } +func (c *Compiler) compileAssignmentUpdateExpressionWAT(lhs Expression, updateWAT string, evaluateToOldValue bool) (string, error) { + switch lhs.Type { + case Expression_VariableReference: + ref := lhs.Value.(VariableReferenceExpression) + local := strconv.Itoa(getLocal(c.CurrentBlock, ref.Variable).Index) + + exprWAT, err := c.compileExpressionWAT(lhs) + if err != nil { + return "", err + } + + var tmpLocal Local + wat := exprWAT + if evaluateToOldValue { + tmpLocal = Local{Name: "", Type: *lhs.ValueType, IsParameter: false, Index: len(c.CurrentFunction.Locals)} + c.CurrentFunction.Locals = append(c.CurrentFunction.Locals, tmpLocal) + + wat += "local.tee $" + strconv.Itoa(tmpLocal.Index) + "\n" + } + + wat += updateWAT + + if evaluateToOldValue { + wat += "local.set $" + local + "\n" + wat += "local.get $" + strconv.Itoa(tmpLocal.Index) + "\n" + } else { + wat += "local.tee $" + local + "\n" + } + + return wat, nil + case Expression_ArrayAccess: + panic("TODO") // TODO + case Expression_RawMemoryReference: + raw := lhs.Value.(RawMemoryReferenceExpression) + + localAddress := Local{Name: "", Type: Type{Type: Type_Primitive, Value: c.getEffectiveAddressType()}, IsParameter: false, Index: len(c.CurrentFunction.Locals)} + c.CurrentFunction.Locals = append(c.CurrentFunction.Locals, localAddress) + + localValue := Local{Name: "", Type: *lhs.ValueType, IsParameter: false, Index: len(c.CurrentFunction.Locals)} + c.CurrentFunction.Locals = append(c.CurrentFunction.Locals, localValue) + + if raw.Type.Type != Type_Primitive { + panic("TODO") //TODO + } + + addrWAT, err := c.compileExpressionWAT(raw.Address) + if err != nil { + return "", err + } + + wat := addrWAT + + // dup address + wat += "local.tee $" + strconv.Itoa(localAddress.Index) + "\n" + wat += "local.get $" + strconv.Itoa(localAddress.Index) + "\n" + + wat += c.getWATType(raw.Type) + ".load\n" + + if evaluateToOldValue { + wat += "local.tee $" + strconv.Itoa(localValue.Index) + "\n" + } + + wat += updateWAT + + if !evaluateToOldValue { + wat += "local.tee $" + strconv.Itoa(localValue.Index) + "\n" + } + + wat += c.getWATType(raw.Type) + ".store\n" + wat += "local.get $" + strconv.Itoa(localValue.Index) + "\n" + + return wat, nil + } + + panic("assignment expr not implemented") +} + func (c *Compiler) compileExpressionWAT(expr Expression) (string, error) { var err error @@ -351,7 +436,16 @@ func (c *Compiler) compileExpressionWAT(expr Expression) (string, error) { case UnaryOperation_LogicalNot: return wat + "i32.eqz\n", nil case UnaryOperation_PreIncrement, UnaryOperation_PreDecrement, UnaryOperation_PostIncrement, UnaryOperation_PostDecrement: - // TODO: implement + valueType := c.getWATType(*unary.Value.ValueType) + + updateWAT := valueType + ".const 1\n" + if unary.Operation == UnaryOperation_PreIncrement || unary.Operation == UnaryOperation_PostIncrement { + updateWAT += valueType + ".add\n" + } else { + updateWAT += valueType + ".sub\n" + } + + return c.compileAssignmentUpdateExpressionWAT(unary.Value, updateWAT, unary.Operation == UnaryOperation_PostIncrement || unary.Operation == UnaryOperation_PostDecrement) } case Expression_Cast: cast := expr.Value.(CastExpression) @@ -379,7 +473,7 @@ func (c *Compiler) compileExpressionWAT(expr Expression) (string, error) { } if raw.Type.Type == Type_Primitive { - wat += c.getWATType(raw.Type) + ".load\n" + wat += c.getWATType(raw.Type) + ".load\n" // TODO: use load8/load16(_s/u) for smaller types } return wat, nil diff --git a/example/test.ely b/example/test.ely index 14635b7..a1653bb 100644 --- a/example/test.ely +++ b/example/test.ely @@ -20,3 +20,16 @@ u64 fib(u64 i) { return fibA; } + +(u64, u64) add(u64 a) { + u64 x = a++; + return x, a; +} + +(u64, u64) tuple() { + return 1u64, 2u64; +} + +u64 sub(u64 a) { + return --raw(u64, 0xFFu64); +} diff --git a/main.go b/main.go index e80b138..6befef9 100644 --- a/main.go +++ b/main.go @@ -151,7 +151,7 @@ func main() { parsedFiles = append(parsedFiles, parsed) } - validator := Validator{Files: parsedFiles} + validator := Validator{Files: parsedFiles, Wasm64: *wasm64} errors := validator.validate() if len(errors) != 0 { for _, err := range errors { @@ -188,7 +188,14 @@ func main() { return } - cmd := exec.Command("wat2wasm", "-o", *outputFile, "-") + var command []string + if *wasm64 { + // TODO: wasm64 support is currently broken because x.load doesn't accept 64-bit addresses + command = append(command, "--enable-memory64") + } + command = append(command, "-o", *outputFile, "-") + + cmd := exec.Command("wat2wasm", command...) var input bytes.Buffer input.Write([]byte(wat))