From 2fa7fc7885ee86498861799b8ba7062b5599e31e Mon Sep 17 00:00:00 2001 From: dcodeIO Date: Tue, 23 Jan 2018 15:44:25 +0100 Subject: [PATCH] Take advantage of smaller integer load and store ops --- .../game-of-life/assembly/game-of-life.ts | 8 +- src/builtins.ts | 42 +++--- src/compiler.ts | 30 ++-- src/module.ts | 3 +- src/program.ts | 19 ++- std/assembly.d.ts | 4 +- tests/compiler/builtins.optimized.wast | 134 +++++++++++++++++ tests/compiler/builtins.ts | 41 ++++++ tests/compiler/builtins.wast | 138 ++++++++++++++++++ tests/compiler/game-of-life.optimized.wast | 95 ++++++------ tests/compiler/game-of-life.wast | 57 ++++---- tests/compiler/showcase.optimized.wast | 134 +++++++++++++++++ tests/compiler/showcase.wast | 138 ++++++++++++++++++ 13 files changed, 719 insertions(+), 124 deletions(-) diff --git a/examples/game-of-life/assembly/game-of-life.ts b/examples/game-of-life/assembly/game-of-life.ts index d400fcce..fc7045ab 100644 --- a/examples/game-of-life/assembly/game-of-life.ts +++ b/examples/game-of-life/assembly/game-of-life.ts @@ -21,9 +21,11 @@ export function step(): void { for (var x: u32 = 0; x < w; ++x) { var xm1 = select(wm1, x - 1, x == 0), xp1 = select(0, x + 1, x == wm1); - var n = load(ym1 * w + xm1) + load(ym1 * w + x) + load(ym1 * w + xp1) - + load(y * w + xm1) + load(y * w + xp1) - + load(yp1 * w + xm1) + load(yp1 * w + x) + load(yp1 * w + xp1); + var n = ( + load(ym1 * w + xm1) + load(ym1 * w + x) + load(ym1 * w + xp1) + + load(y * w + xm1) + load(y * w + xp1) + + load(yp1 * w + xm1) + load(yp1 * w + x) + load(yp1 * w + xp1) + ); if (load(y * w + x)) { if (n < 2 || n > 3) store(s + y * w + x, 0); diff --git a/src/builtins.ts b/src/builtins.ts index 1e525279..1ac74c9d 100644 --- a/src/builtins.ts +++ b/src/builtins.ts @@ -1338,7 +1338,7 @@ export function compileCall(compiler: Compiler, prototype: FunctionPrototype, ty // memory access - case "load": // load(offset: usize, constantOffset?: usize) -> T + case "load": // load(offset: usize, constantOffset?: usize) -> * if (operands.length < 1 || operands.length > 2) { if (!(typeArguments && typeArguments.length == 1)) compiler.error(DiagnosticCode.Expected_0_type_arguments_but_got_1, reportNode.range, "1", typeArguments ? typeArguments.length.toString(10) : "0"); @@ -1358,37 +1358,43 @@ export function compileCall(compiler: Compiler, prototype: FunctionPrototype, ty offset = operands.length == 2 ? evaluateConstantOffset(compiler, operands[1]) : 0; // reports if (offset < 0) return module.createUnreachable(); - compiler.currentType = typeArguments[0]; - return module.createLoad(typeArguments[0].byteSize, typeArguments[0].is(TypeFlags.SIGNED | TypeFlags.INTEGER), arg0, typeArguments[0].toNativeType(), offset); + return module.createLoad(typeArguments[0].byteSize, typeArguments[0].is(TypeFlags.SIGNED | TypeFlags.INTEGER), arg0, + typeArguments[0].is(TypeFlags.INTEGER) && contextualType.is(TypeFlags.INTEGER) && contextualType.size >= typeArguments[0].size + ? (compiler.currentType = contextualType).toNativeType() + : (compiler.currentType = typeArguments[0]).toNativeType() + , offset); - case "store": // store(offset: usize, value: T, constantOffset?: usize) -> void + case "store": // store(offset: usize, value: *, constantOffset?: usize) -> void compiler.currentType = Type.void; if (operands.length < 2 || operands.length > 3) { - if (typeArguments && typeArguments.length != 1) - compiler.error(DiagnosticCode.Expected_0_type_arguments_but_got_1, reportNode.range, "1", typeArguments.length.toString(10)); + if (!(typeArguments && typeArguments.length == 1)) + compiler.error(DiagnosticCode.Expected_0_type_arguments_but_got_1, reportNode.range, "1", typeArguments ? typeArguments.length.toString(10) : "0"); if (operands.length < 2) compiler.error(DiagnosticCode.Expected_at_least_0_arguments_but_got_1, reportNode.range, "2", operands.length.toString(10)); else compiler.error(DiagnosticCode.Expected_0_arguments_but_got_1, reportNode.range, "3", operands.length.toString(10)); return module.createUnreachable(); } - if (typeArguments) { - if (typeArguments.length != 1) { - compiler.error(DiagnosticCode.Expected_0_type_arguments_but_got_1, reportNode.range, "1", typeArguments.length.toString(10)); - return module.createUnreachable(); - } - arg0 = compiler.compileExpression(operands[0], compiler.options.usizeType); - arg1 = compiler.compileExpression(operands[1], typeArguments[0]); - } else { - arg0 = compiler.compileExpression(operands[0], compiler.options.usizeType); - arg1 = compiler.compileExpression(operands[1], Type.i32, ConversionKind.NONE); + if (!(typeArguments && typeArguments.length == 1)) { + compiler.error(DiagnosticCode.Expected_0_type_arguments_but_got_1, reportNode.range, "1", typeArguments ? typeArguments.length.toString(10) : "0"); + return module.createUnreachable(); } - type = compiler.currentType; + arg0 = compiler.compileExpression(operands[0], compiler.options.usizeType); + arg1 = compiler.compileExpression(operands[1], typeArguments[0], + typeArguments[0].is(TypeFlags.INTEGER) + ? ConversionKind.NONE // wraps a larger integer type to a smaller one, i.e. i32.store8 + : ConversionKind.IMPLICIT + ); + if (compiler.currentType.is(TypeFlags.INTEGER) && typeArguments[0].is(TypeFlags.INTEGER) && typeArguments[0].size > compiler.currentType.size) { + arg1 = compiler.convertExpression(arg1, compiler.currentType, typeArguments[0], ConversionKind.IMPLICIT, operands[1]); + type = typeArguments[0]; + } else + type = compiler.currentType; offset = operands.length == 3 ? evaluateConstantOffset(compiler, operands[2]) : 0; // reports if (offset < 0) return module.createUnreachable(); compiler.currentType = Type.void; - return module.createStore(type.byteSize, arg0, arg1, type.toNativeType(), offset); + return module.createStore(typeArguments[0].byteSize, arg0, arg1, type.toNativeType(), offset); case "sizeof": // sizeof() -> usize compiler.currentType = compiler.options.usizeType; diff --git a/src/compiler.ts b/src/compiler.ts index 730c8194..6a695287 100644 --- a/src/compiler.ts +++ b/src/compiler.ts @@ -578,15 +578,15 @@ export class Compiler extends DiagnosticEmitter { // compile statements var stmts: ExpressionRef[] | null = null; if (!instance.is(ElementFlags.DECLARED)) { - declaration = assert(declaration); + declaration = assert(declaration, "declaration expected"); var previousFunction = this.currentFunction; this.currentFunction = instance; - var statements = assert(declaration.statements); + var statements = assert(declaration.statements, "implementation expected"); stmts = this.compileStatements(statements); // make sure the top-level branch or all child branches return var allBranchesReturn = this.currentFunction.flow.finalize(); if (instance.returnType != Type.void && !allBranchesReturn) - this.error(DiagnosticCode.A_function_whose_declared_type_is_not_void_must_return_a_value, assert(declaration.returnType).range); + this.error(DiagnosticCode.A_function_whose_declared_type_is_not_void_must_return_a_value, assert(declaration.returnType, "return type expected").range); this.currentFunction = previousFunction; } @@ -895,6 +895,7 @@ export class Compiler extends DiagnosticEmitter { this.error(DiagnosticCode.A_break_statement_can_only_be_used_within_an_enclosing_iteration_or_switch_statement, statement.range); return this.module.createUnreachable(); } + this.currentFunction.flow.set(FlowFlags.POSSIBLY_BREAKS); return this.module.createBreak(breakLabel); } @@ -909,6 +910,7 @@ export class Compiler extends DiagnosticEmitter { this.error(DiagnosticCode.A_continue_statement_can_only_be_used_within_an_enclosing_iteration_statement, statement.range); return this.module.createUnreachable(); } + this.currentFunction.flow.set(FlowFlags.POSSIBLY_CONTINUES); return this.module.createBreak(continueLabel); } @@ -1022,8 +1024,6 @@ export class Compiler extends DiagnosticEmitter { } compileReturnStatement(statement: ReturnStatement): ExpressionRef { - assert(this.currentFunction); - var expression: ExpressionRef = 0; if (statement.value) expression = this.compileExpression(statement.value, this.currentFunction.returnType); @@ -1353,7 +1353,7 @@ export class Compiler extends DiagnosticEmitter { convertExpression(expr: ExpressionRef, fromType: Type, toType: Type, conversionKind: ConversionKind, reportNode: Node): ExpressionRef { if (conversionKind == ConversionKind.NONE) { - assert(false); + assert(false, "concrete type expected"); return expr; } @@ -1437,7 +1437,7 @@ export class Compiler extends DiagnosticEmitter { // float to void } else { - assert(toType.flags == TypeFlags.NONE); + assert(toType.flags == TypeFlags.NONE, "void type expected"); expr = this.module.createDrop(expr); } @@ -2296,11 +2296,10 @@ export class Compiler extends DiagnosticEmitter { // otherwise make use of the temp. local else { - assert(tempLocal); expr = this.module.createIf( condition, right, - this.module.createGetLocal((tempLocal).index, this.currentType.toNativeType()) + this.module.createGetLocal(assert(tempLocal, "tempLocal must be set").index, this.currentType.toNativeType()) ); } break; @@ -2331,10 +2330,9 @@ export class Compiler extends DiagnosticEmitter { // otherwise make use of the temp. local else { - assert(tempLocal); expr = this.module.createIf( condition, - this.module.createGetLocal((tempLocal).index, this.currentType.toNativeType()), + this.module.createGetLocal(assert(tempLocal, "tempLocal must be set").index, this.currentType.toNativeType()), right ); } @@ -2345,7 +2343,7 @@ export class Compiler extends DiagnosticEmitter { throw new Error("not implemented"); } if (possiblyOverflows && wrapSmallIntegers) { - assert(this.currentType.is(TypeFlags.SMALL | TypeFlags.INTEGER)); + assert(this.currentType.is(TypeFlags.SMALL | TypeFlags.INTEGER)), "small integer type expected"; expr = makeSmallIntegerWrap(expr, this.currentType, this.module); } return compound @@ -2366,7 +2364,7 @@ export class Compiler extends DiagnosticEmitter { case ElementKind.GLOBAL: if (!this.compileGlobal(element)) // reports; not yet compiled if a static field compiled as a global return this.module.createUnreachable(); - assert((element).type != Type.void); + assert((element).type != Type.void, "concrete type expected"); // fall-through case ElementKind.LOCAL: @@ -2429,7 +2427,7 @@ export class Compiler extends DiagnosticEmitter { case ElementKind.GLOBAL: if (!this.compileGlobal(element)) // reports; not yet compiled if a static field compiled as a global return this.module.createUnreachable(); - assert((element).type != Type.void); + assert((element).type != Type.void, "concrete type expected"); this.currentType = tee ? (element).type : Type.void; if ((element).is(ElementFlags.CONSTANT)) { this.error(DiagnosticCode.Cannot_assign_to_0_because_it_is_a_constant_or_a_read_only_property, expression.range, (element).internalName); @@ -2448,9 +2446,9 @@ export class Compiler extends DiagnosticEmitter { this.error(DiagnosticCode.Cannot_assign_to_0_because_it_is_a_constant_or_a_read_only_property, expression.range, (element).internalName); return this.module.createUnreachable(); } - assert(resolved.targetExpression != null); + assert(resolved.targetExpression != null, "target expression expected"); targetExpr = this.compileExpression(resolved.targetExpression, this.options.target == Target.WASM64 ? Type.usize64 : Type.usize32, ConversionKind.NONE); - assert(this.currentType.classType); + assert(this.currentType.classType, "class type expected"); this.currentType = tee ? (element).type : Type.void; var elementNativeType = (element).type.toNativeType(); if (!tee) diff --git a/src/module.ts b/src/module.ts index 23b1c065..cbaa06a9 100644 --- a/src/module.ts +++ b/src/module.ts @@ -240,7 +240,8 @@ export class Module { ref: ModuleRef; lit: BinaryenLiteral; - static MAX_MEMORY_WASM32: Index = 0xffff; + static readonly MAX_MEMORY_WASM32: Index = 0xffff; + // TODO: static readonly MAX_MEMORY_WASM64 static create(): Module { var module = new Module(); diff --git a/src/program.ts b/src/program.ts index 54907e4d..5301382e 100644 --- a/src/program.ts +++ b/src/program.ts @@ -2134,6 +2134,10 @@ export const enum FlowFlags { RETURNS = 1 << 0, /** This branch possibly throws. */ POSSIBLY_THROWS = 1 << 1, + /** This branch possible breaks. */ + POSSIBLY_BREAKS = 1 << 2, + /** This branch possible continues. */ + POSSIBLY_CONTINUES = 1 << 3 } /** A control flow evaluator. */ @@ -2185,17 +2189,22 @@ export class Flow { /** Leaves the current branch or scope and returns the parent flow. */ leaveBranchOrScope(): Flow { var parent = assert(this.parent); + + // Free block-scoped locals if (this.scopedLocals) { for (var scopedLocal of this.scopedLocals.values()) this.currentFunction.freeTempLocal(scopedLocal); this.scopedLocals = null; } - // Mark parent as THROWS if any child throws - if (this.is(FlowFlags.POSSIBLY_THROWS)) - parent.set(FlowFlags.POSSIBLY_THROWS); - this.continueLabel = null; - this.breakLabel = null; + // Propagate flags to parent + if (this.is(FlowFlags.POSSIBLY_THROWS)) + parent.set(FlowFlags.POSSIBLY_THROWS); + if (this.is(FlowFlags.POSSIBLY_BREAKS) && parent.breakLabel == this.breakLabel) + parent.set(FlowFlags.POSSIBLY_BREAKS); + if (this.is(FlowFlags.POSSIBLY_CONTINUES) && parent.continueLabel == this.continueLabel) + parent.set(FlowFlags.POSSIBLY_CONTINUES); + return parent; } diff --git a/std/assembly.d.ts b/std/assembly.d.ts index 74249a52..52e3be04 100644 --- a/std/assembly.d.ts +++ b/std/assembly.d.ts @@ -155,9 +155,9 @@ declare function sqrt(value: T): T; /** Rounds to the nearest integer towards zero of a 32-bit or 64-bit float. */ declare function trunc(value: T): T; /** Loads a value of the specified type from memory. Equivalent to dereferncing a pointer in other languages. */ -declare function load(ptr: usize, constantOffset?: usize): T; +declare function load(ptr: usize, constantOffset?: usize): any; /** Stores a value of the specified type to memory. Equivalent to dereferencing a pointer in other languages when assigning a value. */ -declare function store(ptr: usize, value: T, constantOffset?: usize): void; +declare function store(ptr: usize, value: any, constantOffset?: usize): void; /** Returns the current memory size in units of pages. One page is 64kb. */ declare function current_memory(): i32; /** Grows linear memory by a given unsigned delta of pages. One page is 64kb. Returns the previous memory size in units of pages or `-1` on failure. */ diff --git a/tests/compiler/builtins.optimized.wast b/tests/compiler/builtins.optimized.wast index 2021bb2c..f118c906 100644 --- a/tests/compiler/builtins.optimized.wast +++ b/tests/compiler/builtins.optimized.wast @@ -5,6 +5,8 @@ (global $builtins/I (mut i64) (i64.const 0)) (global $builtins/f (mut f32) (f32.const 0)) (global $builtins/F (mut f64) (f64.const 0)) + (global $builtins/u (mut i32) (i32.const 0)) + (global $builtins/U (mut i64) (i64.const 0)) (global $builtins/s (mut i32) (i32.const 0)) (memory $0 1) (export "test" (func $builtins/test)) @@ -414,6 +416,138 @@ (i32.const 8) ) ) + (set_global $builtins/i + (i32.load8_s + (i32.const 8) + ) + ) + (set_global $builtins/i + (i32.load16_s + (i32.const 8) + ) + ) + (set_global $builtins/i + (i32.load + (i32.const 8) + ) + ) + (set_global $builtins/i + (i32.load8_u + (i32.const 8) + ) + ) + (set_global $builtins/i + (i32.load16_u + (i32.const 8) + ) + ) + (set_global $builtins/i + (i32.load + (i32.const 8) + ) + ) + (set_global $builtins/u + (i32.load8_u + (i32.const 8) + ) + ) + (set_global $builtins/u + (i32.load16_u + (i32.const 8) + ) + ) + (set_global $builtins/u + (i32.load + (i32.const 8) + ) + ) + (set_global $builtins/u + (i32.load8_s + (i32.const 8) + ) + ) + (set_global $builtins/u + (i32.load16_s + (i32.const 8) + ) + ) + (set_global $builtins/u + (i32.load + (i32.const 8) + ) + ) + (set_global $builtins/I + (i64.load8_s + (i32.const 8) + ) + ) + (set_global $builtins/I + (i64.load16_s + (i32.const 8) + ) + ) + (set_global $builtins/I + (i64.load32_s + (i32.const 8) + ) + ) + (set_global $builtins/I + (i64.load + (i32.const 8) + ) + ) + (set_global $builtins/U + (i64.load8_u + (i32.const 8) + ) + ) + (set_global $builtins/U + (i64.load16_u + (i32.const 8) + ) + ) + (set_global $builtins/U + (i64.load32_u + (i32.const 8) + ) + ) + (set_global $builtins/U + (i64.load + (i32.const 8) + ) + ) + (i32.store8 + (i32.const 8) + (i32.const 1) + ) + (i32.store16 + (i32.const 8) + (i32.const 1) + ) + (i32.store + (i32.const 8) + (i32.const 1) + ) + (i64.store8 + (i32.const 8) + (i64.const 1) + ) + (i64.store16 + (i32.const 8) + (i64.const 1) + ) + (i64.store32 + (i32.const 8) + (i64.const 1) + ) + (i64.store + (i32.const 8) + (i64.const 1) + ) + (i64.store + (i32.const 8) + (i64.const 1) + ) (set_global $builtins/i (i32.const 1067450368) ) diff --git a/tests/compiler/builtins.ts b/tests/compiler/builtins.ts index 4fc478d4..ed67155c 100644 --- a/tests/compiler/builtins.ts +++ b/tests/compiler/builtins.ts @@ -125,6 +125,47 @@ store(0, load(0, constantOffset), constantOffset); F = load(0, constantOffset); store(0, F, constantOffset); store(0, load(0, constantOffset), constantOffset); +// load and store smaller types + +i = load(8); +i = load(8); +i = load(8); + +i = load(8); +i = load(8); +i = load(8); + +var u: u32; +u = load(8); +u = load(8); +u = load(8); + +u = load(8); +u = load(8); +u = load(8); + +I = load(8); +I = load(8); +I = load(8); +I = load(8); + +var U: u64; +U = load(8); +U = load(8); +U = load(8); +U = load(8); + +store(8, 1); +store(8, 1); +store(8, 1); + +store(8, 1); +store(8, 1); +store(8, 1); +store(8, 1); + +store(8, 1); // must extend + // reinterpretation reinterpret(1.25); diff --git a/tests/compiler/builtins.wast b/tests/compiler/builtins.wast index 7eff9698..a4cd416c 100644 --- a/tests/compiler/builtins.wast +++ b/tests/compiler/builtins.wast @@ -7,6 +7,8 @@ (global $builtins/f (mut f32) (f32.const 0)) (global $builtins/F (mut f64) (f64.const 0)) (global $builtins/constantOffset i32 (i32.const 8)) + (global $builtins/u (mut i32) (i32.const 0)) + (global $builtins/U (mut i64) (i64.const 0)) (global $builtins/s (mut i32) (i32.const 0)) (global $i8.MIN_VALUE i32 (i32.const -128)) (global $i8.MAX_VALUE i32 (i32.const 127)) @@ -810,6 +812,140 @@ (i32.const 0) ) ) + (set_global $builtins/i + (i32.load8_s + (i32.const 8) + ) + ) + (set_global $builtins/i + (i32.load16_s + (i32.const 8) + ) + ) + (set_global $builtins/i + (i32.load + (i32.const 8) + ) + ) + (set_global $builtins/i + (i32.load8_u + (i32.const 8) + ) + ) + (set_global $builtins/i + (i32.load16_u + (i32.const 8) + ) + ) + (set_global $builtins/i + (i32.load + (i32.const 8) + ) + ) + (set_global $builtins/u + (i32.load8_u + (i32.const 8) + ) + ) + (set_global $builtins/u + (i32.load16_u + (i32.const 8) + ) + ) + (set_global $builtins/u + (i32.load + (i32.const 8) + ) + ) + (set_global $builtins/u + (i32.load8_s + (i32.const 8) + ) + ) + (set_global $builtins/u + (i32.load16_s + (i32.const 8) + ) + ) + (set_global $builtins/u + (i32.load + (i32.const 8) + ) + ) + (set_global $builtins/I + (i64.load8_s + (i32.const 8) + ) + ) + (set_global $builtins/I + (i64.load16_s + (i32.const 8) + ) + ) + (set_global $builtins/I + (i64.load32_s + (i32.const 8) + ) + ) + (set_global $builtins/I + (i64.load + (i32.const 8) + ) + ) + (set_global $builtins/U + (i64.load8_u + (i32.const 8) + ) + ) + (set_global $builtins/U + (i64.load16_u + (i32.const 8) + ) + ) + (set_global $builtins/U + (i64.load32_u + (i32.const 8) + ) + ) + (set_global $builtins/U + (i64.load + (i32.const 8) + ) + ) + (i32.store8 + (i32.const 8) + (i32.const 1) + ) + (i32.store16 + (i32.const 8) + (i32.const 1) + ) + (i32.store + (i32.const 8) + (i32.const 1) + ) + (i64.store8 + (i32.const 8) + (i64.const 1) + ) + (i64.store16 + (i32.const 8) + (i64.const 1) + ) + (i64.store32 + (i32.const 8) + (i64.const 1) + ) + (i64.store + (i32.const 8) + (i64.const 1) + ) + (i64.store + (i32.const 8) + (i64.extend_s/i32 + (i32.const 1) + ) + ) (drop (i32.reinterpret/f32 (f32.const 1.25) @@ -1454,6 +1590,8 @@ GLOBAL: builtins/f GLOBAL: builtins/F GLOBAL: builtins/constantOffset + GLOBAL: builtins/u + GLOBAL: builtins/U GLOBAL: builtins/s FUNCTION_PROTOTYPE: builtins/test [program.exports] diff --git a/tests/compiler/game-of-life.optimized.wast b/tests/compiler/game-of-life.optimized.wast index 416ea52b..4fc1e35a 100644 --- a/tests/compiler/game-of-life.optimized.wast +++ b/tests/compiler/game-of-life.optimized.wast @@ -84,39 +84,28 @@ ) (block (set_local $2 - (i32.and + (i32.add (i32.add (i32.add (i32.add (i32.add (i32.add (i32.add - (i32.add - (i32.load8_u - (i32.add - (i32.mul - (get_local $3) - (get_global $../../examples/game-of-life/assembly/game-of-life/w) - ) - (tee_local $2 - (select - (i32.sub - (get_local $1) - (i32.const 1) - ) - (get_local $6) - (get_local $1) - ) - ) + (i32.load8_u + (i32.add + (i32.mul + (get_local $3) + (get_global $../../examples/game-of-life/assembly/game-of-life/w) ) - ) - (i32.load8_u - (i32.add - (i32.mul - (get_local $3) - (get_global $../../examples/game-of-life/assembly/game-of-life/w) + (tee_local $2 + (select + (i32.sub + (get_local $1) + (i32.const 1) + ) + (get_local $6) + (get_local $1) ) - (get_local $1) ) ) ) @@ -126,29 +115,29 @@ (get_local $3) (get_global $../../examples/game-of-life/assembly/game-of-life/w) ) - (tee_local $7 - (select - (i32.const 0) - (i32.add - (get_local $1) - (i32.const 1) - ) - (i32.eq - (get_local $1) - (get_local $6) - ) - ) - ) + (get_local $1) ) ) ) (i32.load8_u (i32.add (i32.mul - (get_local $0) + (get_local $3) (get_global $../../examples/game-of-life/assembly/game-of-life/w) ) - (get_local $2) + (tee_local $7 + (select + (i32.const 0) + (i32.add + (get_local $1) + (i32.const 1) + ) + (i32.eq + (get_local $1) + (get_local $6) + ) + ) + ) ) ) ) @@ -158,17 +147,17 @@ (get_local $0) (get_global $../../examples/game-of-life/assembly/game-of-life/w) ) - (get_local $7) + (get_local $2) ) ) ) (i32.load8_u (i32.add (i32.mul - (get_local $4) + (get_local $0) (get_global $../../examples/game-of-life/assembly/game-of-life/w) ) - (get_local $2) + (get_local $7) ) ) ) @@ -178,7 +167,7 @@ (get_local $4) (get_global $../../examples/game-of-life/assembly/game-of-life/w) ) - (get_local $1) + (get_local $2) ) ) ) @@ -188,11 +177,19 @@ (get_local $4) (get_global $../../examples/game-of-life/assembly/game-of-life/w) ) - (get_local $7) + (get_local $1) ) ) ) - (i32.const 255) + (i32.load8_u + (i32.add + (i32.mul + (get_local $4) + (get_global $../../examples/game-of-life/assembly/game-of-life/w) + ) + (get_local $7) + ) + ) ) ) (if @@ -208,15 +205,15 @@ (if (i32.and (select - (i32.lt_u + (i32.lt_s (get_local $2) (i32.const 2) ) - (i32.gt_u + (i32.gt_s (get_local $2) (i32.const 3) ) - (i32.lt_u + (i32.lt_s (get_local $2) (i32.const 2) ) diff --git a/tests/compiler/game-of-life.wast b/tests/compiler/game-of-life.wast index c3ca4267..99f0830f 100644 --- a/tests/compiler/game-of-life.wast +++ b/tests/compiler/game-of-life.wast @@ -128,31 +128,20 @@ ) ) (set_local $8 - (i32.and + (i32.add (i32.add (i32.add (i32.add (i32.add (i32.add (i32.add - (i32.add - (i32.load8_u - (i32.add - (i32.mul - (get_local $3) - (get_global $../../examples/game-of-life/assembly/game-of-life/w) - ) - (get_local $6) - ) - ) - (i32.load8_u - (i32.add - (i32.mul - (get_local $3) - (get_global $../../examples/game-of-life/assembly/game-of-life/w) - ) - (get_local $5) + (i32.load8_u + (i32.add + (i32.mul + (get_local $3) + (get_global $../../examples/game-of-life/assembly/game-of-life/w) ) + (get_local $6) ) ) (i32.load8_u @@ -161,17 +150,17 @@ (get_local $3) (get_global $../../examples/game-of-life/assembly/game-of-life/w) ) - (get_local $7) + (get_local $5) ) ) ) (i32.load8_u (i32.add (i32.mul - (get_local $2) + (get_local $3) (get_global $../../examples/game-of-life/assembly/game-of-life/w) ) - (get_local $6) + (get_local $7) ) ) ) @@ -181,17 +170,17 @@ (get_local $2) (get_global $../../examples/game-of-life/assembly/game-of-life/w) ) - (get_local $7) + (get_local $6) ) ) ) (i32.load8_u (i32.add (i32.mul - (get_local $4) + (get_local $2) (get_global $../../examples/game-of-life/assembly/game-of-life/w) ) - (get_local $6) + (get_local $7) ) ) ) @@ -201,7 +190,7 @@ (get_local $4) (get_global $../../examples/game-of-life/assembly/game-of-life/w) ) - (get_local $5) + (get_local $6) ) ) ) @@ -211,11 +200,19 @@ (get_local $4) (get_global $../../examples/game-of-life/assembly/game-of-life/w) ) - (get_local $7) + (get_local $5) ) ) ) - (i32.const 255) + (i32.load8_u + (i32.add + (i32.mul + (get_local $4) + (get_global $../../examples/game-of-life/assembly/game-of-life/w) + ) + (get_local $7) + ) + ) ) ) (if @@ -232,17 +229,17 @@ (i32.and (if (result i32) (i32.ne - (i32.lt_u + (i32.lt_s (get_local $8) (i32.const 2) ) (i32.const 0) ) - (i32.lt_u + (i32.lt_s (get_local $8) (i32.const 2) ) - (i32.gt_u + (i32.gt_s (get_local $8) (i32.const 3) ) diff --git a/tests/compiler/showcase.optimized.wast b/tests/compiler/showcase.optimized.wast index ac340c10..81fe4696 100644 --- a/tests/compiler/showcase.optimized.wast +++ b/tests/compiler/showcase.optimized.wast @@ -24,6 +24,8 @@ (global $builtins/I (mut i64) (i64.const 0)) (global $builtins/f (mut f32) (f32.const 0)) (global $builtins/F (mut f64) (f64.const 0)) + (global $builtins/u (mut i32) (i32.const 0)) + (global $builtins/U (mut i64) (i64.const 0)) (global $builtins/s (mut i32) (i32.const 0)) (global $showcase/ANamespace.aNamespacedGlobal (mut i32) (i32.const 42)) (global $showcase/AnEnum.ONE i32 (i32.const 1)) @@ -3658,6 +3660,138 @@ (i32.const 8) ) ) + (set_global $builtins/i + (i32.load8_s + (i32.const 8) + ) + ) + (set_global $builtins/i + (i32.load16_s + (i32.const 8) + ) + ) + (set_global $builtins/i + (i32.load + (i32.const 8) + ) + ) + (set_global $builtins/i + (i32.load8_u + (i32.const 8) + ) + ) + (set_global $builtins/i + (i32.load16_u + (i32.const 8) + ) + ) + (set_global $builtins/i + (i32.load + (i32.const 8) + ) + ) + (set_global $builtins/u + (i32.load8_u + (i32.const 8) + ) + ) + (set_global $builtins/u + (i32.load16_u + (i32.const 8) + ) + ) + (set_global $builtins/u + (i32.load + (i32.const 8) + ) + ) + (set_global $builtins/u + (i32.load8_s + (i32.const 8) + ) + ) + (set_global $builtins/u + (i32.load16_s + (i32.const 8) + ) + ) + (set_global $builtins/u + (i32.load + (i32.const 8) + ) + ) + (set_global $builtins/I + (i64.load8_s + (i32.const 8) + ) + ) + (set_global $builtins/I + (i64.load16_s + (i32.const 8) + ) + ) + (set_global $builtins/I + (i64.load32_s + (i32.const 8) + ) + ) + (set_global $builtins/I + (i64.load + (i32.const 8) + ) + ) + (set_global $builtins/U + (i64.load8_u + (i32.const 8) + ) + ) + (set_global $builtins/U + (i64.load16_u + (i32.const 8) + ) + ) + (set_global $builtins/U + (i64.load32_u + (i32.const 8) + ) + ) + (set_global $builtins/U + (i64.load + (i32.const 8) + ) + ) + (i32.store8 + (i32.const 8) + (i32.const 1) + ) + (i32.store16 + (i32.const 8) + (i32.const 1) + ) + (i32.store + (i32.const 8) + (i32.const 1) + ) + (i64.store8 + (i32.const 8) + (i64.const 1) + ) + (i64.store16 + (i32.const 8) + (i64.const 1) + ) + (i64.store32 + (i32.const 8) + (i64.const 1) + ) + (i64.store + (i32.const 8) + (i64.const 1) + ) + (i64.store + (i32.const 8) + (i64.const 1) + ) (set_global $builtins/i (i32.const 1067450368) ) diff --git a/tests/compiler/showcase.wast b/tests/compiler/showcase.wast index 68c7c25f..ccbb5703 100644 --- a/tests/compiler/showcase.wast +++ b/tests/compiler/showcase.wast @@ -34,6 +34,8 @@ (global $builtins/f (mut f32) (f32.const 0)) (global $builtins/F (mut f64) (f64.const 0)) (global $builtins/constantOffset i32 (i32.const 8)) + (global $builtins/u (mut i32) (i32.const 0)) + (global $builtins/U (mut i64) (i64.const 0)) (global $builtins/s (mut i32) (i32.const 0)) (global $i8.MIN_VALUE i32 (i32.const -128)) (global $i8.MAX_VALUE i32 (i32.const 127)) @@ -5195,6 +5197,140 @@ (i32.const 0) ) ) + (set_global $builtins/i + (i32.load8_s + (i32.const 8) + ) + ) + (set_global $builtins/i + (i32.load16_s + (i32.const 8) + ) + ) + (set_global $builtins/i + (i32.load + (i32.const 8) + ) + ) + (set_global $builtins/i + (i32.load8_u + (i32.const 8) + ) + ) + (set_global $builtins/i + (i32.load16_u + (i32.const 8) + ) + ) + (set_global $builtins/i + (i32.load + (i32.const 8) + ) + ) + (set_global $builtins/u + (i32.load8_u + (i32.const 8) + ) + ) + (set_global $builtins/u + (i32.load16_u + (i32.const 8) + ) + ) + (set_global $builtins/u + (i32.load + (i32.const 8) + ) + ) + (set_global $builtins/u + (i32.load8_s + (i32.const 8) + ) + ) + (set_global $builtins/u + (i32.load16_s + (i32.const 8) + ) + ) + (set_global $builtins/u + (i32.load + (i32.const 8) + ) + ) + (set_global $builtins/I + (i64.load8_s + (i32.const 8) + ) + ) + (set_global $builtins/I + (i64.load16_s + (i32.const 8) + ) + ) + (set_global $builtins/I + (i64.load32_s + (i32.const 8) + ) + ) + (set_global $builtins/I + (i64.load + (i32.const 8) + ) + ) + (set_global $builtins/U + (i64.load8_u + (i32.const 8) + ) + ) + (set_global $builtins/U + (i64.load16_u + (i32.const 8) + ) + ) + (set_global $builtins/U + (i64.load32_u + (i32.const 8) + ) + ) + (set_global $builtins/U + (i64.load + (i32.const 8) + ) + ) + (i32.store8 + (i32.const 8) + (i32.const 1) + ) + (i32.store16 + (i32.const 8) + (i32.const 1) + ) + (i32.store + (i32.const 8) + (i32.const 1) + ) + (i64.store8 + (i32.const 8) + (i64.const 1) + ) + (i64.store16 + (i32.const 8) + (i64.const 1) + ) + (i64.store32 + (i32.const 8) + (i64.const 1) + ) + (i64.store + (i32.const 8) + (i64.const 1) + ) + (i64.store + (i32.const 8) + (i64.extend_s/i32 + (i32.const 1) + ) + ) (drop (i32.reinterpret/f32 (f32.const 1.25) @@ -6369,6 +6505,8 @@ GLOBAL: builtins/f GLOBAL: builtins/F GLOBAL: builtins/constantOffset + GLOBAL: builtins/u + GLOBAL: builtins/U GLOBAL: builtins/s FUNCTION_PROTOTYPE: builtins/test FUNCTION_PROTOTYPE: memcpy/memcpy