From 9ae3328e58d2cad382ca1d41f1bdd862e7776594 Mon Sep 17 00:00:00 2001 From: dcodeIO Date: Wed, 6 Dec 2017 23:38:17 +0100 Subject: [PATCH] Precompute and inline constant globals This is necessary so that other constant globals referencing constant globals can be precomputed as well (NON_STANDALONE_FLOW in binaryen) --- src/compiler.ts | 118 +++++++++++++++++++++------ src/diagnosticMessages.generated.ts | 4 + src/diagnosticMessages.json | 2 + src/module.ts | 37 ++++++++- src/program.ts | 1 - tests/compiler/enum.optimized.wast | 24 ++++++ tests/compiler/enum.ts | 29 +++++++ tests/compiler/enum.wast | 76 +++++++++++++++++ tests/compiler/import.optimized.wast | 10 +-- tests/compiler/import.wast | 8 +- tests/compiler/tlsf.optimized.wast | 100 ++++------------------- tests/compiler/tlsf.ts | 10 +-- tests/compiler/tlsf.wast | 102 +++++++---------------- 13 files changed, 323 insertions(+), 198 deletions(-) create mode 100644 tests/compiler/enum.optimized.wast create mode 100644 tests/compiler/enum.ts create mode 100644 tests/compiler/enum.wast diff --git a/src/compiler.ts b/src/compiler.ts index efaebd23..ce115da0 100644 --- a/src/compiler.ts +++ b/src/compiler.ts @@ -1,8 +1,8 @@ -import { compileCall as compileBuiltinCall } from "./builtins"; +import { compileCall as compileBuiltinCall, initialize } from "./builtins"; import { PATH_DELIMITER } from "./constants"; import { DiagnosticCode, DiagnosticEmitter } from "./diagnostics"; -import { Module, MemorySegment, ExpressionRef, UnaryOp, BinaryOp, NativeType, FunctionTypeRef, getExpressionId, ExpressionId } from "./module"; -import { Program, ClassPrototype, Class, Element, ElementKind, Enum, FunctionPrototype, Function, Global, Local, Namespace, Parameter } from "./program"; +import { Module, MemorySegment, ExpressionRef, UnaryOp, BinaryOp, NativeType, FunctionRef, FunctionTypeRef, getExpressionId, ExpressionId, getExpressionType, getFunctionBody, getConstValueI32, getConstValueI64Low, getConstValueI64High, getConstValueF32, getConstValueF64 } from "./module"; +import { Program, ClassPrototype, Class, Element, ElementKind, Enum, FunctionPrototype, Function, Global, Local, Namespace, Parameter, EnumValue } from "./program"; import { I64, U64, sb } from "./util"; import { Token } from "./tokenizer"; import { @@ -298,7 +298,7 @@ export class Compiler extends DiagnosticEmitter { if (!this.compileGlobal(element)) return null; if (declaration.range.source.isEntry && (declaration.parent).parent == declaration.range.source && hasModifier(ModifierKind.EXPORT, declaration.modifiers)) { - if (!(element).isCompiledMutable) + if ((element).hasConstantValue) this.module.addGlobalExport(element.internalName, declaration.identifier.name); else this.warning(DiagnosticCode.Cannot_export_a_mutable_global, declaration.range); @@ -325,7 +325,7 @@ export class Compiler extends DiagnosticEmitter { return true; const nativeType: NativeType = typeToNativeType(type); let initializer: ExpressionRef; - let initializeInStart: bool; + let initializeInStart: bool = false; if (element.hasConstantValue) { if (type.isLongInteger) initializer = element.constantIntegerValue ? this.module.createI64(element.constantIntegerValue.lo, element.constantIntegerValue.hi) : this.module.createI64(0, 0); @@ -341,25 +341,49 @@ export class Compiler extends DiagnosticEmitter { initializer = this.module.createI32(element.constantIntegerValue ? element.constantIntegerValue.toI32() & type.smallIntegerMask: 0); } else initializer = this.module.createI32(element.constantIntegerValue ? element.constantIntegerValue.toI32() : 0); - initializeInStart = false; } else if (declaration) { if (declaration.initializer) { initializer = this.compileExpression(declaration.initializer, type); - initializeInStart = getExpressionId(initializer) != ExpressionId.Const; // MVP doesn't support complex initializers - } else { + if (getExpressionId(initializer) != ExpressionId.Const) { + if (!element.isMutable) { + initializer = this.precomputeExpressionRef(initializer); + if (getExpressionId(initializer) != ExpressionId.Const) { + this.warning(DiagnosticCode.Compiling_constant_global_with_non_constant_initializer_as_mutable, declaration.range); + initializeInStart = true; + } + } else + initializeInStart = true; + } + } else initializer = typeToNativeZero(this.module, type); - initializeInStart = false; - } } else throw new Error("unexpected missing declaration or constant value"); const internalName: string = element.internalName; if (initializeInStart) { this.module.addGlobal(internalName, nativeType, true, typeToNativeZero(this.module, type)); this.startFunctionBody.push(this.module.createSetGlobal(internalName, initializer)); - element.isCompiledMutable = true; } else { this.module.addGlobal(internalName, nativeType, element.isMutable, initializer); - element.isCompiledMutable = element.isMutable; + if (!element.isMutable) { + element.hasConstantValue = true; + const exprType: NativeType = getExpressionType(initializer); + switch (exprType) { + case NativeType.I32: + element.constantIntegerValue = new I64(getConstValueI32(initializer), 0); + break; + case NativeType.I64: + element.constantIntegerValue = new I64(getConstValueI64Low(initializer), getConstValueI64High(initializer)); + break; + case NativeType.F32: + element.constantFloatValue = getConstValueF32(initializer); + break; + case NativeType.F64: + element.constantFloatValue = getConstValueF64(initializer); + break; + default: + throw new Error("unexpected initializer type"); + } + } } return element.isCompiled = true; } @@ -376,7 +400,7 @@ export class Compiler extends DiagnosticEmitter { compileEnum(element: Enum): void { if (element.isCompiled) return; - let previousInternalName: string | null = null; + let previousValue: EnumValue | null = null; for (let [key, val] of element.members) { if (val.hasConstantValue) { this.module.addGlobal(val.internalName, NativeType.I32, false, this.module.createI32(val.constantValue)); @@ -386,15 +410,24 @@ export class Compiler extends DiagnosticEmitter { let initializeInStart: bool = false; if (declaration.value) { initializer = this.compileExpression(declaration.value, Type.i32); - initializeInStart = getExpressionId(initializer) != ExpressionId.Const; // MVP doesn't support complex initializers - } else if (previousInternalName == null) { + if (getExpressionId(initializer) != ExpressionId.Const) { + initializer = this.precomputeExpressionRef(initializer); + if (getExpressionId(initializer) != ExpressionId.Const) { + this.warning(DiagnosticCode.Compiling_constant_global_with_non_constant_initializer_as_mutable, declaration.range); + initializeInStart = true; + } + } + } else if (previousValue == null) { initializer = this.module.createI32(0); - initializeInStart = false; + } else if (previousValue.hasConstantValue) { + initializer = this.module.createI32(previousValue.constantValue + 1); } else { + // in TypeScript this errors with TS1061, but actually we can do: initializer = this.module.createBinary(BinaryOp.AddI32, - this.module.createGetGlobal(previousInternalName, NativeType.I32), + this.module.createGetGlobal(previousValue.internalName, NativeType.I32), this.module.createI32(1) ); + this.warning(DiagnosticCode.Compiling_constant_global_with_non_constant_initializer_as_mutable, val.declaration.range); initializeInStart = true; } if (initializeInStart) { @@ -402,11 +435,15 @@ export class Compiler extends DiagnosticEmitter { this.startFunctionBody.push(this.module.createSetGlobal(val.internalName, initializer)); } else { this.module.addGlobal(val.internalName, NativeType.I32, false, initializer); - // TODO: check export, requires updated binaryen.js with Module#addGlobalExport + if (getExpressionType(initializer) == NativeType.I32) { + val.hasConstantValue = true; + val.constantValue = getConstValueI32(initializer); + } else + throw new Error("unexpected initializer type"); } } else throw new Error("unexpected missing declaration or constant value"); - previousInternalName = val.internalName; + previousValue = val; } element.isCompiled = true; } @@ -588,7 +625,7 @@ export class Compiler extends DiagnosticEmitter { case ElementKind.GLOBAL: if (this.compileGlobal(element) && statement.range.source.isEntry) { - if (!(element).isCompiledMutable) + if ((element).hasConstantValue) this.module.addGlobalExport(element.internalName, member.externalIdentifier.name); else this.warning(DiagnosticCode.Cannot_export_a_mutable_global, member.range); @@ -988,6 +1025,24 @@ export class Compiler extends DiagnosticEmitter { return expr; } + precomputeExpression(expression: Expression, contextualType: Type, conversionKind: ConversionKind = ConversionKind.IMPLICIT): ExpressionRef { + const expr: ExpressionRef = this.compileExpression(expression, contextualType, conversionKind); + return this.precomputeExpressionRef(expr); + } + + precomputeExpressionRef(expr: ExpressionRef): ExpressionRef { + const nativeType: NativeType = typeToNativeType(this.currentType); + let typeRef: FunctionTypeRef = this.module.getFunctionTypeBySignature(nativeType, []); + if (!typeRef) + typeRef = this.module.addFunctionType(typeToSignatureNamePart(this.currentType), nativeType, []); + const funcRef: FunctionRef = this.module.addFunction("__precompute", typeRef, [], expr); + this.module.runPasses([ "precompute" ], funcRef); + const ret: ExpressionRef = getFunctionBody(funcRef); + this.module.removeFunction("__precompute"); + // TODO: also remove the function type somehow if no longer used + return ret; + } + convertExpression(expr: ExpressionRef, fromType: Type, toType: Type, conversionKind: ConversionKind, reportNode: Node): ExpressionRef { if (conversionKind == ConversionKind.NONE) return expr; @@ -1636,11 +1691,24 @@ export class Compiler extends DiagnosticEmitter { // global if (element.kind == ElementKind.GLOBAL) { - if ((element).type) - this.currentType = (element).type; - return this.compileGlobal(element) // reports - ? this.module.createGetGlobal((element).internalName, typeToNativeType(this.currentType = (element).type)) - : this.module.createUnreachable(); + const global: Global = element; + if (global.type) + this.currentType = global.type; + if (!this.compileGlobal(global)) // reports + return this.module.createUnreachable(); + if (global.hasConstantValue) { + if (global.type == Type.f32) + return this.module.createF32((element).constantFloatValue); + else if (global.type == Type.f64) + return this.module.createF64((element).constantFloatValue); + else if ((global.type).isLongInteger) + return this.module.createI64((global.constantIntegerValue).lo, (global.constantIntegerValue).hi); + else if ((global.type).isAnyInteger) + return this.module.createI32((global.constantIntegerValue).lo); + else + throw new Error("unexpected global type"); + } else + return this.module.createGetGlobal((element).internalName, typeToNativeType(this.currentType = (element).type)); } // field diff --git a/src/diagnosticMessages.generated.ts b/src/diagnosticMessages.generated.ts index 0da1eccc..a043c65c 100644 --- a/src/diagnosticMessages.generated.ts +++ b/src/diagnosticMessages.generated.ts @@ -6,6 +6,7 @@ export enum DiagnosticCode { Operation_not_supported = 102, Operation_is_unsafe = 103, Cannot_export_a_mutable_global = 104, + Compiling_constant_global_with_non_constant_initializer_as_mutable = 105, Unterminated_string_literal = 1002, Identifier_expected = 1003, _0_expected = 1005, @@ -14,6 +15,7 @@ export enum DiagnosticCode { Unexpected_token = 1012, A_rest_parameter_must_be_last_in_a_parameter_list = 1014, A_required_parameter_cannot_follow_an_optional_parameter = 1016, + Enum_member_must_have_initializer = 1061, Statements_are_not_allowed_in_ambient_contexts = 1036, Initializers_are_not_allowed_in_ambient_contexts = 1039, _0_modifier_cannot_be_used_here = 1042, @@ -76,6 +78,7 @@ export function diagnosticCodeToString(code: DiagnosticCode): string { case 102: return "Operation not supported."; case 103: return "Operation is unsafe."; case 104: return "Cannot export a mutable global."; + case 105: return "Compiling constant global with non-constant initializer as mutable."; case 1002: return "Unterminated string literal."; case 1003: return "Identifier expected."; case 1005: return "'{0}' expected."; @@ -84,6 +87,7 @@ export function diagnosticCodeToString(code: DiagnosticCode): string { case 1012: return "Unexpected token."; case 1014: return "A rest parameter must be last in a parameter list."; case 1016: return "A required parameter cannot follow an optional parameter."; + case 1061: return "Enum member must have initializer."; case 1036: return "Statements are not allowed in ambient contexts."; case 1039: return "Initializers are not allowed in ambient contexts."; case 1042: return "'{0}' modifier cannot be used here."; diff --git a/src/diagnosticMessages.json b/src/diagnosticMessages.json index cebad79a..98cce5ba 100644 --- a/src/diagnosticMessages.json +++ b/src/diagnosticMessages.json @@ -4,6 +4,7 @@ "Operation not supported.": 102, "Operation is unsafe.": 103, "Cannot export a mutable global.": 104, + "Compiling constant global with non-constant initializer as mutable.": 105, "Unterminated string literal.": 1002, "Identifier expected.": 1003, @@ -13,6 +14,7 @@ "Unexpected token.": 1012, "A rest parameter must be last in a parameter list.": 1014, "A required parameter cannot follow an optional parameter.": 1016, + "Enum member must have initializer.": 1061, "Statements are not allowed in ambient contexts.": 1036, "Initializers are not allowed in ambient contexts.": 1039, "'{0}' modifier cannot be used here.": 1042, diff --git a/src/module.ts b/src/module.ts index 5560bc8f..9f033fa8 100644 --- a/src/module.ts +++ b/src/module.ts @@ -522,6 +522,15 @@ export class Module { } } + removeFunction(name: string): void { + const cStr: CString = allocString(name); + try { + _BinaryenRemoveFunction(this.ref, cStr); + } finally { + _free(cStr); + } + } + addFunctionExport(internalName: string, externalName: string): ExportRef { if (this.noEmit) return 0; const cStr1: CString = allocString(internalName); @@ -691,9 +700,27 @@ export class Module { _BinaryenSetStart(this.ref, func); } - optimize(): void { - if (this.noEmit) return; - _BinaryenModuleOptimize(this.ref); + optimize(func: FunctionRef = 0): void { + if (func) + _BinaryenFunctionOptimize(func, this.ref); + else + _BinaryenModuleOptimize(this.ref); + } + + runPasses(passes: string[], func: FunctionRef = 0): void { + let i: i32, k: i32 = passes.length; + const names: CString[] = new Array(k); + for (i = 0; i < k; ++i) names[i] = allocString(passes[i]); + const cArr: CArray = allocI32Array(names); + try { + if (func) + _BinaryenFunctionRunPasses(func, this.ref, cArr, k); + else + _BinaryenModuleRunPasses(this.ref, cArr, k); + } finally { + _free(cArr); + for (; i >= 0; --i) _free(names[i]); + } } validate(): bool { @@ -773,6 +800,10 @@ export function getConstValueF64(expr: ExpressionRef): f64 { return _BinaryenConstGetValueF64(expr); } +export function getFunctionBody(func: FunctionRef): ExpressionRef { + return _BinaryenFunctionGetBody(func); +} + export class Relooper { module: Module; diff --git a/src/program.ts b/src/program.ts index e113c122..42b28a18 100644 --- a/src/program.ts +++ b/src/program.ts @@ -771,7 +771,6 @@ export class Global extends Element { hasConstantValue: bool = false; constantIntegerValue: I64 | null = null; constantFloatValue: f64 = 0; - isCompiledMutable: bool = false; constructor(program: Program, internalName: string, declaration: VariableLikeDeclarationStatement | null, type: Type | null) { super(program, internalName); diff --git a/tests/compiler/enum.optimized.wast b/tests/compiler/enum.optimized.wast new file mode 100644 index 00000000..9505dc59 --- /dev/null +++ b/tests/compiler/enum.optimized.wast @@ -0,0 +1,24 @@ +(module + (type $i (func (result i32))) + (type $v (func)) + (global $enum/NonConstant.ZERO (mut i32) (i32.const 0)) + (global $enum/NonConstant.ONE (mut i32) (i32.const 0)) + (memory $0 1) + (data (i32.const 4) "\08") + (export "memory" (memory $0)) + (start $start) + (func $enum/getZero (; 0 ;) (type $i) (result i32) + (i32.const 0) + ) + (func $start (; 1 ;) (type $v) + (set_global $enum/NonConstant.ZERO + (call $enum/getZero) + ) + (set_global $enum/NonConstant.ONE + (i32.add + (get_global $enum/NonConstant.ZERO) + (i32.const 1) + ) + ) + ) +) diff --git a/tests/compiler/enum.ts b/tests/compiler/enum.ts new file mode 100644 index 00000000..af6472de --- /dev/null +++ b/tests/compiler/enum.ts @@ -0,0 +1,29 @@ +export enum Implicit { + ZERO, + ONE, + TWO, + THREE +} + +export enum Explicit { + ZERO = 0, + ONE = 0 + 1, + TWO = 1 + 1, + THREE = 3 +} + +export enum Mixed { + ZERO, + ONE, + THREE = 3, + FOUR +} + +function getZero(): i32 { + return 0; +} + +export enum NonConstant { + ZERO = getZero(), + ONE +} diff --git a/tests/compiler/enum.wast b/tests/compiler/enum.wast new file mode 100644 index 00000000..d15d73fb --- /dev/null +++ b/tests/compiler/enum.wast @@ -0,0 +1,76 @@ +(module + (type $i (func (result i32))) + (type $v (func)) + (global $enum/Implicit.ZERO i32 (i32.const 0)) + (global $enum/Implicit.ONE i32 (i32.const 1)) + (global $enum/Implicit.TWO i32 (i32.const 2)) + (global $enum/Implicit.THREE i32 (i32.const 3)) + (global $enum/Explicit.ZERO i32 (i32.const 0)) + (global $enum/Explicit.ONE i32 (i32.const 1)) + (global $enum/Explicit.TWO i32 (i32.const 2)) + (global $enum/Explicit.THREE i32 (i32.const 3)) + (global $enum/Mixed.ZERO i32 (i32.const 0)) + (global $enum/Mixed.ONE i32 (i32.const 1)) + (global $enum/Mixed.THREE i32 (i32.const 3)) + (global $enum/Mixed.FOUR i32 (i32.const 4)) + (global $enum/NonConstant.ZERO (mut i32) (i32.const 0)) + (global $enum/NonConstant.ONE (mut i32) (i32.const 0)) + (memory $0 1) + (data (i32.const 4) "\08\00\00\00") + (export "memory" (memory $0)) + (start $start) + (func $enum/getZero (; 0 ;) (type $i) (result i32) + (return + (i32.const 0) + ) + ) + (func $start (; 1 ;) (type $v) + (set_global $enum/NonConstant.ZERO + (call $enum/getZero) + ) + (set_global $enum/NonConstant.ONE + (i32.add + (get_global $enum/NonConstant.ZERO) + (i32.const 1) + ) + ) + ) +) +(; +[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 + enum/Implicit + enum/Explicit + enum/Mixed + enum/getZero + enum/NonConstant +[program.exports] + enum/Implicit + enum/Explicit + enum/Mixed + enum/NonConstant +;) diff --git a/tests/compiler/import.optimized.wast b/tests/compiler/import.optimized.wast index de65d688..91b3f080 100644 --- a/tests/compiler/import.optimized.wast +++ b/tests/compiler/import.optimized.wast @@ -1,8 +1,6 @@ (module (type $iii (func (param i32 i32) (result i32))) (type $v (func)) - (global $export/a i32 (i32.const 1)) - (global $export/b i32 (i32.const 2)) (memory $0 1) (data (i32.const 4) "\08") (export "memory" (memory $0)) @@ -23,12 +21,12 @@ (drop (i32.add (call $export/add - (get_global $export/a) - (get_global $export/b) + (i32.const 1) + (i32.const 2) ) (call $export/sub - (get_global $export/b) - (get_global $export/a) + (i32.const 2) + (i32.const 1) ) ) ) diff --git a/tests/compiler/import.wast b/tests/compiler/import.wast index bfe38896..80e26efa 100644 --- a/tests/compiler/import.wast +++ b/tests/compiler/import.wast @@ -27,12 +27,12 @@ (drop (i32.add (call $export/add - (get_global $export/a) - (get_global $export/b) + (i32.const 1) + (i32.const 2) ) (call $export/sub - (get_global $export/b) - (get_global $export/a) + (i32.const 2) + (i32.const 1) ) ) ) diff --git a/tests/compiler/tlsf.optimized.wast b/tests/compiler/tlsf.optimized.wast index 5f0c8b56..64d309f2 100644 --- a/tests/compiler/tlsf.optimized.wast +++ b/tests/compiler/tlsf.optimized.wast @@ -5,18 +5,6 @@ (type $iiiiv (func (param i32 i32 i32 i32))) (type $iv (func (param i32))) (type $v (func)) - (global $tlsf/ALIGN_SIZE_LOG2 i32 (i32.const 3)) - (global $tlsf/ALIGN_SIZE (mut i32) (i32.const 0)) - (global $tlsf/BLOCK_PREV_PHYS_OFFSET i32 (i32.const 0)) - (global $tlsf/BLOCK_SIZE_OFFSET (mut i32) (i32.const 0)) - (global $tlsf/BLOCK_NEXT_FREE_OFFSET (mut i32) (i32.const 0)) - (global $tlsf/BLOCK_PREV_FREE_OFFSET (mut i32) (i32.const 0)) - (global $tlsf/CONTROL_FL_BITMAP_OFFSET (mut i32) (i32.const 0)) - (global $tlsf/FL_INDEX_MAX i32 (i32.const 30)) - (global $tlsf/SL_INDEX_COUNT_LOG2 i32 (i32.const 5)) - (global $tlsf/FL_INDEX_SHIFT (mut i32) (i32.const 0)) - (global $tlsf/FL_INDEX_COUNT (mut i32) (i32.const 0)) - (global $tlsf/SL_INDEX_COUNT (mut i32) (i32.const 0)) (memory $0 1) (data (i32.const 4) "\08") (export "control_construct" (func $tlsf/control_construct)) @@ -47,7 +35,7 @@ (i32.store (i32.add (get_local $0) - (get_global $tlsf/BLOCK_NEXT_FREE_OFFSET) + (i32.const 8) ) (get_local $1) ) @@ -56,7 +44,7 @@ (i32.store (i32.add (get_local $0) - (get_global $tlsf/BLOCK_PREV_FREE_OFFSET) + (i32.const 12) ) (get_local $1) ) @@ -65,7 +53,7 @@ (i32.store (i32.add (get_local $0) - (get_global $tlsf/CONTROL_FL_BITMAP_OFFSET) + (i32.const 16) ) (get_local $1) ) @@ -74,13 +62,16 @@ (if (i32.ge_s (get_local $1) - (get_global $tlsf/FL_INDEX_COUNT) + (i32.const 23) ) (unreachable) ) (i32.store (i32.add - (get_local $0) + (i32.add + (get_local $0) + (i32.const 20) + ) (i32.mul (get_local $1) (i32.const 4) @@ -93,25 +84,28 @@ (if (i32.ge_s (get_local $1) - (get_global $tlsf/FL_INDEX_COUNT) + (i32.const 23) ) (unreachable) ) (if (i32.ge_s (get_local $2) - (get_global $tlsf/SL_INDEX_COUNT) + (i32.const 32) ) (unreachable) ) (i32.store (i32.add - (get_local $0) + (i32.add + (get_local $0) + (i32.const 112) + ) (i32.mul (i32.add (i32.mul (get_local $1) - (get_global $tlsf/SL_INDEX_COUNT) + (i32.const 32) ) (get_local $2) ) @@ -143,7 +137,7 @@ (if (i32.lt_s (get_local $1) - (get_global $tlsf/FL_INDEX_COUNT) + (i32.const 23) ) (block (call $tlsf/control_set_sl @@ -158,7 +152,7 @@ (if (i32.lt_s (get_local $2) - (get_global $tlsf/SL_INDEX_COUNT) + (i32.const 32) ) (block (call $tlsf/control_set_block @@ -246,67 +240,9 @@ ) (unreachable) ) - (set_global $tlsf/ALIGN_SIZE - (i32.shl - (i32.const 1) - (get_global $tlsf/ALIGN_SIZE_LOG2) - ) - ) - (if - (i32.ne - (get_global $tlsf/ALIGN_SIZE) - (i32.const 8) - ) - (unreachable) - ) - (set_global $tlsf/BLOCK_SIZE_OFFSET - (i32.add - (get_global $tlsf/BLOCK_PREV_PHYS_OFFSET) - (i32.const 4) - ) - ) - (set_global $tlsf/BLOCK_NEXT_FREE_OFFSET - (i32.add - (get_global $tlsf/BLOCK_SIZE_OFFSET) - (i32.const 4) - ) - ) - (set_global $tlsf/BLOCK_PREV_FREE_OFFSET - (i32.add - (get_global $tlsf/BLOCK_NEXT_FREE_OFFSET) - (i32.const 4) - ) - ) - (set_global $tlsf/CONTROL_FL_BITMAP_OFFSET - (i32.add - (get_global $tlsf/BLOCK_PREV_FREE_OFFSET) - (i32.const 4) - ) - ) - (set_global $tlsf/FL_INDEX_SHIFT - (i32.add - (get_global $tlsf/SL_INDEX_COUNT_LOG2) - (get_global $tlsf/ALIGN_SIZE_LOG2) - ) - ) - (set_global $tlsf/FL_INDEX_COUNT - (i32.add - (i32.sub - (get_global $tlsf/FL_INDEX_MAX) - (get_global $tlsf/FL_INDEX_SHIFT) - ) - (i32.const 1) - ) - ) - (set_global $tlsf/SL_INDEX_COUNT - (i32.shl - (i32.const 1) - (get_global $tlsf/SL_INDEX_COUNT_LOG2) - ) - ) (call $tlsf/control_construct (i32.load - (i32.const 8) + (i32.const 4) ) ) ) diff --git a/tests/compiler/tlsf.ts b/tests/compiler/tlsf.ts index e5fa4e16..2ad4c057 100644 --- a/tests/compiler/tlsf.ts +++ b/tests/compiler/tlsf.ts @@ -104,24 +104,24 @@ function control_set_fl(ptr: usize, value: u32): void { function control_get_sl(ptr: usize, flIndex: usize): u32 { assert(flIndex < FL_INDEX_COUNT); - return load(ptr + flIndex * sizeof()); + return load(ptr + CONTROL_SL_BITMAP_OFFSET + flIndex * sizeof()); } function control_set_sl(ptr: usize, flIndex: usize, value: u32): void { assert(flIndex < FL_INDEX_COUNT); - store(ptr + flIndex * sizeof(), value); + store(ptr + CONTROL_SL_BITMAP_OFFSET + flIndex * sizeof(), value); } function control_get_block(ptr: usize, flIndex: usize, slIndex: usize): usize { assert(flIndex < FL_INDEX_COUNT); assert(slIndex < SL_INDEX_COUNT); - return load(ptr + (flIndex * SL_INDEX_COUNT + slIndex) * sizeof()); + return load(ptr + CONTROL_BLOCKS_OFFSET + (flIndex * SL_INDEX_COUNT + slIndex) * sizeof()); } function control_set_block(ptr: usize, flIndex: usize, slIndex: usize, value: usize): void { assert(flIndex < FL_INDEX_COUNT); assert(slIndex < SL_INDEX_COUNT); - store(ptr + (flIndex * SL_INDEX_COUNT + slIndex) * sizeof(), value); + store(ptr + CONTROL_BLOCKS_OFFSET + (flIndex * SL_INDEX_COUNT + slIndex) * sizeof(), value); } /* Clear structure and point all empty lists at the null block. */ @@ -136,4 +136,4 @@ export function control_construct(ptr: usize): void { } } -control_construct(load(8)); +control_construct(load(sizeof())); // get HEAP_OFFSET and initialize there diff --git a/tests/compiler/tlsf.wast b/tests/compiler/tlsf.wast index c595249f..a141f1b0 100644 --- a/tests/compiler/tlsf.wast +++ b/tests/compiler/tlsf.wast @@ -1,22 +1,25 @@ (module (type $ii (func (param i32) (result i32))) + (type $i (func (result i32))) (type $iiv (func (param i32 i32))) (type $iiiv (func (param i32 i32 i32))) (type $iiiiv (func (param i32 i32 i32 i32))) (type $iv (func (param i32))) (type $v (func)) (global $tlsf/ALIGN_SIZE_LOG2 i32 (i32.const 3)) - (global $tlsf/ALIGN_SIZE (mut i32) (i32.const 0)) + (global $tlsf/ALIGN_SIZE i32 (i32.const 8)) (global $tlsf/BLOCK_PREV_PHYS_OFFSET i32 (i32.const 0)) - (global $tlsf/BLOCK_SIZE_OFFSET (mut i32) (i32.const 0)) - (global $tlsf/BLOCK_NEXT_FREE_OFFSET (mut i32) (i32.const 0)) - (global $tlsf/BLOCK_PREV_FREE_OFFSET (mut i32) (i32.const 0)) - (global $tlsf/CONTROL_FL_BITMAP_OFFSET (mut i32) (i32.const 0)) + (global $tlsf/BLOCK_SIZE_OFFSET i32 (i32.const 4)) + (global $tlsf/BLOCK_NEXT_FREE_OFFSET i32 (i32.const 8)) + (global $tlsf/BLOCK_PREV_FREE_OFFSET i32 (i32.const 12)) + (global $tlsf/CONTROL_FL_BITMAP_OFFSET i32 (i32.const 16)) (global $tlsf/FL_INDEX_MAX i32 (i32.const 30)) (global $tlsf/SL_INDEX_COUNT_LOG2 i32 (i32.const 5)) - (global $tlsf/FL_INDEX_SHIFT (mut i32) (i32.const 0)) - (global $tlsf/FL_INDEX_COUNT (mut i32) (i32.const 0)) - (global $tlsf/SL_INDEX_COUNT (mut i32) (i32.const 0)) + (global $tlsf/FL_INDEX_SHIFT i32 (i32.const 8)) + (global $tlsf/FL_INDEX_COUNT i32 (i32.const 23)) + (global $tlsf/CONTROL_SL_BITMAP_OFFSET i32 (i32.const 20)) + (global $tlsf/SL_INDEX_COUNT i32 (i32.const 32)) + (global $tlsf/CONTROL_BLOCKS_OFFSET i32 (i32.const 112)) (memory $0 1) (data (i32.const 4) "\08\00\00\00") (export "control_construct" (func $tlsf/control_construct)) @@ -61,7 +64,7 @@ (i32.store (i32.add (get_local $0) - (get_global $tlsf/BLOCK_NEXT_FREE_OFFSET) + (i32.const 8) ) (get_local $1) ) @@ -70,7 +73,7 @@ (i32.store (i32.add (get_local $0) - (get_global $tlsf/BLOCK_PREV_FREE_OFFSET) + (i32.const 12) ) (get_local $1) ) @@ -79,7 +82,7 @@ (i32.store (i32.add (get_local $0) - (get_global $tlsf/CONTROL_FL_BITMAP_OFFSET) + (i32.const 16) ) (get_local $1) ) @@ -89,14 +92,17 @@ (i32.eqz (i32.lt_s (get_local $1) - (get_global $tlsf/FL_INDEX_COUNT) + (i32.const 23) ) ) (unreachable) ) (i32.store (i32.add - (get_local $0) + (i32.add + (get_local $0) + (i32.const 20) + ) (i32.mul (get_local $1) (i32.const 4) @@ -110,7 +116,7 @@ (i32.eqz (i32.lt_s (get_local $1) - (get_global $tlsf/FL_INDEX_COUNT) + (i32.const 23) ) ) (unreachable) @@ -119,19 +125,22 @@ (i32.eqz (i32.lt_s (get_local $2) - (get_global $tlsf/SL_INDEX_COUNT) + (i32.const 32) ) ) (unreachable) ) (i32.store (i32.add - (get_local $0) + (i32.add + (get_local $0) + (i32.const 112) + ) (i32.mul (i32.add (i32.mul (get_local $1) - (get_global $tlsf/SL_INDEX_COUNT) + (i32.const 32) ) (get_local $2) ) @@ -166,7 +175,7 @@ (if (i32.lt_s (get_local $1) - (get_global $tlsf/FL_INDEX_COUNT) + (i32.const 23) ) (block (block @@ -185,7 +194,7 @@ (if (i32.lt_s (get_local $2) - (get_global $tlsf/SL_INDEX_COUNT) + (i32.const 32) ) (block (call $tlsf/control_set_block @@ -302,69 +311,18 @@ ) (unreachable) ) - (set_global $tlsf/ALIGN_SIZE - (i32.shl - (i32.const 1) - (get_global $tlsf/ALIGN_SIZE_LOG2) - ) - ) (if (i32.eqz (i32.eq - (get_global $tlsf/ALIGN_SIZE) + (i32.const 8) (i32.const 8) ) ) (unreachable) ) - (set_global $tlsf/BLOCK_SIZE_OFFSET - (i32.add - (get_global $tlsf/BLOCK_PREV_PHYS_OFFSET) - (i32.const 4) - ) - ) - (set_global $tlsf/BLOCK_NEXT_FREE_OFFSET - (i32.add - (get_global $tlsf/BLOCK_SIZE_OFFSET) - (i32.const 4) - ) - ) - (set_global $tlsf/BLOCK_PREV_FREE_OFFSET - (i32.add - (get_global $tlsf/BLOCK_NEXT_FREE_OFFSET) - (i32.const 4) - ) - ) - (set_global $tlsf/CONTROL_FL_BITMAP_OFFSET - (i32.add - (get_global $tlsf/BLOCK_PREV_FREE_OFFSET) - (i32.const 4) - ) - ) - (set_global $tlsf/FL_INDEX_SHIFT - (i32.add - (get_global $tlsf/SL_INDEX_COUNT_LOG2) - (get_global $tlsf/ALIGN_SIZE_LOG2) - ) - ) - (set_global $tlsf/FL_INDEX_COUNT - (i32.add - (i32.sub - (get_global $tlsf/FL_INDEX_MAX) - (get_global $tlsf/FL_INDEX_SHIFT) - ) - (i32.const 1) - ) - ) - (set_global $tlsf/SL_INDEX_COUNT - (i32.shl - (i32.const 1) - (get_global $tlsf/SL_INDEX_COUNT_LOG2) - ) - ) (call $tlsf/control_construct (i32.load - (i32.const 8) + (i32.const 4) ) ) )