diff --git a/src/compiler.ts b/src/compiler.ts index 4a24b623..6c766329 100644 --- a/src/compiler.ts +++ b/src/compiler.ts @@ -1330,7 +1330,7 @@ export class Compiler extends DiagnosticEmitter { compileAssignment(expression: Expression, valueExpression: Expression, contextualType: Type): ExpressionRef { this.currentType = this.determineExpressionType(expression, contextualType); - return this.compileAssignmentWithValue(expression, this.compileExpression(valueExpression, this.currentType), contextualType != Type.void); + return this.compileAssignmentWithValue(expression, this.compileExpression(valueExpression, this.currentType, ConversionKind.IMPLICIT), contextualType != Type.void); } compileAssignmentWithValue(expression: Expression, valueWithCorrectType: ExpressionRef, tee: bool = false): ExpressionRef { @@ -1773,33 +1773,52 @@ export class Compiler extends DiagnosticEmitter { compileUnaryPostfixExpression(expression: UnaryPostfixExpression, contextualType: Type): ExpressionRef { const operator: Token = expression.operator; + // make a getter for the expression (also obtains the type) + const getValue: ExpressionRef = this.compileExpression(expression.expression, contextualType, contextualType == Type.void ? ConversionKind.NONE : ConversionKind.IMPLICIT); + + // use a temp local for the intermediate value + const tempLocal: Local = this.currentFunction.addLocal(this.currentType); + let op: BinaryOp; let nativeType: NativeType; let nativeOne: ExpressionRef; - if (contextualType == Type.f32) { + if (tempLocal.type == Type.f32) { op = operator == Token.PLUS_PLUS ? BinaryOp.AddF32 : BinaryOp.SubF32; nativeType = NativeType.F32; nativeOne = this.module.createF32(1); - } else if (contextualType == Type.f64) { + + } else if (tempLocal.type == Type.f64) { op = operator == Token.PLUS_PLUS ? BinaryOp.AddF64 : BinaryOp.SubF64; nativeType = NativeType.F64; nativeOne = this.module.createF64(1); - } else if (contextualType.isLongInteger) { + + } else if (tempLocal.type.isLongInteger) { op = operator == Token.PLUS_PLUS ? BinaryOp.AddI64 : BinaryOp.SubI64; nativeType = NativeType.I64; nativeOne = this.module.createI64(1, 0); + } else { op = operator == Token.PLUS_PLUS ? BinaryOp.AddI32 : BinaryOp.SubI32; nativeType = NativeType.I32; nativeOne = this.module.createI32(1); } - const getValue: ExpressionRef = this.compileExpression(expression.expression, contextualType); - const setValue: ExpressionRef = this.compileAssignmentWithValue(expression.expression, this.module.createBinary(op, getValue, nativeOne), false); // reports + // make a setter that sets the new value (temp value +/- 1) + const setValue: ExpressionRef = this.compileAssignmentWithValue(expression.expression, + this.module.createBinary(op, + this.module.createGetLocal(tempLocal.index, nativeType), + nativeOne + ), false + ); + + // NOTE: can't preemptively tee_local the return value on the stack because binaryen expects + // this to be well-formed. becomes a tee_local when optimizing, though. + this.currentType = tempLocal.type; return this.module.createBlock(null, [ - getValue, - setValue + this.module.createSetLocal(tempLocal.index, getValue), // +++ this.module.createTeeLocal(tempLocal.index, getValue), + setValue, + this.module.createGetLocal(tempLocal.index, nativeType) // --- ], nativeType); } diff --git a/tests/binaryen/block-stack.js b/tests/binaryen/block-stack.js new file mode 100644 index 00000000..229e1483 --- /dev/null +++ b/tests/binaryen/block-stack.js @@ -0,0 +1,19 @@ +var binaryen = require("binaryen"); + +// "non-final block elements returning a value must be drop()ed" +// "0 == 0: block with value must not have last element that is none, on" + +var mod = new binaryen.Module(); + +var funcType = mod.addFunctionType("i", binaryen.i32, []); +var func = mod.addFunction("test", funcType, [ binaryen.i32 ], + mod.block("", [ + mod.teeLocal(0, mod.i32.const(1)), + mod.nop() + ], binaryen.i32) +); +mod.addExport("test", func); + +console.log(mod.emitText()); +if (!mod.validate()) + console.log("-> does not validate"); diff --git a/tests/set_global-immutable.js b/tests/binaryen/set_global-immutable.js similarity index 100% rename from tests/set_global-immutable.js rename to tests/binaryen/set_global-immutable.js diff --git a/tests/compiler/literals.ts b/tests/compiler/literals.ts index 6c6f629b..585f14a7 100644 --- a/tests/compiler/literals.ts +++ b/tests/compiler/literals.ts @@ -44,3 +44,5 @@ true; false; NaN; Infinity; +NaN; +Infinity; diff --git a/tests/compiler/literals.wast b/tests/compiler/literals.wast index 095128d2..dff16834 100644 --- a/tests/compiler/literals.wast +++ b/tests/compiler/literals.wast @@ -143,6 +143,12 @@ (drop (f64.const inf) ) + (drop + (f32.const nan:0x400000) + ) + (drop + (f32.const inf) + ) ) ) (; diff --git a/tests/compiler/unary.ts b/tests/compiler/unary.ts index 416c26f0..d8993e60 100644 --- a/tests/compiler/unary.ts +++ b/tests/compiler/unary.ts @@ -5,7 +5,6 @@ +1.25; -1.25; !1.25; -// ~1.25; let i: i32 = 0; @@ -15,6 +14,8 @@ let i: i32 = 0; ~i; ++i; --i; +i++; +i--; i = +1; i = -1; @@ -26,6 +27,8 @@ i = !i; i = ~i; i = ++i; i = --i; +i = i++; +i = i--; let I: i64 = 0; @@ -35,6 +38,8 @@ let I: i64 = 0; ~I; ++I; --I; +I++; +I--; I = +1; I = -1; @@ -46,43 +51,47 @@ I = !I; I = ~I; I = ++I; I = --I; +I = I++; +I = I--; let f: f32 = 0; +f; -f; !f; -// ~f; ++f; --f; +f++; +f--; f = +1.25; f = -1.25; i = !1.25; -// i = ~1.25; f = +f; f = -f; i = !f; -// i = ~f; f = ++f; f = --f; +f = f++; +f = f--; let F: f64 = 0; +F; -F; !F; -// ~F; ++F; --F; +F++; +F--; F = +1.25; F = -1.25; I = !1.25; -// I = ~1.25; F = +F; F = -F; I = !F; -// I = ~F; F = ++F; F = --F; +F = F++; +F = F--; diff --git a/tests/compiler/unary.wast b/tests/compiler/unary.wast index 42043d2b..288d38e0 100644 --- a/tests/compiler/unary.wast +++ b/tests/compiler/unary.wast @@ -9,6 +9,22 @@ (export "memory" (memory $0)) (start $start) (func $start (; 0 ;) (type $v) + (local $0 i32) + (local $1 i32) + (local $2 i32) + (local $3 i32) + (local $4 i64) + (local $5 i64) + (local $6 i64) + (local $7 i64) + (local $8 f32) + (local $9 f32) + (local $10 f32) + (local $11 f32) + (local $12 f64) + (local $13 f64) + (local $14 f64) + (local $15 f64) (drop (i32.const 1) ) @@ -75,6 +91,34 @@ (i32.const 1) ) ) + (drop + (block (result i32) + (set_local $0 + (get_global $unary/i) + ) + (set_global $unary/i + (i32.add + (get_local $0) + (i32.const 1) + ) + ) + (get_local $0) + ) + ) + (drop + (block (result i32) + (set_local $1 + (get_global $unary/i) + ) + (set_global $unary/i + (i32.sub + (get_local $1) + (i32.const 1) + ) + ) + (get_local $1) + ) + ) (set_global $unary/i (i32.const 1) ) @@ -137,6 +181,34 @@ (get_global $unary/i) ) ) + (set_global $unary/i + (block (result i32) + (set_local $2 + (get_global $unary/i) + ) + (set_global $unary/i + (i32.add + (get_local $2) + (i32.const 1) + ) + ) + (get_local $2) + ) + ) + (set_global $unary/i + (block (result i32) + (set_local $3 + (get_global $unary/i) + ) + (set_global $unary/i + (i32.sub + (get_local $3) + (i32.const 1) + ) + ) + (get_local $3) + ) + ) (drop (get_global $unary/I) ) @@ -169,6 +241,34 @@ (i64.const 1) ) ) + (drop + (block (result i64) + (set_local $4 + (get_global $unary/I) + ) + (set_global $unary/I + (i64.add + (get_local $4) + (i64.const 1) + ) + ) + (get_local $4) + ) + ) + (drop + (block (result i64) + (set_local $5 + (get_global $unary/I) + ) + (set_global $unary/I + (i64.sub + (get_local $5) + (i64.const 1) + ) + ) + (get_local $5) + ) + ) (set_global $unary/I (i64.const 1) ) @@ -235,6 +335,34 @@ (get_global $unary/I) ) ) + (set_global $unary/I + (block (result i64) + (set_local $6 + (get_global $unary/I) + ) + (set_global $unary/I + (i64.add + (get_local $6) + (i64.const 1) + ) + ) + (get_local $6) + ) + ) + (set_global $unary/I + (block (result i64) + (set_local $7 + (get_global $unary/I) + ) + (set_global $unary/I + (i64.sub + (get_local $7) + (i64.const 1) + ) + ) + (get_local $7) + ) + ) (drop (get_global $unary/f) ) @@ -261,6 +389,34 @@ (f32.const 1) ) ) + (drop + (block (result f32) + (set_local $8 + (get_global $unary/f) + ) + (set_global $unary/f + (f32.add + (get_local $8) + (f32.const 1) + ) + ) + (get_local $8) + ) + ) + (drop + (block (result f32) + (set_local $9 + (get_global $unary/f) + ) + (set_global $unary/f + (f32.sub + (get_local $9) + (f32.const 1) + ) + ) + (get_local $9) + ) + ) (set_global $unary/f (f32.const 1.25) ) @@ -311,6 +467,34 @@ (get_global $unary/f) ) ) + (set_global $unary/f + (block (result f32) + (set_local $10 + (get_global $unary/f) + ) + (set_global $unary/f + (f32.add + (get_local $10) + (f32.const 1) + ) + ) + (get_local $10) + ) + ) + (set_global $unary/f + (block (result f32) + (set_local $11 + (get_global $unary/f) + ) + (set_global $unary/f + (f32.sub + (get_local $11) + (f32.const 1) + ) + ) + (get_local $11) + ) + ) (drop (get_global $unary/F) ) @@ -337,6 +521,34 @@ (f64.const 1) ) ) + (drop + (block (result f64) + (set_local $12 + (get_global $unary/F) + ) + (set_global $unary/F + (f64.add + (get_local $12) + (f64.const 1) + ) + ) + (get_local $12) + ) + ) + (drop + (block (result f64) + (set_local $13 + (get_global $unary/F) + ) + (set_global $unary/F + (f64.sub + (get_local $13) + (f64.const 1) + ) + ) + (get_local $13) + ) + ) (set_global $unary/F (f64.const 1.25) ) @@ -391,6 +603,34 @@ (get_global $unary/F) ) ) + (set_global $unary/F + (block (result f64) + (set_local $14 + (get_global $unary/F) + ) + (set_global $unary/F + (f64.add + (get_local $14) + (f64.const 1) + ) + ) + (get_local $14) + ) + ) + (set_global $unary/F + (block (result f64) + (set_local $15 + (get_global $unary/F) + ) + (set_global $unary/F + (f64.sub + (get_local $15) + (f64.const 1) + ) + ) + (get_local $15) + ) + ) ) ) (;