From f045975a4b78c1a8eeccc1af38e5728ff2dca093 Mon Sep 17 00:00:00 2001 From: dcodeIO Date: Tue, 5 Dec 2017 22:47:20 +0100 Subject: [PATCH] Built-in abs/min/max for integers; For-loop fixes --- assembly.d.ts | 4 +- src/builtins.ts | 115 +++- src/compiler.ts | 8 +- src/program.ts | 4 +- tests/compiler/assert.optimized.wast | 10 + tests/compiler/assert.ts | 1 + tests/compiler/assert.wast | 45 ++ tests/compiler/builtins.optimized.wast | 249 ++++++++ tests/compiler/builtins.ts | 47 +- tests/compiler/builtins.wast | 815 +++++++++++++++++-------- tests/compiler/for.optimized.wast | 70 +++ tests/compiler/for.ts | 18 +- tests/compiler/for.wast | 115 +++- tests/compiler/logical.ts | 24 +- tests/compiler/logical.wast | 64 +- tests/compiler/switch.optimized.wast | 87 +-- 16 files changed, 1273 insertions(+), 403 deletions(-) create mode 100644 tests/compiler/assert.optimized.wast create mode 100644 tests/compiler/assert.ts create mode 100644 tests/compiler/assert.wast diff --git a/assembly.d.ts b/assembly.d.ts index 9a4c9bf7..a951c326 100644 --- a/assembly.d.ts +++ b/assembly.d.ts @@ -87,11 +87,9 @@ declare function assert(isTrue: bool): void; // internal decorators -/** A decorator marking a function or class as global. */ declare function global(name?: string): any; -/** A decorator marking a function as ideally being inlined. */ +declare function struct(): any declare function inline(): any; -/** A decorator marking a class that manually manages its memory. */ declare function allocates(): any; declare function operator(token: string, fn: any): any; diff --git a/src/builtins.ts b/src/builtins.ts index 78c1e9c8..d26a9736 100644 --- a/src/builtins.ts +++ b/src/builtins.ts @@ -53,7 +53,9 @@ export function compileCall(compiler: Compiler, internalName: string, typeArgume arg1: ExpressionRef, arg2: ExpressionRef; - let tempLocal: Local; + let tempLocal0: Local; + let tempLocal1: Local; + let nativeType: NativeType; switch (internalName) { @@ -149,7 +151,34 @@ export function compileCall(compiler: Compiler, internalName: string, typeArgume ? compiler.module.createUnary(UnaryOp.AbsF32, arg0) : compiler.module.createUnary(UnaryOp.AbsF64, arg0); if (typeArguments[0].isAnyInteger) { - // TODO: ternaries for integers + if (typeArguments[0].isSignedInteger) { + tempLocal0 = compiler.currentFunction.addLocal(typeArguments[0]); + if (typeArguments[0].isLongInteger) + return compiler.module.createSelect( + compiler.module.createBinary(BinaryOp.SubI64, + compiler.module.createI64(0, 0), + compiler.module.createTeeLocal(tempLocal0.index, arg0) + ), + compiler.module.createGetLocal(tempLocal0.index, NativeType.I64), + compiler.module.createBinary(BinaryOp.LtI64, + compiler.module.createGetLocal(tempLocal0.index, NativeType.I64), + compiler.module.createI64(0, 0) + ) + ); + else + return compiler.module.createSelect( + compiler.module.createBinary(BinaryOp.SubI32, + compiler.module.createI32(0), + compiler.module.createTeeLocal(tempLocal0.index, arg0) + ), + compiler.module.createGetLocal(tempLocal0.index, NativeType.I32), + compiler.module.createBinary(BinaryOp.LtI32, + compiler.module.createGetLocal(tempLocal0.index, NativeType.I32), + compiler.module.createI32(0) + ) + ); + } else + return arg0; } } break; @@ -165,7 +194,26 @@ export function compileCall(compiler: Compiler, internalName: string, typeArgume ? compiler.module.createBinary(BinaryOp.MaxF32, arg0, arg1) : compiler.module.createBinary(BinaryOp.MaxF64, arg0, arg1); if (typeArguments[0].isAnyInteger) { - // TODO: ternaries for integers + tempLocal0 = compiler.currentFunction.addLocal(typeArguments[0]); + tempLocal1 = compiler.currentFunction.addLocal(typeArguments[0]); + if (typeArguments[0].isLongInteger) + return compiler.module.createSelect( + compiler.module.createTeeLocal(tempLocal0.index, arg0), + compiler.module.createTeeLocal(tempLocal1.index, arg1), + compiler.module.createBinary(typeArguments[0].isSignedInteger ? BinaryOp.GtI64 : BinaryOp.GtU64, + compiler.module.createGetLocal(tempLocal0.index, NativeType.I64), + compiler.module.createGetLocal(tempLocal1.index, NativeType.I64) + ) + ); + else + return compiler.module.createSelect( + compiler.module.createTeeLocal(tempLocal0.index, arg0), + compiler.module.createTeeLocal(tempLocal1.index, arg1), + compiler.module.createBinary(typeArguments[0].isSignedInteger ? BinaryOp.GtI32 : BinaryOp.GtU32, + compiler.module.createGetLocal(tempLocal0.index, NativeType.I32), + compiler.module.createGetLocal(tempLocal1.index, NativeType.I32) + ) + ); } } break; @@ -181,7 +229,26 @@ export function compileCall(compiler: Compiler, internalName: string, typeArgume ? compiler.module.createBinary(BinaryOp.MinF32, arg0, arg1) : compiler.module.createBinary(BinaryOp.MinF64, arg0, arg1); if (typeArguments[0].isAnyInteger) { - // TODO: ternaries for integers + tempLocal0 = compiler.currentFunction.addLocal(typeArguments[0]); + tempLocal1 = compiler.currentFunction.addLocal(typeArguments[0]); + if (typeArguments[0].isLongInteger) + return compiler.module.createSelect( + compiler.module.createTeeLocal(tempLocal0.index, arg0), + compiler.module.createTeeLocal(tempLocal1.index, arg1), + compiler.module.createBinary(typeArguments[0].isSignedInteger ? BinaryOp.LtI64 : BinaryOp.LtU64, + compiler.module.createGetLocal(tempLocal0.index, NativeType.I64), + compiler.module.createGetLocal(tempLocal1.index, NativeType.I64) + ) + ); + else + return compiler.module.createSelect( + compiler.module.createTeeLocal(tempLocal0.index, arg0), + compiler.module.createTeeLocal(tempLocal1.index, arg1), + compiler.module.createBinary(typeArguments[0].isSignedInteger ? BinaryOp.LtI32 : BinaryOp.LtU32, + compiler.module.createGetLocal(tempLocal0.index, NativeType.I32), + compiler.module.createGetLocal(tempLocal1.index, NativeType.I32) + ) + ); } } break; @@ -220,7 +287,7 @@ export function compileCall(compiler: Compiler, internalName: string, typeArgume } break; - case "nearest": + case "nearest": // nearest(value: T) -> T if (!validateCall(compiler, typeArguments, 1, operands, 1, reportNode)) return compiler.module.createUnreachable(); if ((compiler.currentType = typeArguments[0]).isAnyFloat) { @@ -231,7 +298,7 @@ export function compileCall(compiler: Compiler, internalName: string, typeArgume } break; - case "sqrt": + case "sqrt": // sqrt(value: T) -> T if (!validateCall(compiler, typeArguments, 1, operands, 1, reportNode)) return compiler.module.createUnreachable(); if ((compiler.currentType = typeArguments[0]).isAnyFloat) { @@ -242,7 +309,7 @@ export function compileCall(compiler: Compiler, internalName: string, typeArgume } break; - case "trunc": + case "trunc": // trunc(value: T) -> T if (!validateCall(compiler, typeArguments, 1, operands, 1, reportNode)) return compiler.module.createUnreachable(); if ((compiler.currentType = typeArguments[0]).isAnyFloat) { @@ -336,7 +403,7 @@ export function compileCall(compiler: Compiler, internalName: string, typeArgume validateCall(compiler, typeArguments, 0, operands, 0, reportNode); return compiler.module.createUnreachable(); - case "isNaN": + case "isNaN": // isNaN(value: T) -> bool compiler.currentType = Type.bool; if (!validateCall(compiler, typeArguments, 1, operands, 1, reportNode)) return compiler.module.createUnreachable(); @@ -346,22 +413,22 @@ export function compileCall(compiler: Compiler, internalName: string, typeArgume arg0 = compiler.compileExpression(operands[0], typeArguments[0]); // reports compiler.currentType = Type.bool; if (typeArguments[0] == Type.f32) { - tempLocal = compiler.currentFunction.addLocal(Type.f32); + tempLocal0 = compiler.currentFunction.addLocal(Type.f32); return compiler.module.createBinary(BinaryOp.NeF32, - compiler.module.createTeeLocal(tempLocal.index, arg0), - compiler.module.createGetLocal(tempLocal.index, NativeType.F32) + compiler.module.createTeeLocal(tempLocal0.index, arg0), + compiler.module.createGetLocal(tempLocal0.index, NativeType.F32) ); } else { - tempLocal = compiler.currentFunction.addLocal(Type.f64); + tempLocal0 = compiler.currentFunction.addLocal(Type.f64); return compiler.module.createBinary(BinaryOp.NeF64, - compiler.module.createTeeLocal(tempLocal.index, arg0), - compiler.module.createGetLocal(tempLocal.index, NativeType.F64) + compiler.module.createTeeLocal(tempLocal0.index, arg0), + compiler.module.createGetLocal(tempLocal0.index, NativeType.F64) ); } } break; - case "isFinite": + case "isFinite": // isFinite(value: T) -> bool compiler.currentType = Type.bool; if (!validateCall(compiler, typeArguments, 1, operands, 1, reportNode)) return compiler.module.createUnreachable(); @@ -371,40 +438,40 @@ export function compileCall(compiler: Compiler, internalName: string, typeArgume arg0 = compiler.compileExpression(operands[0], typeArguments[0]); // reports compiler.currentType = Type.bool; if (typeArguments[0] == Type.f32) { - tempLocal = compiler.currentFunction.addLocal(Type.f32); + tempLocal0 = compiler.currentFunction.addLocal(Type.f32); return compiler.module.createSelect( compiler.module.createBinary(BinaryOp.NeF32, compiler.module.createUnary(UnaryOp.AbsF32, - compiler.module.createTeeLocal(tempLocal.index, arg0) + compiler.module.createTeeLocal(tempLocal0.index, arg0) ), compiler.module.createF32(Infinity) ), compiler.module.createI32(0), compiler.module.createBinary(BinaryOp.EqF32, - compiler.module.createGetLocal(tempLocal.index, NativeType.F32), - compiler.module.createGetLocal(tempLocal.index, NativeType.F32) + compiler.module.createGetLocal(tempLocal0.index, NativeType.F32), + compiler.module.createGetLocal(tempLocal0.index, NativeType.F32) ) ); } else { - tempLocal = compiler.currentFunction.addLocal(Type.f64); + tempLocal0 = compiler.currentFunction.addLocal(Type.f64); return compiler.module.createSelect( compiler.module.createBinary(BinaryOp.NeF64, compiler.module.createUnary(UnaryOp.AbsF64, - compiler.module.createTeeLocal(tempLocal.index, arg0) + compiler.module.createTeeLocal(tempLocal0.index, arg0) ), compiler.module.createF64(Infinity) ), compiler.module.createI32(0), compiler.module.createBinary(BinaryOp.EqF64, - compiler.module.createGetLocal(tempLocal.index, NativeType.F64), - compiler.module.createGetLocal(tempLocal.index, NativeType.F64) + compiler.module.createGetLocal(tempLocal0.index, NativeType.F64), + compiler.module.createGetLocal(tempLocal0.index, NativeType.F64) ) ); } } break; - case "assert": + case "assert": // assert(isTrue: bool) -> void compiler.currentType = Type.void; if (!validateCall(compiler, typeArguments, 0, operands, 1, reportNode)) return compiler.module.createUnreachable(); diff --git a/src/compiler.ts b/src/compiler.ts index d63a964d..adc23a92 100644 --- a/src/compiler.ts +++ b/src/compiler.ts @@ -122,6 +122,8 @@ export class Compiler extends DiagnosticEmitter { currentFunction: Function; /** Marker indicating whether continue statements are allowed in the current break context. */ disallowContinue: bool = true; + /** Marker indicating that a new variable, if present, is always a local. Used to distinguish locals from globals in the start function. */ + variableIsLocal: bool = false; /** Counting memory offset. */ memoryOffset: U64 = new U64(8, 0); // leave space for (any size of) NULL @@ -757,7 +759,11 @@ export class Compiler extends DiagnosticEmitter { compileForStatement(statement: ForStatement): ExpressionRef { const context: string = this.currentFunction.enterBreakContext(); + const variableWasLocal: bool = this.variableIsLocal; + if (this.currentFunction == this.startFunction) + this.variableIsLocal = true; const initializer: ExpressionRef = statement.initializer ? this.compileStatement(statement.initializer) : this.module.createNop(); + this.variableIsLocal = variableWasLocal; const condition: ExpressionRef = statement.condition ? this.compileExpression(statement.condition, Type.i32) : this.module.createI32(1); const incrementor: ExpressionRef = statement.incrementor ? this.compileExpression(statement.incrementor, Type.void) : this.module.createNop(); const body: ExpressionRef = this.compileStatement(statement.statement); @@ -860,7 +866,7 @@ export class Compiler extends DiagnosticEmitter { const declarations: VariableDeclaration[] = statement.declarations; // top-level variables become globals - if (this.currentFunction == this.startFunction) { + if (this.currentFunction == this.startFunction && !this.variableIsLocal) { const isConst: bool = hasModifier(ModifierKind.CONST, statement.modifiers); for (let i: i32 = 0, k: i32 = declarations.length; i < k; ++i) this.compileGlobalDeclaration(declarations[i], isConst); diff --git a/src/program.ts b/src/program.ts index 5210b5a8..fff83495 100644 --- a/src/program.ts +++ b/src/program.ts @@ -981,9 +981,9 @@ export class Function extends Element { /** Leaves the current break context. */ leaveBreakContext(): void { - if (--this.breakMinor < 0) + if (this.breakMinor < 1) throw new Error("unexpected unbalanced break context"); - if (this.breakMinor == 0 && !--this.breakMajor) + if (--this.breakMinor == 0) this.breakContext = null; } } diff --git a/tests/compiler/assert.optimized.wast b/tests/compiler/assert.optimized.wast new file mode 100644 index 00000000..2b1bd4dc --- /dev/null +++ b/tests/compiler/assert.optimized.wast @@ -0,0 +1,10 @@ +(module + (type $v (func)) + (memory $0 1) + (data (i32.const 4) "\08") + (export "memory" (memory $0)) + (start $start) + (func $start (; 0 ;) (type $v) + (nop) + ) +) diff --git a/tests/compiler/assert.ts b/tests/compiler/assert.ts new file mode 100644 index 00000000..4d1656bd --- /dev/null +++ b/tests/compiler/assert.ts @@ -0,0 +1 @@ +assert(true); diff --git a/tests/compiler/assert.wast b/tests/compiler/assert.wast new file mode 100644 index 00000000..ba061847 --- /dev/null +++ b/tests/compiler/assert.wast @@ -0,0 +1,45 @@ +(module + (type $v (func)) + (memory $0 1) + (data (i32.const 4) "\08\00\00\00") + (export "memory" (memory $0)) + (start $start) + (func $start (; 0 ;) (type $v) + (if + (i32.eqz + (i32.const 1) + ) + (unreachable) + ) + ) +) +(; +[program.elements] + clz + ctz + popcnt + rotl + rotr + abs + ceil + copysign + floor + max + min + nearest + sqrt + trunc + current_memory + grow_memory + unreachable + load + store + reinterpret + select + sizeof + isNaN + isFinite + assert +[program.exports] + +;) diff --git a/tests/compiler/builtins.optimized.wast b/tests/compiler/builtins.optimized.wast index 1098edcc..88b5efa0 100644 --- a/tests/compiler/builtins.optimized.wast +++ b/tests/compiler/builtins.optimized.wast @@ -13,6 +13,38 @@ (func $start (; 0 ;) (type $v) (local $0 f32) (local $1 f64) + (local $2 i32) + (local $3 i32) + (local $4 i64) + (local $5 i64) + (drop + (select + (tee_local $2 + (i32.const 1) + ) + (tee_local $3 + (i32.const 2) + ) + (i32.gt_s + (get_local $2) + (get_local $3) + ) + ) + ) + (drop + (select + (tee_local $2 + (i32.const 1) + ) + (tee_local $3 + (i32.const 2) + ) + (i32.lt_s + (get_local $2) + (get_local $3) + ) + ) + ) (set_global $builtins/i (i32.const 31) ) @@ -28,6 +60,70 @@ (set_global $builtins/i (i32.const -2147483648) ) + (set_global $builtins/i + (select + (i32.sub + (i32.const 0) + (tee_local $2 + (i32.const -42) + ) + ) + (get_local $2) + (i32.lt_s + (get_local $2) + (i32.const 0) + ) + ) + ) + (if + (i32.ne + (get_global $builtins/i) + (i32.const 42) + ) + (unreachable) + ) + (set_global $builtins/i + (select + (tee_local $2 + (i32.const 1) + ) + (tee_local $3 + (i32.const 2) + ) + (i32.gt_s + (get_local $2) + (get_local $3) + ) + ) + ) + (if + (i32.ne + (get_global $builtins/i) + (i32.const 2) + ) + (unreachable) + ) + (set_global $builtins/i + (select + (tee_local $2 + (i32.const 1) + ) + (tee_local $3 + (i32.const 2) + ) + (i32.lt_s + (get_local $2) + (get_local $3) + ) + ) + ) + (if + (i32.ne + (get_global $builtins/i) + (i32.const 1) + ) + (unreachable) + ) (set_global $builtins/I (i64.const 63) ) @@ -43,6 +139,70 @@ (set_global $builtins/I (i64.const -9223372036854775808) ) + (set_global $builtins/I + (select + (i64.sub + (i64.const 0) + (tee_local $4 + (i64.const -42) + ) + ) + (get_local $4) + (i64.lt_s + (get_local $4) + (i64.const 0) + ) + ) + ) + (if + (i64.ne + (get_global $builtins/I) + (i64.const 42) + ) + (unreachable) + ) + (set_global $builtins/I + (select + (tee_local $4 + (i64.const 1) + ) + (tee_local $5 + (i64.const 2) + ) + (i64.gt_s + (get_local $4) + (get_local $5) + ) + ) + ) + (if + (i64.ne + (get_global $builtins/I) + (i64.const 2) + ) + (unreachable) + ) + (set_global $builtins/I + (select + (tee_local $4 + (i64.const 1) + ) + (tee_local $5 + (i64.const 2) + ) + (i64.lt_s + (get_local $4) + (get_local $5) + ) + ) + ) + (if + (i32.ne + (get_global $builtins/i) + (i32.const 1) + ) + (unreachable) + ) (set_global $builtins/f (f32.const nan:0x400000) ) @@ -168,6 +328,12 @@ (i32.const 8) (get_global $builtins/i) ) + (i32.store + (i32.const 8) + (i32.load + (i32.const 8) + ) + ) (set_global $builtins/I (i64.load (i32.const 8) @@ -177,6 +343,12 @@ (i32.const 8) (get_global $builtins/I) ) + (i64.store + (i32.const 8) + (i64.load + (i32.const 8) + ) + ) (set_global $builtins/f (f32.load (i32.const 8) @@ -186,6 +358,12 @@ (i32.const 8) (get_global $builtins/f) ) + (f32.store + (i32.const 8) + (f32.load + (i32.const 8) + ) + ) (set_global $builtins/F (f64.load (i32.const 8) @@ -195,6 +373,12 @@ (i32.const 8) (get_global $builtins/F) ) + (f64.store + (i32.const 8) + (f64.load + (i32.const 8) + ) + ) (set_global $builtins/i (i32.const 1067450368) ) @@ -244,6 +428,15 @@ ) (unreachable) ) + (if + (f64.eq + (tee_local $1 + (f64.const nan:0x8000000000000) + ) + (get_local $1) + ) + (unreachable) + ) (if (select (f32.ne @@ -280,6 +473,62 @@ ) (unreachable) ) + (if + (select + (f64.ne + (f64.abs + (tee_local $1 + (f64.const nan:0x8000000000000) + ) + ) + (f64.const inf) + ) + (i32.const 0) + (f64.eq + (get_local $1) + (get_local $1) + ) + ) + (unreachable) + ) + (if + (select + (f64.ne + (f64.abs + (tee_local $1 + (f64.const inf) + ) + ) + (f64.const inf) + ) + (i32.const 0) + (f64.eq + (get_local $1) + (get_local $1) + ) + ) + (unreachable) + ) + (if + (i32.eqz + (select + (f32.ne + (f32.abs + (tee_local $0 + (f32.const 0) + ) + ) + (f32.const inf) + ) + (i32.const 0) + (f32.eq + (get_local $0) + (get_local $0) + ) + ) + ) + (unreachable) + ) (if (i32.eqz (select diff --git a/tests/compiler/builtins.ts b/tests/compiler/builtins.ts index eaebe28e..5b27fd12 100644 --- a/tests/compiler/builtins.ts +++ b/tests/compiler/builtins.ts @@ -9,12 +9,18 @@ ctz(1); popcnt(1); rotl(1, 1); rotr(1, 1); +abs(-42); +max(1, 2); +min(1, 2); i = clz(1); i = ctz(1); i = popcnt(1); i = rotl(1, 1); i = rotr(1, 1); +i = abs(-42); assert(i == 42); +i = max(1, 2); assert(i == 2); +i = min(1, 2); assert(i == 1); let I: i64; @@ -23,12 +29,16 @@ ctz(1); popcnt(1); rotl(1, 1); rotr(1, 1); +abs(-42); I = clz(1); I = ctz(1); I = popcnt(1); I = rotl(1, 1); I = rotr(1, 1); +I = abs(-42); assert(I == 42); +I = max(1, 2); assert(I == 2); +I = min(1, 2); assert(i == 1); // floating point builtins @@ -96,14 +106,14 @@ b = isFinite(1.25); // load and store builtins -i = load(8); -store(8, i); -I = load(8); -store(8, I); -f = load(8); -store(8, f); -F = load(8); -store(8, F); +i = load(8); store(8, i); +store(8, load(8)); +I = load(8); store(8, I); +store(8, load(8)); +f = load(8); store(8, f); +store(8, load(8)); +F = load(8); store(8, F); +store(8, load(8)); // reinterpretation builtins @@ -143,8 +153,6 @@ if (0) unreachable(); // AS specific builtins -assert(true); - sizeof(); sizeof(); sizeof(); @@ -159,13 +167,12 @@ sizeof(); sizeof(); sizeof(); -if (NaN == NaN) - unreachable(); -if (!isNaN(NaN)) - unreachable(); -if (isFinite(NaN)) - unreachable(); -if (isFinite(Infinity)) - unreachable(); -if (!isFinite(0)) - unreachable(); +assert(NaN != NaN); +assert(isNaN(NaN)); +assert(isNaN(NaN)); +assert(!isFinite(NaN)); +assert(!isFinite(Infinity)); +assert(!isFinite(NaN)); +assert(!isFinite(Infinity)); +assert(isFinite(0)); +assert(isFinite(0)); diff --git a/tests/compiler/builtins.wast b/tests/compiler/builtins.wast index 8b68ac67..86eeb309 100644 --- a/tests/compiler/builtins.wast +++ b/tests/compiler/builtins.wast @@ -11,18 +11,38 @@ (export "memory" (memory $0)) (start $start) (func $start (; 0 ;) (type $v) - (local $0 f32) - (local $1 f32) - (local $2 f32) - (local $3 f32) - (local $4 f64) - (local $5 f64) - (local $6 f64) - (local $7 f64) - (local $8 f32) - (local $9 f32) - (local $10 f32) - (local $11 f64) + (local $0 i32) + (local $1 i32) + (local $2 i32) + (local $3 i32) + (local $4 i32) + (local $5 i32) + (local $6 i32) + (local $7 i32) + (local $8 i32) + (local $9 i32) + (local $10 i64) + (local $11 i64) + (local $12 i64) + (local $13 i64) + (local $14 i64) + (local $15 i64) + (local $16 f32) + (local $17 f32) + (local $18 f32) + (local $19 f32) + (local $20 f64) + (local $21 f64) + (local $22 f64) + (local $23 f64) + (local $24 f32) + (local $25 f64) + (local $26 f32) + (local $27 f32) + (local $28 f64) + (local $29 f64) + (local $30 f32) + (local $31 f64) (drop (i32.clz (i32.const 1) @@ -50,154 +70,364 @@ (i32.const 1) ) ) - (set_global $builtins/i - (i32.clz - (i32.const 1) - ) - ) - (set_global $builtins/i - (i32.ctz - (i32.const 1) - ) - ) - (set_global $builtins/i - (i32.popcnt - (i32.const 1) - ) - ) - (set_global $builtins/i - (i32.rotl - (i32.const 1) - (i32.const 1) - ) - ) - (set_global $builtins/i - (i32.rotr - (i32.const 1) - (i32.const 1) - ) - ) (drop - (i64.clz - (i64.const 1) - ) - ) - (drop - (i64.ctz - (i64.const 1) - ) - ) - (drop - (i64.popcnt - (i64.const 1) - ) - ) - (drop - (i64.rotl - (i64.const 1) - (i64.const 1) - ) - ) - (drop - (i64.rotr - (i64.const 1) - (i64.const 1) - ) - ) - (set_global $builtins/I - (i64.clz - (i64.const 1) - ) - ) - (set_global $builtins/I - (i64.ctz - (i64.const 1) - ) - ) - (set_global $builtins/I - (i64.popcnt - (i64.const 1) - ) - ) - (set_global $builtins/I - (i64.rotl - (i64.const 1) - (i64.const 1) - ) - ) - (set_global $builtins/I - (i64.rotr - (i64.const 1) - (i64.const 1) - ) - ) - (drop - (f32.const nan:0x400000) - ) - (drop - (f32.const inf) - ) - (drop - (f32.abs - (f32.const 1.25) - ) - ) - (drop - (f32.ceil - (f32.const 1.25) - ) - ) - (drop - (f32.copysign - (f32.const 1.25) - (f32.const 2.5) - ) - ) - (drop - (f32.floor - (f32.const 1.25) - ) - ) - (drop - (f32.max - (f32.const 1.25) - (f32.const 2.5) - ) - ) - (drop - (f32.min - (f32.const 1.25) - (f32.const 2.5) - ) - ) - (drop - (f32.nearest - (f32.const 1.25) - ) - ) - (drop - (f32.sqrt - (f32.const 1.25) - ) - ) - (drop - (f32.trunc - (f32.const 1.25) - ) - ) - (drop - (f32.ne - (tee_local $0 - (f32.const 1.25) + (select + (i32.sub + (i32.const 0) + (tee_local $0 + (i32.sub + (i32.const 0) + (i32.const 42) + ) + ) ) (get_local $0) + (i32.lt_s + (get_local $0) + (i32.const 0) + ) + ) + ) + (drop + (select + (tee_local $1 + (i32.const 1) + ) + (tee_local $2 + (i32.const 2) + ) + (i32.gt_s + (get_local $1) + (get_local $2) + ) + ) + ) + (drop + (select + (tee_local $3 + (i32.const 1) + ) + (tee_local $4 + (i32.const 2) + ) + (i32.lt_s + (get_local $3) + (get_local $4) + ) + ) + ) + (set_global $builtins/i + (i32.clz + (i32.const 1) + ) + ) + (set_global $builtins/i + (i32.ctz + (i32.const 1) + ) + ) + (set_global $builtins/i + (i32.popcnt + (i32.const 1) + ) + ) + (set_global $builtins/i + (i32.rotl + (i32.const 1) + (i32.const 1) + ) + ) + (set_global $builtins/i + (i32.rotr + (i32.const 1) + (i32.const 1) + ) + ) + (set_global $builtins/i + (select + (i32.sub + (i32.const 0) + (tee_local $5 + (i32.sub + (i32.const 0) + (i32.const 42) + ) + ) + ) + (get_local $5) + (i32.lt_s + (get_local $5) + (i32.const 0) + ) + ) + ) + (if + (i32.eqz + (i32.eq + (get_global $builtins/i) + (i32.const 42) + ) + ) + (unreachable) + ) + (set_global $builtins/i + (select + (tee_local $6 + (i32.const 1) + ) + (tee_local $7 + (i32.const 2) + ) + (i32.gt_s + (get_local $6) + (get_local $7) + ) + ) + ) + (if + (i32.eqz + (i32.eq + (get_global $builtins/i) + (i32.const 2) + ) + ) + (unreachable) + ) + (set_global $builtins/i + (select + (tee_local $8 + (i32.const 1) + ) + (tee_local $9 + (i32.const 2) + ) + (i32.lt_s + (get_local $8) + (get_local $9) + ) + ) + ) + (if + (i32.eqz + (i32.eq + (get_global $builtins/i) + (i32.const 1) + ) + ) + (unreachable) + ) + (drop + (i64.clz + (i64.const 1) + ) + ) + (drop + (i64.ctz + (i64.const 1) + ) + ) + (drop + (i64.popcnt + (i64.const 1) + ) + ) + (drop + (i64.rotl + (i64.const 1) + (i64.const 1) + ) + ) + (drop + (i64.rotr + (i64.const 1) + (i64.const 1) + ) + ) + (drop + (select + (i64.sub + (i64.const 0) + (tee_local $10 + (i64.sub + (i64.const 0) + (i64.const 42) + ) + ) + ) + (get_local $10) + (i64.lt_s + (get_local $10) + (i64.const 0) + ) + ) + ) + (set_global $builtins/I + (i64.clz + (i64.const 1) + ) + ) + (set_global $builtins/I + (i64.ctz + (i64.const 1) + ) + ) + (set_global $builtins/I + (i64.popcnt + (i64.const 1) + ) + ) + (set_global $builtins/I + (i64.rotl + (i64.const 1) + (i64.const 1) + ) + ) + (set_global $builtins/I + (i64.rotr + (i64.const 1) + (i64.const 1) + ) + ) + (set_global $builtins/I + (select + (i64.sub + (i64.const 0) + (tee_local $11 + (i64.sub + (i64.const 0) + (i64.const 42) + ) + ) + ) + (get_local $11) + (i64.lt_s + (get_local $11) + (i64.const 0) + ) + ) + ) + (if + (i32.eqz + (i64.eq + (get_global $builtins/I) + (i64.const 42) + ) + ) + (unreachable) + ) + (set_global $builtins/I + (select + (tee_local $12 + (i64.const 1) + ) + (tee_local $13 + (i64.const 2) + ) + (i64.gt_s + (get_local $12) + (get_local $13) + ) + ) + ) + (if + (i32.eqz + (i64.eq + (get_global $builtins/I) + (i64.const 2) + ) + ) + (unreachable) + ) + (set_global $builtins/I + (select + (tee_local $14 + (i64.const 1) + ) + (tee_local $15 + (i64.const 2) + ) + (i64.lt_s + (get_local $14) + (get_local $15) + ) + ) + ) + (if + (i32.eqz + (i32.eq + (get_global $builtins/i) + (i32.const 1) + ) + ) + (unreachable) + ) + (drop + (f32.const nan:0x400000) + ) + (drop + (f32.const inf) + ) + (drop + (f32.abs + (f32.const 1.25) + ) + ) + (drop + (f32.ceil + (f32.const 1.25) + ) + ) + (drop + (f32.copysign + (f32.const 1.25) + (f32.const 2.5) + ) + ) + (drop + (f32.floor + (f32.const 1.25) + ) + ) + (drop + (f32.max + (f32.const 1.25) + (f32.const 2.5) + ) + ) + (drop + (f32.min + (f32.const 1.25) + (f32.const 2.5) + ) + ) + (drop + (f32.nearest + (f32.const 1.25) + ) + ) + (drop + (f32.sqrt + (f32.const 1.25) + ) + ) + (drop + (f32.trunc + (f32.const 1.25) + ) + ) + (drop + (f32.ne + (tee_local $16 + (f32.const 1.25) + ) + (get_local $16) ) ) (drop (select (f32.ne (f32.abs - (tee_local $1 + (tee_local $17 (f32.const 1.25) ) ) @@ -205,8 +435,8 @@ ) (i32.const 0) (f32.eq - (get_local $1) - (get_local $1) + (get_local $17) + (get_local $17) ) ) ) @@ -266,17 +496,17 @@ ) (set_global $builtins/b (f32.ne - (tee_local $2 + (tee_local $18 (f32.const 1.25) ) - (get_local $2) + (get_local $18) ) ) (set_global $builtins/b (select (f32.ne (f32.abs - (tee_local $3 + (tee_local $19 (f32.const 1.25) ) ) @@ -284,8 +514,8 @@ ) (i32.const 0) (f32.eq - (get_local $3) - (get_local $3) + (get_local $19) + (get_local $19) ) ) ) @@ -351,17 +581,17 @@ ) (drop (f64.ne - (tee_local $4 + (tee_local $20 (f64.const 1.25) ) - (get_local $4) + (get_local $20) ) ) (drop (select (f64.ne (f64.abs - (tee_local $5 + (tee_local $21 (f64.const 1.25) ) ) @@ -369,8 +599,8 @@ ) (i32.const 0) (f64.eq - (get_local $5) - (get_local $5) + (get_local $21) + (get_local $21) ) ) ) @@ -430,17 +660,17 @@ ) (set_global $builtins/b (f64.ne - (tee_local $6 + (tee_local $22 (f64.const 1.25) ) - (get_local $6) + (get_local $22) ) ) (set_global $builtins/b (select (f64.ne (f64.abs - (tee_local $7 + (tee_local $23 (f64.const 1.25) ) ) @@ -448,8 +678,8 @@ ) (i32.const 0) (f64.eq - (get_local $7) - (get_local $7) + (get_local $23) + (get_local $23) ) ) ) @@ -462,6 +692,12 @@ (i32.const 8) (get_global $builtins/i) ) + (i32.store + (i32.const 8) + (i32.load + (i32.const 8) + ) + ) (set_global $builtins/I (i64.load (i32.const 8) @@ -471,6 +707,12 @@ (i32.const 8) (get_global $builtins/I) ) + (i64.store + (i32.const 8) + (i64.load + (i32.const 8) + ) + ) (set_global $builtins/f (f32.load (i32.const 8) @@ -480,6 +722,12 @@ (i32.const 8) (get_global $builtins/f) ) + (f32.store + (i32.const 8) + (f32.load + (i32.const 8) + ) + ) (set_global $builtins/F (f64.load (i32.const 8) @@ -489,6 +737,12 @@ (i32.const 8) (get_global $builtins/F) ) + (f64.store + (i32.const 8) + (f64.load + (i32.const 8) + ) + ) (drop (i32.reinterpret/f32 (f32.const 1.25) @@ -605,101 +859,180 @@ (i32.const 0) (unreachable) ) + (drop + (i32.const 1) + ) + (drop + (i32.const 2) + ) + (drop + (i32.const 4) + ) + (drop + (i32.const 8) + ) + (drop + (i32.const 4) + ) + (drop + (i32.const 1) + ) + (drop + (i32.const 1) + ) + (drop + (i32.const 2) + ) + (drop + (i32.const 4) + ) + (drop + (i32.const 8) + ) + (drop + (i32.const 4) + ) + (drop + (i32.const 4) + ) + (drop + (i32.const 8) + ) (if (i32.eqz - (i32.const 1) - ) - (unreachable) - ) - (drop - (i32.const 1) - ) - (drop - (i32.const 2) - ) - (drop - (i32.const 4) - ) - (drop - (i32.const 8) - ) - (drop - (i32.const 4) - ) - (drop - (i32.const 1) - ) - (drop - (i32.const 1) - ) - (drop - (i32.const 2) - ) - (drop - (i32.const 4) - ) - (drop - (i32.const 8) - ) - (drop - (i32.const 4) - ) - (drop - (i32.const 4) - ) - (drop - (i32.const 8) - ) - (if - (f64.eq - (f64.const nan:0x8000000000000) - (f64.const nan:0x8000000000000) + (f64.ne + (f64.const nan:0x8000000000000) + (f64.const nan:0x8000000000000) + ) ) (unreachable) ) (if (i32.eqz (f32.ne - (tee_local $8 + (tee_local $24 (f32.const nan:0x400000) ) - (get_local $8) + (get_local $24) ) ) (unreachable) ) (if - (select - (f32.ne - (f32.abs - (tee_local $9 - (f32.const nan:0x400000) - ) + (i32.eqz + (f64.ne + (tee_local $25 + (f64.const nan:0x8000000000000) ) - (f32.const inf) - ) - (i32.const 0) - (f32.eq - (get_local $9) - (get_local $9) + (get_local $25) ) ) (unreachable) ) (if - (select - (f32.ne - (f32.abs - (tee_local $10 + (i32.eqz + (i32.eqz + (select + (f32.ne + (f32.abs + (tee_local $26 + (f32.const nan:0x400000) + ) + ) (f32.const inf) ) + (i32.const 0) + (f32.eq + (get_local $26) + (get_local $26) + ) ) - (f32.const inf) ) - (i32.const 0) - (f32.eq - (get_local $10) - (get_local $10) + ) + (unreachable) + ) + (if + (i32.eqz + (i32.eqz + (select + (f32.ne + (f32.abs + (tee_local $27 + (f32.const inf) + ) + ) + (f32.const inf) + ) + (i32.const 0) + (f32.eq + (get_local $27) + (get_local $27) + ) + ) + ) + ) + (unreachable) + ) + (if + (i32.eqz + (i32.eqz + (select + (f64.ne + (f64.abs + (tee_local $28 + (f64.const nan:0x8000000000000) + ) + ) + (f64.const inf) + ) + (i32.const 0) + (f64.eq + (get_local $28) + (get_local $28) + ) + ) + ) + ) + (unreachable) + ) + (if + (i32.eqz + (i32.eqz + (select + (f64.ne + (f64.abs + (tee_local $29 + (f64.const inf) + ) + ) + (f64.const inf) + ) + (i32.const 0) + (f64.eq + (get_local $29) + (get_local $29) + ) + ) + ) + ) + (unreachable) + ) + (if + (i32.eqz + (select + (f32.ne + (f32.abs + (tee_local $30 + (f32.const 0) + ) + ) + (f32.const inf) + ) + (i32.const 0) + (f32.eq + (get_local $30) + (get_local $30) + ) ) ) (unreachable) @@ -709,7 +1042,7 @@ (select (f64.ne (f64.abs - (tee_local $11 + (tee_local $31 (f64.const 0) ) ) @@ -717,8 +1050,8 @@ ) (i32.const 0) (f64.eq - (get_local $11) - (get_local $11) + (get_local $31) + (get_local $31) ) ) ) diff --git a/tests/compiler/for.optimized.wast b/tests/compiler/for.optimized.wast index e2892b45..0d8c6433 100644 --- a/tests/compiler/for.optimized.wast +++ b/tests/compiler/for.optimized.wast @@ -6,6 +6,7 @@ (export "memory" (memory $0)) (start $start) (func $start (; 0 ;) (type $v) + (local $0 i32) (set_global $for/i (i32.const 0) ) @@ -33,5 +34,74 @@ ) (unreachable) ) + (set_local $0 + (i32.const 0) + ) + (loop $continue$2.1 + (if + (i32.lt_s + (get_local $0) + (i32.const 10) + ) + (block + (set_local $0 + (i32.add + (get_local $0) + (i32.const 1) + ) + ) + (br $continue$2.1) + ) + ) + ) + (loop $continue$3.1 + (if + (i32.gt_s + (get_global $for/i) + (i32.const 0) + ) + (block + (set_global $for/i + (i32.sub + (get_global $for/i) + (i32.const 1) + ) + ) + (br $continue$3.1) + ) + ) + ) + (if + (get_global $for/i) + (unreachable) + ) + (block $break$4.1 + (loop $continue$4.1 + (br_if $break$4.1 + (i32.eq + (get_global $for/i) + (i32.const 10) + ) + ) + (set_global $for/i + (i32.add + (get_global $for/i) + (i32.const 1) + ) + ) + (br $continue$4.1) + ) + ) + (loop $continue$5.1 + (set_global $for/i + (i32.sub + (get_global $for/i) + (i32.const 1) + ) + ) + (br_if $continue$5.1 + (get_global $for/i) + ) + ) ) ) diff --git a/tests/compiler/for.ts b/tests/compiler/for.ts index 1549178b..0c392197 100644 --- a/tests/compiler/for.ts +++ b/tests/compiler/for.ts @@ -2,5 +2,19 @@ let i: i32; for (i = 0; i < 10; ++i) { ; } -if (i != 10) - unreachable(); +assert(i == 10); + +for (let j: i32 = 0; j < 10; ++j) { + ; +} + +for (; i > 0; --i); +assert(i == 0); + +for (;; ++i) + if (i == 10) + break; + +for (;;) + if (--i == 0) + break; diff --git a/tests/compiler/for.wast b/tests/compiler/for.wast index 5ab91989..25a6254f 100644 --- a/tests/compiler/for.wast +++ b/tests/compiler/for.wast @@ -6,6 +6,7 @@ (export "memory" (memory $0)) (start $start) (func $start (; 0 ;) (type $v) + (local $0 i32) (block $break$1.1 (set_global $for/i (i32.const 0) @@ -30,12 +31,120 @@ ) ) (if - (i32.ne - (get_global $for/i) - (i32.const 10) + (i32.eqz + (i32.eq + (get_global $for/i) + (i32.const 10) + ) ) (unreachable) ) + (block $break$2.1 + (block + (set_local $0 + (i32.const 0) + ) + ) + (loop $continue$2.1 + (if + (i32.lt_s + (get_local $0) + (i32.const 10) + ) + (block + (nop) + (set_local $0 + (i32.add + (get_local $0) + (i32.const 1) + ) + ) + (br $continue$2.1) + ) + ) + ) + ) + (block $break$3.1 + (nop) + (loop $continue$3.1 + (if + (i32.gt_s + (get_global $for/i) + (i32.const 0) + ) + (block + (nop) + (set_global $for/i + (i32.sub + (get_global $for/i) + (i32.const 1) + ) + ) + (br $continue$3.1) + ) + ) + ) + ) + (if + (i32.eqz + (i32.eq + (get_global $for/i) + (i32.const 0) + ) + ) + (unreachable) + ) + (block $break$4.1 + (nop) + (loop $continue$4.1 + (if + (i32.const 1) + (block + (if + (i32.eq + (get_global $for/i) + (i32.const 10) + ) + (br $break$4.1) + ) + (set_global $for/i + (i32.add + (get_global $for/i) + (i32.const 1) + ) + ) + (br $continue$4.1) + ) + ) + ) + ) + (block $break$5.1 + (nop) + (loop $continue$5.1 + (if + (i32.const 1) + (block + (if + (i32.eq + (block (result i32) + (set_global $for/i + (i32.sub + (get_global $for/i) + (i32.const 1) + ) + ) + (get_global $for/i) + ) + (i32.const 0) + ) + (br $break$5.1) + ) + (nop) + (br $continue$5.1) + ) + ) + ) + ) ) ) (; diff --git a/tests/compiler/logical.ts b/tests/compiler/logical.ts index 68dc4f89..233a45e4 100644 --- a/tests/compiler/logical.ts +++ b/tests/compiler/logical.ts @@ -9,39 +9,31 @@ let i: i32; i = 1 && 2; -if (i != 2) - unreachable(); +assert(i == 2); i = 0 || 1; -if (i != 1) - unreachable(); +assert(i == 1); let I: i64; I = 1 && 2; -if (I != 2) - unreachable(); +assert(I == 2); I = 0 || 1; -if (I != 1) - unreachable(); +assert(I == 1); let f: f32; f = 1.0 && 2.0; -if (f != 2.0) - unreachable(); +assert(f == 2.0); f = 0.0 || 1.0; -if (f != 1.0) - unreachable(); +assert(f == 1.0); let F: f64; F = 1.0 && 2.0; -if (F != 2.0) - unreachable(); +assert(F == 2.0); F = 0.0 || 1.0; -if (F != 1.0) - unreachable(); +assert(F == 1.0); diff --git a/tests/compiler/logical.wast b/tests/compiler/logical.wast index 090776e2..a7909041 100644 --- a/tests/compiler/logical.wast +++ b/tests/compiler/logical.wast @@ -113,9 +113,11 @@ ) ) (if - (i32.ne - (get_global $logical/i) - (i32.const 2) + (i32.eqz + (i32.eq + (get_global $logical/i) + (i32.const 2) + ) ) (unreachable) ) @@ -129,9 +131,11 @@ ) ) (if - (i32.ne - (get_global $logical/i) - (i32.const 1) + (i32.eqz + (i32.eq + (get_global $logical/i) + (i32.const 1) + ) ) (unreachable) ) @@ -148,9 +152,11 @@ ) ) (if - (i64.ne - (get_global $logical/I) - (i64.const 2) + (i32.eqz + (i64.eq + (get_global $logical/I) + (i64.const 2) + ) ) (unreachable) ) @@ -167,9 +173,11 @@ ) ) (if - (i64.ne - (get_global $logical/I) - (i64.const 1) + (i32.eqz + (i64.eq + (get_global $logical/I) + (i64.const 1) + ) ) (unreachable) ) @@ -186,9 +194,11 @@ ) ) (if - (f32.ne - (get_global $logical/f) - (f32.const 2) + (i32.eqz + (f32.eq + (get_global $logical/f) + (f32.const 2) + ) ) (unreachable) ) @@ -205,9 +215,11 @@ ) ) (if - (f32.ne - (get_global $logical/f) - (f32.const 1) + (i32.eqz + (f32.eq + (get_global $logical/f) + (f32.const 1) + ) ) (unreachable) ) @@ -224,9 +236,11 @@ ) ) (if - (f64.ne - (get_global $logical/F) - (f64.const 2) + (i32.eqz + (f64.eq + (get_global $logical/F) + (f64.const 2) + ) ) (unreachable) ) @@ -243,9 +257,11 @@ ) ) (if - (f64.ne - (get_global $logical/F) - (f64.const 1) + (i32.eqz + (f64.eq + (get_global $logical/F) + (f64.const 1) + ) ) (unreachable) ) diff --git a/tests/compiler/switch.optimized.wast b/tests/compiler/switch.optimized.wast index bb32ec06..c3d6d2ad 100644 --- a/tests/compiler/switch.optimized.wast +++ b/tests/compiler/switch.optimized.wast @@ -7,36 +7,15 @@ (export "doSwitchDefaultOmitted" (func $switch/doSwitchDefaultOmitted)) (export "memory" (memory $0)) (func $switch/doSwitch (; 0 ;) (type $ii) (param $0 i32) (result i32) - (local $1 i32) (block $case4$1.1 (block $case2$1.1 - (if - (i32.ne - (tee_local $1 + (block $case0$1.1 + (block $tablify|0 + (br_table $case2$1.1 $case0$1.1 $case4$1.1 $case4$1.1 $tablify|0 (get_local $0) ) - (i32.const 1) - ) - (block - (br_if $case2$1.1 - (i32.eqz - (get_local $1) - ) - ) - (br_if $case4$1.1 - (i32.eq - (get_local $1) - (i32.const 2) - ) - ) - (br_if $case4$1.1 - (i32.eq - (get_local $1) - (i32.const 3) - ) - ) - (br $case2$1.1) ) + (br $case2$1.1) ) (return (i32.const 1) @@ -49,31 +28,18 @@ (i32.const 23) ) (func $switch/doSwitchDefaultFirst (; 1 ;) (type $ii) (param $0 i32) (result i32) - (local $1 i32) (block $case3$1.1 - (if - (i32.ne - (tee_local $1 - (get_local $0) + (block $case1$1.1 + (block $tablify|0 + (br_table $case1$1.1 $case3$1.1 $case3$1.1 $tablify|0 + (i32.sub + (get_local $0) + (i32.const 1) + ) ) - (i32.const 1) ) - (block - (br_if $case3$1.1 - (i32.eq - (get_local $1) - (i32.const 2) - ) - ) - (br_if $case3$1.1 - (i32.eq - (get_local $1) - (i32.const 3) - ) - ) - (return - (i32.const 0) - ) + (return + (i32.const 0) ) ) (return @@ -83,31 +49,18 @@ (i32.const 23) ) (func $switch/doSwitchDefaultOmitted (; 2 ;) (type $ii) (param $0 i32) (result i32) - (local $1 i32) (block $break$1.1 (block $case2$1.1 - (if - (i32.ne - (tee_local $1 - (get_local $0) - ) - (i32.const 1) - ) - (block - (br_if $case2$1.1 - (i32.eq - (get_local $1) - (i32.const 2) + (block $case0$1.1 + (block $tablify|0 + (br_table $case0$1.1 $case2$1.1 $case2$1.1 $tablify|0 + (i32.sub + (get_local $0) + (i32.const 1) ) ) - (br_if $case2$1.1 - (i32.eq - (get_local $1) - (i32.const 3) - ) - ) - (br $break$1.1) ) + (br $break$1.1) ) (return (i32.const 1)