summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/abi/js.h74
-rw-r--r--src/abi/stack.h56
-rw-r--r--src/abi/wasm-object.h16
-rw-r--r--src/asm2wasm.h1535
-rw-r--r--src/asm_v_wasm.h11
-rw-r--r--src/asmjs/asm_v_wasm.cpp86
-rw-r--r--src/asmjs/asmangle.cpp96
-rw-r--r--src/asmjs/asmangle.h5
-rw-r--r--src/asmjs/shared-constants.cpp186
-rw-r--r--src/asmjs/shared-constants.h170
-rw-r--r--src/binaryen-c.cpp1490
-rw-r--r--src/binaryen-c.h499
-rw-r--r--src/cfg/Relooper.cpp544
-rw-r--r--src/cfg/Relooper.h192
-rw-r--r--src/cfg/cfg-traversal.h95
-rw-r--r--src/cfg/liveness-traversal.h104
-rw-r--r--src/compiler-support.h34
-rw-r--r--src/dataflow/graph.h135
-rw-r--r--src/dataflow/node.h75
-rw-r--r--src/dataflow/users.h8
-rw-r--r--src/dataflow/utils.h38
-rw-r--r--src/emscripten-optimizer/istring.h109
-rw-r--r--src/emscripten-optimizer/optimizer-shared.cpp234
-rw-r--r--src/emscripten-optimizer/optimizer.h47
-rw-r--r--src/emscripten-optimizer/parser.cpp211
-rw-r--r--src/emscripten-optimizer/parser.h607
-rw-r--r--src/emscripten-optimizer/simple_ast.cpp52
-rw-r--r--src/emscripten-optimizer/simple_ast.h773
-rw-r--r--src/emscripten-optimizer/snprintf.h34
-rw-r--r--src/ir/ExpressionAnalyzer.cpp220
-rw-r--r--src/ir/ExpressionManipulator.cpp151
-rw-r--r--src/ir/LocalGraph.cpp79
-rw-r--r--src/ir/ReFinalize.cpp11
-rw-r--r--src/ir/abstract.h183
-rw-r--r--src/ir/bits.h39
-rw-r--r--src/ir/block-utils.h74
-rw-r--r--src/ir/branch-utils.h62
-rw-r--r--src/ir/cost.h702
-rw-r--r--src/ir/effects.h195
-rw-r--r--src/ir/equivalent_sets.h8
-rw-r--r--src/ir/features.h4
-rw-r--r--src/ir/find_all.h13
-rw-r--r--src/ir/flat.h36
-rw-r--r--src/ir/function-type-utils.h1
-rw-r--r--src/ir/function-utils.h18
-rw-r--r--src/ir/global-utils.h46
-rw-r--r--src/ir/hashed.h33
-rw-r--r--src/ir/import-utils.h12
-rw-r--r--src/ir/iteration.h27
-rw-r--r--src/ir/label-utils.h15
-rw-r--r--src/ir/load-utils.h8
-rw-r--r--src/ir/local-graph.h31
-rw-r--r--src/ir/local-utils.h28
-rw-r--r--src/ir/localize.h1
-rw-r--r--src/ir/manipulation.h71
-rw-r--r--src/ir/memory-utils.h253
-rw-r--r--src/ir/module-utils.h31
-rw-r--r--src/ir/parents.h18
-rw-r--r--src/ir/properties.h26
-rw-r--r--src/ir/table-utils.h2
-rw-r--r--src/ir/trapping.h43
-rw-r--r--src/ir/type-updating.h41
-rw-r--r--src/ir/utils.h118
-rw-r--r--src/literal.h153
-rw-r--r--src/mixed_arena.h99
-rw-r--r--src/parsing.h149
-rw-r--r--src/pass.h106
-rw-r--r--src/passes/CoalesceLocals.cpp186
-rw-r--r--src/passes/CodeFolding.cpp253
-rw-r--r--src/passes/CodePushing.cpp87
-rw-r--r--src/passes/ConstHoisting.cpp22
-rw-r--r--src/passes/DataFlowOpts.cpp41
-rw-r--r--src/passes/DeadArgumentElimination.cpp85
-rw-r--r--src/passes/DeadCodeElimination.cpp228
-rw-r--r--src/passes/Directize.cpp40
-rw-r--r--src/passes/DuplicateFunctionElimination.cpp45
-rw-r--r--src/passes/ExtractFunction.cpp11
-rw-r--r--src/passes/Flatten.cpp42
-rw-r--r--src/passes/FuncCastEmulation.cpp52
-rw-r--r--src/passes/I64ToI32Lowering.cpp1170
-rw-r--r--src/passes/Inlining.cpp113
-rw-r--r--src/passes/InstrumentLocals.cpp108
-rw-r--r--src/passes/InstrumentMemory.cpp138
-rw-r--r--src/passes/LegalizeJSInterface.cpp86
-rw-r--r--src/passes/LimitSegments.cpp7
-rw-r--r--src/passes/LocalCSE.cpp23
-rw-r--r--src/passes/LogExecution.cpp32
-rw-r--r--src/passes/LoopInvariantCodeMotion.cpp35
-rw-r--r--src/passes/MemoryPacking.cpp16
-rw-r--r--src/passes/MergeBlocks.cpp138
-rw-r--r--src/passes/MergeLocals.cpp38
-rw-r--r--src/passes/Metrics.cpp52
-rw-r--r--src/passes/MinifyImportsAndExports.cpp28
-rw-r--r--src/passes/NameList.cpp12
-rw-r--r--src/passes/NoExitRuntime.cpp24
-rw-r--r--src/passes/OptimizeAddedConstants.cpp114
-rw-r--r--src/passes/OptimizeInstructions.cpp603
-rw-r--r--src/passes/PickLoadSigns.cpp26
-rw-r--r--src/passes/PostEmscripten.cpp21
-rw-r--r--src/passes/Precompute.cpp149
-rw-r--r--src/passes/Print.cpp1383
-rw-r--r--src/passes/PrintCallGraph.cpp45
-rw-r--r--src/passes/PrintFeatures.cpp8
-rw-r--r--src/passes/ReReloop.cpp96
-rw-r--r--src/passes/RedundantSetElimination.cpp43
-rw-r--r--src/passes/RelooperJumpThreading.cpp109
-rw-r--r--src/passes/RemoveImports.cpp17
-rw-r--r--src/passes/RemoveMemory.cpp6
-rw-r--r--src/passes/RemoveNonJSOps.cpp76
-rw-r--r--src/passes/RemoveUnusedBrs.cpp581
-rw-r--r--src/passes/RemoveUnusedModuleElements.cpp113
-rw-r--r--src/passes/RemoveUnusedNames.cpp32
-rw-r--r--src/passes/ReorderFunctions.cpp38
-rw-r--r--src/passes/ReorderLocals.cpp50
-rw-r--r--src/passes/SSAify.cpp51
-rw-r--r--src/passes/SafeHeap.cpp205
-rw-r--r--src/passes/SimplifyLocals.cpp260
-rw-r--r--src/passes/Souperify.cpp193
-rw-r--r--src/passes/SpillPointers.cpp82
-rw-r--r--src/passes/StackIR.cpp75
-rw-r--r--src/passes/Strip.cpp23
-rw-r--r--src/passes/StripTargetFeatures.cpp4
-rw-r--r--src/passes/TrapMode.cpp237
-rw-r--r--src/passes/Untee.cpp17
-rw-r--r--src/passes/Vacuum.cpp142
-rw-r--r--src/passes/intrinsics-module.h1
-rw-r--r--src/passes/opt-utils.h9
-rw-r--r--src/passes/pass.cpp391
-rw-r--r--src/passes/passes.h2
-rw-r--r--src/pretty_printing.h20
-rw-r--r--src/shared-constants.h80
-rw-r--r--src/shell-interface.h78
-rw-r--r--src/support/alloc.h7
-rw-r--r--src/support/archive.cpp62
-rw-r--r--src/support/archive.h12
-rw-r--r--src/support/base64.h23
-rw-r--r--src/support/bits.cpp92
-rw-r--r--src/support/bits.h24
-rw-r--r--src/support/colors.cpp18
-rw-r--r--src/support/colors.h29
-rw-r--r--src/support/command-line.cpp35
-rw-r--r--src/support/command-line.h26
-rw-r--r--src/support/file.cpp83
-rw-r--r--src/support/file.h45
-rw-r--r--src/support/hash.h3
-rw-r--r--src/support/json.h91
-rw-r--r--src/support/learning.h39
-rw-r--r--src/support/name.h4
-rw-r--r--src/support/path.cpp10
-rw-r--r--src/support/safe_integer.cpp28
-rw-r--r--src/support/safe_integer.h4
-rw-r--r--src/support/small_vector.h33
-rw-r--r--src/support/sorted_vector.h9
-rw-r--r--src/support/threads.cpp43
-rw-r--r--src/support/threads.h19
-rw-r--r--src/support/timing.h18
-rw-r--r--src/support/unique_deferring_queue.h3
-rw-r--r--src/support/utilities.h21
-rw-r--r--src/tools/asm2wasm.cpp271
-rw-r--r--src/tools/execution-results.h17
-rw-r--r--src/tools/fuzzing.h1554
-rw-r--r--src/tools/js-wrapper.h35
-rw-r--r--src/tools/optimization-options.h230
-rw-r--r--src/tools/spec-wrapper.h29
-rw-r--r--src/tools/tool-options.h117
-rw-r--r--src/tools/tool-utils.h1
-rw-r--r--src/tools/wasm-as.cpp115
-rw-r--r--src/tools/wasm-ctor-eval.cpp207
-rw-r--r--src/tools/wasm-dis.cpp54
-rw-r--r--src/tools/wasm-emscripten-finalize.cpp150
-rw-r--r--src/tools/wasm-metadce.cpp268
-rw-r--r--src/tools/wasm-opt.cpp225
-rw-r--r--src/tools/wasm-reduce.cpp562
-rw-r--r--src/tools/wasm-shell.cpp125
-rw-r--r--src/tools/wasm2js.cpp321
-rw-r--r--src/wasm-binary.h297
-rw-r--r--src/wasm-builder.h246
-rw-r--r--src/wasm-emscripten.h22
-rw-r--r--src/wasm-features.h50
-rw-r--r--src/wasm-interpreter.h1286
-rw-r--r--src/wasm-io.h21
-rw-r--r--src/wasm-module-building.h67
-rw-r--r--src/wasm-printing.h13
-rw-r--r--src/wasm-s-parser.h54
-rw-r--r--src/wasm-stack.h1720
-rw-r--r--src/wasm-traversal.h618
-rw-r--r--src/wasm-validator.h2
-rw-r--r--src/wasm.h536
-rw-r--r--src/wasm/literal.cpp869
-rw-r--r--src/wasm/wasm-binary.cpp2599
-rw-r--r--src/wasm/wasm-emscripten.cpp161
-rw-r--r--src/wasm/wasm-interpreter.cpp4
-rw-r--r--src/wasm/wasm-io.cpp47
-rw-r--r--src/wasm/wasm-s-parser.cpp672
-rw-r--r--src/wasm/wasm-type.cpp77
-rw-r--r--src/wasm/wasm-validator.cpp1091
-rw-r--r--src/wasm/wasm.cpp451
-rw-r--r--src/wasm2js.h1022
198 files changed, 22447 insertions, 13655 deletions
diff --git a/src/abi/js.h b/src/abi/js.h
index 6994a4291..8391346c8 100644
--- a/src/abi/js.h
+++ b/src/abi/js.h
@@ -17,17 +17,14 @@
#ifndef wasm_abi_abi_h
#define wasm_abi_abi_h
-#include "wasm.h"
#include "asmjs/shared-constants.h"
+#include "wasm.h"
namespace wasm {
namespace ABI {
-enum class LegalizationLevel {
- Full = 0,
- Minimal = 1
-};
+enum class LegalizationLevel { Full = 0, Minimal = 1 };
inline std::string getLegalizationPass(LegalizationLevel level) {
if (level == LegalizationLevel::Full) {
@@ -39,51 +36,52 @@ inline std::string getLegalizationPass(LegalizationLevel level) {
namespace wasm2js {
-extern cashew::IString SCRATCH_LOAD_I32,
- SCRATCH_STORE_I32,
- SCRATCH_LOAD_I64,
- SCRATCH_STORE_I64,
- SCRATCH_LOAD_F32,
- SCRATCH_STORE_F32,
- SCRATCH_LOAD_F64,
- SCRATCH_STORE_F64;
+extern cashew::IString SCRATCH_LOAD_I32;
+extern cashew::IString SCRATCH_STORE_I32;
+extern cashew::IString SCRATCH_LOAD_I64;
+extern cashew::IString SCRATCH_STORE_I64;
+extern cashew::IString SCRATCH_LOAD_F32;
+extern cashew::IString SCRATCH_STORE_F32;
+extern cashew::IString SCRATCH_LOAD_F64;
+extern cashew::IString SCRATCH_STORE_F64;
// The wasm2js scratch memory helpers let us read and write to scratch memory
// for purposes of implementing things like reinterpret, etc.
// The optional "specific" parameter is a specific function we want. If not
// provided, we create them all.
-inline void ensureScratchMemoryHelpers(Module* wasm, cashew::IString specific = cashew::IString()) {
- auto ensureImport = [&](Name name, const std::vector<Type> params, Type result) {
- if (wasm->getFunctionOrNull(name)) return;
- if (specific.is() && name != specific) return;
- auto func = make_unique<Function>();
- func->name = name;
- func->params = params;
- func->result = result;
- func->module = ENV;
- func->base = name;
- wasm->addFunction(std::move(func));
- };
+inline void
+ensureScratchMemoryHelpers(Module* wasm,
+ cashew::IString specific = cashew::IString()) {
+ auto ensureImport =
+ [&](Name name, const std::vector<Type> params, Type result) {
+ if (wasm->getFunctionOrNull(name))
+ return;
+ if (specific.is() && name != specific)
+ return;
+ auto func = make_unique<Function>();
+ func->name = name;
+ func->params = params;
+ func->result = result;
+ func->module = ENV;
+ func->base = name;
+ wasm->addFunction(std::move(func));
+ };
- ensureImport(SCRATCH_LOAD_I32, { i32 }, i32);
- ensureImport(SCRATCH_STORE_I32, { i32, i32 }, none);
+ ensureImport(SCRATCH_LOAD_I32, {i32}, i32);
+ ensureImport(SCRATCH_STORE_I32, {i32, i32}, none);
ensureImport(SCRATCH_LOAD_I64, {}, i64);
- ensureImport(SCRATCH_STORE_I64, { i64 }, none);
+ ensureImport(SCRATCH_STORE_I64, {i64}, none);
ensureImport(SCRATCH_LOAD_F32, {}, f32);
- ensureImport(SCRATCH_STORE_F32, { f32 }, none);
+ ensureImport(SCRATCH_STORE_F32, {f32}, none);
ensureImport(SCRATCH_LOAD_F64, {}, f64);
- ensureImport(SCRATCH_STORE_F64, { f64 }, none);
+ ensureImport(SCRATCH_STORE_F64, {f64}, none);
}
inline bool isScratchMemoryHelper(cashew::IString name) {
- return name == SCRATCH_LOAD_I32 ||
- name == SCRATCH_STORE_I32 ||
- name == SCRATCH_LOAD_I64 ||
- name == SCRATCH_STORE_I64 ||
- name == SCRATCH_LOAD_F32 ||
- name == SCRATCH_STORE_F32 ||
- name == SCRATCH_LOAD_F64 ||
- name == SCRATCH_STORE_F64;
+ return name == SCRATCH_LOAD_I32 || name == SCRATCH_STORE_I32 ||
+ name == SCRATCH_LOAD_I64 || name == SCRATCH_STORE_I64 ||
+ name == SCRATCH_LOAD_F32 || name == SCRATCH_STORE_F32 ||
+ name == SCRATCH_LOAD_F64 || name == SCRATCH_STORE_F64;
}
} // namespace wasm2js
diff --git a/src/abi/stack.h b/src/abi/stack.h
index 77e166c2a..f84c15d90 100644
--- a/src/abi/stack.h
+++ b/src/abi/stack.h
@@ -17,31 +17,31 @@
#ifndef wasm_abi_stack_h
#define wasm_abi_stack_h
-#include "wasm.h"
-#include "wasm-builder.h"
-#include "shared-constants.h"
+#include "abi.h"
#include "asmjs/shared-constants.h"
#include "ir/find_all.h"
#include "ir/global-utils.h"
-#include "abi.h"
+#include "shared-constants.h"
+#include "wasm-builder.h"
+#include "wasm.h"
namespace wasm {
namespace ABI {
-enum {
- StackAlign = 16
-};
+enum { StackAlign = 16 };
inline Index stackAlign(Index size) {
return (size + StackAlign - 1) & -StackAlign;
}
// Allocate some space on the stack, and assign it to a local.
-// The local will have the same constant value in all the function, so you can just
-// local.get it anywhere there.
-inline void getStackSpace(Index local, Function* func, Index size, Module& wasm) {
- auto* stackPointer = GlobalUtils::getGlobalInitializedToImport(wasm, ENV, "STACKTOP");
+// The local will have the same constant value in all the function, so you can
+// just local.get it anywhere there.
+inline void
+getStackSpace(Index local, Function* func, Index size, Module& wasm) {
+ auto* stackPointer =
+ GlobalUtils::getGlobalInitializedToImport(wasm, ENV, "STACKTOP");
if (!stackPointer) {
Fatal() << "getStackSpace: failed to find the stack pointer";
}
@@ -50,34 +50,21 @@ inline void getStackSpace(Index local, Function* func, Index size, Module& wasm)
// TODO: find existing stack usage, and add on top of that - carefully
Builder builder(wasm);
auto* block = builder.makeBlock();
- block->list.push_back(
- builder.makeSetLocal(
- local,
- builder.makeGetGlobal(stackPointer->name, PointerType)
- )
- );
+ block->list.push_back(builder.makeSetLocal(
+ local, builder.makeGetGlobal(stackPointer->name, PointerType)));
// TODO: add stack max check
Expression* added;
if (PointerType == i32) {
- added = builder.makeBinary(
- AddInt32,
- builder.makeGetLocal(local, PointerType),
- builder.makeConst(Literal(int32_t(size)))
- );
+ added = builder.makeBinary(AddInt32,
+ builder.makeGetLocal(local, PointerType),
+ builder.makeConst(Literal(int32_t(size))));
} else {
WASM_UNREACHABLE();
}
- block->list.push_back(
- builder.makeSetGlobal(
- stackPointer->name,
- added
- )
- );
+ block->list.push_back(builder.makeSetGlobal(stackPointer->name, added));
auto makeStackRestore = [&]() {
- return builder.makeSetGlobal(
- stackPointer->name,
- builder.makeGetLocal(local, PointerType)
- );
+ return builder.makeSetGlobal(stackPointer->name,
+ builder.makeGetLocal(local, PointerType));
};
// add stack restores to the returns
FindAllPointers<Return> finder(func->body);
@@ -89,9 +76,8 @@ inline void getStackSpace(Index local, Function* func, Index size, Module& wasm)
auto temp = builder.addVar(func, ret->value->type);
block->list.push_back(builder.makeSetLocal(temp, ret->value));
block->list.push_back(makeStackRestore());
- block->list.push_back(builder.makeReturn(
- builder.makeGetLocal(temp, ret->value->type)
- ));
+ block->list.push_back(
+ builder.makeReturn(builder.makeGetLocal(temp, ret->value->type)));
block->finalize();
*ptr = block;
} else {
diff --git a/src/abi/wasm-object.h b/src/abi/wasm-object.h
index 0ce814030..d12e1f581 100644
--- a/src/abi/wasm-object.h
+++ b/src/abi/wasm-object.h
@@ -25,14 +25,14 @@
namespace wasm {
namespace ABI {
- enum LinkType : unsigned {
- WASM_STACK_POINTER = 0x1,
- WASM_SYMBOL_INFO = 0x2,
- WASM_DATA_SIZE = 0x3,
- WASM_DATA_ALIGNMENT = 0x4,
- WASM_SEGMENT_INFO = 0x5,
- WASM_INIT_FUNCS = 0x6,
- };
+enum LinkType : unsigned {
+ WASM_STACK_POINTER = 0x1,
+ WASM_SYMBOL_INFO = 0x2,
+ WASM_DATA_SIZE = 0x3,
+ WASM_DATA_ALIGNMENT = 0x4,
+ WASM_SEGMENT_INFO = 0x5,
+ WASM_INIT_FUNCS = 0x6,
+};
} // namespace ABI
} // namespace wasm
diff --git a/src/asm2wasm.h b/src/asm2wasm.h
index a981cb660..ba6a3df57 100644
--- a/src/asm2wasm.h
+++ b/src/asm2wasm.h
@@ -22,15 +22,10 @@
#ifndef wasm_asm2wasm_h
#define wasm_asm2wasm_h
-#include "wasm.h"
-#include "emscripten-optimizer/optimizer.h"
-#include "mixed_arena.h"
-#include "shared-constants.h"
-#include "asmjs/shared-constants.h"
+#include "abi/js.h"
#include "asm_v_wasm.h"
-#include "passes/passes.h"
-#include "pass.h"
-#include "parsing.h"
+#include "asmjs/shared-constants.h"
+#include "emscripten-optimizer/optimizer.h"
#include "ir/bits.h"
#include "ir/branch-utils.h"
#include "ir/function-type-utils.h"
@@ -38,10 +33,15 @@
#include "ir/module-utils.h"
#include "ir/trapping.h"
#include "ir/utils.h"
+#include "mixed_arena.h"
+#include "parsing.h"
+#include "pass.h"
+#include "passes/passes.h"
+#include "shared-constants.h"
#include "wasm-builder.h"
#include "wasm-emscripten.h"
#include "wasm-module-building.h"
-#include "abi/js.h"
+#include "wasm.h"
namespace wasm {
@@ -49,90 +49,90 @@ using namespace cashew;
// Names
-Name I32_CTTZ("i32_cttz"),
- I32_CTPOP("i32_ctpop"),
- I32_BC2F("i32_bc2f"),
- I32_BC2I("i32_bc2i"),
- I64("i64"),
- I64_CONST("i64_const"),
- I64_ADD("i64_add"),
- I64_SUB("i64_sub"),
- I64_MUL("i64_mul"),
- I64_UDIV("i64_udiv"),
- I64_SDIV("i64_sdiv"),
- I64_UREM("i64_urem"),
- I64_SREM("i64_srem"),
- I64_AND("i64_and"),
- I64_OR("i64_or"),
- I64_XOR("i64_xor"),
- I64_SHL("i64_shl"),
- I64_ASHR("i64_ashr"),
- I64_LSHR("i64_lshr"),
- I64_EQ("i64_eq"),
- I64_NE("i64_ne"),
- I64_ULE("i64_ule"),
- I64_SLE("i64_sle"),
- I64_UGE("i64_uge"),
- I64_SGE("i64_sge"),
- I64_ULT("i64_ult"),
- I64_SLT("i64_slt"),
- I64_UGT("i64_ugt"),
- I64_SGT("i64_sgt"),
- I64_TRUNC("i64_trunc"),
- I64_SEXT("i64_sext"),
- I64_ZEXT("i64_zext"),
- I64_S2F("i64_s2f"),
- I64_S2D("i64_s2d"),
- I64_U2F("i64_u2f"),
- I64_U2D("i64_u2d"),
- I64_F2S("i64_f2s"),
- I64_D2S("i64_d2s"),
- I64_F2U("i64_f2u"),
- I64_D2U("i64_d2u"),
- I64_BC2D("i64_bc2d"),
- I64_BC2I("i64_bc2i"),
- I64_CTTZ("i64_cttz"),
- I64_CTLZ("i64_ctlz"),
- I64_CTPOP("i64_ctpop"),
- F32_COPYSIGN("f32_copysign"),
- F64_COPYSIGN("f64_copysign"),
- LOAD1("load1"),
- LOAD2("load2"),
- LOAD4("load4"),
- LOAD8("load8"),
- LOADF("loadf"),
- LOADD("loadd"),
- STORE1("store1"),
- STORE2("store2"),
- STORE4("store4"),
- STORE8("store8"),
- STOREF("storef"),
- STORED("stored"),
- FTCALL("ftCall_"),
- MFTCALL("mftCall_"),
- MAX_("max"),
- MIN_("min"),
- ATOMICS("Atomics"),
- ATOMICS_LOAD("load"),
- ATOMICS_STORE("store"),
- ATOMICS_EXCHANGE("exchange"),
- ATOMICS_COMPARE_EXCHANGE("compareExchange"),
- ATOMICS_ADD("add"),
- ATOMICS_SUB("sub"),
- ATOMICS_AND("and"),
- ATOMICS_OR("or"),
- ATOMICS_XOR("xor"),
- I64_ATOMICS_LOAD("i64_atomics_load"),
- I64_ATOMICS_STORE("i64_atomics_store"),
- I64_ATOMICS_AND("i64_atomics_and"),
- I64_ATOMICS_OR("i64_atomics_or"),
- I64_ATOMICS_XOR("i64_atomics_xor"),
- I64_ATOMICS_ADD("i64_atomics_add"),
- I64_ATOMICS_SUB("i64_atomics_sub"),
- I64_ATOMICS_EXCHANGE("i64_atomics_exchange"),
- I64_ATOMICS_COMPAREEXCHANGE("i64_atomics_compareExchange"),
- TEMP_DOUBLE_PTR("tempDoublePtr"),
- EMSCRIPTEN_DEBUGINFO("emscripten_debuginfo");
+Name I32_CTTZ("i32_cttz");
+Name I32_CTPOP("i32_ctpop");
+Name I32_BC2F("i32_bc2f");
+Name I32_BC2I("i32_bc2i");
+Name I64("i64");
+Name I64_CONST("i64_const");
+Name I64_ADD("i64_add");
+Name I64_SUB("i64_sub");
+Name I64_MUL("i64_mul");
+Name I64_UDIV("i64_udiv");
+Name I64_SDIV("i64_sdiv");
+Name I64_UREM("i64_urem");
+Name I64_SREM("i64_srem");
+Name I64_AND("i64_and");
+Name I64_OR("i64_or");
+Name I64_XOR("i64_xor");
+Name I64_SHL("i64_shl");
+Name I64_ASHR("i64_ashr");
+Name I64_LSHR("i64_lshr");
+Name I64_EQ("i64_eq");
+Name I64_NE("i64_ne");
+Name I64_ULE("i64_ule");
+Name I64_SLE("i64_sle");
+Name I64_UGE("i64_uge");
+Name I64_SGE("i64_sge");
+Name I64_ULT("i64_ult");
+Name I64_SLT("i64_slt");
+Name I64_UGT("i64_ugt");
+Name I64_SGT("i64_sgt");
+Name I64_TRUNC("i64_trunc");
+Name I64_SEXT("i64_sext");
+Name I64_ZEXT("i64_zext");
+Name I64_S2F("i64_s2f");
+Name I64_S2D("i64_s2d");
+Name I64_U2F("i64_u2f");
+Name I64_U2D("i64_u2d");
+Name I64_F2S("i64_f2s");
+Name I64_D2S("i64_d2s");
+Name I64_F2U("i64_f2u");
+Name I64_D2U("i64_d2u");
+Name I64_BC2D("i64_bc2d");
+Name I64_BC2I("i64_bc2i");
+Name I64_CTTZ("i64_cttz");
+Name I64_CTLZ("i64_ctlz");
+Name I64_CTPOP("i64_ctpop");
+Name F32_COPYSIGN("f32_copysign");
+Name F64_COPYSIGN("f64_copysign");
+Name LOAD1("load1");
+Name LOAD2("load2");
+Name LOAD4("load4");
+Name LOAD8("load8");
+Name LOADF("loadf");
+Name LOADD("loadd");
+Name STORE1("store1");
+Name STORE2("store2");
+Name STORE4("store4");
+Name STORE8("store8");
+Name STOREF("storef");
+Name STORED("stored");
+Name FTCALL("ftCall_");
+Name MFTCALL("mftCall_");
+Name MAX_("max");
+Name MIN_("min");
+Name ATOMICS("Atomics");
+Name ATOMICS_LOAD("load");
+Name ATOMICS_STORE("store");
+Name ATOMICS_EXCHANGE("exchange");
+Name ATOMICS_COMPARE_EXCHANGE("compareExchange");
+Name ATOMICS_ADD("add");
+Name ATOMICS_SUB("sub");
+Name ATOMICS_AND("and");
+Name ATOMICS_OR("or");
+Name ATOMICS_XOR("xor");
+Name I64_ATOMICS_LOAD("i64_atomics_load");
+Name I64_ATOMICS_STORE("i64_atomics_store");
+Name I64_ATOMICS_AND("i64_atomics_and");
+Name I64_ATOMICS_OR("i64_atomics_or");
+Name I64_ATOMICS_XOR("i64_atomics_xor");
+Name I64_ATOMICS_ADD("i64_atomics_add");
+Name I64_ATOMICS_SUB("i64_atomics_sub");
+Name I64_ATOMICS_EXCHANGE("i64_atomics_exchange");
+Name I64_ATOMICS_COMPAREEXCHANGE("i64_atomics_compareExchange");
+Name TEMP_DOUBLE_PTR("tempDoublePtr");
+Name EMSCRIPTEN_DEBUGINFO("emscripten_debuginfo");
// Utilities
@@ -147,22 +147,16 @@ static void abort_on(std::string why, IString element) {
abort();
}
-Index indexOr(Index x, Index y) {
- return x ? x : y;
-}
+Index indexOr(Index x, Index y) { return x ? x : y; }
// useful when we need to see our parent, in an asm.js expression stack
struct AstStackHelper {
static std::vector<Ref> astStack;
- AstStackHelper(Ref curr) {
- astStack.push_back(curr);
- }
- ~AstStackHelper() {
- astStack.pop_back();
- }
+ AstStackHelper(Ref curr) { astStack.push_back(curr); }
+ ~AstStackHelper() { astStack.pop_back(); }
Ref getParent() {
if (astStack.size() >= 2) {
- return astStack[astStack.size()-2];
+ return astStack[astStack.size() - 2];
} else {
return Ref();
}
@@ -171,11 +165,14 @@ struct AstStackHelper {
std::vector<Ref> AstStackHelper::astStack;
-static bool startsWith(const char* string, const char *prefix) {
+static bool startsWith(const char* string, const char* prefix) {
while (1) {
- if (*prefix == 0) return true;
- if (*string == 0) return false;
- if (*string++ != *prefix++) return false;
+ if (*prefix == 0)
+ return true;
+ if (*string == 0)
+ return false;
+ if (*string++ != *prefix++)
+ return false;
}
};
@@ -194,7 +191,8 @@ struct Asm2WasmPreProcessor {
char* allocatedCopy = nullptr;
~Asm2WasmPreProcessor() {
- if (allocatedCopy) free(allocatedCopy);
+ if (allocatedCopy)
+ free(allocatedCopy);
}
char* process(char* input) {
@@ -211,31 +209,38 @@ struct Asm2WasmPreProcessor {
input++;
num--;
}
- char *end = input + num - 1;
+ char* end = input + num - 1;
while (*end != '}') {
*end = 0;
end--;
}
}
- // asm.js memory growth uses a quite elaborate pattern. Instead of parsing and
- // matching it, we do a simpler detection on emscripten's asm.js output format
+ // asm.js memory growth uses a quite elaborate pattern. Instead of parsing
+ // and matching it, we do a simpler detection on emscripten's asm.js output
+ // format
const char* START_FUNCS = "// EMSCRIPTEN_START_FUNCS";
- char *marker = strstr(input, START_FUNCS);
+ char* marker = strstr(input, START_FUNCS);
if (marker) {
- *marker = 0; // look for memory growth code just up to here, as an optimization
+ // look for memory growth code just up to here, as an optimization
+ *marker = 0;
}
- char *growthSign = strstr(input, "return true;"); // this can only show up in growth code, as normal asm.js lacks "true"
+ // this can only show up in growth code, as normal asm.js lacks "true"
+ char* growthSign = strstr(input, "return true;");
if (growthSign) {
memoryGrowth = true;
// clean out this function, we don't need it. first where it starts
- char *growthFuncStart = growthSign;
- while (*growthFuncStart != '{') growthFuncStart--; // skip body
- while (*growthFuncStart != '(') growthFuncStart--; // skip params
- while (*growthFuncStart != ' ') growthFuncStart--; // skip function name
- while (*growthFuncStart != 'f') growthFuncStart--; // skip 'function'
+ char* growthFuncStart = growthSign;
+ while (*growthFuncStart != '{')
+ growthFuncStart--; // skip body
+ while (*growthFuncStart != '(')
+ growthFuncStart--; // skip params
+ while (*growthFuncStart != ' ')
+ growthFuncStart--; // skip function name
+ while (*growthFuncStart != 'f')
+ growthFuncStart--; // skip 'function'
assert(strstr(growthFuncStart, "function ") == growthFuncStart);
- char *growthFuncEnd = strchr(growthSign, '}');
+ char* growthFuncEnd = strchr(growthSign, '}');
assert(growthFuncEnd > growthFuncStart + 5);
growthFuncStart[0] = '/';
growthFuncStart[1] = '*';
@@ -257,8 +262,12 @@ struct Asm2WasmPreProcessor {
// that, we can apply the debug info to the wasm node right
// before it - this is guaranteed to be correct without opts,
// and is usually decently accurate with them.
- const auto SCALE_FACTOR = 1.25; // an upper bound on how much more space we need as a multiple of the original
- const auto ADD_FACTOR = 100; // an upper bound on how much we write for each debug info element itself
+
+ // an upper bound on how much more space we need as a multiple of the
+ // original
+ const auto SCALE_FACTOR = 1.25;
+ // an upper bound on how much we write for each debug info element itself
+ const auto ADD_FACTOR = 100;
auto size = strlen(input);
auto upperBound = Index(size * SCALE_FACTOR) + ADD_FACTOR;
char* copy = allocatedCopy = (char*)malloc(upperBound);
@@ -321,15 +330,18 @@ struct Asm2WasmPreProcessor {
out += line.size();
*out++ = ')';
*out++ = ';';
- } else if (!seenUseAsm && (startsWith(input, "asm'") || startsWith(input, "asm\""))) {
+ } else if (!seenUseAsm &&
+ (startsWith(input, "asm'") || startsWith(input, "asm\""))) {
// end of "use asm" or "almost asm"
- const auto SKIP = 5; // skip the end of "use asm"; (5 chars, a,s,m," or ',;)
+ // skip the end of "use asm"; (5 chars, a,s,m," or ',;)
+ const auto SKIP = 5;
seenUseAsm = true;
memcpy(out, input, SKIP);
out += SKIP;
input += SKIP;
// add a fake import for the intrinsic, so the module validates
- std::string import = "\n var emscripten_debuginfo = env.emscripten_debuginfo;";
+ std::string import =
+ "\n var emscripten_debuginfo = env.emscripten_debuginfo;";
strcpy(out, import.c_str());
out += import.size();
} else {
@@ -356,21 +368,21 @@ static Call* checkDebugInfo(Expression* curr) {
return nullptr;
}
-// Debug info appears in the ast as calls to the debug intrinsic. These are usually
-// after the relevant node. We adjust them to a position that is not dce-able, so that
-// they are not trivially removed when optimizing.
-struct AdjustDebugInfo : public WalkerPass<PostWalker<AdjustDebugInfo, Visitor<AdjustDebugInfo>>> {
+// Debug info appears in the ast as calls to the debug intrinsic. These are
+// usually after the relevant node. We adjust them to a position that is not
+// dce-able, so that they are not trivially removed when optimizing.
+struct AdjustDebugInfo
+ : public WalkerPass<PostWalker<AdjustDebugInfo, Visitor<AdjustDebugInfo>>> {
bool isFunctionParallel() override { return true; }
Pass* create() override { return new AdjustDebugInfo(); }
- AdjustDebugInfo() {
- name = "adjust-debug-info";
- }
+ AdjustDebugInfo() { name = "adjust-debug-info"; }
void visitBlock(Block* curr) {
// look for a debug info call that is unreachable
- if (curr->list.size() == 0) return;
+ if (curr->list.size() == 0)
+ return;
auto* back = curr->list.back();
for (Index i = 1; i < curr->list.size(); i++) {
if (checkDebugInfo(curr->list[i]) && !checkDebugInfo(curr->list[i - 1])) {
@@ -393,7 +405,7 @@ class Asm2WasmBuilder {
public:
Module& wasm;
- MixedArena &allocator;
+ MixedArena& allocator;
Builder builder;
@@ -403,15 +415,20 @@ public:
struct MappedGlobal {
Type type;
- bool import; // if true, this is an import - we should read the value, not just set a zero
+ // if true, this is an import - we should read the value, not just set a
+ // zero
+ bool import;
IString module, base;
MappedGlobal() : type(none), import(false) {}
MappedGlobal(Type type) : type(type), import(false) {}
- MappedGlobal(Type type, bool import, IString module, IString base) : type(type), import(import), module(module), base(base) {}
+ MappedGlobal(Type type, bool import, IString module, IString base)
+ : type(type), import(import), module(module), base(base) {}
};
// function table
- std::map<IString, int> functionTableStarts; // each asm function table gets a range in the one wasm table, starting at a location
+ // each asm function table gets a range in the one wasm table, starting at a
+ // location
+ std::map<IString, int> functionTableStarts;
Asm2WasmPreProcessor& preprocessor;
bool debug;
@@ -426,18 +443,14 @@ public:
std::map<IString, MappedGlobal> mappedGlobals;
private:
- void allocateGlobal(IString name, Type type, Literal value=Literal()) {
+ void allocateGlobal(IString name, Type type, Literal value = Literal()) {
assert(mappedGlobals.find(name) == mappedGlobals.end());
if (value.type == none) {
value = Literal::makeZero(type);
}
mappedGlobals.emplace(name, MappedGlobal(type));
wasm.addGlobal(builder.makeGlobal(
- name,
- type,
- builder.makeConst(value),
- Builder::Mutable
- ));
+ name, type, builder.makeConst(value), Builder::Mutable));
}
struct View {
@@ -445,7 +458,8 @@ private:
bool integer, signed_;
AsmType type;
View() : bytes(0) {}
- View(unsigned bytes, bool integer, bool signed_, AsmType type) : bytes(bytes), integer(integer), signed_(signed_), type(type) {}
+ View(unsigned bytes, bool integer, bool signed_, AsmType type)
+ : bytes(bytes), integer(integer), signed_(signed_), type(type) {}
};
std::map<IString, View> views; // name (e.g. HEAP8) => view info
@@ -489,18 +503,20 @@ private:
assert(ast[0] == CALL && ast[1]->isString());
IString importName = ast[1]->getIString();
auto type = make_unique<FunctionType>();
- type->name = IString((std::string("type$") + importName.str).c_str(), false); // TODO: make a list of such types
+ type->name = IString((std::string("type$") + importName.str).c_str(),
+ false); // TODO: make a list of such types
type->result = resultType;
for (auto* operand : call->operands) {
type->params.push_back(operand->type);
}
- // if we already saw this signature, verify it's the same (or else handle that)
+ // if we already saw this signature, verify it's the same (or else handle
+ // that)
if (importedFunctionTypes.find(importName) != importedFunctionTypes.end()) {
FunctionType* previous = importedFunctionTypes[importName].get();
if (*type != *previous) {
- // merge it in. we'll add on extra 0 parameters for ones not actually used, and upgrade types to
- // double where there is a conflict (which is ok since in JS, double can contain everything
- // i32 and f32 can).
+ // merge it in. we'll add on extra 0 parameters for ones not actually
+ // used, and upgrade types to double where there is a conflict (which is
+ // ok since in JS, double can contain everything i32 and f32 can).
for (size_t i = 0; i < type->params.size(); i++) {
if (previous->params.size() > i) {
if (previous->params[i] == none) {
@@ -512,7 +528,8 @@ private:
previous->params.push_back(type->params[i]); // add a new param
}
}
- // we accept none and a concrete type, but two concrete types mean we need to use an f64 to contain anything
+ // we accept none and a concrete type, but two concrete types mean we
+ // need to use an f64 to contain anything
if (previous->result == none) {
previous->result = type->result; // use a more concrete type
} else if (previous->result != type->result && type->result != none) {
@@ -527,8 +544,9 @@ private:
Type getResultTypeOfCallUsingParent(Ref parent, AsmData* data) {
auto result = none;
if (!!parent) {
- // if the parent is a seq, we cannot be the last element in it (we would have a coercion, which would be
- // the parent), so we must be (us, somethingElse), and so our return is void
+ // if the parent is a seq, we cannot be the last element in it (we would
+ // have a coercion, which would be the parent), so we must be (us,
+ // somethingElse), and so our return is void
if (parent[0] != SEQ) {
result = detectWasmType(parent, data);
}
@@ -536,29 +554,31 @@ private:
return result;
}
- FunctionType* getFunctionType(Ref parent, ExpressionList& operands, AsmData* data) {
+ FunctionType*
+ getFunctionType(Ref parent, ExpressionList& operands, AsmData* data) {
Type result = getResultTypeOfCallUsingParent(parent, data);
return ensureFunctionType(getSig(result, operands), &wasm);
}
public:
- Asm2WasmBuilder(Module& wasm, Asm2WasmPreProcessor& preprocessor, bool debug, TrapMode trapMode, PassOptions passOptions, bool legalizeJavaScriptFFI, bool runOptimizationPasses, bool wasmOnly)
- : wasm(wasm),
- allocator(wasm.allocator),
- builder(wasm),
- preprocessor(preprocessor),
- debug(debug),
- trapMode(trapMode),
- trappingFunctions(trapMode, wasm, /* immediate = */ true),
- passOptions(passOptions),
- legalizeJavaScriptFFI(legalizeJavaScriptFFI),
- runOptimizationPasses(runOptimizationPasses),
- wasmOnly(wasmOnly) {}
-
- void processAsm(Ref ast);
+ Asm2WasmBuilder(Module& wasm,
+ Asm2WasmPreProcessor& preprocessor,
+ bool debug,
+ TrapMode trapMode,
+ PassOptions passOptions,
+ bool legalizeJavaScriptFFI,
+ bool runOptimizationPasses,
+ bool wasmOnly)
+ : wasm(wasm), allocator(wasm.allocator), builder(wasm),
+ preprocessor(preprocessor), debug(debug), trapMode(trapMode),
+ trappingFunctions(trapMode, wasm, /* immediate = */ true),
+ passOptions(passOptions), legalizeJavaScriptFFI(legalizeJavaScriptFFI),
+ runOptimizationPasses(runOptimizationPasses), wasmOnly(wasmOnly) {}
+
+ void processAsm(Ref ast);
private:
- AsmType detectAsmType(Ref ast, AsmData *data) {
+ AsmType detectAsmType(Ref ast, AsmData* data) {
if (ast->isString()) {
IString name = ast->getIString();
if (!data->isLocal(name)) {
@@ -576,7 +596,7 @@ private:
return detectType(ast, data, false, Math_fround, wasmOnly);
}
- Type detectWasmType(Ref ast, AsmData *data) {
+ Type detectWasmType(Ref ast, AsmData* data) {
return asmToWasmType(detectAsmType(ast, data));
}
@@ -586,27 +606,53 @@ private:
bool isParentUnsignedCoercion(Ref parent) {
// parent may not exist, or may be a non-relevant node
- if (!!parent && parent->isArray() && parent[0] == BINARY && isUnsignedCoercion(parent)) {
+ if (!!parent && parent->isArray() && parent[0] == BINARY &&
+ isUnsignedCoercion(parent)) {
return true;
}
return false;
}
- BinaryOp parseAsmBinaryOp(IString op, Ref left, Ref right, Expression* leftWasm, Expression* rightWasm) {
+ BinaryOp parseAsmBinaryOp(IString op,
+ Ref left,
+ Ref right,
+ Expression* leftWasm,
+ Expression* rightWasm) {
Type leftType = leftWasm->type;
bool isInteger = leftType == Type::i32;
- if (op == PLUS) return isInteger ? BinaryOp::AddInt32 : (leftType == f32 ? BinaryOp::AddFloat32 : BinaryOp::AddFloat64);
- if (op == MINUS) return isInteger ? BinaryOp::SubInt32 : (leftType == f32 ? BinaryOp::SubFloat32 : BinaryOp::SubFloat64);
- if (op == MUL) return isInteger ? BinaryOp::MulInt32 : (leftType == f32 ? BinaryOp::MulFloat32 : BinaryOp::MulFloat64);
- if (op == AND) return BinaryOp::AndInt32;
- if (op == OR) return BinaryOp::OrInt32;
- if (op == XOR) return BinaryOp::XorInt32;
- if (op == LSHIFT) return BinaryOp::ShlInt32;
- if (op == RSHIFT) return BinaryOp::ShrSInt32;
- if (op == TRSHIFT) return BinaryOp::ShrUInt32;
- if (op == EQ) return isInteger ? BinaryOp::EqInt32 : (leftType == f32 ? BinaryOp::EqFloat32 : BinaryOp::EqFloat64);
- if (op == NE) return isInteger ? BinaryOp::NeInt32 : (leftType == f32 ? BinaryOp::NeFloat32 : BinaryOp::NeFloat64);
+ if (op == PLUS)
+ return isInteger ? BinaryOp::AddInt32
+ : (leftType == f32 ? BinaryOp::AddFloat32
+ : BinaryOp::AddFloat64);
+ if (op == MINUS)
+ return isInteger ? BinaryOp::SubInt32
+ : (leftType == f32 ? BinaryOp::SubFloat32
+ : BinaryOp::SubFloat64);
+ if (op == MUL)
+ return isInteger ? BinaryOp::MulInt32
+ : (leftType == f32 ? BinaryOp::MulFloat32
+ : BinaryOp::MulFloat64);
+ if (op == AND)
+ return BinaryOp::AndInt32;
+ if (op == OR)
+ return BinaryOp::OrInt32;
+ if (op == XOR)
+ return BinaryOp::XorInt32;
+ if (op == LSHIFT)
+ return BinaryOp::ShlInt32;
+ if (op == RSHIFT)
+ return BinaryOp::ShrSInt32;
+ if (op == TRSHIFT)
+ return BinaryOp::ShrUInt32;
+ if (op == EQ)
+ return isInteger
+ ? BinaryOp::EqInt32
+ : (leftType == f32 ? BinaryOp::EqFloat32 : BinaryOp::EqFloat64);
+ if (op == NE)
+ return isInteger
+ ? BinaryOp::NeInt32
+ : (leftType == f32 ? BinaryOp::NeFloat32 : BinaryOp::NeFloat64);
bool isUnsigned = isUnsignedCoercion(left) || isUnsignedCoercion(right);
@@ -620,7 +666,8 @@ private:
if (isInteger) {
return isUnsigned ? BinaryOp::RemUInt32 : BinaryOp::RemSInt32;
}
- return BinaryOp::RemSInt32; // XXX no floating-point remainder op, this must be handled by the caller
+ return BinaryOp::RemSInt32; // XXX no floating-point remainder op, this
+ // must be handled by the caller
}
if (op == GE) {
if (isInteger) {
@@ -652,10 +699,14 @@ private:
int32_t bytesToShift(unsigned bytes) {
switch (bytes) {
- case 1: return 0;
- case 2: return 1;
- case 4: return 2;
- case 8: return 3;
+ case 1:
+ return 0;
+ case 2:
+ return 1;
+ case 4:
+ return 2;
+ case 8:
+ return 3;
default: {}
}
abort();
@@ -677,17 +728,22 @@ private:
}
if (ast[1] == MINUS && ast[2]->isNumber()) {
double num = -ast[2]->getNumber();
- if (isSInteger32(num)) return Literal((int32_t)num);
- if (isUInteger32(num)) return Literal((uint32_t)num);
+ if (isSInteger32(num))
+ return Literal((int32_t)num);
+ if (isUInteger32(num))
+ return Literal((uint32_t)num);
assert(false && "expected signed or unsigned int32");
}
- if (ast[1] == PLUS && ast[2]->isArray(UNARY_PREFIX) && ast[2][1] == MINUS && ast[2][2]->isNumber()) {
+ if (ast[1] == PLUS && ast[2]->isArray(UNARY_PREFIX) &&
+ ast[2][1] == MINUS && ast[2][2]->isNumber()) {
return Literal((double)-ast[2][2]->getNumber());
}
- if (ast[1] == MINUS && ast[2]->isArray(UNARY_PREFIX) && ast[2][1] == PLUS && ast[2][2]->isNumber()) {
+ if (ast[1] == MINUS && ast[2]->isArray(UNARY_PREFIX) &&
+ ast[2][1] == PLUS && ast[2][2]->isNumber()) {
return Literal((double)-ast[2][2]->getNumber());
}
- } else if (wasmOnly && ast->isArray(CALL) && ast[1]->isString() && ast[1] == I64_CONST) {
+ } else if (wasmOnly && ast->isArray(CALL) && ast[1]->isString() &&
+ ast[1] == I64_CONST) {
uint64_t low = ast[2][0]->getNumber();
uint64_t high = ast[2][1]->getNumber();
return Literal(uint64_t(low + (high << 32)));
@@ -702,18 +758,25 @@ private:
}
void fixCallType(Expression* call, Type type) {
- if (call->is<Call>()) call->cast<Call>()->type = type;
- else if (call->is<CallIndirect>()) call->cast<CallIndirect>()->type = type;
+ if (call->is<Call>())
+ call->cast<Call>()->type = type;
+ else if (call->is<CallIndirect>())
+ call->cast<CallIndirect>()->type = type;
}
- FunctionType* getBuiltinFunctionType(Name module, Name base, ExpressionList* operands = nullptr) {
+ FunctionType* getBuiltinFunctionType(Name module,
+ Name base,
+ ExpressionList* operands = nullptr) {
if (module == GLOBAL_MATH) {
if (base == ABS) {
assert(operands && operands->size() == 1);
Type type = (*operands)[0]->type;
- if (type == i32) return ensureFunctionType("ii", &wasm);
- if (type == f32) return ensureFunctionType("ff", &wasm);
- if (type == f64) return ensureFunctionType("dd", &wasm);
+ if (type == i32)
+ return ensureFunctionType("ii", &wasm);
+ if (type == f32)
+ return ensureFunctionType("ff", &wasm);
+ if (type == f64)
+ return ensureFunctionType("dd", &wasm);
}
}
return nullptr;
@@ -721,7 +784,8 @@ private:
// ensure a nameless block
Block* blockify(Expression* expression) {
- if (expression->is<Block>() && !expression->cast<Block>()->name.is()) return expression->dynCast<Block>();
+ if (expression->is<Block>() && !expression->cast<Block>()->name.is())
+ return expression->dynCast<Block>();
auto ret = allocator.alloc<Block>();
ret->list.push_back(expression);
ret->finalize();
@@ -733,8 +797,10 @@ private:
}
Expression* truncateToInt32(Expression* value) {
- if (value->type == i64) return builder.makeUnary(UnaryOp::WrapInt64, value);
- // either i32, or a call_import whose type we don't know yet (but would be legalized to i32 anyhow)
+ if (value->type == i64)
+ return builder.makeUnary(UnaryOp::WrapInt64, value);
+ // either i32, or a call_import whose type we don't know yet (but would be
+ // legalized to i32 anyhow)
return value;
}
@@ -749,7 +815,9 @@ void Asm2WasmBuilder::processAsm(Ref ast) {
Ref asmFunction = ast[1][0];
assert(asmFunction[0] == DEFUN);
Ref body = asmFunction[3];
- assert(body[0][0] == STRING && (body[0][1]->getIString() == IString("use asm") || body[0][1]->getIString() == IString("almost asm")));
+ assert(body[0][0] == STRING &&
+ (body[0][1]->getIString() == IString("use asm") ||
+ body[0][1]->getIString() == IString("almost asm")));
// extra functions that we add, that are not from the compiled code. we need
// to make sure to optimize them normally (OptimizingIncrementalModuleBuilder
@@ -885,7 +953,7 @@ void Asm2WasmBuilder::processAsm(Ref ast) {
}
std::string fullName = module[1]->getCString();
fullName += '.';
- fullName += + module[2]->getCString();
+ fullName += +module[2]->getCString();
moduleName = IString(fullName.c_str(), false);
} else {
assert(module->isString());
@@ -895,7 +963,8 @@ void Asm2WasmBuilder::processAsm(Ref ast) {
if (base == TEMP_DOUBLE_PTR) {
assert(tempDoublePtr.isNull());
tempDoublePtr = name;
- // we don't return here, as we can only optimize out some uses of tDP. So it remains imported
+ // we don't return here, as we can only optimize out some uses of tDP.
+ // So it remains imported
} else if (base == LLVM_CTTZ_I32) {
assert(llvm_cttz_i32.isNull());
llvm_cttz_i32 = name;
@@ -916,19 +985,20 @@ void Asm2WasmBuilder::processAsm(Ref ast) {
import->base = base;
import->type = type;
mappedGlobals.emplace(name, type);
- // __table_base and __memory_base are used as segment/element offsets, and must be constant;
- // otherwise, an asm.js import of a constant is mutable, e.g. STACKTOP
+ // __table_base and __memory_base are used as segment/element offsets, and
+ // must be constant; otherwise, an asm.js import of a constant is mutable,
+ // e.g. STACKTOP
if (name != TABLE_BASE && name != MEMORY_BASE) {
- // we need imported globals to be mutable, but wasm doesn't support that yet, so we must
- // import an immutable and create a mutable global initialized to its value
+ // we need imported globals to be mutable, but wasm doesn't support that
+ // yet, so we must import an immutable and create a mutable global
+ // initialized to its value
import->name = Name(std::string(import->name.str) + "$asm2wasm$import");
{
- wasm.addGlobal(builder.makeGlobal(
- name,
- type,
- builder.makeGetGlobal(import->name, type),
- Builder::Mutable
- ));
+ wasm.addGlobal(
+ builder.makeGlobal(name,
+ type,
+ builder.makeGetGlobal(import->name, type),
+ Builder::Mutable));
}
}
if ((name == TABLE_BASE || name == MEMORY_BASE) &&
@@ -946,34 +1016,44 @@ void Asm2WasmBuilder::processAsm(Ref ast) {
}
};
- IString Int8Array, Int16Array, Int32Array, UInt8Array, UInt16Array, UInt32Array, Float32Array, Float64Array;
+ IString Int8Array, Int16Array, Int32Array, UInt8Array, UInt16Array,
+ UInt32Array, Float32Array, Float64Array;
// set up optimization
if (runOptimizationPasses) {
Index numFunctions = 0;
for (unsigned i = 1; i < body->size(); i++) {
- if (body[i][0] == DEFUN) numFunctions++;
+ if (body[i][0] == DEFUN)
+ numFunctions++;
}
- optimizingBuilder = make_unique<OptimizingIncrementalModuleBuilder>(&wasm, numFunctions, passOptions, [&](PassRunner& passRunner) {
- // addPrePasses
- passRunner.options.lowMemoryUnused = true;
- if (debug) {
- passRunner.setDebug(true);
- passRunner.setValidateGlobally(false);
- }
- // run autodrop first, before optimizations
- passRunner.add<AutoDrop>();
- if (preprocessor.debugInfo) {
- // fix up debug info to better survive optimization
- passRunner.add<AdjustDebugInfo>();
- }
- // optimize relooper label variable usage at the wasm level, where it is easy
- passRunner.add("relooper-jump-threading");
- }, debug, false /* do not validate globally yet */);
+ optimizingBuilder = make_unique<OptimizingIncrementalModuleBuilder>(
+ &wasm,
+ numFunctions,
+ passOptions,
+ [&](PassRunner& passRunner) {
+ // addPrePasses
+ passRunner.options.lowMemoryUnused = true;
+ if (debug) {
+ passRunner.setDebug(true);
+ passRunner.setValidateGlobally(false);
+ }
+ // run autodrop first, before optimizations
+ passRunner.add<AutoDrop>();
+ if (preprocessor.debugInfo) {
+ // fix up debug info to better survive optimization
+ passRunner.add<AdjustDebugInfo>();
+ }
+ // optimize relooper label variable usage at the wasm level, where it is
+ // easy
+ passRunner.add("relooper-jump-threading");
+ },
+ debug,
+ false /* do not validate globally yet */);
}
- // if we see no function tables in the processing below, then the table still exists and has size 0
+ // if we see no function tables in the processing below, then the table still
+ // exists and has size 0
wasm.table.initial = wasm.table.max = 0;
@@ -990,10 +1070,12 @@ void Asm2WasmBuilder::processAsm(Ref ast) {
Ref value = pair[1];
if (value->isNumber()) {
// global int
- allocateGlobal(name, Type::i32, Literal(int32_t(value->getInteger())));
+ allocateGlobal(
+ name, Type::i32, Literal(int32_t(value->getInteger())));
} else if (value[0] == BINARY) {
// int import
- assert(value[1] == OR && value[3]->isNumber() && value[3]->getNumber() == 0);
+ assert(value[1] == OR && value[3]->isNumber() &&
+ value[3]->getNumber() == 0);
Ref import = value[2]; // env.what
addImport(name, import, Type::i32);
} else if (value[0] == UNARY_PREFIX) {
@@ -1009,7 +1091,8 @@ void Asm2WasmBuilder::processAsm(Ref ast) {
addImport(name, import, Type::f64);
}
} else if (value[0] == CALL) {
- assert(value[1]->isString() && value[1] == Math_fround && value[2][0]->isNumber() && value[2][0]->getNumber() == 0);
+ assert(value[1]->isString() && value[1] == Math_fround &&
+ value[2][0]->isNumber() && value[2][0]->getNumber() == 0);
allocateGlobal(name, Type::f32);
} else if (value[0] == DOT) {
// simple module.base import. can be a view, or a function.
@@ -1049,21 +1132,45 @@ void Asm2WasmBuilder::processAsm(Ref ast) {
if (constructor->isArray(DOT)) { // global.*Array
IString heap = constructor[2]->getIString();
if (heap == INT8ARRAY) {
- bytes = 1; integer = true; signed_ = true; asmType = ASM_INT;
+ bytes = 1;
+ integer = true;
+ signed_ = true;
+ asmType = ASM_INT;
} else if (heap == INT16ARRAY) {
- bytes = 2; integer = true; signed_ = true; asmType = ASM_INT;
+ bytes = 2;
+ integer = true;
+ signed_ = true;
+ asmType = ASM_INT;
} else if (heap == INT32ARRAY) {
- bytes = 4; integer = true; signed_ = true; asmType = ASM_INT;
+ bytes = 4;
+ integer = true;
+ signed_ = true;
+ asmType = ASM_INT;
} else if (heap == UINT8ARRAY) {
- bytes = 1; integer = true; signed_ = false; asmType = ASM_INT;
+ bytes = 1;
+ integer = true;
+ signed_ = false;
+ asmType = ASM_INT;
} else if (heap == UINT16ARRAY) {
- bytes = 2; integer = true; signed_ = false; asmType = ASM_INT;
+ bytes = 2;
+ integer = true;
+ signed_ = false;
+ asmType = ASM_INT;
} else if (heap == UINT32ARRAY) {
- bytes = 4; integer = true; signed_ = false; asmType = ASM_INT;
+ bytes = 4;
+ integer = true;
+ signed_ = false;
+ asmType = ASM_INT;
} else if (heap == FLOAT32ARRAY) {
- bytes = 4; integer = false; signed_ = true; asmType = ASM_FLOAT;
+ bytes = 4;
+ integer = false;
+ signed_ = true;
+ asmType = ASM_FLOAT;
} else if (heap == FLOAT64ARRAY) {
- bytes = 8; integer = false; signed_ = true; asmType = ASM_DOUBLE;
+ bytes = 8;
+ integer = false;
+ signed_ = true;
+ asmType = ASM_DOUBLE;
} else {
abort_on("invalid view import", heap);
}
@@ -1071,21 +1178,45 @@ void Asm2WasmBuilder::processAsm(Ref ast) {
assert(constructor->isString());
IString viewName = constructor->getIString();
if (viewName == Int8Array) {
- bytes = 1; integer = true; signed_ = true; asmType = ASM_INT;
+ bytes = 1;
+ integer = true;
+ signed_ = true;
+ asmType = ASM_INT;
} else if (viewName == Int16Array) {
- bytes = 2; integer = true; signed_ = true; asmType = ASM_INT;
+ bytes = 2;
+ integer = true;
+ signed_ = true;
+ asmType = ASM_INT;
} else if (viewName == Int32Array) {
- bytes = 4; integer = true; signed_ = true; asmType = ASM_INT;
+ bytes = 4;
+ integer = true;
+ signed_ = true;
+ asmType = ASM_INT;
} else if (viewName == UInt8Array) {
- bytes = 1; integer = true; signed_ = false; asmType = ASM_INT;
+ bytes = 1;
+ integer = true;
+ signed_ = false;
+ asmType = ASM_INT;
} else if (viewName == UInt16Array) {
- bytes = 2; integer = true; signed_ = false; asmType = ASM_INT;
+ bytes = 2;
+ integer = true;
+ signed_ = false;
+ asmType = ASM_INT;
} else if (viewName == UInt32Array) {
- bytes = 4; integer = true; signed_ = false; asmType = ASM_INT;
+ bytes = 4;
+ integer = true;
+ signed_ = false;
+ asmType = ASM_INT;
} else if (viewName == Float32Array) {
- bytes = 4; integer = false; signed_ = true; asmType = ASM_FLOAT;
+ bytes = 4;
+ integer = false;
+ signed_ = true;
+ asmType = ASM_FLOAT;
} else if (viewName == Float64Array) {
- bytes = 8; integer = false; signed_ = true; asmType = ASM_DOUBLE;
+ bytes = 8;
+ integer = false;
+ signed_ = true;
+ asmType = ASM_DOUBLE;
} else {
abort_on("invalid short view import", viewName);
}
@@ -1093,15 +1224,20 @@ void Asm2WasmBuilder::processAsm(Ref ast) {
assert(views.find(name) == views.end());
views.emplace(name, View(bytes, integer, signed_, asmType));
} else if (value[0] == ARRAY) {
- // function table. we merge them into one big table, so e.g. [foo, b1] , [b2, bar] => [foo, b1, b2, bar]
- // TODO: when not using aliasing function pointers, we could merge them by noticing that
- // index 0 in each table is the null func, and each other index should only have one
- // non-null func. However, that breaks down when function pointer casts are emulated.
+ // function table. we merge them into one big table, so e.g. [foo,
+ // b1] , [b2, bar] => [foo, b1, b2, bar]
+ // TODO: when not using aliasing function pointers, we could merge
+ // them by noticing that
+ // index 0 in each table is the null func, and each other index
+ // should only have one non-null func. However, that breaks down
+ // when function pointer casts are emulated.
if (wasm.table.segments.size() == 0) {
- wasm.table.segments.emplace_back(builder.makeGetGlobal(Name(TABLE_BASE), i32));
+ wasm.table.segments.emplace_back(
+ builder.makeGetGlobal(Name(TABLE_BASE), i32));
}
auto& segment = wasm.table.segments[0];
- functionTableStarts[name] = segment.data.size(); // this table starts here
+ functionTableStarts[name] =
+ segment.data.size(); // this table starts here
Ref contents = value[1];
for (unsigned k = 0; k < contents->size(); k++) {
IString curr = contents[k]->getIString();
@@ -1124,7 +1260,8 @@ void Asm2WasmBuilder::processAsm(Ref ast) {
// exporting a function
IString value = pair[1]->getIString();
if (key == Name("_emscripten_replace_memory")) {
- // asm.js memory growth provides this special non-asm function, which we don't need (we use grow_memory)
+ // asm.js memory growth provides this special non-asm function,
+ // which we don't need (we use grow_memory)
assert(!wasm.getFunctionOrNull(value));
continue;
} else if (key == UDIVMODDI4) {
@@ -1133,7 +1270,8 @@ void Asm2WasmBuilder::processAsm(Ref ast) {
getTempRet0 = value;
}
if (exported.count(key) > 0) {
- // asm.js allows duplicate exports, but not wasm. use the last, like asm.js
+ // asm.js allows duplicate exports, but not wasm. use the last, like
+ // asm.js
exported[key]->value = value;
} else {
auto* export_ = new Export;
@@ -1148,12 +1286,11 @@ void Asm2WasmBuilder::processAsm(Ref ast) {
assert(pair[1]->isNumber());
assert(exported.count(key) == 0);
auto value = pair[1]->getInteger();
- auto* global = builder.makeGlobal(
- key,
- i32,
- builder.makeConst(Literal(int32_t(value))),
- Builder::Immutable
- );
+ auto* global =
+ builder.makeGlobal(key,
+ i32,
+ builder.makeConst(Literal(int32_t(value))),
+ Builder::Immutable);
wasm.addGlobal(global);
auto* export_ = new Export;
export_->name = key;
@@ -1185,10 +1322,10 @@ void Asm2WasmBuilder::processAsm(Ref ast) {
if (runOptimizationPasses) {
optimizingBuilder->finish();
- // if we added any helper functions (like non-trapping i32-div, etc.), then those
- // have not been optimized (the optimizing builder has just been fed the asm.js
- // functions). Optimize those now. Typically there are very few, just do it
- // sequentially.
+ // if we added any helper functions (like non-trapping i32-div, etc.), then
+ // those have not been optimized (the optimizing builder has just been fed
+ // the asm.js functions). Optimize those now. Typically there are very few,
+ // just do it sequentially.
PassRunner passRunner(&wasm, passOptions);
passRunner.options.lowMemoryUnused = true;
passRunner.addDefaultFunctionOptimizationPasses();
@@ -1210,14 +1347,18 @@ void Asm2WasmBuilder::processAsm(Ref ast) {
IString name = import->name;
if (importedFunctionTypes.find(name) != importedFunctionTypes.end()) {
// special math builtins
- FunctionType* builtin = getBuiltinFunctionType(import->module, import->base);
+ FunctionType* builtin =
+ getBuiltinFunctionType(import->module, import->base);
if (builtin) {
import->type = builtin->name;
} else {
- import->type = ensureFunctionType(getSig(importedFunctionTypes[name].get()), &wasm)->name;
+ import->type =
+ ensureFunctionType(getSig(importedFunctionTypes[name].get()), &wasm)
+ ->name;
}
} else if (import->module != ASM2WASM) { // special-case the special module
- // never actually used, which means we don't know the function type since the usage tells us, so illegal for it to remain
+ // never actually used, which means we don't know the function type since
+ // the usage tells us, so illegal for it to remain
toErase.push_back(name);
}
});
@@ -1255,55 +1396,70 @@ void Asm2WasmBuilder::processAsm(Ref ast) {
numShown = make_unique<std::atomic<int>>();
numShown->store(0);
}
- if (numShown->load() >= MAX_SHOWN) return;
- std::cerr << why << " in call from " << getFunction()->name << " to " << calledFunc->name << " (this is likely due to undefined behavior in C, like defining a function one way and calling it in another, which is important to fix)\n";
+ if (numShown->load() >= MAX_SHOWN)
+ return;
+ std::cerr << why << " in call from " << getFunction()->name << " to "
+ << calledFunc->name
+ << " (this is likely due to undefined behavior in C, like "
+ "defining a function one way and calling it in another, "
+ "which is important to fix)\n";
(*numShown)++;
if (numShown->load() >= MAX_SHOWN) {
- std::cerr << "(" << numShown->load() << " such warnings shown; not showing any more)\n";
+ std::cerr << "(" << numShown->load()
+ << " such warnings shown; not showing any more)\n";
}
}
void visitCall(Call* curr) {
- // The call target may not exist if it is one of our special fake imports for callIndirect fixups
+ // The call target may not exist if it is one of our special fake imports
+ // for callIndirect fixups
auto* calledFunc = getModule()->getFunctionOrNull(curr->target);
if (calledFunc && !calledFunc->imported()) {
- // The result type of the function being called is now known, and can be applied.
+ // The result type of the function being called is now known, and can be
+ // applied.
auto result = calledFunc->result;
if (curr->type != result) {
curr->type = result;
}
- // Handle mismatched numbers of arguments. In clang, if a function is declared one way
- // but called in another, it inserts bitcasts to make things work. Those end up
- // working since it is "ok" to drop or add parameters in native platforms, even
- // though it's undefined behavior. We warn about it here, but tolerate it, if there is
- // a simple solution.
+ // Handle mismatched numbers of arguments. In clang, if a function is
+ // declared one way but called in another, it inserts bitcasts to make
+ // things work. Those end up working since it is "ok" to drop or add
+ // parameters in native platforms, even though it's undefined behavior.
+ // We warn about it here, but tolerate it, if there is a simple
+ // solution.
if (curr->operands.size() < calledFunc->params.size()) {
- notifyAboutWrongOperands("warning: asm2wasm adding operands", calledFunc);
+ notifyAboutWrongOperands("warning: asm2wasm adding operands",
+ calledFunc);
while (curr->operands.size() < calledFunc->params.size()) {
// Add params as necessary, with zeros.
- curr->operands.push_back(
- LiteralUtils::makeZero(calledFunc->params[curr->operands.size()], *getModule())
- );
+ curr->operands.push_back(LiteralUtils::makeZero(
+ calledFunc->params[curr->operands.size()], *getModule()));
}
}
if (curr->operands.size() > calledFunc->params.size()) {
- notifyAboutWrongOperands("warning: asm2wasm dropping operands", calledFunc);
+ notifyAboutWrongOperands("warning: asm2wasm dropping operands",
+ calledFunc);
curr->operands.resize(calledFunc->params.size());
}
- // If the types are wrong, validation will fail later anyhow, but add a warning here,
- // it may help people.
+ // If the types are wrong, validation will fail later anyhow, but add a
+ // warning here, it may help people.
for (Index i = 0; i < curr->operands.size(); i++) {
auto sent = curr->operands[i]->type;
auto expected = calledFunc->params[i];
if (sent != unreachable && sent != expected) {
- notifyAboutWrongOperands("error: asm2wasm seeing an invalid argument type at index " + std::to_string(i) + " (this will not validate)", calledFunc);
+ notifyAboutWrongOperands(
+ "error: asm2wasm seeing an invalid argument type at index " +
+ std::to_string(i) + " (this will not validate)",
+ calledFunc);
}
}
} else {
// A call to an import
- // fill things out: add extra params as needed, etc. asm tolerates ffi overloading, wasm does not
+ // fill things out: add extra params as needed, etc. asm tolerates ffi
+ // overloading, wasm does not
auto iter = parent->importedFunctionTypes.find(curr->target);
- if (iter == parent->importedFunctionTypes.end()) return; // one of our fake imports for callIndirect fixups
+ if (iter == parent->importedFunctionTypes.end())
+ return; // one of our fake imports for callIndirect fixups
auto type = iter->second.get();
for (size_t i = 0; i < type->params.size(); i++) {
if (i >= curr->operands.size()) {
@@ -1312,28 +1468,40 @@ void Asm2WasmBuilder::processAsm(Ref ast) {
val->type = val->value.type = type->params[i];
curr->operands.push_back(val);
} else if (curr->operands[i]->type != type->params[i]) {
- // if the param is used, then we have overloading here and the combined type must be f64;
- // if this is an unreachable param, then it doesn't matter.
- assert(type->params[i] == f64 || curr->operands[i]->type == unreachable);
+ // if the param is used, then we have overloading here and the
+ // combined type must be f64; if this is an unreachable param, then
+ // it doesn't matter.
+ assert(type->params[i] == f64 ||
+ curr->operands[i]->type == unreachable);
// overloaded, upgrade to f64
switch (curr->operands[i]->type) {
- case i32: curr->operands[i] = parent->builder.makeUnary(ConvertSInt32ToFloat64, curr->operands[i]); break;
- case f32: curr->operands[i] = parent->builder.makeUnary(PromoteFloat32, curr->operands[i]); break;
+ case i32:
+ curr->operands[i] = parent->builder.makeUnary(
+ ConvertSInt32ToFloat64, curr->operands[i]);
+ break;
+ case f32:
+ curr->operands[i] =
+ parent->builder.makeUnary(PromoteFloat32, curr->operands[i]);
+ break;
default: {} // f64, unreachable, etc., are all good
}
}
}
Module* wasm = getModule();
- auto importResult = wasm->getFunctionType(wasm->getFunction(curr->target)->type)->result;
+ auto importResult =
+ wasm->getFunctionType(wasm->getFunction(curr->target)->type)->result;
if (curr->type != importResult) {
auto old = curr->type;
curr->type = importResult;
if (importResult == f64) {
- // we use a JS f64 value which is the most general, and convert to it
+ // we use a JS f64 value which is the most general, and convert to
+ // it
switch (old) {
- case i32: {
- Unary* trunc = parent->builder.makeUnary(TruncSFloat64ToInt32, curr);
- replaceCurrent(makeTrappingUnary(trunc, parent->trappingFunctions));
+ case i32: {
+ Unary* trunc =
+ parent->builder.makeUnary(TruncSFloat64ToInt32, curr);
+ replaceCurrent(
+ makeTrappingUnary(trunc, parent->trappingFunctions));
break;
}
case f32: {
@@ -1341,24 +1509,27 @@ void Asm2WasmBuilder::processAsm(Ref ast) {
break;
}
case none: {
- // this function returns a value, but we are not using it, so it must be dropped.
- // autodrop will do that for us.
+ // this function returns a value, but we are not using it, so it
+ // must be dropped. autodrop will do that for us.
break;
}
- default: WASM_UNREACHABLE();
+ default:
+ WASM_UNREACHABLE();
}
} else {
assert(old == none);
- // we don't want a return value here, but the import does provide one
- // autodrop will do that for us.
+ // we don't want a return value here, but the import does provide
+ // one autodrop will do that for us.
}
}
}
}
void visitCallIndirect(CallIndirect* curr) {
- // we already call into target = something + offset, where offset is a callImport with the name of the table. replace that with the table offset
- // note that for an ftCall or mftCall, we have no asm.js mask, so have nothing to do here
+ // we already call into target = something + offset, where offset is a
+ // callImport with the name of the table. replace that with the table
+ // offset note that for an ftCall or mftCall, we have no asm.js mask, so
+ // have nothing to do here
auto* target = curr->target;
// might be a block with a fallthrough
if (auto* block = target->dynCast<Block>()) {
@@ -1367,23 +1538,34 @@ void Asm2WasmBuilder::processAsm(Ref ast) {
// the something might have been optimized out, leaving only the call
if (auto* call = target->dynCast<Call>()) {
auto tableName = call->target;
- if (parent->functionTableStarts.find(tableName) == parent->functionTableStarts.end()) return;
- curr->target = parent->builder.makeConst(Literal((int32_t)parent->functionTableStarts[tableName]));
+ if (parent->functionTableStarts.find(tableName) ==
+ parent->functionTableStarts.end())
+ return;
+ curr->target = parent->builder.makeConst(
+ Literal((int32_t)parent->functionTableStarts[tableName]));
return;
}
auto* add = target->dynCast<Binary>();
- if (!add) return;
+ if (!add)
+ return;
if (add->right->is<Call>()) {
auto* offset = add->right->cast<Call>();
auto tableName = offset->target;
- if (parent->functionTableStarts.find(tableName) == parent->functionTableStarts.end()) return;
- add->right = parent->builder.makeConst(Literal((int32_t)parent->functionTableStarts[tableName]));
+ if (parent->functionTableStarts.find(tableName) ==
+ parent->functionTableStarts.end())
+ return;
+ add->right = parent->builder.makeConst(
+ Literal((int32_t)parent->functionTableStarts[tableName]));
} else {
auto* offset = add->left->dynCast<Call>();
- if (!offset) return;
+ if (!offset)
+ return;
auto tableName = offset->target;
- if (parent->functionTableStarts.find(tableName) == parent->functionTableStarts.end()) return;
- add->left = parent->builder.makeConst(Literal((int32_t)parent->functionTableStarts[tableName]));
+ if (parent->functionTableStarts.find(tableName) ==
+ parent->functionTableStarts.end())
+ return;
+ add->left = parent->builder.makeConst(
+ Literal((int32_t)parent->functionTableStarts[tableName]));
}
}
@@ -1394,15 +1576,17 @@ void Asm2WasmBuilder::processAsm(Ref ast) {
}
};
- // apply debug info, reducing intrinsic calls into annotations on the ast nodes
- struct ApplyDebugInfo : public WalkerPass<ExpressionStackWalker<ApplyDebugInfo, UnifiedExpressionVisitor<ApplyDebugInfo>>> {
+ // apply debug info, reducing intrinsic calls into annotations on the ast
+ // nodes
+ struct ApplyDebugInfo
+ : public WalkerPass<
+ ExpressionStackWalker<ApplyDebugInfo,
+ UnifiedExpressionVisitor<ApplyDebugInfo>>> {
bool isFunctionParallel() override { return true; }
Pass* create() override { return new ApplyDebugInfo(); }
- ApplyDebugInfo() {
- name = "apply-debug-info";
- }
+ ApplyDebugInfo() { name = "apply-debug-info"; }
Call* lastDebugInfo = nullptr;
@@ -1413,30 +1597,34 @@ void Asm2WasmBuilder::processAsm(Ref ast) {
} else {
if (lastDebugInfo) {
auto& debugLocations = getFunction()->debugLocations;
- uint32_t fileIndex = lastDebugInfo->operands[0]->cast<Const>()->value.geti32();
+ uint32_t fileIndex =
+ lastDebugInfo->operands[0]->cast<Const>()->value.geti32();
assert(getModule()->debugInfoFileNames.size() > fileIndex);
- uint32_t lineNumber = lastDebugInfo->operands[1]->cast<Const>()->value.geti32();
+ uint32_t lineNumber =
+ lastDebugInfo->operands[1]->cast<Const>()->value.geti32();
// look up the stack, apply to the root expression
Index i = expressionStack.size() - 1;
while (1) {
auto* exp = expressionStack[i];
- bool parentIsStructure = i > 0 && (expressionStack[i - 1]->is<Block>() ||
- expressionStack[i - 1]->is<Loop>() ||
- expressionStack[i - 1]->is<If>());
- if (i == 0 || parentIsStructure || exp->type == none || exp->type == unreachable) {
+ bool parentIsStructure =
+ i > 0 && (expressionStack[i - 1]->is<Block>() ||
+ expressionStack[i - 1]->is<Loop>() ||
+ expressionStack[i - 1]->is<If>());
+ if (i == 0 || parentIsStructure || exp->type == none ||
+ exp->type == unreachable) {
if (debugLocations.count(exp) > 0) {
// already present, so look back up
i++;
while (i < expressionStack.size()) {
exp = expressionStack[i];
if (debugLocations.count(exp) == 0) {
- debugLocations[exp] = { fileIndex, lineNumber, 0 };
+ debugLocations[exp] = {fileIndex, lineNumber, 0};
break;
}
i++;
}
} else {
- debugLocations[exp] = { fileIndex, lineNumber, 0 };
+ debugLocations[exp] = {fileIndex, lineNumber, 0};
}
break;
}
@@ -1454,13 +1642,12 @@ void Asm2WasmBuilder::processAsm(Ref ast) {
passRunner.setDebug(true);
passRunner.setValidateGlobally(false);
}
- // finalizeCalls also does autoDrop, which is crucial for the non-optimizing case,
- // so that the output of the first pass is valid
+ // finalizeCalls also does autoDrop, which is crucial for the non-optimizing
+ // case, so that the output of the first pass is valid
passRunner.add<FinalizeCalls>(this);
- passRunner.add(ABI::getLegalizationPass(
- legalizeJavaScriptFFI ? ABI::LegalizationLevel::Full
- : ABI::LegalizationLevel::Minimal
- ));
+ passRunner.add(ABI::getLegalizationPass(legalizeJavaScriptFFI
+ ? ABI::LegalizationLevel::Full
+ : ABI::LegalizationLevel::Minimal));
if (runOptimizationPasses) {
// autodrop can add some garbage
passRunner.add("vacuum");
@@ -1478,7 +1665,9 @@ void Asm2WasmBuilder::processAsm(Ref ast) {
}
if (preprocessor.debugInfo) {
passRunner.add<ApplyDebugInfo>();
- passRunner.add("vacuum"); // FIXME maybe just remove the nops that were debuginfo nodes, if not optimizing?
+ // FIXME maybe just remove the nops that were debuginfo nodes, if not
+ // optimizing?
+ passRunner.add("vacuum");
}
if (runOptimizationPasses) {
// do final global optimizations after all function work is done
@@ -1493,14 +1682,18 @@ void Asm2WasmBuilder::processAsm(Ref ast) {
}
if (udivmoddi4.is() && getTempRet0.is()) {
- // generate a wasm-optimized __udivmoddi4 method, which we can do much more efficiently in wasm
- // we can only do this if we know getTempRet0 as well since we use it to figure out which minified global is tempRet0
- // (getTempRet0 might be an import, if this is a shared module, so we can't optimize that case)
+ // generate a wasm-optimized __udivmoddi4 method, which we can do much more
+ // efficiently in wasm we can only do this if we know getTempRet0 as well
+ // since we use it to figure out which minified global is tempRet0
+ // (getTempRet0 might be an import, if this is a shared module, so we can't
+ // optimize that case)
Name tempRet0;
{
Expression* curr = wasm.getFunction(getTempRet0)->body;
- if (curr->is<Block>()) curr = curr->cast<Block>()->list.back();
- if (curr->is<Return>()) curr = curr->cast<Return>()->value;
+ if (curr->is<Block>())
+ curr = curr->cast<Block>()->list.back();
+ if (curr->is<Return>())
+ curr = curr->cast<Return>()->value;
auto* get = curr->cast<GetGlobal>();
tempRet0 = get->name;
}
@@ -1510,47 +1703,35 @@ void Asm2WasmBuilder::processAsm(Ref ast) {
auto* func = wasm.getFunction(udivmoddi4);
assert(!func->type.is());
Builder::clearLocals(func);
- Index xl = Builder::addParam(func, "xl", i32),
- xh = Builder::addParam(func, "xh", i32),
- yl = Builder::addParam(func, "yl", i32),
- yh = Builder::addParam(func, "yh", i32),
- r = Builder::addParam(func, "r", i32),
+ Index xl = Builder::addParam(func, "xl", i32),
+ xh = Builder::addParam(func, "xh", i32),
+ yl = Builder::addParam(func, "yl", i32),
+ yh = Builder::addParam(func, "yh", i32),
+ r = Builder::addParam(func, "r", i32),
x64 = Builder::addVar(func, "x64", i64),
y64 = Builder::addVar(func, "y64", i64);
auto* body = allocator.alloc<Block>();
- body->list.push_back(builder.makeSetLocal(x64, I64Utilities::recreateI64(builder, xl, xh)));
- body->list.push_back(builder.makeSetLocal(y64, I64Utilities::recreateI64(builder, yl, yh)));
body->list.push_back(
- builder.makeIf(
- builder.makeGetLocal(r, i32),
- builder.makeStore(
- 8, 0, 8,
- builder.makeGetLocal(r, i32),
- builder.makeBinary(
- RemUInt64,
- builder.makeGetLocal(x64, i64),
- builder.makeGetLocal(y64, i64)
- ),
- i64
- )
- )
- );
+ builder.makeSetLocal(x64, I64Utilities::recreateI64(builder, xl, xh)));
body->list.push_back(
- builder.makeSetLocal(
- x64,
- builder.makeBinary(
- DivUInt64,
- builder.makeGetLocal(x64, i64),
- builder.makeGetLocal(y64, i64)
- )
- )
- );
+ builder.makeSetLocal(y64, I64Utilities::recreateI64(builder, yl, yh)));
+ body->list.push_back(builder.makeIf(
+ builder.makeGetLocal(r, i32),
+ builder.makeStore(8,
+ 0,
+ 8,
+ builder.makeGetLocal(r, i32),
+ builder.makeBinary(RemUInt64,
+ builder.makeGetLocal(x64, i64),
+ builder.makeGetLocal(y64, i64)),
+ i64)));
body->list.push_back(
- builder.makeSetGlobal(
- tempRet0,
- I64Utilities::getI64High(builder, x64)
- )
- );
+ builder.makeSetLocal(x64,
+ builder.makeBinary(DivUInt64,
+ builder.makeGetLocal(x64, i64),
+ builder.makeGetLocal(y64, i64))));
+ body->list.push_back(
+ builder.makeSetGlobal(tempRet0, I64Utilities::getI64High(builder, x64)));
body->list.push_back(I64Utilities::getI64Low(builder, x64));
body->finalize();
func->body = body;
@@ -1581,7 +1762,7 @@ Function* Asm2WasmBuilder::processFunction(Ref ast) {
IStringSet functionVariables; // params or vars
- IString parentLabel; // set in LABEL, then read in WHILE/DO/SWITCH
+ IString parentLabel; // set in LABEL, then read in WHILE/DO/SWITCH
std::vector<IString> breakStack; // where a break will go
std::vector<IString> continueStack; // where a continue will go
@@ -1591,7 +1772,8 @@ Function* Asm2WasmBuilder::processFunction(Ref ast) {
Ref curr = body[i];
auto* assign = curr->asAssignName();
IString name = assign->target();
- AsmType asmType = detectType(assign->value(), nullptr, false, Math_fround, wasmOnly);
+ AsmType asmType =
+ detectType(assign->value(), nullptr, false, Math_fround, wasmOnly);
Builder::addParam(function, name, asmToWasmType(asmType));
functionVariables.insert(name);
asmData.addParam(name, asmType);
@@ -1602,7 +1784,8 @@ Function* Asm2WasmBuilder::processFunction(Ref ast) {
for (unsigned j = 0; j < curr[1]->size(); j++) {
Ref pair = curr[1][j];
IString name = pair[0]->getIString();
- AsmType asmType = detectType(pair[1], nullptr, true, Math_fround, wasmOnly);
+ AsmType asmType =
+ detectType(pair[1], nullptr, true, Math_fround, wasmOnly);
Builder::addVar(function, name, asmToWasmType(asmType));
functionVariables.insert(name);
asmData.addVar(name, asmType);
@@ -1612,7 +1795,8 @@ Function* Asm2WasmBuilder::processFunction(Ref ast) {
bool addedI32Temp = false;
auto ensureI32Temp = [&]() {
- if (addedI32Temp) return;
+ if (addedI32Temp)
+ return;
addedI32Temp = true;
Builder::addVar(function, I32_TEMP, i32);
functionVariables.insert(I32_TEMP);
@@ -1621,12 +1805,13 @@ Function* Asm2WasmBuilder::processFunction(Ref ast) {
bool seenReturn = false; // function->result is updated if we see a return
// processors
- std::function<Expression* (Ref, unsigned)> processStatements;
- std::function<Expression* (Ref, unsigned)> processUnshifted;
- std::function<Expression* (Ref, unsigned)> processIgnoringShift;
+ std::function<Expression*(Ref, unsigned)> processStatements;
+ std::function<Expression*(Ref, unsigned)> processUnshifted;
+ std::function<Expression*(Ref, unsigned)> processIgnoringShift;
- std::function<Expression* (Ref)> process = [&](Ref ast) -> Expression* {
- AstStackHelper astStackHelper(ast); // TODO: only create one when we need it?
+ std::function<Expression*(Ref)> process = [&](Ref ast) -> Expression* {
+ AstStackHelper astStackHelper(
+ ast); // TODO: only create one when we need it?
if (ast->isString()) {
IString name = ast->getIString();
if (functionVariables.has(name)) {
@@ -1637,7 +1822,7 @@ Function* Asm2WasmBuilder::processFunction(Ref ast) {
return ret;
}
if (name == DEBUGGER) {
- Call *call = allocator.alloc<Call>();
+ Call* call = allocator.alloc<Call>();
call->target = DEBUGGER;
call->type = none;
static bool addedImport = false;
@@ -1655,7 +1840,9 @@ Function* Asm2WasmBuilder::processFunction(Ref ast) {
return call;
}
// global var
- assert(mappedGlobals.find(name) != mappedGlobals.end() ? true : (std::cerr << name.str << '\n', false));
+ assert(mappedGlobals.find(name) != mappedGlobals.end()
+ ? true
+ : (std::cerr << name.str << '\n', false));
MappedGlobal& global = mappedGlobals[name];
return builder.makeGetGlobal(name, global.type);
}
@@ -1688,10 +1875,13 @@ Function* Asm2WasmBuilder::processFunction(Ref ast) {
Fatal() << "error: access of a non-existent global var " << name.str;
}
auto* ret = builder.makeSetGlobal(name, process(assign->value()));
- // global.set does not return; if our value is trivially not used, don't emit a load (if nontrivially not used, opts get it later)
+ // global.set does not return; if our value is trivially not used, don't
+ // emit a load (if nontrivially not used, opts get it later)
auto parent = astStackHelper.getParent();
- if (!parent || parent->isArray(BLOCK) || parent->isArray(IF)) return ret;
- return builder.makeSequence(ret, builder.makeGetGlobal(name, ret->value->type));
+ if (!parent || parent->isArray(BLOCK) || parent->isArray(IF))
+ return ret;
+ return builder.makeSequence(
+ ret, builder.makeGetGlobal(name, ret->value->type));
}
if (ast->isAssign()) {
auto* assign = ast->asAssign();
@@ -1711,7 +1901,8 @@ Function* Asm2WasmBuilder::processFunction(Ref ast) {
ret->valueType = asmToWasmType(view.type);
ret->finalize();
if (ret->valueType != ret->value->type) {
- // in asm.js we have some implicit coercions that we must do explicitly here
+ // in asm.js we have some implicit coercions that we must do explicitly
+ // here
if (ret->valueType == f32 && ret->value->type == f64) {
auto conv = allocator.alloc<Unary>();
conv->op = DemoteFloat64;
@@ -1728,19 +1919,23 @@ Function* Asm2WasmBuilder::processFunction(Ref ast) {
}
IString what = ast[0]->getIString();
if (what == BINARY) {
- if ((ast[1] == OR || ast[1] == TRSHIFT) && ast[3]->isNumber() && ast[3]->getNumber() == 0) {
- auto ret = process(ast[2]); // just look through the ()|0 or ()>>>0 coercion
+ if ((ast[1] == OR || ast[1] == TRSHIFT) && ast[3]->isNumber() &&
+ ast[3]->getNumber() == 0) {
+ auto ret =
+ process(ast[2]); // just look through the ()|0 or ()>>>0 coercion
fixCallType(ret, i32);
return ret;
}
auto ret = allocator.alloc<Binary>();
ret->left = process(ast[2]);
ret->right = process(ast[3]);
- ret->op = parseAsmBinaryOp(ast[1]->getIString(), ast[2], ast[3], ret->left, ret->right);
+ ret->op = parseAsmBinaryOp(
+ ast[1]->getIString(), ast[2], ast[3], ret->left, ret->right);
ret->finalize();
if (ret->op == BinaryOp::RemSInt32 && isFloatType(ret->type)) {
- // WebAssembly does not have floating-point remainder, we have to emit a call to a special import of ours
- Call *call = allocator.alloc<Call>();
+ // WebAssembly does not have floating-point remainder, we have to emit a
+ // call to a special import of ours
+ Call* call = allocator.alloc<Call>();
call->target = F64_REM;
call->operands.push_back(ensureDouble(ret->left));
call->operands.push_back(ensureDouble(ret->right));
@@ -1784,7 +1979,8 @@ Function* Asm2WasmBuilder::processFunction(Ref ast) {
auto ret = process(ast[2]); // we are a +() coercion
if (ret->type == i32) {
auto conv = allocator.alloc<Unary>();
- conv->op = isUnsignedCoercion(ast[2]) ? ConvertUInt32ToFloat64 : ConvertSInt32ToFloat64;
+ conv->op = isUnsignedCoercion(ast[2]) ? ConvertUInt32ToFloat64
+ : ConvertSInt32ToFloat64;
conv->value = ret;
conv->type = Type::f64;
return conv;
@@ -1795,7 +1991,9 @@ Function* Asm2WasmBuilder::processFunction(Ref ast) {
fixCallType(ret, f64);
return ret;
} else if (ast[1] == MINUS) {
- if (ast[2]->isNumber() || (ast[2]->isArray(UNARY_PREFIX) && ast[2][1] == PLUS && ast[2][2]->isNumber())) {
+ if (ast[2]->isNumber() ||
+ (ast[2]->isArray(UNARY_PREFIX) && ast[2][1] == PLUS &&
+ ast[2][2]->isNumber())) {
auto ret = allocator.alloc<Const>();
ret->value = getLiteral(ast);
ret->type = ret->value.type;
@@ -1840,7 +2038,8 @@ Function* Asm2WasmBuilder::processFunction(Ref ast) {
} else { // !isSigned && !isF64
op = UnaryOp::TruncUFloat32ToInt32;
}
- return makeTrappingUnary(builder.makeUnary(op, expr), trappingFunctions);
+ return makeTrappingUnary(builder.makeUnary(op, expr),
+ trappingFunctions);
}
// no bitwise unary not, so do xor with -1
auto ret = allocator.alloc<Binary>();
@@ -1860,7 +2059,9 @@ Function* Asm2WasmBuilder::processFunction(Ref ast) {
} else if (what == IF) {
auto* condition = process(ast[1]);
auto* ifTrue = process(ast[2]);
- return builder.makeIf(truncateToInt32(condition), ifTrue, !!ast[3] ? process(ast[3]) : nullptr);
+ return builder.makeIf(truncateToInt32(condition),
+ ifTrue,
+ !!ast[3] ? process(ast[3]) : nullptr);
} else if (what == CALL) {
if (ast[1]->isString()) {
IString name = ast[1]->getIString();
@@ -1961,13 +2162,18 @@ Function* Asm2WasmBuilder::processFunction(Ref ast) {
auto ret = allocator.alloc<Unary>();
ret->value = value;
if (value->type == f32) {
- ret->op = name == Math_floor ? FloorFloat32 : name == Math_ceil ? CeilFloat32 : SqrtFloat32;
+ ret->op = name == Math_floor
+ ? FloorFloat32
+ : name == Math_ceil ? CeilFloat32 : SqrtFloat32;
ret->type = value->type;
} else if (value->type == f64) {
- ret->op = name == Math_floor ? FloorFloat64 : name == Math_ceil ? CeilFloat64 : SqrtFloat64;
+ ret->op = name == Math_floor
+ ? FloorFloat64
+ : name == Math_ceil ? CeilFloat64 : SqrtFloat64;
ret->type = value->type;
} else {
- Fatal() << "floor/sqrt/ceil only work on float/double in asm.js and wasm";
+ Fatal()
+ << "floor/sqrt/ceil only work on float/double in asm.js and wasm";
}
return ret;
}
@@ -1987,15 +2193,10 @@ Function* Asm2WasmBuilder::processFunction(Ref ast) {
ret->type = ret->left->type;
return ret;
}
- if (name == Atomics_load ||
- name == Atomics_store ||
- name == Atomics_exchange ||
- name == Atomics_compareExchange ||
- name == Atomics_add ||
- name == Atomics_sub ||
- name == Atomics_and ||
- name == Atomics_or ||
- name == Atomics_xor) {
+ if (name == Atomics_load || name == Atomics_store ||
+ name == Atomics_exchange || name == Atomics_compareExchange ||
+ name == Atomics_add || name == Atomics_sub || name == Atomics_and ||
+ name == Atomics_or || name == Atomics_xor) {
// atomic operation
Ref target = ast[2][0];
assert(target->isString());
@@ -2004,7 +2205,11 @@ Function* Asm2WasmBuilder::processFunction(Ref ast) {
View& view = views[heap];
wasm.memory.shared = true;
if (name == Atomics_load) {
- Expression* ret = builder.makeAtomicLoad(view.bytes, 0, processUnshifted(ast[2][1], view.bytes), asmToWasmType(view.type));
+ Expression* ret =
+ builder.makeAtomicLoad(view.bytes,
+ 0,
+ processUnshifted(ast[2][1], view.bytes),
+ asmToWasmType(view.type));
if (view.signed_) {
// atomic loads are unsigned; add a signing
ret = Bits::makeSignExt(ret, view.bytes, wasm);
@@ -2015,26 +2220,71 @@ Function* Asm2WasmBuilder::processFunction(Ref ast) {
auto type = asmToWasmType(view.type);
auto temp = Builder::addVar(function, type);
return builder.makeSequence(
- builder.makeAtomicStore(view.bytes, 0, processUnshifted(ast[2][1], view.bytes),
- builder.makeTeeLocal(temp, process(ast[2][2])),
- type),
- builder.makeGetLocal(temp, type)
- );
+ builder.makeAtomicStore(
+ view.bytes,
+ 0,
+ processUnshifted(ast[2][1], view.bytes),
+ builder.makeTeeLocal(temp, process(ast[2][2])),
+ type),
+ builder.makeGetLocal(temp, type));
} else if (name == Atomics_exchange) {
- return builder.makeAtomicRMW(AtomicRMWOp::Xchg, view.bytes, 0, processUnshifted(ast[2][1], view.bytes), process(ast[2][2]), asmToWasmType(view.type));
+ return builder.makeAtomicRMW(
+ AtomicRMWOp::Xchg,
+ view.bytes,
+ 0,
+ processUnshifted(ast[2][1], view.bytes),
+ process(ast[2][2]),
+ asmToWasmType(view.type));
} else if (name == Atomics_compareExchange) {
- // cmpxchg is odd in fastcomp output - we must ignore the shift, a cmpxchg of a i8 will look like compareExchange(HEAP8, ptr >> 2)
- return builder.makeAtomicCmpxchg(view.bytes, 0, processIgnoringShift(ast[2][1], view.bytes), process(ast[2][2]), process(ast[2][3]), asmToWasmType(view.type));
+ // cmpxchg is odd in fastcomp output - we must ignore the shift, a
+ // cmpxchg of a i8 will look like compareExchange(HEAP8, ptr >> 2)
+ return builder.makeAtomicCmpxchg(
+ view.bytes,
+ 0,
+ processIgnoringShift(ast[2][1], view.bytes),
+ process(ast[2][2]),
+ process(ast[2][3]),
+ asmToWasmType(view.type));
} else if (name == Atomics_add) {
- return builder.makeAtomicRMW(AtomicRMWOp::Add, view.bytes, 0, processUnshifted(ast[2][1], view.bytes), process(ast[2][2]), asmToWasmType(view.type));
+ return builder.makeAtomicRMW(
+ AtomicRMWOp::Add,
+ view.bytes,
+ 0,
+ processUnshifted(ast[2][1], view.bytes),
+ process(ast[2][2]),
+ asmToWasmType(view.type));
} else if (name == Atomics_sub) {
- return builder.makeAtomicRMW(AtomicRMWOp::Sub, view.bytes, 0, processUnshifted(ast[2][1], view.bytes), process(ast[2][2]), asmToWasmType(view.type));
+ return builder.makeAtomicRMW(
+ AtomicRMWOp::Sub,
+ view.bytes,
+ 0,
+ processUnshifted(ast[2][1], view.bytes),
+ process(ast[2][2]),
+ asmToWasmType(view.type));
} else if (name == Atomics_and) {
- return builder.makeAtomicRMW(AtomicRMWOp::And, view.bytes, 0, processUnshifted(ast[2][1], view.bytes), process(ast[2][2]), asmToWasmType(view.type));
+ return builder.makeAtomicRMW(
+ AtomicRMWOp::And,
+ view.bytes,
+ 0,
+ processUnshifted(ast[2][1], view.bytes),
+ process(ast[2][2]),
+ asmToWasmType(view.type));
} else if (name == Atomics_or) {
- return builder.makeAtomicRMW(AtomicRMWOp::Or, view.bytes, 0, processUnshifted(ast[2][1], view.bytes), process(ast[2][2]), asmToWasmType(view.type));
+ return builder.makeAtomicRMW(
+ AtomicRMWOp::Or,
+ view.bytes,
+ 0,
+ processUnshifted(ast[2][1], view.bytes),
+ process(ast[2][2]),
+ asmToWasmType(view.type));
} else if (name == Atomics_xor) {
- return builder.makeAtomicRMW(AtomicRMWOp::Xor, view.bytes, 0, processUnshifted(ast[2][1], view.bytes), process(ast[2][2]), asmToWasmType(view.type));
+ return builder.makeAtomicRMW(
+ AtomicRMWOp::Xor,
+ view.bytes,
+ 0,
+ processUnshifted(ast[2][1], view.bytes),
+ process(ast[2][2]),
+ asmToWasmType(view.type));
}
WASM_UNREACHABLE();
}
@@ -2044,118 +2294,208 @@ Function* Asm2WasmBuilder::processFunction(Ref ast) {
switch (name.str[0]) {
case 'l': {
auto align = num == 2 ? ast[2][1]->getInteger() : 0;
- if (name == LOAD1) return builder.makeLoad(1, true, 0, 1, process(ast[2][0]), i32);
- if (name == LOAD2) return builder.makeLoad(2, true, 0, indexOr(align, 2), process(ast[2][0]), i32);
- if (name == LOAD4) return builder.makeLoad(4, true, 0, indexOr(align, 4), process(ast[2][0]), i32);
- if (name == LOAD8) return builder.makeLoad(8, true, 0, indexOr(align, 8), process(ast[2][0]), i64);
- if (name == LOADF) return builder.makeLoad(4, true, 0, indexOr(align, 4), process(ast[2][0]), f32);
- if (name == LOADD) return builder.makeLoad(8, true, 0, indexOr(align, 8), process(ast[2][0]), f64);
+ if (name == LOAD1)
+ return builder.makeLoad(1, true, 0, 1, process(ast[2][0]), i32);
+ if (name == LOAD2)
+ return builder.makeLoad(
+ 2, true, 0, indexOr(align, 2), process(ast[2][0]), i32);
+ if (name == LOAD4)
+ return builder.makeLoad(
+ 4, true, 0, indexOr(align, 4), process(ast[2][0]), i32);
+ if (name == LOAD8)
+ return builder.makeLoad(
+ 8, true, 0, indexOr(align, 8), process(ast[2][0]), i64);
+ if (name == LOADF)
+ return builder.makeLoad(
+ 4, true, 0, indexOr(align, 4), process(ast[2][0]), f32);
+ if (name == LOADD)
+ return builder.makeLoad(
+ 8, true, 0, indexOr(align, 8), process(ast[2][0]), f64);
break;
}
case 's': {
auto align = num == 3 ? ast[2][2]->getInteger() : 0;
- if (name == STORE1) return builder.makeStore(1, 0, 1, process(ast[2][0]), process(ast[2][1]), i32);
- if (name == STORE2) return builder.makeStore(2, 0, indexOr(align, 2), process(ast[2][0]), process(ast[2][1]), i32);
- if (name == STORE4) return builder.makeStore(4, 0, indexOr(align, 4), process(ast[2][0]), process(ast[2][1]), i32);
- if (name == STORE8) return builder.makeStore(8, 0, indexOr(align, 8), process(ast[2][0]), process(ast[2][1]), i64);
+ if (name == STORE1)
+ return builder.makeStore(
+ 1, 0, 1, process(ast[2][0]), process(ast[2][1]), i32);
+ if (name == STORE2)
+ return builder.makeStore(2,
+ 0,
+ indexOr(align, 2),
+ process(ast[2][0]),
+ process(ast[2][1]),
+ i32);
+ if (name == STORE4)
+ return builder.makeStore(4,
+ 0,
+ indexOr(align, 4),
+ process(ast[2][0]),
+ process(ast[2][1]),
+ i32);
+ if (name == STORE8)
+ return builder.makeStore(8,
+ 0,
+ indexOr(align, 8),
+ process(ast[2][0]),
+ process(ast[2][1]),
+ i64);
if (name == STOREF) {
auto* value = process(ast[2][1]);
if (value->type == f64) {
- // asm.js allows storing a double to HEAPF32, we must cast here
+ // asm.js allows storing a double to HEAPF32, we must cast
+ // here
value = builder.makeUnary(DemoteFloat64, value);
}
- return builder.makeStore(4, 0, indexOr(align, 4), process(ast[2][0]), value, f32);
+ return builder.makeStore(
+ 4, 0, indexOr(align, 4), process(ast[2][0]), value, f32);
}
- if (name == STORED) return builder.makeStore(8, 0, indexOr(align, 8), process(ast[2][0]), process(ast[2][1]), f64);
+ if (name == STORED)
+ return builder.makeStore(8,
+ 0,
+ indexOr(align, 8),
+ process(ast[2][0]),
+ process(ast[2][1]),
+ f64);
break;
}
case 'i': {
if (num == 1) {
auto* value = process(ast[2][0]);
if (name == I64) {
- // no-op "coercion" / "cast", although we also tolerate i64(0) for constants that fit in i32
+ // no-op "coercion" / "cast", although we also tolerate i64(0)
+ // for constants that fit in i32
if (value->type == i32) {
- return builder.makeConst(Literal(int64_t(value->cast<Const>()->value.geti32())));
+ return builder.makeConst(
+ Literal(int64_t(value->cast<Const>()->value.geti32())));
} else {
fixCallType(value, i64);
return value;
}
}
- if (name == I32_CTTZ) return builder.makeUnary(UnaryOp::CtzInt32, value);
- if (name == I32_CTPOP) return builder.makeUnary(UnaryOp::PopcntInt32, value);
- if (name == I32_BC2F) return builder.makeUnary(UnaryOp::ReinterpretInt32, value);
- if (name == I32_BC2I) return builder.makeUnary(UnaryOp::ReinterpretFloat32, value);
-
- if (name == I64_TRUNC) return builder.makeUnary(UnaryOp::WrapInt64, value);
- if (name == I64_SEXT) return builder.makeUnary(UnaryOp::ExtendSInt32, value);
- if (name == I64_ZEXT) return builder.makeUnary(UnaryOp::ExtendUInt32, value);
- if (name == I64_S2F) return builder.makeUnary(UnaryOp::ConvertSInt64ToFloat32, value);
- if (name == I64_S2D) return builder.makeUnary(UnaryOp::ConvertSInt64ToFloat64, value);
- if (name == I64_U2F) return builder.makeUnary(UnaryOp::ConvertUInt64ToFloat32, value);
- if (name == I64_U2D) return builder.makeUnary(UnaryOp::ConvertUInt64ToFloat64, value);
+ if (name == I32_CTTZ)
+ return builder.makeUnary(UnaryOp::CtzInt32, value);
+ if (name == I32_CTPOP)
+ return builder.makeUnary(UnaryOp::PopcntInt32, value);
+ if (name == I32_BC2F)
+ return builder.makeUnary(UnaryOp::ReinterpretInt32, value);
+ if (name == I32_BC2I)
+ return builder.makeUnary(UnaryOp::ReinterpretFloat32, value);
+
+ if (name == I64_TRUNC)
+ return builder.makeUnary(UnaryOp::WrapInt64, value);
+ if (name == I64_SEXT)
+ return builder.makeUnary(UnaryOp::ExtendSInt32, value);
+ if (name == I64_ZEXT)
+ return builder.makeUnary(UnaryOp::ExtendUInt32, value);
+ if (name == I64_S2F)
+ return builder.makeUnary(UnaryOp::ConvertSInt64ToFloat32,
+ value);
+ if (name == I64_S2D)
+ return builder.makeUnary(UnaryOp::ConvertSInt64ToFloat64,
+ value);
+ if (name == I64_U2F)
+ return builder.makeUnary(UnaryOp::ConvertUInt64ToFloat32,
+ value);
+ if (name == I64_U2D)
+ return builder.makeUnary(UnaryOp::ConvertUInt64ToFloat64,
+ value);
if (name == I64_F2S) {
- Unary* conv = builder.makeUnary(UnaryOp::TruncSFloat32ToInt64, value);
+ Unary* conv =
+ builder.makeUnary(UnaryOp::TruncSFloat32ToInt64, value);
return makeTrappingUnary(conv, trappingFunctions);
}
if (name == I64_D2S) {
- Unary* conv = builder.makeUnary(UnaryOp::TruncSFloat64ToInt64, value);
+ Unary* conv =
+ builder.makeUnary(UnaryOp::TruncSFloat64ToInt64, value);
return makeTrappingUnary(conv, trappingFunctions);
}
if (name == I64_F2U) {
- Unary* conv = builder.makeUnary(UnaryOp::TruncUFloat32ToInt64, value);
+ Unary* conv =
+ builder.makeUnary(UnaryOp::TruncUFloat32ToInt64, value);
return makeTrappingUnary(conv, trappingFunctions);
}
if (name == I64_D2U) {
- Unary* conv = builder.makeUnary(UnaryOp::TruncUFloat64ToInt64, value);
+ Unary* conv =
+ builder.makeUnary(UnaryOp::TruncUFloat64ToInt64, value);
return makeTrappingUnary(conv, trappingFunctions);
}
- if (name == I64_BC2D) return builder.makeUnary(UnaryOp::ReinterpretInt64, value);
- if (name == I64_BC2I) return builder.makeUnary(UnaryOp::ReinterpretFloat64, value);
- if (name == I64_CTTZ) return builder.makeUnary(UnaryOp::CtzInt64, value);
- if (name == I64_CTLZ) return builder.makeUnary(UnaryOp::ClzInt64, value);
- if (name == I64_CTPOP) return builder.makeUnary(UnaryOp::PopcntInt64, value);
- if (name == I64_ATOMICS_LOAD) return builder.makeAtomicLoad(8, 0, value, i64);
+ if (name == I64_BC2D)
+ return builder.makeUnary(UnaryOp::ReinterpretInt64, value);
+ if (name == I64_BC2I)
+ return builder.makeUnary(UnaryOp::ReinterpretFloat64, value);
+ if (name == I64_CTTZ)
+ return builder.makeUnary(UnaryOp::CtzInt64, value);
+ if (name == I64_CTLZ)
+ return builder.makeUnary(UnaryOp::ClzInt64, value);
+ if (name == I64_CTPOP)
+ return builder.makeUnary(UnaryOp::PopcntInt64, value);
+ if (name == I64_ATOMICS_LOAD)
+ return builder.makeAtomicLoad(8, 0, value, i64);
} else if (num == 2) { // 2 params,binary
- if (name == I64_CONST) return builder.makeConst(getLiteral(ast));
+ if (name == I64_CONST)
+ return builder.makeConst(getLiteral(ast));
auto* left = process(ast[2][0]);
auto* right = process(ast[2][1]);
// maths
- if (name == I64_ADD) return builder.makeBinary(BinaryOp::AddInt64, left, right);
- if (name == I64_SUB) return builder.makeBinary(BinaryOp::SubInt64, left, right);
- if (name == I64_MUL) return builder.makeBinary(BinaryOp::MulInt64, left, right);
+ if (name == I64_ADD)
+ return builder.makeBinary(BinaryOp::AddInt64, left, right);
+ if (name == I64_SUB)
+ return builder.makeBinary(BinaryOp::SubInt64, left, right);
+ if (name == I64_MUL)
+ return builder.makeBinary(BinaryOp::MulInt64, left, right);
if (name == I64_UDIV) {
- Binary* div = builder.makeBinary(BinaryOp::DivUInt64, left, right);
+ Binary* div =
+ builder.makeBinary(BinaryOp::DivUInt64, left, right);
return makeTrappingBinary(div, trappingFunctions);
}
if (name == I64_SDIV) {
- Binary* div = builder.makeBinary(BinaryOp::DivSInt64, left, right);
+ Binary* div =
+ builder.makeBinary(BinaryOp::DivSInt64, left, right);
return makeTrappingBinary(div, trappingFunctions);
}
if (name == I64_UREM) {
- Binary* rem = builder.makeBinary(BinaryOp::RemUInt64, left, right);
+ Binary* rem =
+ builder.makeBinary(BinaryOp::RemUInt64, left, right);
return makeTrappingBinary(rem, trappingFunctions);
}
if (name == I64_SREM) {
- Binary* rem = builder.makeBinary(BinaryOp::RemSInt64, left, right);
+ Binary* rem =
+ builder.makeBinary(BinaryOp::RemSInt64, left, right);
return makeTrappingBinary(rem, trappingFunctions);
}
- if (name == I64_AND) return builder.makeBinary(BinaryOp::AndInt64, left, right);
- if (name == I64_OR) return builder.makeBinary(BinaryOp::OrInt64, left, right);
- if (name == I64_XOR) return builder.makeBinary(BinaryOp::XorInt64, left, right);
- if (name == I64_SHL) return builder.makeBinary(BinaryOp::ShlInt64, left, right);
- if (name == I64_ASHR) return builder.makeBinary(BinaryOp::ShrSInt64, left, right);
- if (name == I64_LSHR) return builder.makeBinary(BinaryOp::ShrUInt64, left, right);
+ if (name == I64_AND)
+ return builder.makeBinary(BinaryOp::AndInt64, left, right);
+ if (name == I64_OR)
+ return builder.makeBinary(BinaryOp::OrInt64, left, right);
+ if (name == I64_XOR)
+ return builder.makeBinary(BinaryOp::XorInt64, left, right);
+ if (name == I64_SHL)
+ return builder.makeBinary(BinaryOp::ShlInt64, left, right);
+ if (name == I64_ASHR)
+ return builder.makeBinary(BinaryOp::ShrSInt64, left, right);
+ if (name == I64_LSHR)
+ return builder.makeBinary(BinaryOp::ShrUInt64, left, right);
// comps
- if (name == I64_EQ) return builder.makeBinary(BinaryOp::EqInt64, left, right);
- if (name == I64_NE) return builder.makeBinary(BinaryOp::NeInt64, left, right);
- if (name == I64_ULE) return builder.makeBinary(BinaryOp::LeUInt64, left, right);
- if (name == I64_SLE) return builder.makeBinary(BinaryOp::LeSInt64, left, right);
- if (name == I64_UGE) return builder.makeBinary(BinaryOp::GeUInt64, left, right);
- if (name == I64_SGE) return builder.makeBinary(BinaryOp::GeSInt64, left, right);
- if (name == I64_ULT) return builder.makeBinary(BinaryOp::LtUInt64, left, right);
- if (name == I64_SLT) return builder.makeBinary(BinaryOp::LtSInt64, left, right);
- if (name == I64_UGT) return builder.makeBinary(BinaryOp::GtUInt64, left, right);
- if (name == I64_SGT) return builder.makeBinary(BinaryOp::GtSInt64, left, right);
+ if (name == I64_EQ)
+ return builder.makeBinary(BinaryOp::EqInt64, left, right);
+ if (name == I64_NE)
+ return builder.makeBinary(BinaryOp::NeInt64, left, right);
+ if (name == I64_ULE)
+ return builder.makeBinary(BinaryOp::LeUInt64, left, right);
+ if (name == I64_SLE)
+ return builder.makeBinary(BinaryOp::LeSInt64, left, right);
+ if (name == I64_UGE)
+ return builder.makeBinary(BinaryOp::GeUInt64, left, right);
+ if (name == I64_SGE)
+ return builder.makeBinary(BinaryOp::GeSInt64, left, right);
+ if (name == I64_ULT)
+ return builder.makeBinary(BinaryOp::LtUInt64, left, right);
+ if (name == I64_SLT)
+ return builder.makeBinary(BinaryOp::LtSInt64, left, right);
+ if (name == I64_UGT)
+ return builder.makeBinary(BinaryOp::GtUInt64, left, right);
+ if (name == I64_SGT)
+ return builder.makeBinary(BinaryOp::GtSInt64, left, right);
// atomics
if (name == I64_ATOMICS_STORE) {
wasm.memory.shared = true;
@@ -2163,47 +2503,64 @@ Function* Asm2WasmBuilder::processFunction(Ref ast) {
}
if (name == I64_ATOMICS_ADD) {
wasm.memory.shared = true;
- return builder.makeAtomicRMW(AtomicRMWOp::Add, 8, 0, left, right, i64);
+ return builder.makeAtomicRMW(
+ AtomicRMWOp::Add, 8, 0, left, right, i64);
}
if (name == I64_ATOMICS_SUB) {
wasm.memory.shared = true;
- return builder.makeAtomicRMW(AtomicRMWOp::Sub, 8, 0, left, right, i64);
+ return builder.makeAtomicRMW(
+ AtomicRMWOp::Sub, 8, 0, left, right, i64);
}
if (name == I64_ATOMICS_AND) {
wasm.memory.shared = true;
- return builder.makeAtomicRMW(AtomicRMWOp::And, 8, 0, left, right, i64);
+ return builder.makeAtomicRMW(
+ AtomicRMWOp::And, 8, 0, left, right, i64);
}
if (name == I64_ATOMICS_OR) {
wasm.memory.shared = true;
- return builder.makeAtomicRMW(AtomicRMWOp::Or, 8, 0, left, right, i64);
+ return builder.makeAtomicRMW(
+ AtomicRMWOp::Or, 8, 0, left, right, i64);
}
if (name == I64_ATOMICS_XOR) {
wasm.memory.shared = true;
- return builder.makeAtomicRMW(AtomicRMWOp::Xor, 8, 0, left, right, i64);
+ return builder.makeAtomicRMW(
+ AtomicRMWOp::Xor, 8, 0, left, right, i64);
}
if (name == I64_ATOMICS_EXCHANGE) {
wasm.memory.shared = true;
- return builder.makeAtomicRMW(AtomicRMWOp::Xchg, 8, 0, left, right, i64);
+ return builder.makeAtomicRMW(
+ AtomicRMWOp::Xchg, 8, 0, left, right, i64);
}
} else if (num == 3) {
if (name == I64_ATOMICS_COMPAREEXCHANGE) {
wasm.memory.shared = true;
- return builder.makeAtomicCmpxchg(8, 0, process(ast[2][0]), process(ast[2][1]), process(ast[2][2]), i64);
+ return builder.makeAtomicCmpxchg(8,
+ 0,
+ process(ast[2][0]),
+ process(ast[2][1]),
+ process(ast[2][2]),
+ i64);
}
}
break;
}
case 'f': {
- if (name == F32_COPYSIGN) return builder.makeBinary(BinaryOp::CopySignFloat32, process(ast[2][0]), process(ast[2][1]));
- if (name == F64_COPYSIGN) return builder.makeBinary(BinaryOp::CopySignFloat64, process(ast[2][0]), process(ast[2][1]));
+ if (name == F32_COPYSIGN)
+ return builder.makeBinary(BinaryOp::CopySignFloat32,
+ process(ast[2][0]),
+ process(ast[2][1]));
+ if (name == F64_COPYSIGN)
+ return builder.makeBinary(BinaryOp::CopySignFloat64,
+ process(ast[2][0]),
+ process(ast[2][1]));
break;
}
default: {}
}
}
- // ftCall_* and mftCall_* represent function table calls, either from the outside, or
- // from the inside of the module. when compiling to wasm, we can just convert those
- // into table calls
+ // ftCall_* and mftCall_* represent function table calls, either from
+ // the outside, or from the inside of the module. when compiling to
+ // wasm, we can just convert those into table calls
if ((name.str[0] == 'f' && strncmp(name.str, FTCALL.str, 7) == 0) ||
(name.str[0] == 'm' && strncmp(name.str, MFTCALL.str, 8) == 0)) {
tableCall = true;
@@ -2234,22 +2591,26 @@ Function* Asm2WasmBuilder::processFunction(Ref ast) {
}
if (tableCall) {
auto specific = ret->dynCast<CallIndirect>();
- // note that we could also get the type from the suffix of the name, e.g., mftCall_vi
- auto* fullType = getFunctionType(astStackHelper.getParent(), specific->operands, &asmData);
+ // note that we could also get the type from the suffix of the name,
+ // e.g., mftCall_vi
+ auto* fullType = getFunctionType(
+ astStackHelper.getParent(), specific->operands, &asmData);
specific->fullType = fullType->name;
specific->type = fullType->result;
}
if (callImport) {
// apply the detected type from the parent
- // note that this may not be complete, e.g. we may see f(); but f is an
- // import which does return a value, and we use that elsewhere. finalizeCalls
- // fixes that up. what we do here is wherever a value is used, we set the right
- // value, which is enough to ensure that the wasm ast is valid for such uses.
- // this is important as we run the optimizer on functions before we get
- // to finalizeCalls (which we can only do once we've read all the functions,
- // and we optimize in parallel starting earlier).
+ // note that this may not be complete, e.g. we may see f(); but f is
+ // an import which does return a value, and we use that elsewhere.
+ // finalizeCalls fixes that up. what we do here is wherever a value is
+ // used, we set the right value, which is enough to ensure that the
+ // wasm ast is valid for such uses. this is important as we run the
+ // optimizer on functions before we get to finalizeCalls (which we can
+ // only do once we've read all the functions, and we optimize in
+ // parallel starting earlier).
auto* call = ret->cast<Call>();
- call->type = getResultTypeOfCallUsingParent(astStackHelper.getParent(), &asmData);
+ call->type = getResultTypeOfCallUsingParent(
+ astStackHelper.getParent(), &asmData);
noteImportedFunctionCall(ast, call->type, call);
}
return ret;
@@ -2257,17 +2618,26 @@ Function* Asm2WasmBuilder::processFunction(Ref ast) {
// function pointers
auto ret = allocator.alloc<CallIndirect>();
Ref target = ast[1];
- assert(target[0] == SUB && target[1]->isString() && target[2][0] == BINARY && target[2][1] == AND && target[2][3]->isNumber()); // FUNCTION_TABLE[(expr) & mask]
- ret->target = process(target[2]); // TODO: as an optimization, we could look through the mask
+ assert(target[0] == SUB && target[1]->isString() &&
+ target[2][0] == BINARY && target[2][1] == AND &&
+ target[2][3]->isNumber()); // FUNCTION_TABLE[(expr) & mask]
+ // TODO: as an optimization, we could look through the mask
+ ret->target = process(target[2]);
Ref args = ast[2];
for (unsigned i = 0; i < args->size(); i++) {
ret->operands.push_back(process(args[i]));
}
- auto* fullType = getFunctionType(astStackHelper.getParent(), ret->operands, &asmData);
+ auto* fullType =
+ getFunctionType(astStackHelper.getParent(), ret->operands, &asmData);
ret->fullType = fullType->name;
ret->type = fullType->result;
- // we don't know the table offset yet. emit target = target + callImport(tableName), which we fix up later when we know how asm function tables are layed out inside the wasm table.
- ret->target = builder.makeBinary(BinaryOp::AddInt32, ret->target, builder.makeCall(target[1]->getIString(), {}, i32));
+ // we don't know the table offset yet. emit target = target +
+ // callImport(tableName), which we fix up later when we know how asm
+ // function tables are layed out inside the wasm table.
+ ret->target =
+ builder.makeBinary(BinaryOp::AddInt32,
+ ret->target,
+ builder.makeCall(target[1]->getIString(), {}, i32));
return ret;
} else if (what == RETURN) {
Type type = !!ast[1] ? detectWasmType(ast[1], &asmData) : none;
@@ -2306,12 +2676,17 @@ Function* Asm2WasmBuilder::processFunction(Ref ast) {
} else if (what == BREAK) {
auto ret = allocator.alloc<Break>();
assert(breakStack.size() > 0);
- ret->name = !!ast[1] ? nameMapper.sourceToUnique(getBreakLabelName(ast[1]->getIString())) : breakStack.back();
+ ret->name =
+ !!ast[1]
+ ? nameMapper.sourceToUnique(getBreakLabelName(ast[1]->getIString()))
+ : breakStack.back();
return ret;
} else if (what == CONTINUE) {
auto ret = allocator.alloc<Break>();
assert(continueStack.size() > 0);
- ret->name = !!ast[1] ? nameMapper.sourceToUnique(getContinueLabelName(ast[1]->getIString())) : continueStack.back();
+ ret->name = !!ast[1] ? nameMapper.sourceToUnique(
+ getContinueLabelName(ast[1]->getIString()))
+ : continueStack.back();
return ret;
} else if (what == WHILE) {
bool forever = ast[1]->isNumber() && ast[1]->getInteger() == 1;
@@ -2333,9 +2708,9 @@ Function* Asm2WasmBuilder::processFunction(Ref ast) {
if (forever) {
ret->body = process(ast[2]);
} else {
- Break *breakOut = allocator.alloc<Break>();
+ Break* breakOut = allocator.alloc<Break>();
breakOut->name = out;
- If *condition = allocator.alloc<If>();
+ If* condition = allocator.alloc<If>();
condition->condition = builder.makeUnary(EqZInt32, process(ast[1]));
condition->ifTrue = breakOut;
condition->finalize();
@@ -2384,7 +2759,9 @@ Function* Asm2WasmBuilder::processFunction(Ref ast) {
auto block = allocator.alloc<Block>();
block->list.push_back(child);
if (isConcreteType(child->type)) {
- block->list.push_back(builder.makeNop()); // ensure a nop at the end, so the block has guaranteed none type and no values fall through
+ // ensure a nop at the end, so the block has guaranteed none type
+ // and no values fall through
+ block->list.push_back(builder.makeNop());
}
block->name = stop;
block->finalize();
@@ -2418,19 +2795,16 @@ Function* Asm2WasmBuilder::processFunction(Ref ast) {
breakStack.pop_back();
nameMapper.popLabelName(in);
nameMapper.popLabelName(out);
- Break *continuer = allocator.alloc<Break>();
+ Break* continuer = allocator.alloc<Break>();
continuer->name = in;
continuer->condition = process(ast[1]);
continuer->finalize();
- Block *block = builder.blockifyWithName(loop->body, out, continuer);
+ Block* block = builder.blockifyWithName(loop->body, out, continuer);
loop->body = block;
loop->finalize();
return loop;
} else if (what == FOR) {
- Ref finit = ast[1],
- fcond = ast[2],
- finc = ast[3],
- fbody = ast[4];
+ Ref finit = ast[1], fcond = ast[2], finc = ast[3], fbody = ast[4];
auto ret = allocator.alloc<Loop>();
IString out, in;
if (!parentLabel.isNull()) {
@@ -2446,9 +2820,9 @@ Function* Asm2WasmBuilder::processFunction(Ref ast) {
ret->name = in;
breakStack.push_back(out);
continueStack.push_back(in);
- Break *breakOut = allocator.alloc<Break>();
+ Break* breakOut = allocator.alloc<Break>();
breakOut->name = out;
- If *condition = allocator.alloc<If>();
+ If* condition = allocator.alloc<If>();
condition->condition = builder.makeUnary(EqZInt32, process(fcond));
condition->ifTrue = breakOut;
condition->finalize();
@@ -2468,7 +2842,7 @@ Function* Asm2WasmBuilder::processFunction(Ref ast) {
breakStack.pop_back();
nameMapper.popLabelName(in);
nameMapper.popLabelName(out);
- Block *outer = allocator.alloc<Block>();
+ Block* outer = allocator.alloc<Block>();
// add an outer block for the init as well
outer->list.push_back(process(finit));
outer->list.push_back(ret);
@@ -2487,36 +2861,48 @@ Function* Asm2WasmBuilder::processFunction(Ref ast) {
return ret;
} else if (what == SEQ) {
// Some (x, y) patterns can be optimized, like bitcasts,
- // (HEAP32[tempDoublePtr >> 2] = i, Math_fround(HEAPF32[tempDoublePtr >> 2])); // i32->f32
- // (HEAP32[tempDoublePtr >> 2] = i, +HEAPF32[tempDoublePtr >> 2]); // i32->f32, no fround
- // (HEAPF32[tempDoublePtr >> 2] = f, HEAP32[tempDoublePtr >> 2] | 0); // f32->i32
+ // (HEAP32[tempDoublePtr >> 2] = i,
+ // Math_fround(HEAPF32[tempDoublePtr >> 2])); // i32->f32
+ // (HEAP32[tempDoublePtr >> 2] = i,
+ // +HEAPF32[tempDoublePtr >> 2]); // i32->f32, no fround
+ // (HEAPF32[tempDoublePtr >> 2] = f,
+ // HEAP32[tempDoublePtr >> 2] | 0); // f32->i32
if (ast[1]->isAssign()) {
auto* assign = ast[1]->asAssign();
Ref target = assign->target();
- if (target->isArray(SUB) && target[1]->isString() && target[2]->isArray(BINARY) && target[2][1] == RSHIFT &&
- target[2][2]->isString() && target[2][2] == tempDoublePtr && target[2][3]->isNumber() && target[2][3]->getNumber() == 2) {
+ if (target->isArray(SUB) && target[1]->isString() &&
+ target[2]->isArray(BINARY) && target[2][1] == RSHIFT &&
+ target[2][2]->isString() && target[2][2] == tempDoublePtr &&
+ target[2][3]->isNumber() && target[2][3]->getNumber() == 2) {
// (?[tempDoublePtr >> 2] = ?, ?) so far
auto heap = target[1]->getIString();
if (views.find(heap) != views.end()) {
AsmType writeType = views[heap].type;
AsmType readType = ASM_NONE;
Ref readValue;
- if (ast[2]->isArray(BINARY) && ast[2][1] == OR && ast[2][3]->isNumber() && ast[2][3]->getNumber() == 0) {
+ if (ast[2]->isArray(BINARY) && ast[2][1] == OR &&
+ ast[2][3]->isNumber() && ast[2][3]->getNumber() == 0) {
readType = ASM_INT;
readValue = ast[2][2];
} else if (ast[2]->isArray(UNARY_PREFIX) && ast[2][1] == PLUS) {
readType = ASM_DOUBLE;
readValue = ast[2][2];
- } else if (ast[2]->isArray(CALL) && ast[2][1]->isString() && ast[2][1] == Math_fround) {
+ } else if (ast[2]->isArray(CALL) && ast[2][1]->isString() &&
+ ast[2][1] == Math_fround) {
readType = ASM_FLOAT;
readValue = ast[2][2][0];
}
if (readType != ASM_NONE) {
- if (readValue->isArray(SUB) && readValue[1]->isString() && readValue[2]->isArray(BINARY) && readValue[2][1] == RSHIFT &&
- readValue[2][2]->isString() && readValue[2][2] == tempDoublePtr && readValue[2][3]->isNumber() && readValue[2][3]->getNumber() == 2) {
+ if (readValue->isArray(SUB) && readValue[1]->isString() &&
+ readValue[2]->isArray(BINARY) && readValue[2][1] == RSHIFT &&
+ readValue[2][2]->isString() &&
+ readValue[2][2] == tempDoublePtr &&
+ readValue[2][3]->isNumber() &&
+ readValue[2][3]->getNumber() == 2) {
// pattern looks right!
Ref writtenValue = assign->value();
- if (writeType == ASM_INT && (readType == ASM_FLOAT || readType == ASM_DOUBLE)) {
+ if (writeType == ASM_INT &&
+ (readType == ASM_FLOAT || readType == ASM_DOUBLE)) {
auto conv = allocator.alloc<Unary>();
conv->op = ReinterpretInt32;
conv->value = process(writtenValue);
@@ -2574,8 +2960,10 @@ Function* Asm2WasmBuilder::processFunction(Ref ast) {
min = index;
max = index;
} else {
- if (index < min) min = index;
- if (index > max) max = index;
+ if (index < min)
+ min = index;
+ if (index > max)
+ max = index;
}
}
}
@@ -2600,32 +2988,31 @@ Function* Asm2WasmBuilder::processFunction(Ref ast) {
br->condition = offsetor;
} else {
assert(br->condition->type == i64);
- // 64-bit condition. after offsetting it must be in a reasonable range, but the offsetting itself must be 64-bit
+ // 64-bit condition. after offsetting it must be in a reasonable
+ // range, but the offsetting itself must be 64-bit
Binary* offsetor = allocator.alloc<Binary>();
offsetor->op = BinaryOp::SubInt64;
offsetor->left = br->condition;
offsetor->right = builder.makeConst(Literal(int64_t(min)));
offsetor->type = i64;
- // the switch itself can be 32-bit, as the range is in a reasonable range. so after
- // offsetting, we need to make sure there are no high bits, then we can just look
- // at the lower 32 bits
+ // the switch itself can be 32-bit, as the range is in a reasonable
+ // range. so after offsetting, we need to make sure there are no high
+ // bits, then we can just look at the lower 32 bits
auto temp = Builder::addVar(function, i64);
auto* block = builder.makeBlock();
block->list.push_back(builder.makeSetLocal(temp, offsetor));
- // if high bits, we can break to the default (we'll fill in the name later)
- breakWhenNotMatching = builder.makeBreak(Name(), nullptr,
+ // if high bits, we can break to the default (we'll fill in the name
+ // later)
+ breakWhenNotMatching = builder.makeBreak(
+ Name(),
+ nullptr,
builder.makeUnary(
UnaryOp::WrapInt64,
builder.makeBinary(BinaryOp::ShrUInt64,
- builder.makeGetLocal(temp, i64),
- builder.makeConst(Literal(int64_t(32)))
- )
- )
- );
+ builder.makeGetLocal(temp, i64),
+ builder.makeConst(Literal(int64_t(32))))));
block->list.push_back(breakWhenNotMatching);
- block->list.push_back(
- builder.makeGetLocal(temp, i64)
- );
+ block->list.push_back(builder.makeGetLocal(temp, i64));
block->finalize();
br->condition = builder.makeUnary(UnaryOp::WrapInt64, block);
}
@@ -2672,7 +3059,8 @@ Function* Asm2WasmBuilder::processFunction(Ref ast) {
breakWhenNotMatching->name = br->default_;
}
for (size_t i = 0; i < br->targets.size(); i++) {
- if (br->targets[i].isNull()) br->targets[i] = br->default_;
+ if (br->targets[i].isNull())
+ br->targets[i] = br->default_;
}
} else {
// we can't switch, make an if-chain instead of br_table
@@ -2693,16 +3081,14 @@ Function* Asm2WasmBuilder::processFunction(Ref ast) {
} else {
name = nameMapper.pushLabelName("switch-case");
auto* iff = builder.makeIf(
- builder.makeBinary(
- br->condition->type == i32 ? EqInt32 : EqInt64,
- builder.makeGetLocal(var, br->condition->type),
- builder.makeConst(getLiteral(condition))
- ),
+ builder.makeBinary(br->condition->type == i32 ? EqInt32 : EqInt64,
+ builder.makeGetLocal(var, br->condition->type),
+ builder.makeConst(getLiteral(condition))),
builder.makeBreak(name),
- chain
- );
+ chain);
chain = iff;
- if (!first) first = iff;
+ if (!first)
+ first = iff;
}
auto next = allocator.alloc<Block>();
top->name = name;
@@ -2734,13 +3120,15 @@ Function* Asm2WasmBuilder::processFunction(Ref ast) {
return (Expression*)nullptr; // avoid warning
};
- // given HEAP32[addr >> 2], we need an absolute address, and would like to remove that shift.
- // if there is a shift, we can just look through it, etc.
+ // given HEAP32[addr >> 2], we need an absolute address, and would like to
+ // remove that shift. if there is a shift, we can just look through it, etc.
processUnshifted = [&](Ref ptr, unsigned bytes) {
auto shifts = bytesToShift(bytes);
// HEAP?[addr >> ?], or HEAP8[x | 0]
- if ((ptr->isArray(BINARY) && ptr[1] == RSHIFT && ptr[3]->isNumber() && ptr[3]->getInteger() == shifts) ||
- (bytes == 1 && ptr->isArray(BINARY) && ptr[1] == OR && ptr[3]->isNumber() && ptr[3]->getInteger() == 0)) {
+ if ((ptr->isArray(BINARY) && ptr[1] == RSHIFT && ptr[3]->isNumber() &&
+ ptr[3]->getInteger() == shifts) ||
+ (bytes == 1 && ptr->isArray(BINARY) && ptr[1] == OR &&
+ ptr[3]->isNumber() && ptr[3]->getInteger() == 0)) {
return process(ptr[2]); // look through it
} else if (ptr->isNumber()) {
// constant, apply a shift (e.g. HEAP32[1] is address 4)
@@ -2755,7 +3143,8 @@ Function* Asm2WasmBuilder::processFunction(Ref ast) {
processIgnoringShift = [&](Ref ptr, unsigned bytes) {
// If there is a shift here, no matter the size look through it.
if ((ptr->isArray(BINARY) && ptr[1] == RSHIFT && ptr[3]->isNumber()) ||
- (bytes == 1 && ptr->isArray(BINARY) && ptr[1] == OR && ptr[3]->isNumber() && ptr[3]->getInteger() == 0)) {
+ (bytes == 1 && ptr->isArray(BINARY) && ptr[1] == OR &&
+ ptr[3]->isNumber() && ptr[3]->getInteger() == 0)) {
return process(ptr[2]);
}
// Otherwise do the same as processUnshifted.
@@ -2764,8 +3153,10 @@ Function* Asm2WasmBuilder::processFunction(Ref ast) {
processStatements = [&](Ref ast, unsigned from) -> Expression* {
unsigned size = ast->size() - from;
- if (size == 0) return allocator.alloc<Nop>();
- if (size == 1) return process(ast[from]);
+ if (size == 0)
+ return allocator.alloc<Nop>();
+ if (size == 1)
+ return process(ast[from]);
auto block = allocator.alloc<Block>();
for (unsigned i = from; i < ast->size(); i++) {
block->list.push_back(process(ast[i]));
diff --git a/src/asm_v_wasm.h b/src/asm_v_wasm.h
index 08416ef80..66601cf10 100644
--- a/src/asm_v_wasm.h
+++ b/src/asm_v_wasm.h
@@ -17,8 +17,8 @@
#ifndef wasm_asm_v_wasm_h
#define wasm_asm_v_wasm_h
-#include "mixed_arena.h"
#include "emscripten-optimizer/optimizer.h"
+#include "mixed_arena.h"
#include "wasm.h"
namespace wasm {
@@ -29,13 +29,14 @@ AsmType wasmToAsmType(Type type);
char getSig(Type type);
-std::string getSig(const FunctionType *type);
+std::string getSig(const FunctionType* type);
-std::string getSig(Function *func);
+std::string getSig(Function* func);
template<typename T,
- typename std::enable_if<std::is_base_of<Expression, T>::value>::type* = nullptr>
-std::string getSig(T *call) {
+ typename std::enable_if<std::is_base_of<Expression, T>::value>::type* =
+ nullptr>
+std::string getSig(T* call) {
std::string ret;
ret += getSig(call->type);
for (auto operand : call->operands) {
diff --git a/src/asmjs/asm_v_wasm.cpp b/src/asmjs/asm_v_wasm.cpp
index a0b3938fa..bbc7dabd9 100644
--- a/src/asmjs/asm_v_wasm.cpp
+++ b/src/asmjs/asm_v_wasm.cpp
@@ -17,52 +17,71 @@
#include "asm_v_wasm.h"
#include "wasm.h"
-
namespace wasm {
Type asmToWasmType(AsmType asmType) {
switch (asmType) {
- case ASM_INT: return Type::i32;
- case ASM_DOUBLE: return Type::f64;
- case ASM_FLOAT: return Type::f32;
- case ASM_INT64: return Type::i64;
- case ASM_NONE: return Type::none;
+ case ASM_INT:
+ return Type::i32;
+ case ASM_DOUBLE:
+ return Type::f64;
+ case ASM_FLOAT:
+ return Type::f32;
+ case ASM_INT64:
+ return Type::i64;
+ case ASM_NONE:
+ return Type::none;
case ASM_FLOAT32X4:
case ASM_FLOAT64X2:
case ASM_INT8X16:
case ASM_INT16X8:
- case ASM_INT32X4: return Type::v128;
+ case ASM_INT32X4:
+ return Type::v128;
}
WASM_UNREACHABLE();
}
AsmType wasmToAsmType(Type type) {
switch (type) {
- case i32: return ASM_INT;
- case f32: return ASM_FLOAT;
- case f64: return ASM_DOUBLE;
- case i64: return ASM_INT64;
- case v128: assert(false && "v128 not implemented yet");
- case none: return ASM_NONE;
- case unreachable: WASM_UNREACHABLE();
+ case i32:
+ return ASM_INT;
+ case f32:
+ return ASM_FLOAT;
+ case f64:
+ return ASM_DOUBLE;
+ case i64:
+ return ASM_INT64;
+ case v128:
+ assert(false && "v128 not implemented yet");
+ case none:
+ return ASM_NONE;
+ case unreachable:
+ WASM_UNREACHABLE();
}
WASM_UNREACHABLE();
}
char getSig(Type type) {
switch (type) {
- case i32: return 'i';
- case i64: return 'j';
- case f32: return 'f';
- case f64: return 'd';
- case v128: return 'V';
- case none: return 'v';
- case unreachable: WASM_UNREACHABLE();
+ case i32:
+ return 'i';
+ case i64:
+ return 'j';
+ case f32:
+ return 'f';
+ case f64:
+ return 'd';
+ case v128:
+ return 'V';
+ case none:
+ return 'v';
+ case unreachable:
+ WASM_UNREACHABLE();
}
WASM_UNREACHABLE();
}
-std::string getSig(const FunctionType *type) {
+std::string getSig(const FunctionType* type) {
std::string ret;
ret += getSig(type->result);
for (auto param : type->params) {
@@ -71,7 +90,7 @@ std::string getSig(const FunctionType *type) {
return ret;
}
-std::string getSig(Function *func) {
+std::string getSig(Function* func) {
std::string ret;
ret += getSig(func->result);
for (auto type : func->params) {
@@ -82,13 +101,20 @@ std::string getSig(Function *func) {
Type sigToType(char sig) {
switch (sig) {
- case 'i': return i32;
- case 'j': return i64;
- case 'f': return f32;
- case 'd': return f64;
- case 'V': return v128;
- case 'v': return none;
- default: abort();
+ case 'i':
+ return i32;
+ case 'j':
+ return i64;
+ case 'f':
+ return f32;
+ case 'd':
+ return f64;
+ case 'V':
+ return v128;
+ case 'v':
+ return none;
+ default:
+ abort();
}
}
diff --git a/src/asmjs/asmangle.cpp b/src/asmjs/asmangle.cpp
index 0453139b3..743603023 100644
--- a/src/asmjs/asmangle.cpp
+++ b/src/asmjs/asmangle.cpp
@@ -17,7 +17,6 @@
#include "asmjs/asmangle.h"
#include <assert.h>
-
namespace wasm {
std::string asmangle(std::string name) {
@@ -49,10 +48,7 @@ std::string asmangle(std::string name) {
break;
}
default: {
- if (
- !(ch >= 'a' && ch <= 'z') &&
- !(ch >= 'A' && ch <= 'Z')
- ) {
+ if (!(ch >= 'a' && ch <= 'z') && !(ch >= 'A' && ch <= 'Z')) {
name = "$" + name.substr(1);
mightBeKeyword = false;
}
@@ -79,10 +75,7 @@ std::string asmangle(std::string name) {
break;
}
default: {
- if (
- !(ch >= 'a' && ch <= 'z') &&
- !(ch >= 'A' && ch <= 'Z')
- ) {
+ if (!(ch >= 'a' && ch <= 'z') && !(ch >= 'A' && ch <= 'Z')) {
name = name.substr(0, i) + "_" + name.substr(i + 1);
mightBeKeyword = false;
}
@@ -106,59 +99,36 @@ std::string asmangle(std::string name) {
break;
}
case 'c': {
- if (
- name == "case" ||
- name == "continue" ||
- name == "catch" ||
- name == "const" ||
- name == "class"
- ) {
+ if (name == "case" || name == "continue" || name == "catch" ||
+ name == "const" || name == "class") {
goto mangleKeyword;
}
break;
}
case 'd': {
- if (
- name == "do" ||
- name == "default" ||
- name == "debugger"
- ) {
+ if (name == "do" || name == "default" || name == "debugger") {
goto mangleKeyword;
}
break;
}
case 'e': {
- if (
- name == "else" ||
- name == "enum" ||
- name == "eval" || // to be sure
- name == "export" ||
- name == "extends"
- ) {
+ if (name == "else" || name == "enum" || name == "eval" || // to be sure
+ name == "export" || name == "extends") {
goto mangleKeyword;
}
break;
}
case 'f': {
- if (
- name == "for" ||
- name == "false" ||
- name == "finally" ||
- name == "function"
- ) {
+ if (name == "for" || name == "false" || name == "finally" ||
+ name == "function") {
goto mangleKeyword;
}
break;
}
case 'i': {
- if (
- name == "if" ||
- name == "in" ||
- name == "import" ||
- name == "interface" ||
- name == "implements" ||
- name == "instanceof"
- ) {
+ if (name == "if" || name == "in" || name == "import" ||
+ name == "interface" || name == "implements" ||
+ name == "instanceof") {
goto mangleKeyword;
}
break;
@@ -170,21 +140,14 @@ std::string asmangle(std::string name) {
break;
}
case 'n': {
- if (
- name == "new" ||
- name == "null"
- ) {
+ if (name == "new" || name == "null") {
goto mangleKeyword;
}
break;
}
case 'p': {
- if (
- name == "public" ||
- name == "package" ||
- name == "private" ||
- name == "protected"
- ) {
+ if (name == "public" || name == "package" || name == "private" ||
+ name == "protected") {
goto mangleKeyword;
}
break;
@@ -196,41 +159,26 @@ std::string asmangle(std::string name) {
break;
}
case 's': {
- if (
- name == "super" ||
- name == "static" ||
- name == "switch"
- ) {
+ if (name == "super" || name == "static" || name == "switch") {
goto mangleKeyword;
}
break;
}
case 't': {
- if (
- name == "try" ||
- name == "this" ||
- name == "true" ||
- name == "throw" ||
- name == "typeof"
- ) {
+ if (name == "try" || name == "this" || name == "true" ||
+ name == "throw" || name == "typeof") {
goto mangleKeyword;
}
break;
}
case 'v': {
- if (
- name == "var" ||
- name == "void"
- ) {
+ if (name == "var" || name == "void") {
goto mangleKeyword;
}
break;
}
case 'w': {
- if (
- name == "with" ||
- name == "while"
- ) {
+ if (name == "with" || name == "while") {
goto mangleKeyword;
}
break;
@@ -241,9 +189,7 @@ std::string asmangle(std::string name) {
}
break;
}
- mangleKeyword: {
- name = name + "_";
- }
+ mangleKeyword : { name = name + "_"; }
}
}
return name;
diff --git a/src/asmjs/asmangle.h b/src/asmjs/asmangle.h
index 161101c07..f0e96317b 100644
--- a/src/asmjs/asmangle.h
+++ b/src/asmjs/asmangle.h
@@ -19,11 +19,10 @@
#include <string>
-
namespace wasm {
- // Mangles a WebAssembly name to a valid JavaScript identifier.
- std::string asmangle(std::string name);
+// Mangles a WebAssembly name to a valid JavaScript identifier.
+std::string asmangle(std::string name);
} // namespace wasm
diff --git a/src/asmjs/shared-constants.cpp b/src/asmjs/shared-constants.cpp
index ec04b63e7..f1123ba67 100644
--- a/src/asmjs/shared-constants.cpp
+++ b/src/asmjs/shared-constants.cpp
@@ -18,104 +18,104 @@
namespace wasm {
-cashew::IString GLOBAL("global"),
- NAN_("NaN"),
- INFINITY_("Infinity"),
- NAN__("nan"),
- INFINITY__("infinity"),
- TOPMOST("topmost"),
- INT8ARRAY("Int8Array"),
- INT16ARRAY("Int16Array"),
- INT32ARRAY("Int32Array"),
- UINT8ARRAY("Uint8Array"),
- UINT16ARRAY("Uint16Array"),
- UINT32ARRAY("Uint32Array"),
- FLOAT32ARRAY("Float32Array"),
- FLOAT64ARRAY("Float64Array"),
- ARRAY_BUFFER("ArrayBuffer"),
- ASM_MODULE("asmModule"),
- IMPOSSIBLE_CONTINUE("impossible-continue"),
- MATH("Math"),
- IMUL("imul"),
- CLZ32("clz32"),
- FROUND("fround"),
- ASM2WASM("asm2wasm"),
- MIN("min"),
- MAX("max"),
- F64_REM("f64-rem"),
- F64_TO_INT("f64-to-int"),
- F64_TO_UINT("f64-to-uint"),
- F64_TO_INT64("f64-to-int64"),
- F64_TO_UINT64("f64-to-uint64"),
- F32_TO_INT("f32-to-int"),
- F32_TO_UINT("f32-to-uint"),
- F32_TO_INT64("f32-to-int64"),
- F32_TO_UINT64("f32-to-uint64"),
- I32S_DIV("i32s-div"),
- I32U_DIV("i32u-div"),
- I32S_REM("i32s-rem"),
- I32U_REM("i32u-rem"),
- GLOBAL_MATH("global.Math"),
- ABS("abs"),
- FLOOR("floor"),
- CEIL("ceil"),
- SQRT("sqrt"),
- POW("pow"),
- I32_TEMP("asm2wasm_i32_temp"),
- DEBUGGER("debugger"),
- USE_ASM("use asm"),
- ALMOST_ASM("almost asm"),
- BUFFER("buffer"),
- ENV("env"),
- STACKTOP("STACKTOP"),
- STACK_MAX("STACK_MAX"),
- INSTRUMENT("instrument"),
- MATH_IMUL("Math_imul"),
- MATH_ABS("Math_abs"),
- MATH_CEIL("Math_ceil"),
- MATH_CLZ32("Math_clz32"),
- MATH_FLOOR("Math_floor"),
- MATH_TRUNC("Math_trunc"),
- MATH_SQRT("Math_sqrt"),
- MATH_MIN("Math_min"),
- MATH_MAX("Math_max"),
- WASM_CTZ32("__wasm_ctz_i32"),
- WASM_CTZ64("__wasm_ctz_i64"),
- WASM_CLZ32("__wasm_clz_i32"),
- WASM_CLZ64("__wasm_clz_i64"),
- WASM_POPCNT32("__wasm_popcnt_i32"),
- WASM_POPCNT64("__wasm_popcnt_i64"),
- WASM_ROTL32("__wasm_rotl_i32"),
- WASM_ROTL64("__wasm_rotl_i64"),
- WASM_ROTR32("__wasm_rotr_i32"),
- WASM_ROTR64("__wasm_rotr_i64"),
- WASM_GROW_MEMORY("__wasm_grow_memory"),
- WASM_CURRENT_MEMORY("__wasm_current_memory"),
- WASM_FETCH_HIGH_BITS("__wasm_fetch_high_bits"),
- INT64_TO_32_HIGH_BITS("i64toi32_i32$HIGH_BITS"),
- WASM_NEAREST_F32("__wasm_nearest_f32"),
- WASM_NEAREST_F64("__wasm_nearest_f64"),
- WASM_TRUNC_F32("__wasm_trunc_f32"),
- WASM_TRUNC_F64("__wasm_trunc_f64"),
- WASM_I64_MUL("__wasm_i64_mul"),
- WASM_I64_SDIV("__wasm_i64_sdiv"),
- WASM_I64_UDIV("__wasm_i64_udiv"),
- WASM_I64_SREM("__wasm_i64_srem"),
- WASM_I64_UREM("__wasm_i64_urem");
+cashew::IString GLOBAL("global");
+cashew::IString NAN_("NaN");
+cashew::IString INFINITY_("Infinity");
+cashew::IString NAN__("nan");
+cashew::IString INFINITY__("infinity");
+cashew::IString TOPMOST("topmost");
+cashew::IString INT8ARRAY("Int8Array");
+cashew::IString INT16ARRAY("Int16Array");
+cashew::IString INT32ARRAY("Int32Array");
+cashew::IString UINT8ARRAY("Uint8Array");
+cashew::IString UINT16ARRAY("Uint16Array");
+cashew::IString UINT32ARRAY("Uint32Array");
+cashew::IString FLOAT32ARRAY("Float32Array");
+cashew::IString FLOAT64ARRAY("Float64Array");
+cashew::IString ARRAY_BUFFER("ArrayBuffer");
+cashew::IString ASM_MODULE("asmModule");
+cashew::IString IMPOSSIBLE_CONTINUE("impossible-continue");
+cashew::IString MATH("Math");
+cashew::IString IMUL("imul");
+cashew::IString CLZ32("clz32");
+cashew::IString FROUND("fround");
+cashew::IString ASM2WASM("asm2wasm");
+cashew::IString MIN("min");
+cashew::IString MAX("max");
+cashew::IString F64_REM("f64-rem");
+cashew::IString F64_TO_INT("f64-to-int");
+cashew::IString F64_TO_UINT("f64-to-uint");
+cashew::IString F64_TO_INT64("f64-to-int64");
+cashew::IString F64_TO_UINT64("f64-to-uint64");
+cashew::IString F32_TO_INT("f32-to-int");
+cashew::IString F32_TO_UINT("f32-to-uint");
+cashew::IString F32_TO_INT64("f32-to-int64");
+cashew::IString F32_TO_UINT64("f32-to-uint64");
+cashew::IString I32S_DIV("i32s-div");
+cashew::IString I32U_DIV("i32u-div");
+cashew::IString I32S_REM("i32s-rem");
+cashew::IString I32U_REM("i32u-rem");
+cashew::IString GLOBAL_MATH("global.Math");
+cashew::IString ABS("abs");
+cashew::IString FLOOR("floor");
+cashew::IString CEIL("ceil");
+cashew::IString SQRT("sqrt");
+cashew::IString POW("pow");
+cashew::IString I32_TEMP("asm2wasm_i32_temp");
+cashew::IString DEBUGGER("debugger");
+cashew::IString USE_ASM("use asm");
+cashew::IString ALMOST_ASM("almost asm");
+cashew::IString BUFFER("buffer");
+cashew::IString ENV("env");
+cashew::IString STACKTOP("STACKTOP");
+cashew::IString STACK_MAX("STACK_MAX");
+cashew::IString INSTRUMENT("instrument");
+cashew::IString MATH_IMUL("Math_imul");
+cashew::IString MATH_ABS("Math_abs");
+cashew::IString MATH_CEIL("Math_ceil");
+cashew::IString MATH_CLZ32("Math_clz32");
+cashew::IString MATH_FLOOR("Math_floor");
+cashew::IString MATH_TRUNC("Math_trunc");
+cashew::IString MATH_SQRT("Math_sqrt");
+cashew::IString MATH_MIN("Math_min");
+cashew::IString MATH_MAX("Math_max");
+cashew::IString WASM_CTZ32("__wasm_ctz_i32");
+cashew::IString WASM_CTZ64("__wasm_ctz_i64");
+cashew::IString WASM_CLZ32("__wasm_clz_i32");
+cashew::IString WASM_CLZ64("__wasm_clz_i64");
+cashew::IString WASM_POPCNT32("__wasm_popcnt_i32");
+cashew::IString WASM_POPCNT64("__wasm_popcnt_i64");
+cashew::IString WASM_ROTL32("__wasm_rotl_i32");
+cashew::IString WASM_ROTL64("__wasm_rotl_i64");
+cashew::IString WASM_ROTR32("__wasm_rotr_i32");
+cashew::IString WASM_ROTR64("__wasm_rotr_i64");
+cashew::IString WASM_GROW_MEMORY("__wasm_grow_memory");
+cashew::IString WASM_CURRENT_MEMORY("__wasm_current_memory");
+cashew::IString WASM_FETCH_HIGH_BITS("__wasm_fetch_high_bits");
+cashew::IString INT64_TO_32_HIGH_BITS("i64toi32_i32$HIGH_BITS");
+cashew::IString WASM_NEAREST_F32("__wasm_nearest_f32");
+cashew::IString WASM_NEAREST_F64("__wasm_nearest_f64");
+cashew::IString WASM_TRUNC_F32("__wasm_trunc_f32");
+cashew::IString WASM_TRUNC_F64("__wasm_trunc_f64");
+cashew::IString WASM_I64_MUL("__wasm_i64_mul");
+cashew::IString WASM_I64_SDIV("__wasm_i64_sdiv");
+cashew::IString WASM_I64_UDIV("__wasm_i64_udiv");
+cashew::IString WASM_I64_SREM("__wasm_i64_srem");
+cashew::IString WASM_I64_UREM("__wasm_i64_urem");
namespace ABI {
namespace wasm2js {
-cashew::IString SCRATCH_LOAD_I32("wasm2js_scratch_load_i32"),
- SCRATCH_STORE_I32("wasm2js_scratch_store_i32"),
- SCRATCH_LOAD_I64("wasm2js_scratch_load_i64"),
- SCRATCH_STORE_I64("wasm2js_scratch_store_i64"),
- SCRATCH_LOAD_F32("wasm2js_scratch_load_f32"),
- SCRATCH_STORE_F32("wasm2js_scratch_store_f32"),
- SCRATCH_LOAD_F64("wasm2js_scratch_load_f64"),
- SCRATCH_STORE_F64("wasm2js_scratch_store_f64");
+cashew::IString SCRATCH_LOAD_I32("wasm2js_scratch_load_i32");
+cashew::IString SCRATCH_STORE_I32("wasm2js_scratch_store_i32");
+cashew::IString SCRATCH_LOAD_I64("wasm2js_scratch_load_i64");
+cashew::IString SCRATCH_STORE_I64("wasm2js_scratch_store_i64");
+cashew::IString SCRATCH_LOAD_F32("wasm2js_scratch_load_f32");
+cashew::IString SCRATCH_STORE_F32("wasm2js_scratch_store_f32");
+cashew::IString SCRATCH_LOAD_F64("wasm2js_scratch_load_f64");
+cashew::IString SCRATCH_STORE_F64("wasm2js_scratch_store_f64");
} // namespace wasm2js
} // namespace ABI
-}
+} // namespace wasm
diff --git a/src/asmjs/shared-constants.h b/src/asmjs/shared-constants.h
index b1f93336b..e8d5d5693 100644
--- a/src/asmjs/shared-constants.h
+++ b/src/asmjs/shared-constants.h
@@ -21,90 +21,90 @@
namespace wasm {
-extern cashew::IString GLOBAL,
- NAN_,
- INFINITY_,
- NAN__,
- INFINITY__,
- TOPMOST,
- INT8ARRAY,
- INT16ARRAY,
- INT32ARRAY,
- UINT8ARRAY,
- UINT16ARRAY,
- UINT32ARRAY,
- FLOAT32ARRAY,
- FLOAT64ARRAY,
- ARRAY_BUFFER,
- ASM_MODULE,
- IMPOSSIBLE_CONTINUE,
- MATH,
- IMUL,
- CLZ32,
- FROUND,
- ASM2WASM,
- MIN,
- MAX,
- F64_REM,
- F64_TO_INT,
- F64_TO_UINT,
- F64_TO_INT64,
- F64_TO_UINT64,
- F32_TO_INT,
- F32_TO_UINT,
- F32_TO_INT64,
- F32_TO_UINT64,
- I32S_DIV,
- I32U_DIV,
- I32S_REM,
- I32U_REM,
- GLOBAL_MATH,
- ABS,
- FLOOR,
- CEIL,
- SQRT,
- POW,
- I32_TEMP,
- DEBUGGER,
- USE_ASM,
- ALMOST_ASM,
- BUFFER,
- ENV,
- STACKTOP,
- STACK_MAX,
- INSTRUMENT,
- MATH_IMUL,
- MATH_ABS,
- MATH_CEIL,
- MATH_CLZ32,
- MATH_FLOOR,
- MATH_TRUNC,
- MATH_SQRT,
- MATH_MIN,
- MATH_MAX,
- WASM_CTZ32,
- WASM_CTZ64,
- WASM_CLZ32,
- WASM_CLZ64,
- WASM_POPCNT32,
- WASM_POPCNT64,
- WASM_ROTL32,
- WASM_ROTL64,
- WASM_ROTR32,
- WASM_ROTR64,
- WASM_GROW_MEMORY,
- WASM_CURRENT_MEMORY,
- WASM_FETCH_HIGH_BITS,
- INT64_TO_32_HIGH_BITS,
- WASM_NEAREST_F32,
- WASM_NEAREST_F64,
- WASM_TRUNC_F32,
- WASM_TRUNC_F64,
- WASM_I64_MUL,
- WASM_I64_SDIV,
- WASM_I64_UDIV,
- WASM_I64_SREM,
- WASM_I64_UREM;
-}
+extern cashew::IString GLOBAL;
+extern cashew::IString NAN_;
+extern cashew::IString INFINITY_;
+extern cashew::IString NAN__;
+extern cashew::IString INFINITY__;
+extern cashew::IString TOPMOST;
+extern cashew::IString INT8ARRAY;
+extern cashew::IString INT16ARRAY;
+extern cashew::IString INT32ARRAY;
+extern cashew::IString UINT8ARRAY;
+extern cashew::IString UINT16ARRAY;
+extern cashew::IString UINT32ARRAY;
+extern cashew::IString FLOAT32ARRAY;
+extern cashew::IString FLOAT64ARRAY;
+extern cashew::IString ARRAY_BUFFER;
+extern cashew::IString ASM_MODULE;
+extern cashew::IString IMPOSSIBLE_CONTINUE;
+extern cashew::IString MATH;
+extern cashew::IString IMUL;
+extern cashew::IString CLZ32;
+extern cashew::IString FROUND;
+extern cashew::IString ASM2WASM;
+extern cashew::IString MIN;
+extern cashew::IString MAX;
+extern cashew::IString F64_REM;
+extern cashew::IString F64_TO_INT;
+extern cashew::IString F64_TO_UINT;
+extern cashew::IString F64_TO_INT64;
+extern cashew::IString F64_TO_UINT64;
+extern cashew::IString F32_TO_INT;
+extern cashew::IString F32_TO_UINT;
+extern cashew::IString F32_TO_INT64;
+extern cashew::IString F32_TO_UINT64;
+extern cashew::IString I32S_DIV;
+extern cashew::IString I32U_DIV;
+extern cashew::IString I32S_REM;
+extern cashew::IString I32U_REM;
+extern cashew::IString GLOBAL_MATH;
+extern cashew::IString ABS;
+extern cashew::IString FLOOR;
+extern cashew::IString CEIL;
+extern cashew::IString SQRT;
+extern cashew::IString POW;
+extern cashew::IString I32_TEMP;
+extern cashew::IString DEBUGGER;
+extern cashew::IString USE_ASM;
+extern cashew::IString ALMOST_ASM;
+extern cashew::IString BUFFER;
+extern cashew::IString ENV;
+extern cashew::IString STACKTOP;
+extern cashew::IString STACK_MAX;
+extern cashew::IString INSTRUMENT;
+extern cashew::IString MATH_IMUL;
+extern cashew::IString MATH_ABS;
+extern cashew::IString MATH_CEIL;
+extern cashew::IString MATH_CLZ32;
+extern cashew::IString MATH_FLOOR;
+extern cashew::IString MATH_TRUNC;
+extern cashew::IString MATH_SQRT;
+extern cashew::IString MATH_MIN;
+extern cashew::IString MATH_MAX;
+extern cashew::IString WASM_CTZ32;
+extern cashew::IString WASM_CTZ64;
+extern cashew::IString WASM_CLZ32;
+extern cashew::IString WASM_CLZ64;
+extern cashew::IString WASM_POPCNT32;
+extern cashew::IString WASM_POPCNT64;
+extern cashew::IString WASM_ROTL32;
+extern cashew::IString WASM_ROTL64;
+extern cashew::IString WASM_ROTR32;
+extern cashew::IString WASM_ROTR64;
+extern cashew::IString WASM_GROW_MEMORY;
+extern cashew::IString WASM_CURRENT_MEMORY;
+extern cashew::IString WASM_FETCH_HIGH_BITS;
+extern cashew::IString INT64_TO_32_HIGH_BITS;
+extern cashew::IString WASM_NEAREST_F32;
+extern cashew::IString WASM_NEAREST_F64;
+extern cashew::IString WASM_TRUNC_F32;
+extern cashew::IString WASM_TRUNC_F64;
+extern cashew::IString WASM_I64_MUL;
+extern cashew::IString WASM_I64_SDIV;
+extern cashew::IString WASM_I64_UDIV;
+extern cashew::IString WASM_I64_SREM;
+extern cashew::IString WASM_I64_UREM;
+} // namespace wasm
#endif // wasm_asmjs_shared_constants_h
diff --git a/src/binaryen-c.cpp b/src/binaryen-c.cpp
index 87dd631d3..5842e5afe 100644
--- a/src/binaryen-c.cpp
+++ b/src/binaryen-c.cpp
@@ -21,19 +21,19 @@
#include <mutex>
#include "binaryen-c.h"
+#include "cfg/Relooper.h"
+#include "ir/function-type-utils.h"
+#include "ir/utils.h"
#include "pass.h"
-#include "wasm.h"
+#include "shell-interface.h"
#include "wasm-binary.h"
#include "wasm-builder.h"
#include "wasm-interpreter.h"
#include "wasm-printing.h"
#include "wasm-s-parser.h"
#include "wasm-validator.h"
+#include "wasm.h"
#include "wasm2js.h"
-#include "cfg/Relooper.h"
-#include "ir/function-type-utils.h"
-#include "ir/utils.h"
-#include "shell-interface.h"
#ifdef __EMSCRIPTEN__
#include <emscripten.h>
@@ -43,35 +43,51 @@ using namespace wasm;
// Literal utilities
-static_assert(sizeof(BinaryenLiteral) == sizeof(Literal), "Binaryen C API literal must match wasm.h");
+static_assert(sizeof(BinaryenLiteral) == sizeof(Literal),
+ "Binaryen C API literal must match wasm.h");
BinaryenLiteral toBinaryenLiteral(Literal x) {
BinaryenLiteral ret;
ret.type = x.type;
switch (x.type) {
- case Type::i32: ret.i32 = x.geti32(); break;
- case Type::i64: ret.i64 = x.geti64(); break;
- case Type::f32: ret.i32 = x.reinterpreti32(); break;
- case Type::f64: ret.i64 = x.reinterpreti64(); break;
+ case Type::i32:
+ ret.i32 = x.geti32();
+ break;
+ case Type::i64:
+ ret.i64 = x.geti64();
+ break;
+ case Type::f32:
+ ret.i32 = x.reinterpreti32();
+ break;
+ case Type::f64:
+ ret.i64 = x.reinterpreti64();
+ break;
case Type::v128: {
memcpy(&ret.v128, x.getv128Ptr(), 16);
break;
}
case Type::none:
- case Type::unreachable: WASM_UNREACHABLE();
+ case Type::unreachable:
+ WASM_UNREACHABLE();
}
return ret;
}
Literal fromBinaryenLiteral(BinaryenLiteral x) {
switch (x.type) {
- case Type::i32: return Literal(x.i32);
- case Type::i64: return Literal(x.i64);
- case Type::f32: return Literal(x.i32).castToF32();
- case Type::f64: return Literal(x.i64).castToF64();
- case Type::v128: return Literal(x.v128);
+ case Type::i32:
+ return Literal(x.i32);
+ case Type::i64:
+ return Literal(x.i64);
+ case Type::f32:
+ return Literal(x.i32).castToF32();
+ case Type::f64:
+ return Literal(x.i64).castToF64();
+ case Type::v128:
+ return Literal(x.v128);
case Type::none:
- case Type::unreachable: WASM_UNREACHABLE();
+ case Type::unreachable:
+ WASM_UNREACHABLE();
}
WASM_UNREACHABLE();
}
@@ -84,15 +100,18 @@ static std::mutex BinaryenFunctionMutex;
static std::mutex BinaryenFunctionTypeMutex;
// Optimization options
-static PassOptions globalPassOptions = PassOptions::getWithDefaultOptimizationOptions();
+static PassOptions globalPassOptions =
+ PassOptions::getWithDefaultOptimizationOptions();
// Tracing support
static int tracing = 0;
-void traceNameOrNULL(const char* name, std::ostream &out = std::cout) {
- if (name) out << "\"" << name << "\"";
- else out << "NULL";
+void traceNameOrNULL(const char* name, std::ostream& out = std::cout) {
+ if (name)
+ out << "\"" << name << "\"";
+ else
+ out << "NULL";
}
std::map<BinaryenFunctionTypeRef, size_t> functionTypes;
@@ -115,27 +134,29 @@ std::string getTemp() {
}
template<typename T>
-void printArg(std::ostream &setup, std::ostream& out, T arg) {
+void printArg(std::ostream& setup, std::ostream& out, T arg) {
out << arg;
}
template<>
-void printArg(std::ostream &setup, std::ostream& out, BinaryenExpressionRef arg) {
+void printArg(std::ostream& setup,
+ std::ostream& out,
+ BinaryenExpressionRef arg) {
out << "expressions[" << expressions[arg] << "]";
}
struct StringLit {
const char* name;
- StringLit(const char* name) : name(name) {};
+ StringLit(const char* name) : name(name){};
};
template<>
-void printArg(std::ostream &setup, std::ostream& out, StringLit arg) {
+void printArg(std::ostream& setup, std::ostream& out, StringLit arg) {
traceNameOrNULL(arg.name, out);
}
template<>
-void printArg(std::ostream &setup, std::ostream &out, BinaryenType arg) {
+void printArg(std::ostream& setup, std::ostream& out, BinaryenType arg) {
if (arg == BinaryenTypeAuto()) {
out << "BinaryenTypeAuto()";
} else {
@@ -144,21 +165,29 @@ void printArg(std::ostream &setup, std::ostream &out, BinaryenType arg) {
}
template<>
-void printArg(std::ostream &setup, std::ostream &out, BinaryenLiteral arg) {
+void printArg(std::ostream& setup, std::ostream& out, BinaryenLiteral arg) {
switch (arg.type) {
- case Type::i32: out << "BinaryenLiteralInt32(" << arg.i32 << ")"; break;
- case Type::i64: out << "BinaryenLiteralInt64(" << arg.i64 << ")"; break;
+ case Type::i32:
+ out << "BinaryenLiteralInt32(" << arg.i32 << ")";
+ break;
+ case Type::i64:
+ out << "BinaryenLiteralInt64(" << arg.i64 << ")";
+ break;
case Type::f32:
if (std::isnan(arg.f32)) {
- out << "BinaryenLiteralFloat32(NAN)"; break;
+ out << "BinaryenLiteralFloat32(NAN)";
+ break;
} else {
- out << "BinaryenLiteralFloat32(" << arg.f32 << ")"; break;
+ out << "BinaryenLiteralFloat32(" << arg.f32 << ")";
+ break;
}
case Type::f64:
if (std::isnan(arg.f64)) {
- out << "BinaryenLiteralFloat64(NAN)"; break;
+ out << "BinaryenLiteralFloat64(NAN)";
+ break;
} else {
- out << "BinaryenLiteralFloat64(" << arg.f64 << ")"; break;
+ out << "BinaryenLiteralFloat64(" << arg.f64 << ")";
+ break;
}
case Type::v128: {
std::string array = getTemp();
@@ -174,24 +203,28 @@ void printArg(std::ostream &setup, std::ostream &out, BinaryenLiteral arg) {
break;
}
case Type::none:
- case Type::unreachable: WASM_UNREACHABLE();
+ case Type::unreachable:
+ WASM_UNREACHABLE();
}
}
template<typename T>
-void traceArgs(std::ostream &setup, std::ostream &out, T arg) {
+void traceArgs(std::ostream& setup, std::ostream& out, T arg) {
printArg(setup, out, arg);
}
-template<typename T, typename S, typename ...Ts>
-void traceArgs(std::ostream &setup, std::ostream &out, T arg, S next, Ts... rest) {
+template<typename T, typename S, typename... Ts>
+void traceArgs(
+ std::ostream& setup, std::ostream& out, T arg, S next, Ts... rest) {
printArg(setup, out, arg);
out << ", ";
traceArgs(setup, out, next, rest...);
}
-template<typename ...Ts>
-void traceExpression(BinaryenExpressionRef expr, const char* constructor, Ts... args) {
+template<typename... Ts>
+void traceExpression(BinaryenExpressionRef expr,
+ const char* constructor,
+ Ts... args) {
auto id = noteExpression(expr);
std::stringstream setup, out;
out << "expressions[" << id << "] = " << constructor << "(";
@@ -235,18 +268,30 @@ WASM_DEPRECATED BinaryenType BinaryenUndefined(void) { return uint32_t(-1); }
// Expression ids
-BinaryenExpressionId BinaryenInvalidId(void) { return Expression::Id::InvalidId; }
+BinaryenExpressionId BinaryenInvalidId(void) {
+ return Expression::Id::InvalidId;
+}
BinaryenExpressionId BinaryenBlockId(void) { return Expression::Id::BlockId; }
BinaryenExpressionId BinaryenIfId(void) { return Expression::Id::IfId; }
BinaryenExpressionId BinaryenLoopId(void) { return Expression::Id::LoopId; }
BinaryenExpressionId BinaryenBreakId(void) { return Expression::Id::BreakId; }
BinaryenExpressionId BinaryenSwitchId(void) { return Expression::Id::SwitchId; }
BinaryenExpressionId BinaryenCallId(void) { return Expression::Id::CallId; }
-BinaryenExpressionId BinaryenCallIndirectId(void) { return Expression::Id::CallIndirectId; }
-BinaryenExpressionId BinaryenGetLocalId(void) { return Expression::Id::GetLocalId; }
-BinaryenExpressionId BinaryenSetLocalId(void) { return Expression::Id::SetLocalId; }
-BinaryenExpressionId BinaryenGetGlobalId(void) { return Expression::Id::GetGlobalId; }
-BinaryenExpressionId BinaryenSetGlobalId(void) { return Expression::Id::SetGlobalId; }
+BinaryenExpressionId BinaryenCallIndirectId(void) {
+ return Expression::Id::CallIndirectId;
+}
+BinaryenExpressionId BinaryenGetLocalId(void) {
+ return Expression::Id::GetLocalId;
+}
+BinaryenExpressionId BinaryenSetLocalId(void) {
+ return Expression::Id::SetLocalId;
+}
+BinaryenExpressionId BinaryenGetGlobalId(void) {
+ return Expression::Id::GetGlobalId;
+}
+BinaryenExpressionId BinaryenSetGlobalId(void) {
+ return Expression::Id::SetGlobalId;
+}
BinaryenExpressionId BinaryenLoadId(void) { return Expression::Id::LoadId; }
BinaryenExpressionId BinaryenStoreId(void) { return Expression::Id::StoreId; }
BinaryenExpressionId BinaryenConstId(void) { return Expression::Id::ConstId; }
@@ -257,27 +302,63 @@ BinaryenExpressionId BinaryenDropId(void) { return Expression::Id::DropId; }
BinaryenExpressionId BinaryenReturnId(void) { return Expression::Id::ReturnId; }
BinaryenExpressionId BinaryenHostId(void) { return Expression::Id::HostId; }
BinaryenExpressionId BinaryenNopId(void) { return Expression::Id::NopId; }
-BinaryenExpressionId BinaryenUnreachableId(void) { return Expression::Id::UnreachableId; }
-BinaryenExpressionId BinaryenAtomicCmpxchgId(void) { return Expression::Id::AtomicCmpxchgId; }
-BinaryenExpressionId BinaryenAtomicRMWId(void) { return Expression::Id::AtomicRMWId; }
-BinaryenExpressionId BinaryenAtomicWaitId(void) { return Expression::Id::AtomicWaitId; }
-BinaryenExpressionId BinaryenAtomicNotifyId(void) { return Expression::Id::AtomicNotifyId; }
-BinaryenExpressionId BinaryenSIMDExtractId(void) { return Expression::Id::SIMDExtractId; }
-BinaryenExpressionId BinaryenSIMDReplaceId(void) { return Expression::Id::SIMDReplaceId; }
-BinaryenExpressionId BinaryenSIMDShuffleId(void) { return Expression::Id::SIMDShuffleId; }
-BinaryenExpressionId BinaryenSIMDBitselectId(void) { return Expression::Id::SIMDBitselectId; }
-BinaryenExpressionId BinaryenSIMDShiftId(void) { return Expression::Id::SIMDShiftId; }
-BinaryenExpressionId BinaryenMemoryInitId(void) { return Expression::Id::MemoryInitId; }
-BinaryenExpressionId BinaryenDataDropId(void) { return Expression::Id::DataDropId; }
-BinaryenExpressionId BinaryenMemoryCopyId(void) { return Expression::Id::MemoryCopyId; }
-BinaryenExpressionId BinaryenMemoryFillId(void) { return Expression::Id::MemoryFillId; }
+BinaryenExpressionId BinaryenUnreachableId(void) {
+ return Expression::Id::UnreachableId;
+}
+BinaryenExpressionId BinaryenAtomicCmpxchgId(void) {
+ return Expression::Id::AtomicCmpxchgId;
+}
+BinaryenExpressionId BinaryenAtomicRMWId(void) {
+ return Expression::Id::AtomicRMWId;
+}
+BinaryenExpressionId BinaryenAtomicWaitId(void) {
+ return Expression::Id::AtomicWaitId;
+}
+BinaryenExpressionId BinaryenAtomicNotifyId(void) {
+ return Expression::Id::AtomicNotifyId;
+}
+BinaryenExpressionId BinaryenSIMDExtractId(void) {
+ return Expression::Id::SIMDExtractId;
+}
+BinaryenExpressionId BinaryenSIMDReplaceId(void) {
+ return Expression::Id::SIMDReplaceId;
+}
+BinaryenExpressionId BinaryenSIMDShuffleId(void) {
+ return Expression::Id::SIMDShuffleId;
+}
+BinaryenExpressionId BinaryenSIMDBitselectId(void) {
+ return Expression::Id::SIMDBitselectId;
+}
+BinaryenExpressionId BinaryenSIMDShiftId(void) {
+ return Expression::Id::SIMDShiftId;
+}
+BinaryenExpressionId BinaryenMemoryInitId(void) {
+ return Expression::Id::MemoryInitId;
+}
+BinaryenExpressionId BinaryenDataDropId(void) {
+ return Expression::Id::DataDropId;
+}
+BinaryenExpressionId BinaryenMemoryCopyId(void) {
+ return Expression::Id::MemoryCopyId;
+}
+BinaryenExpressionId BinaryenMemoryFillId(void) {
+ return Expression::Id::MemoryFillId;
+}
// External kinds
-BinaryenExternalKind BinaryenExternalFunction(void) { return static_cast<BinaryenExternalKind>(ExternalKind::Function); }
-BinaryenExternalKind BinaryenExternalTable(void) { return static_cast<BinaryenExternalKind>(ExternalKind::Table); }
-BinaryenExternalKind BinaryenExternalMemory(void) { return static_cast<BinaryenExternalKind>(ExternalKind::Memory); }
-BinaryenExternalKind BinaryenExternalGlobal(void) { return static_cast<BinaryenExternalKind>(ExternalKind::Global); }
+BinaryenExternalKind BinaryenExternalFunction(void) {
+ return static_cast<BinaryenExternalKind>(ExternalKind::Function);
+}
+BinaryenExternalKind BinaryenExternalTable(void) {
+ return static_cast<BinaryenExternalKind>(ExternalKind::Table);
+}
+BinaryenExternalKind BinaryenExternalMemory(void) {
+ return static_cast<BinaryenExternalKind>(ExternalKind::Memory);
+}
+BinaryenExternalKind BinaryenExternalGlobal(void) {
+ return static_cast<BinaryenExternalKind>(ExternalKind::Global);
+}
// Modules
@@ -312,11 +393,17 @@ void BinaryenModuleDispose(BinaryenModuleRef module) {
// Function types
-BinaryenFunctionTypeRef BinaryenAddFunctionType(BinaryenModuleRef module, const char* name, BinaryenType result, BinaryenType* paramTypes, BinaryenIndex numParams) {
+BinaryenFunctionTypeRef BinaryenAddFunctionType(BinaryenModuleRef module,
+ const char* name,
+ BinaryenType result,
+ BinaryenType* paramTypes,
+ BinaryenIndex numParams) {
auto* wasm = (Module*)module;
auto ret = make_unique<FunctionType>();
- if (name) ret->name = name;
- else ret->name = Name::fromInt(wasm->functionTypes.size());
+ if (name)
+ ret->name = name;
+ else
+ ret->name = Name::fromInt(wasm->functionTypes.size());
ret->result = Type(result);
for (BinaryenIndex i = 0; i < numParams; i++) {
ret->params.push_back(Type(paramTypes[i]));
@@ -326,13 +413,17 @@ BinaryenFunctionTypeRef BinaryenAddFunctionType(BinaryenModuleRef module, const
std::cout << " {\n";
std::cout << " BinaryenType paramTypes[] = { ";
for (BinaryenIndex i = 0; i < numParams; i++) {
- if (i > 0) std::cout << ", ";
+ if (i > 0)
+ std::cout << ", ";
std::cout << paramTypes[i];
}
- if (numParams == 0) std::cout << "0"; // ensure the array is not empty, otherwise a compiler error on VS
+ if (numParams == 0)
+ // ensure the array is not empty, otherwise a compiler error on VS
+ std::cout << "0";
std::cout << " };\n";
size_t id = functionTypes.size();
- std::cout << " functionTypes[" << id << "] = BinaryenAddFunctionType(the_module, ";
+ std::cout << " functionTypes[" << id
+ << "] = BinaryenAddFunctionType(the_module, ";
functionTypes[ret.get()] = id;
traceNameOrNULL(name);
std::cout << ", " << result << ", paramTypes, " << numParams << ");\n";
@@ -362,13 +453,27 @@ void BinaryenRemoveFunctionType(BinaryenModuleRef module, const char* name) {
}
}
-BinaryenLiteral BinaryenLiteralInt32(int32_t x) { return toBinaryenLiteral(Literal(x)); }
-BinaryenLiteral BinaryenLiteralInt64(int64_t x) { return toBinaryenLiteral(Literal(x)); }
-BinaryenLiteral BinaryenLiteralFloat32(float x) { return toBinaryenLiteral(Literal(x)); }
-BinaryenLiteral BinaryenLiteralFloat64(double x) { return toBinaryenLiteral(Literal(x)); }
-BinaryenLiteral BinaryenLiteralVec128(const uint8_t x[16]) { return toBinaryenLiteral(Literal(x)); }
-BinaryenLiteral BinaryenLiteralFloat32Bits(int32_t x) { return toBinaryenLiteral(Literal(x).castToF32()); }
-BinaryenLiteral BinaryenLiteralFloat64Bits(int64_t x) { return toBinaryenLiteral(Literal(x).castToF64()); }
+BinaryenLiteral BinaryenLiteralInt32(int32_t x) {
+ return toBinaryenLiteral(Literal(x));
+}
+BinaryenLiteral BinaryenLiteralInt64(int64_t x) {
+ return toBinaryenLiteral(Literal(x));
+}
+BinaryenLiteral BinaryenLiteralFloat32(float x) {
+ return toBinaryenLiteral(Literal(x));
+}
+BinaryenLiteral BinaryenLiteralFloat64(double x) {
+ return toBinaryenLiteral(Literal(x));
+}
+BinaryenLiteral BinaryenLiteralVec128(const uint8_t x[16]) {
+ return toBinaryenLiteral(Literal(x));
+}
+BinaryenLiteral BinaryenLiteralFloat32Bits(int32_t x) {
+ return toBinaryenLiteral(Literal(x).castToF32());
+}
+BinaryenLiteral BinaryenLiteralFloat64Bits(int64_t x) {
+ return toBinaryenLiteral(Literal(x).castToF64());
+}
// Expressions
@@ -412,14 +517,30 @@ BinaryenOp BinaryenExtendS16Int32(void) { return ExtendS16Int32; }
BinaryenOp BinaryenExtendS8Int64(void) { return ExtendS8Int64; }
BinaryenOp BinaryenExtendS16Int64(void) { return ExtendS16Int64; }
BinaryenOp BinaryenExtendS32Int64(void) { return ExtendS32Int64; }
-BinaryenOp BinaryenConvertSInt32ToFloat32(void) { return ConvertSInt32ToFloat32; }
-BinaryenOp BinaryenConvertSInt32ToFloat64(void) { return ConvertSInt32ToFloat64; }
-BinaryenOp BinaryenConvertUInt32ToFloat32(void) { return ConvertUInt32ToFloat32; }
-BinaryenOp BinaryenConvertUInt32ToFloat64(void) { return ConvertUInt32ToFloat64; }
-BinaryenOp BinaryenConvertSInt64ToFloat32(void) { return ConvertSInt64ToFloat32; }
-BinaryenOp BinaryenConvertSInt64ToFloat64(void) { return ConvertSInt64ToFloat64; }
-BinaryenOp BinaryenConvertUInt64ToFloat32(void) { return ConvertUInt64ToFloat32; }
-BinaryenOp BinaryenConvertUInt64ToFloat64(void) { return ConvertUInt64ToFloat64; }
+BinaryenOp BinaryenConvertSInt32ToFloat32(void) {
+ return ConvertSInt32ToFloat32;
+}
+BinaryenOp BinaryenConvertSInt32ToFloat64(void) {
+ return ConvertSInt32ToFloat64;
+}
+BinaryenOp BinaryenConvertUInt32ToFloat32(void) {
+ return ConvertUInt32ToFloat32;
+}
+BinaryenOp BinaryenConvertUInt32ToFloat64(void) {
+ return ConvertUInt32ToFloat64;
+}
+BinaryenOp BinaryenConvertSInt64ToFloat32(void) {
+ return ConvertSInt64ToFloat32;
+}
+BinaryenOp BinaryenConvertSInt64ToFloat64(void) {
+ return ConvertSInt64ToFloat64;
+}
+BinaryenOp BinaryenConvertUInt64ToFloat32(void) {
+ return ConvertUInt64ToFloat32;
+}
+BinaryenOp BinaryenConvertUInt64ToFloat64(void) {
+ return ConvertUInt64ToFloat64;
+}
BinaryenOp BinaryenPromoteFloat32(void) { return PromoteFloat32; }
BinaryenOp BinaryenDemoteFloat64(void) { return DemoteFloat64; }
BinaryenOp BinaryenReinterpretInt32(void) { return ReinterpretInt32; }
@@ -508,14 +629,30 @@ BinaryenOp BinaryenAtomicRMWAnd(void) { return AtomicRMWOp::And; }
BinaryenOp BinaryenAtomicRMWOr(void) { return AtomicRMWOp::Or; }
BinaryenOp BinaryenAtomicRMWXor(void) { return AtomicRMWOp::Xor; }
BinaryenOp BinaryenAtomicRMWXchg(void) { return AtomicRMWOp::Xchg; }
-BinaryenOp BinaryenTruncSatSFloat32ToInt32(void) { return TruncSatSFloat32ToInt32; }
-BinaryenOp BinaryenTruncSatSFloat32ToInt64(void) { return TruncSatSFloat32ToInt64; }
-BinaryenOp BinaryenTruncSatUFloat32ToInt32(void) { return TruncSatUFloat32ToInt32; }
-BinaryenOp BinaryenTruncSatUFloat32ToInt64(void) { return TruncSatUFloat32ToInt64; }
-BinaryenOp BinaryenTruncSatSFloat64ToInt32(void) { return TruncSatSFloat64ToInt32; }
-BinaryenOp BinaryenTruncSatSFloat64ToInt64(void) { return TruncSatSFloat64ToInt64; }
-BinaryenOp BinaryenTruncSatUFloat64ToInt32(void) { return TruncSatUFloat64ToInt32; }
-BinaryenOp BinaryenTruncSatUFloat64ToInt64(void) { return TruncSatUFloat64ToInt64; }
+BinaryenOp BinaryenTruncSatSFloat32ToInt32(void) {
+ return TruncSatSFloat32ToInt32;
+}
+BinaryenOp BinaryenTruncSatSFloat32ToInt64(void) {
+ return TruncSatSFloat32ToInt64;
+}
+BinaryenOp BinaryenTruncSatUFloat32ToInt32(void) {
+ return TruncSatUFloat32ToInt32;
+}
+BinaryenOp BinaryenTruncSatUFloat32ToInt64(void) {
+ return TruncSatUFloat32ToInt64;
+}
+BinaryenOp BinaryenTruncSatSFloat64ToInt32(void) {
+ return TruncSatSFloat64ToInt32;
+}
+BinaryenOp BinaryenTruncSatSFloat64ToInt64(void) {
+ return TruncSatSFloat64ToInt64;
+}
+BinaryenOp BinaryenTruncSatUFloat64ToInt32(void) {
+ return TruncSatUFloat64ToInt32;
+}
+BinaryenOp BinaryenTruncSatUFloat64ToInt64(void) {
+ return TruncSatUFloat64ToInt64;
+}
BinaryenOp BinaryenSplatVecI8x16(void) { return SplatVecI8x16; }
BinaryenOp BinaryenExtractLaneSVecI8x16(void) { return ExtractLaneSVecI8x16; }
BinaryenOp BinaryenExtractLaneUVecI8x16(void) { return ExtractLaneUVecI8x16; }
@@ -643,41 +780,72 @@ BinaryenOp BinaryenMulVecF64x2(void) { return MulVecF64x2; }
BinaryenOp BinaryenDivVecF64x2(void) { return DivVecF64x2; }
BinaryenOp BinaryenMinVecF64x2(void) { return MinVecF64x2; }
BinaryenOp BinaryenMaxVecF64x2(void) { return MaxVecF64x2; }
-BinaryenOp BinaryenTruncSatSVecF32x4ToVecI32x4(void) { return TruncSatSVecF32x4ToVecI32x4; }
-BinaryenOp BinaryenTruncSatUVecF32x4ToVecI32x4(void) { return TruncSatUVecF32x4ToVecI32x4; }
-BinaryenOp BinaryenTruncSatSVecF64x2ToVecI64x2(void) { return TruncSatSVecF64x2ToVecI64x2; }
-BinaryenOp BinaryenTruncSatUVecF64x2ToVecI64x2(void) { return TruncSatUVecF64x2ToVecI64x2; }
-BinaryenOp BinaryenConvertSVecI32x4ToVecF32x4(void) { return ConvertSVecI32x4ToVecF32x4; }
-BinaryenOp BinaryenConvertUVecI32x4ToVecF32x4(void) { return ConvertUVecI32x4ToVecF32x4; }
-BinaryenOp BinaryenConvertSVecI64x2ToVecF64x2(void) { return ConvertSVecI64x2ToVecF64x2; }
-BinaryenOp BinaryenConvertUVecI64x2ToVecF64x2(void) { return ConvertUVecI64x2ToVecF64x2; }
-
-BinaryenExpressionRef BinaryenBlock(BinaryenModuleRef module, const char* name, BinaryenExpressionRef* children, BinaryenIndex numChildren, BinaryenType type) {
+BinaryenOp BinaryenTruncSatSVecF32x4ToVecI32x4(void) {
+ return TruncSatSVecF32x4ToVecI32x4;
+}
+BinaryenOp BinaryenTruncSatUVecF32x4ToVecI32x4(void) {
+ return TruncSatUVecF32x4ToVecI32x4;
+}
+BinaryenOp BinaryenTruncSatSVecF64x2ToVecI64x2(void) {
+ return TruncSatSVecF64x2ToVecI64x2;
+}
+BinaryenOp BinaryenTruncSatUVecF64x2ToVecI64x2(void) {
+ return TruncSatUVecF64x2ToVecI64x2;
+}
+BinaryenOp BinaryenConvertSVecI32x4ToVecF32x4(void) {
+ return ConvertSVecI32x4ToVecF32x4;
+}
+BinaryenOp BinaryenConvertUVecI32x4ToVecF32x4(void) {
+ return ConvertUVecI32x4ToVecF32x4;
+}
+BinaryenOp BinaryenConvertSVecI64x2ToVecF64x2(void) {
+ return ConvertSVecI64x2ToVecF64x2;
+}
+BinaryenOp BinaryenConvertUVecI64x2ToVecF64x2(void) {
+ return ConvertUVecI64x2ToVecF64x2;
+}
+
+BinaryenExpressionRef BinaryenBlock(BinaryenModuleRef module,
+ const char* name,
+ BinaryenExpressionRef* children,
+ BinaryenIndex numChildren,
+ BinaryenType type) {
auto* ret = ((Module*)module)->allocator.alloc<Block>();
- if (name) ret->name = name;
+ if (name)
+ ret->name = name;
for (BinaryenIndex i = 0; i < numChildren; i++) {
ret->list.push_back((Expression*)children[i]);
}
- if (type != BinaryenTypeAuto()) ret->finalize(Type(type));
- else ret->finalize();
+ if (type != BinaryenTypeAuto())
+ ret->finalize(Type(type));
+ else
+ ret->finalize();
if (tracing) {
std::cout << " {\n";
std::cout << " BinaryenExpressionRef children[] = { ";
for (BinaryenIndex i = 0; i < numChildren; i++) {
- if (i > 0) std::cout << ", ";
- if (i % 6 == 5) std::cout << "\n "; // don't create hugely long lines
+ if (i > 0)
+ std::cout << ", ";
+ if (i % 6 == 5)
+ std::cout << "\n "; // don't create hugely long lines
std::cout << "expressions[" << expressions[children[i]] << "]";
}
- if (numChildren == 0) std::cout << "0"; // ensure the array is not empty, otherwise a compiler error on VS
+ if (numChildren == 0)
+ // ensure the array is not empty, otherwise a compiler error on VS
+ std::cout << "0";
std::cout << " };\n ";
- traceExpression(ret, "BinaryenBlock", StringLit(name), "children", numChildren, type);
+ traceExpression(
+ ret, "BinaryenBlock", StringLit(name), "children", numChildren, type);
std::cout << " }\n";
}
return static_cast<Expression*>(ret);
}
-BinaryenExpressionRef BinaryenIf(BinaryenModuleRef module, BinaryenExpressionRef condition, BinaryenExpressionRef ifTrue, BinaryenExpressionRef ifFalse) {
+BinaryenExpressionRef BinaryenIf(BinaryenModuleRef module,
+ BinaryenExpressionRef condition,
+ BinaryenExpressionRef ifTrue,
+ BinaryenExpressionRef ifFalse) {
auto* ret = ((Module*)module)->allocator.alloc<If>();
ret->condition = (Expression*)condition;
ret->ifTrue = (Expression*)ifTrue;
@@ -690,8 +858,11 @@ BinaryenExpressionRef BinaryenIf(BinaryenModuleRef module, BinaryenExpressionRef
return static_cast<Expression*>(ret);
}
-BinaryenExpressionRef BinaryenLoop(BinaryenModuleRef module, const char* name, BinaryenExpressionRef body) {
- auto* ret = Builder(*((Module*)module)).makeLoop(name ? Name(name) : Name(), (Expression*)body);
+BinaryenExpressionRef BinaryenLoop(BinaryenModuleRef module,
+ const char* name,
+ BinaryenExpressionRef body) {
+ auto* ret = Builder(*((Module*)module))
+ .makeLoop(name ? Name(name) : Name(), (Expression*)body);
if (tracing) {
traceExpression(ret, "BinaryenLoop", StringLit(name), body);
@@ -699,8 +870,12 @@ BinaryenExpressionRef BinaryenLoop(BinaryenModuleRef module, const char* name, B
return static_cast<Expression*>(ret);
}
-BinaryenExpressionRef BinaryenBreak(BinaryenModuleRef module, const char* name, BinaryenExpressionRef condition, BinaryenExpressionRef value) {
- auto* ret = Builder(*((Module*)module)).makeBreak(name, (Expression*)value, (Expression*)condition);
+BinaryenExpressionRef BinaryenBreak(BinaryenModuleRef module,
+ const char* name,
+ BinaryenExpressionRef condition,
+ BinaryenExpressionRef value) {
+ auto* ret = Builder(*((Module*)module))
+ .makeBreak(name, (Expression*)value, (Expression*)condition);
if (tracing) {
traceExpression(ret, "BinaryenBreak", StringLit(name), condition, value);
@@ -708,19 +883,33 @@ BinaryenExpressionRef BinaryenBreak(BinaryenModuleRef module, const char* name,
return static_cast<Expression*>(ret);
}
-BinaryenExpressionRef BinaryenSwitch(BinaryenModuleRef module, const char** names, BinaryenIndex numNames, const char* defaultName, BinaryenExpressionRef condition, BinaryenExpressionRef value) {
+BinaryenExpressionRef BinaryenSwitch(BinaryenModuleRef module,
+ const char** names,
+ BinaryenIndex numNames,
+ const char* defaultName,
+ BinaryenExpressionRef condition,
+ BinaryenExpressionRef value) {
auto* ret = ((Module*)module)->allocator.alloc<Switch>();
if (tracing) {
std::cout << " {\n";
std::cout << " const char* names[] = { ";
for (BinaryenIndex i = 0; i < numNames; i++) {
- if (i > 0) std::cout << ", ";
+ if (i > 0)
+ std::cout << ", ";
std::cout << "\"" << names[i] << "\"";
}
- if (numNames == 0) std::cout << "0"; // ensure the array is not empty, otherwise a compiler error on VS
+ if (numNames == 0)
+ std::cout << "0"; // ensure the array is not empty, otherwise a compiler
+ // error on VS
std::cout << " };\n ";
- traceExpression(ret, "BinaryenSwitch", "names", numNames, StringLit(defaultName), condition, value);
+ traceExpression(ret,
+ "BinaryenSwitch",
+ "names",
+ numNames,
+ StringLit(defaultName),
+ condition,
+ value);
std::cout << " }\n";
}
@@ -733,19 +922,31 @@ BinaryenExpressionRef BinaryenSwitch(BinaryenModuleRef module, const char** name
ret->finalize();
return static_cast<Expression*>(ret);
}
-BinaryenExpressionRef BinaryenCall(BinaryenModuleRef module, const char* target, BinaryenExpressionRef* operands, BinaryenIndex numOperands, BinaryenType returnType) {
+BinaryenExpressionRef BinaryenCall(BinaryenModuleRef module,
+ const char* target,
+ BinaryenExpressionRef* operands,
+ BinaryenIndex numOperands,
+ BinaryenType returnType) {
auto* ret = ((Module*)module)->allocator.alloc<Call>();
if (tracing) {
std::cout << " {\n";
std::cout << " BinaryenExpressionRef operands[] = { ";
for (BinaryenIndex i = 0; i < numOperands; i++) {
- if (i > 0) std::cout << ", ";
+ if (i > 0)
+ std::cout << ", ";
std::cout << "expressions[" << expressions[operands[i]] << "]";
}
- if (numOperands == 0) std::cout << "0"; // ensure the array is not empty, otherwise a compiler error on VS
+ if (numOperands == 0)
+ // ensure the array is not empty, otherwise a compiler error on VS
+ std::cout << "0";
std::cout << " };\n ";
- traceExpression(ret, "BinaryenCall", StringLit(target), "operands", numOperands, returnType);
+ traceExpression(ret,
+ "BinaryenCall",
+ StringLit(target),
+ "operands",
+ numOperands,
+ returnType);
std::cout << " }\n";
}
@@ -757,7 +958,11 @@ BinaryenExpressionRef BinaryenCall(BinaryenModuleRef module, const char* target,
ret->finalize();
return static_cast<Expression*>(ret);
}
-BinaryenExpressionRef BinaryenCallIndirect(BinaryenModuleRef module, BinaryenExpressionRef target, BinaryenExpressionRef* operands, BinaryenIndex numOperands, const char* type) {
+BinaryenExpressionRef BinaryenCallIndirect(BinaryenModuleRef module,
+ BinaryenExpressionRef target,
+ BinaryenExpressionRef* operands,
+ BinaryenIndex numOperands,
+ const char* type) {
auto* wasm = (Module*)module;
auto* ret = wasm->allocator.alloc<CallIndirect>();
@@ -765,12 +970,20 @@ BinaryenExpressionRef BinaryenCallIndirect(BinaryenModuleRef module, BinaryenExp
std::cout << " {\n";
std::cout << " BinaryenExpressionRef operands[] = { ";
for (BinaryenIndex i = 0; i < numOperands; i++) {
- if (i > 0) std::cout << ", ";
+ if (i > 0)
+ std::cout << ", ";
std::cout << "expressions[" << expressions[operands[i]] << "]";
}
- if (numOperands == 0) std::cout << "0"; // ensure the array is not empty, otherwise a compiler error on VS
+ if (numOperands == 0)
+ // ensure the array is not empty, otherwise a compiler error on VS
+ std::cout << "0";
std::cout << " };\n ";
- traceExpression(ret, "BinaryenCallIndirect", target, "operands", numOperands, StringLit(type));
+ traceExpression(ret,
+ "BinaryenCallIndirect",
+ target,
+ "operands",
+ numOperands,
+ StringLit(type));
std::cout << " }\n";
}
@@ -783,7 +996,9 @@ BinaryenExpressionRef BinaryenCallIndirect(BinaryenModuleRef module, BinaryenExp
ret->finalize();
return static_cast<Expression*>(ret);
}
-BinaryenExpressionRef BinaryenGetLocal(BinaryenModuleRef module, BinaryenIndex index, BinaryenType type) {
+BinaryenExpressionRef BinaryenGetLocal(BinaryenModuleRef module,
+ BinaryenIndex index,
+ BinaryenType type) {
auto* ret = ((Module*)module)->allocator.alloc<GetLocal>();
if (tracing) {
@@ -795,7 +1010,9 @@ BinaryenExpressionRef BinaryenGetLocal(BinaryenModuleRef module, BinaryenIndex i
ret->finalize();
return static_cast<Expression*>(ret);
}
-BinaryenExpressionRef BinaryenSetLocal(BinaryenModuleRef module, BinaryenIndex index, BinaryenExpressionRef value) {
+BinaryenExpressionRef BinaryenSetLocal(BinaryenModuleRef module,
+ BinaryenIndex index,
+ BinaryenExpressionRef value) {
auto* ret = ((Module*)module)->allocator.alloc<SetLocal>();
if (tracing) {
@@ -808,7 +1025,9 @@ BinaryenExpressionRef BinaryenSetLocal(BinaryenModuleRef module, BinaryenIndex i
ret->finalize();
return static_cast<Expression*>(ret);
}
-BinaryenExpressionRef BinaryenTeeLocal(BinaryenModuleRef module, BinaryenIndex index, BinaryenExpressionRef value) {
+BinaryenExpressionRef BinaryenTeeLocal(BinaryenModuleRef module,
+ BinaryenIndex index,
+ BinaryenExpressionRef value) {
auto* ret = ((Module*)module)->allocator.alloc<SetLocal>();
if (tracing) {
@@ -821,7 +1040,9 @@ BinaryenExpressionRef BinaryenTeeLocal(BinaryenModuleRef module, BinaryenIndex i
ret->finalize();
return static_cast<Expression*>(ret);
}
-BinaryenExpressionRef BinaryenGetGlobal(BinaryenModuleRef module, const char* name, BinaryenType type) {
+BinaryenExpressionRef BinaryenGetGlobal(BinaryenModuleRef module,
+ const char* name,
+ BinaryenType type) {
auto* ret = ((Module*)module)->allocator.alloc<GetGlobal>();
if (tracing) {
@@ -833,7 +1054,9 @@ BinaryenExpressionRef BinaryenGetGlobal(BinaryenModuleRef module, const char* na
ret->finalize();
return static_cast<Expression*>(ret);
}
-BinaryenExpressionRef BinaryenSetGlobal(BinaryenModuleRef module, const char* name, BinaryenExpressionRef value) {
+BinaryenExpressionRef BinaryenSetGlobal(BinaryenModuleRef module,
+ const char* name,
+ BinaryenExpressionRef value) {
auto* ret = ((Module*)module)->allocator.alloc<SetGlobal>();
if (tracing) {
@@ -845,11 +1068,18 @@ BinaryenExpressionRef BinaryenSetGlobal(BinaryenModuleRef module, const char* na
ret->finalize();
return static_cast<Expression*>(ret);
}
-BinaryenExpressionRef BinaryenLoad(BinaryenModuleRef module, uint32_t bytes, int8_t signed_, uint32_t offset, uint32_t align, BinaryenType type, BinaryenExpressionRef ptr) {
+BinaryenExpressionRef BinaryenLoad(BinaryenModuleRef module,
+ uint32_t bytes,
+ int8_t signed_,
+ uint32_t offset,
+ uint32_t align,
+ BinaryenType type,
+ BinaryenExpressionRef ptr) {
auto* ret = ((Module*)module)->allocator.alloc<Load>();
if (tracing) {
- traceExpression(ret, "BinaryenLoad", bytes, int(signed_), offset, align, type, ptr);
+ traceExpression(
+ ret, "BinaryenLoad", bytes, int(signed_), offset, align, type, ptr);
}
ret->isAtomic = false;
ret->bytes = bytes;
@@ -861,11 +1091,18 @@ BinaryenExpressionRef BinaryenLoad(BinaryenModuleRef module, uint32_t bytes, int
ret->finalize();
return static_cast<Expression*>(ret);
}
-BinaryenExpressionRef BinaryenStore(BinaryenModuleRef module, uint32_t bytes, uint32_t offset, uint32_t align, BinaryenExpressionRef ptr, BinaryenExpressionRef value, BinaryenType type) {
+BinaryenExpressionRef BinaryenStore(BinaryenModuleRef module,
+ uint32_t bytes,
+ uint32_t offset,
+ uint32_t align,
+ BinaryenExpressionRef ptr,
+ BinaryenExpressionRef value,
+ BinaryenType type) {
auto* ret = ((Module*)module)->allocator.alloc<Store>();
if (tracing) {
- traceExpression(ret, "BinaryenStore", bytes, offset, align, ptr, value, type);
+ traceExpression(
+ ret, "BinaryenStore", bytes, offset, align, ptr, value, type);
}
ret->isAtomic = false;
ret->bytes = bytes;
@@ -877,15 +1114,19 @@ BinaryenExpressionRef BinaryenStore(BinaryenModuleRef module, uint32_t bytes, ui
ret->finalize();
return static_cast<Expression*>(ret);
}
-BinaryenExpressionRef BinaryenConst(BinaryenModuleRef module, BinaryenLiteral value) {
+BinaryenExpressionRef BinaryenConst(BinaryenModuleRef module,
+ BinaryenLiteral value) {
auto* ret = Builder(*((Module*)module)).makeConst(fromBinaryenLiteral(value));
if (tracing) {
traceExpression(ret, "BinaryenConst", value);
}
return static_cast<Expression*>(ret);
}
-BinaryenExpressionRef BinaryenUnary(BinaryenModuleRef module, BinaryenOp op, BinaryenExpressionRef value) {
- auto* ret = Builder(*((Module*)module)).makeUnary(UnaryOp(op), (Expression*)value);
+BinaryenExpressionRef BinaryenUnary(BinaryenModuleRef module,
+ BinaryenOp op,
+ BinaryenExpressionRef value) {
+ auto* ret =
+ Builder(*((Module*)module)).makeUnary(UnaryOp(op), (Expression*)value);
if (tracing) {
traceExpression(ret, "BinaryenUnary", op, value);
@@ -893,8 +1134,13 @@ BinaryenExpressionRef BinaryenUnary(BinaryenModuleRef module, BinaryenOp op, Bin
return static_cast<Expression*>(ret);
}
-BinaryenExpressionRef BinaryenBinary(BinaryenModuleRef module, BinaryenOp op, BinaryenExpressionRef left, BinaryenExpressionRef right) {
- auto* ret = Builder(*((Module*)module)).makeBinary(BinaryOp(op), (Expression*)left, (Expression*)right);
+BinaryenExpressionRef BinaryenBinary(BinaryenModuleRef module,
+ BinaryenOp op,
+ BinaryenExpressionRef left,
+ BinaryenExpressionRef right) {
+ auto* ret =
+ Builder(*((Module*)module))
+ .makeBinary(BinaryOp(op), (Expression*)left, (Expression*)right);
if (tracing) {
traceExpression(ret, "BinaryenBinary", op, left, right);
@@ -902,7 +1148,10 @@ BinaryenExpressionRef BinaryenBinary(BinaryenModuleRef module, BinaryenOp op, Bi
return static_cast<Expression*>(ret);
}
-BinaryenExpressionRef BinaryenSelect(BinaryenModuleRef module, BinaryenExpressionRef condition, BinaryenExpressionRef ifTrue, BinaryenExpressionRef ifFalse) {
+BinaryenExpressionRef BinaryenSelect(BinaryenModuleRef module,
+ BinaryenExpressionRef condition,
+ BinaryenExpressionRef ifTrue,
+ BinaryenExpressionRef ifFalse) {
auto* ret = ((Module*)module)->allocator.alloc<Select>();
if (tracing) {
@@ -915,7 +1164,8 @@ BinaryenExpressionRef BinaryenSelect(BinaryenModuleRef module, BinaryenExpressio
ret->finalize();
return static_cast<Expression*>(ret);
}
-BinaryenExpressionRef BinaryenDrop(BinaryenModuleRef module, BinaryenExpressionRef value) {
+BinaryenExpressionRef BinaryenDrop(BinaryenModuleRef module,
+ BinaryenExpressionRef value) {
auto* ret = ((Module*)module)->allocator.alloc<Drop>();
if (tracing) {
@@ -926,7 +1176,8 @@ BinaryenExpressionRef BinaryenDrop(BinaryenModuleRef module, BinaryenExpressionR
ret->finalize();
return static_cast<Expression*>(ret);
}
-BinaryenExpressionRef BinaryenReturn(BinaryenModuleRef module, BinaryenExpressionRef value) {
+BinaryenExpressionRef BinaryenReturn(BinaryenModuleRef module,
+ BinaryenExpressionRef value) {
auto* ret = Builder(*((Module*)module)).makeReturn((Expression*)value);
if (tracing) {
@@ -935,24 +1186,33 @@ BinaryenExpressionRef BinaryenReturn(BinaryenModuleRef module, BinaryenExpressio
return static_cast<Expression*>(ret);
}
-BinaryenExpressionRef BinaryenHost(BinaryenModuleRef module, BinaryenOp op, const char* name, BinaryenExpressionRef* operands, BinaryenIndex numOperands) {
+BinaryenExpressionRef BinaryenHost(BinaryenModuleRef module,
+ BinaryenOp op,
+ const char* name,
+ BinaryenExpressionRef* operands,
+ BinaryenIndex numOperands) {
auto* ret = ((Module*)module)->allocator.alloc<Host>();
if (tracing) {
std::cout << " {\n";
std::cout << " BinaryenExpressionRef operands[] = { ";
for (BinaryenIndex i = 0; i < numOperands; i++) {
- if (i > 0) std::cout << ", ";
+ if (i > 0)
+ std::cout << ", ";
std::cout << "expressions[" << expressions[operands[i]] << "]";
}
- if (numOperands == 0) std::cout << "0"; // ensure the array is not empty, otherwise a compiler error on VS
+ if (numOperands == 0)
+ // ensure the array is not empty, otherwise a compiler error on VS
+ std::cout << "0";
std::cout << " };\n ";
- traceExpression(ret, "BinaryenHost", StringLit(name), "operands", numOperands);
+ traceExpression(
+ ret, "BinaryenHost", StringLit(name), "operands", numOperands);
std::cout << " }\n";
}
ret->op = HostOp(op);
- if (name) ret->nameOperand = name;
+ if (name)
+ ret->nameOperand = name;
for (BinaryenIndex i = 0; i < numOperands; i++) {
ret->operands.push_back((Expression*)operands[i]);
}
@@ -977,8 +1237,13 @@ BinaryenExpressionRef BinaryenUnreachable(BinaryenModuleRef module) {
return static_cast<Expression*>(ret);
}
-BinaryenExpressionRef BinaryenAtomicLoad(BinaryenModuleRef module, uint32_t bytes, uint32_t offset, BinaryenType type, BinaryenExpressionRef ptr) {
- auto* ret = Builder(*((Module*)module)).makeAtomicLoad(bytes, offset, (Expression*)ptr, Type(type));
+BinaryenExpressionRef BinaryenAtomicLoad(BinaryenModuleRef module,
+ uint32_t bytes,
+ uint32_t offset,
+ BinaryenType type,
+ BinaryenExpressionRef ptr) {
+ auto* ret = Builder(*((Module*)module))
+ .makeAtomicLoad(bytes, offset, (Expression*)ptr, Type(type));
if (tracing) {
traceExpression(ret, "BinaryenAtomicLoad", bytes, offset, type, ptr);
@@ -986,44 +1251,99 @@ BinaryenExpressionRef BinaryenAtomicLoad(BinaryenModuleRef module, uint32_t byte
return static_cast<Expression*>(ret);
}
-BinaryenExpressionRef BinaryenAtomicStore(BinaryenModuleRef module, uint32_t bytes, uint32_t offset, BinaryenExpressionRef ptr, BinaryenExpressionRef value, BinaryenType type) {
- auto* ret = Builder(*((Module*)module)).makeAtomicStore(bytes, offset, (Expression*)ptr, (Expression*)value, Type(type));
+BinaryenExpressionRef BinaryenAtomicStore(BinaryenModuleRef module,
+ uint32_t bytes,
+ uint32_t offset,
+ BinaryenExpressionRef ptr,
+ BinaryenExpressionRef value,
+ BinaryenType type) {
+ auto* ret =
+ Builder(*((Module*)module))
+ .makeAtomicStore(
+ bytes, offset, (Expression*)ptr, (Expression*)value, Type(type));
if (tracing) {
- traceExpression(ret, "BinaryenAtomicStore", bytes, offset, ptr, value, type);
+ traceExpression(
+ ret, "BinaryenAtomicStore", bytes, offset, ptr, value, type);
}
return static_cast<Expression*>(ret);
}
-BinaryenExpressionRef BinaryenAtomicRMW(BinaryenModuleRef module, BinaryenOp op, BinaryenIndex bytes, BinaryenIndex offset, BinaryenExpressionRef ptr, BinaryenExpressionRef value, BinaryenType type) {
- auto* ret = Builder(*((Module*)module)).makeAtomicRMW(AtomicRMWOp(op), bytes, offset, (Expression*)ptr, (Expression*)value, Type(type));
+BinaryenExpressionRef BinaryenAtomicRMW(BinaryenModuleRef module,
+ BinaryenOp op,
+ BinaryenIndex bytes,
+ BinaryenIndex offset,
+ BinaryenExpressionRef ptr,
+ BinaryenExpressionRef value,
+ BinaryenType type) {
+ auto* ret = Builder(*((Module*)module))
+ .makeAtomicRMW(AtomicRMWOp(op),
+ bytes,
+ offset,
+ (Expression*)ptr,
+ (Expression*)value,
+ Type(type));
if (tracing) {
- traceExpression(ret, "BinaryenAtomicRMW", op, bytes, offset, ptr, value, type);
+ traceExpression(
+ ret, "BinaryenAtomicRMW", op, bytes, offset, ptr, value, type);
}
return static_cast<Expression*>(ret);
}
-BinaryenExpressionRef BinaryenAtomicCmpxchg(BinaryenModuleRef module, BinaryenIndex bytes, BinaryenIndex offset, BinaryenExpressionRef ptr, BinaryenExpressionRef expected, BinaryenExpressionRef replacement, BinaryenType type) {
- auto* ret = Builder(*((Module*)module)).makeAtomicCmpxchg(bytes, offset, (Expression*)ptr, (Expression*)expected, (Expression*)replacement, Type(type));
-
- if (tracing) {
- traceExpression(ret, "BinaryenAtomicCmpxchg", bytes, offset, ptr, expected, replacement, type);
+BinaryenExpressionRef BinaryenAtomicCmpxchg(BinaryenModuleRef module,
+ BinaryenIndex bytes,
+ BinaryenIndex offset,
+ BinaryenExpressionRef ptr,
+ BinaryenExpressionRef expected,
+ BinaryenExpressionRef replacement,
+ BinaryenType type) {
+ auto* ret = Builder(*((Module*)module))
+ .makeAtomicCmpxchg(bytes,
+ offset,
+ (Expression*)ptr,
+ (Expression*)expected,
+ (Expression*)replacement,
+ Type(type));
+
+ if (tracing) {
+ traceExpression(ret,
+ "BinaryenAtomicCmpxchg",
+ bytes,
+ offset,
+ ptr,
+ expected,
+ replacement,
+ type);
}
return static_cast<Expression*>(ret);
}
-BinaryenExpressionRef BinaryenAtomicWait(BinaryenModuleRef module, BinaryenExpressionRef ptr, BinaryenExpressionRef expected, BinaryenExpressionRef timeout, BinaryenType expectedType) {
- auto* ret = Builder(*((Module*)module)).makeAtomicWait((Expression*)ptr, (Expression*)expected, (Expression*)timeout, Type(expectedType), 0);
+BinaryenExpressionRef BinaryenAtomicWait(BinaryenModuleRef module,
+ BinaryenExpressionRef ptr,
+ BinaryenExpressionRef expected,
+ BinaryenExpressionRef timeout,
+ BinaryenType expectedType) {
+ auto* ret = Builder(*((Module*)module))
+ .makeAtomicWait((Expression*)ptr,
+ (Expression*)expected,
+ (Expression*)timeout,
+ Type(expectedType),
+ 0);
if (tracing) {
- traceExpression(ret, "BinaryenAtomicWait", ptr, expected, timeout, expectedType);
+ traceExpression(
+ ret, "BinaryenAtomicWait", ptr, expected, timeout, expectedType);
}
return static_cast<Expression*>(ret);
}
-BinaryenExpressionRef BinaryenAtomicNotify(BinaryenModuleRef module, BinaryenExpressionRef ptr, BinaryenExpressionRef notifyCount) {
- auto* ret = Builder(*((Module*)module)).makeAtomicNotify((Expression*)ptr, (Expression*)notifyCount, 0);
+BinaryenExpressionRef BinaryenAtomicNotify(BinaryenModuleRef module,
+ BinaryenExpressionRef ptr,
+ BinaryenExpressionRef notifyCount) {
+ auto* ret =
+ Builder(*((Module*)module))
+ .makeAtomicNotify((Expression*)ptr, (Expression*)notifyCount, 0);
if (tracing) {
traceExpression(ret, "BinaryenAtomicNotify", ptr, notifyCount);
@@ -1031,24 +1351,39 @@ BinaryenExpressionRef BinaryenAtomicNotify(BinaryenModuleRef module, BinaryenExp
return static_cast<Expression*>(ret);
}
-BinaryenExpressionRef BinaryenSIMDExtract(BinaryenModuleRef module, BinaryenOp op, BinaryenExpressionRef vec, uint8_t index) {
- auto* ret = Builder(*((Module*)module)).makeSIMDExtract(SIMDExtractOp(op), (Expression*) vec, index);
+BinaryenExpressionRef BinaryenSIMDExtract(BinaryenModuleRef module,
+ BinaryenOp op,
+ BinaryenExpressionRef vec,
+ uint8_t index) {
+ auto* ret = Builder(*((Module*)module))
+ .makeSIMDExtract(SIMDExtractOp(op), (Expression*)vec, index);
if (tracing) {
traceExpression(ret, "BinaryenSIMDExtract", op, vec, int(index));
}
return static_cast<Expression*>(ret);
}
-BinaryenExpressionRef BinaryenSIMDReplace(BinaryenModuleRef module, BinaryenOp op, BinaryenExpressionRef vec, uint8_t index, BinaryenExpressionRef value) {
- auto* ret = Builder(*((Module*)module)).makeSIMDReplace(SIMDReplaceOp(op), (Expression*) vec, index, (Expression*)value);
+BinaryenExpressionRef BinaryenSIMDReplace(BinaryenModuleRef module,
+ BinaryenOp op,
+ BinaryenExpressionRef vec,
+ uint8_t index,
+ BinaryenExpressionRef value) {
+ auto* ret =
+ Builder(*((Module*)module))
+ .makeSIMDReplace(
+ SIMDReplaceOp(op), (Expression*)vec, index, (Expression*)value);
if (tracing) {
traceExpression(ret, "BinaryenSIMDReplace", op, vec, int(index), value);
}
return static_cast<Expression*>(ret);
}
-BinaryenExpressionRef BinaryenSIMDShuffle(BinaryenModuleRef module, BinaryenExpressionRef left, BinaryenExpressionRef right, const uint8_t mask_[16]) {
+BinaryenExpressionRef BinaryenSIMDShuffle(BinaryenModuleRef module,
+ BinaryenExpressionRef left,
+ BinaryenExpressionRef right,
+ const uint8_t mask_[16]) {
std::array<uint8_t, 16> mask;
memcpy(mask.data(), mask_, 16);
- auto* ret = Builder(*((Module*)module)).makeSIMDShuffle((Expression*)left, (Expression*)right, mask);
+ auto* ret = Builder(*((Module*)module))
+ .makeSIMDShuffle((Expression*)left, (Expression*)right, mask);
if (tracing) {
std::cout << " {\n";
std::cout << " uint8_t mask[] = {";
@@ -1064,29 +1399,47 @@ BinaryenExpressionRef BinaryenSIMDShuffle(BinaryenModuleRef module, BinaryenExpr
}
return static_cast<Expression*>(ret);
}
-BinaryenExpressionRef BinaryenSIMDBitselect(BinaryenModuleRef module, BinaryenExpressionRef left, BinaryenExpressionRef right, BinaryenExpressionRef cond) {
- auto* ret = Builder(*((Module*)module)).makeSIMDBitselect((Expression*)left, (Expression*)right, (Expression*)cond);
+BinaryenExpressionRef BinaryenSIMDBitselect(BinaryenModuleRef module,
+ BinaryenExpressionRef left,
+ BinaryenExpressionRef right,
+ BinaryenExpressionRef cond) {
+ auto* ret = Builder(*((Module*)module))
+ .makeSIMDBitselect(
+ (Expression*)left, (Expression*)right, (Expression*)cond);
if (tracing) {
traceExpression(ret, "BinaryenSIMDBitselect", left, right, cond);
}
return static_cast<Expression*>(ret);
}
-BinaryenExpressionRef BinaryenSIMDShift(BinaryenModuleRef module, BinaryenOp op, BinaryenExpressionRef vec, BinaryenExpressionRef shift) {
- auto* ret = Builder(*((Module*)module)).makeSIMDShift(SIMDShiftOp(op), (Expression*)vec, (Expression*)shift);
+BinaryenExpressionRef BinaryenSIMDShift(BinaryenModuleRef module,
+ BinaryenOp op,
+ BinaryenExpressionRef vec,
+ BinaryenExpressionRef shift) {
+ auto* ret =
+ Builder(*((Module*)module))
+ .makeSIMDShift(SIMDShiftOp(op), (Expression*)vec, (Expression*)shift);
if (tracing) {
traceExpression(ret, "BinaryenSIMDShift", op, vec, shift);
}
return static_cast<Expression*>(ret);
}
-BinaryenExpressionRef BinaryenMemoryInit(BinaryenModuleRef module, uint32_t segment, BinaryenExpressionRef dest, BinaryenExpressionRef offset, BinaryenExpressionRef size) {
- auto* ret = Builder(*((Module*)module)).makeMemoryInit(segment, (Expression*)dest, (Expression*)offset, (Expression*)size);
+BinaryenExpressionRef BinaryenMemoryInit(BinaryenModuleRef module,
+ uint32_t segment,
+ BinaryenExpressionRef dest,
+ BinaryenExpressionRef offset,
+ BinaryenExpressionRef size) {
+ auto* ret =
+ Builder(*((Module*)module))
+ .makeMemoryInit(
+ segment, (Expression*)dest, (Expression*)offset, (Expression*)size);
if (tracing) {
traceExpression(ret, "BinaryenMemoryInit", segment, dest, offset, size);
}
return static_cast<Expression*>(ret);
}
-BinaryenExpressionRef BinaryenDataDrop(BinaryenModuleRef module, uint32_t segment) {
+BinaryenExpressionRef BinaryenDataDrop(BinaryenModuleRef module,
+ uint32_t segment) {
auto* ret = Builder(*((Module*)module)).makeDataDrop(segment);
if (tracing) {
traceExpression(ret, "BinaryenDataDrop", segment);
@@ -1094,16 +1447,26 @@ BinaryenExpressionRef BinaryenDataDrop(BinaryenModuleRef module, uint32_t segmen
return static_cast<Expression*>(ret);
}
-BinaryenExpressionRef BinaryenMemoryCopy(BinaryenModuleRef module, BinaryenExpressionRef dest, BinaryenExpressionRef source, BinaryenExpressionRef size) {
- auto* ret = Builder(*((Module*)module)).makeMemoryCopy((Expression*)dest, (Expression*)source, (Expression*)size);
+BinaryenExpressionRef BinaryenMemoryCopy(BinaryenModuleRef module,
+ BinaryenExpressionRef dest,
+ BinaryenExpressionRef source,
+ BinaryenExpressionRef size) {
+ auto* ret = Builder(*((Module*)module))
+ .makeMemoryCopy(
+ (Expression*)dest, (Expression*)source, (Expression*)size);
if (tracing) {
traceExpression(ret, "BinaryenMemoryCopy", dest, source, size);
}
return static_cast<Expression*>(ret);
}
-BinaryenExpressionRef BinaryenMemoryFill(BinaryenModuleRef module, BinaryenExpressionRef dest, BinaryenExpressionRef value, BinaryenExpressionRef size) {
- auto* ret = Builder(*((Module*)module)).makeMemoryFill((Expression*)dest, (Expression*)value, (Expression*)size);
+BinaryenExpressionRef BinaryenMemoryFill(BinaryenModuleRef module,
+ BinaryenExpressionRef dest,
+ BinaryenExpressionRef value,
+ BinaryenExpressionRef size) {
+ auto* ret =
+ Builder(*((Module*)module))
+ .makeMemoryFill((Expression*)dest, (Expression*)value, (Expression*)size);
if (tracing) {
traceExpression(ret, "BinaryenMemoryFill", dest, value, size);
}
@@ -1114,21 +1477,24 @@ BinaryenExpressionRef BinaryenMemoryFill(BinaryenModuleRef module, BinaryenExpre
BinaryenExpressionId BinaryenExpressionGetId(BinaryenExpressionRef expr) {
if (tracing) {
- std::cout << " BinaryenExpressionGetId(expressions[" << expressions[expr] << "]);\n";
+ std::cout << " BinaryenExpressionGetId(expressions[" << expressions[expr]
+ << "]);\n";
}
return ((Expression*)expr)->_id;
}
BinaryenType BinaryenExpressionGetType(BinaryenExpressionRef expr) {
if (tracing) {
- std::cout << " BinaryenExpressionGetType(expressions[" << expressions[expr] << "]);\n";
+ std::cout << " BinaryenExpressionGetType(expressions[" << expressions[expr]
+ << "]);\n";
}
return ((Expression*)expr)->type;
}
void BinaryenExpressionPrint(BinaryenExpressionRef expr) {
if (tracing) {
- std::cout << " BinaryenExpressionPrint(expressions[" << expressions[expr] << "]);\n";
+ std::cout << " BinaryenExpressionPrint(expressions[" << expressions[expr]
+ << "]);\n";
}
WasmPrinter::printExpression((Expression*)expr, std::cout);
@@ -1140,7 +1506,8 @@ void BinaryenExpressionPrint(BinaryenExpressionRef expr) {
// Block
const char* BinaryenBlockGetName(BinaryenExpressionRef expr) {
if (tracing) {
- std::cout << " BinaryenBlockGetName(expressions[" << expressions[expr] << "]);\n";
+ std::cout << " BinaryenBlockGetName(expressions[" << expressions[expr]
+ << "]);\n";
}
auto* expression = (Expression*)expr;
@@ -1149,16 +1516,19 @@ const char* BinaryenBlockGetName(BinaryenExpressionRef expr) {
}
BinaryenIndex BinaryenBlockGetNumChildren(BinaryenExpressionRef expr) {
if (tracing) {
- std::cout << " BinaryenBlockGetNumChildren(expressions[" << expressions[expr] << "]);\n";
+ std::cout << " BinaryenBlockGetNumChildren(expressions["
+ << expressions[expr] << "]);\n";
}
auto* expression = (Expression*)expr;
assert(expression->is<Block>());
return static_cast<Block*>(expression)->list.size();
}
-BinaryenExpressionRef BinaryenBlockGetChild(BinaryenExpressionRef expr, BinaryenIndex index) {
+BinaryenExpressionRef BinaryenBlockGetChild(BinaryenExpressionRef expr,
+ BinaryenIndex index) {
if (tracing) {
- std::cout << " BinaryenBlockGetChild(expressions[" << expressions[expr] << "], " << index << ");\n";
+ std::cout << " BinaryenBlockGetChild(expressions[" << expressions[expr]
+ << "], " << index << ");\n";
}
auto* expression = (Expression*)expr;
@@ -1169,7 +1539,8 @@ BinaryenExpressionRef BinaryenBlockGetChild(BinaryenExpressionRef expr, Binaryen
// If
BinaryenExpressionRef BinaryenIfGetCondition(BinaryenExpressionRef expr) {
if (tracing) {
- std::cout << " BinaryenIfGetCondition(expressions[" << expressions[expr] << "]);\n";
+ std::cout << " BinaryenIfGetCondition(expressions[" << expressions[expr]
+ << "]);\n";
}
auto* expression = (Expression*)expr;
@@ -1178,7 +1549,8 @@ BinaryenExpressionRef BinaryenIfGetCondition(BinaryenExpressionRef expr) {
}
BinaryenExpressionRef BinaryenIfGetIfTrue(BinaryenExpressionRef expr) {
if (tracing) {
- std::cout << " BinaryenIfGetIfTrue(expressions[" << expressions[expr] << "]);\n";
+ std::cout << " BinaryenIfGetIfTrue(expressions[" << expressions[expr]
+ << "]);\n";
}
auto* expression = (Expression*)expr;
@@ -1187,7 +1559,8 @@ BinaryenExpressionRef BinaryenIfGetIfTrue(BinaryenExpressionRef expr) {
}
BinaryenExpressionRef BinaryenIfGetIfFalse(BinaryenExpressionRef expr) {
if (tracing) {
- std::cout << " BinaryenIfGetIfFalse(expressions[" << expressions[expr] << "]);\n";
+ std::cout << " BinaryenIfGetIfFalse(expressions[" << expressions[expr]
+ << "]);\n";
}
auto* expression = (Expression*)expr;
@@ -1197,7 +1570,8 @@ BinaryenExpressionRef BinaryenIfGetIfFalse(BinaryenExpressionRef expr) {
// Loop
const char* BinaryenLoopGetName(BinaryenExpressionRef expr) {
if (tracing) {
- std::cout << " BinaryenLoopGetName(expressions[" << expressions[expr] << "]);\n";
+ std::cout << " BinaryenLoopGetName(expressions[" << expressions[expr]
+ << "]);\n";
}
auto* expression = (Expression*)expr;
@@ -1206,7 +1580,8 @@ const char* BinaryenLoopGetName(BinaryenExpressionRef expr) {
}
BinaryenExpressionRef BinaryenLoopGetBody(BinaryenExpressionRef expr) {
if (tracing) {
- std::cout << " BinaryenLoopGetBody(expressions[" << expressions[expr] << "]);\n";
+ std::cout << " BinaryenLoopGetBody(expressions[" << expressions[expr]
+ << "]);\n";
}
auto* expression = (Expression*)expr;
@@ -1216,7 +1591,8 @@ BinaryenExpressionRef BinaryenLoopGetBody(BinaryenExpressionRef expr) {
// Break
const char* BinaryenBreakGetName(BinaryenExpressionRef expr) {
if (tracing) {
- std::cout << " BinaryenBreakGetName(expressions[" << expressions[expr] << "]);\n";
+ std::cout << " BinaryenBreakGetName(expressions[" << expressions[expr]
+ << "]);\n";
}
auto* expression = (Expression*)expr;
@@ -1225,7 +1601,8 @@ const char* BinaryenBreakGetName(BinaryenExpressionRef expr) {
}
BinaryenExpressionRef BinaryenBreakGetCondition(BinaryenExpressionRef expr) {
if (tracing) {
- std::cout << " BinaryenBreakGetCondition(expressions[" << expressions[expr] << "]);\n";
+ std::cout << " BinaryenBreakGetCondition(expressions[" << expressions[expr]
+ << "]);\n";
}
auto* expression = (Expression*)expr;
@@ -1234,7 +1611,8 @@ BinaryenExpressionRef BinaryenBreakGetCondition(BinaryenExpressionRef expr) {
}
BinaryenExpressionRef BinaryenBreakGetValue(BinaryenExpressionRef expr) {
if (tracing) {
- std::cout << " BinaryenBreakGetValue(expressions[" << expressions[expr] << "]);\n";
+ std::cout << " BinaryenBreakGetValue(expressions[" << expressions[expr]
+ << "]);\n";
}
auto* expression = (Expression*)expr;
@@ -1244,16 +1622,19 @@ BinaryenExpressionRef BinaryenBreakGetValue(BinaryenExpressionRef expr) {
// Switch
BinaryenIndex BinaryenSwitchGetNumNames(BinaryenExpressionRef expr) {
if (tracing) {
- std::cout << " BinaryenSwitchGetNumNames(expressions[" << expressions[expr] << "]);\n";
+ std::cout << " BinaryenSwitchGetNumNames(expressions[" << expressions[expr]
+ << "]);\n";
}
auto* expression = (Expression*)expr;
assert(expression->is<Switch>());
return static_cast<Switch*>(expression)->targets.size();
}
-const char* BinaryenSwitchGetName(BinaryenExpressionRef expr, BinaryenIndex index) {
+const char* BinaryenSwitchGetName(BinaryenExpressionRef expr,
+ BinaryenIndex index) {
if (tracing) {
- std::cout << " BinaryenSwitchGetName(expressions[" << expressions[expr] << "], " << index << ");\n";
+ std::cout << " BinaryenSwitchGetName(expressions[" << expressions[expr]
+ << "], " << index << ");\n";
}
auto* expression = (Expression*)expr;
@@ -1263,7 +1644,8 @@ const char* BinaryenSwitchGetName(BinaryenExpressionRef expr, BinaryenIndex inde
}
const char* BinaryenSwitchGetDefaultName(BinaryenExpressionRef expr) {
if (tracing) {
- std::cout << " BinaryenSwitchGetDefaultName(expressions[" << expressions[expr] << "]);\n";
+ std::cout << " BinaryenSwitchGetDefaultName(expressions["
+ << expressions[expr] << "]);\n";
}
auto* expression = (Expression*)expr;
@@ -1272,7 +1654,8 @@ const char* BinaryenSwitchGetDefaultName(BinaryenExpressionRef expr) {
}
BinaryenExpressionRef BinaryenSwitchGetCondition(BinaryenExpressionRef expr) {
if (tracing) {
- std::cout << " BinaryenSwitchGetCondition(expressions[" << expressions[expr] << "]);\n";
+ std::cout << " BinaryenSwitchGetCondition(expressions["
+ << expressions[expr] << "]);\n";
}
auto* expression = (Expression*)expr;
@@ -1281,7 +1664,8 @@ BinaryenExpressionRef BinaryenSwitchGetCondition(BinaryenExpressionRef expr) {
}
BinaryenExpressionRef BinaryenSwitchGetValue(BinaryenExpressionRef expr) {
if (tracing) {
- std::cout << " BinaryenSwitchGetValue(expressions[" << expressions[expr] << "]);\n";
+ std::cout << " BinaryenSwitchGetValue(expressions[" << expressions[expr]
+ << "]);\n";
}
auto* expression = (Expression*)expr;
@@ -1291,7 +1675,8 @@ BinaryenExpressionRef BinaryenSwitchGetValue(BinaryenExpressionRef expr) {
// Call
const char* BinaryenCallGetTarget(BinaryenExpressionRef expr) {
if (tracing) {
- std::cout << " BinaryenCallGetTarget(expressions[" << expressions[expr] << "]);\n";
+ std::cout << " BinaryenCallGetTarget(expressions[" << expressions[expr]
+ << "]);\n";
}
auto* expression = (Expression*)expr;
@@ -1300,16 +1685,19 @@ const char* BinaryenCallGetTarget(BinaryenExpressionRef expr) {
}
BinaryenIndex BinaryenCallGetNumOperands(BinaryenExpressionRef expr) {
if (tracing) {
- std::cout << " BinaryenCallGetNumOperands(expressions[" << expressions[expr] << "]);\n";
+ std::cout << " BinaryenCallGetNumOperands(expressions["
+ << expressions[expr] << "]);\n";
}
auto* expression = (Expression*)expr;
assert(expression->is<Call>());
return static_cast<Call*>(expression)->operands.size();
}
-BinaryenExpressionRef BinaryenCallGetOperand(BinaryenExpressionRef expr, BinaryenIndex index) {
+BinaryenExpressionRef BinaryenCallGetOperand(BinaryenExpressionRef expr,
+ BinaryenIndex index) {
if (tracing) {
- std::cout << " BinaryenCallGetOperand(expressions[" << expressions[expr] << "], " << index << ");\n";
+ std::cout << " BinaryenCallGetOperand(expressions[" << expressions[expr]
+ << "], " << index << ");\n";
}
auto* expression = (Expression*)expr;
@@ -1318,9 +1706,11 @@ BinaryenExpressionRef BinaryenCallGetOperand(BinaryenExpressionRef expr, Binarye
return static_cast<Call*>(expression)->operands[index];
}
// CallIndirect
-BinaryenExpressionRef BinaryenCallIndirectGetTarget(BinaryenExpressionRef expr) {
+BinaryenExpressionRef
+BinaryenCallIndirectGetTarget(BinaryenExpressionRef expr) {
if (tracing) {
- std::cout << " BinaryenCallIndirectGetTarget(expressions[" << expressions[expr] << "]);\n";
+ std::cout << " BinaryenCallIndirectGetTarget(expressions["
+ << expressions[expr] << "]);\n";
}
auto* expression = (Expression*)expr;
@@ -1329,16 +1719,19 @@ BinaryenExpressionRef BinaryenCallIndirectGetTarget(BinaryenExpressionRef expr)
}
BinaryenIndex BinaryenCallIndirectGetNumOperands(BinaryenExpressionRef expr) {
if (tracing) {
- std::cout << " BinaryenCallIndirectGetNumOperands(expressions[" << expressions[expr] << "]);\n";
+ std::cout << " BinaryenCallIndirectGetNumOperands(expressions["
+ << expressions[expr] << "]);\n";
}
auto* expression = (Expression*)expr;
assert(expression->is<CallIndirect>());
return static_cast<CallIndirect*>(expression)->operands.size();
}
-BinaryenExpressionRef BinaryenCallIndirectGetOperand(BinaryenExpressionRef expr, BinaryenIndex index) {
+BinaryenExpressionRef BinaryenCallIndirectGetOperand(BinaryenExpressionRef expr,
+ BinaryenIndex index) {
if (tracing) {
- std::cout << " BinaryenCallIndirectGetOperand(expressions[" << expressions[expr] << "], " << index << ");\n";
+ std::cout << " BinaryenCallIndirectGetOperand(expressions["
+ << expressions[expr] << "], " << index << ");\n";
}
auto* expression = (Expression*)expr;
@@ -1349,7 +1742,8 @@ BinaryenExpressionRef BinaryenCallIndirectGetOperand(BinaryenExpressionRef expr,
// GetLocal
BinaryenIndex BinaryenGetLocalGetIndex(BinaryenExpressionRef expr) {
if (tracing) {
- std::cout << " BinaryenGetLocalGetIndex(expressions[" << expressions[expr] << "]);\n";
+ std::cout << " BinaryenGetLocalGetIndex(expressions[" << expressions[expr]
+ << "]);\n";
}
auto* expression = (Expression*)expr;
@@ -1359,7 +1753,8 @@ BinaryenIndex BinaryenGetLocalGetIndex(BinaryenExpressionRef expr) {
// SetLocal
int BinaryenSetLocalIsTee(BinaryenExpressionRef expr) {
if (tracing) {
- std::cout << " BinaryenSetLocalIsTee(expressions[" << expressions[expr] << "]);\n";
+ std::cout << " BinaryenSetLocalIsTee(expressions[" << expressions[expr]
+ << "]);\n";
}
auto* expression = (Expression*)expr;
@@ -1368,7 +1763,8 @@ int BinaryenSetLocalIsTee(BinaryenExpressionRef expr) {
}
BinaryenIndex BinaryenSetLocalGetIndex(BinaryenExpressionRef expr) {
if (tracing) {
- std::cout << " BinaryenSetLocalGetIndex(expressions[" << expressions[expr] << "]);\n";
+ std::cout << " BinaryenSetLocalGetIndex(expressions[" << expressions[expr]
+ << "]);\n";
}
auto* expression = (Expression*)expr;
@@ -1377,7 +1773,8 @@ BinaryenIndex BinaryenSetLocalGetIndex(BinaryenExpressionRef expr) {
}
BinaryenExpressionRef BinaryenSetLocalGetValue(BinaryenExpressionRef expr) {
if (tracing) {
- std::cout << " BinaryenSetLocalGetValue(expressions[" << expressions[expr] << "]);\n";
+ std::cout << " BinaryenSetLocalGetValue(expressions[" << expressions[expr]
+ << "]);\n";
}
auto* expression = (Expression*)expr;
@@ -1387,7 +1784,8 @@ BinaryenExpressionRef BinaryenSetLocalGetValue(BinaryenExpressionRef expr) {
// GetGlobal
const char* BinaryenGetGlobalGetName(BinaryenExpressionRef expr) {
if (tracing) {
- std::cout << " BinaryenGetGlobalGetName(expressions[" << expressions[expr] << "]);\n";
+ std::cout << " BinaryenGetGlobalGetName(expressions[" << expressions[expr]
+ << "]);\n";
}
auto* expression = (Expression*)expr;
@@ -1397,7 +1795,8 @@ const char* BinaryenGetGlobalGetName(BinaryenExpressionRef expr) {
// SetGlobal
const char* BinaryenSetGlobalGetName(BinaryenExpressionRef expr) {
if (tracing) {
- std::cout << " BinaryenSetGlobalGetName(expressions[" << expressions[expr] << "]);\n";
+ std::cout << " BinaryenSetGlobalGetName(expressions[" << expressions[expr]
+ << "]);\n";
}
auto* expression = (Expression*)expr;
@@ -1406,7 +1805,8 @@ const char* BinaryenSetGlobalGetName(BinaryenExpressionRef expr) {
}
BinaryenExpressionRef BinaryenSetGlobalGetValue(BinaryenExpressionRef expr) {
if (tracing) {
- std::cout << " BinaryenSetGlobalGetValue(expressions[" << expressions[expr] << "]);\n";
+ std::cout << " BinaryenSetGlobalGetValue(expressions[" << expressions[expr]
+ << "]);\n";
}
auto* expression = (Expression*)expr;
@@ -1416,7 +1816,8 @@ BinaryenExpressionRef BinaryenSetGlobalGetValue(BinaryenExpressionRef expr) {
// Host
BinaryenOp BinaryenHostGetOp(BinaryenExpressionRef expr) {
if (tracing) {
- std::cout << " BinaryenHostGetOp(expressions[" << expressions[expr] << "]);\n";
+ std::cout << " BinaryenHostGetOp(expressions[" << expressions[expr]
+ << "]);\n";
}
auto* expression = (Expression*)expr;
@@ -1425,7 +1826,8 @@ BinaryenOp BinaryenHostGetOp(BinaryenExpressionRef expr) {
}
const char* BinaryenHostGetNameOperand(BinaryenExpressionRef expr) {
if (tracing) {
- std::cout << " BinaryenHostGetNameOperand(expressions[" << expressions[expr] << "]);\n";
+ std::cout << " BinaryenHostGetNameOperand(expressions["
+ << expressions[expr] << "]);\n";
}
auto* expression = (Expression*)expr;
@@ -1434,16 +1836,19 @@ const char* BinaryenHostGetNameOperand(BinaryenExpressionRef expr) {
}
BinaryenIndex BinaryenHostGetNumOperands(BinaryenExpressionRef expr) {
if (tracing) {
- std::cout << " BinaryenHostGetNumOperands(expressions[" << expressions[expr] << "]);\n";
+ std::cout << " BinaryenHostGetNumOperands(expressions["
+ << expressions[expr] << "]);\n";
}
auto* expression = (Expression*)expr;
assert(expression->is<Host>());
return static_cast<Host*>(expression)->operands.size();
}
-BinaryenExpressionRef BinaryenHostGetOperand(BinaryenExpressionRef expr, BinaryenIndex index) {
+BinaryenExpressionRef BinaryenHostGetOperand(BinaryenExpressionRef expr,
+ BinaryenIndex index) {
if (tracing) {
- std::cout << " BinaryenHostGetOperand(expressions[" << expressions[expr] << "], " << index << ");\n";
+ std::cout << " BinaryenHostGetOperand(expressions[" << expressions[expr]
+ << "], " << index << ");\n";
}
auto* expression = (Expression*)expr;
@@ -1454,7 +1859,8 @@ BinaryenExpressionRef BinaryenHostGetOperand(BinaryenExpressionRef expr, Binarye
// Load
int BinaryenLoadIsAtomic(BinaryenExpressionRef expr) {
if (tracing) {
- std::cout << " BinaryenLoadIsAtomic(expressions[" << expressions[expr] << "]);\n";
+ std::cout << " BinaryenLoadIsAtomic(expressions[" << expressions[expr]
+ << "]);\n";
}
auto* expression = (Expression*)expr;
@@ -1463,7 +1869,8 @@ int BinaryenLoadIsAtomic(BinaryenExpressionRef expr) {
}
int BinaryenLoadIsSigned(BinaryenExpressionRef expr) {
if (tracing) {
- std::cout << " BinaryenLoadIsSigned(expressions[" << expressions[expr] << "]);\n";
+ std::cout << " BinaryenLoadIsSigned(expressions[" << expressions[expr]
+ << "]);\n";
}
auto* expression = (Expression*)expr;
@@ -1472,7 +1879,8 @@ int BinaryenLoadIsSigned(BinaryenExpressionRef expr) {
}
uint32_t BinaryenLoadGetBytes(BinaryenExpressionRef expr) {
if (tracing) {
- std::cout << " BinaryenLoadGetBytes(expressions[" << expressions[expr] << "]);\n";
+ std::cout << " BinaryenLoadGetBytes(expressions[" << expressions[expr]
+ << "]);\n";
}
auto* expression = (Expression*)expr;
@@ -1481,7 +1889,8 @@ uint32_t BinaryenLoadGetBytes(BinaryenExpressionRef expr) {
}
uint32_t BinaryenLoadGetOffset(BinaryenExpressionRef expr) {
if (tracing) {
- std::cout << " BinaryenLoadGetOffset(expressions[" << expressions[expr] << "]);\n";
+ std::cout << " BinaryenLoadGetOffset(expressions[" << expressions[expr]
+ << "]);\n";
}
auto* expression = (Expression*)expr;
@@ -1490,7 +1899,8 @@ uint32_t BinaryenLoadGetOffset(BinaryenExpressionRef expr) {
}
uint32_t BinaryenLoadGetAlign(BinaryenExpressionRef expr) {
if (tracing) {
- std::cout << " BinaryenLoadGetAlign(expressions[" << expressions[expr] << "]);\n";
+ std::cout << " BinaryenLoadGetAlign(expressions[" << expressions[expr]
+ << "]);\n";
}
auto* expression = (Expression*)expr;
@@ -1499,7 +1909,8 @@ uint32_t BinaryenLoadGetAlign(BinaryenExpressionRef expr) {
}
BinaryenExpressionRef BinaryenLoadGetPtr(BinaryenExpressionRef expr) {
if (tracing) {
- std::cout << " BinaryenLoadGetPtr(expressions[" << expressions[expr] << "]);\n";
+ std::cout << " BinaryenLoadGetPtr(expressions[" << expressions[expr]
+ << "]);\n";
}
auto* expression = (Expression*)expr;
@@ -1509,7 +1920,8 @@ BinaryenExpressionRef BinaryenLoadGetPtr(BinaryenExpressionRef expr) {
// Store
int BinaryenStoreIsAtomic(BinaryenExpressionRef expr) {
if (tracing) {
- std::cout << " BinaryenStoreIsAtomic(expressions[" << expressions[expr] << "]);\n";
+ std::cout << " BinaryenStoreIsAtomic(expressions[" << expressions[expr]
+ << "]);\n";
}
auto* expression = (Expression*)expr;
@@ -1518,7 +1930,8 @@ int BinaryenStoreIsAtomic(BinaryenExpressionRef expr) {
}
uint32_t BinaryenStoreGetBytes(BinaryenExpressionRef expr) {
if (tracing) {
- std::cout << " BinaryenStoreGetBytes(expressions[" << expressions[expr] << "]);\n";
+ std::cout << " BinaryenStoreGetBytes(expressions[" << expressions[expr]
+ << "]);\n";
}
auto* expression = (Expression*)expr;
@@ -1527,7 +1940,8 @@ uint32_t BinaryenStoreGetBytes(BinaryenExpressionRef expr) {
}
uint32_t BinaryenStoreGetOffset(BinaryenExpressionRef expr) {
if (tracing) {
- std::cout << " BinaryenStoreGetOffset(expressions[" << expressions[expr] << "]);\n";
+ std::cout << " BinaryenStoreGetOffset(expressions[" << expressions[expr]
+ << "]);\n";
}
auto* expression = (Expression*)expr;
@@ -1536,7 +1950,8 @@ uint32_t BinaryenStoreGetOffset(BinaryenExpressionRef expr) {
}
uint32_t BinaryenStoreGetAlign(BinaryenExpressionRef expr) {
if (tracing) {
- std::cout << " BinaryenStoreGetAlign(expressions[" << expressions[expr] << "]);\n";
+ std::cout << " BinaryenStoreGetAlign(expressions[" << expressions[expr]
+ << "]);\n";
}
auto* expression = (Expression*)expr;
@@ -1545,7 +1960,8 @@ uint32_t BinaryenStoreGetAlign(BinaryenExpressionRef expr) {
}
BinaryenExpressionRef BinaryenStoreGetPtr(BinaryenExpressionRef expr) {
if (tracing) {
- std::cout << " BinaryenStoreGetPtr(expressions[" << expressions[expr] << "]);\n";
+ std::cout << " BinaryenStoreGetPtr(expressions[" << expressions[expr]
+ << "]);\n";
}
auto* expression = (Expression*)expr;
@@ -1554,7 +1970,8 @@ BinaryenExpressionRef BinaryenStoreGetPtr(BinaryenExpressionRef expr) {
}
BinaryenExpressionRef BinaryenStoreGetValue(BinaryenExpressionRef expr) {
if (tracing) {
- std::cout << " BinaryenStoreGetValue(expressions[" << expressions[expr] << "]);\n";
+ std::cout << " BinaryenStoreGetValue(expressions[" << expressions[expr]
+ << "]);\n";
}
auto* expression = (Expression*)expr;
@@ -1564,7 +1981,8 @@ BinaryenExpressionRef BinaryenStoreGetValue(BinaryenExpressionRef expr) {
// Const
int32_t BinaryenConstGetValueI32(BinaryenExpressionRef expr) {
if (tracing) {
- std::cout << " BinaryenConstGetValueI32(expressions[" << expressions[expr] << "]);\n";
+ std::cout << " BinaryenConstGetValueI32(expressions[" << expressions[expr]
+ << "]);\n";
}
auto* expression = (Expression*)expr;
@@ -1573,7 +1991,8 @@ int32_t BinaryenConstGetValueI32(BinaryenExpressionRef expr) {
}
int64_t BinaryenConstGetValueI64(BinaryenExpressionRef expr) {
if (tracing) {
- std::cout << " BinaryenConstGetValueI64(expressions[" << expressions[expr] << "]);\n";
+ std::cout << " BinaryenConstGetValueI64(expressions[" << expressions[expr]
+ << "]);\n";
}
auto* expression = (Expression*)expr;
@@ -1582,16 +2001,19 @@ int64_t BinaryenConstGetValueI64(BinaryenExpressionRef expr) {
}
int32_t BinaryenConstGetValueI64Low(BinaryenExpressionRef expr) {
if (tracing) {
- std::cout << " BinaryenConstGetValueI64Low(expressions[" << expressions[expr] << "]);\n";
+ std::cout << " BinaryenConstGetValueI64Low(expressions["
+ << expressions[expr] << "]);\n";
}
auto* expression = (Expression*)expr;
assert(expression->is<Const>());
- return (int32_t)(static_cast<Const*>(expression)->value.geti64() & 0xffffffff);
+ return (int32_t)(static_cast<Const*>(expression)->value.geti64() &
+ 0xffffffff);
}
int32_t BinaryenConstGetValueI64High(BinaryenExpressionRef expr) {
if (tracing) {
- std::cout << " BinaryenConstGetValueI64High(expressions[" << expressions[expr] << "]);\n";
+ std::cout << " BinaryenConstGetValueI64High(expressions["
+ << expressions[expr] << "]);\n";
}
auto* expression = (Expression*)expr;
@@ -1600,7 +2022,8 @@ int32_t BinaryenConstGetValueI64High(BinaryenExpressionRef expr) {
}
float BinaryenConstGetValueF32(BinaryenExpressionRef expr) {
if (tracing) {
- std::cout << " BinaryenConstGetValueF32(expressions[" << expressions[expr] << "]);\n";
+ std::cout << " BinaryenConstGetValueF32(expressions[" << expressions[expr]
+ << "]);\n";
}
auto* expression = (Expression*)expr;
@@ -1609,7 +2032,8 @@ float BinaryenConstGetValueF32(BinaryenExpressionRef expr) {
}
double BinaryenConstGetValueF64(BinaryenExpressionRef expr) {
if (tracing) {
- std::cout << " BinaryenConstGetValueF64(expressions[" << expressions[expr] << "]);\n";
+ std::cout << " BinaryenConstGetValueF64(expressions[" << expressions[expr]
+ << "]);\n";
}
auto* expression = (Expression*)expr;
@@ -1618,7 +2042,8 @@ double BinaryenConstGetValueF64(BinaryenExpressionRef expr) {
}
void BinaryenConstGetValueV128(BinaryenExpressionRef expr, uint8_t* out) {
if (tracing) {
- std::cout << " BinaryenConstGetValueV128(expressions[" << expressions[expr] << "], " << out << ");\n";
+ std::cout << " BinaryenConstGetValueV128(expressions[" << expressions[expr]
+ << "], " << out << ");\n";
}
auto* expression = (Expression*)expr;
@@ -1628,7 +2053,8 @@ void BinaryenConstGetValueV128(BinaryenExpressionRef expr, uint8_t* out) {
// Unary
BinaryenOp BinaryenUnaryGetOp(BinaryenExpressionRef expr) {
if (tracing) {
- std::cout << " BinaryenUnaryGetOp(expressions[" << expressions[expr] << "]);\n";
+ std::cout << " BinaryenUnaryGetOp(expressions[" << expressions[expr]
+ << "]);\n";
}
auto* expression = (Expression*)expr;
@@ -1637,7 +2063,8 @@ BinaryenOp BinaryenUnaryGetOp(BinaryenExpressionRef expr) {
}
BinaryenExpressionRef BinaryenUnaryGetValue(BinaryenExpressionRef expr) {
if (tracing) {
- std::cout << " BinaryenUnaryGetValue(expressions[" << expressions[expr] << "]);\n";
+ std::cout << " BinaryenUnaryGetValue(expressions[" << expressions[expr]
+ << "]);\n";
}
auto* expression = (Expression*)expr;
@@ -1647,7 +2074,8 @@ BinaryenExpressionRef BinaryenUnaryGetValue(BinaryenExpressionRef expr) {
// Binary
BinaryenOp BinaryenBinaryGetOp(BinaryenExpressionRef expr) {
if (tracing) {
- std::cout << " BinaryenBinaryGetOp(expressions[" << expressions[expr] << "]);\n";
+ std::cout << " BinaryenBinaryGetOp(expressions[" << expressions[expr]
+ << "]);\n";
}
auto* expression = (Expression*)expr;
@@ -1656,7 +2084,8 @@ BinaryenOp BinaryenBinaryGetOp(BinaryenExpressionRef expr) {
}
BinaryenExpressionRef BinaryenBinaryGetLeft(BinaryenExpressionRef expr) {
if (tracing) {
- std::cout << " BinaryenBinaryGetLeft(expressions[" << expressions[expr] << "]);\n";
+ std::cout << " BinaryenBinaryGetLeft(expressions[" << expressions[expr]
+ << "]);\n";
}
auto* expression = (Expression*)expr;
@@ -1665,7 +2094,8 @@ BinaryenExpressionRef BinaryenBinaryGetLeft(BinaryenExpressionRef expr) {
}
BinaryenExpressionRef BinaryenBinaryGetRight(BinaryenExpressionRef expr) {
if (tracing) {
- std::cout << " BinaryenBinaryGetRight(expressions[" << expressions[expr] << "]);\n";
+ std::cout << " BinaryenBinaryGetRight(expressions[" << expressions[expr]
+ << "]);\n";
}
auto* expression = (Expression*)expr;
@@ -1675,7 +2105,8 @@ BinaryenExpressionRef BinaryenBinaryGetRight(BinaryenExpressionRef expr) {
// Select
BinaryenExpressionRef BinaryenSelectGetIfTrue(BinaryenExpressionRef expr) {
if (tracing) {
- std::cout << " BinaryenSelectGetIfTrue(expressions[" << expressions[expr] << "]);\n";
+ std::cout << " BinaryenSelectGetIfTrue(expressions[" << expressions[expr]
+ << "]);\n";
}
auto* expression = (Expression*)expr;
@@ -1684,7 +2115,8 @@ BinaryenExpressionRef BinaryenSelectGetIfTrue(BinaryenExpressionRef expr) {
}
BinaryenExpressionRef BinaryenSelectGetIfFalse(BinaryenExpressionRef expr) {
if (tracing) {
- std::cout << " BinaryenSelectGetIfFalse(expressions[" << expressions[expr] << "]);\n";
+ std::cout << " BinaryenSelectGetIfFalse(expressions[" << expressions[expr]
+ << "]);\n";
}
auto* expression = (Expression*)expr;
@@ -1693,7 +2125,8 @@ BinaryenExpressionRef BinaryenSelectGetIfFalse(BinaryenExpressionRef expr) {
}
BinaryenExpressionRef BinaryenSelectGetCondition(BinaryenExpressionRef expr) {
if (tracing) {
- std::cout << " BinaryenSelectGetCondition(expressions[" << expressions[expr] << "]);\n";
+ std::cout << " BinaryenSelectGetCondition(expressions["
+ << expressions[expr] << "]);\n";
}
auto* expression = (Expression*)expr;
@@ -1703,7 +2136,8 @@ BinaryenExpressionRef BinaryenSelectGetCondition(BinaryenExpressionRef expr) {
// Drop
BinaryenExpressionRef BinaryenDropGetValue(BinaryenExpressionRef expr) {
if (tracing) {
- std::cout << " BinaryenDropGetValue(expressions[" << expressions[expr] << "]);\n";
+ std::cout << " BinaryenDropGetValue(expressions[" << expressions[expr]
+ << "]);\n";
}
auto* expression = (Expression*)expr;
@@ -1713,7 +2147,8 @@ BinaryenExpressionRef BinaryenDropGetValue(BinaryenExpressionRef expr) {
// Return
BinaryenExpressionRef BinaryenReturnGetValue(BinaryenExpressionRef expr) {
if (tracing) {
- std::cout << " BinaryenReturnGetValue(expressions[" << expressions[expr] << "]);\n";
+ std::cout << " BinaryenReturnGetValue(expressions[" << expressions[expr]
+ << "]);\n";
}
auto* expression = (Expression*)expr;
@@ -1723,7 +2158,8 @@ BinaryenExpressionRef BinaryenReturnGetValue(BinaryenExpressionRef expr) {
// AtomicRMW
BinaryenOp BinaryenAtomicRMWGetOp(BinaryenExpressionRef expr) {
if (tracing) {
- std::cout << " BinaryenAtomicRMWGetOp(expressions[" << expressions[expr] << "]);\n";
+ std::cout << " BinaryenAtomicRMWGetOp(expressions[" << expressions[expr]
+ << "]);\n";
}
auto* expression = (Expression*)expr;
@@ -1732,7 +2168,8 @@ BinaryenOp BinaryenAtomicRMWGetOp(BinaryenExpressionRef expr) {
}
uint32_t BinaryenAtomicRMWGetBytes(BinaryenExpressionRef expr) {
if (tracing) {
- std::cout << " BinaryenAtomicRMWGetBytes(expressions[" << expressions[expr] << "]);\n";
+ std::cout << " BinaryenAtomicRMWGetBytes(expressions[" << expressions[expr]
+ << "]);\n";
}
auto* expression = (Expression*)expr;
@@ -1741,7 +2178,8 @@ uint32_t BinaryenAtomicRMWGetBytes(BinaryenExpressionRef expr) {
}
uint32_t BinaryenAtomicRMWGetOffset(BinaryenExpressionRef expr) {
if (tracing) {
- std::cout << " BinaryenAtomicRMWGetOffset(expressions[" << expressions[expr] << "]);\n";
+ std::cout << " BinaryenAtomicRMWGetOffset(expressions["
+ << expressions[expr] << "]);\n";
}
auto* expression = (Expression*)expr;
@@ -1750,7 +2188,8 @@ uint32_t BinaryenAtomicRMWGetOffset(BinaryenExpressionRef expr) {
}
BinaryenExpressionRef BinaryenAtomicRMWGetPtr(BinaryenExpressionRef expr) {
if (tracing) {
- std::cout << " BinaryenAtomicRMWGetPtr(expressions[" << expressions[expr] << "]);\n";
+ std::cout << " BinaryenAtomicRMWGetPtr(expressions[" << expressions[expr]
+ << "]);\n";
}
auto* expression = (Expression*)expr;
@@ -1759,7 +2198,8 @@ BinaryenExpressionRef BinaryenAtomicRMWGetPtr(BinaryenExpressionRef expr) {
}
BinaryenExpressionRef BinaryenAtomicRMWGetValue(BinaryenExpressionRef expr) {
if (tracing) {
- std::cout << " BinaryenAtomicRMWGetValue(expressions[" << expressions[expr] << "]);\n";
+ std::cout << " BinaryenAtomicRMWGetValue(expressions[" << expressions[expr]
+ << "]);\n";
}
auto* expression = (Expression*)expr;
@@ -1769,7 +2209,8 @@ BinaryenExpressionRef BinaryenAtomicRMWGetValue(BinaryenExpressionRef expr) {
// AtomicCmpxchg
uint32_t BinaryenAtomicCmpxchgGetBytes(BinaryenExpressionRef expr) {
if (tracing) {
- std::cout << " BinaryenAtomicCmpxchgGetBytes(expressions[" << expressions[expr] << "]);\n";
+ std::cout << " BinaryenAtomicCmpxchgGetBytes(expressions["
+ << expressions[expr] << "]);\n";
}
auto* expression = (Expression*)expr;
@@ -1778,7 +2219,8 @@ uint32_t BinaryenAtomicCmpxchgGetBytes(BinaryenExpressionRef expr) {
}
uint32_t BinaryenAtomicCmpxchgGetOffset(BinaryenExpressionRef expr) {
if (tracing) {
- std::cout << " BinaryenAtomicCmpxchgGetOffset(expressions[" << expressions[expr] << "]);\n";
+ std::cout << " BinaryenAtomicCmpxchgGetOffset(expressions["
+ << expressions[expr] << "]);\n";
}
auto* expression = (Expression*)expr;
@@ -1787,25 +2229,30 @@ uint32_t BinaryenAtomicCmpxchgGetOffset(BinaryenExpressionRef expr) {
}
BinaryenExpressionRef BinaryenAtomicCmpxchgGetPtr(BinaryenExpressionRef expr) {
if (tracing) {
- std::cout << " BinaryenAtomicCmpxchgGetPtr(expressions[" << expressions[expr] << "]);\n";
+ std::cout << " BinaryenAtomicCmpxchgGetPtr(expressions["
+ << expressions[expr] << "]);\n";
}
auto* expression = (Expression*)expr;
assert(expression->is<AtomicCmpxchg>());
return static_cast<AtomicCmpxchg*>(expression)->ptr;
}
-BinaryenExpressionRef BinaryenAtomicCmpxchgGetExpected(BinaryenExpressionRef expr) {
+BinaryenExpressionRef
+BinaryenAtomicCmpxchgGetExpected(BinaryenExpressionRef expr) {
if (tracing) {
- std::cout << " BinaryenAtomicCmpxchgGetExpected(expressions[" << expressions[expr] << "]);\n";
+ std::cout << " BinaryenAtomicCmpxchgGetExpected(expressions["
+ << expressions[expr] << "]);\n";
}
auto* expression = (Expression*)expr;
assert(expression->is<AtomicCmpxchg>());
return static_cast<AtomicCmpxchg*>(expression)->expected;
}
-BinaryenExpressionRef BinaryenAtomicCmpxchgGetReplacement(BinaryenExpressionRef expr) {
+BinaryenExpressionRef
+BinaryenAtomicCmpxchgGetReplacement(BinaryenExpressionRef expr) {
if (tracing) {
- std::cout << " BinaryenAtomicCmpxchgGetReplacement(expressions[" << expressions[expr] << "]);\n";
+ std::cout << " BinaryenAtomicCmpxchgGetReplacement(expressions["
+ << expressions[expr] << "]);\n";
}
auto* expression = (Expression*)expr;
@@ -1815,16 +2262,19 @@ BinaryenExpressionRef BinaryenAtomicCmpxchgGetReplacement(BinaryenExpressionRef
// AtomicWait
BinaryenExpressionRef BinaryenAtomicWaitGetPtr(BinaryenExpressionRef expr) {
if (tracing) {
- std::cout << " BinaryenAtomicWaitGetPtr(expressions[" << expressions[expr] << "]);\n";
+ std::cout << " BinaryenAtomicWaitGetPtr(expressions[" << expressions[expr]
+ << "]);\n";
}
auto* expression = (Expression*)expr;
assert(expression->is<AtomicWait>());
return static_cast<AtomicWait*>(expression)->ptr;
}
-BinaryenExpressionRef BinaryenAtomicWaitGetExpected(BinaryenExpressionRef expr) {
+BinaryenExpressionRef
+BinaryenAtomicWaitGetExpected(BinaryenExpressionRef expr) {
if (tracing) {
- std::cout << " BinaryenAtomicWaitGetExpected(expressions[" << expressions[expr] << "]);\n";
+ std::cout << " BinaryenAtomicWaitGetExpected(expressions["
+ << expressions[expr] << "]);\n";
}
auto* expression = (Expression*)expr;
@@ -1833,7 +2283,8 @@ BinaryenExpressionRef BinaryenAtomicWaitGetExpected(BinaryenExpressionRef expr)
}
BinaryenExpressionRef BinaryenAtomicWaitGetTimeout(BinaryenExpressionRef expr) {
if (tracing) {
- std::cout << " BinaryenAtomicWaitGetTimeout(expressions[" << expressions[expr] << "]);\n";
+ std::cout << " BinaryenAtomicWaitGetTimeout(expressions["
+ << expressions[expr] << "]);\n";
}
auto* expression = (Expression*)expr;
@@ -1842,7 +2293,8 @@ BinaryenExpressionRef BinaryenAtomicWaitGetTimeout(BinaryenExpressionRef expr) {
}
BinaryenType BinaryenAtomicWaitGetExpectedType(BinaryenExpressionRef expr) {
if (tracing) {
- std::cout << " BinaryenAtomicWaitGetExpectedType(expressions[" << expressions[expr] << "]);\n";
+ std::cout << " BinaryenAtomicWaitGetExpectedType(expressions["
+ << expressions[expr] << "]);\n";
}
auto* expression = (Expression*)expr;
@@ -1852,16 +2304,19 @@ BinaryenType BinaryenAtomicWaitGetExpectedType(BinaryenExpressionRef expr) {
// AtomicNotify
BinaryenExpressionRef BinaryenAtomicNotifyGetPtr(BinaryenExpressionRef expr) {
if (tracing) {
- std::cout << " BinaryenAtomicNotifyGetPtr(expressions[" << expressions[expr] << "]);\n";
+ std::cout << " BinaryenAtomicNotifyGetPtr(expressions["
+ << expressions[expr] << "]);\n";
}
auto* expression = (Expression*)expr;
assert(expression->is<AtomicNotify>());
return static_cast<AtomicNotify*>(expression)->ptr;
}
-BinaryenExpressionRef BinaryenAtomicNotifyGetNotifyCount(BinaryenExpressionRef expr) {
+BinaryenExpressionRef
+BinaryenAtomicNotifyGetNotifyCount(BinaryenExpressionRef expr) {
if (tracing) {
- std::cout << " BinaryenAtomicNotifyGetNotifyCount(expressions[" << expressions[expr] << "]);\n";
+ std::cout << " BinaryenAtomicNotifyGetNotifyCount(expressions["
+ << expressions[expr] << "]);\n";
}
auto* expression = (Expression*)expr;
@@ -1871,7 +2326,8 @@ BinaryenExpressionRef BinaryenAtomicNotifyGetNotifyCount(BinaryenExpressionRef e
// SIMDExtract
BinaryenOp BinaryenSIMDExtractGetOp(BinaryenExpressionRef expr) {
if (tracing) {
- std::cout << " BinaryenSIMDExtractGetOp(expressions[" << expressions[expr] << "]);\n";
+ std::cout << " BinaryenSIMDExtractGetOp(expressions[" << expressions[expr]
+ << "]);\n";
}
auto* expression = (Expression*)expr;
@@ -1880,7 +2336,8 @@ BinaryenOp BinaryenSIMDExtractGetOp(BinaryenExpressionRef expr) {
}
BinaryenExpressionRef BinaryenSIMDExtractGetVec(BinaryenExpressionRef expr) {
if (tracing) {
- std::cout << " BinaryenSIMDExtractGetVec(expressions[" << expressions[expr] << "]);\n";
+ std::cout << " BinaryenSIMDExtractGetVec(expressions[" << expressions[expr]
+ << "]);\n";
}
auto* expression = (Expression*)expr;
@@ -1889,7 +2346,8 @@ BinaryenExpressionRef BinaryenSIMDExtractGetVec(BinaryenExpressionRef expr) {
}
uint8_t BinaryenSIMDExtractGetIndex(BinaryenExpressionRef expr) {
if (tracing) {
- std::cout << " BinaryenSIMDExtractGetIndex(expressions[" << expressions[expr] << "]);\n";
+ std::cout << " BinaryenSIMDExtractGetIndex(expressions["
+ << expressions[expr] << "]);\n";
}
auto* expression = (Expression*)expr;
@@ -1899,7 +2357,8 @@ uint8_t BinaryenSIMDExtractGetIndex(BinaryenExpressionRef expr) {
// SIMDReplace
BinaryenOp BinaryenSIMDReplaceGetOp(BinaryenExpressionRef expr) {
if (tracing) {
- std::cout << " BinaryenSIMDReplaceGetOp(expressions[" << expressions[expr] << "]);\n";
+ std::cout << " BinaryenSIMDReplaceGetOp(expressions[" << expressions[expr]
+ << "]);\n";
}
auto* expression = (Expression*)expr;
@@ -1908,7 +2367,8 @@ BinaryenOp BinaryenSIMDReplaceGetOp(BinaryenExpressionRef expr) {
}
BinaryenExpressionRef BinaryenSIMDReplaceGetVec(BinaryenExpressionRef expr) {
if (tracing) {
- std::cout << " BinaryenSIMDReplaceGetVec(expressions[" << expressions[expr] << "]);\n";
+ std::cout << " BinaryenSIMDReplaceGetVec(expressions[" << expressions[expr]
+ << "]);\n";
}
auto* expression = (Expression*)expr;
@@ -1917,7 +2377,8 @@ BinaryenExpressionRef BinaryenSIMDReplaceGetVec(BinaryenExpressionRef expr) {
}
uint8_t BinaryenSIMDReplaceGetIndex(BinaryenExpressionRef expr) {
if (tracing) {
- std::cout << " BinaryenSIMDReplaceGetIndex(expressions[" << expressions[expr] << "]);\n";
+ std::cout << " BinaryenSIMDReplaceGetIndex(expressions["
+ << expressions[expr] << "]);\n";
}
auto* expression = (Expression*)expr;
@@ -1926,7 +2387,8 @@ uint8_t BinaryenSIMDReplaceGetIndex(BinaryenExpressionRef expr) {
}
BinaryenExpressionRef BinaryenSIMDReplaceGetValue(BinaryenExpressionRef expr) {
if (tracing) {
- std::cout << " BinaryenSIMDReplaceGetValue(expressions[" << expressions[expr] << "]);\n";
+ std::cout << " BinaryenSIMDReplaceGetValue(expressions["
+ << expressions[expr] << "]);\n";
}
auto* expression = (Expression*)expr;
@@ -1936,7 +2398,8 @@ BinaryenExpressionRef BinaryenSIMDReplaceGetValue(BinaryenExpressionRef expr) {
// SIMDShuffle
BinaryenExpressionRef BinaryenSIMDShuffleGetLeft(BinaryenExpressionRef expr) {
if (tracing) {
- std::cout << " BinaryenSIMDShuffleGetLeft(expressions[" << expressions[expr] << "]);\n";
+ std::cout << " BinaryenSIMDShuffleGetLeft(expressions["
+ << expressions[expr] << "]);\n";
}
auto* expression = (Expression*)expr;
@@ -1945,16 +2408,18 @@ BinaryenExpressionRef BinaryenSIMDShuffleGetLeft(BinaryenExpressionRef expr) {
}
BinaryenExpressionRef BinaryenSIMDShuffleGetRight(BinaryenExpressionRef expr) {
if (tracing) {
- std::cout << " BinaryenSIMDShuffleGetRight(expressions[" << expressions[expr] << "]);\n";
+ std::cout << " BinaryenSIMDShuffleGetRight(expressions["
+ << expressions[expr] << "]);\n";
}
auto* expression = (Expression*)expr;
assert(expression->is<SIMDShuffle>());
return static_cast<SIMDShuffle*>(expression)->right;
}
-void BinaryenSIMDShuffleGetMask(BinaryenExpressionRef expr, uint8_t *mask) {
+void BinaryenSIMDShuffleGetMask(BinaryenExpressionRef expr, uint8_t* mask) {
if (tracing) {
- std::cout << " BinaryenSIMDShuffleGetMask(expressions[" << expressions[expr] << "], " << mask << ");\n";
+ std::cout << " BinaryenSIMDShuffleGetMask(expressions["
+ << expressions[expr] << "], " << mask << ");\n";
}
auto* expression = (Expression*)expr;
@@ -1964,16 +2429,19 @@ void BinaryenSIMDShuffleGetMask(BinaryenExpressionRef expr, uint8_t *mask) {
// SIMDBitselect
BinaryenExpressionRef BinaryenSIMDBitselectGetLeft(BinaryenExpressionRef expr) {
if (tracing) {
- std::cout << " BinaryenSIMDBitselectGetLeft(expressions[" << expressions[expr] << "]);\n";
+ std::cout << " BinaryenSIMDBitselectGetLeft(expressions["
+ << expressions[expr] << "]);\n";
}
auto* expression = (Expression*)expr;
assert(expression->is<SIMDBitselect>());
return static_cast<SIMDBitselect*>(expression)->left;
}
-BinaryenExpressionRef BinaryenSIMDBitselectGetRight(BinaryenExpressionRef expr) {
+BinaryenExpressionRef
+BinaryenSIMDBitselectGetRight(BinaryenExpressionRef expr) {
if (tracing) {
- std::cout << " BinaryenSIMDBitselectGetRight(expressions[" << expressions[expr] << "]);\n";
+ std::cout << " BinaryenSIMDBitselectGetRight(expressions["
+ << expressions[expr] << "]);\n";
}
auto* expression = (Expression*)expr;
@@ -1982,7 +2450,8 @@ BinaryenExpressionRef BinaryenSIMDBitselectGetRight(BinaryenExpressionRef expr)
}
BinaryenExpressionRef BinaryenSIMDBitselectGetCond(BinaryenExpressionRef expr) {
if (tracing) {
- std::cout << " BinaryenSIMDBitselectGetCond(expressions[" << expressions[expr] << "]);\n";
+ std::cout << " BinaryenSIMDBitselectGetCond(expressions["
+ << expressions[expr] << "]);\n";
}
auto* expression = (Expression*)expr;
@@ -1992,7 +2461,8 @@ BinaryenExpressionRef BinaryenSIMDBitselectGetCond(BinaryenExpressionRef expr) {
// SIMDShift
BinaryenOp BinaryenSIMDShiftGetOp(BinaryenExpressionRef expr) {
if (tracing) {
- std::cout << " BinaryenSIMDShiftGetOp(expressions[" << expressions[expr] << "]);\n";
+ std::cout << " BinaryenSIMDShiftGetOp(expressions[" << expressions[expr]
+ << "]);\n";
}
auto* expression = (Expression*)expr;
@@ -2001,7 +2471,8 @@ BinaryenOp BinaryenSIMDShiftGetOp(BinaryenExpressionRef expr) {
}
BinaryenExpressionRef BinaryenSIMDShiftGetVec(BinaryenExpressionRef expr) {
if (tracing) {
- std::cout << " BinaryenSIMDShiftGetVec(expressions[" << expressions[expr] << "]);\n";
+ std::cout << " BinaryenSIMDShiftGetVec(expressions[" << expressions[expr]
+ << "]);\n";
}
auto* expression = (Expression*)expr;
@@ -2010,7 +2481,8 @@ BinaryenExpressionRef BinaryenSIMDShiftGetVec(BinaryenExpressionRef expr) {
}
BinaryenExpressionRef BinaryenSIMDShiftGetShift(BinaryenExpressionRef expr) {
if (tracing) {
- std::cout << " BinaryenSIMDShiftGetShift(expressions[" << expressions[expr] << "]);\n";
+ std::cout << " BinaryenSIMDShiftGetShift(expressions[" << expressions[expr]
+ << "]);\n";
}
auto* expression = (Expression*)expr;
@@ -2020,7 +2492,8 @@ BinaryenExpressionRef BinaryenSIMDShiftGetShift(BinaryenExpressionRef expr) {
// MemoryInit
uint32_t BinaryenMemoryInitGetSegment(BinaryenExpressionRef expr) {
if (tracing) {
- std::cout << " BinaryenMemoryInitGetSegment(expressions[" << expressions[expr] << "]);\n";
+ std::cout << " BinaryenMemoryInitGetSegment(expressions["
+ << expressions[expr] << "]);\n";
}
auto* expression = (Expression*)expr;
@@ -2029,7 +2502,8 @@ uint32_t BinaryenMemoryInitGetSegment(BinaryenExpressionRef expr) {
}
BinaryenExpressionRef BinaryenMemoryInitGetDest(BinaryenExpressionRef expr) {
if (tracing) {
- std::cout << " BinaryenMemoryInitGetDest(expressions[" << expressions[expr] << "]);\n";
+ std::cout << " BinaryenMemoryInitGetDest(expressions[" << expressions[expr]
+ << "]);\n";
}
auto* expression = (Expression*)expr;
@@ -2038,7 +2512,8 @@ BinaryenExpressionRef BinaryenMemoryInitGetDest(BinaryenExpressionRef expr) {
}
BinaryenExpressionRef BinaryenMemoryInitGetOffset(BinaryenExpressionRef expr) {
if (tracing) {
- std::cout << " BinaryenMemoryInitGetOffset(expressions[" << expressions[expr] << "]);\n";
+ std::cout << " BinaryenMemoryInitGetOffset(expressions["
+ << expressions[expr] << "]);\n";
}
auto* expression = (Expression*)expr;
@@ -2047,7 +2522,8 @@ BinaryenExpressionRef BinaryenMemoryInitGetOffset(BinaryenExpressionRef expr) {
}
BinaryenExpressionRef BinaryenMemoryInitGetSize(BinaryenExpressionRef expr) {
if (tracing) {
- std::cout << " BinaryenMemoryInitGetSize(expressions[" << expressions[expr] << "]);\n";
+ std::cout << " BinaryenMemoryInitGetSize(expressions[" << expressions[expr]
+ << "]);\n";
}
auto* expression = (Expression*)expr;
@@ -2057,7 +2533,8 @@ BinaryenExpressionRef BinaryenMemoryInitGetSize(BinaryenExpressionRef expr) {
// DataDrop
uint32_t BinaryenDataDropGetSegment(BinaryenExpressionRef expr) {
if (tracing) {
- std::cout << " BinaryenDataDropGetSegment(expressions[" << expressions[expr] << "]);\n";
+ std::cout << " BinaryenDataDropGetSegment(expressions["
+ << expressions[expr] << "]);\n";
}
auto* expression = (Expression*)expr;
@@ -2067,7 +2544,8 @@ uint32_t BinaryenDataDropGetSegment(BinaryenExpressionRef expr) {
// MemoryCopy
BinaryenExpressionRef BinaryenMemoryCopyGetDest(BinaryenExpressionRef expr) {
if (tracing) {
- std::cout << " BinaryenMemoryCopyGetDest(expressions[" << expressions[expr] << "]);\n";
+ std::cout << " BinaryenMemoryCopyGetDest(expressions[" << expressions[expr]
+ << "]);\n";
}
auto* expression = (Expression*)expr;
@@ -2076,7 +2554,8 @@ BinaryenExpressionRef BinaryenMemoryCopyGetDest(BinaryenExpressionRef expr) {
}
BinaryenExpressionRef BinaryenMemoryCopyGetSource(BinaryenExpressionRef expr) {
if (tracing) {
- std::cout << " BinaryenMemoryCopyGetSource(expressions[" << expressions[expr] << "]);\n";
+ std::cout << " BinaryenMemoryCopyGetSource(expressions["
+ << expressions[expr] << "]);\n";
}
auto* expression = (Expression*)expr;
@@ -2085,7 +2564,8 @@ BinaryenExpressionRef BinaryenMemoryCopyGetSource(BinaryenExpressionRef expr) {
}
BinaryenExpressionRef BinaryenMemoryCopyGetSize(BinaryenExpressionRef expr) {
if (tracing) {
- std::cout << " BinaryenMemoryCopyGetSize(expressions[" << expressions[expr] << "]);\n";
+ std::cout << " BinaryenMemoryCopyGetSize(expressions[" << expressions[expr]
+ << "]);\n";
}
auto* expression = (Expression*)expr;
@@ -2095,7 +2575,8 @@ BinaryenExpressionRef BinaryenMemoryCopyGetSize(BinaryenExpressionRef expr) {
// MemoryFill
BinaryenExpressionRef BinaryenMemoryFillGetDest(BinaryenExpressionRef expr) {
if (tracing) {
- std::cout << " BinaryenMemoryFillGetDest(expressions[" << expressions[expr] << "]);\n";
+ std::cout << " BinaryenMemoryFillGetDest(expressions[" << expressions[expr]
+ << "]);\n";
}
auto* expression = (Expression*)expr;
@@ -2104,7 +2585,8 @@ BinaryenExpressionRef BinaryenMemoryFillGetDest(BinaryenExpressionRef expr) {
}
BinaryenExpressionRef BinaryenMemoryFillGetValue(BinaryenExpressionRef expr) {
if (tracing) {
- std::cout << " BinaryenMemoryFillGetValue(expressions[" << expressions[expr] << "]);\n";
+ std::cout << " BinaryenMemoryFillGetValue(expressions["
+ << expressions[expr] << "]);\n";
}
auto* expression = (Expression*)expr;
@@ -2113,7 +2595,8 @@ BinaryenExpressionRef BinaryenMemoryFillGetValue(BinaryenExpressionRef expr) {
}
BinaryenExpressionRef BinaryenMemoryFillGetSize(BinaryenExpressionRef expr) {
if (tracing) {
- std::cout << " BinaryenMemoryFillGetSize(expressions[" << expressions[expr] << "]);\n";
+ std::cout << " BinaryenMemoryFillGetSize(expressions[" << expressions[expr]
+ << "]);\n";
}
auto* expression = (Expression*)expr;
@@ -2123,7 +2606,12 @@ BinaryenExpressionRef BinaryenMemoryFillGetSize(BinaryenExpressionRef expr) {
// Functions
-BinaryenFunctionRef BinaryenAddFunction(BinaryenModuleRef module, const char* name, BinaryenFunctionTypeRef type, BinaryenType* varTypes, BinaryenIndex numVarTypes, BinaryenExpressionRef body) {
+BinaryenFunctionRef BinaryenAddFunction(BinaryenModuleRef module,
+ const char* name,
+ BinaryenFunctionTypeRef type,
+ BinaryenType* varTypes,
+ BinaryenIndex numVarTypes,
+ BinaryenExpressionRef body) {
auto* wasm = (Module*)module;
auto* ret = new Function;
@@ -2131,14 +2619,21 @@ BinaryenFunctionRef BinaryenAddFunction(BinaryenModuleRef module, const char* na
std::cout << " {\n";
std::cout << " BinaryenType varTypes[] = { ";
for (BinaryenIndex i = 0; i < numVarTypes; i++) {
- if (i > 0) std::cout << ", ";
+ if (i > 0)
+ std::cout << ", ";
std::cout << varTypes[i];
}
- if (numVarTypes == 0) std::cout << "0"; // ensure the array is not empty, otherwise a compiler error on VS
+ if (numVarTypes == 0)
+ // ensure the array is not empty, otherwise a compiler error on VS
+ std::cout << "0";
std::cout << " };\n";
auto id = functions.size();
functions[ret] = id;
- std::cout << " functions[" << id << "] = BinaryenAddFunction(the_module, \"" << name << "\", functionTypes[" << functionTypes[type] << "], varTypes, " << numVarTypes << ", expressions[" << expressions[body] << "]);\n";
+ std::cout << " functions[" << id
+ << "] = BinaryenAddFunction(the_module, \"" << name
+ << "\", functionTypes[" << functionTypes[type] << "], varTypes, "
+ << numVarTypes << ", expressions[" << expressions[body]
+ << "]);\n";
std::cout << " }\n";
}
@@ -2161,7 +2656,8 @@ BinaryenFunctionRef BinaryenAddFunction(BinaryenModuleRef module, const char* na
return ret;
}
-BinaryenFunctionRef BinaryenGetFunction(BinaryenModuleRef module, const char* name) {
+BinaryenFunctionRef BinaryenGetFunction(BinaryenModuleRef module,
+ const char* name) {
if (tracing) {
std::cout << " BinaryenGetFunction(the_module, \"" << name << "\");\n";
}
@@ -2178,9 +2674,15 @@ void BinaryenRemoveFunction(BinaryenModuleRef module, const char* name) {
wasm->removeFunction(name);
}
-BinaryenGlobalRef BinaryenAddGlobal(BinaryenModuleRef module, const char* name, BinaryenType type, int8_t mutable_, BinaryenExpressionRef init) {
+BinaryenGlobalRef BinaryenAddGlobal(BinaryenModuleRef module,
+ const char* name,
+ BinaryenType type,
+ int8_t mutable_,
+ BinaryenExpressionRef init) {
if (tracing) {
- std::cout << " BinaryenAddGlobal(the_module, \"" << name << "\", " << type << ", " << int(mutable_) << ", expressions[" << expressions[init] << "]);\n";
+ std::cout << " BinaryenAddGlobal(the_module, \"" << name << "\", " << type
+ << ", " << int(mutable_) << ", expressions[" << expressions[init]
+ << "]);\n";
}
auto* wasm = (Module*)module;
@@ -2203,12 +2705,18 @@ void BinaryenRemoveGlobal(BinaryenModuleRef module, const char* name) {
// Imports
-void BinaryenAddFunctionImport(BinaryenModuleRef module, const char* internalName, const char* externalModuleName, const char* externalBaseName, BinaryenFunctionTypeRef functionType) {
+void BinaryenAddFunctionImport(BinaryenModuleRef module,
+ const char* internalName,
+ const char* externalModuleName,
+ const char* externalBaseName,
+ BinaryenFunctionTypeRef functionType) {
auto* wasm = (Module*)module;
auto* ret = new Function();
if (tracing) {
- std::cout << " BinaryenAddFunctionImport(the_module, \"" << internalName << "\", \"" << externalModuleName << "\", \"" << externalBaseName << "\", functionTypes[" << functionTypes[functionType] << "]);\n";
+ std::cout << " BinaryenAddFunctionImport(the_module, \"" << internalName
+ << "\", \"" << externalModuleName << "\", \"" << externalBaseName
+ << "\", functionTypes[" << functionTypes[functionType] << "]);\n";
}
ret->name = internalName;
@@ -2218,33 +2726,50 @@ void BinaryenAddFunctionImport(BinaryenModuleRef module, const char* internalNam
FunctionTypeUtils::fillFunction(ret, (FunctionType*)functionType);
wasm->addFunction(ret);
}
-void BinaryenAddTableImport(BinaryenModuleRef module, const char* internalName, const char* externalModuleName, const char* externalBaseName) {
+void BinaryenAddTableImport(BinaryenModuleRef module,
+ const char* internalName,
+ const char* externalModuleName,
+ const char* externalBaseName) {
auto* wasm = (Module*)module;
if (tracing) {
- std::cout << " BinaryenAddTableImport(the_module, \"" << internalName << "\", \"" << externalModuleName << "\", \"" << externalBaseName << "\");\n";
+ std::cout << " BinaryenAddTableImport(the_module, \"" << internalName
+ << "\", \"" << externalModuleName << "\", \"" << externalBaseName
+ << "\");\n";
}
wasm->table.module = externalModuleName;
wasm->table.base = externalBaseName;
}
-void BinaryenAddMemoryImport(BinaryenModuleRef module, const char* internalName, const char* externalModuleName, const char* externalBaseName, uint8_t shared) {
+void BinaryenAddMemoryImport(BinaryenModuleRef module,
+ const char* internalName,
+ const char* externalModuleName,
+ const char* externalBaseName,
+ uint8_t shared) {
auto* wasm = (Module*)module;
if (tracing) {
- std::cout << " BinaryenAddMemoryImport(the_module, \"" << internalName << "\", \"" << externalModuleName << "\", \"" << externalBaseName << "\", " << int(shared) << ");\n";
+ std::cout << " BinaryenAddMemoryImport(the_module, \"" << internalName
+ << "\", \"" << externalModuleName << "\", \"" << externalBaseName
+ << "\", " << int(shared) << ");\n";
}
wasm->memory.module = externalModuleName;
wasm->memory.base = externalBaseName;
wasm->memory.shared = shared;
}
-void BinaryenAddGlobalImport(BinaryenModuleRef module, const char* internalName, const char* externalModuleName, const char* externalBaseName, BinaryenType globalType) {
+void BinaryenAddGlobalImport(BinaryenModuleRef module,
+ const char* internalName,
+ const char* externalModuleName,
+ const char* externalBaseName,
+ BinaryenType globalType) {
auto* wasm = (Module*)module;
auto* ret = new Global();
if (tracing) {
- std::cout << " BinaryenAddGlobalImport(the_module, \"" << internalName << "\", \"" << externalModuleName << "\", \"" << externalBaseName << "\", " << globalType << ");\n";
+ std::cout << " BinaryenAddGlobalImport(the_module, \"" << internalName
+ << "\", \"" << externalModuleName << "\", \"" << externalBaseName
+ << "\", " << globalType << ");\n";
}
ret->name = internalName;
@@ -2256,17 +2781,23 @@ void BinaryenAddGlobalImport(BinaryenModuleRef module, const char* internalName,
// Exports
-WASM_DEPRECATED BinaryenExportRef BinaryenAddExport(BinaryenModuleRef module, const char* internalName, const char* externalName) {
+WASM_DEPRECATED BinaryenExportRef BinaryenAddExport(BinaryenModuleRef module,
+ const char* internalName,
+ const char* externalName) {
return BinaryenAddFunctionExport(module, internalName, externalName);
}
-BinaryenExportRef BinaryenAddFunctionExport(BinaryenModuleRef module, const char* internalName, const char* externalName) {
+BinaryenExportRef BinaryenAddFunctionExport(BinaryenModuleRef module,
+ const char* internalName,
+ const char* externalName) {
auto* wasm = (Module*)module;
auto* ret = new Export();
if (tracing) {
auto id = exports.size();
exports[ret] = id;
- std::cout << " exports[" << id << "] = BinaryenAddFunctionExport(the_module, \"" << internalName << "\", \"" << externalName << "\");\n";
+ std::cout << " exports[" << id
+ << "] = BinaryenAddFunctionExport(the_module, \"" << internalName
+ << "\", \"" << externalName << "\");\n";
}
ret->value = internalName;
@@ -2275,14 +2806,18 @@ BinaryenExportRef BinaryenAddFunctionExport(BinaryenModuleRef module, const char
wasm->addExport(ret);
return ret;
}
-BinaryenExportRef BinaryenAddTableExport(BinaryenModuleRef module, const char* internalName, const char* externalName) {
+BinaryenExportRef BinaryenAddTableExport(BinaryenModuleRef module,
+ const char* internalName,
+ const char* externalName) {
auto* wasm = (Module*)module;
auto* ret = new Export();
if (tracing) {
auto id = exports.size();
exports[ret] = id;
- std::cout << " exports[" << id << "] = BinaryenAddTableExport(the_module, \"" << internalName << "\", \"" << externalName << "\");\n";
+ std::cout << " exports[" << id
+ << "] = BinaryenAddTableExport(the_module, \"" << internalName
+ << "\", \"" << externalName << "\");\n";
}
ret->value = internalName;
@@ -2291,14 +2826,18 @@ BinaryenExportRef BinaryenAddTableExport(BinaryenModuleRef module, const char* i
wasm->addExport(ret);
return ret;
}
-BinaryenExportRef BinaryenAddMemoryExport(BinaryenModuleRef module, const char* internalName, const char* externalName) {
+BinaryenExportRef BinaryenAddMemoryExport(BinaryenModuleRef module,
+ const char* internalName,
+ const char* externalName) {
auto* wasm = (Module*)module;
auto* ret = new Export();
if (tracing) {
auto id = exports.size();
exports[ret] = id;
- std::cout << " exports[" << id << "] = BinaryenAddMemoryExport(the_module, \"" << internalName << "\", \"" << externalName << "\");\n";
+ std::cout << " exports[" << id
+ << "] = BinaryenAddMemoryExport(the_module, \"" << internalName
+ << "\", \"" << externalName << "\");\n";
}
ret->value = internalName;
@@ -2307,14 +2846,18 @@ BinaryenExportRef BinaryenAddMemoryExport(BinaryenModuleRef module, const char*
wasm->addExport(ret);
return ret;
}
-BinaryenExportRef BinaryenAddGlobalExport(BinaryenModuleRef module, const char* internalName, const char* externalName) {
+BinaryenExportRef BinaryenAddGlobalExport(BinaryenModuleRef module,
+ const char* internalName,
+ const char* externalName) {
auto* wasm = (Module*)module;
auto* ret = new Export();
if (tracing) {
auto id = exports.size();
exports[ret] = id;
- std::cout << " exports[" << id << "] = BinaryenAddGlobalExport(the_module, \"" << internalName << "\", \"" << externalName << "\");\n";
+ std::cout << " exports[" << id
+ << "] = BinaryenAddGlobalExport(the_module, \"" << internalName
+ << "\", \"" << externalName << "\");\n";
}
ret->value = internalName;
@@ -2325,7 +2868,8 @@ BinaryenExportRef BinaryenAddGlobalExport(BinaryenModuleRef module, const char*
}
void BinaryenRemoveExport(BinaryenModuleRef module, const char* externalName) {
if (tracing) {
- std::cout << " BinaryenRemoveExport(the_module, \"" << externalName << "\");\n";
+ std::cout << " BinaryenRemoveExport(the_module, \"" << externalName
+ << "\");\n";
}
auto* wasm = (Module*)module;
@@ -2334,21 +2878,28 @@ void BinaryenRemoveExport(BinaryenModuleRef module, const char* externalName) {
// Function table. One per module
-void BinaryenSetFunctionTable(BinaryenModuleRef module, BinaryenIndex initial, BinaryenIndex maximum, const char** funcNames, BinaryenIndex numFuncNames) {
+void BinaryenSetFunctionTable(BinaryenModuleRef module,
+ BinaryenIndex initial,
+ BinaryenIndex maximum,
+ const char** funcNames,
+ BinaryenIndex numFuncNames) {
if (tracing) {
std::cout << " {\n";
std::cout << " const char* funcNames[] = { ";
for (BinaryenIndex i = 0; i < numFuncNames; i++) {
- if (i > 0) std::cout << ", ";
+ if (i > 0)
+ std::cout << ", ";
std::cout << "\"" << funcNames[i] << "\"";
}
std::cout << " };\n";
- std::cout << " BinaryenSetFunctionTable(the_module, " << initial << ", " << maximum << ", funcNames, " << numFuncNames << ");\n";
+ std::cout << " BinaryenSetFunctionTable(the_module, " << initial << ", "
+ << maximum << ", funcNames, " << numFuncNames << ");\n";
std::cout << " }\n";
}
auto* wasm = (Module*)module;
- Table::Segment segment(wasm->allocator.alloc<Const>()->set(Literal(int32_t(0))));
+ Table::Segment segment(
+ wasm->allocator.alloc<Const>()->set(Literal(int32_t(0))));
for (BinaryenIndex i = 0; i < numFuncNames; i++) {
segment.data.push_back(funcNames[i]);
}
@@ -2360,48 +2911,72 @@ void BinaryenSetFunctionTable(BinaryenModuleRef module, BinaryenIndex initial, B
// Memory. One per module
-void BinaryenSetMemory(BinaryenModuleRef module, BinaryenIndex initial, BinaryenIndex maximum, const char* exportName, const char** segments, int8_t* segmentPassive, BinaryenExpressionRef* segmentOffsets, BinaryenIndex* segmentSizes, BinaryenIndex numSegments, uint8_t shared) {
+void BinaryenSetMemory(BinaryenModuleRef module,
+ BinaryenIndex initial,
+ BinaryenIndex maximum,
+ const char* exportName,
+ const char** segments,
+ int8_t* segmentPassive,
+ BinaryenExpressionRef* segmentOffsets,
+ BinaryenIndex* segmentSizes,
+ BinaryenIndex numSegments,
+ uint8_t shared) {
if (tracing) {
std::cout << " {\n";
for (BinaryenIndex i = 0; i < numSegments; i++) {
std::cout << " const char segment" << i << "[] = { ";
for (BinaryenIndex j = 0; j < segmentSizes[i]; j++) {
- if (j > 0) std::cout << ", ";
+ if (j > 0)
+ std::cout << ", ";
std::cout << int(segments[i][j]);
}
std::cout << " };\n";
}
std::cout << " const char* segments[] = { ";
for (BinaryenIndex i = 0; i < numSegments; i++) {
- if (i > 0) std::cout << ", ";
+ if (i > 0)
+ std::cout << ", ";
std::cout << "segment" << i;
}
- if (numSegments == 0) std::cout << "0"; // ensure the array is not empty, otherwise a compiler error on VS
+ if (numSegments == 0)
+ // ensure the array is not empty, otherwise a compiler error on VS
+ std::cout << "0";
std::cout << " };\n";
std::cout << " int8_t segmentPassive[] = { ";
for (BinaryenIndex i = 0; i < numSegments; i++) {
- if (i > 0) std::cout << ", ";
+ if (i > 0)
+ std::cout << ", ";
std::cout << int(segmentPassive[i]);
}
- if (numSegments == 0) std::cout << "0"; // ensure the array is not empty, otherwise a compiler error on VS
+ if (numSegments == 0)
+ // ensure the array is not empty, otherwise a compiler error on VS
+ std::cout << "0";
std::cout << " };\n";
std::cout << " BinaryenExpressionRef segmentOffsets[] = { ";
for (BinaryenIndex i = 0; i < numSegments; i++) {
- if (i > 0) std::cout << ", ";
+ if (i > 0)
+ std::cout << ", ";
std::cout << "expressions[" << expressions[segmentOffsets[i]] << "]";
}
- if (numSegments == 0) std::cout << "0"; // ensure the array is not empty, otherwise a compiler error on VS
+ if (numSegments == 0)
+ // ensure the array is not empty, otherwise a compiler error on VS
+ std::cout << "0";
std::cout << " };\n";
std::cout << " BinaryenIndex segmentSizes[] = { ";
for (BinaryenIndex i = 0; i < numSegments; i++) {
- if (i > 0) std::cout << ", ";
+ if (i > 0)
+ std::cout << ", ";
std::cout << segmentSizes[i];
}
- if (numSegments == 0) std::cout << "0"; // ensure the array is not empty, otherwise a compiler error on VS
+ if (numSegments == 0)
+ // ensure the array is not empty, otherwise a compiler error on VS
+ std::cout << "0";
std::cout << " };\n";
- std::cout << " BinaryenSetMemory(the_module, " << initial << ", " << maximum << ", ";
+ std::cout << " BinaryenSetMemory(the_module, " << initial << ", "
+ << maximum << ", ";
traceNameOrNULL(exportName);
- std::cout << ", segments, segmentPassive, segmentOffsets, segmentSizes, " << numSegments << ", " << int(shared) << ");\n";
+ std::cout << ", segments, segmentPassive, segmentOffsets, segmentSizes, "
+ << numSegments << ", " << int(shared) << ");\n";
std::cout << " }\n";
}
@@ -2418,7 +2993,10 @@ void BinaryenSetMemory(BinaryenModuleRef module, BinaryenIndex initial, Binaryen
wasm->addExport(memoryExport.release());
}
for (BinaryenIndex i = 0; i < numSegments; i++) {
- wasm->memory.segments.emplace_back(segmentPassive[i], (Expression*)segmentOffsets[i], segments[i], segmentSizes[i]);
+ wasm->memory.segments.emplace_back(segmentPassive[i],
+ (Expression*)segmentOffsets[i],
+ segments[i],
+ segmentSizes[i]);
}
}
@@ -2426,7 +3004,8 @@ void BinaryenSetMemory(BinaryenModuleRef module, BinaryenIndex initial, Binaryen
void BinaryenSetStart(BinaryenModuleRef module, BinaryenFunctionRef start) {
if (tracing) {
- std::cout << " BinaryenSetStart(the_module, functions[" << functions[start] << "]);\n";
+ std::cout << " BinaryenSetStart(the_module, functions[" << functions[start]
+ << "]);\n";
}
auto* wasm = (Module*)module;
@@ -2551,16 +3130,20 @@ void BinaryenSetDebugInfo(int on) {
globalPassOptions.debugInfo = on != 0;
}
-void BinaryenModuleRunPasses(BinaryenModuleRef module, const char** passes, BinaryenIndex numPasses) {
+void BinaryenModuleRunPasses(BinaryenModuleRef module,
+ const char** passes,
+ BinaryenIndex numPasses) {
if (tracing) {
std::cout << " {\n";
std::cout << " const char* passes[] = { ";
for (BinaryenIndex i = 0; i < numPasses; i++) {
- if (i > 0) std::cout << ", ";
+ if (i > 0)
+ std::cout << ", ";
std::cout << "\"" << passes[i] << "\"";
}
std::cout << " };\n";
- std::cout << " BinaryenModuleRunPasses(the_module, passes, " << numPasses << ");\n";
+ std::cout << " BinaryenModuleRunPasses(the_module, passes, " << numPasses
+ << ");\n";
std::cout << " }\n";
}
@@ -2585,7 +3168,12 @@ void BinaryenModuleAutoDrop(BinaryenModuleRef module) {
passRunner.run();
}
-static BinaryenBufferSizes writeModule(BinaryenModuleRef module, char* output, size_t outputSize, const char* sourceMapUrl, char* sourceMap, size_t sourceMapSize) {
+static BinaryenBufferSizes writeModule(BinaryenModuleRef module,
+ char* output,
+ size_t outputSize,
+ const char* sourceMapUrl,
+ char* sourceMap,
+ size_t sourceMapSize) {
Module* wasm = (Module*)module;
BufferWithRandomAccess buffer(false);
WasmBinaryWriter writer(wasm, buffer, false);
@@ -2603,28 +3191,38 @@ static BinaryenBufferSizes writeModule(BinaryenModuleRef module, char* output, s
sourceMapBytes = std::min(str.length(), sourceMapSize);
std::copy_n(str.c_str(), sourceMapBytes, sourceMap);
}
- return { bytes, sourceMapBytes };
+ return {bytes, sourceMapBytes};
}
-size_t BinaryenModuleWrite(BinaryenModuleRef module, char* output, size_t outputSize) {
+size_t
+BinaryenModuleWrite(BinaryenModuleRef module, char* output, size_t outputSize) {
if (tracing) {
std::cout << " // BinaryenModuleWrite\n";
}
- return writeModule((Module*)module, output, outputSize, nullptr, nullptr, 0).outputBytes;
+ return writeModule((Module*)module, output, outputSize, nullptr, nullptr, 0)
+ .outputBytes;
}
-BinaryenBufferSizes BinaryenModuleWriteWithSourceMap(BinaryenModuleRef module, const char* url, char* output, size_t outputSize, char* sourceMap, size_t sourceMapSize) {
+BinaryenBufferSizes BinaryenModuleWriteWithSourceMap(BinaryenModuleRef module,
+ const char* url,
+ char* output,
+ size_t outputSize,
+ char* sourceMap,
+ size_t sourceMapSize) {
if (tracing) {
std::cout << " // BinaryenModuleWriteWithSourceMap\n";
}
assert(url);
assert(sourceMap);
- return writeModule((Module*)module, output, outputSize, url, sourceMap, sourceMapSize);
+ return writeModule(
+ (Module*)module, output, outputSize, url, sourceMap, sourceMapSize);
}
-BinaryenModuleAllocateAndWriteResult BinaryenModuleAllocateAndWrite(BinaryenModuleRef module, const char* sourceMapUrl) {
+BinaryenModuleAllocateAndWriteResult
+BinaryenModuleAllocateAndWrite(BinaryenModuleRef module,
+ const char* sourceMapUrl) {
if (tracing) {
std::cout << " // BinaryenModuleAllocateAndWrite(the_module, ";
traceNameOrNULL(sourceMapUrl);
@@ -2648,7 +3246,7 @@ BinaryenModuleAllocateAndWriteResult BinaryenModuleAllocateAndWrite(BinaryenModu
sourceMap = (char*)malloc(str.length() + 1);
std::copy_n(str.c_str(), str.length() + 1, sourceMap);
}
- return { binary, buffer.size(), sourceMap };
+ return {binary, buffer.size(), sourceMap};
}
BinaryenModuleRef BinaryenModuleRead(char* input, size_t inputSize) {
@@ -2680,9 +3278,11 @@ void BinaryenModuleInterpret(BinaryenModuleRef module) {
ModuleInstance instance(*wasm, &interface);
}
-BinaryenIndex BinaryenModuleAddDebugInfoFileName(BinaryenModuleRef module, const char* filename) {
+BinaryenIndex BinaryenModuleAddDebugInfoFileName(BinaryenModuleRef module,
+ const char* filename) {
if (tracing) {
- std::cout << " BinaryenModuleAddDebugInfoFileName(the_module, \"" << filename << "\");\n";
+ std::cout << " BinaryenModuleAddDebugInfoFileName(the_module, \""
+ << filename << "\");\n";
}
Module* wasm = (Module*)module;
@@ -2691,13 +3291,17 @@ BinaryenIndex BinaryenModuleAddDebugInfoFileName(BinaryenModuleRef module, const
return index;
}
-const char* BinaryenModuleGetDebugInfoFileName(BinaryenModuleRef module, BinaryenIndex index) {
+const char* BinaryenModuleGetDebugInfoFileName(BinaryenModuleRef module,
+ BinaryenIndex index) {
if (tracing) {
- std::cout << " BinaryenModuleGetDebugInfoFileName(the_module, \"" << index << "\");\n";
+ std::cout << " BinaryenModuleGetDebugInfoFileName(the_module, \"" << index
+ << "\");\n";
}
Module* wasm = (Module*)module;
- return index < wasm->debugInfoFileNames.size() ? wasm->debugInfoFileNames.at(index).c_str() : nullptr;
+ return index < wasm->debugInfoFileNames.size()
+ ? wasm->debugInfoFileNames.at(index).c_str()
+ : nullptr;
}
//
@@ -2706,21 +3310,25 @@ const char* BinaryenModuleGetDebugInfoFileName(BinaryenModuleRef module, Binarye
const char* BinaryenFunctionTypeGetName(BinaryenFunctionTypeRef ftype) {
if (tracing) {
- std::cout << " BinaryenFunctionTypeGetName(functionsTypes[" << functions[ftype] << "]);\n";
+ std::cout << " BinaryenFunctionTypeGetName(functionsTypes["
+ << functions[ftype] << "]);\n";
}
return ((FunctionType*)ftype)->name.c_str();
}
BinaryenIndex BinaryenFunctionTypeGetNumParams(BinaryenFunctionTypeRef ftype) {
if (tracing) {
- std::cout << " BinaryenFunctionTypeGetNumParams(functionsTypes[" << functions[ftype] << "]);\n";
+ std::cout << " BinaryenFunctionTypeGetNumParams(functionsTypes["
+ << functions[ftype] << "]);\n";
}
return ((FunctionType*)ftype)->params.size();
}
-BinaryenType BinaryenFunctionTypeGetParam(BinaryenFunctionTypeRef ftype, BinaryenIndex index) {
+BinaryenType BinaryenFunctionTypeGetParam(BinaryenFunctionTypeRef ftype,
+ BinaryenIndex index) {
if (tracing) {
- std::cout << " BinaryenFunctionTypeGetParam(functionsTypes[" << functions[ftype] << "], " << index << ");\n";
+ std::cout << " BinaryenFunctionTypeGetParam(functionsTypes["
+ << functions[ftype] << "], " << index << ");\n";
}
auto* ft = (FunctionType*)ftype;
@@ -2729,7 +3337,8 @@ BinaryenType BinaryenFunctionTypeGetParam(BinaryenFunctionTypeRef ftype, Binarye
}
BinaryenType BinaryenFunctionTypeGetResult(BinaryenFunctionTypeRef ftype) {
if (tracing) {
- std::cout << " BinaryenFunctionTypeGetResult(functionsTypes[" << functions[ftype] << "]);\n";
+ std::cout << " BinaryenFunctionTypeGetResult(functionsTypes["
+ << functions[ftype] << "]);\n";
}
return ((FunctionType*)ftype)->result;
@@ -2741,28 +3350,33 @@ BinaryenType BinaryenFunctionTypeGetResult(BinaryenFunctionTypeRef ftype) {
const char* BinaryenFunctionGetName(BinaryenFunctionRef func) {
if (tracing) {
- std::cout << " BinaryenFunctionGetName(functions[" << functions[func] << "]);\n";
+ std::cout << " BinaryenFunctionGetName(functions[" << functions[func]
+ << "]);\n";
}
return ((Function*)func)->name.c_str();
}
const char* BinaryenFunctionGetType(BinaryenFunctionRef func) {
if (tracing) {
- std::cout << " BinaryenFunctionGetType(functions[" << functions[func] << "]);\n";
+ std::cout << " BinaryenFunctionGetType(functions[" << functions[func]
+ << "]);\n";
}
return ((Function*)func)->type.c_str();
}
BinaryenIndex BinaryenFunctionGetNumParams(BinaryenFunctionRef func) {
if (tracing) {
- std::cout << " BinaryenFunctionGetNumParams(functions[" << functions[func] << "]);\n";
+ std::cout << " BinaryenFunctionGetNumParams(functions[" << functions[func]
+ << "]);\n";
}
return ((Function*)func)->params.size();
}
-BinaryenType BinaryenFunctionGetParam(BinaryenFunctionRef func, BinaryenIndex index) {
+BinaryenType BinaryenFunctionGetParam(BinaryenFunctionRef func,
+ BinaryenIndex index) {
if (tracing) {
- std::cout << " BinaryenFunctionGetParam(functions[" << functions[func] << "], " << index << ");\n";
+ std::cout << " BinaryenFunctionGetParam(functions[" << functions[func]
+ << "], " << index << ");\n";
}
auto* fn = (Function*)func;
@@ -2771,21 +3385,25 @@ BinaryenType BinaryenFunctionGetParam(BinaryenFunctionRef func, BinaryenIndex in
}
BinaryenType BinaryenFunctionGetResult(BinaryenFunctionRef func) {
if (tracing) {
- std::cout << " BinaryenFunctionGetResult(functions[" << functions[func] << "]);\n";
+ std::cout << " BinaryenFunctionGetResult(functions[" << functions[func]
+ << "]);\n";
}
return ((Function*)func)->result;
}
BinaryenIndex BinaryenFunctionGetNumVars(BinaryenFunctionRef func) {
if (tracing) {
- std::cout << " BinaryenFunctionGetNumVars(functions[" << functions[func] << "]);\n";
+ std::cout << " BinaryenFunctionGetNumVars(functions[" << functions[func]
+ << "]);\n";
}
return ((Function*)func)->vars.size();
}
-BinaryenType BinaryenFunctionGetVar(BinaryenFunctionRef func, BinaryenIndex index) {
+BinaryenType BinaryenFunctionGetVar(BinaryenFunctionRef func,
+ BinaryenIndex index) {
if (tracing) {
- std::cout << " BinaryenFunctionGetVar(functions[" << functions[func] << "], " << index << ");\n";
+ std::cout << " BinaryenFunctionGetVar(functions[" << functions[func]
+ << "], " << index << ");\n";
}
auto* fn = (Function*)func;
@@ -2794,14 +3412,17 @@ BinaryenType BinaryenFunctionGetVar(BinaryenFunctionRef func, BinaryenIndex inde
}
BinaryenExpressionRef BinaryenFunctionGetBody(BinaryenFunctionRef func) {
if (tracing) {
- std::cout << " BinaryenFunctionGetBody(functions[" << functions[func] << "]);\n";
+ std::cout << " BinaryenFunctionGetBody(functions[" << functions[func]
+ << "]);\n";
}
return ((Function*)func)->body;
}
-void BinaryenFunctionOptimize(BinaryenFunctionRef func, BinaryenModuleRef module) {
+void BinaryenFunctionOptimize(BinaryenFunctionRef func,
+ BinaryenModuleRef module) {
if (tracing) {
- std::cout << " BinaryenFunctionOptimize(functions[" << functions[func] << "], the_module);\n";
+ std::cout << " BinaryenFunctionOptimize(functions[" << functions[func]
+ << "], the_module);\n";
}
Module* wasm = (Module*)module;
@@ -2810,16 +3431,21 @@ void BinaryenFunctionOptimize(BinaryenFunctionRef func, BinaryenModuleRef module
passRunner.addDefaultOptimizationPasses();
passRunner.runOnFunction((Function*)func);
}
-void BinaryenFunctionRunPasses(BinaryenFunctionRef func, BinaryenModuleRef module, const char** passes, BinaryenIndex numPasses) {
+void BinaryenFunctionRunPasses(BinaryenFunctionRef func,
+ BinaryenModuleRef module,
+ const char** passes,
+ BinaryenIndex numPasses) {
if (tracing) {
std::cout << " {\n";
std::cout << " const char* passes[] = { ";
for (BinaryenIndex i = 0; i < numPasses; i++) {
- if (i > 0) std::cout << ", ";
+ if (i > 0)
+ std::cout << ", ";
std::cout << "\"" << passes[i] << "\"";
}
std::cout << " };\n";
- std::cout << " BinaryenFunctionRunPasses(functions[" << functions[func] << ", the_module, passes, " << numPasses << ");\n";
+ std::cout << " BinaryenFunctionRunPasses(functions[" << functions[func]
+ << ", the_module, passes, " << numPasses << ");\n";
std::cout << " }\n";
}
@@ -2831,9 +3457,16 @@ void BinaryenFunctionRunPasses(BinaryenFunctionRef func, BinaryenModuleRef modul
}
passRunner.runOnFunction((Function*)func);
}
-void BinaryenFunctionSetDebugLocation(BinaryenFunctionRef func, BinaryenExpressionRef expr, BinaryenIndex fileIndex, BinaryenIndex lineNumber, BinaryenIndex columnNumber) {
+void BinaryenFunctionSetDebugLocation(BinaryenFunctionRef func,
+ BinaryenExpressionRef expr,
+ BinaryenIndex fileIndex,
+ BinaryenIndex lineNumber,
+ BinaryenIndex columnNumber) {
if (tracing) {
- std::cout << " BinaryenFunctionSetDebugLocation(functions[" << functions[func] << "], expressions[" << expressions[expr] << "], " << fileIndex << ", " << lineNumber << ", " << columnNumber << ");\n";
+ std::cout << " BinaryenFunctionSetDebugLocation(functions["
+ << functions[func] << "], expressions[" << expressions[expr]
+ << "], " << fileIndex << ", " << lineNumber << ", "
+ << columnNumber << ");\n";
}
auto* fn = (Function*)func;
@@ -2853,7 +3486,8 @@ void BinaryenFunctionSetDebugLocation(BinaryenFunctionRef func, BinaryenExpressi
const char* BinaryenFunctionImportGetModule(BinaryenFunctionRef import) {
if (tracing) {
- std::cout << " BinaryenFunctionImportGetModule(functions[" << functions[import] << "]);\n";
+ std::cout << " BinaryenFunctionImportGetModule(functions["
+ << functions[import] << "]);\n";
}
auto* func = (Function*)import;
@@ -2865,7 +3499,8 @@ const char* BinaryenFunctionImportGetModule(BinaryenFunctionRef import) {
}
const char* BinaryenGlobalImportGetModule(BinaryenGlobalRef import) {
if (tracing) {
- std::cout << " BinaryenGlobalImportGetModule(globals[" << globals[import] << "]);\n";
+ std::cout << " BinaryenGlobalImportGetModule(globals[" << globals[import]
+ << "]);\n";
}
auto* global = (Global*)import;
@@ -2877,7 +3512,8 @@ const char* BinaryenGlobalImportGetModule(BinaryenGlobalRef import) {
}
const char* BinaryenFunctionImportGetBase(BinaryenFunctionRef import) {
if (tracing) {
- std::cout << " BinaryenFunctionImportGetBase(functions[" << functions[import] << "]);\n";
+ std::cout << " BinaryenFunctionImportGetBase(functions["
+ << functions[import] << "]);\n";
}
auto* func = (Function*)import;
@@ -2889,7 +3525,8 @@ const char* BinaryenFunctionImportGetBase(BinaryenFunctionRef import) {
}
const char* BinaryenGlobalImportGetBase(BinaryenGlobalRef import) {
if (tracing) {
- std::cout << " BinaryenGlobalImportGetBase(globals[" << globals[import] << "]);\n";
+ std::cout << " BinaryenGlobalImportGetBase(globals[" << globals[import]
+ << "]);\n";
}
auto* global = (Global*)import;
@@ -2906,21 +3543,24 @@ const char* BinaryenGlobalImportGetBase(BinaryenGlobalRef import) {
BinaryenExternalKind BinaryenExportGetKind(BinaryenExportRef export_) {
if (tracing) {
- std::cout << " BinaryenExportGetKind(exports[" << exports[export_] << "]);\n";
+ std::cout << " BinaryenExportGetKind(exports[" << exports[export_]
+ << "]);\n";
}
return BinaryenExternalKind(((Export*)export_)->kind);
}
const char* BinaryenExportGetName(BinaryenExportRef export_) {
if (tracing) {
- std::cout << " BinaryenExportGetName(exports[" << exports[export_] << "]);\n";
+ std::cout << " BinaryenExportGetName(exports[" << exports[export_]
+ << "]);\n";
}
return ((Export*)export_)->name.c_str();
}
const char* BinaryenExportGetValue(BinaryenExportRef export_) {
if (tracing) {
- std::cout << " BinaryenExportGetValue(exports[" << exports[export_] << "]);\n";
+ std::cout << " BinaryenExportGetValue(exports[" << exports[export_]
+ << "]);\n";
}
return ((Export*)export_)->value.c_str();
@@ -2939,23 +3579,32 @@ RelooperRef RelooperCreate(BinaryenModuleRef module) {
return RelooperRef(new CFG::Relooper(wasm));
}
-RelooperBlockRef RelooperAddBlock(RelooperRef relooper, BinaryenExpressionRef code) {
+RelooperBlockRef RelooperAddBlock(RelooperRef relooper,
+ BinaryenExpressionRef code) {
auto* R = (CFG::Relooper*)relooper;
auto* ret = new CFG::Block((Expression*)code);
if (tracing) {
auto id = relooperBlocks.size();
relooperBlocks[ret] = id;
- std::cout << " relooperBlocks[" << id << "] = RelooperAddBlock(the_relooper, expressions[" << expressions[code] << "]);\n";
+ std::cout << " relooperBlocks[" << id
+ << "] = RelooperAddBlock(the_relooper, expressions["
+ << expressions[code] << "]);\n";
}
R->AddBlock(ret);
return RelooperRef(ret);
}
-void RelooperAddBranch(RelooperBlockRef from, RelooperBlockRef to, BinaryenExpressionRef condition, BinaryenExpressionRef code) {
+void RelooperAddBranch(RelooperBlockRef from,
+ RelooperBlockRef to,
+ BinaryenExpressionRef condition,
+ BinaryenExpressionRef code) {
if (tracing) {
- std::cout << " RelooperAddBranch(relooperBlocks[" << relooperBlocks[from] << "], relooperBlocks[" << relooperBlocks[to] << "], expressions[" << expressions[condition] << "], expressions[" << expressions[code] << "]);\n";
+ std::cout << " RelooperAddBranch(relooperBlocks[" << relooperBlocks[from]
+ << "], relooperBlocks[" << relooperBlocks[to] << "], expressions["
+ << expressions[condition] << "], expressions["
+ << expressions[code] << "]);\n";
}
auto* fromBlock = (CFG::Block*)from;
@@ -2963,29 +3612,44 @@ void RelooperAddBranch(RelooperBlockRef from, RelooperBlockRef to, BinaryenExpre
fromBlock->AddBranchTo(toBlock, (Expression*)condition, (Expression*)code);
}
-RelooperBlockRef RelooperAddBlockWithSwitch(RelooperRef relooper, BinaryenExpressionRef code, BinaryenExpressionRef condition) {
+RelooperBlockRef RelooperAddBlockWithSwitch(RelooperRef relooper,
+ BinaryenExpressionRef code,
+ BinaryenExpressionRef condition) {
auto* R = (CFG::Relooper*)relooper;
auto* ret = new CFG::Block((Expression*)code, (Expression*)condition);
if (tracing) {
- std::cout << " relooperBlocks[" << relooperBlocks[ret] << "] = RelooperAddBlockWithSwitch(the_relooper, expressions[" << expressions[code] << "], expressions[" << expressions[condition] << "]);\n";
+ std::cout << " relooperBlocks[" << relooperBlocks[ret]
+ << "] = RelooperAddBlockWithSwitch(the_relooper, expressions["
+ << expressions[code] << "], expressions["
+ << expressions[condition] << "]);\n";
}
R->AddBlock(ret);
return RelooperRef(ret);
}
-void RelooperAddBranchForSwitch(RelooperBlockRef from, RelooperBlockRef to, BinaryenIndex* indexes, BinaryenIndex numIndexes, BinaryenExpressionRef code) {
+void RelooperAddBranchForSwitch(RelooperBlockRef from,
+ RelooperBlockRef to,
+ BinaryenIndex* indexes,
+ BinaryenIndex numIndexes,
+ BinaryenExpressionRef code) {
if (tracing) {
std::cout << " {\n";
std::cout << " BinaryenIndex indexes[] = { ";
for (BinaryenIndex i = 0; i < numIndexes; i++) {
- if (i > 0) std::cout << ", ";
+ if (i > 0)
+ std::cout << ", ";
std::cout << indexes[i];
}
- if (numIndexes == 0) std::cout << "0"; // ensure the array is not empty, otherwise a compiler error on VS
+ if (numIndexes == 0)
+ // ensure the array is not empty, otherwise a compiler error on VS
+ std::cout << "0";
std::cout << " };\n";
- std::cout << " RelooperAddBranchForSwitch(relooperBlocks[" << relooperBlocks[from] << "], relooperBlocks[" << relooperBlocks[to] << "], indexes, " << numIndexes << ", expressions[" << expressions[code] << "]);\n";
+ std::cout << " RelooperAddBranchForSwitch(relooperBlocks["
+ << relooperBlocks[from] << "], relooperBlocks["
+ << relooperBlocks[to] << "], indexes, " << numIndexes
+ << ", expressions[" << expressions[code] << "]);\n";
std::cout << " }\n";
}
@@ -2998,7 +3662,9 @@ void RelooperAddBranchForSwitch(RelooperBlockRef from, RelooperBlockRef to, Bina
fromBlock->AddSwitchBranchTo(toBlock, std::move(values), (Expression*)code);
}
-BinaryenExpressionRef RelooperRenderAndDispose(RelooperRef relooper, RelooperBlockRef entry, BinaryenIndex labelHelper) {
+BinaryenExpressionRef RelooperRenderAndDispose(RelooperRef relooper,
+ RelooperBlockRef entry,
+ BinaryenIndex labelHelper) {
auto* R = (CFG::Relooper*)relooper;
R->Calculate((CFG::Block*)entry);
CFG::RelooperBuilder builder(*R->Module, labelHelper);
@@ -3006,7 +3672,9 @@ BinaryenExpressionRef RelooperRenderAndDispose(RelooperRef relooper, RelooperBlo
if (tracing) {
auto id = noteExpression(ret);
- std::cout << " expressions[" << id << "] = RelooperRenderAndDispose(the_relooper, relooperBlocks[" << relooperBlocks[entry] << "], " << labelHelper << ");\n";
+ std::cout << " expressions[" << id
+ << "] = RelooperRenderAndDispose(the_relooper, relooperBlocks["
+ << relooperBlocks[entry] << "], " << labelHelper << ");\n";
relooperBlocks.clear();
}
@@ -3045,7 +3713,11 @@ void BinaryenSetAPITracing(int on) {
// ========= Utilities =========
//
-BinaryenFunctionTypeRef BinaryenGetFunctionTypeBySignature(BinaryenModuleRef module, BinaryenType result, BinaryenType* paramTypes, BinaryenIndex numParams) {
+BinaryenFunctionTypeRef
+BinaryenGetFunctionTypeBySignature(BinaryenModuleRef module,
+ BinaryenType result,
+ BinaryenType* paramTypes,
+ BinaryenIndex numParams) {
if (tracing) {
std::cout << " // BinaryenGetFunctionTypeBySignature\n";
}
@@ -3074,17 +3746,13 @@ BinaryenFunctionTypeRef BinaryenGetFunctionTypeBySignature(BinaryenModuleRef mod
#ifdef __EMSCRIPTEN__
// Override atexit - we don't need any global ctors to actually run, and
// otherwise we get clutter in the output in debug builds
-int atexit(void (*function)(void)) {
- return 0;
-}
+int atexit(void (*function)(void)) { return 0; }
// Internal binaryen.js APIs
// Returns the size of a Literal object.
EMSCRIPTEN_KEEPALIVE
-size_t BinaryenSizeofLiteral(void) {
- return sizeof(Literal);
-}
+size_t BinaryenSizeofLiteral(void) { return sizeof(Literal); }
// Returns the size of an allocate and write result object.
EMSCRIPTEN_KEEPALIVE
diff --git a/src/binaryen-c.h b/src/binaryen-c.h
index 7478a4642..9a57cac79 100644
--- a/src/binaryen-c.h
+++ b/src/binaryen-c.h
@@ -139,14 +139,14 @@ BinaryenExternalKind BinaryenExternalGlobal(void);
// Modules
//
// Modules contain lists of functions, imports, exports, function types. The
-// Add* methods create them on a module. The module owns them and will free their
-// memory when the module is disposed of.
+// Add* methods create them on a module. The module owns them and will free
+// their memory when the module is disposed of.
//
-// Expressions are also allocated inside modules, and freed with the module. They
-// are not created by Add* methods, since they are not added directly on the
-// module, instead, they are arguments to other expressions (and then they are
-// the children of that AST node), or to a function (and then they are the body
-// of that function).
+// Expressions are also allocated inside modules, and freed with the module.
+// They are not created by Add* methods, since they are not added directly on
+// the module, instead, they are arguments to other expressions (and then they
+// are the children of that AST node), or to a function (and then they are the
+// body of that function).
//
// A module can also contain a function table for indirect calls, a memory,
// and a start method.
@@ -162,7 +162,11 @@ typedef void* BinaryenFunctionTypeRef;
// Add a new function type. This is thread-safe.
// Note: name can be NULL, in which case we auto-generate a name
-BinaryenFunctionTypeRef BinaryenAddFunctionType(BinaryenModuleRef module, const char* name, BinaryenType result, BinaryenType* paramTypes, BinaryenIndex numParams);
+BinaryenFunctionTypeRef BinaryenAddFunctionType(BinaryenModuleRef module,
+ const char* name,
+ BinaryenType result,
+ BinaryenType* paramTypes,
+ BinaryenIndex numParams);
// Removes a function type.
void BinaryenRemoveFunctionType(BinaryenModuleRef module, const char* name);
@@ -485,20 +489,45 @@ typedef void* BinaryenExpressionRef;
// parameter indicates that the block's type shall be figured out
// automatically instead of explicitly providing it. This conforms
// to the behavior before the 'type' parameter has been introduced.
-BinaryenExpressionRef BinaryenBlock(BinaryenModuleRef module, const char* name, BinaryenExpressionRef* children, BinaryenIndex numChildren, BinaryenType type);
+BinaryenExpressionRef BinaryenBlock(BinaryenModuleRef module,
+ const char* name,
+ BinaryenExpressionRef* children,
+ BinaryenIndex numChildren,
+ BinaryenType type);
// If: ifFalse can be NULL
-BinaryenExpressionRef BinaryenIf(BinaryenModuleRef module, BinaryenExpressionRef condition, BinaryenExpressionRef ifTrue, BinaryenExpressionRef ifFalse);
-BinaryenExpressionRef BinaryenLoop(BinaryenModuleRef module, const char* in, BinaryenExpressionRef body);
+BinaryenExpressionRef BinaryenIf(BinaryenModuleRef module,
+ BinaryenExpressionRef condition,
+ BinaryenExpressionRef ifTrue,
+ BinaryenExpressionRef ifFalse);
+BinaryenExpressionRef BinaryenLoop(BinaryenModuleRef module,
+ const char* in,
+ BinaryenExpressionRef body);
// Break: value and condition can be NULL
-BinaryenExpressionRef BinaryenBreak(BinaryenModuleRef module, const char* name, BinaryenExpressionRef condition, BinaryenExpressionRef value);
+BinaryenExpressionRef BinaryenBreak(BinaryenModuleRef module,
+ const char* name,
+ BinaryenExpressionRef condition,
+ BinaryenExpressionRef value);
// Switch: value can be NULL
-BinaryenExpressionRef BinaryenSwitch(BinaryenModuleRef module, const char** names, BinaryenIndex numNames, const char* defaultName, BinaryenExpressionRef condition, BinaryenExpressionRef value);
+BinaryenExpressionRef BinaryenSwitch(BinaryenModuleRef module,
+ const char** names,
+ BinaryenIndex numNames,
+ const char* defaultName,
+ BinaryenExpressionRef condition,
+ BinaryenExpressionRef value);
// Call: Note the 'returnType' parameter. You must declare the
// type returned by the function being called, as that
// function might not have been created yet, so we don't
// know what it is.
-BinaryenExpressionRef BinaryenCall(BinaryenModuleRef module, const char* target, BinaryenExpressionRef* operands, BinaryenIndex numOperands, BinaryenType returnType);
-BinaryenExpressionRef BinaryenCallIndirect(BinaryenModuleRef module, BinaryenExpressionRef target, BinaryenExpressionRef* operands, BinaryenIndex numOperands, const char* type);
+BinaryenExpressionRef BinaryenCall(BinaryenModuleRef module,
+ const char* target,
+ BinaryenExpressionRef* operands,
+ BinaryenIndex numOperands,
+ BinaryenType returnType);
+BinaryenExpressionRef BinaryenCallIndirect(BinaryenModuleRef module,
+ BinaryenExpressionRef target,
+ BinaryenExpressionRef* operands,
+ BinaryenIndex numOperands,
+ const char* type);
// GetLocal: Note the 'type' parameter. It might seem redundant, since the
// local at that index must have a type. However, this API lets you
// build code "top-down": create a node, then its parents, and so
@@ -513,41 +542,134 @@ BinaryenExpressionRef BinaryenCallIndirect(BinaryenModuleRef module, BinaryenExp
// a var, that is, either a parameter to the function or a variable
// declared when you call BinaryenAddFunction. See BinaryenAddFunction
// for more details.
-BinaryenExpressionRef BinaryenGetLocal(BinaryenModuleRef module, BinaryenIndex index, BinaryenType type);
-BinaryenExpressionRef BinaryenSetLocal(BinaryenModuleRef module, BinaryenIndex index, BinaryenExpressionRef value);
-BinaryenExpressionRef BinaryenTeeLocal(BinaryenModuleRef module, BinaryenIndex index, BinaryenExpressionRef value);
-BinaryenExpressionRef BinaryenGetGlobal(BinaryenModuleRef module, const char* name, BinaryenType type);
-BinaryenExpressionRef BinaryenSetGlobal(BinaryenModuleRef module, const char* name, BinaryenExpressionRef value);
-// Load: align can be 0, in which case it will be the natural alignment (equal to bytes)
-BinaryenExpressionRef BinaryenLoad(BinaryenModuleRef module, uint32_t bytes, int8_t signed_, uint32_t offset, uint32_t align, BinaryenType type, BinaryenExpressionRef ptr);
-// Store: align can be 0, in which case it will be the natural alignment (equal to bytes)
-BinaryenExpressionRef BinaryenStore(BinaryenModuleRef module, uint32_t bytes, uint32_t offset, uint32_t align, BinaryenExpressionRef ptr, BinaryenExpressionRef value, BinaryenType type);
-BinaryenExpressionRef BinaryenConst(BinaryenModuleRef module, struct BinaryenLiteral value);
-BinaryenExpressionRef BinaryenUnary(BinaryenModuleRef module, BinaryenOp op, BinaryenExpressionRef value);
-BinaryenExpressionRef BinaryenBinary(BinaryenModuleRef module, BinaryenOp op, BinaryenExpressionRef left, BinaryenExpressionRef right);
-BinaryenExpressionRef BinaryenSelect(BinaryenModuleRef module, BinaryenExpressionRef condition, BinaryenExpressionRef ifTrue, BinaryenExpressionRef ifFalse);
-BinaryenExpressionRef BinaryenDrop(BinaryenModuleRef module, BinaryenExpressionRef value);
+BinaryenExpressionRef BinaryenGetLocal(BinaryenModuleRef module,
+ BinaryenIndex index,
+ BinaryenType type);
+BinaryenExpressionRef BinaryenSetLocal(BinaryenModuleRef module,
+ BinaryenIndex index,
+ BinaryenExpressionRef value);
+BinaryenExpressionRef BinaryenTeeLocal(BinaryenModuleRef module,
+ BinaryenIndex index,
+ BinaryenExpressionRef value);
+BinaryenExpressionRef BinaryenGetGlobal(BinaryenModuleRef module,
+ const char* name,
+ BinaryenType type);
+BinaryenExpressionRef BinaryenSetGlobal(BinaryenModuleRef module,
+ const char* name,
+ BinaryenExpressionRef value);
+// Load: align can be 0, in which case it will be the natural alignment (equal
+// to bytes)
+BinaryenExpressionRef BinaryenLoad(BinaryenModuleRef module,
+ uint32_t bytes,
+ int8_t signed_,
+ uint32_t offset,
+ uint32_t align,
+ BinaryenType type,
+ BinaryenExpressionRef ptr);
+// Store: align can be 0, in which case it will be the natural alignment (equal
+// to bytes)
+BinaryenExpressionRef BinaryenStore(BinaryenModuleRef module,
+ uint32_t bytes,
+ uint32_t offset,
+ uint32_t align,
+ BinaryenExpressionRef ptr,
+ BinaryenExpressionRef value,
+ BinaryenType type);
+BinaryenExpressionRef BinaryenConst(BinaryenModuleRef module,
+ struct BinaryenLiteral value);
+BinaryenExpressionRef BinaryenUnary(BinaryenModuleRef module,
+ BinaryenOp op,
+ BinaryenExpressionRef value);
+BinaryenExpressionRef BinaryenBinary(BinaryenModuleRef module,
+ BinaryenOp op,
+ BinaryenExpressionRef left,
+ BinaryenExpressionRef right);
+BinaryenExpressionRef BinaryenSelect(BinaryenModuleRef module,
+ BinaryenExpressionRef condition,
+ BinaryenExpressionRef ifTrue,
+ BinaryenExpressionRef ifFalse);
+BinaryenExpressionRef BinaryenDrop(BinaryenModuleRef module,
+ BinaryenExpressionRef value);
// Return: value can be NULL
-BinaryenExpressionRef BinaryenReturn(BinaryenModuleRef module, BinaryenExpressionRef value);
+BinaryenExpressionRef BinaryenReturn(BinaryenModuleRef module,
+ BinaryenExpressionRef value);
// Host: name may be NULL
-BinaryenExpressionRef BinaryenHost(BinaryenModuleRef module, BinaryenOp op, const char* name, BinaryenExpressionRef* operands, BinaryenIndex numOperands);
+BinaryenExpressionRef BinaryenHost(BinaryenModuleRef module,
+ BinaryenOp op,
+ const char* name,
+ BinaryenExpressionRef* operands,
+ BinaryenIndex numOperands);
BinaryenExpressionRef BinaryenNop(BinaryenModuleRef module);
BinaryenExpressionRef BinaryenUnreachable(BinaryenModuleRef module);
-BinaryenExpressionRef BinaryenAtomicLoad(BinaryenModuleRef module, uint32_t bytes, uint32_t offset, BinaryenType type, BinaryenExpressionRef ptr);
-BinaryenExpressionRef BinaryenAtomicStore(BinaryenModuleRef module, uint32_t bytes, uint32_t offset, BinaryenExpressionRef ptr, BinaryenExpressionRef value, BinaryenType type);
-BinaryenExpressionRef BinaryenAtomicRMW(BinaryenModuleRef module, BinaryenOp op, BinaryenIndex bytes, BinaryenIndex offset, BinaryenExpressionRef ptr, BinaryenExpressionRef value, BinaryenType type);
-BinaryenExpressionRef BinaryenAtomicCmpxchg(BinaryenModuleRef module, BinaryenIndex bytes, BinaryenIndex offset, BinaryenExpressionRef ptr, BinaryenExpressionRef expected, BinaryenExpressionRef replacement, BinaryenType type);
-BinaryenExpressionRef BinaryenAtomicWait(BinaryenModuleRef module, BinaryenExpressionRef ptr, BinaryenExpressionRef expected, BinaryenExpressionRef timeout, BinaryenType type);
-BinaryenExpressionRef BinaryenAtomicNotify(BinaryenModuleRef module, BinaryenExpressionRef ptr, BinaryenExpressionRef notifyCount);
-BinaryenExpressionRef BinaryenSIMDExtract(BinaryenModuleRef module, BinaryenOp op, BinaryenExpressionRef vec, uint8_t index);
-BinaryenExpressionRef BinaryenSIMDReplace(BinaryenModuleRef module, BinaryenOp op, BinaryenExpressionRef vec, uint8_t index, BinaryenExpressionRef value);
-BinaryenExpressionRef BinaryenSIMDShuffle(BinaryenModuleRef module, BinaryenExpressionRef left, BinaryenExpressionRef right, const uint8_t mask[16]);
-BinaryenExpressionRef BinaryenSIMDBitselect(BinaryenModuleRef module, BinaryenExpressionRef left, BinaryenExpressionRef right, BinaryenExpressionRef cond);
-BinaryenExpressionRef BinaryenSIMDShift(BinaryenModuleRef module, BinaryenOp op, BinaryenExpressionRef vec, BinaryenExpressionRef shift);
-BinaryenExpressionRef BinaryenMemoryInit(BinaryenModuleRef module, uint32_t segment, BinaryenExpressionRef dest, BinaryenExpressionRef offset, BinaryenExpressionRef size);
-BinaryenExpressionRef BinaryenDataDrop(BinaryenModuleRef module, uint32_t segment);
-BinaryenExpressionRef BinaryenMemoryCopy(BinaryenModuleRef module, BinaryenExpressionRef dest, BinaryenExpressionRef source, BinaryenExpressionRef size);
-BinaryenExpressionRef BinaryenMemoryFill(BinaryenModuleRef module, BinaryenExpressionRef dest, BinaryenExpressionRef value, BinaryenExpressionRef size);
+BinaryenExpressionRef BinaryenAtomicLoad(BinaryenModuleRef module,
+ uint32_t bytes,
+ uint32_t offset,
+ BinaryenType type,
+ BinaryenExpressionRef ptr);
+BinaryenExpressionRef BinaryenAtomicStore(BinaryenModuleRef module,
+ uint32_t bytes,
+ uint32_t offset,
+ BinaryenExpressionRef ptr,
+ BinaryenExpressionRef value,
+ BinaryenType type);
+BinaryenExpressionRef BinaryenAtomicRMW(BinaryenModuleRef module,
+ BinaryenOp op,
+ BinaryenIndex bytes,
+ BinaryenIndex offset,
+ BinaryenExpressionRef ptr,
+ BinaryenExpressionRef value,
+ BinaryenType type);
+BinaryenExpressionRef BinaryenAtomicCmpxchg(BinaryenModuleRef module,
+ BinaryenIndex bytes,
+ BinaryenIndex offset,
+ BinaryenExpressionRef ptr,
+ BinaryenExpressionRef expected,
+ BinaryenExpressionRef replacement,
+ BinaryenType type);
+BinaryenExpressionRef BinaryenAtomicWait(BinaryenModuleRef module,
+ BinaryenExpressionRef ptr,
+ BinaryenExpressionRef expected,
+ BinaryenExpressionRef timeout,
+ BinaryenType type);
+BinaryenExpressionRef BinaryenAtomicNotify(BinaryenModuleRef module,
+ BinaryenExpressionRef ptr,
+ BinaryenExpressionRef notifyCount);
+BinaryenExpressionRef BinaryenSIMDExtract(BinaryenModuleRef module,
+ BinaryenOp op,
+ BinaryenExpressionRef vec,
+ uint8_t index);
+BinaryenExpressionRef BinaryenSIMDReplace(BinaryenModuleRef module,
+ BinaryenOp op,
+ BinaryenExpressionRef vec,
+ uint8_t index,
+ BinaryenExpressionRef value);
+BinaryenExpressionRef BinaryenSIMDShuffle(BinaryenModuleRef module,
+ BinaryenExpressionRef left,
+ BinaryenExpressionRef right,
+ const uint8_t mask[16]);
+BinaryenExpressionRef BinaryenSIMDBitselect(BinaryenModuleRef module,
+ BinaryenExpressionRef left,
+ BinaryenExpressionRef right,
+ BinaryenExpressionRef cond);
+BinaryenExpressionRef BinaryenSIMDShift(BinaryenModuleRef module,
+ BinaryenOp op,
+ BinaryenExpressionRef vec,
+ BinaryenExpressionRef shift);
+BinaryenExpressionRef BinaryenMemoryInit(BinaryenModuleRef module,
+ uint32_t segment,
+ BinaryenExpressionRef dest,
+ BinaryenExpressionRef offset,
+ BinaryenExpressionRef size);
+BinaryenExpressionRef BinaryenDataDrop(BinaryenModuleRef module,
+ uint32_t segment);
+BinaryenExpressionRef BinaryenMemoryCopy(BinaryenModuleRef module,
+ BinaryenExpressionRef dest,
+ BinaryenExpressionRef source,
+ BinaryenExpressionRef size);
+BinaryenExpressionRef BinaryenMemoryFill(BinaryenModuleRef module,
+ BinaryenExpressionRef dest,
+ BinaryenExpressionRef value,
+ BinaryenExpressionRef size);
BinaryenExpressionId BinaryenExpressionGetId(BinaryenExpressionRef expr);
BinaryenType BinaryenExpressionGetType(BinaryenExpressionRef expr);
@@ -555,7 +677,8 @@ void BinaryenExpressionPrint(BinaryenExpressionRef expr);
const char* BinaryenBlockGetName(BinaryenExpressionRef expr);
BinaryenIndex BinaryenBlockGetNumChildren(BinaryenExpressionRef expr);
-BinaryenExpressionRef BinaryenBlockGetChild(BinaryenExpressionRef expr, BinaryenIndex index);
+BinaryenExpressionRef BinaryenBlockGetChild(BinaryenExpressionRef expr,
+ BinaryenIndex index);
BinaryenExpressionRef BinaryenIfGetCondition(BinaryenExpressionRef expr);
BinaryenExpressionRef BinaryenIfGetIfTrue(BinaryenExpressionRef expr);
@@ -569,18 +692,21 @@ BinaryenExpressionRef BinaryenBreakGetCondition(BinaryenExpressionRef expr);
BinaryenExpressionRef BinaryenBreakGetValue(BinaryenExpressionRef expr);
BinaryenIndex BinaryenSwitchGetNumNames(BinaryenExpressionRef expr);
-const char* BinaryenSwitchGetName(BinaryenExpressionRef expr, BinaryenIndex index);
+const char* BinaryenSwitchGetName(BinaryenExpressionRef expr,
+ BinaryenIndex index);
const char* BinaryenSwitchGetDefaultName(BinaryenExpressionRef expr);
BinaryenExpressionRef BinaryenSwitchGetCondition(BinaryenExpressionRef expr);
BinaryenExpressionRef BinaryenSwitchGetValue(BinaryenExpressionRef expr);
const char* BinaryenCallGetTarget(BinaryenExpressionRef expr);
BinaryenIndex BinaryenCallGetNumOperands(BinaryenExpressionRef expr);
-BinaryenExpressionRef BinaryenCallGetOperand(BinaryenExpressionRef expr, BinaryenIndex index);
+BinaryenExpressionRef BinaryenCallGetOperand(BinaryenExpressionRef expr,
+ BinaryenIndex index);
BinaryenExpressionRef BinaryenCallIndirectGetTarget(BinaryenExpressionRef expr);
BinaryenIndex BinaryenCallIndirectGetNumOperands(BinaryenExpressionRef expr);
-BinaryenExpressionRef BinaryenCallIndirectGetOperand(BinaryenExpressionRef expr, BinaryenIndex index);
+BinaryenExpressionRef BinaryenCallIndirectGetOperand(BinaryenExpressionRef expr,
+ BinaryenIndex index);
BinaryenIndex BinaryenGetLocalGetIndex(BinaryenExpressionRef expr);
@@ -596,7 +722,8 @@ BinaryenExpressionRef BinaryenSetGlobalGetValue(BinaryenExpressionRef expr);
BinaryenOp BinaryenHostGetOp(BinaryenExpressionRef expr);
const char* BinaryenHostGetNameOperand(BinaryenExpressionRef expr);
BinaryenIndex BinaryenHostGetNumOperands(BinaryenExpressionRef expr);
-BinaryenExpressionRef BinaryenHostGetOperand(BinaryenExpressionRef expr, BinaryenIndex index);
+BinaryenExpressionRef BinaryenHostGetOperand(BinaryenExpressionRef expr,
+ BinaryenIndex index);
int BinaryenLoadIsAtomic(BinaryenExpressionRef expr);
int BinaryenLoadIsSigned(BinaryenExpressionRef expr);
@@ -644,8 +771,10 @@ BinaryenExpressionRef BinaryenAtomicRMWGetValue(BinaryenExpressionRef expr);
uint32_t BinaryenAtomicCmpxchgGetBytes(BinaryenExpressionRef expr);
uint32_t BinaryenAtomicCmpxchgGetOffset(BinaryenExpressionRef expr);
BinaryenExpressionRef BinaryenAtomicCmpxchgGetPtr(BinaryenExpressionRef expr);
-BinaryenExpressionRef BinaryenAtomicCmpxchgGetExpected(BinaryenExpressionRef expr);
-BinaryenExpressionRef BinaryenAtomicCmpxchgGetReplacement(BinaryenExpressionRef expr);
+BinaryenExpressionRef
+BinaryenAtomicCmpxchgGetExpected(BinaryenExpressionRef expr);
+BinaryenExpressionRef
+BinaryenAtomicCmpxchgGetReplacement(BinaryenExpressionRef expr);
BinaryenExpressionRef BinaryenAtomicWaitGetPtr(BinaryenExpressionRef expr);
BinaryenExpressionRef BinaryenAtomicWaitGetExpected(BinaryenExpressionRef expr);
@@ -653,7 +782,8 @@ BinaryenExpressionRef BinaryenAtomicWaitGetTimeout(BinaryenExpressionRef expr);
BinaryenType BinaryenAtomicWaitGetExpectedType(BinaryenExpressionRef expr);
BinaryenExpressionRef BinaryenAtomicNotifyGetPtr(BinaryenExpressionRef expr);
-BinaryenExpressionRef BinaryenAtomicNotifyGetNotifyCount(BinaryenExpressionRef expr);
+BinaryenExpressionRef
+BinaryenAtomicNotifyGetNotifyCount(BinaryenExpressionRef expr);
BinaryenOp BinaryenSIMDExtractGetOp(BinaryenExpressionRef expr);
BinaryenExpressionRef BinaryenSIMDExtractGetVec(BinaryenExpressionRef expr);
@@ -666,7 +796,7 @@ BinaryenExpressionRef BinaryenSIMDReplaceGetValue(BinaryenExpressionRef expr);
BinaryenExpressionRef BinaryenSIMDShuffleGetLeft(BinaryenExpressionRef expr);
BinaryenExpressionRef BinaryenSIMDShuffleGetRight(BinaryenExpressionRef expr);
-void BinaryenSIMDShuffleGetMask(BinaryenExpressionRef expr, uint8_t *mask);
+void BinaryenSIMDShuffleGetMask(BinaryenExpressionRef expr, uint8_t* mask);
BinaryenExpressionRef BinaryenSIMDBitselectGetLeft(BinaryenExpressionRef expr);
BinaryenExpressionRef BinaryenSIMDBitselectGetRight(BinaryenExpressionRef expr);
@@ -703,48 +833,96 @@ typedef void* BinaryenFunctionRef;
// and then vars, so if you have one param it will be at index
// 0 (and written $0), and if you also have 2 vars they will be
// at indexes 1 and 2, etc., that is, they share an index space.
-BinaryenFunctionRef BinaryenAddFunction(BinaryenModuleRef module, const char* name, BinaryenFunctionTypeRef type, BinaryenType* varTypes, BinaryenIndex numVarTypes, BinaryenExpressionRef body);
+BinaryenFunctionRef BinaryenAddFunction(BinaryenModuleRef module,
+ const char* name,
+ BinaryenFunctionTypeRef type,
+ BinaryenType* varTypes,
+ BinaryenIndex numVarTypes,
+ BinaryenExpressionRef body);
// Gets a function reference by name.
-BinaryenFunctionRef BinaryenGetFunction(BinaryenModuleRef module, const char* name);
+BinaryenFunctionRef BinaryenGetFunction(BinaryenModuleRef module,
+ const char* name);
// Removes a function by name.
void BinaryenRemoveFunction(BinaryenModuleRef module, const char* name);
// Imports
-void BinaryenAddFunctionImport(BinaryenModuleRef module, const char* internalName, const char* externalModuleName, const char* externalBaseName, BinaryenFunctionTypeRef functionType);
-void BinaryenAddTableImport(BinaryenModuleRef module, const char* internalName, const char* externalModuleName, const char* externalBaseName);
-void BinaryenAddMemoryImport(BinaryenModuleRef module, const char* internalName, const char* externalModuleName, const char* externalBaseName, uint8_t shared);
-void BinaryenAddGlobalImport(BinaryenModuleRef module, const char* internalName, const char* externalModuleName, const char* externalBaseName, BinaryenType globalType);
+void BinaryenAddFunctionImport(BinaryenModuleRef module,
+ const char* internalName,
+ const char* externalModuleName,
+ const char* externalBaseName,
+ BinaryenFunctionTypeRef functionType);
+void BinaryenAddTableImport(BinaryenModuleRef module,
+ const char* internalName,
+ const char* externalModuleName,
+ const char* externalBaseName);
+void BinaryenAddMemoryImport(BinaryenModuleRef module,
+ const char* internalName,
+ const char* externalModuleName,
+ const char* externalBaseName,
+ uint8_t shared);
+void BinaryenAddGlobalImport(BinaryenModuleRef module,
+ const char* internalName,
+ const char* externalModuleName,
+ const char* externalBaseName,
+ BinaryenType globalType);
// Exports
typedef void* BinaryenExportRef;
-WASM_DEPRECATED BinaryenExportRef BinaryenAddExport(BinaryenModuleRef module, const char* internalName, const char* externalName);
-BinaryenExportRef BinaryenAddFunctionExport(BinaryenModuleRef module, const char* internalName, const char* externalName);
-BinaryenExportRef BinaryenAddTableExport(BinaryenModuleRef module, const char* internalName, const char* externalName);
-BinaryenExportRef BinaryenAddMemoryExport(BinaryenModuleRef module, const char* internalName, const char* externalName);
-BinaryenExportRef BinaryenAddGlobalExport(BinaryenModuleRef module, const char* internalName, const char* externalName);
+WASM_DEPRECATED BinaryenExportRef BinaryenAddExport(BinaryenModuleRef module,
+ const char* internalName,
+ const char* externalName);
+BinaryenExportRef BinaryenAddFunctionExport(BinaryenModuleRef module,
+ const char* internalName,
+ const char* externalName);
+BinaryenExportRef BinaryenAddTableExport(BinaryenModuleRef module,
+ const char* internalName,
+ const char* externalName);
+BinaryenExportRef BinaryenAddMemoryExport(BinaryenModuleRef module,
+ const char* internalName,
+ const char* externalName);
+BinaryenExportRef BinaryenAddGlobalExport(BinaryenModuleRef module,
+ const char* internalName,
+ const char* externalName);
void BinaryenRemoveExport(BinaryenModuleRef module, const char* externalName);
// Globals
typedef void* BinaryenGlobalRef;
-BinaryenGlobalRef BinaryenAddGlobal(BinaryenModuleRef module, const char* name, BinaryenType type, int8_t mutable_, BinaryenExpressionRef init);
+BinaryenGlobalRef BinaryenAddGlobal(BinaryenModuleRef module,
+ const char* name,
+ BinaryenType type,
+ int8_t mutable_,
+ BinaryenExpressionRef init);
void BinaryenRemoveGlobal(BinaryenModuleRef module, const char* name);
// Function table. One per module
-void BinaryenSetFunctionTable(BinaryenModuleRef module, BinaryenIndex initial, BinaryenIndex maximum, const char** funcNames, BinaryenIndex numFuncNames);
+void BinaryenSetFunctionTable(BinaryenModuleRef module,
+ BinaryenIndex initial,
+ BinaryenIndex maximum,
+ const char** funcNames,
+ BinaryenIndex numFuncNames);
// Memory. One per module
-// Each segment has data in segments, a start offset in segmentOffsets, and a size in segmentSizes.
-// exportName can be NULL
-void BinaryenSetMemory(BinaryenModuleRef module, BinaryenIndex initial, BinaryenIndex maximum, const char* exportName, const char** segments, int8_t* segmentPassive, BinaryenExpressionRef* segmentOffsets, BinaryenIndex* segmentSizes, BinaryenIndex numSegments, uint8_t shared);
+// Each segment has data in segments, a start offset in segmentOffsets, and a
+// size in segmentSizes. exportName can be NULL
+void BinaryenSetMemory(BinaryenModuleRef module,
+ BinaryenIndex initial,
+ BinaryenIndex maximum,
+ const char* exportName,
+ const char** segments,
+ int8_t* segmentPassive,
+ BinaryenExpressionRef* segmentOffsets,
+ BinaryenIndex* segmentSizes,
+ BinaryenIndex numSegments,
+ uint8_t shared);
// Start function. One per module
@@ -797,29 +975,41 @@ void BinaryenSetDebugInfo(int on);
// Runs the specified passes on the module. Uses the currently set global
// optimize and shrink level.
-void BinaryenModuleRunPasses(BinaryenModuleRef module, const char** passes, BinaryenIndex numPasses);
+void BinaryenModuleRunPasses(BinaryenModuleRef module,
+ const char** passes,
+ BinaryenIndex numPasses);
-// Auto-generate drop() operations where needed. This lets you generate code without
-// worrying about where they are needed. (It is more efficient to do it yourself,
-// but simpler to use autodrop).
+// Auto-generate drop() operations where needed. This lets you generate code
+// without worrying about where they are needed. (It is more efficient to do it
+// yourself, but simpler to use autodrop).
void BinaryenModuleAutoDrop(BinaryenModuleRef module);
-// Serialize a module into binary form. Uses the currently set global debugInfo option.
-// @return how many bytes were written. This will be less than or equal to outputSize
-size_t BinaryenModuleWrite(BinaryenModuleRef module, char* output, size_t outputSize);
+// Serialize a module into binary form. Uses the currently set global debugInfo
+// option.
+// @return how many bytes were written. This will be less than or equal to
+// outputSize
+size_t
+BinaryenModuleWrite(BinaryenModuleRef module, char* output, size_t outputSize);
typedef struct BinaryenBufferSizes {
size_t outputBytes;
size_t sourceMapBytes;
} BinaryenBufferSizes;
-// Serialize a module into binary form including its source map. Uses the currently set
-// global debugInfo option.
-// @returns how many bytes were written. This will be less than or equal to outputSize
-BinaryenBufferSizes BinaryenModuleWriteWithSourceMap(BinaryenModuleRef module, const char* url, char* output, size_t outputSize, char* sourceMap, size_t sourceMapSize);
-
-// Result structure of BinaryenModuleAllocateAndWrite. Contained buffers have been allocated
-// using malloc() and the user is expected to free() them manually once not needed anymore.
+// Serialize a module into binary form including its source map. Uses the
+// currently set global debugInfo option.
+// @returns how many bytes were written. This will be less than or equal to
+// outputSize
+BinaryenBufferSizes BinaryenModuleWriteWithSourceMap(BinaryenModuleRef module,
+ const char* url,
+ char* output,
+ size_t outputSize,
+ char* sourceMap,
+ size_t sourceMapSize);
+
+// Result structure of BinaryenModuleAllocateAndWrite. Contained buffers have
+// been allocated using malloc() and the user is expected to free() them
+// manually once not needed anymore.
typedef struct BinaryenModuleAllocateAndWriteResult {
void* binary;
size_t binaryBytes;
@@ -827,25 +1017,30 @@ typedef struct BinaryenModuleAllocateAndWriteResult {
} BinaryenModuleAllocateAndWriteResult;
// Serializes a module into binary form, optionally including its source map if
-// sourceMapUrl has been specified. Uses the currently set global debugInfo option.
-// Differs from BinaryenModuleWrite in that it implicitly allocates appropriate buffers
-// using malloc(), and expects the user to free() them manually once not needed anymore.
-BinaryenModuleAllocateAndWriteResult BinaryenModuleAllocateAndWrite(BinaryenModuleRef module, const char* sourceMapUrl);
+// sourceMapUrl has been specified. Uses the currently set global debugInfo
+// option. Differs from BinaryenModuleWrite in that it implicitly allocates
+// appropriate buffers using malloc(), and expects the user to free() them
+// manually once not needed anymore.
+BinaryenModuleAllocateAndWriteResult
+BinaryenModuleAllocateAndWrite(BinaryenModuleRef module,
+ const char* sourceMapUrl);
// Deserialize a module from binary form.
BinaryenModuleRef BinaryenModuleRead(char* input, size_t inputSize);
// Execute a module in the Binaryen interpreter. This will create an instance of
-// the module, run it in the interpreter - which means running the start method -
-// and then destroying the instance.
+// the module, run it in the interpreter - which means running the start method
+// - and then destroying the instance.
void BinaryenModuleInterpret(BinaryenModuleRef module);
// Adds a debug info file name to the module and returns its index.
-BinaryenIndex BinaryenModuleAddDebugInfoFileName(BinaryenModuleRef module, const char* filename);
+BinaryenIndex BinaryenModuleAddDebugInfoFileName(BinaryenModuleRef module,
+ const char* filename);
-// Gets the name of the debug info file at the specified index. Returns `NULL` if it
-// does not exist.
-const char* BinaryenModuleGetDebugInfoFileName(BinaryenModuleRef module, BinaryenIndex index);
+// Gets the name of the debug info file at the specified index. Returns `NULL`
+// if it does not exist.
+const char* BinaryenModuleGetDebugInfoFileName(BinaryenModuleRef module,
+ BinaryenIndex index);
//
// ======== FunctionType Operations ========
@@ -855,8 +1050,10 @@ const char* BinaryenModuleGetDebugInfoFileName(BinaryenModuleRef module, Binarye
const char* BinaryenFunctionTypeGetName(BinaryenFunctionTypeRef ftype);
// Gets the number of parameters of the specified `FunctionType`.
BinaryenIndex BinaryenFunctionTypeGetNumParams(BinaryenFunctionTypeRef ftype);
-// Gets the type of the parameter at the specified index of the specified `FunctionType`.
-BinaryenType BinaryenFunctionTypeGetParam(BinaryenFunctionTypeRef ftype, BinaryenIndex index);
+// Gets the type of the parameter at the specified index of the specified
+// `FunctionType`.
+BinaryenType BinaryenFunctionTypeGetParam(BinaryenFunctionTypeRef ftype,
+ BinaryenIndex index);
// Gets the result type of the specified `FunctionType`.
BinaryenType BinaryenFunctionTypeGetResult(BinaryenFunctionTypeRef ftype);
@@ -866,31 +1063,45 @@ BinaryenType BinaryenFunctionTypeGetResult(BinaryenFunctionTypeRef ftype);
// Gets the name of the specified `Function`.
const char* BinaryenFunctionGetName(BinaryenFunctionRef func);
-// Gets the name of the `FunctionType` associated with the specified `Function`. May be `NULL` if the signature is implicit.
+// Gets the name of the `FunctionType` associated with the specified `Function`.
+// May be `NULL` if the signature is implicit.
const char* BinaryenFunctionGetType(BinaryenFunctionRef func);
// Gets the number of parameters of the specified `Function`.
BinaryenIndex BinaryenFunctionGetNumParams(BinaryenFunctionRef func);
-// Gets the type of the parameter at the specified index of the specified `Function`.
-BinaryenType BinaryenFunctionGetParam(BinaryenFunctionRef func, BinaryenIndex index);
+// Gets the type of the parameter at the specified index of the specified
+// `Function`.
+BinaryenType BinaryenFunctionGetParam(BinaryenFunctionRef func,
+ BinaryenIndex index);
// Gets the result type of the specified `Function`.
BinaryenType BinaryenFunctionGetResult(BinaryenFunctionRef func);
// Gets the number of additional locals within the specified `Function`.
BinaryenIndex BinaryenFunctionGetNumVars(BinaryenFunctionRef func);
-// Gets the type of the additional local at the specified index within the specified `Function`.
-BinaryenType BinaryenFunctionGetVar(BinaryenFunctionRef func, BinaryenIndex index);
+// Gets the type of the additional local at the specified index within the
+// specified `Function`.
+BinaryenType BinaryenFunctionGetVar(BinaryenFunctionRef func,
+ BinaryenIndex index);
// Gets the body of the specified `Function`.
BinaryenExpressionRef BinaryenFunctionGetBody(BinaryenFunctionRef func);
// Runs the standard optimization passes on the function. Uses the currently set
// global optimize and shrink level.
-void BinaryenFunctionOptimize(BinaryenFunctionRef func, BinaryenModuleRef module);
+void BinaryenFunctionOptimize(BinaryenFunctionRef func,
+ BinaryenModuleRef module);
// Runs the specified passes on the function. Uses the currently set global
// optimize and shrink level.
-void BinaryenFunctionRunPasses(BinaryenFunctionRef func, BinaryenModuleRef module, const char** passes, BinaryenIndex numPasses);
-
-// Sets the debug location of the specified `Expression` within the specified `Function`.
-void BinaryenFunctionSetDebugLocation(BinaryenFunctionRef func, BinaryenExpressionRef expr, BinaryenIndex fileIndex, BinaryenIndex lineNumber, BinaryenIndex columnNumber);
+void BinaryenFunctionRunPasses(BinaryenFunctionRef func,
+ BinaryenModuleRef module,
+ const char** passes,
+ BinaryenIndex numPasses);
+
+// Sets the debug location of the specified `Expression` within the specified
+// `Function`.
+void BinaryenFunctionSetDebugLocation(BinaryenFunctionRef func,
+ BinaryenExpressionRef expr,
+ BinaryenIndex fileIndex,
+ BinaryenIndex lineNumber,
+ BinaryenIndex columnNumber);
//
// ========== Import Operations ==========
@@ -930,37 +1141,53 @@ typedef void* RelooperBlockRef;
RelooperRef RelooperCreate(BinaryenModuleRef module);
// Create a basic block that ends with nothing, or with some simple branching
-RelooperBlockRef RelooperAddBlock(RelooperRef relooper, BinaryenExpressionRef code);
+RelooperBlockRef RelooperAddBlock(RelooperRef relooper,
+ BinaryenExpressionRef code);
// Create a branch to another basic block
-// The branch can have code on it, that is executed as the branch happens. this is useful for phis. otherwise, code can be NULL
-void RelooperAddBranch(RelooperBlockRef from, RelooperBlockRef to, BinaryenExpressionRef condition, BinaryenExpressionRef code);
+// The branch can have code on it, that is executed as the branch happens. this
+// is useful for phis. otherwise, code can be NULL
+void RelooperAddBranch(RelooperBlockRef from,
+ RelooperBlockRef to,
+ BinaryenExpressionRef condition,
+ BinaryenExpressionRef code);
// Create a basic block that ends a switch on a condition
-RelooperBlockRef RelooperAddBlockWithSwitch(RelooperRef relooper, BinaryenExpressionRef code, BinaryenExpressionRef condition);
-
-// Create a switch-style branch to another basic block. The block's switch table will have these indexes going to that target
-void RelooperAddBranchForSwitch(RelooperBlockRef from, RelooperBlockRef to, BinaryenIndex* indexes, BinaryenIndex numIndexes, BinaryenExpressionRef code);
-
-// Generate structed wasm control flow from the CFG of blocks and branches that were created
-// on this relooper instance. This returns the rendered output, and also disposes of the
-// relooper and its blocks and branches, as they are no longer needed.
-// @param labelHelper To render irreducible control flow, we may need a helper variable to
-// guide us to the right target label. This value should be an index of
-// an i32 local variable that is free for us to use.
-BinaryenExpressionRef RelooperRenderAndDispose(RelooperRef relooper, RelooperBlockRef entry, BinaryenIndex labelHelper);
+RelooperBlockRef RelooperAddBlockWithSwitch(RelooperRef relooper,
+ BinaryenExpressionRef code,
+ BinaryenExpressionRef condition);
+
+// Create a switch-style branch to another basic block. The block's switch table
+// will have these indexes going to that target
+void RelooperAddBranchForSwitch(RelooperBlockRef from,
+ RelooperBlockRef to,
+ BinaryenIndex* indexes,
+ BinaryenIndex numIndexes,
+ BinaryenExpressionRef code);
+
+// Generate structed wasm control flow from the CFG of blocks and branches that
+// were created on this relooper instance. This returns the rendered output, and
+// also disposes of the relooper and its blocks and branches, as they are no
+// longer needed.
+// @param labelHelper To render irreducible control flow, we may need a helper
+// variable to guide us to the right target label. This value should be
+// an index of an i32 local variable that is free for us to use.
+BinaryenExpressionRef RelooperRenderAndDispose(RelooperRef relooper,
+ RelooperBlockRef entry,
+ BinaryenIndex labelHelper);
//
// ========= Other APIs =========
//
-// Sets whether API tracing is on or off. It is off by default. When on, each call
-// to an API method will print out C code equivalent to it, which is useful for
-// auto-generating standalone testcases from projects using the API.
-// When calling this to turn on tracing, the prelude of the full program is printed,
-// and when calling it to turn it off, the ending of the program is printed, giving
-// you the full compilable testcase.
-// TODO: compile-time option to enable/disable this feature entirely at build time?
+// Sets whether API tracing is on or off. It is off by default. When on, each
+// call to an API method will print out C code equivalent to it, which is useful
+// for auto-generating standalone testcases from projects using the API. When
+// calling this to turn on tracing, the prelude of the full program is printed,
+// and when calling it to turn it off, the ending of the program is printed,
+// giving you the full compilable testcase.
+// TODO: compile-time option to enable/disable this feature entirely at build
+// time?
void BinaryenSetAPITracing(int on);
//
@@ -968,11 +1195,15 @@ void BinaryenSetAPITracing(int on);
//
// Note that this function has been added because there is no better alternative
-// currently and is scheduled for removal once there is one. It takes the same set
-// of parameters as BinaryenAddFunctionType but instead of adding a new function
-// signature, it returns a pointer to the existing signature or NULL if there is no
-// such signature yet.
-BinaryenFunctionTypeRef BinaryenGetFunctionTypeBySignature(BinaryenModuleRef module, BinaryenType result, BinaryenType* paramTypes, BinaryenIndex numParams);
+// currently and is scheduled for removal once there is one. It takes the same
+// set of parameters as BinaryenAddFunctionType but instead of adding a new
+// function signature, it returns a pointer to the existing signature or NULL if
+// there is no such signature yet.
+BinaryenFunctionTypeRef
+BinaryenGetFunctionTypeBySignature(BinaryenModuleRef module,
+ BinaryenType result,
+ BinaryenType* paramTypes,
+ BinaryenIndex numParams);
#ifdef __cplusplus
} // extern "C"
diff --git a/src/cfg/Relooper.cpp b/src/cfg/Relooper.cpp
index 3acdabd52..8a15fe75c 100644
--- a/src/cfg/Relooper.cpp
+++ b/src/cfg/Relooper.cpp
@@ -16,8 +16,8 @@
#include "Relooper.h"
-#include <string.h>
#include <stdlib.h>
+#include <string.h>
#include <list>
#include <stack>
@@ -29,12 +29,13 @@
namespace CFG {
-template<class T, class U> static bool contains(const T& container, const U& contained) {
+template<class T, class U>
+static bool contains(const T& container, const U& contained) {
return !!container.count(contained);
}
#ifdef RELOOPER_DEBUG
-static void PrintDebug(const char *Format, ...);
+static void PrintDebug(const char* Format, ...);
#define DebugDump(x, ...) Debugging::Dump(x, __VA_ARGS__)
#else
#define PrintDebug(x, ...)
@@ -43,8 +44,12 @@ static void PrintDebug(const char *Format, ...);
// Rendering utilities
-static wasm::Expression* HandleFollowupMultiples(wasm::Expression* Ret, Shape* Parent, RelooperBuilder& Builder, bool InLoop) {
- if (!Parent->Next) return Ret;
+static wasm::Expression* HandleFollowupMultiples(wasm::Expression* Ret,
+ Shape* Parent,
+ RelooperBuilder& Builder,
+ bool InLoop) {
+ if (!Parent->Next)
+ return Ret;
auto* Curr = Ret->dynCast<wasm::Block>();
if (!Curr || Curr->name.is()) {
@@ -53,7 +58,8 @@ static wasm::Expression* HandleFollowupMultiples(wasm::Expression* Ret, Shape* P
// for each multiple after us, we create a block target for breaks to reach
while (Parent->Next) {
auto* Multiple = Shape::IsMultiple(Parent->Next);
- if (!Multiple) break;
+ if (!Multiple)
+ break;
for (auto& iter : Multiple->InnerMap) {
int Id = iter.first;
Shape* Body = iter.second;
@@ -66,9 +72,9 @@ static wasm::Expression* HandleFollowupMultiples(wasm::Expression* Ret, Shape* P
}
Parent->Next = Parent->Next->Next;
}
- // after the multiples is a simple or a loop, in both cases we must hit an entry
- // block, and so this is the last one we need to take into account now (this
- // is why we require that loops hit an entry).
+ // after the multiples is a simple or a loop, in both cases we must hit an
+ // entry block, and so this is the last one we need to take into account now
+ // (this is why we require that loops hit an entry).
if (Parent->Next) {
auto* Simple = Shape::IsSimple(Parent->Next);
if (Simple) {
@@ -99,19 +105,25 @@ static wasm::Expression* HandleFollowupMultiples(wasm::Expression* Ret, Shape* P
// Branch
-Branch::Branch(wasm::Expression* ConditionInit, wasm::Expression* CodeInit) : Condition(ConditionInit), Code(CodeInit) {}
+Branch::Branch(wasm::Expression* ConditionInit, wasm::Expression* CodeInit)
+ : Condition(ConditionInit), Code(CodeInit) {}
-Branch::Branch(std::vector<wasm::Index>&& ValuesInit, wasm::Expression* CodeInit) : Condition(nullptr), Code(CodeInit) {
+Branch::Branch(std::vector<wasm::Index>&& ValuesInit,
+ wasm::Expression* CodeInit)
+ : Condition(nullptr), Code(CodeInit) {
if (ValuesInit.size() > 0) {
SwitchValues = wasm::make_unique<std::vector<wasm::Index>>(ValuesInit);
}
// otherwise, it is the default
}
-wasm::Expression* Branch::Render(RelooperBuilder& Builder, Block* Target, bool SetLabel) {
+wasm::Expression*
+Branch::Render(RelooperBuilder& Builder, Block* Target, bool SetLabel) {
auto* Ret = Builder.makeBlock();
- if (Code) Ret->list.push_back(Code);
- if (SetLabel) Ret->list.push_back(Builder.makeSetLabel(Target->Id));
+ if (Code)
+ Ret->list.push_back(Code);
+ if (SetLabel)
+ Ret->list.push_back(Builder.makeSetLabel(Target->Id));
if (Type == Break) {
Ret->list.push_back(Builder.makeBlockBreak(Target->Id));
} else if (Type == Continue) {
@@ -124,7 +136,9 @@ wasm::Expression* Branch::Render(RelooperBuilder& Builder, Block* Target, bool S
// Block
-Block::Block(wasm::Expression* CodeInit, wasm::Expression* SwitchConditionInit) : Code(CodeInit), SwitchCondition(SwitchConditionInit), IsCheckedMultipleEntry(false) {}
+Block::Block(wasm::Expression* CodeInit, wasm::Expression* SwitchConditionInit)
+ : Code(CodeInit), SwitchCondition(SwitchConditionInit),
+ IsCheckedMultipleEntry(false) {}
Block::~Block() {
for (auto& iter : ProcessedBranchesOut) {
@@ -135,13 +149,19 @@ Block::~Block() {
}
}
-void Block::AddBranchTo(Block* Target, wasm::Expression* Condition, wasm::Expression* Code) {
- assert(!contains(BranchesOut, Target)); // cannot add more than one branch to the same target
+void Block::AddBranchTo(Block* Target,
+ wasm::Expression* Condition,
+ wasm::Expression* Code) {
+ // cannot add more than one branch to the same target
+ assert(!contains(BranchesOut, Target));
BranchesOut[Target] = new Branch(Condition, Code);
}
-void Block::AddSwitchBranchTo(Block* Target, std::vector<wasm::Index>&& Values, wasm::Expression* Code) {
- assert(!contains(BranchesOut, Target)); // cannot add more than one branch to the same target
+void Block::AddSwitchBranchTo(Block* Target,
+ std::vector<wasm::Index>&& Values,
+ wasm::Expression* Code) {
+ // cannot add more than one branch to the same target
+ assert(!contains(BranchesOut, Target));
BranchesOut[Target] = new Branch(std::move(Values), Code);
}
@@ -150,14 +170,16 @@ wasm::Expression* Block::Render(RelooperBuilder& Builder, bool InLoop) {
if (IsCheckedMultipleEntry && InLoop) {
Ret->list.push_back(Builder.makeSetLabel(0));
}
- if (Code) Ret->list.push_back(Code);
+ if (Code)
+ Ret->list.push_back(Code);
if (!ProcessedBranchesOut.size()) {
Ret->finalize();
return Ret;
}
- bool SetLabel = true; // in some cases it is clear we can avoid setting label, see later
+ // in some cases it is clear we can avoid setting label, see later
+ bool SetLabel = true;
// A setting of the label variable (label = x) is necessary if it can
// cause an impact. The main case is where we set label to x, then elsewhere
@@ -189,31 +211,40 @@ wasm::Expression* Block::Render(RelooperBuilder& Builder, bool InLoop) {
// When the Multiple has the same number of groups as we have branches,
// they will all be fused, so it is safe to not set the label at all.
// If a switch, then we can have multiple branches to the same target
- // (in different table indexes), and so this check is not sufficient TODO: optimize
- if (SetLabel && Fused->InnerMap.size() == ProcessedBranchesOut.size() && !SwitchCondition) {
+ // (in different table indexes), and so this check is not sufficient
+ // TODO: optimize
+ if (SetLabel && Fused->InnerMap.size() == ProcessedBranchesOut.size() &&
+ !SwitchCondition) {
SetLabel = false;
}
}
- Block* DefaultTarget = nullptr; // The block we branch to without checking the condition, if none of the other conditions held.
+ // The block we branch to without checking the condition, if none of the other
+ // conditions held.
+ Block* DefaultTarget = nullptr;
// Find the default target, the one without a condition
for (auto& iter : ProcessedBranchesOut) {
- if ((!SwitchCondition && !iter.second->Condition) || (SwitchCondition && !iter.second->SwitchValues)) {
- assert(!DefaultTarget && "block has branches without a default (nullptr for the condition)"); // Must be exactly one default // nullptr
+ if ((!SwitchCondition && !iter.second->Condition) ||
+ (SwitchCondition && !iter.second->SwitchValues)) {
+ assert(!DefaultTarget &&
+ "block has branches without a default (nullptr for the "
+ "condition)"); // Must be exactly one default // nullptr
DefaultTarget = iter.first;
}
}
- assert(DefaultTarget); // Since each Block* must* branch somewhere, this must be set
+ // Since each Block* must* branch somewhere, this must be set
+ assert(DefaultTarget);
- wasm::Expression* Root = nullptr; // root of the main part, that we are about to emit
+ // root of the main part, that we are about to emit
+ wasm::Expression* Root = nullptr;
if (!SwitchCondition) {
// We'll emit a chain of if-elses
wasm::If* CurrIf = nullptr;
- // we build an if, then add a child, then add a child to that, etc., so we must
- // finalize them in reverse order
+ // we build an if, then add a child, then add a child to that, etc., so we
+ // must finalize them in reverse order
std::vector<wasm::If*> finalizeStack;
wasm::Expression* RemainingConditions = nullptr;
@@ -223,9 +254,11 @@ wasm::Expression* Block::Render(RelooperBuilder& Builder, bool InLoop) {
Branch* Details;
if (iter != ProcessedBranchesOut.end()) {
Target = iter->first;
- if (Target == DefaultTarget) continue; // done at the end
+ if (Target == DefaultTarget)
+ continue; // done at the end
Details = iter->second;
- assert(Details->Condition); // must have a condition if this is not the default target
+ // must have a condition if this is not the default target
+ assert(Details->Condition);
} else {
Target = DefaultTarget;
Details = ProcessedBranchesOut[DefaultTarget];
@@ -238,10 +271,13 @@ wasm::Expression* Block::Render(RelooperBuilder& Builder, bool InLoop) {
}
wasm::Expression* CurrContent = nullptr;
bool IsDefault = iter == ProcessedBranchesOut.end();
- if (SetCurrLabel || Details->Type != Branch::Direct || HasFusedContent || Details->Code) {
+ if (SetCurrLabel || Details->Type != Branch::Direct || HasFusedContent ||
+ Details->Code) {
CurrContent = Details->Render(Builder, Target, SetCurrLabel);
if (HasFusedContent) {
- CurrContent = Builder.blockify(CurrContent, Fused->InnerMap.find(Target->Id)->second->Render(Builder, InLoop));
+ CurrContent = Builder.blockify(
+ CurrContent,
+ Fused->InnerMap.find(Target->Id)->second->Render(Builder, InLoop));
}
}
// If there is nothing to show in this branch, omit the condition
@@ -276,12 +312,14 @@ wasm::Expression* Block::Render(RelooperBuilder& Builder, bool InLoop) {
} else {
auto* Now = Builder.makeUnary(wasm::EqZInt32, Details->Condition);
if (RemainingConditions) {
- RemainingConditions = Builder.makeBinary(wasm::AndInt32, RemainingConditions, Now);
+ RemainingConditions =
+ Builder.makeBinary(wasm::AndInt32, RemainingConditions, Now);
} else {
RemainingConditions = Now;
}
}
- if (IsDefault) break;
+ if (IsDefault)
+ break;
}
// finalize the if-chains
@@ -317,17 +355,21 @@ wasm::Expression* Block::Render(RelooperBuilder& Builder, bool InLoop) {
Details->Type = Branch::Direct;
}
wasm::Expression* CurrContent = nullptr;
- if (SetCurrLabel || Details->Type != Branch::Direct || HasFusedContent || Details->Code) {
+ if (SetCurrLabel || Details->Type != Branch::Direct || HasFusedContent ||
+ Details->Code) {
CurrContent = Details->Render(Builder, Target, SetCurrLabel);
if (HasFusedContent) {
- CurrContent = Builder.blockify(CurrContent, Fused->InnerMap.find(Target->Id)->second->Render(Builder, InLoop));
+ CurrContent = Builder.blockify(
+ CurrContent,
+ Fused->InnerMap.find(Target->Id)->second->Render(Builder, InLoop));
}
}
// generate a block to branch to, if we have content
if (CurrContent) {
auto* NextOuter = Builder.makeBlock();
NextOuter->list.push_back(Outer);
- Outer->name = CurrName; // breaking on Outer leads to the content in NextOuter
+ // breaking on Outer leads to the content in NextOuter
+ Outer->name = CurrName;
NextOuter->list.push_back(CurrContent);
// if this is not a dead end, also need to break to the outside
// this is both an optimization, and avoids incorrectness as adding
@@ -340,23 +382,27 @@ wasm::Expression* Block::Render(RelooperBuilder& Builder, bool InLoop) {
} else {
CurrName = SwitchLeave; // just go out straight from the table
if (!Details->SwitchValues) {
- // this is the default, and it has no content. So make the default be the leave
+ // this is the default, and it has no content. So make the default be
+ // the leave
for (auto& Value : Table) {
- if (Value == SwitchDefault) Value = SwitchLeave;
+ if (Value == SwitchDefault)
+ Value = SwitchLeave;
}
SwitchDefault = SwitchLeave;
}
}
if (Details->SwitchValues) {
for (auto Value : *Details->SwitchValues) {
- while (Table.size() <= Value) Table.push_back(SwitchDefault);
+ while (Table.size() <= Value)
+ Table.push_back(SwitchDefault);
Table[Value] = CurrName;
}
}
}
// finish up the whole pattern
Outer->name = SwitchLeave;
- Inner->list.push_back(Builder.makeSwitch(Table, SwitchDefault, SwitchCondition));
+ Inner->list.push_back(
+ Builder.makeSwitch(Table, SwitchDefault, SwitchCondition));
Root = Outer;
}
@@ -379,7 +425,6 @@ wasm::Expression* SimpleShape::Render(RelooperBuilder& Builder, bool InLoop) {
return Ret;
}
-
// MultipleShape
wasm::Expression* MultipleShape::Render(RelooperBuilder& Builder, bool InLoop) {
@@ -389,10 +434,8 @@ wasm::Expression* MultipleShape::Render(RelooperBuilder& Builder, bool InLoop) {
wasm::If* CurrIf = nullptr;
std::vector<wasm::If*> finalizeStack;
for (auto& iter : InnerMap) {
- auto* Now = Builder.makeIf(
- Builder.makeCheckLabel(iter.first),
- iter.second->Render(Builder, InLoop)
- );
+ auto* Now = Builder.makeIf(Builder.makeCheckLabel(iter.first),
+ iter.second->Render(Builder, InLoop));
finalizeStack.push_back(Now);
if (!CurrIf) {
FirstIf = CurrIf = Now;
@@ -418,7 +461,8 @@ wasm::Expression* MultipleShape::Render(RelooperBuilder& Builder, bool InLoop) {
// LoopShape
wasm::Expression* LoopShape::Render(RelooperBuilder& Builder, bool InLoop) {
- wasm::Expression* Ret = Builder.makeLoop(Builder.getShapeContinueName(Id), Inner->Render(Builder, true));
+ wasm::Expression* Ret = Builder.makeLoop(Builder.getShapeContinueName(Id),
+ Inner->Render(Builder, true));
Ret = HandleFollowupMultiples(Ret, this, Builder, InLoop);
if (Next) {
Ret = Builder.makeSequence(Ret, Next->Render(Builder, InLoop));
@@ -428,14 +472,16 @@ wasm::Expression* LoopShape::Render(RelooperBuilder& Builder, bool InLoop) {
// Relooper
-Relooper::Relooper(wasm::Module* ModuleInit) :
- Module(ModuleInit), Root(nullptr), MinSize(false),
- BlockIdCounter(1), ShapeIdCounter(0) { // block ID 0 is reserved for clearings
+Relooper::Relooper(wasm::Module* ModuleInit)
+ : Module(ModuleInit), Root(nullptr), MinSize(false), BlockIdCounter(1),
+ ShapeIdCounter(0) { // block ID 0 is reserved for clearings
}
Relooper::~Relooper() {
- for (unsigned i = 0; i < Blocks.size(); i++) delete Blocks[i];
- for (unsigned i = 0; i < Shapes.size(); i++) delete Shapes[i];
+ for (unsigned i = 0; i < Blocks.size(); i++)
+ delete Blocks[i];
+ for (unsigned i = 0; i < Shapes.size(); i++)
+ delete Shapes[i];
}
void Relooper::AddBlock(Block* New, int Id) {
@@ -462,7 +508,8 @@ struct Liveness : public RelooperRecursor {
while (ToInvestigate.size() > 0) {
Block* Curr = ToInvestigate.front();
ToInvestigate.pop_front();
- if (contains(Live, Curr)) continue;
+ if (contains(Live, Curr))
+ continue;
Live.insert(Curr);
for (auto& iter : Curr->BranchesOut) {
ToInvestigate.push_back(iter.first);
@@ -475,7 +522,8 @@ typedef std::pair<Branch*, Block*> BranchBlock;
struct Optimizer : public RelooperRecursor {
Optimizer(Relooper* Parent) : RelooperRecursor(Parent) {
- // TODO: there are likely some rare but possible O(N^2) cases with this looping
+ // TODO: there are likely some rare but possible O(N^2) cases with this
+ // looping
bool More = true;
#if RELOOPER_OPTIMIZER_DEBUG
std::cout << "pre-optimize\n";
@@ -494,9 +542,9 @@ struct Optimizer : public RelooperRecursor {
More = MergeEquivalentBranches() || More;
More = UnSwitch() || More;
More = MergeConsecutiveBlocks() || More;
- // TODO: Merge identical blocks. This would avoid taking into account their
- // position / how they are reached, which means that the merging
- // may add overhead, so we do it carefully:
+ // TODO: Merge identical blocks. This would avoid taking into account
+ // their position / how they are reached, which means that the merging may
+ // add overhead, so we do it carefully:
// * Merging a large-enough block is good for size, and we do it
// in we are in MinSize mode, which means we can tolerate slightly
// slower throughput.
@@ -541,12 +589,12 @@ struct Optimizer : public RelooperRecursor {
auto* First = Next;
auto* Replacement = First;
#if RELOOPER_OPTIMIZER_DEBUG
- std::cout << " maybeskip from " << Block->Id << " to next=" << Next->Id << '\n';
+ std::cout << " maybeskip from " << Block->Id << " to next=" << Next->Id
+ << '\n';
#endif
std::unordered_set<decltype(Replacement)> Seen;
while (1) {
- if (IsEmpty(Next) &&
- Next->BranchesOut.size() == 1) {
+ if (IsEmpty(Next) && Next->BranchesOut.size() == 1) {
auto iter = Next->BranchesOut.begin();
Block* NextNext = iter->first;
Branch* NextNextBranch = iter->second;
@@ -554,13 +602,13 @@ struct Optimizer : public RelooperRecursor {
if (!NextNextBranch->Code) { // TODO: handle extra code too
// We can skip through!
Next = Replacement = NextNext;
- // If we've already seen this, stop - it's an infinite loop of empty
- // blocks we can skip through.
+ // If we've already seen this, stop - it's an infinite loop of
+ // empty blocks we can skip through.
if (Seen.count(Replacement)) {
- // Stop here. Note that if we started from X and ended up with X once
- // more, then Replacement == First and so lower down we will not
- // report that we did any work, avoiding an infinite loop due to
- // always thinking there is more work to do.
+ // Stop here. Note that if we started from X and ended up with X
+ // once more, then Replacement == First and so lower down we
+ // will not report that we did any work, avoiding an infinite
+ // loop due to always thinking there is more work to do.
break;
} else {
// Otherwise, keep going.
@@ -573,12 +621,14 @@ struct Optimizer : public RelooperRecursor {
}
if (Replacement != First) {
#if RELOOPER_OPTIMIZER_DEBUG
- std::cout << " skip to replacement! " << CurrBlock->Id << " -> " << First->Id << " -> " << Replacement->Id << '\n';
+ std::cout << " skip to replacement! " << CurrBlock->Id << " -> "
+ << First->Id << " -> " << Replacement->Id << '\n';
#endif
Worked = true;
}
- // Add a branch to the target (which may be the unchanged original) in the set of new branches.
- // If it's a replacement, it may collide, and we need to merge.
+ // Add a branch to the target (which may be the unchanged original) in
+ // the set of new branches. If it's a replacement, it may collide, and
+ // we need to merge.
if (NewBranchesOut.count(Replacement)) {
#if RELOOPER_OPTIMIZER_DEBUG
std::cout << " merge\n";
@@ -588,7 +638,8 @@ struct Optimizer : public RelooperRecursor {
NewBranchesOut[Replacement] = NextBranch;
}
}
- CurrBlock->BranchesOut.swap(NewBranchesOut); // FIXME do we leak old unused Branches?
+ // FIXME do we leak old unused Branches?
+ CurrBlock->BranchesOut.swap(NewBranchesOut);
}
return Worked;
}
@@ -603,7 +654,8 @@ struct Optimizer : public RelooperRecursor {
std::cout << "at parent " << ParentBlock->Id << '\n';
#endif
if (ParentBlock->BranchesOut.size() >= 2) {
- std::unordered_map<wasm::HashType, std::vector<BranchBlock>> HashedBranchesOut;
+ std::unordered_map<wasm::HashType, std::vector<BranchBlock>>
+ HashedBranchesOut;
std::vector<Block*> BlocksToErase;
for (auto& iter : ParentBlock->BranchesOut) {
Block* CurrBlock = iter.first;
@@ -633,7 +685,8 @@ struct Optimizer : public RelooperRecursor {
}
#if RELOOPER_OPTIMIZER_DEBUG
else {
- std::cout << " same hash, but not equiv to " << SiblingBlock->Id << '\n';
+ std::cout << " same hash, but not equiv to "
+ << SiblingBlock->Id << '\n';
}
#endif
}
@@ -672,9 +725,11 @@ struct Optimizer : public RelooperRecursor {
wasm::Builder Builder(*Parent->Module);
// Merge in code on the branch as well, if any.
if (NextBranch->Code) {
- CurrBlock->Code = Builder.makeSequence(CurrBlock->Code, NextBranch->Code);
+ CurrBlock->Code =
+ Builder.makeSequence(CurrBlock->Code, NextBranch->Code);
}
- CurrBlock->Code = Builder.makeSequence(CurrBlock->Code, NextBlock->Code);
+ CurrBlock->Code =
+ Builder.makeSequence(CurrBlock->Code, NextBlock->Code);
// Use the next block's branching behavior
CurrBlock->BranchesOut.swap(NextBlock->BranchesOut);
NextBlock->BranchesOut.clear();
@@ -694,7 +749,9 @@ struct Optimizer : public RelooperRecursor {
bool Worked = false;
for (auto* ParentBlock : Parent->Blocks) {
#if RELOOPER_OPTIMIZER_DEBUG
- std::cout << "un-switching at " << ParentBlock->Id << ' ' << !!ParentBlock->SwitchCondition << ' ' << ParentBlock->BranchesOut.size() << '\n';
+ std::cout << "un-switching at " << ParentBlock->Id << ' '
+ << !!ParentBlock->SwitchCondition << ' '
+ << ParentBlock->BranchesOut.size() << '\n';
#endif
if (ParentBlock->SwitchCondition) {
if (ParentBlock->BranchesOut.size() <= 1) {
@@ -761,24 +818,25 @@ private:
SeenUnreachableType = true;
}
};
- std::function<void (wasm::Block*)> FlattenIntoNewList = [&](wasm::Block* Curr) {
- assert(!Curr->name.is());
- for (auto* Item : Curr->list) {
- if (auto* Block = Item->dynCast<wasm::Block>()) {
- if (Block->name.is()) {
- // Leave it whole, it's not a trivial block.
- Add(Block);
+ std::function<void(wasm::Block*)> FlattenIntoNewList =
+ [&](wasm::Block* Curr) {
+ assert(!Curr->name.is());
+ for (auto* Item : Curr->list) {
+ if (auto* Block = Item->dynCast<wasm::Block>()) {
+ if (Block->name.is()) {
+ // Leave it whole, it's not a trivial block.
+ Add(Block);
+ } else {
+ FlattenIntoNewList(Block);
+ }
} else {
- FlattenIntoNewList(Block);
+ // A random item.
+ Add(Item);
}
- } else {
- // A random item.
- Add(Item);
}
- }
- // All the items have been moved out.
- Curr->list.clear();
- };
+ // All the items have been moved out.
+ Curr->list.clear();
+ };
FlattenIntoNewList(Outer);
assert(Outer->list.empty());
Outer->list.swap(NewList);
@@ -831,7 +889,8 @@ private:
if (!IsPossibleCodeEquivalent(ABranch->Condition, BBranch->Condition)) {
return false;
}
- if (!IsPossibleUniquePtrEquivalent(ABranch->SwitchValues, BBranch->SwitchValues)) {
+ if (!IsPossibleUniquePtrEquivalent(ABranch->SwitchValues,
+ BBranch->SwitchValues)) {
return false;
}
if (!IsPossibleCodeEquivalent(ABranch->Code, BBranch->Code)) {
@@ -841,18 +900,25 @@ private:
return true;
}
- // Checks if values referred to by pointers are identical, allowing the code to also be nullptr
+ // Checks if values referred to by pointers are identical, allowing the code
+ // to also be nullptr
template<typename T>
- static bool IsPossibleUniquePtrEquivalent(std::unique_ptr<T>& A, std::unique_ptr<T>& B) {
- if (A == B) return true;
- if (!A || !B) return false;
+ static bool IsPossibleUniquePtrEquivalent(std::unique_ptr<T>& A,
+ std::unique_ptr<T>& B) {
+ if (A == B)
+ return true;
+ if (!A || !B)
+ return false;
return *A == *B;
}
// Checks if code is equivalent, allowing the code to also be nullptr
- static bool IsPossibleCodeEquivalent(wasm::Expression* A, wasm::Expression* B) {
- if (A == B) return true;
- if (!A || !B) return false;
+ static bool IsPossibleCodeEquivalent(wasm::Expression* A,
+ wasm::Expression* B) {
+ if (A == B)
+ return true;
+ if (!A || !B)
+ return false;
return IsCodeEquivalent(A, B);
}
@@ -873,9 +939,9 @@ private:
assert(!Into->Condition);
// Merging into the already-default, nothing to do.
} else {
- Into->SwitchValues->insert(
- Into->SwitchValues->end(),
- Curr->SwitchValues->begin(), Curr->SwitchValues->end());
+ Into->SwitchValues->insert(Into->SwitchValues->end(),
+ Curr->SwitchValues->begin(),
+ Curr->SwitchValues->end());
}
} else {
if (!Curr->Condition) {
@@ -888,11 +954,9 @@ private:
} else {
assert(!Into->SwitchValues);
// Merge them, checking both.
- Into->Condition = wasm::Builder(*Parent->Module).makeBinary(
- wasm::OrInt32,
- Into->Condition,
- Curr->Condition
- );
+ Into->Condition =
+ wasm::Builder(*Parent->Module)
+ .makeBinary(wasm::OrInt32, Into->Condition, Curr->Condition);
}
}
if (!Curr->Code) {
@@ -919,7 +983,8 @@ private:
Ret = wasm::rehash(Ret, 2);
for (auto& Pair : Curr->BranchesOut) {
// Hash the Block* as a pointer TODO: full hash?
- Ret = wasm::rehash(Ret, wasm::HashType(reinterpret_cast<size_t>(Pair.first)));
+ Ret =
+ wasm::rehash(Ret, wasm::HashType(reinterpret_cast<size_t>(Pair.first)));
// Hash the Branch info properly
Ret = wasm::rehash(Ret, Hash(Pair.second));
}
@@ -960,7 +1025,8 @@ void Relooper::Calculate(Block* Entry) {
// Add incoming branches from live blocks, ignoring dead code
for (unsigned i = 0; i < Blocks.size(); i++) {
Block* Curr = Blocks[i];
- if (!contains(Live.Live, Curr)) continue;
+ if (!contains(Live.Live, Curr))
+ continue;
for (auto& iter : Curr->BranchesOut) {
iter.first->BranchesIn.insert(Curr);
}
@@ -977,9 +1043,11 @@ void Relooper::Calculate(Block* Entry) {
Parent->Shapes.push_back(New);
}
- // Create a list of entries from a block. If LimitTo is provided, only results in that set
- // will appear
- void GetBlocksOut(Block* Source, BlockSet& Entries, BlockSet* LimitTo = nullptr) {
+ // Create a list of entries from a block. If LimitTo is provided, only
+ // results in that set will appear
+ void GetBlocksOut(Block* Source,
+ BlockSet& Entries,
+ BlockSet* LimitTo = nullptr) {
for (auto& iter : Source->BranchesOut) {
if (!LimitTo || contains(*LimitTo, iter.first)) {
Entries.insert(iter.first);
@@ -988,10 +1056,14 @@ void Relooper::Calculate(Block* Entry) {
}
// Converts/processes all branchings to a specific target
- void Solipsize(Block* Target, Branch::FlowType Type, Shape* Ancestor, BlockSet &From) {
+ void Solipsize(Block* Target,
+ Branch::FlowType Type,
+ Shape* Ancestor,
+ BlockSet& From) {
PrintDebug("Solipsizing branches into %d\n", Target->Id);
DebugDump(From, " relevant to solipsize: ");
- for (auto iter = Target->BranchesIn.begin(); iter != Target->BranchesIn.end();) {
+ for (auto iter = Target->BranchesIn.begin();
+ iter != Target->BranchesIn.end();) {
Block* Prior = *iter;
if (!contains(From, Prior)) {
iter++;
@@ -1009,7 +1081,7 @@ void Relooper::Calculate(Block* Entry) {
}
}
- Shape* MakeSimple(BlockSet &Blocks, Block* Inner, BlockSet &NextEntries) {
+ Shape* MakeSimple(BlockSet& Blocks, Block* Inner, BlockSet& NextEntries) {
PrintDebug("creating simple block with block #%d\n", Inner->Id);
SimpleShape* Simple = new SimpleShape;
Notice(Simple);
@@ -1027,9 +1099,10 @@ void Relooper::Calculate(Block* Entry) {
return Simple;
}
- Shape* MakeLoop(BlockSet &Blocks, BlockSet& Entries, BlockSet &NextEntries) {
- // Find the inner blocks in this loop. Proceed backwards from the entries until
- // you reach a seen block, collecting as you go.
+ Shape*
+ MakeLoop(BlockSet& Blocks, BlockSet& Entries, BlockSet& NextEntries) {
+ // Find the inner blocks in this loop. Proceed backwards from the entries
+ // until you reach a seen block, collecting as you go.
BlockSet InnerBlocks;
BlockSet Queue = Entries;
while (Queue.size() > 0) {
@@ -1123,12 +1196,14 @@ void Relooper::Calculate(Block* Entry) {
LoopShape* Loop = new LoopShape();
Notice(Loop);
- // Solipsize the loop, replacing with break/continue and marking branches as Processed (will not affect later calculations)
- // A. Branches to the loop entries become a continue to this shape
+ // Solipsize the loop, replacing with break/continue and marking branches
+ // as Processed (will not affect later calculations) A. Branches to the
+ // loop entries become a continue to this shape
for (auto* Entry : Entries) {
Solipsize(Entry, Branch::Continue, Loop, InnerBlocks);
}
- // B. Branches to outside the loop (a next entry) become breaks on this shape
+ // B. Branches to outside the loop (a next entry) become breaks on this
+ // shape
for (auto* Next : NextEntries) {
Solipsize(Next, Branch::Break, Loop, InnerBlocks);
}
@@ -1139,29 +1214,38 @@ void Relooper::Calculate(Block* Entry) {
return Loop;
}
- // For each entry, find the independent group reachable by it. The independent group is
- // the entry itself, plus all the blocks it can reach that cannot be directly reached by another entry. Note that we
- // ignore directly reaching the entry itself by another entry.
+ // For each entry, find the independent group reachable by it. The
+ // independent group is the entry itself, plus all the blocks it can reach
+ // that cannot be directly reached by another entry. Note that we ignore
+ // directly reaching the entry itself by another entry.
// @param Ignore - previous blocks that are irrelevant
- void FindIndependentGroups(BlockSet &Entries, BlockBlockSetMap& IndependentGroups, BlockSet* Ignore = nullptr) {
+ void FindIndependentGroups(BlockSet& Entries,
+ BlockBlockSetMap& IndependentGroups,
+ BlockSet* Ignore = nullptr) {
typedef std::map<Block*, Block*> BlockBlockMap;
struct HelperClass {
BlockBlockSetMap& IndependentGroups;
- BlockBlockMap Ownership; // For each block, which entry it belongs to. We have reached it from there.
+ // For each block, which entry it belongs to. We have reached it from
+ // there.
+ BlockBlockMap Ownership;
- HelperClass(BlockBlockSetMap& IndependentGroupsInit) : IndependentGroups(IndependentGroupsInit) {}
+ HelperClass(BlockBlockSetMap& IndependentGroupsInit)
+ : IndependentGroups(IndependentGroupsInit) {}
void InvalidateWithChildren(Block* New) { // TODO: rename New
- BlockList ToInvalidate; // Being in the list means you need to be invalidated
+ // Being in the list means you need to be invalidated
+ BlockList ToInvalidate;
ToInvalidate.push_back(New);
while (ToInvalidate.size() > 0) {
Block* Invalidatee = ToInvalidate.front();
ToInvalidate.pop_front();
Block* Owner = Ownership[Invalidatee];
- if (contains(IndependentGroups, Owner)) { // Owner may have been invalidated, do not add to IndependentGroups!
+ // Owner may have been invalidated, do not add to IndependentGroups!
+ if (contains(IndependentGroups, Owner)) {
IndependentGroups[Owner].erase(Invalidatee);
}
- if (Ownership[Invalidatee]) { // may have been seen before and invalidated already
+ // may have been seen before and invalidated already
+ if (Ownership[Invalidatee]) {
Ownership[Invalidatee] = nullptr;
for (auto& iter : Invalidatee->BranchesOut) {
Block* Target = iter.first;
@@ -1180,12 +1264,14 @@ void Relooper::Calculate(Block* Entry) {
HelperClass Helper(IndependentGroups);
// We flow out from each of the entries, simultaneously.
- // When we reach a new block, we add it as belonging to the one we got to it from.
- // If we reach a new block that is already marked as belonging to someone, it is reachable by
- // two entries and is not valid for any of them. Remove it and all it can reach that have been
- // visited.
-
- BlockList Queue; // Being in the queue means we just added this item, and we need to add its children
+ // When we reach a new block, we add it as belonging to the one we got to
+ // it from. If we reach a new block that is already marked as belonging to
+ // someone, it is reachable by two entries and is not valid for any of
+ // them. Remove it and all it can reach that have been visited.
+
+ // Being in the queue means we just added this item, and we need to add
+ // its children
+ BlockList Queue;
for (auto* Entry : Entries) {
Helper.Ownership[Entry] = Entry;
IndependentGroups[Entry].insert(Entry);
@@ -1194,8 +1280,12 @@ void Relooper::Calculate(Block* Entry) {
while (Queue.size() > 0) {
Block* Curr = Queue.front();
Queue.pop_front();
- Block* Owner = Helper.Ownership[Curr]; // Curr must be in the ownership map if we are in the queue
- if (!Owner) continue; // we have been invalidated meanwhile after being reached from two entries
+ // Curr must be in the ownership map if we are in the queue
+ Block* Owner = Helper.Ownership[Curr];
+ if (!Owner)
+ // we have been invalidated meanwhile after being reached from two
+ // entries
+ continue;
// Add all children
for (auto& iter : Curr->BranchesOut) {
Block* New = iter.first;
@@ -1208,27 +1298,31 @@ void Relooper::Calculate(Block* Entry) {
continue;
}
Block* NewOwner = Known->second;
- if (!NewOwner) continue; // We reached an invalidated node
+ if (!NewOwner)
+ continue; // We reached an invalidated node
if (NewOwner != Owner) {
- // Invalidate this and all reachable that we have seen - we reached this from two locations
+ // Invalidate this and all reachable that we have seen - we reached
+ // this from two locations
Helper.InvalidateWithChildren(New);
}
// otherwise, we have the same owner, so do nothing
}
}
- // Having processed all the interesting blocks, we remain with just one potential issue:
- // If a->b, and a was invalidated, but then b was later reached by someone else, we must
- // invalidate b. To check for this, we go over all elements in the independent groups,
- // if an element has a parent which does *not* have the same owner, we must remove it
- // and all its children.
+ // Having processed all the interesting blocks, we remain with just one
+ // potential issue: If a->b, and a was invalidated, but then b was later
+ // reached by someone else, we must invalidate b. To check for this, we go
+ // over all elements in the independent groups, if an element has a parent
+ // which does *not* have the same owner, we must remove it and all its
+ // children.
for (auto* Entry : Entries) {
- BlockSet &CurrGroup = IndependentGroups[Entry];
+ BlockSet& CurrGroup = IndependentGroups[Entry];
BlockList ToInvalidate;
for (auto* Child : CurrGroup) {
for (auto* Parent : Child->BranchesIn) {
- if (Ignore && contains(*Ignore, Parent)) continue;
+ if (Ignore && contains(*Ignore, Parent))
+ continue;
if (Helper.Ownership[Parent] != Helper.Ownership[Child]) {
ToInvalidate.push_back(Child);
}
@@ -1256,14 +1350,19 @@ void Relooper::Calculate(Block* Entry) {
#endif
}
- Shape* MakeMultiple(BlockSet &Blocks, BlockSet& Entries, BlockBlockSetMap& IndependentGroups, BlockSet &NextEntries, bool IsCheckedMultiple) {
- PrintDebug("creating multiple block with %d inner groups\n", IndependentGroups.size());
+ Shape* MakeMultiple(BlockSet& Blocks,
+ BlockSet& Entries,
+ BlockBlockSetMap& IndependentGroups,
+ BlockSet& NextEntries,
+ bool IsCheckedMultiple) {
+ PrintDebug("creating multiple block with %d inner groups\n",
+ IndependentGroups.size());
MultipleShape* Multiple = new MultipleShape();
Notice(Multiple);
BlockSet CurrEntries;
for (auto& iter : IndependentGroups) {
Block* CurrEntry = iter.first;
- BlockSet &CurrBlocks = iter.second;
+ BlockSet& CurrBlocks = iter.second;
PrintDebug(" multiple group with entry %d:\n", CurrEntry->Id);
DebugDump(CurrBlocks, " ");
// Create inner block
@@ -1273,13 +1372,14 @@ void Relooper::Calculate(Block* Entry) {
// Remove the block from the remaining blocks
Blocks.erase(CurrInner);
// Find new next entries and fix branches to them
- for (auto iter = CurrInner->BranchesOut.begin(); iter != CurrInner->BranchesOut.end();) {
+ for (auto iter = CurrInner->BranchesOut.begin();
+ iter != CurrInner->BranchesOut.end();) {
Block* CurrTarget = iter->first;
auto Next = iter;
Next++;
if (!contains(CurrBlocks, CurrTarget)) {
NextEntries.insert(CurrTarget);
- Solipsize(CurrTarget, Branch::Break, Multiple, CurrBlocks);
+ Solipsize(CurrTarget, Branch::Break, Multiple, CurrBlocks);
}
iter = Next; // increment carefully because Solipsize can remove us
}
@@ -1301,10 +1401,12 @@ void Relooper::Calculate(Block* Entry) {
// Main function.
// Process a set of blocks with specified entries, returns a shape
- // The Make* functions receive a NextEntries. If they fill it with data, those are the entries for the
- // ->Next block on them, and the blocks are what remains in Blocks (which Make* modify). In this way
- // we avoid recursing on Next (imagine a long chain of Simples, if we recursed we could blow the stack).
- Shape* Process(BlockSet &Blocks, BlockSet& InitialEntries) {
+ // The Make* functions receive a NextEntries. If they fill it with data,
+ // those are the entries for the
+ // ->Next block on them, and the blocks are what remains in Blocks (which
+ // Make* modify). In this way we avoid recursing on Next (imagine a long
+ // chain of Simples, if we recursed we could blow the stack).
+ Shape* Process(BlockSet& Blocks, BlockSet& InitialEntries) {
PrintDebug("Process() called\n", 0);
BlockSet* Entries = &InitialEntries;
BlockSet TempEntries[2];
@@ -1312,24 +1414,30 @@ void Relooper::Calculate(Block* Entry) {
BlockSet* NextEntries;
Shape* Ret = nullptr;
Shape* Prev = nullptr;
- #define Make(call) \
- Shape* Temp = call; \
- if (Prev) Prev->Next = Temp; \
- if (!Ret) Ret = Temp; \
- if (!NextEntries->size()) { PrintDebug("Process() returning\n", 0); return Ret; } \
- Prev = Temp; \
- Entries = NextEntries; \
- continue;
+#define Make(call) \
+ Shape* Temp = call; \
+ if (Prev) \
+ Prev->Next = Temp; \
+ if (!Ret) \
+ Ret = Temp; \
+ if (!NextEntries->size()) { \
+ PrintDebug("Process() returning\n", 0); \
+ return Ret; \
+ } \
+ Prev = Temp; \
+ Entries = NextEntries; \
+ continue;
while (1) {
PrintDebug("Process() running\n", 0);
DebugDump(Blocks, " blocks : ");
DebugDump(*Entries, " entries: ");
- CurrTempIndex = 1-CurrTempIndex;
+ CurrTempIndex = 1 - CurrTempIndex;
NextEntries = &TempEntries[CurrTempIndex];
NextEntries->clear();
- if (Entries->size() == 0) return Ret;
+ if (Entries->size() == 0)
+ return Ret;
if (Entries->size() == 1) {
Block* Curr = *(Entries->begin());
if (Curr->BranchesIn.size() == 0) {
@@ -1341,41 +1449,53 @@ void Relooper::Calculate(Block* Entry) {
}
// More than one entry, try to eliminate through a Multiple groups of
- // independent blocks from an entry/ies. It is important to remove through
- // multiples as opposed to looping since the former is more performant.
+ // independent blocks from an entry/ies. It is important to remove
+ // through multiples as opposed to looping since the former is more
+ // performant.
BlockBlockSetMap IndependentGroups;
FindIndependentGroups(*Entries, IndependentGroups);
PrintDebug("Independent groups: %d\n", IndependentGroups.size());
if (IndependentGroups.size() > 0) {
- // We can handle a group in a multiple if its entry cannot be reached by another group.
- // Note that it might be reachable by itself - a loop. But that is fine, we will create
- // a loop inside the multiple block, which is both the performant order to do it, and
- // preserves the property that a loop will always reach an entry.
- for (auto iter = IndependentGroups.begin(); iter != IndependentGroups.end();) {
+ // We can handle a group in a multiple if its entry cannot be reached
+ // by another group. Note that it might be reachable by itself - a
+ // loop. But that is fine, we will create a loop inside the multiple
+ // block, which is both the performant order to do it, and preserves
+ // the property that a loop will always reach an entry.
+ for (auto iter = IndependentGroups.begin();
+ iter != IndependentGroups.end();) {
Block* Entry = iter->first;
- BlockSet &Group = iter->second;
+ BlockSet& Group = iter->second;
auto curr = iter++; // iterate carefully, we may delete
- for (auto iterBranch = Entry->BranchesIn.begin(); iterBranch != Entry->BranchesIn.end(); iterBranch++) {
+ for (auto iterBranch = Entry->BranchesIn.begin();
+ iterBranch != Entry->BranchesIn.end();
+ iterBranch++) {
Block* Origin = *iterBranch;
if (!contains(Group, Origin)) {
// Reached from outside the group, so we cannot handle this
- PrintDebug("Cannot handle group with entry %d because of incoming branch from %d\n", Entry->Id, Origin->Id);
+ PrintDebug("Cannot handle group with entry %d because of "
+ "incoming branch from %d\n",
+ Entry->Id,
+ Origin->Id);
IndependentGroups.erase(curr);
break;
}
}
}
- // As an optimization, if we have 2 independent groups, and one is a small dead end, we can handle only that dead end.
- // The other then becomes a Next - without nesting in the code and recursion in the analysis.
+ // As an optimization, if we have 2 independent groups, and one is a
+ // small dead end, we can handle only that dead end. The other then
+ // becomes a Next - without nesting in the code and recursion in the
+ // analysis.
// TODO: if the larger is the only dead end, handle that too
// TODO: handle >2 groups
- // TODO: handle not just dead ends, but also that do not branch to the NextEntries. However, must be careful
- // there since we create a Next, and that Next can prevent eliminating a break (since we no longer
- // naturally reach the same place), which may necessitate a one-time loop, which makes the unnesting
- // pointless.
+ // TODO: handle not just dead ends, but also that do not branch to the
+ // NextEntries. However, must be careful
+ // there since we create a Next, and that Next can prevent
+ // eliminating a break (since we no longer naturally reach the
+ // same place), which may necessitate a one-time loop, which
+ // makes the unnesting pointless.
if (IndependentGroups.size() == 2) {
// Find the smaller one
auto iter = IndependentGroups.begin();
@@ -1384,15 +1504,19 @@ void Relooper::Calculate(Block* Entry) {
iter++;
Block* LargeEntry = iter->first;
int LargeSize = iter->second.size();
- if (SmallSize != LargeSize) { // ignore the case where they are identical - keep things symmetrical there
+ // ignore the case where they are identical - keep things
+ // symmetrical there
+ if (SmallSize != LargeSize) {
if (SmallSize > LargeSize) {
Block* Temp = SmallEntry;
SmallEntry = LargeEntry;
- LargeEntry = Temp; // Note: we did not flip the Sizes too, they are now invalid. TODO: use the smaller size as a limit?
+ // Note: we did not flip the Sizes too, they are now invalid.
+ // TODO: use the smaller size as a limit?
+ LargeEntry = Temp;
}
// Check if dead end
bool DeadEnd = true;
- BlockSet &SmallGroup = IndependentGroups[SmallEntry];
+ BlockSet& SmallGroup = IndependentGroups[SmallEntry];
for (auto* Curr : SmallGroup) {
for (auto& iter : Curr->BranchesOut) {
Block* Target = iter.first;
@@ -1401,23 +1525,28 @@ void Relooper::Calculate(Block* Entry) {
break;
}
}
- if (!DeadEnd) break;
+ if (!DeadEnd)
+ break;
}
if (DeadEnd) {
- PrintDebug("Removing nesting by not handling large group because small group is dead end\n", 0);
+ PrintDebug("Removing nesting by not handling large group "
+ "because small group is dead end\n",
+ 0);
IndependentGroups.erase(LargeEntry);
}
}
}
- PrintDebug("Handleable independent groups: %d\n", IndependentGroups.size());
+ PrintDebug("Handleable independent groups: %d\n",
+ IndependentGroups.size());
if (IndependentGroups.size() > 0) {
// Some groups removable ==> Multiple
- // This is a checked multiple if it has an entry that is an entry to this Process call, that is,
- // if we can reach it from outside this set of blocks, then we must check the label variable
- // to do so. Otherwise, if it is just internal blocks, those can always be jumped to forward,
- // without using the label variable
+ // This is a checked multiple if it has an entry that is an entry to
+ // this Process call, that is, if we can reach it from outside this
+ // set of blocks, then we must check the label variable to do so.
+ // Otherwise, if it is just internal blocks, those can always be
+ // jumped to forward, without using the label variable
bool Checked = false;
for (auto* Entry : *Entries) {
if (InitialEntries.count(Entry)) {
@@ -1425,7 +1554,8 @@ void Relooper::Calculate(Block* Entry) {
break;
}
}
- Make(MakeMultiple(Blocks, *Entries, IndependentGroups, *NextEntries, Checked));
+ Make(MakeMultiple(
+ Blocks, *Entries, IndependentGroups, *NextEntries, Checked));
}
}
// No independent groups, must be loopable ==> Loop
@@ -1461,10 +1591,13 @@ wasm::Expression* Relooper::Render(RelooperBuilder& Builder) {
#ifdef RELOOPER_DEBUG
// Debugging
-void Debugging::Dump(Block* Curr, const char *prefix) {
- if (prefix) std::cout << prefix << ": ";
- std::cout << Curr->Id << " [code " << *Curr->Code << "] [switch? " << !!Curr->SwitchCondition << "]\n";
- for (auto iter2 = Curr->BranchesOut.begin(); iter2 != Curr->BranchesOut.end(); iter2++) {
+void Debugging::Dump(Block* Curr, const char* prefix) {
+ if (prefix)
+ std::cout << prefix << ": ";
+ std::cout << Curr->Id << " [code " << *Curr->Code << "] [switch? "
+ << !!Curr->SwitchCondition << "]\n";
+ for (auto iter2 = Curr->BranchesOut.begin(); iter2 != Curr->BranchesOut.end();
+ iter2++) {
Block* Other = iter2->first;
Branch* Br = iter2->second;
std::cout << " -> " << Other->Id << ' ';
@@ -1479,21 +1612,24 @@ void Debugging::Dump(Block* Curr, const char *prefix) {
} else {
std::cout << "[default] ";
}
- if (Br->Code) std::cout << "[phi " << *Br->Code << "] ";
+ if (Br->Code)
+ std::cout << "[phi " << *Br->Code << "] ";
std::cout << '\n';
}
std::cout << '\n';
}
-void Debugging::Dump(BlockSet &Blocks, const char *prefix) {
- if (prefix) std::cout << prefix << ": ";
+void Debugging::Dump(BlockSet& Blocks, const char* prefix) {
+ if (prefix)
+ std::cout << prefix << ": ";
for (auto* Curr : Blocks) {
Dump(Curr);
}
}
-void Debugging::Dump(Shape* S, const char *prefix) {
- if (prefix) std::cout << prefix << ": ";
+void Debugging::Dump(Shape* S, const char* prefix) {
+ if (prefix)
+ std::cout << prefix << ": ";
if (!S) {
printf(" (null)\n");
return;
@@ -1513,7 +1649,7 @@ void Debugging::Dump(Shape* S, const char *prefix) {
}
}
-static void PrintDebug(const char *Format, ...) {
+static void PrintDebug(const char* Format, ...) {
printf("// ");
va_list Args;
va_start(Args, Format);
diff --git a/src/cfg/Relooper.h b/src/cfg/Relooper.h
index 5773721cd..c38cb56b3 100644
--- a/src/cfg/Relooper.h
+++ b/src/cfg/Relooper.h
@@ -19,12 +19,16 @@ This is an optimized C++ implemention of the Relooper algorithm originally
developed as part of Emscripten. This implementation includes optimizations
added since the original academic paper [1] was published about it.
-[1] Alon Zakai. 2011. Emscripten: an LLVM-to-JavaScript compiler. In Proceedings of the ACM international conference companion on Object oriented programming systems languages and applications companion (SPLASH '11). ACM, New York, NY, USA, 301-312. DOI=10.1145/2048147.2048224 http://doi.acm.org/10.1145/2048147.2048224
+[1] Alon Zakai. 2011. Emscripten: an LLVM-to-JavaScript compiler. In Proceedings
+of the ACM international conference companion on Object oriented programming
+systems languages and applications companion (SPLASH '11). ACM, New York, NY,
+USA, 301-312. DOI=10.1145/2048147.2048224
+http://doi.acm.org/10.1145/2048147.2048224
*/
#include <assert.h>
-#include <stdio.h>
#include <stdarg.h>
+#include <stdio.h>
#include <stdlib.h>
#include <deque>
@@ -33,8 +37,8 @@ added since the original academic paper [1] was published about it.
#include <memory>
#include <set>
-#include "wasm.h"
#include "wasm-builder.h"
+#include "wasm.h"
namespace CFG {
@@ -42,7 +46,8 @@ class RelooperBuilder : public wasm::Builder {
wasm::Index labelHelper;
public:
- RelooperBuilder(wasm::Module& wasm, wasm::Index labelHelper) : wasm::Builder(wasm), labelHelper(labelHelper) {}
+ RelooperBuilder(wasm::Module& wasm, wasm::Index labelHelper)
+ : wasm::Builder(wasm), labelHelper(labelHelper) {}
wasm::GetLocal* makeGetLabel() {
return makeGetLocal(labelHelper, wasm::i32);
@@ -51,15 +56,17 @@ public:
return makeSetLocal(labelHelper, makeConst(wasm::Literal(int32_t(value))));
}
wasm::Binary* makeCheckLabel(wasm::Index value) {
- return makeBinary(wasm::EqInt32, makeGetLabel(), makeConst(wasm::Literal(int32_t(value))));
+ return makeBinary(
+ wasm::EqInt32, makeGetLabel(), makeConst(wasm::Literal(int32_t(value))));
}
- // breaks are on blocks, as they can be specific, we make one wasm block per basic block
+ // breaks are on blocks, as they can be specific, we make one wasm block per
+ // basic block
wasm::Break* makeBlockBreak(int id) {
return wasm::Builder::makeBreak(getBlockBreakName(id));
}
- // continues are on shapes, as there is one per loop, and if we have more than one
- // going there, it is irreducible control flow anyhow
+ // continues are on shapes, as there is one per loop, and if we have more than
+ // one going there, it is irreducible control flow anyhow
wasm::Break* makeShapeContinue(int id) {
return wasm::Builder::makeBreak(getShapeContinueName(id));
}
@@ -78,42 +85,49 @@ struct Shape;
// Info about a branching from one block to another
struct Branch {
enum FlowType {
- Direct = 0, // We will directly reach the right location through other means, no need for continue or break
+ Direct = 0, // We will directly reach the right location through other
+ // means, no need for continue or break
Break = 1,
Continue = 2
};
- Shape* Ancestor = nullptr; // If not NULL, this shape is the relevant one for purposes of getting to the target block. We break or continue on it
- Branch::FlowType Type; // If Ancestor is not NULL, this says whether to break or continue
-
- // A branch either has a condition expression if the block ends in ifs, or if the block ends in a switch, then a list of indexes, which
- // becomes the indexes in the table of the switch. If not a switch, the condition can be any expression (or nullptr for the
- // branch taken when no other condition is true)
- // A condition must not have side effects, as the Relooper can reorder or eliminate condition checking.
- // This must not have side effects.
+ // If not NULL, this shape is the relevant one for purposes of getting to the
+ // target block. We break or continue on it
+ Shape* Ancestor = nullptr;
+ // If Ancestor is not NULL, this says whether to break or continue
+ Branch::FlowType Type;
+
+ // A branch either has a condition expression if the block ends in ifs, or if
+ // the block ends in a switch, then a list of indexes, which becomes the
+ // indexes in the table of the switch. If not a switch, the condition can be
+ // any expression (or nullptr for the branch taken when no other condition is
+ // true) A condition must not have side effects, as the Relooper can reorder
+ // or eliminate condition checking. This must not have side effects.
wasm::Expression* Condition;
- // Switches are rare, so have just a pointer for their values. This contains the values
- // for which the branch will be taken, or for the default it is simply not present.
+ // Switches are rare, so have just a pointer for their values. This contains
+ // the values for which the branch will be taken, or for the default it is
+ // simply not present.
std::unique_ptr<std::vector<wasm::Index>> SwitchValues;
- // If provided, code that is run right before the branch is taken. This is useful for phis.
+ // If provided, code that is run right before the branch is taken. This is
+ // useful for phis.
wasm::Expression* Code;
Branch(wasm::Expression* ConditionInit, wasm::Expression* CodeInit = nullptr);
- Branch(std::vector<wasm::Index>&& ValuesInit, wasm::Expression* CodeInit = nullptr);
+ Branch(std::vector<wasm::Index>&& ValuesInit,
+ wasm::Expression* CodeInit = nullptr);
// Emits code for branch
- wasm::Expression* Render(RelooperBuilder& Builder, Block* Target, bool SetLabel);
+ wasm::Expression*
+ Render(RelooperBuilder& Builder, Block* Target, bool SetLabel);
};
// like std::set, except that begin() -> end() iterates in the
// order that elements were added to the set (not in the order
// of operator<(T, T))
-template<typename T>
-struct InsertOrderedSet
-{
- std::map<T, typename std::list<T>::iterator> Map;
- std::list<T> List;
+template<typename T> struct InsertOrderedSet {
+ std::map<T, typename std::list<T>::iterator> Map;
+ std::list<T> List;
typedef typename std::list<T>::iterator iterator;
iterator begin() { return List.begin(); }
@@ -152,9 +166,7 @@ struct InsertOrderedSet
size_t count(const T& val) const { return Map.count(val); }
InsertOrderedSet() = default;
- InsertOrderedSet(const InsertOrderedSet& other) {
- *this = other;
- }
+ InsertOrderedSet(const InsertOrderedSet& other) { *this = other; }
InsertOrderedSet& operator=(const InsertOrderedSet& other) {
clear();
for (auto i : other.List) {
@@ -167,11 +179,9 @@ struct InsertOrderedSet
// like std::map, except that begin() -> end() iterates in the
// order that elements were added to the map (not in the order
// of operator<(Key, Key))
-template<typename Key, typename T>
-struct InsertOrderedMap
-{
- std::map<Key, typename std::list<std::pair<Key,T>>::iterator> Map;
- std::list<std::pair<Key,T>> List;
+template<typename Key, typename T> struct InsertOrderedMap {
+ std::map<Key, typename std::list<std::pair<Key, T>>::iterator> Map;
+ std::list<std::pair<Key, T>> List;
T& operator[](const Key& k) {
auto it = Map.find(k);
@@ -184,7 +194,7 @@ struct InsertOrderedMap
return it->second->second;
}
- typedef typename std::list<std::pair<Key,T>>::iterator iterator;
+ typedef typename std::list<std::pair<Key, T>>::iterator iterator;
iterator begin() { return List.begin(); }
iterator end() { return List.end(); }
@@ -196,9 +206,7 @@ struct InsertOrderedMap
}
}
- void erase(iterator position) {
- erase(position->first);
- }
+ void erase(iterator position) { erase(position->first); }
void clear() {
Map.clear();
@@ -224,50 +232,61 @@ struct InsertOrderedMap
bool operator==(const InsertOrderedMap& other) {
return Map == other.Map && List == other.List;
}
- bool operator!=(const InsertOrderedMap& other) {
- return !(*this == other);
- }
+ bool operator!=(const InsertOrderedMap& other) { return !(*this == other); }
};
-
typedef InsertOrderedSet<Block*> BlockSet;
typedef InsertOrderedMap<Block*, Branch*> BlockBranchMap;
// Represents a basic block of code - some instructions that end with a
// control flow modifier (a branch, return or throw).
struct Block {
- // Branches become processed after we finish the shape relevant to them. For example,
- // when we recreate a loop, branches to the loop start become continues and are now
- // processed. When we calculate what shape to generate from a set of blocks, we ignore
- // processed branches.
- // Blocks own the Branch objects they use, and destroy them when done.
+ // Branches become processed after we finish the shape relevant to them. For
+ // example, when we recreate a loop, branches to the loop start become
+ // continues and are now processed. When we calculate what shape to generate
+ // from a set of blocks, we ignore processed branches. Blocks own the Branch
+ // objects they use, and destroy them when done.
BlockBranchMap BranchesOut;
BlockSet BranchesIn;
BlockBranchMap ProcessedBranchesOut;
BlockSet ProcessedBranchesIn;
Shape* Parent = nullptr; // The shape we are directly inside
int Id = -1; // A unique identifier, defined when added to relooper
- wasm::Expression* Code; // The code in this block. This can be arbitrary wasm code, including internal control flow, it should just not branch to the outside
- wasm::Expression* SwitchCondition; // If nullptr, then this block ends in ifs (or nothing). otherwise, this block ends in a switch, done on this condition
- bool IsCheckedMultipleEntry; // If true, we are a multiple entry, so reaching us requires setting the label variable
-
- Block(wasm::Expression* CodeInit, wasm::Expression* SwitchConditionInit = nullptr);
+ // The code in this block. This can be arbitrary wasm code, including internal
+ // control flow, it should just not branch to the outside
+ wasm::Expression* Code;
+ // If nullptr, then this block ends in ifs (or nothing). otherwise, this block
+ // ends in a switch, done on this condition
+ wasm::Expression* SwitchCondition;
+ // If true, we are a multiple entry, so reaching us requires setting the label
+ // variable
+ bool IsCheckedMultipleEntry;
+
+ Block(wasm::Expression* CodeInit,
+ wasm::Expression* SwitchConditionInit = nullptr);
~Block();
- // Add a branch: if the condition holds we branch (or if null, we branch if all others failed)
- // Note that there can be only one branch from A to B (if you need multiple conditions for the branch,
- // create a more interesting expression in the Condition).
- // If a Block has no outgoing branches, the contents in Code must contain a terminating
- // instruction, as the relooper doesn't know whether you want control flow to stop with
- // an `unreachable` or a `return` or something else (if you forget to do this, control
- // flow may continue into the block that happens to be emitted right after it).
- // Internally, adding a branch only adds the outgoing branch. The matching incoming branch
- // on the target is added by the Relooper itself as it works.
- void AddBranchTo(Block* Target, wasm::Expression* Condition, wasm::Expression* Code = nullptr);
-
- // Add a switch branch: if the switch condition is one of these values, we branch (or if the list is empty, we are the default)
- // Note that there can be only one branch from A to B (if you need multiple values for the branch, that's what the array and default are for).
- void AddSwitchBranchTo(Block* Target, std::vector<wasm::Index>&& Values, wasm::Expression* Code = nullptr);
+ // Add a branch: if the condition holds we branch (or if null, we branch if
+ // all others failed) Note that there can be only one branch from A to B (if
+ // you need multiple conditions for the branch, create a more interesting
+ // expression in the Condition). If a Block has no outgoing branches, the
+ // contents in Code must contain a terminating instruction, as the relooper
+ // doesn't know whether you want control flow to stop with an `unreachable` or
+ // a `return` or something else (if you forget to do this, control flow may
+ // continue into the block that happens to be emitted right after it).
+ // Internally, adding a branch only adds the outgoing branch. The matching
+ // incoming branch on the target is added by the Relooper itself as it works.
+ void AddBranchTo(Block* Target,
+ wasm::Expression* Condition,
+ wasm::Expression* Code = nullptr);
+
+ // Add a switch branch: if the switch condition is one of these values, we
+ // branch (or if the list is empty, we are the default) Note that there can be
+ // only one branch from A to B (if you need multiple values for the branch,
+ // that's what the array and default are for).
+ void AddSwitchBranchTo(Block* Target,
+ std::vector<wasm::Index>&& Values,
+ wasm::Expression* Code = nullptr);
// Emit code for the block, including its contents and branchings out
wasm::Expression* Render(RelooperBuilder& Builder, bool InLoop);
@@ -296,15 +315,16 @@ struct MultipleShape;
struct LoopShape;
struct Shape {
- int Id = -1; // A unique identifier. Used to identify loops, labels are Lx where x is the Id. Defined when added to relooper
- Shape* Next = nullptr; // The shape that will appear in the code right after this one
- Shape* Natural; // The shape that control flow gets to naturally (if there is Next, then this is Next)
-
- enum ShapeType {
- Simple,
- Multiple,
- Loop
- };
+ // A unique identifier. Used to identify loops, labels are Lx where x is the
+ // Id. Defined when added to relooper
+ int Id = -1;
+ // The shape that will appear in the code right after this one
+ Shape* Next = nullptr;
+ // The shape that control flow gets to naturally (if there is Next, then this
+ // is Next)
+ Shape* Natural;
+
+ enum ShapeType { Simple, Multiple, Loop };
ShapeType Type;
Shape(ShapeType TypeInit) : Type(TypeInit) {}
@@ -312,9 +332,15 @@ struct Shape {
virtual wasm::Expression* Render(RelooperBuilder& Builder, bool InLoop) = 0;
- static SimpleShape* IsSimple(Shape* It) { return It && It->Type == Simple ? (SimpleShape*)It : NULL; }
- static MultipleShape* IsMultiple(Shape* It) { return It && It->Type == Multiple ? (MultipleShape*)It : NULL; }
- static LoopShape* IsLoop(Shape* It) { return It && It->Type == Loop ? (LoopShape*)It : NULL; }
+ static SimpleShape* IsSimple(Shape* It) {
+ return It && It->Type == Simple ? (SimpleShape*)It : NULL;
+ }
+ static MultipleShape* IsMultiple(Shape* It) {
+ return It && It->Type == Multiple ? (MultipleShape*)It : NULL;
+ }
+ static LoopShape* IsLoop(Shape* It) {
+ return It && It->Type == Loop ? (LoopShape*)It : NULL;
+ }
};
struct SimpleShape : public Shape {
@@ -366,7 +392,7 @@ struct Relooper {
Relooper(wasm::Module* ModuleInit);
~Relooper();
- void AddBlock(Block* New, int Id=-1);
+ void AddBlock(Block* New, int Id = -1);
// Calculates the shapes
void Calculate(Block* Entry);
@@ -382,9 +408,9 @@ typedef InsertOrderedMap<Block*, BlockSet> BlockBlockSetMap;
#ifdef RELOOPER_DEBUG
struct Debugging {
- static void Dump(Block* Curr, const char *prefix=NULL);
- static void Dump(BlockSet &Blocks, const char *prefix=NULL);
- static void Dump(Shape* S, const char *prefix=NULL);
+ static void Dump(Block* Curr, const char* prefix = NULL);
+ static void Dump(BlockSet& Blocks, const char* prefix = NULL);
+ static void Dump(Shape* S, const char* prefix = NULL);
};
#endif
diff --git a/src/cfg/cfg-traversal.h b/src/cfg/cfg-traversal.h
index 73463eaa3..abaf63c5b 100644
--- a/src/cfg/cfg-traversal.h
+++ b/src/cfg/cfg-traversal.h
@@ -30,8 +30,8 @@
#ifndef cfg_traversal_h
#define cfg_traversal_h
-#include "wasm.h"
#include "wasm-traversal.h"
+#include "wasm.h"
namespace wasm {
@@ -47,21 +47,23 @@ struct CFGWalker : public ControlFlowWalker<SubType, VisitorType> {
BasicBlock* entry; // the entry block
- BasicBlock* makeBasicBlock() { // override this with code to create a BasicBlock if necessary
- return new BasicBlock();
- }
+ // override this with code to create a BasicBlock if necessary
+ BasicBlock* makeBasicBlock() { return new BasicBlock(); }
// internal details
std::vector<std::unique_ptr<BasicBlock>> basicBlocks; // all the blocks
- std::vector<BasicBlock*> loopTops; // blocks that are the tops of loops, i.e., have backedges to them
+ // blocks that are the tops of loops, i.e., have backedges to them
+ std::vector<BasicBlock*> loopTops;
// traversal state
- BasicBlock* currBasicBlock; // the current block in play during traversal. can be nullptr if unreachable,
- // but note that we don't do a deep unreachability analysis - just enough
- // to avoid constructing obviously-unreachable blocks (we do a full reachability
- // analysis on the CFG once it is constructed).
- std::map<Expression*, std::vector<BasicBlock*>> branches; // a block or loop => its branches
+ // the current block in play during traversal. can be nullptr if unreachable,
+ // but note that we don't do a deep unreachability analysis - just enough to
+ // avoid constructing obviously-unreachable blocks (we do a full reachability
+ // analysis on the CFG once it is constructed).
+ BasicBlock* currBasicBlock;
+ // a block or loop => its branches
+ std::map<Expression*, std::vector<BasicBlock*>> branches;
std::vector<BasicBlock*> ifStack;
std::vector<BasicBlock*> loopStack;
@@ -70,27 +72,29 @@ struct CFGWalker : public ControlFlowWalker<SubType, VisitorType> {
basicBlocks.push_back(std::unique_ptr<BasicBlock>(currBasicBlock));
}
- void startUnreachableBlock() {
- currBasicBlock = nullptr;
- }
+ void startUnreachableBlock() { currBasicBlock = nullptr; }
static void doStartUnreachableBlock(SubType* self, Expression** currp) {
self->startUnreachableBlock();
}
void link(BasicBlock* from, BasicBlock* to) {
- if (!from || !to) return; // if one of them is not reachable, ignore
+ if (!from || !to)
+ return; // if one of them is not reachable, ignore
from->out.push_back(to);
to->in.push_back(from);
}
static void doEndBlock(SubType* self, Expression** currp) {
auto* curr = (*currp)->cast<Block>();
- if (!curr->name.is()) return;
+ if (!curr->name.is())
+ return;
auto iter = self->branches.find(curr);
- if (iter == self->branches.end()) return;
+ if (iter == self->branches.end())
+ return;
auto& origins = iter->second;
- if (origins.size() == 0) return;
+ if (origins.size() == 0)
+ return;
// we have branches to here, so we need a new block
auto* last = self->currBasicBlock;
self->startBasicBlock();
@@ -106,19 +110,22 @@ struct CFGWalker : public ControlFlowWalker<SubType, VisitorType> {
auto* last = self->currBasicBlock;
self->startBasicBlock();
self->link(last, self->currBasicBlock); // ifTrue
- self->ifStack.push_back(last); // the block before the ifTrue
+ self->ifStack.push_back(last); // the block before the ifTrue
}
static void doStartIfFalse(SubType* self, Expression** currp) {
self->ifStack.push_back(self->currBasicBlock); // the ifTrue fallthrough
self->startBasicBlock();
- self->link(self->ifStack[self->ifStack.size() - 2], self->currBasicBlock); // before if -> ifFalse
+ self->link(self->ifStack[self->ifStack.size() - 2],
+ self->currBasicBlock); // before if -> ifFalse
}
static void doEndIf(SubType* self, Expression** currp) {
auto* last = self->currBasicBlock;
self->startBasicBlock();
- self->link(last, self->currBasicBlock); // last one is ifFalse's fallthrough if there was one, otherwise it's the ifTrue fallthrough
+ // last one is ifFalse's fallthrough if there was one, otherwise it's the
+ // ifTrue fallthrough
+ self->link(last, self->currBasicBlock);
if ((*currp)->cast<If>()->ifFalse) {
// we just linked ifFalse, need to link ifTrue to the end
self->link(self->ifStack.back(), self->currBasicBlock);
@@ -133,7 +140,8 @@ struct CFGWalker : public ControlFlowWalker<SubType, VisitorType> {
static void doStartLoop(SubType* self, Expression** currp) {
auto* last = self->currBasicBlock;
self->startBasicBlock();
- self->loopTops.push_back(self->currBasicBlock); // a loop with no backedges would still be counted here, but oh well
+ // a loop with no backedges would still be counted here, but oh well
+ self->loopTops.push_back(self->currBasicBlock);
self->link(last, self->currBasicBlock);
self->loopStack.push_back(self->currBasicBlock);
}
@@ -157,7 +165,8 @@ struct CFGWalker : public ControlFlowWalker<SubType, VisitorType> {
static void doEndBreak(SubType* self, Expression** currp) {
auto* curr = (*currp)->cast<Break>();
- self->branches[self->findBreakTarget(curr->name)].push_back(self->currBasicBlock); // branch to the target
+ self->branches[self->findBreakTarget(curr->name)].push_back(
+ self->currBasicBlock); // branch to the target
if (curr->condition) {
auto* last = self->currBasicBlock;
self->startBasicBlock();
@@ -169,15 +178,18 @@ struct CFGWalker : public ControlFlowWalker<SubType, VisitorType> {
static void doEndSwitch(SubType* self, Expression** currp) {
auto* curr = (*currp)->cast<Switch>();
- std::set<Name> seen; // we might see the same label more than once; do not spam branches
+ // we might see the same label more than once; do not spam branches
+ std::set<Name> seen;
for (Name target : curr->targets) {
if (!seen.count(target)) {
- self->branches[self->findBreakTarget(target)].push_back(self->currBasicBlock); // branch to the target
+ self->branches[self->findBreakTarget(target)].push_back(
+ self->currBasicBlock); // branch to the target
seen.insert(target);
}
}
if (!seen.count(curr->default_)) {
- self->branches[self->findBreakTarget(curr->default_)].push_back(self->currBasicBlock); // branch to the target
+ self->branches[self->findBreakTarget(curr->default_)].push_back(
+ self->currBasicBlock); // branch to the target
}
self->startUnreachableBlock();
}
@@ -258,7 +270,8 @@ struct CFGWalker : public ControlFlowWalker<SubType, VisitorType> {
queue.erase(iter);
alive.insert(curr);
for (auto* out : curr->out) {
- if (!alive.count(out)) queue.insert(out);
+ if (!alive.count(out))
+ queue.insert(out);
}
}
return alive;
@@ -271,21 +284,29 @@ struct CFGWalker : public ControlFlowWalker<SubType, VisitorType> {
block->out.clear();
continue;
}
- block->in.erase(std::remove_if(block->in.begin(), block->in.end(), [&alive](BasicBlock* other) {
- return !alive.count(other);
- }), block->in.end());
- block->out.erase(std::remove_if(block->out.begin(), block->out.end(), [&alive](BasicBlock* other) {
- return !alive.count(other);
- }), block->out.end());
+ block->in.erase(std::remove_if(block->in.begin(),
+ block->in.end(),
+ [&alive](BasicBlock* other) {
+ return !alive.count(other);
+ }),
+ block->in.end());
+ block->out.erase(std::remove_if(block->out.begin(),
+ block->out.end(),
+ [&alive](BasicBlock* other) {
+ return !alive.count(other);
+ }),
+ block->out.end());
}
}
- // TODO: utility method for optimizing cfg, removing empty blocks depending on their .content
+ // TODO: utility method for optimizing cfg, removing empty blocks depending on
+ // their .content
std::map<BasicBlock*, size_t> debugIds;
void generateDebugIds() {
- if (debugIds.size() > 0) return;
+ if (debugIds.size() > 0)
+ return;
for (auto& block : basicBlocks) {
debugIds[block.get()] = debugIds.size();
}
@@ -300,12 +321,14 @@ struct CFGWalker : public ControlFlowWalker<SubType, VisitorType> {
block->contents.dump(static_cast<SubType*>(this)->getFunction());
for (auto& in : block->in) {
assert(debugIds.count(in) > 0);
- assert(std::find(in->out.begin(), in->out.end(), block.get()) != in->out.end()); // must be a parallel link back
+ assert(std::find(in->out.begin(), in->out.end(), block.get()) !=
+ in->out.end()); // must be a parallel link back
}
for (auto& out : block->out) {
assert(debugIds.count(out) > 0);
std::cout << " out: " << debugIds[out] << "\n";
- assert(std::find(out->in.begin(), out->in.end(), block.get()) != out->in.end()); // must be a parallel link back
+ assert(std::find(out->in.begin(), out->in.end(), block.get()) !=
+ out->in.end()); // must be a parallel link back
}
checkDuplicates(block->in);
checkDuplicates(block->out);
diff --git a/src/cfg/liveness-traversal.h b/src/cfg/liveness-traversal.h
index edbe52fd6..b26898460 100644
--- a/src/cfg/liveness-traversal.h
+++ b/src/cfg/liveness-traversal.h
@@ -21,12 +21,12 @@
#ifndef liveness_traversal_h
#define liveness_traversal_h
+#include "cfg-traversal.h"
+#include "ir/utils.h"
#include "support/sorted_vector.h"
-#include "wasm.h"
#include "wasm-builder.h"
#include "wasm-traversal.h"
-#include "cfg-traversal.h"
-#include "ir/utils.h"
+#include "wasm.h"
namespace wasm {
@@ -41,20 +41,19 @@ typedef SortedVector LocalSet;
// "other" which can be used for other purposes, to mark
// their position in a block
struct LivenessAction {
- enum What {
- Get = 0,
- Set = 1,
- Other = 2
- };
+ enum What { Get = 0, Set = 1, Other = 2 };
What what;
- Index index; // the local index read or written
+ Index index; // the local index read or written
Expression** origin; // the origin
bool effective; // whether a store is actually effective, i.e., may be read
- LivenessAction(What what, Index index, Expression** origin) : what(what), index(index), origin(origin), effective(false) {
+ LivenessAction(What what, Index index, Expression** origin)
+ : what(what), index(index), origin(origin), effective(false) {
assert(what != Other);
- if (what == Get) assert((*origin)->is<GetLocal>());
- if (what == Set) assert((*origin)->is<SetLocal>());
+ if (what == Get)
+ assert((*origin)->is<GetLocal>());
+ if (what == Set)
+ assert((*origin)->is<SetLocal>());
}
LivenessAction(Expression** origin) : what(Other), origin(origin) {}
@@ -80,15 +79,18 @@ struct LivenessAction {
// information about liveness in a basic block
struct Liveness {
- LocalSet start, end; // live locals at the start and end
+ LocalSet start, end; // live locals at the start and end
std::vector<LivenessAction> actions; // actions occurring in this block
#if LIVENESS_DEBUG
void dump(Function* func) {
- if (actions.empty()) return;
+ if (actions.empty())
+ return;
std::cout << " actions:\n";
for (auto& action : actions) {
- std::cout << " " << (action.isGet() ? "get" : (action.isSet() ? "set" : "other")) << " " << func->getLocalName(action.index) << "\n";
+ std::cout << " "
+ << (action.isGet() ? "get" : (action.isSet() ? "set" : "other"))
+ << " " << func->getLocalName(action.index) << "\n";
}
}
#endif // LIVENESS_DEBUG
@@ -96,28 +98,35 @@ struct Liveness {
template<typename SubType, typename VisitorType>
struct LivenessWalker : public CFGWalker<SubType, VisitorType, Liveness> {
- typedef typename CFGWalker<SubType, VisitorType, Liveness>::BasicBlock BasicBlock;
+ typedef
+ typename CFGWalker<SubType, VisitorType, Liveness>::BasicBlock BasicBlock;
Index numLocals;
std::unordered_set<BasicBlock*> liveBlocks;
- std::vector<uint8_t> copies; // canonicalized - accesses should check (low, high) TODO: use a map for high N, as this tends to be sparse? or don't look at copies at all for big N?
- std::vector<Index> totalCopies; // total # of copies for each local, with all others
+ // canonicalized - accesses should check (low, high)
+ // TODO: use a map for high N, as this tends to be sparse? or don't look at
+ // copies at all for big N?
+ std::vector<uint8_t> copies;
+ // total # of copies for each local, with all others
+ std::vector<Index> totalCopies;
// cfg traversal work
static void doVisitGetLocal(SubType* self, Expression** currp) {
auto* curr = (*currp)->cast<GetLocal>();
- // if in unreachable code, ignore
+ // if in unreachable code, ignore
if (!self->currBasicBlock) {
*currp = Builder(*self->getModule()).replaceWithIdenticalType(curr);
return;
}
- self->currBasicBlock->contents.actions.emplace_back(LivenessAction::Get, curr->index, currp);
+ self->currBasicBlock->contents.actions.emplace_back(
+ LivenessAction::Get, curr->index, currp);
}
static void doVisitSetLocal(SubType* self, Expression** currp) {
auto* curr = (*currp)->cast<SetLocal>();
- // if in unreachable code, we don't need the tee (but might need the value, if it has side effects)
+ // if in unreachable code, we don't need the tee (but might need the value,
+ // if it has side effects)
if (!self->currBasicBlock) {
if (curr->isTee()) {
*currp = curr->value;
@@ -126,10 +135,12 @@ struct LivenessWalker : public CFGWalker<SubType, VisitorType, Liveness> {
}
return;
}
- self->currBasicBlock->contents.actions.emplace_back(LivenessAction::Set, curr->index, currp);
+ self->currBasicBlock->contents.actions.emplace_back(
+ LivenessAction::Set, curr->index, currp);
// if this is a copy, note it
if (auto* get = self->getCopy(curr)) {
- // add 2 units, so that backedge prioritization can decide ties, but not much more
+ // add 2 units, so that backedge prioritization can decide ties, but not
+ // much more
self->addCopy(curr->index, get->index);
self->addCopy(curr->index, get->index);
}
@@ -137,16 +148,19 @@ struct LivenessWalker : public CFGWalker<SubType, VisitorType, Liveness> {
// A simple copy is a set of a get. A more interesting copy
// is a set of an if with a value, where one side a get.
- // That can happen when we create an if value in simplify-locals. TODO: recurse into
- // nested ifs, and block return values? Those cases are trickier, need to
- // count to see if worth it.
+ // That can happen when we create an if value in simplify-locals. TODO:
+ // recurse into nested ifs, and block return values? Those cases are trickier,
+ // need to count to see if worth it.
// TODO: an if can have two copies
GetLocal* getCopy(SetLocal* set) {
- if (auto* get = set->value->dynCast<GetLocal>()) return get;
+ if (auto* get = set->value->dynCast<GetLocal>())
+ return get;
if (auto* iff = set->value->dynCast<If>()) {
- if (auto* get = iff->ifTrue->dynCast<GetLocal>()) return get;
+ if (auto* get = iff->ifTrue->dynCast<GetLocal>())
+ return get;
if (iff->ifFalse) {
- if (auto* get = iff->ifFalse->dynCast<GetLocal>()) return get;
+ if (auto* get = iff->ifFalse->dynCast<GetLocal>())
+ return get;
}
}
return nullptr;
@@ -162,7 +176,8 @@ struct LivenessWalker : public CFGWalker<SubType, VisitorType, Liveness> {
std::fill(totalCopies.begin(), totalCopies.end(), 0);
// create the CFG by walking the IR
CFGWalker<SubType, VisitorType, Liveness>::doWalkFunction(func);
- // ignore links to dead blocks, so they don't confuse us and we can see their stores are all ineffective
+ // ignore links to dead blocks, so they don't confuse us and we can see
+ // their stores are all ineffective
liveBlocks = CFGWalker<SubType, VisitorType, Liveness>::findLiveBlocks();
CFGWalker<SubType, VisitorType, Liveness>::unlinkDeadBlocks(liveBlocks);
// flow liveness across blocks
@@ -173,24 +188,30 @@ struct LivenessWalker : public CFGWalker<SubType, VisitorType, Liveness> {
// keep working while stuff is flowing
std::unordered_set<BasicBlock*> queue;
for (auto& curr : CFGWalker<SubType, VisitorType, Liveness>::basicBlocks) {
- if (liveBlocks.count(curr.get()) == 0) continue; // ignore dead blocks
+ if (liveBlocks.count(curr.get()) == 0)
+ continue; // ignore dead blocks
queue.insert(curr.get());
- // do the first scan through the block, starting with nothing live at the end, and updating the liveness at the start
+ // do the first scan through the block, starting with nothing live at the
+ // end, and updating the liveness at the start
scanLivenessThroughActions(curr->contents.actions, curr->contents.start);
}
- // at every point in time, we assume we already noted interferences between things already known alive at the end, and scanned back through the block using that
+ // at every point in time, we assume we already noted interferences between
+ // things already known alive at the end, and scanned back through the block
+ // using that
while (queue.size() > 0) {
auto iter = queue.begin();
auto* curr = *iter;
queue.erase(iter);
LocalSet live;
- if (!mergeStartsAndCheckChange(curr->out, curr->contents.end, live)) continue;
+ if (!mergeStartsAndCheckChange(curr->out, curr->contents.end, live))
+ continue;
assert(curr->contents.end.size() < live.size());
curr->contents.end = live;
scanLivenessThroughActions(curr->contents.actions, live);
// liveness is now calculated at the start. if something
// changed, all predecessor blocks need recomputation
- if (curr->contents.start == live) continue;
+ if (curr->contents.start == live)
+ continue;
assert(curr->contents.start.size() < live.size());
curr->contents.start = live;
for (auto* in : curr->in) {
@@ -200,9 +221,13 @@ struct LivenessWalker : public CFGWalker<SubType, VisitorType, Liveness> {
}
// merge starts of a list of blocks. return
- // whether anything changed vs an old state (which indicates further processing is necessary).
- bool mergeStartsAndCheckChange(std::vector<BasicBlock*>& blocks, LocalSet& old, LocalSet& ret) {
- if (blocks.size() == 0) return false;
+ // whether anything changed vs an old state (which indicates further
+ // processing is necessary).
+ bool mergeStartsAndCheckChange(std::vector<BasicBlock*>& blocks,
+ LocalSet& old,
+ LocalSet& ret) {
+ if (blocks.size() == 0)
+ return false;
ret = blocks[0]->contents.start;
if (blocks.size() > 1) {
// more than one, so we must merge
@@ -213,7 +238,8 @@ struct LivenessWalker : public CFGWalker<SubType, VisitorType, Liveness> {
return old != ret;
}
- void scanLivenessThroughActions(std::vector<LivenessAction>& actions, LocalSet& live) {
+ void scanLivenessThroughActions(std::vector<LivenessAction>& actions,
+ LocalSet& live) {
// move towards the front
for (int i = int(actions.size()) - 1; i >= 0; i--) {
auto& action = actions[i];
diff --git a/src/compiler-support.h b/src/compiler-support.h
index e7cb4db8c..911d92ef5 100644
--- a/src/compiler-support.h
+++ b/src/compiler-support.h
@@ -18,26 +18,34 @@
#define wasm_compiler_support_h
#ifndef __has_feature
-# define __has_feature(x) 0
+#define __has_feature(x) 0
#endif
#ifndef __has_builtin
-# define __has_builtin(x) 0
+#define __has_builtin(x) 0
#endif
// If control flow reaches the point of the WASM_UNREACHABLE(), the program is
// undefined.
#if __has_builtin(__builtin_unreachable) && defined(NDEBUG)
-# define WASM_UNREACHABLE() __builtin_unreachable()
+#define WASM_UNREACHABLE() __builtin_unreachable()
#elif defined(_MSC_VER)
-# define WASM_UNREACHABLE() __assume(false)
+#define WASM_UNREACHABLE() __assume(false)
#elif __has_feature(address_sanitizer) || defined(__SANITIZE_ADDRESS__)
-# include "sanitizer/common_interface_defs.h"
-# define WASM_UNREACHABLE() do { __sanitizer_print_stack_trace(); __builtin_trap(); } while (0)
+#include "sanitizer/common_interface_defs.h"
+#define WASM_UNREACHABLE() \
+ do { \
+ __sanitizer_print_stack_trace(); \
+ __builtin_trap(); \
+ } while (0)
#else
-# include <assert.h>
-# include <stdlib.h>
-# define WASM_UNREACHABLE() do { assert(false); abort(); } while (0)
+#include <assert.h>
+#include <stdlib.h>
+#define WASM_UNREACHABLE() \
+ do { \
+ assert(false); \
+ abort(); \
+ } while (0)
#endif
#ifdef __GNUC__
@@ -54,7 +62,11 @@
// The code might contain TODOs or stubs that read some values but do nothing
// with them. The compiler might fail with [-Werror,-Wunused-variable].
// The WASM_UNUSED(varible) is a wrapper that helps to suppress the error.
-#define WASM_UNUSED(expr) \
- do { if (sizeof expr) { (void)0; } } while (0)
+#define WASM_UNUSED(expr) \
+ do { \
+ if (sizeof expr) { \
+ (void)0; \
+ } \
+ } while (0)
#endif // wasm_compiler_support_h
diff --git a/src/dataflow/graph.h b/src/dataflow/graph.h
index 85b37b7b0..f93621a91 100644
--- a/src/dataflow/graph.h
+++ b/src/dataflow/graph.h
@@ -25,11 +25,11 @@
#ifndef wasm_dataflow_graph_h
#define wasm_dataflow_graph_h
-#include "wasm.h"
+#include "dataflow/node.h"
#include "ir/abstract.h"
#include "ir/iteration.h"
#include "ir/literal-utils.h"
-#include "dataflow/node.h"
+#include "wasm.h"
namespace wasm {
@@ -99,7 +99,8 @@ struct Graph : public UnifiedExpressionVisitor<Graph, Node*> {
struct FlowState {
Locals locals;
Node* condition;
- FlowState(Locals locals, Node* condition) : locals(locals), condition(condition) {}
+ FlowState(Locals locals, Node* condition)
+ : locals(locals), condition(condition) {}
};
// API
@@ -109,11 +110,13 @@ struct Graph : public UnifiedExpressionVisitor<Graph, Node*> {
module = moduleInit;
auto numLocals = func->getNumLocals();
- if (numLocals == 0) return; // nothing to do
+ if (numLocals == 0)
+ return; // nothing to do
// Set up initial local state IR.
setInReachable();
for (Index i = 0; i < numLocals; i++) {
- if (!isRelevantType(func->getLocalType(i))) continue;
+ if (!isRelevantType(func->getLocalType(i)))
+ continue;
Node* node;
auto type = func->getLocalType(i);
if (func->isParam(i)) {
@@ -141,7 +144,7 @@ struct Graph : public UnifiedExpressionVisitor<Graph, Node*> {
Node* makeConst(Literal value) {
auto iter = constantNodes.find(value);
- if (iter!= constantNodes.end()) {
+ if (iter != constantNodes.end()) {
return iter->second;
}
// Create one for this literal.
@@ -152,9 +155,7 @@ struct Graph : public UnifiedExpressionVisitor<Graph, Node*> {
return ret;
}
- Node* makeZero(wasm::Type type) {
- return makeConst(Literal::makeZero(type));
- }
+ Node* makeZero(wasm::Type type) { return makeConst(Literal::makeZero(type)); }
// Add a new node to our list of owned nodes.
Node* addNode(Node* node) {
@@ -166,34 +167,26 @@ struct Graph : public UnifiedExpressionVisitor<Graph, Node*> {
assert(!node->isBad());
Builder builder(*module);
auto type = node->getWasmType();
- if (!isConcreteType(type)) return &bad;
+ if (!isConcreteType(type))
+ return &bad;
auto* zero = makeZero(type);
auto* expr = builder.makeBinary(
Abstract::getBinary(type, equal ? Abstract::Eq : Abstract::Ne),
makeUse(node),
- makeUse(zero)
- );
+ makeUse(zero));
auto* check = addNode(Node::makeExpr(expr, origin));
check->addValue(expandFromI1(node, origin));
check->addValue(zero);
return check;
}
- void setInUnreachable() {
- locals.clear();
- }
+ void setInUnreachable() { locals.clear(); }
- void setInReachable() {
- locals.resize(func->getNumLocals());
- }
+ void setInReachable() { locals.resize(func->getNumLocals()); }
- bool isInUnreachable() {
- return isInUnreachable(locals);
- }
+ bool isInUnreachable() { return isInUnreachable(locals); }
- bool isInUnreachable(const Locals& state) {
- return state.empty();
- }
+ bool isInUnreachable(const Locals& state) { return state.empty(); }
bool isInUnreachable(const FlowState& state) {
return isInUnreachable(state.locals);
@@ -320,7 +313,8 @@ struct Graph : public UnifiedExpressionVisitor<Graph, Node*> {
auto& breaks = breakStates[curr->name];
// Phis are possible, check for them.
for (Index i = 0; i < numLocals; i++) {
- if (!isRelevantType(func->getLocalType(i))) continue;
+ if (!isRelevantType(func->getLocalType(i)))
+ continue;
bool needPhi = false;
// We replaced the proper value with a Var. If it's still that
// Var - or it's the original proper value, which can happen with
@@ -413,9 +407,7 @@ struct Graph : public UnifiedExpressionVisitor<Graph, Node*> {
}
return &bad;
}
- Node* doVisitConst(Const* curr) {
- return makeConst(curr->value);
- }
+ Node* doVisitConst(Const* curr) { return makeConst(curr->value); }
Node* doVisitUnary(Unary* curr) {
// First, check if we support this op.
switch (curr->op) {
@@ -428,7 +420,8 @@ struct Graph : public UnifiedExpressionVisitor<Graph, Node*> {
// These are ok as-is.
// Check if our child is supported.
auto* value = expandFromI1(visit(curr->value), curr);
- if (value->isBad()) return value;
+ if (value->isBad())
+ return value;
// Great, we are supported!
auto* ret = addNode(Node::makeExpr(curr, curr));
ret->addValue(value);
@@ -439,7 +432,8 @@ struct Graph : public UnifiedExpressionVisitor<Graph, Node*> {
// These can be implemented using a binary.
// Check if our child is supported.
auto* value = expandFromI1(visit(curr->value), curr);
- if (value->isBad()) return value;
+ if (value->isBad())
+ return value;
// Great, we are supported!
return makeZeroComp(value, true, curr);
}
@@ -449,7 +443,7 @@ struct Graph : public UnifiedExpressionVisitor<Graph, Node*> {
}
}
}
- Node* doVisitBinary(Binary *curr) {
+ Node* doVisitBinary(Binary* curr) {
// First, check if we support this op.
switch (curr->op) {
case AddInt32:
@@ -497,9 +491,11 @@ struct Graph : public UnifiedExpressionVisitor<Graph, Node*> {
// These are ok as-is.
// Check if our children are supported.
auto* left = expandFromI1(visit(curr->left), curr);
- if (left->isBad()) return left;
+ if (left->isBad())
+ return left;
auto* right = expandFromI1(visit(curr->right), curr);
- if (right->isBad()) return right;
+ if (right->isBad())
+ return right;
// Great, we are supported!
auto* ret = addNode(Node::makeExpr(curr, curr));
ret->addValue(left);
@@ -518,19 +514,37 @@ struct Graph : public UnifiedExpressionVisitor<Graph, Node*> {
Builder builder(*module);
BinaryOp opposite;
switch (curr->op) {
- case GtSInt32: opposite = LtSInt32; break;
- case GtSInt64: opposite = LtSInt64; break;
- case GeSInt32: opposite = LeSInt32; break;
- case GeSInt64: opposite = LeSInt64; break;
- case GtUInt32: opposite = LtUInt32; break;
- case GtUInt64: opposite = LtUInt64; break;
- case GeUInt32: opposite = LeUInt32; break;
- case GeUInt64: opposite = LeUInt64; break;
- default: WASM_UNREACHABLE();
+ case GtSInt32:
+ opposite = LtSInt32;
+ break;
+ case GtSInt64:
+ opposite = LtSInt64;
+ break;
+ case GeSInt32:
+ opposite = LeSInt32;
+ break;
+ case GeSInt64:
+ opposite = LeSInt64;
+ break;
+ case GtUInt32:
+ opposite = LtUInt32;
+ break;
+ case GtUInt64:
+ opposite = LtUInt64;
+ break;
+ case GeUInt32:
+ opposite = LeUInt32;
+ break;
+ case GeUInt64:
+ opposite = LeUInt64;
+ break;
+ default:
+ WASM_UNREACHABLE();
}
- auto* ret = visitBinary(builder.makeBinary(opposite, curr->right, curr->left));
- // We just created a new binary node, but we need to set the origin properly
- // to the original.
+ auto* ret =
+ visitBinary(builder.makeBinary(opposite, curr->right, curr->left));
+ // We just created a new binary node, but we need to set the origin
+ // properly to the original.
ret->origin = curr;
return ret;
}
@@ -542,11 +556,14 @@ struct Graph : public UnifiedExpressionVisitor<Graph, Node*> {
}
Node* doVisitSelect(Select* curr) {
auto* ifTrue = expandFromI1(visit(curr->ifTrue), curr);
- if (ifTrue->isBad()) return ifTrue;
+ if (ifTrue->isBad())
+ return ifTrue;
auto* ifFalse = expandFromI1(visit(curr->ifFalse), curr);
- if (ifFalse->isBad()) return ifFalse;
+ if (ifFalse->isBad())
+ return ifFalse;
auto* condition = ensureI1(visit(curr->condition), curr);
- if (condition->isBad()) return condition;
+ if (condition->isBad())
+ return condition;
// Great, we are supported!
auto* ret = addNode(Node::makeExpr(curr, curr));
ret->addValue(condition);
@@ -575,16 +592,18 @@ struct Graph : public UnifiedExpressionVisitor<Graph, Node*> {
// Helpers.
- bool isRelevantType(wasm::Type type) {
- return isIntegerType(type);
- }
+ bool isRelevantType(wasm::Type type) { return isIntegerType(type); }
bool isRelevantLocal(Index index) {
return isRelevantType(func->getLocalType(index));
}
// Merge local state for an if, also creating a block and conditions.
- void mergeIf(Locals& aState, Locals& bState, Node* condition, Expression* expr, Locals& out) {
+ void mergeIf(Locals& aState,
+ Locals& bState,
+ Node* condition,
+ Expression* expr,
+ Locals& out) {
// Create the conditions (if we can).
Node* ifTrue;
Node* ifFalse;
@@ -642,7 +661,8 @@ struct Graph : public UnifiedExpressionVisitor<Graph, Node*> {
Index numLocals = func->getNumLocals();
Node* block = nullptr;
for (Index i = 0; i < numLocals; i++) {
- if (!isRelevantType(func->getLocalType(i))) continue;
+ if (!isRelevantType(func->getLocalType(i)))
+ continue;
// Process the inputs. If any is bad, the phi is bad.
bool bad = false;
for (auto& state : states) {
@@ -653,7 +673,8 @@ struct Graph : public UnifiedExpressionVisitor<Graph, Node*> {
break;
}
}
- if (bad) continue;
+ if (bad)
+ continue;
// Nothing is bad, proceed.
Node* first = nullptr;
for (auto& state : states) {
@@ -703,14 +724,16 @@ struct Graph : public UnifiedExpressionVisitor<Graph, Node*> {
// the set.
SetLocal* getSet(Node* node) {
auto iter = nodeParentMap.find(node);
- if (iter == nodeParentMap.end()) return nullptr;
+ if (iter == nodeParentMap.end())
+ return nullptr;
return iter->second->dynCast<SetLocal>();
}
// Given an expression, return the parent if such exists.
Expression* getParent(Expression* curr) {
auto iter = expressionParentMap.find(curr);
- if (iter == expressionParentMap.end()) return nullptr;
+ if (iter == expressionParentMap.end())
+ return nullptr;
return iter->second;
}
diff --git a/src/dataflow/node.h b/src/dataflow/node.h
index d6514588e..8977ab41c 100644
--- a/src/dataflow/node.h
+++ b/src/dataflow/node.h
@@ -25,6 +25,7 @@
#ifndef wasm_dataflow_node_h
#define wasm_dataflow_node_h
+#include "ir/utils.h"
#include "wasm.h"
namespace wasm {
@@ -34,11 +35,11 @@ namespace DataFlow {
//
// The core IR representation in DataFlow: a Node.
//
-// We reuse the Binaryen IR as much as possible: when things are identical between
-// the two IRs, we just create an Expr node, which stores the opcode and other
-// details, and we can emit them to Souper by reading the Binaryen Expression.
-// Other node types here are special things from Souper IR that we can't
-// represent that way.
+// We reuse the Binaryen IR as much as possible: when things are identical
+// between the two IRs, we just create an Expr node, which stores the opcode and
+// other details, and we can emit them to Souper by reading the Binaryen
+// Expression. Other node types here are special things from Souper IR that we
+// can't represent that way.
//
// * Souper comparisons return an i1. We extend them immediately if they are
// going to be used as i32s or i64s.
@@ -52,15 +53,17 @@ namespace DataFlow {
struct Node {
enum Type {
- Var, // an unknown variable number (not to be confused with var/param/local in wasm)
- Expr, // a value represented by a Binaryen Expression
- Phi, // a phi from converging control flow
- Cond, // a blockpc, representing one of the branchs for a Block
+ Var, // an unknown variable number (not to be confused with var/param/local
+ // in wasm)
+ Expr, // a value represented by a Binaryen Expression
+ Phi, // a phi from converging control flow
+ Cond, // a blockpc, representing one of the branchs for a Block
Block, // a source of phis
- Zext, // zero-extend an i1 (from an op where Souper returns i1 but wasm does not,
- // and so we need a special way to get back to an i32/i64 if we operate
- // on that value instead of just passing it straight to Souper).
- Bad // something we can't handle and should ignore
+ Zext, // zero-extend an i1 (from an op where Souper returns i1 but wasm does
+ // not, and so we need a special way to get back to an i32/i64 if we
+ // operate on that value instead of just passing it straight to
+ // Souper).
+ Bad // something we can't handle and should ignore
} type;
Node(Type type) : type(type) {}
@@ -144,50 +147,56 @@ struct Node {
// Helpers
- void addValue(Node* value) {
- values.push_back(value);
- }
- Node* getValue(Index i) {
- return values.at(i);
- }
+ void addValue(Node* value) { values.push_back(value); }
+ Node* getValue(Index i) { return values.at(i); }
// Gets the wasm type of the node. If there isn't a valid one,
// return unreachable.
wasm::Type getWasmType() {
switch (type) {
- case Var: return wasmType;
- case Expr: return expr->type;
- case Phi: return getValue(1)->getWasmType();
- case Zext: return getValue(0)->getWasmType();
- case Bad: return unreachable;
- default: WASM_UNREACHABLE();
+ case Var:
+ return wasmType;
+ case Expr:
+ return expr->type;
+ case Phi:
+ return getValue(1)->getWasmType();
+ case Zext:
+ return getValue(0)->getWasmType();
+ case Bad:
+ return unreachable;
+ default:
+ WASM_UNREACHABLE();
}
}
bool operator==(const Node& other) {
- if (type != other.type) return false;
+ if (type != other.type)
+ return false;
switch (type) {
case Var:
- case Block: return this == &other;
+ case Block:
+ return this == &other;
case Expr: {
if (!ExpressionAnalyzer::equal(expr, other.expr)) {
return false;
}
break;
}
- case Cond: if (index != other.index) return false;
+ case Cond:
+ if (index != other.index)
+ return false;
default: {}
}
- if (values.size() != other.values.size()) return false;
+ if (values.size() != other.values.size())
+ return false;
for (Index i = 0; i < values.size(); i++) {
- if (*(values[i]) != *(other.values[i])) return false;
+ if (*(values[i]) != *(other.values[i]))
+ return false;
}
return true;
}
- bool operator!=(const Node& other) {
- return !(*this == other);
- }
+ bool operator!=(const Node& other) { return !(*this == other); }
// As mentioned above, comparisons return i1. This checks
// if an operation is of that sort.
diff --git a/src/dataflow/users.h b/src/dataflow/users.h
index ab9a2ccef..369d18bbb 100644
--- a/src/dataflow/users.h
+++ b/src/dataflow/users.h
@@ -89,14 +89,10 @@ public:
}
// Adds a new user to a node. Called when we add or change a value of a node.
- void addUser(Node* node, Node* newUser) {
- users[node].insert(newUser);
- }
+ void addUser(Node* node, Node* newUser) { users[node].insert(newUser); }
// Remove all uses of a node. Called when a node is being removed.
- void removeAllUsesOf(Node* node) {
- users.erase(node);
- }
+ void removeAllUsesOf(Node* node) { users.erase(node); }
};
} // namespace DataFlow
diff --git a/src/dataflow/utils.h b/src/dataflow/utils.h
index 5328e6ab7..337dfec5e 100644
--- a/src/dataflow/utils.h
+++ b/src/dataflow/utils.h
@@ -25,9 +25,9 @@
#ifndef wasm_dataflow_utils_h
#define wasm_dataflow_utils_h
-#include "wasm.h"
-#include "wasm-printing.h"
#include "dataflow/node.h"
+#include "wasm-printing.h"
+#include "wasm.h"
namespace wasm {
@@ -35,27 +35,39 @@ namespace DataFlow {
inline std::ostream& dump(Node* node, std::ostream& o, size_t indent = 0) {
auto doIndent = [&]() {
- for (size_t i = 0; i < indent; i++) o << ' ';
+ for (size_t i = 0; i < indent; i++)
+ o << ' ';
};
doIndent();
o << '[' << node << ' ';
switch (node->type) {
- case Node::Type::Var: o << "var " << printType(node->wasmType) << ' ' << node; break;
- case Node::Type::Expr: {
+ case Node::Type::Var:
+ o << "var " << printType(node->wasmType) << ' ' << node;
+ break;
+ case Node::Type::Expr: {
o << "expr ";
WasmPrinter::printExpression(node->expr, o, true);
break;
}
- case Node::Type::Phi: o << "phi " << node->index; break;
- case Node::Type::Cond: o << "cond " << node->index; break;
+ case Node::Type::Phi:
+ o << "phi " << node->index;
+ break;
+ case Node::Type::Cond:
+ o << "cond " << node->index;
+ break;
case Node::Type::Block: {
// don't print the conds - they would recurse
o << "block (" << node->values.size() << " conds)]\n";
return o;
}
- case Node::Type::Zext: o << "zext"; break;
- case Node::Type::Bad: o << "bad"; break;
- default: WASM_UNREACHABLE();
+ case Node::Type::Zext:
+ o << "zext";
+ break;
+ case Node::Type::Bad:
+ o << "bad";
+ break;
+ default:
+ WASM_UNREACHABLE();
}
if (!node->values.empty()) {
o << '\n';
@@ -115,11 +127,9 @@ inline bool allInputsConstant(Node* node) {
if (node->expr->is<Unary>()) {
return node->getValue(0)->isConst();
} else if (node->expr->is<Binary>()) {
- return node->getValue(0)->isConst() &&
- node->getValue(1)->isConst();
+ return node->getValue(0)->isConst() && node->getValue(1)->isConst();
} else if (node->expr->is<Select>()) {
- return node->getValue(0)->isConst() &&
- node->getValue(1)->isConst() &&
+ return node->getValue(0)->isConst() && node->getValue(1)->isConst() &&
node->getValue(2)->isConst();
}
break;
diff --git a/src/emscripten-optimizer/istring.h b/src/emscripten-optimizer/istring.h
index 5c3b094c3..320a3e590 100644
--- a/src/emscripten-optimizer/istring.h
+++ b/src/emscripten-optimizer/istring.h
@@ -14,20 +14,21 @@
* limitations under the License.
*/
-// Interned String type, 100% interned on creation. Comparisons are always just a pointer comparison
+// Interned String type, 100% interned on creation. Comparisons are always just
+// a pointer comparison
#ifndef wasm_istring_h
#define wasm_istring_h
-#include <unordered_set>
-#include <unordered_map>
#include <set>
+#include <unordered_map>
+#include <unordered_set>
-#include <string.h>
+#include <assert.h>
#include <stdint.h>
-#include <stdlib.h>
#include <stdio.h>
-#include <assert.h>
+#include <stdlib.h>
+#include <string.h>
#include "support/threads.h"
#include "support/utilities.h"
@@ -35,9 +36,10 @@
namespace cashew {
struct IString {
- const char *str = nullptr;
+ const char* str = nullptr;
- static size_t hash_c(const char *str) { // see http://www.cse.yorku.ca/~oz/hash.html
+ static size_t
+ hash_c(const char* str) { // see http://www.cse.yorku.ca/~oz/hash.html
unsigned int hash = 5381;
int c;
while ((c = *str++)) {
@@ -46,27 +48,27 @@ struct IString {
return (size_t)hash;
}
- class CStringHash : public std::hash<const char *> {
+ class CStringHash : public std::hash<const char*> {
public:
- size_t operator()(const char *str) const {
- return IString::hash_c(str);
- }
+ size_t operator()(const char* str) const { return IString::hash_c(str); }
};
- class CStringEqual : public std::equal_to<const char *> {
+ class CStringEqual : public std::equal_to<const char*> {
public:
- bool operator()(const char *x, const char *y) const {
+ bool operator()(const char* x, const char* y) const {
return strcmp(x, y) == 0;
}
};
IString() = default;
- IString(const char *s, bool reuse=true) { // if reuse=true, then input is assumed to remain alive; not copied
+ // if reuse=true, then input is assumed to remain alive; not copied
+ IString(const char* s, bool reuse = true) {
assert(s);
set(s, reuse);
}
- void set(const char *s, bool reuse=true) {
- typedef std::unordered_set<const char *, CStringHash, CStringEqual> StringSet;
+ void set(const char* s, bool reuse = true) {
+ typedef std::unordered_set<const char*, CStringHash, CStringEqual>
+ StringSet;
// one global store of strings per thread, we must not access this
// in parallel
thread_local static StringSet strings;
@@ -79,8 +81,8 @@ struct IString {
// exactly once
static std::mutex mutex;
std::unique_lock<std::mutex> lock(mutex);
- // a single global set contains the actual strings, so we allocate each one
- // exactly once.
+ // a single global set contains the actual strings, so we allocate each
+ // one exactly once.
static StringSet globalStrings;
auto globalExisting = globalStrings.find(s);
if (globalExisting == globalStrings.end()) {
@@ -103,56 +105,51 @@ struct IString {
str = s;
}
- void set(const IString &s) {
- str = s.str;
- }
+ void set(const IString& s) { str = s.str; }
- void clear() {
- str = nullptr;
- }
+ void clear() { str = nullptr; }
bool operator==(const IString& other) const {
- //assert((str == other.str) == !strcmp(str, other.str));
+ // assert((str == other.str) == !strcmp(str, other.str));
return str == other.str; // fast!
}
bool operator!=(const IString& other) const {
- //assert((str == other.str) == !strcmp(str, other.str));
+ // assert((str == other.str) == !strcmp(str, other.str));
return str != other.str; // fast!
}
bool operator<(const IString& other) const {
return strcmp(str ? str : "", other.str ? other.str : "") < 0;
}
- char operator[](int x) const {
- return str[x];
- }
+ char operator[](int x) const { return str[x]; }
bool operator!() const { // no string, or empty string
return !str || str[0] == 0;
}
- const char *c_str() const { return str; }
- bool equals(const char *other) const { return !strcmp(str, other); }
+ const char* c_str() const { return str; }
+ bool equals(const char* other) const { return !strcmp(str, other); }
- bool is() const { return str != nullptr; }
+ bool is() const { return str != nullptr; }
bool isNull() const { return str == nullptr; }
- const char* stripPrefix(const char *prefix) const {
- const char *ptr = str;
+ const char* stripPrefix(const char* prefix) const {
+ const char* ptr = str;
while (true) {
- if (*prefix == 0) return ptr;
- if (*ptr == 0) return nullptr;
- if (*ptr++ != *prefix++) return nullptr;
+ if (*prefix == 0)
+ return ptr;
+ if (*ptr == 0)
+ return nullptr;
+ if (*ptr++ != *prefix++)
+ return nullptr;
}
}
- bool startsWith(const char *prefix) const {
+ bool startsWith(const char* prefix) const {
return stripPrefix(prefix) != nullptr;
}
- size_t size() const {
- return str ? strlen(str) : 0;
- }
+ size_t size() const { return str ? strlen(str) : 0; }
};
} // namespace cashew
@@ -161,13 +158,16 @@ struct IString {
namespace std {
-template<> struct hash<cashew::IString> : public unary_function<cashew::IString, size_t> {
+template<>
+struct hash<cashew::IString> : public unary_function<cashew::IString, size_t> {
size_t operator()(const cashew::IString& str) const {
return std::hash<size_t>{}(size_t(str.str));
}
};
-template<> struct equal_to<cashew::IString> : public binary_function<cashew::IString, cashew::IString, bool> {
+template<>
+struct equal_to<cashew::IString>
+ : public binary_function<cashew::IString, cashew::IString, bool> {
bool operator()(const cashew::IString& x, const cashew::IString& y) const {
return x == y;
}
@@ -181,32 +181,31 @@ namespace cashew {
class IStringSet : public std::unordered_set<IString> {
std::vector<char> data;
+
public:
IStringSet() = default;
- IStringSet(const char *init) { // comma-delimited list
+ IStringSet(const char* init) { // comma-delimited list
int size = strlen(init) + 1;
data.resize(size);
- char *curr = &data[0];
+ char* curr = &data[0];
strncpy(curr, init, size);
while (1) {
- char *end = strchr(curr, ' ');
- if (end) *end = 0;
+ char* end = strchr(curr, ' ');
+ if (end)
+ *end = 0;
insert(curr);
- if (!end) break;
+ if (!end)
+ break;
curr = end + 1;
}
}
- bool has(const IString& str) {
- return count(str) > 0;
- }
+ bool has(const IString& str) { return count(str) > 0; }
};
class IOrderedStringSet : public std::set<IString> {
public:
- bool has(const IString& str) {
- return count(str) > 0;
- }
+ bool has(const IString& str) { return count(str) > 0; }
};
} // namespace cashew
diff --git a/src/emscripten-optimizer/optimizer-shared.cpp b/src/emscripten-optimizer/optimizer-shared.cpp
index 81f7949ba..3ac3ca7ea 100644
--- a/src/emscripten-optimizer/optimizer-shared.cpp
+++ b/src/emscripten-optimizer/optimizer-shared.cpp
@@ -23,14 +23,14 @@ using namespace cashew;
IString ASM_FLOAT_ZERO;
-IString SIMD_INT8X16_CHECK("SIMD_Int8x16_check"),
- SIMD_INT16X8_CHECK("SIMD_Int16x8_check"),
- SIMD_INT32X4_CHECK("SIMD_Int32x4_check"),
- SIMD_FLOAT32X4_CHECK("SIMD_Float32x4_check"),
- SIMD_FLOAT64X2_CHECK("SIMD_Float64x2_check"),
- TEMP_RET0("tempRet0");
+IString SIMD_INT8X16_CHECK("SIMD_Int8x16_check");
+IString SIMD_INT16X8_CHECK("SIMD_Int16x8_check");
+IString SIMD_INT32X4_CHECK("SIMD_Int32x4_check");
+IString SIMD_FLOAT32X4_CHECK("SIMD_Float32x4_check");
+IString SIMD_FLOAT64X2_CHECK("SIMD_Float64x2_check");
+IString TEMP_RET0("tempRet0");
-int parseInt(const char *str) {
+int parseInt(const char* str) {
int ret = *str - '0';
while (*(++str)) {
ret *= 10;
@@ -39,7 +39,7 @@ int parseInt(const char *str) {
return ret;
}
-HeapInfo parseHeap(const char *name) {
+HeapInfo parseHeap(const char* name) {
HeapInfo ret;
if (name[0] != 'H' || name[1] != 'E' || name[2] != 'A' || name[3] != 'P') {
ret.valid = false;
@@ -53,33 +53,49 @@ HeapInfo parseHeap(const char *name) {
return ret;
}
-AsmType detectType(Ref node, AsmData *asmData, bool inVarDef, IString minifiedFround, bool allowI64) {
+AsmType detectType(Ref node,
+ AsmData* asmData,
+ bool inVarDef,
+ IString minifiedFround,
+ bool allowI64) {
if (node->isString()) {
if (asmData) {
AsmType ret = asmData->getType(node->getCString());
- if (ret != ASM_NONE) return ret;
+ if (ret != ASM_NONE)
+ return ret;
}
if (!inVarDef) {
- if (node == INF || node == NaN) return ASM_DOUBLE;
- if (node == TEMP_RET0) return ASM_INT;
+ if (node == INF || node == NaN)
+ return ASM_DOUBLE;
+ if (node == TEMP_RET0)
+ return ASM_INT;
return ASM_NONE;
}
- // We are in a variable definition, where Math_fround(0) optimized into a global constant becomes f0 = Math_fround(0)
- if (ASM_FLOAT_ZERO.isNull()) ASM_FLOAT_ZERO = node->getIString();
- else assert(node == ASM_FLOAT_ZERO);
+ // We are in a variable definition, where Math_fround(0) optimized into a
+ // global constant becomes f0 = Math_fround(0)
+ if (ASM_FLOAT_ZERO.isNull())
+ ASM_FLOAT_ZERO = node->getIString();
+ else
+ assert(node == ASM_FLOAT_ZERO);
return ASM_FLOAT;
}
if (node->isNumber()) {
- if (!wasm::isInteger(node->getNumber())) return ASM_DOUBLE;
+ if (!wasm::isInteger(node->getNumber()))
+ return ASM_DOUBLE;
return ASM_INT;
}
switch (node[0]->getCString()[0]) {
case 'u': {
if (node[0] == UNARY_PREFIX) {
switch (node[1]->getCString()[0]) {
- case '+': return ASM_DOUBLE;
- case '-': return detectType(node[2], asmData, inVarDef, minifiedFround, allowI64);
- case '!': case '~': return ASM_INT;
+ case '+':
+ return ASM_DOUBLE;
+ case '-':
+ return detectType(
+ node[2], asmData, inVarDef, minifiedFround, allowI64);
+ case '!':
+ case '~':
+ return ASM_INT;
}
break;
}
@@ -89,13 +105,20 @@ AsmType detectType(Ref node, AsmData *asmData, bool inVarDef, IString minifiedFr
if (node[0] == CALL) {
if (node[1]->isString()) {
IString name = node[1]->getIString();
- if (name == MATH_FROUND || name == minifiedFround) return ASM_FLOAT;
- else if (allowI64 && (name == INT64 || name == INT64_CONST)) return ASM_INT64;
- else if (name == SIMD_FLOAT32X4 || name == SIMD_FLOAT32X4_CHECK) return ASM_FLOAT32X4;
- else if (name == SIMD_FLOAT64X2 || name == SIMD_FLOAT64X2_CHECK) return ASM_FLOAT64X2;
- else if (name == SIMD_INT8X16 || name == SIMD_INT8X16_CHECK) return ASM_INT8X16;
- else if (name == SIMD_INT16X8 || name == SIMD_INT16X8_CHECK) return ASM_INT16X8;
- else if (name == SIMD_INT32X4 || name == SIMD_INT32X4_CHECK) return ASM_INT32X4;
+ if (name == MATH_FROUND || name == minifiedFround)
+ return ASM_FLOAT;
+ else if (allowI64 && (name == INT64 || name == INT64_CONST))
+ return ASM_INT64;
+ else if (name == SIMD_FLOAT32X4 || name == SIMD_FLOAT32X4_CHECK)
+ return ASM_FLOAT32X4;
+ else if (name == SIMD_FLOAT64X2 || name == SIMD_FLOAT64X2_CHECK)
+ return ASM_FLOAT64X2;
+ else if (name == SIMD_INT8X16 || name == SIMD_INT8X16_CHECK)
+ return ASM_INT8X16;
+ else if (name == SIMD_INT16X8 || name == SIMD_INT16X8_CHECK)
+ return ASM_INT16X8;
+ else if (name == SIMD_INT32X4 || name == SIMD_INT32X4_CHECK)
+ return ASM_INT32X4;
}
return ASM_NONE;
} else if (node[0] == CONDITIONAL) {
@@ -106,10 +129,20 @@ AsmType detectType(Ref node, AsmData *asmData, bool inVarDef, IString minifiedFr
case 'b': {
if (node[0] == BINARY) {
switch (node[1]->getCString()[0]) {
- case '+': case '-':
- case '*': case '/': case '%': return detectType(node[2], asmData, inVarDef, minifiedFround, allowI64);
- case '|': case '&': case '^': case '<': case '>': // handles <<, >>, >>=, <=, >=
- case '=': case '!': { // handles ==, !=
+ case '+':
+ case '-':
+ case '*':
+ case '/':
+ case '%':
+ return detectType(
+ node[2], asmData, inVarDef, minifiedFround, allowI64);
+ case '|':
+ case '&':
+ case '^':
+ case '<':
+ case '>': // handles <<, >>, >>=, <=, >=
+ case '=':
+ case '!': { // handles ==, !=
return ASM_INT;
}
}
@@ -122,14 +155,15 @@ AsmType detectType(Ref node, AsmData *asmData, bool inVarDef, IString minifiedFr
} else if (node[0] == SUB) {
assert(node[1]->isString());
HeapInfo info = parseHeap(node[1][1]->getCString());
- if (info.valid) return ASM_NONE;
+ if (info.valid)
+ return ASM_NONE;
return info.floaty ? ASM_DOUBLE : ASM_INT; // XXX ASM_FLOAT?
}
break;
}
}
- //dump("horrible", node);
- //assert(0);
+ // dump("horrible", node);
+ // assert(0);
return ASM_NONE;
}
@@ -145,9 +179,12 @@ AsmSign detectSign(Ref node, IString minifiedFround) {
}
if (node->isNumber()) {
double value = node->getNumber();
- if (value < 0) return ASM_SIGNED;
- if (value > uint32_t(-1) || fmod(value, 1) != 0) return ASM_NONSIGNED;
- if (wasm::isSInteger32(value)) return ASM_FLEXIBLE;
+ if (value < 0)
+ return ASM_SIGNED;
+ if (value > uint32_t(-1) || fmod(value, 1) != 0)
+ return ASM_NONSIGNED;
+ if (wasm::isSInteger32(value))
+ return ASM_FLEXIBLE;
return ASM_UNSIGNED;
}
IString type = node[0]->getIString();
@@ -155,25 +192,44 @@ AsmSign detectSign(Ref node, IString minifiedFround) {
IString op = node[1]->getIString();
switch (op.str[0]) {
case '>': {
- if (op == TRSHIFT) return ASM_UNSIGNED;
+ if (op == TRSHIFT)
+ return ASM_UNSIGNED;
} // fallthrough
- case '|': case '&': case '^': case '<': case '=': case '!': return ASM_SIGNED;
- case '+': case '-': return ASM_FLEXIBLE;
- case '*': case '/': case '%': return ASM_NONSIGNED; // without a coercion, these are double
- default: abort_on(node);
+ case '|':
+ case '&':
+ case '^':
+ case '<':
+ case '=':
+ case '!':
+ return ASM_SIGNED;
+ case '+':
+ case '-':
+ return ASM_FLEXIBLE;
+ case '*':
+ case '/':
+ case '%':
+ return ASM_NONSIGNED; // without a coercion, these are double
+ default:
+ abort_on(node);
}
} else if (type == UNARY_PREFIX) {
IString op = node[1]->getIString();
switch (op.str[0]) {
- case '-': return ASM_FLEXIBLE;
- case '+': return ASM_NONSIGNED; // XXX double
- case '~': return ASM_SIGNED;
- default: abort_on(node);
+ case '-':
+ return ASM_FLEXIBLE;
+ case '+':
+ return ASM_NONSIGNED; // XXX double
+ case '~':
+ return ASM_SIGNED;
+ default:
+ abort_on(node);
}
} else if (type == CONDITIONAL) {
return detectSign(node[2], minifiedFround);
} else if (type == CALL) {
- if (node[1]->isString() && (node[1] == MATH_FROUND || node[1] == minifiedFround)) return ASM_NONSIGNED;
+ if (node[1]->isString() &&
+ (node[1] == MATH_FROUND || node[1] == minifiedFround))
+ return ASM_NONSIGNED;
} else if (type == SEQ) {
return detectSign(node[2], minifiedFround);
}
@@ -183,8 +239,12 @@ AsmSign detectSign(Ref node, IString minifiedFround) {
Ref makeAsmCoercedZero(AsmType type) {
switch (type) {
- case ASM_INT: return ValueBuilder::makeNum(0); break;
- case ASM_DOUBLE: return ValueBuilder::makeUnary(PLUS, ValueBuilder::makeNum(0)); break;
+ case ASM_INT:
+ return ValueBuilder::makeNum(0);
+ break;
+ case ASM_DOUBLE:
+ return ValueBuilder::makeUnary(PLUS, ValueBuilder::makeNum(0));
+ break;
case ASM_FLOAT: {
if (!ASM_FLOAT_ZERO.isNull()) {
return ValueBuilder::makeName(ASM_FLOAT_ZERO);
@@ -194,46 +254,92 @@ Ref makeAsmCoercedZero(AsmType type) {
break;
}
case ASM_FLOAT32X4: {
- return ValueBuilder::makeCall(SIMD_FLOAT32X4, ValueBuilder::makeNum(0), ValueBuilder::makeNum(0), ValueBuilder::makeNum(0), ValueBuilder::makeNum(0));
+ return ValueBuilder::makeCall(SIMD_FLOAT32X4,
+ ValueBuilder::makeNum(0),
+ ValueBuilder::makeNum(0),
+ ValueBuilder::makeNum(0),
+ ValueBuilder::makeNum(0));
break;
}
case ASM_FLOAT64X2: {
- return ValueBuilder::makeCall(SIMD_FLOAT64X2, ValueBuilder::makeNum(0), ValueBuilder::makeNum(0));
+ return ValueBuilder::makeCall(
+ SIMD_FLOAT64X2, ValueBuilder::makeNum(0), ValueBuilder::makeNum(0));
break;
}
case ASM_INT8X16: {
- return ValueBuilder::makeCall(SIMD_INT8X16, ValueBuilder::makeNum(0), ValueBuilder::makeNum(0), ValueBuilder::makeNum(0), ValueBuilder::makeNum(0), ValueBuilder::makeNum(0), ValueBuilder::makeNum(0), ValueBuilder::makeNum(0), ValueBuilder::makeNum(0), ValueBuilder::makeNum(0), ValueBuilder::makeNum(0), ValueBuilder::makeNum(0), ValueBuilder::makeNum(0), ValueBuilder::makeNum(0), ValueBuilder::makeNum(0), ValueBuilder::makeNum(0), ValueBuilder::makeNum(0));
+ return ValueBuilder::makeCall(SIMD_INT8X16,
+ ValueBuilder::makeNum(0),
+ ValueBuilder::makeNum(0),
+ ValueBuilder::makeNum(0),
+ ValueBuilder::makeNum(0),
+ ValueBuilder::makeNum(0),
+ ValueBuilder::makeNum(0),
+ ValueBuilder::makeNum(0),
+ ValueBuilder::makeNum(0),
+ ValueBuilder::makeNum(0),
+ ValueBuilder::makeNum(0),
+ ValueBuilder::makeNum(0),
+ ValueBuilder::makeNum(0),
+ ValueBuilder::makeNum(0),
+ ValueBuilder::makeNum(0),
+ ValueBuilder::makeNum(0),
+ ValueBuilder::makeNum(0));
break;
}
case ASM_INT16X8: {
- return ValueBuilder::makeCall(SIMD_INT16X8, ValueBuilder::makeNum(0), ValueBuilder::makeNum(0), ValueBuilder::makeNum(0), ValueBuilder::makeNum(0), ValueBuilder::makeNum(0), ValueBuilder::makeNum(0), ValueBuilder::makeNum(0), ValueBuilder::makeNum(0));
+ return ValueBuilder::makeCall(SIMD_INT16X8,
+ ValueBuilder::makeNum(0),
+ ValueBuilder::makeNum(0),
+ ValueBuilder::makeNum(0),
+ ValueBuilder::makeNum(0),
+ ValueBuilder::makeNum(0),
+ ValueBuilder::makeNum(0),
+ ValueBuilder::makeNum(0),
+ ValueBuilder::makeNum(0));
break;
}
case ASM_INT32X4: {
- return ValueBuilder::makeCall(SIMD_INT32X4, ValueBuilder::makeNum(0), ValueBuilder::makeNum(0), ValueBuilder::makeNum(0), ValueBuilder::makeNum(0));
+ return ValueBuilder::makeCall(SIMD_INT32X4,
+ ValueBuilder::makeNum(0),
+ ValueBuilder::makeNum(0),
+ ValueBuilder::makeNum(0),
+ ValueBuilder::makeNum(0));
break;
}
- default: assert(0);
+ default:
+ assert(0);
}
abort();
}
Ref makeAsmCoercion(Ref node, AsmType type) {
switch (type) {
- case ASM_INT: return ValueBuilder::makeBinary(node, OR, ValueBuilder::makeNum(0));
- case ASM_DOUBLE: return ValueBuilder::makeUnary(PLUS, node);
- case ASM_FLOAT: return ValueBuilder::makeCall(MATH_FROUND, node);
- case ASM_FLOAT32X4: return ValueBuilder::makeCall(SIMD_FLOAT32X4_CHECK, node);
- case ASM_FLOAT64X2: return ValueBuilder::makeCall(SIMD_FLOAT64X2_CHECK, node);
- case ASM_INT8X16: return ValueBuilder::makeCall(SIMD_INT8X16_CHECK, node);
- case ASM_INT16X8: return ValueBuilder::makeCall(SIMD_INT16X8_CHECK, node);
- case ASM_INT32X4: return ValueBuilder::makeCall(SIMD_INT32X4_CHECK, node);
+ case ASM_INT:
+ return ValueBuilder::makeBinary(node, OR, ValueBuilder::makeNum(0));
+ case ASM_DOUBLE:
+ return ValueBuilder::makeUnary(PLUS, node);
+ case ASM_FLOAT:
+ return ValueBuilder::makeCall(MATH_FROUND, node);
+ case ASM_FLOAT32X4:
+ return ValueBuilder::makeCall(SIMD_FLOAT32X4_CHECK, node);
+ case ASM_FLOAT64X2:
+ return ValueBuilder::makeCall(SIMD_FLOAT64X2_CHECK, node);
+ case ASM_INT8X16:
+ return ValueBuilder::makeCall(SIMD_INT8X16_CHECK, node);
+ case ASM_INT16X8:
+ return ValueBuilder::makeCall(SIMD_INT16X8_CHECK, node);
+ case ASM_INT32X4:
+ return ValueBuilder::makeCall(SIMD_INT32X4_CHECK, node);
case ASM_NONE:
- default: return node; // non-validating code, emit nothing XXX this is dangerous, we should only allow this when we know we are not validating
+ default:
+ // non-validating code, emit nothing XXX this is dangerous, we should only
+ // allow this when we know we are not validating
+ return node;
}
}
Ref makeSigning(Ref node, AsmSign sign) {
assert(sign == ASM_SIGNED || sign == ASM_UNSIGNED);
- return ValueBuilder::makeBinary(node, sign == ASM_SIGNED ? OR : TRSHIFT, ValueBuilder::makeNum(0));
+ return ValueBuilder::makeBinary(
+ node, sign == ASM_SIGNED ? OR : TRSHIFT, ValueBuilder::makeNum(0));
}
diff --git a/src/emscripten-optimizer/optimizer.h b/src/emscripten-optimizer/optimizer.h
index f6b3aa536..36a9322fd 100644
--- a/src/emscripten-optimizer/optimizer.h
+++ b/src/emscripten-optimizer/optimizer.h
@@ -19,11 +19,7 @@
#include "simple_ast.h"
-extern bool preciseF32,
- receiveJSON,
- emitJSON,
- minifyWhitespace,
- last;
+extern bool preciseF32, receiveJSON, emitJSON, minifyWhitespace, last;
extern cashew::Ref extraInfo;
@@ -39,12 +35,16 @@ enum AsmType {
ASM_INT16X8,
ASM_INT32X4,
ASM_INT64, // non-asm.js
- ASM_NONE // number of types
+ ASM_NONE // number of types
};
struct AsmData;
-AsmType detectType(cashew::Ref node, AsmData *asmData=nullptr, bool inVarDef=false, cashew::IString minifiedFround=cashew::IString(), bool allowI64=false);
+AsmType detectType(cashew::Ref node,
+ AsmData* asmData = nullptr,
+ bool inVarDef = false,
+ cashew::IString minifiedFround = cashew::IString(),
+ bool allowI64 = false);
struct AsmData {
struct Local {
@@ -57,23 +57,22 @@ struct AsmData {
Locals locals;
std::vector<cashew::IString> params; // in order
- std::vector<cashew::IString> vars; // in order
+ std::vector<cashew::IString> vars; // in order
AsmType ret;
cashew::Ref func;
AsmType getType(const cashew::IString& name) {
auto ret = locals.find(name);
- if (ret != locals.end()) return ret->second.type;
+ if (ret != locals.end())
+ return ret->second.type;
return ASM_NONE;
}
void setType(const cashew::IString& name, AsmType type) {
locals[name].type = type;
}
- bool isLocal(const cashew::IString& name) {
- return locals.count(name) > 0;
- }
+ bool isLocal(const cashew::IString& name) { return locals.count(name) > 0; }
bool isParam(const cashew::IString& name) {
return isLocal(name) && locals[name].param;
}
@@ -81,8 +80,11 @@ struct AsmData {
return isLocal(name) && !locals[name].param;
}
- AsmData() = default; // if you want to fill in the data yourself
- AsmData(cashew::Ref f); // if you want to read data from f, and modify it as you go (parallel to denormalize)
+ // if you want to fill in the data yourself
+ AsmData() = default;
+ // if you want to read data from f, and modify it as you go (parallel to
+ // denormalize)
+ AsmData(cashew::Ref f);
void denormalize();
@@ -108,13 +110,13 @@ struct AsmData {
extern cashew::IString ASM_FLOAT_ZERO;
-extern cashew::IString SIMD_INT8X16_CHECK,
- SIMD_INT16X8_CHECK,
- SIMD_INT32X4_CHECK,
- SIMD_FLOAT32X4_CHECK,
- SIMD_FLOAT64X2_CHECK;
+extern cashew::IString SIMD_INT8X16_CHECK;
+extern cashew::IString SIMD_INT16X8_CHECK;
+extern cashew::IString SIMD_INT32X4_CHECK;
+extern cashew::IString SIMD_FLOAT32X4_CHECK;
+extern cashew::IString SIMD_FLOAT64X2_CHECK;
-int parseInt(const char *str);
+int parseInt(const char* str);
struct HeapInfo {
bool valid, unsign, floaty;
@@ -122,10 +124,11 @@ struct HeapInfo {
AsmType type;
};
-HeapInfo parseHeap(const char *name);
+HeapInfo parseHeap(const char* name);
enum AsmSign {
- ASM_FLEXIBLE = 0, // small constants can be signed or unsigned, variables are also flexible
+ // small constants can be signed or unsigned, variables are also flexible
+ ASM_FLEXIBLE = 0,
ASM_SIGNED = 1,
ASM_UNSIGNED = 2,
ASM_NONSIGNED = 3,
diff --git a/src/emscripten-optimizer/parser.cpp b/src/emscripten-optimizer/parser.cpp
index 035817090..72740908e 100644
--- a/src/emscripten-optimizer/parser.cpp
+++ b/src/emscripten-optimizer/parser.cpp
@@ -20,117 +20,119 @@ namespace cashew {
// common strings
-IString TOPLEVEL("toplevel"),
- DEFUN("defun"),
- BLOCK("block"),
- VAR("var"),
- CONST("const"),
- CONDITIONAL("conditional"),
- BINARY("binary"),
- RETURN("return"),
- IF("if"),
- ELSE("else"),
- WHILE("while"),
- DO("do"),
- FOR("for"),
- SEQ("seq"),
- SUB("sub"),
- CALL("call"),
- LABEL("label"),
- BREAK("break"),
- CONTINUE("continue"),
- SWITCH("switch"),
- STRING("string"),
- TRY("try"),
- INF("inf"),
- NaN("nan"),
- LLVM_CTTZ_I32("_llvm_cttz_i32"),
- UDIVMODDI4("___udivmoddi4"),
- UNARY_PREFIX("unary-prefix"),
- UNARY_POSTFIX("unary-postfix"),
- MATH_FROUND("Math_fround"),
- MATH_CLZ32("Math_clz32"),
- INT64("i64"),
- INT64_CONST("i64_const"),
- SIMD_FLOAT32X4("SIMD_Float32x4"),
- SIMD_FLOAT64X2("SIMD_Float64x2"),
- SIMD_INT8X16("SIMD_Int8x16"),
- SIMD_INT16X8("SIMD_Int16x8"),
- SIMD_INT32X4("SIMD_Int32x4"),
- PLUS("+"),
- MINUS("-"),
- OR("|"),
- AND("&"),
- XOR("^"),
- L_NOT("!"),
- B_NOT("~"),
- LT("<"),
- GE(">="),
- LE("<="),
- GT(">"),
- EQ("=="),
- NE("!="),
- DIV("/"),
- MOD("%"),
- MUL("*"),
- RSHIFT(">>"),
- LSHIFT("<<"),
- TRSHIFT(">>>"),
- HEAP8("HEAP8"),
- HEAP16("HEAP16"),
- HEAP32("HEAP32"),
- HEAPF32("HEAPF32"),
- HEAPU8("HEAPU8"),
- HEAPU16("HEAPU16"),
- HEAPU32("HEAPU32"),
- HEAPF64("HEAPF64"),
- F0("f0"),
- EMPTY(""),
- FUNCTION("function"),
- OPEN_PAREN("("),
- OPEN_BRACE("["),
- OPEN_CURLY("{"),
- CLOSE_CURLY("}"),
- COMMA(","),
- QUESTION("?"),
- COLON(":"),
- CASE("case"),
- DEFAULT("default"),
- DOT("dot"),
- PERIOD("."),
- NEW("new"),
- ARRAY("array"),
- OBJECT("object"),
- THROW("throw"),
- SET("=");
-
-IStringSet keywords("var const function if else do while for break continue return switch case default throw try catch finally true false null new");
-
-const char *OPERATOR_INITS = "+-*/%<>&^|~=!,?:.",
- *SEPARATORS = "([;{}";
+IString TOPLEVEL("toplevel");
+IString DEFUN("defun");
+IString BLOCK("block");
+IString VAR("var");
+IString CONST("const");
+IString CONDITIONAL("conditional");
+IString BINARY("binary");
+IString RETURN("return");
+IString IF("if");
+IString ELSE("else");
+IString WHILE("while");
+IString DO("do");
+IString FOR("for");
+IString SEQ("seq");
+IString SUB("sub");
+IString CALL("call");
+IString LABEL("label");
+IString BREAK("break");
+IString CONTINUE("continue");
+IString SWITCH("switch");
+IString STRING("string");
+IString TRY("try");
+IString INF("inf");
+IString NaN("nan");
+IString LLVM_CTTZ_I32("_llvm_cttz_i32");
+IString UDIVMODDI4("___udivmoddi4");
+IString UNARY_PREFIX("unary-prefix");
+IString UNARY_POSTFIX("unary-postfix");
+IString MATH_FROUND("Math_fround");
+IString MATH_CLZ32("Math_clz32");
+IString INT64("i64");
+IString INT64_CONST("i64_const");
+IString SIMD_FLOAT32X4("SIMD_Float32x4");
+IString SIMD_FLOAT64X2("SIMD_Float64x2");
+IString SIMD_INT8X16("SIMD_Int8x16");
+IString SIMD_INT16X8("SIMD_Int16x8");
+IString SIMD_INT32X4("SIMD_Int32x4");
+IString PLUS("+");
+IString MINUS("-");
+IString OR("|");
+IString AND("&");
+IString XOR("^");
+IString L_NOT("!");
+IString B_NOT("~");
+IString LT("<");
+IString GE(">=");
+IString LE("<=");
+IString GT(">");
+IString EQ("==");
+IString NE("!=");
+IString DIV("/");
+IString MOD("%");
+IString MUL("*");
+IString RSHIFT(">>");
+IString LSHIFT("<<");
+IString TRSHIFT(">>>");
+IString HEAP8("HEAP8");
+IString HEAP16("HEAP16");
+IString HEAP32("HEAP32");
+IString HEAPF32("HEAPF32");
+IString HEAPU8("HEAPU8");
+IString HEAPU16("HEAPU16");
+IString HEAPU32("HEAPU32");
+IString HEAPF64("HEAPF64");
+IString F0("f0");
+IString EMPTY("");
+IString FUNCTION("function");
+IString OPEN_PAREN("(");
+IString OPEN_BRACE("[");
+IString OPEN_CURLY("{");
+IString CLOSE_CURLY("}");
+IString COMMA(",");
+IString QUESTION("?");
+IString COLON(":");
+IString CASE("case");
+IString DEFAULT("default");
+IString DOT("dot");
+IString PERIOD(".");
+IString NEW("new");
+IString ARRAY("array");
+IString OBJECT("object");
+IString THROW("throw");
+IString SET("=");
+
+IStringSet
+ keywords("var const function if else do while for break continue return "
+ "switch case default throw try catch finally true false null new");
+
+const char *OPERATOR_INITS = "+-*/%<>&^|~=!,?:.", *SEPARATORS = "([;{}";
int MAX_OPERATOR_SIZE = 3;
std::vector<OperatorClass> operatorClasses;
-static std::vector<std::unordered_map<IString, int>> precedences; // op, type => prec
+static std::vector<std::unordered_map<IString, int>>
+ precedences; // op, type => prec
struct Init {
Init() {
// operators, rtl, type
- operatorClasses.emplace_back(".", false, OperatorClass::Binary);
- operatorClasses.emplace_back("! ~ + -", true, OperatorClass::Prefix);
- operatorClasses.emplace_back("* / %", false, OperatorClass::Binary);
- operatorClasses.emplace_back("+ -", false, OperatorClass::Binary);
+ operatorClasses.emplace_back(".", false, OperatorClass::Binary);
+ operatorClasses.emplace_back("! ~ + -", true, OperatorClass::Prefix);
+ operatorClasses.emplace_back("* / %", false, OperatorClass::Binary);
+ operatorClasses.emplace_back("+ -", false, OperatorClass::Binary);
operatorClasses.emplace_back("<< >> >>>", false, OperatorClass::Binary);
operatorClasses.emplace_back("< <= > >=", false, OperatorClass::Binary);
- operatorClasses.emplace_back("== !=", false, OperatorClass::Binary);
- operatorClasses.emplace_back("&", false, OperatorClass::Binary);
- operatorClasses.emplace_back("^", false, OperatorClass::Binary);
- operatorClasses.emplace_back("|", false, OperatorClass::Binary);
- operatorClasses.emplace_back("? :", true, OperatorClass::Tertiary);
- operatorClasses.emplace_back("=", true, OperatorClass::Binary);
- operatorClasses.emplace_back(",", true, OperatorClass::Binary);
+ operatorClasses.emplace_back("== !=", false, OperatorClass::Binary);
+ operatorClasses.emplace_back("&", false, OperatorClass::Binary);
+ operatorClasses.emplace_back("^", false, OperatorClass::Binary);
+ operatorClasses.emplace_back("|", false, OperatorClass::Binary);
+ operatorClasses.emplace_back("? :", true, OperatorClass::Tertiary);
+ operatorClasses.emplace_back("=", true, OperatorClass::Binary);
+ operatorClasses.emplace_back(",", true, OperatorClass::Binary);
precedences.resize(OperatorClass::Tertiary + 1);
@@ -148,11 +150,12 @@ int OperatorClass::getPrecedence(Type type, IString op) {
return precedences[type][op];
}
-bool OperatorClass::getRtl(int prec) {
- return operatorClasses[prec].rtl;
-}
+bool OperatorClass::getRtl(int prec) { return operatorClasses[prec].rtl; }
-bool isIdentInit(char x) { return (x >= 'a' && x <= 'z') || (x >= 'A' && x <= 'Z') || x == '_' || x == '$'; }
+bool isIdentInit(char x) {
+ return (x >= 'a' && x <= 'z') || (x >= 'A' && x <= 'Z') || x == '_' ||
+ x == '$';
+}
bool isIdentPart(char x) { return isIdentInit(x) || (x >= '0' && x <= '9'); }
} // namespace cashew
diff --git a/src/emscripten-optimizer/parser.h b/src/emscripten-optimizer/parser.h
index 78ed27933..d180ea12c 100644
--- a/src/emscripten-optimizer/parser.h
+++ b/src/emscripten-optimizer/parser.h
@@ -14,10 +14,12 @@
* limitations under the License.
*/
-// Pure parsing. Calls methods on a Builder (template argument) to actually construct the AST
+// Pure parsing. Calls methods on a Builder (template argument) to actually
+// construct the AST
//
-// XXX All parsing methods assume they take ownership of the input string. This lets them reuse
-// parts of it. You will segfault if the input string cannot be reused and written to.
+// XXX All parsing methods assume they take ownership of the input string. This
+// lets them reuse parts of it. You will segfault if the input string cannot
+// be reused and written to.
#ifndef wasm_parser_h
#define wasm_parser_h
@@ -35,89 +37,89 @@ namespace cashew {
// common strings
-extern IString TOPLEVEL,
- DEFUN,
- BLOCK,
- VAR,
- CONST,
- CONDITIONAL,
- BINARY,
- RETURN,
- IF,
- ELSE,
- WHILE,
- DO,
- FOR,
- SEQ,
- SUB,
- CALL,
- LABEL,
- BREAK,
- CONTINUE,
- SWITCH,
- STRING,
- TRY,
- INF,
- NaN,
- LLVM_CTTZ_I32,
- UDIVMODDI4,
- UNARY_PREFIX,
- UNARY_POSTFIX,
- MATH_FROUND,
- MATH_CLZ32,
- INT64,
- INT64_CONST,
- SIMD_FLOAT32X4,
- SIMD_FLOAT64X2,
- SIMD_INT8X16,
- SIMD_INT16X8,
- SIMD_INT32X4,
- PLUS,
- MINUS,
- OR,
- AND,
- XOR,
- L_NOT,
- B_NOT,
- LT,
- GE,
- LE,
- GT,
- EQ,
- NE,
- DIV,
- MOD,
- MUL,
- RSHIFT,
- LSHIFT,
- TRSHIFT,
- HEAP8,
- HEAP16,
- HEAP32,
- HEAPF32,
- HEAPU8,
- HEAPU16,
- HEAPU32,
- HEAPF64,
- F0,
- EMPTY,
- FUNCTION,
- OPEN_PAREN,
- OPEN_BRACE,
- OPEN_CURLY,
- CLOSE_CURLY,
- COMMA,
- QUESTION,
- COLON,
- CASE,
- DEFAULT,
- DOT,
- PERIOD,
- NEW,
- ARRAY,
- OBJECT,
- THROW,
- SET;
+extern IString TOPLEVEL;
+extern IString DEFUN;
+extern IString BLOCK;
+extern IString VAR;
+extern IString CONST;
+extern IString CONDITIONAL;
+extern IString BINARY;
+extern IString RETURN;
+extern IString IF;
+extern IString ELSE;
+extern IString WHILE;
+extern IString DO;
+extern IString FOR;
+extern IString SEQ;
+extern IString SUB;
+extern IString CALL;
+extern IString LABEL;
+extern IString BREAK;
+extern IString CONTINUE;
+extern IString SWITCH;
+extern IString STRING;
+extern IString TRY;
+extern IString INF;
+extern IString NaN;
+extern IString LLVM_CTTZ_I32;
+extern IString UDIVMODDI4;
+extern IString UNARY_PREFIX;
+extern IString UNARY_POSTFIX;
+extern IString MATH_FROUND;
+extern IString MATH_CLZ32;
+extern IString INT64;
+extern IString INT64_CONST;
+extern IString SIMD_FLOAT32X4;
+extern IString SIMD_FLOAT64X2;
+extern IString SIMD_INT8X16;
+extern IString SIMD_INT16X8;
+extern IString SIMD_INT32X4;
+extern IString PLUS;
+extern IString MINUS;
+extern IString OR;
+extern IString AND;
+extern IString XOR;
+extern IString L_NOT;
+extern IString B_NOT;
+extern IString LT;
+extern IString GE;
+extern IString LE;
+extern IString GT;
+extern IString EQ;
+extern IString NE;
+extern IString DIV;
+extern IString MOD;
+extern IString MUL;
+extern IString RSHIFT;
+extern IString LSHIFT;
+extern IString TRSHIFT;
+extern IString HEAP8;
+extern IString HEAP16;
+extern IString HEAP32;
+extern IString HEAPF32;
+extern IString HEAPU8;
+extern IString HEAPU16;
+extern IString HEAPU32;
+extern IString HEAPF64;
+extern IString F0;
+extern IString EMPTY;
+extern IString FUNCTION;
+extern IString OPEN_PAREN;
+extern IString OPEN_BRACE;
+extern IString OPEN_CURLY;
+extern IString CLOSE_CURLY;
+extern IString COMMA;
+extern IString QUESTION;
+extern IString COLON;
+extern IString CASE;
+extern IString DEFAULT;
+extern IString DOT;
+extern IString PERIOD;
+extern IString NEW;
+extern IString ARRAY;
+extern IString OBJECT;
+extern IString THROW;
+extern IString SET;
extern IStringSet keywords;
@@ -126,12 +128,7 @@ extern const char *OPERATOR_INITS, *SEPARATORS;
extern int MAX_OPERATOR_SIZE, LOWEST_PREC;
struct OperatorClass {
- enum Type {
- Binary = 0,
- Prefix = 1,
- Postfix = 2,
- Tertiary = 3
- };
+ enum Type { Binary = 0, Prefix = 1, Postfix = 2, Tertiary = 3 };
IStringSet ops;
bool rtl;
@@ -150,10 +147,11 @@ extern bool isIdentPart(char x);
// parser
-template<class NodeRef, class Builder>
-class Parser {
+template<class NodeRef, class Builder> class Parser {
- static bool isSpace(char x) { return x == 32 || x == 9 || x == 10 || x == 13; } /* space, tab, linefeed/newline, or return */
+ static bool isSpace(char x) {
+ return x == 32 || x == 9 || x == 10 || x == 13;
+ } /* space, tab, linefeed/newline, or return */
static void skipSpace(char*& curr) {
while (*curr) {
if (isSpace(*curr)) {
@@ -162,13 +160,16 @@ class Parser {
}
if (curr[0] == '/' && curr[1] == '/') {
curr += 2;
- while (*curr && *curr != '\n') curr++;
- if (*curr) curr++;
+ while (*curr && *curr != '\n')
+ curr++;
+ if (*curr)
+ curr++;
continue;
}
if (curr[0] == '/' && curr[1] == '*') {
curr += 2;
- while (*curr && (curr[0] != '*' || curr[1] != '/')) curr++;
+ while (*curr && (curr[0] != '*' || curr[1] != '/'))
+ curr++;
curr += 2;
continue;
}
@@ -178,7 +179,12 @@ class Parser {
static bool isDigit(char x) { return x >= '0' && x <= '9'; }
- static bool hasChar(const char* list, char x) { while (*list) if (*list++ == x) return true; return false; }
+ static bool hasChar(const char* list, char x) {
+ while (*list)
+ if (*list++ == x)
+ return true;
+ return false;
+ }
// An atomic fragment of something. Stops at a natural boundary.
enum FragType {
@@ -192,7 +198,9 @@ class Parser {
};
struct Frag {
-#ifndef _MSC_VER // MSVC does not allow unrestricted unions: http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2544.pdf
+ // MSVC does not allow unrestricted unions:
+ // http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2544.pdf
+#ifndef _MSC_VER
union {
#endif
IString str;
@@ -203,12 +211,10 @@ class Parser {
int size;
FragType type;
- bool isNumber() const {
- return type == INT || type == DOUBLE;
- }
+ bool isNumber() const { return type == INT || type == DOUBLE; }
explicit Frag(char* src) {
- char *start = src;
+ char* start = src;
if (isIdentInit(*src)) {
// read an identifier or a keyword
src++;
@@ -227,15 +233,22 @@ class Parser {
} else if (isDigit(*src) || (src[0] == '.' && isDigit(src[1]))) {
if (src[0] == '0' && (src[1] == 'x' || src[1] == 'X')) {
// Explicitly parse hex numbers of form "0x...", because strtod
- // supports hex number strings only in C++11, and Visual Studio 2013 does
- // not yet support that functionality.
+ // supports hex number strings only in C++11, and Visual Studio 2013
+ // does not yet support that functionality.
src += 2;
num = 0;
while (1) {
- if (*src >= '0' && *src <= '9') { num *= 16; num += *src - '0'; }
- else if (*src >= 'a' && *src <= 'f') { num *= 16; num += *src - 'a' + 10; }
- else if (*src >= 'A' && *src <= 'F') { num *= 16; num += *src - 'A' + 10; }
- else break;
+ if (*src >= '0' && *src <= '9') {
+ num *= 16;
+ num += *src - '0';
+ } else if (*src >= 'a' && *src <= 'f') {
+ num *= 16;
+ num += *src - 'a' + 10;
+ } else if (*src >= 'A' && *src <= 'F') {
+ num *= 16;
+ num += *src - 'A' + 10;
+ } else
+ break;
src++;
}
} else {
@@ -244,33 +257,69 @@ class Parser {
// asm.js must have a '.' for double values. however, we also tolerate
// uglify's tendency to emit without a '.' (and fix it later with a +).
// for valid asm.js input, the '.' should be enough, and for uglify
- // in the emscripten optimizer pipeline, we use simple_ast where INT/DOUBLE
- // is quite the same at this point anyhow
+ // in the emscripten optimizer pipeline, we use simple_ast where
+ // INT/DOUBLE is quite the same at this point anyhow
type = (std::find(start, src, '.') == src &&
(wasm::isSInteger32(num) || wasm::isUInteger32(num)))
- ? INT
- : DOUBLE;
+ ? INT
+ : DOUBLE;
assert(src > start);
} else if (hasChar(OPERATOR_INITS, *src)) {
switch (*src) {
- case '!': str = src[1] == '=' ? NE : L_NOT; break;
- case '%': str = MOD; break;
- case '&': str = AND; break;
- case '*': str = MUL; break;
- case '+': str = PLUS; break;
- case ',': str = COMMA; break;
- case '-': str = MINUS; break;
- case '.': str = PERIOD; break;
- case '/': str = DIV; break;
- case ':': str = COLON; break;
- case '<': str = src[1] == '<' ? LSHIFT : (src[1] == '=' ? LE : LT); break;
- case '=': str = src[1] == '=' ? EQ : SET; break;
- case '>': str = src[1] == '>' ? (src[2] == '>' ? TRSHIFT : RSHIFT) : (src[1] == '=' ? GE : GT); break;
- case '?': str = QUESTION; break;
- case '^': str = XOR; break;
- case '|': str = OR; break;
- case '~': str = B_NOT; break;
- default: abort();
+ case '!':
+ str = src[1] == '=' ? NE : L_NOT;
+ break;
+ case '%':
+ str = MOD;
+ break;
+ case '&':
+ str = AND;
+ break;
+ case '*':
+ str = MUL;
+ break;
+ case '+':
+ str = PLUS;
+ break;
+ case ',':
+ str = COMMA;
+ break;
+ case '-':
+ str = MINUS;
+ break;
+ case '.':
+ str = PERIOD;
+ break;
+ case '/':
+ str = DIV;
+ break;
+ case ':':
+ str = COLON;
+ break;
+ case '<':
+ str = src[1] == '<' ? LSHIFT : (src[1] == '=' ? LE : LT);
+ break;
+ case '=':
+ str = src[1] == '=' ? EQ : SET;
+ break;
+ case '>':
+ str = src[1] == '>' ? (src[2] == '>' ? TRSHIFT : RSHIFT)
+ : (src[1] == '=' ? GE : GT);
+ break;
+ case '?':
+ str = QUESTION;
+ break;
+ case '^':
+ str = XOR;
+ break;
+ case '|':
+ str = OR;
+ break;
+ case '~':
+ str = B_NOT;
+ break;
+ default:
+ abort();
}
size = strlen(str.str);
#ifndef NDEBUG
@@ -289,10 +338,10 @@ class Parser {
src[1] = temp;
src++;
} else if (*src == '"' || *src == '\'') {
- char *end = strchr(src+1, *src);
+ char* end = strchr(src + 1, *src);
*end = 0;
- str.set(src+1);
- src = end+1;
+ str.set(src + 1);
+ src = end + 1;
type = STRING;
} else {
dump("frag parsing", src);
@@ -304,7 +353,9 @@ class Parser {
struct ExpressionElement {
bool isNode;
-#ifndef _MSC_VER // MSVC does not allow unrestricted unions: http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2544.pdf
+ // MSVC does not allow unrestricted unions:
+ // http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2544.pdf
+#ifndef _MSC_VER
union {
#endif
NodeRef node;
@@ -326,13 +377,15 @@ class Parser {
};
// This is a list of the current stack of node-operator-node-operator-etc.
- // this works by each parseExpression call appending to the vector; then recursing out, and the toplevel sorts it all
+ // this works by each parseExpression call appending to the vector; then
+ // recursing out, and the toplevel sorts it all
typedef std::vector<ExpressionElement> ExpressionParts;
std::vector<ExpressionParts> expressionPartsStack;
- // Parses an element in a list of such elements, e.g. list of statements in a block, or list of parameters in a call
- NodeRef parseElement(char*& src, const char* seps=";") {
- //dump("parseElement", src);
+ // Parses an element in a list of such elements, e.g. list of statements in a
+ // block, or list of parameters in a call
+ NodeRef parseElement(char*& src, const char* seps = ";") {
+ // dump("parseElement", src);
skipSpace(src);
Frag frag(src);
src += frag.size;
@@ -349,44 +402,67 @@ class Parser {
return parseExpression(parseFrag(frag), src, seps);
}
case SEPARATOR: {
- if (frag.str == OPEN_PAREN) return parseExpression(parseAfterParen(src), src, seps);
- if (frag.str == OPEN_BRACE) return parseExpression(parseAfterBrace(src), src, seps);
- if (frag.str == OPEN_CURLY) return parseExpression(parseAfterCurly(src), src, seps);
+ if (frag.str == OPEN_PAREN)
+ return parseExpression(parseAfterParen(src), src, seps);
+ if (frag.str == OPEN_BRACE)
+ return parseExpression(parseAfterBrace(src), src, seps);
+ if (frag.str == OPEN_CURLY)
+ return parseExpression(parseAfterCurly(src), src, seps);
abort();
}
case OPERATOR: {
return parseExpression(frag.str, src, seps);
}
- default: /* dump("parseElement", src); printf("bad frag type: %d\n", frag.type); */ abort();
+ default:
+ /* dump("parseElement", src); printf("bad frag type: %d\n",frag.type);
+ */
+ abort();
}
return nullptr;
}
NodeRef parseFrag(Frag& frag) {
switch (frag.type) {
- case IDENT: return Builder::makeName(frag.str);
- case STRING: return Builder::makeString(frag.str);
- case INT: return Builder::makeInt(uint32_t(frag.num));
- case DOUBLE: return Builder::makeDouble(frag.num);
- default: abort();
+ case IDENT:
+ return Builder::makeName(frag.str);
+ case STRING:
+ return Builder::makeString(frag.str);
+ case INT:
+ return Builder::makeInt(uint32_t(frag.num));
+ case DOUBLE:
+ return Builder::makeDouble(frag.num);
+ default:
+ abort();
}
return nullptr;
}
NodeRef parseAfterKeyword(Frag& frag, char*& src, const char* seps) {
skipSpace(src);
- if (frag.str == FUNCTION) return parseFunction(src, seps);
- else if (frag.str == VAR) return parseVar(src, seps, false);
- else if (frag.str == CONST) return parseVar(src, seps, true);
- else if (frag.str == RETURN) return parseReturn(src, seps);
- else if (frag.str == IF) return parseIf(src, seps);
- else if (frag.str == DO) return parseDo(src, seps);
- else if (frag.str == WHILE) return parseWhile(src, seps);
- else if (frag.str == BREAK) return parseBreak(src, seps);
- else if (frag.str == CONTINUE) return parseContinue(src, seps);
- else if (frag.str == SWITCH) return parseSwitch(src, seps);
- else if (frag.str == NEW) return parseNew(src, seps);
- else if (frag.str == FOR) return parseFor(src, seps);
+ if (frag.str == FUNCTION)
+ return parseFunction(src, seps);
+ else if (frag.str == VAR)
+ return parseVar(src, seps, false);
+ else if (frag.str == CONST)
+ return parseVar(src, seps, true);
+ else if (frag.str == RETURN)
+ return parseReturn(src, seps);
+ else if (frag.str == IF)
+ return parseIf(src, seps);
+ else if (frag.str == DO)
+ return parseDo(src, seps);
+ else if (frag.str == WHILE)
+ return parseWhile(src, seps);
+ else if (frag.str == BREAK)
+ return parseBreak(src, seps);
+ else if (frag.str == CONTINUE)
+ return parseContinue(src, seps);
+ else if (frag.str == SWITCH)
+ return parseSwitch(src, seps);
+ else if (frag.str == NEW)
+ return parseNew(src, seps);
+ else if (frag.str == FOR)
+ return parseFor(src, seps);
dump(frag.str.str, src);
abort();
return nullptr;
@@ -406,13 +482,15 @@ class Parser {
src++;
while (1) {
skipSpace(src);
- if (*src == ')') break;
+ if (*src == ')')
+ break;
Frag arg(src);
assert(arg.type == IDENT);
src += arg.size;
Builder::appendArgumentToFunction(ret, arg.str);
skipSpace(src);
- if (*src == ')') break;
+ if (*src == ')')
+ break;
if (*src == ',') {
src++;
continue;
@@ -429,7 +507,8 @@ class Parser {
NodeRef ret = Builder::makeVar(is_const);
while (1) {
skipSpace(src);
- if (*src == ';') break;
+ if (*src == ';')
+ break;
Frag name(src);
assert(name.type == IDENT);
NodeRef value;
@@ -442,7 +521,8 @@ class Parser {
}
Builder::appendToVar(ret, name.str, value);
skipSpace(src);
- if (*src == ';') break;
+ if (*src == ';')
+ break;
if (*src == ',') {
src++;
continue;
@@ -458,7 +538,8 @@ class Parser {
NodeRef value = !hasChar(seps, *src) ? parseElement(src, seps) : nullptr;
skipSpace(src);
assert(hasChar(seps, *src));
- if (*src == ';') src++;
+ if (*src == ';')
+ src++;
return Builder::makeReturn(value);
}
@@ -516,14 +597,16 @@ class Parser {
NodeRef parseBreak(char*& src, const char* seps) {
skipSpace(src);
Frag next(src);
- if (next.type == IDENT) src += next.size;
+ if (next.type == IDENT)
+ src += next.size;
return Builder::makeBreak(next.type == IDENT ? next.str : IString());
}
NodeRef parseContinue(char*& src, const char* seps) {
skipSpace(src);
Frag next(src);
- if (next.type == IDENT) src += next.size;
+ if (next.type == IDENT)
+ src += next.size;
return Builder::makeContinue(next.type == IDENT ? next.str : IString());
}
@@ -535,7 +618,8 @@ class Parser {
while (1) {
// find all cases and possibly a default
skipSpace(src);
- if (*src == '}') break;
+ if (*src == '}')
+ break;
Frag next(src);
if (next.type == KEYWORD) {
if (next.str == CASE) {
@@ -575,12 +659,14 @@ class Parser {
src++;
continue;
}
- // otherwise, may be some keyword that happens to start a block (e.g. case 1: _return_ 5)
+ // otherwise, may be some keyword that happens to start a block (e.g.
+ // case 1: _return_ 5)
}
// not case X: or default: or }, so must be some code
skipSpace(src);
bool explicitBlock = *src == '{';
- NodeRef subBlock = explicitBlock ? parseBracketedBlock(src) : parseBlock(src, ";}", CASE, DEFAULT);
+ NodeRef subBlock = explicitBlock ? parseBracketedBlock(src)
+ : parseBlock(src, ";}", CASE, DEFAULT);
Builder::appendCodeToSwitch(ret, subBlock, explicitBlock);
}
skipSpace(src);
@@ -595,34 +681,40 @@ class Parser {
NodeRef parseAfterIdent(Frag& frag, char*& src, const char* seps) {
skipSpace(src);
- if (*src == '(') return parseExpression(parseCall(parseFrag(frag), src), src, seps);
- if (*src == '[') return parseExpression(parseIndexing(parseFrag(frag), src), src, seps);
+ if (*src == '(')
+ return parseExpression(parseCall(parseFrag(frag), src), src, seps);
+ if (*src == '[')
+ return parseExpression(parseIndexing(parseFrag(frag), src), src, seps);
if (*src == ':' && expressionPartsStack.back().size() == 0) {
src++;
skipSpace(src);
NodeRef inner;
- if (*src == '{') { // context lets us know this is not an object, but a block
+ if (*src == '{') {
+ // context lets us know this is not an object, but a block
inner = parseBracketedBlock(src);
} else {
inner = parseElement(src, seps);
}
return Builder::makeLabel(frag.str, inner);
}
- if (*src == '.') return parseExpression(parseDotting(parseFrag(frag), src), src, seps);
+ if (*src == '.')
+ return parseExpression(parseDotting(parseFrag(frag), src), src, seps);
return parseExpression(parseFrag(frag), src, seps);
}
NodeRef parseCall(NodeRef target, char*& src) {
- expressionPartsStack.resize(expressionPartsStack.size()+1);
+ expressionPartsStack.resize(expressionPartsStack.size() + 1);
assert(*src == '(');
src++;
NodeRef ret = Builder::makeCall(target);
while (1) {
skipSpace(src);
- if (*src == ')') break;
+ if (*src == ')')
+ break;
Builder::appendToCall(ret, parseElement(src, ",)"));
skipSpace(src);
- if (*src == ')') break;
+ if (*src == ')')
+ break;
if (*src == ',') {
src++;
continue;
@@ -636,7 +728,7 @@ class Parser {
}
NodeRef parseIndexing(NodeRef target, char*& src) {
- expressionPartsStack.resize(expressionPartsStack.size()+1);
+ expressionPartsStack.resize(expressionPartsStack.size() + 1);
assert(*src == '[');
src++;
NodeRef ret = Builder::makeIndexing(target, parseElement(src, "]"));
@@ -658,7 +750,7 @@ class Parser {
}
NodeRef parseAfterParen(char*& src) {
- expressionPartsStack.resize(expressionPartsStack.size()+1);
+ expressionPartsStack.resize(expressionPartsStack.size() + 1);
skipSpace(src);
NodeRef ret = parseElement(src, ")");
skipSpace(src);
@@ -670,16 +762,18 @@ class Parser {
}
NodeRef parseAfterBrace(char*& src) {
- expressionPartsStack.resize(expressionPartsStack.size()+1);
+ expressionPartsStack.resize(expressionPartsStack.size() + 1);
NodeRef ret = Builder::makeArray();
while (1) {
skipSpace(src);
assert(*src);
- if (*src == ']') break;
+ if (*src == ']')
+ break;
NodeRef element = parseElement(src, ",]");
Builder::appendToArray(ret, element);
skipSpace(src);
- if (*src == ']') break;
+ if (*src == ']')
+ break;
if (*src == ',') {
src++;
continue;
@@ -691,12 +785,13 @@ class Parser {
}
NodeRef parseAfterCurly(char*& src) {
- expressionPartsStack.resize(expressionPartsStack.size()+1);
+ expressionPartsStack.resize(expressionPartsStack.size() + 1);
NodeRef ret = Builder::makeObject();
while (1) {
skipSpace(src);
assert(*src);
- if (*src == '}') break;
+ if (*src == '}')
+ break;
Frag key(src);
assert(key.type == IDENT || key.type == STRING);
src += key.size;
@@ -706,7 +801,8 @@ class Parser {
NodeRef value = parseElement(src, ",}");
Builder::appendToObject(ret, key.str, value);
skipSpace(src);
- if (*src == '}') break;
+ if (*src == '}')
+ break;
if (*src == ',') {
src++;
continue;
@@ -735,12 +831,13 @@ class Parser {
if (op == PERIOD) {
return Builder::makeDot(left, right);
} else {
- return Builder::makeBinary(left, op ,right);
+ return Builder::makeBinary(left, op, right);
}
}
- NodeRef parseExpression(ExpressionElement initial, char*&src, const char* seps) {
- //dump("parseExpression", src);
+ NodeRef
+ parseExpression(ExpressionElement initial, char*& src, const char* seps) {
+ // dump("parseExpression", src);
ExpressionParts& parts = expressionPartsStack.back();
skipSpace(src);
if (*src == 0 || hasChar(seps, *src)) {
@@ -771,55 +868,77 @@ class Parser {
parts.push_back(initial);
}
NodeRef last = parseElement(src, seps);
- if (!top) return last;
+ if (!top)
+ return last;
{
- ExpressionParts& parts = expressionPartsStack.back(); // |parts| may have been invalidated by that call
+ // |parts| may have been invalidated by that call
+ ExpressionParts& parts = expressionPartsStack.back();
// we are the toplevel. sort it all out
// collapse right to left, highest priority first
- //dumpParts(parts, 0);
+ // dumpParts(parts, 0);
for (auto& ops : operatorClasses) {
if (ops.rtl) {
// right to left
- for (int i = parts.size()-1; i >= 0; i--) {
- if (parts[i].isNode) continue;
+ for (int i = parts.size() - 1; i >= 0; i--) {
+ if (parts[i].isNode)
+ continue;
IString op = parts[i].getOp();
- if (!ops.ops.has(op)) continue;
- if (ops.type == OperatorClass::Binary && i > 0 && i < (int)parts.size()-1) {
- parts[i] = makeBinary(parts[i-1].getNode(), op, parts[i+1].getNode());
+ if (!ops.ops.has(op))
+ continue;
+ if (ops.type == OperatorClass::Binary && i > 0 &&
+ i < (int)parts.size() - 1) {
+ parts[i] =
+ makeBinary(parts[i - 1].getNode(), op, parts[i + 1].getNode());
parts.erase(parts.begin() + i + 1);
parts.erase(parts.begin() + i - 1);
- } else if (ops.type == OperatorClass::Prefix && i < (int)parts.size()-1) {
- if (i > 0 && parts[i-1].isNode) continue; // cannot apply prefix operator if it would join two nodes
- parts[i] = Builder::makePrefix(op, parts[i+1].getNode());
+ } else if (ops.type == OperatorClass::Prefix &&
+ i < (int)parts.size() - 1) {
+ if (i > 0 && parts[i - 1].isNode)
+ // cannot apply prefix operator if it would join two nodes
+ continue;
+ parts[i] = Builder::makePrefix(op, parts[i + 1].getNode());
parts.erase(parts.begin() + i + 1);
} else if (ops.type == OperatorClass::Tertiary) {
// we must be at X ? Y : Z
// ^
- //dumpParts(parts, i);
- if (op != COLON) continue;
- assert(i < (int)parts.size()-1 && i >= 3);
- if (parts[i-2].getOp() != QUESTION) continue; // e.g. x ? y ? 1 : 0 : 2
- parts[i-3] = Builder::makeConditional(parts[i-3].getNode(), parts[i-1].getNode(), parts[i+1].getNode());
+ // dumpParts(parts, i);
+ if (op != COLON)
+ continue;
+ assert(i < (int)parts.size() - 1 && i >= 3);
+ if (parts[i - 2].getOp() != QUESTION)
+ continue; // e.g. x ? y ? 1 : 0 : 2
+ parts[i - 3] = Builder::makeConditional(parts[i - 3].getNode(),
+ parts[i - 1].getNode(),
+ parts[i + 1].getNode());
parts.erase(parts.begin() + i - 2, parts.begin() + i + 2);
- i = parts.size(); // basically a reset, due to things like x ? y ? 1 : 0 : 2
+ // basically a reset, due to things like x ? y ? 1 : 0 : 2
+ i = parts.size();
} // TODO: postfix
}
} else {
// left to right
for (int i = 0; i < (int)parts.size(); i++) {
- if (parts[i].isNode) continue;
+ if (parts[i].isNode)
+ continue;
IString op = parts[i].getOp();
- if (!ops.ops.has(op)) continue;
- if (ops.type == OperatorClass::Binary && i > 0 && i < (int)parts.size()-1) {
- parts[i] = makeBinary(parts[i-1].getNode(), op, parts[i+1].getNode());
+ if (!ops.ops.has(op))
+ continue;
+ if (ops.type == OperatorClass::Binary && i > 0 &&
+ i < (int)parts.size() - 1) {
+ parts[i] =
+ makeBinary(parts[i - 1].getNode(), op, parts[i + 1].getNode());
parts.erase(parts.begin() + i + 1);
parts.erase(parts.begin() + i - 1);
i--;
- } else if (ops.type == OperatorClass::Prefix && i < (int)parts.size()-1) {
- if (i > 0 && parts[i-1].isNode) continue; // cannot apply prefix operator if it would join two nodes
- parts[i] = Builder::makePrefix(op, parts[i+1].getNode());
+ } else if (ops.type == OperatorClass::Prefix &&
+ i < (int)parts.size() - 1) {
+ if (i > 0 && parts[i - 1].isNode)
+ // cannot apply prefix operator if it would join two nodes
+ continue;
+ parts[i] = Builder::makePrefix(op, parts[i + 1].getNode());
parts.erase(parts.begin() + i + 1);
- i = std::max(i-2, 0); // allow a previous prefix operator to cascade
+ // allow a previous prefix operator to cascade
+ i = std::max(i - 2, 0);
} // TODO: tertiary, postfix
}
}
@@ -831,25 +950,33 @@ class Parser {
}
}
- // Parses a block of code (e.g. a bunch of statements inside {,}, or the top level of o file)
- NodeRef parseBlock(char*& src, const char* seps=";", IString keywordSep1=IString(), IString keywordSep2=IString()) {
+ // Parses a block of code (e.g. a bunch of statements inside {,}, or the top
+ // level of o file)
+ NodeRef parseBlock(char*& src,
+ const char* seps = ";",
+ IString keywordSep1 = IString(),
+ IString keywordSep2 = IString()) {
NodeRef block = Builder::makeBlock();
- //dump("parseBlock", src);
+ // dump("parseBlock", src);
while (1) {
skipSpace(src);
- if (*src == 0) break;
+ if (*src == 0)
+ break;
if (*src == ';') {
src++; // skip a statement in this block
continue;
}
- if (hasChar(seps, *src)) break;
+ if (hasChar(seps, *src))
+ break;
if (!!keywordSep1) {
Frag next(src);
- if (next.type == KEYWORD && next.str == keywordSep1) break;
+ if (next.type == KEYWORD && next.str == keywordSep1)
+ break;
}
if (!!keywordSep2) {
Frag next(src);
- if (next.type == KEYWORD && next.str == keywordSep2) break;
+ if (next.type == KEYWORD && next.str == keywordSep2)
+ break;
}
NodeRef element = parseElementOrStatement(src, seps);
Builder::appendToBlock(block, element);
@@ -861,25 +988,29 @@ class Parser {
skipSpace(src);
assert(*src == '{');
src++;
- NodeRef block = parseBlock(src, ";}"); // the two are not symmetrical, ; is just internally separating, } is the final one - parseBlock knows all this
+ // the two are not symmetrical, ; is just internally separating, } is the
+ // final one - parseBlock knows all this
+ NodeRef block = parseBlock(src, ";}");
assert(*src == '}');
src++;
return block;
}
- NodeRef parseElementOrStatement(char*& src, const char *seps) {
+ NodeRef parseElementOrStatement(char*& src, const char* seps) {
skipSpace(src);
if (*src == ';') {
src++;
- return Builder::makeBlock(); // we don't need the brackets here, but oh well
+ // we don't need the brackets here, but oh well
+ return Builder::makeBlock();
}
if (*src == '{') { // detect a trivial {} in a statement context
- char *before = src;
+ char* before = src;
src++;
skipSpace(src);
if (*src == '}') {
src++;
- return Builder::makeBlock(); // we don't need the brackets here, but oh well
+ // we don't need the brackets here, but oh well
+ return Builder::makeBlock();
}
src = before;
}
@@ -892,9 +1023,10 @@ class Parser {
return ret;
}
- NodeRef parseMaybeBracketed(char*& src, const char *seps) {
+ NodeRef parseMaybeBracketed(char*& src, const char* seps) {
skipSpace(src);
- return *src == '{' ? parseBracketedBlock(src) : parseElementOrStatement(src, seps);
+ return *src == '{' ? parseBracketedBlock(src)
+ : parseElementOrStatement(src, seps);
}
NodeRef parseParenned(char*& src) {
@@ -910,13 +1042,15 @@ class Parser {
// Debugging
- char *allSource = nullptr;
+ char* allSource = nullptr;
int allSize = 0;
- static void dump(const char *where, char* curr) {
+ static void dump(const char* where, char* curr) {
/*
printf("%s:\n=============\n", where);
- for (int i = 0; i < allSize; i++) printf("%c", allSource[i] ? allSource[i] : '?');
+ for (int i = 0; i < allSize; i++)
+ printf("%c", allSource[i] ? allSource[i] :
+ '?');
printf("\n");
for (int i = 0; i < (curr - allSource); i++) printf(" ");
printf("^\n=============\n");
@@ -927,20 +1061,19 @@ class Parser {
while (*curr) {
if (*curr == '\n') {
newlinesLeft--;
- if (newlinesLeft == 0) break;
+ if (newlinesLeft == 0)
+ break;
}
charsLeft--;
- if (charsLeft == 0) break;
+ if (charsLeft == 0)
+ break;
fprintf(stderr, "%c", *curr++);
}
fprintf(stderr, "\n\n");
}
public:
-
- Parser() {
- expressionPartsStack.resize(1);
- }
+ Parser() { expressionPartsStack.resize(1); }
// Highest-level parsing, as of a JavaScript script file.
NodeRef parseToplevel(char* src) {
diff --git a/src/emscripten-optimizer/simple_ast.cpp b/src/emscripten-optimizer/simple_ast.cpp
index 7575cc6f7..5853b3289 100644
--- a/src/emscripten-optimizer/simple_ast.cpp
+++ b/src/emscripten-optimizer/simple_ast.cpp
@@ -20,37 +20,29 @@ namespace cashew {
// Ref methods
-Ref& Ref::operator[](unsigned x) {
- return (*get())[x];
-}
+Ref& Ref::operator[](unsigned x) { return (*get())[x]; }
-Ref& Ref::operator[](IString x) {
- return (*get())[x];
-}
+Ref& Ref::operator[](IString x) { return (*get())[x]; }
-bool Ref::operator==(const char *str) {
+bool Ref::operator==(const char* str) {
return get()->isString() && !strcmp(get()->str.str, str);
}
-bool Ref::operator!=(const char *str) {
+bool Ref::operator!=(const char* str) {
return get()->isString() ? !!strcmp(get()->str.str, str) : true;
}
-bool Ref::operator==(const IString &str) {
+bool Ref::operator==(const IString& str) {
return get()->isString() && get()->str == str;
}
-bool Ref::operator!=(const IString &str) {
+bool Ref::operator!=(const IString& str) {
return get()->isString() && get()->str != str;
}
-bool Ref::operator==(Ref other) {
- return **this == *other;
-}
+bool Ref::operator==(Ref other) { return **this == *other; }
-bool Ref::operator!() {
- return !get() || get()->isNull();
-}
+bool Ref::operator!() { return !get() || get()->isNull(); }
// Arena
@@ -80,9 +72,13 @@ AssignName* Value::asAssignName() {
return static_cast<AssignName*>(this);
}
-void Value::stringify(std::ostream &os, bool pretty) {
+void Value::stringify(std::ostream& os, bool pretty) {
static int indent = 0;
- #define indentify() { for (int i_ = 0; i_ < indent; i_++) os << " "; }
+#define indentify() \
+ { \
+ for (int i_ = 0; i_ < indent; i_++) \
+ os << " "; \
+ }
switch (type) {
case String: {
if (str.str) {
@@ -93,7 +89,8 @@ void Value::stringify(std::ostream &os, bool pretty) {
break;
}
case Number: {
- os << std::setprecision(17) << num; // doubles can have 17 digits of precision
+ // doubles can have 17 digits of precision
+ os << std::setprecision(17) << num;
break;
}
case Array: {
@@ -108,8 +105,10 @@ void Value::stringify(std::ostream &os, bool pretty) {
}
for (size_t i = 0; i < arr->size(); i++) {
if (i > 0) {
- if (pretty) os << "," << std::endl;
- else os << ", ";
+ if (pretty)
+ os << "," << std::endl;
+ else
+ os << ", ";
}
indentify();
(*arr)[i]->stringify(os, pretty);
@@ -142,7 +141,8 @@ void Value::stringify(std::ostream &os, bool pretty) {
first = false;
} else {
os << ", ";
- if (pretty) os << std::endl;
+ if (pretty)
+ os << std::endl;
}
indentify();
os << '"' << i.first.c_str() << "\": ";
@@ -176,10 +176,12 @@ void Value::stringify(std::ostream &os, bool pretty) {
// dump
-void dump(const char *str, Ref node, bool pretty) {
+void dump(const char* str, Ref node, bool pretty) {
std::cerr << str << ": ";
- if (!!node) node->stringify(std::cerr, pretty);
- else std::cerr << "(nullptr)";
+ if (!!node)
+ node->stringify(std::cerr, pretty);
+ else
+ std::cerr << "(nullptr)";
std::cerr << std::endl;
}
diff --git a/src/emscripten-optimizer/simple_ast.h b/src/emscripten-optimizer/simple_ast.h
index 81d20e612..e4f2c1f86 100644
--- a/src/emscripten-optimizer/simple_ast.h
+++ b/src/emscripten-optimizer/simple_ast.h
@@ -33,10 +33,10 @@
#include <unordered_set>
#include <vector>
+#include "mixed_arena.h"
#include "parser.h"
#include "snprintf.h"
#include "support/safe_integer.h"
-#include "mixed_arena.h"
#define err(str) fprintf(stderr, str "\n");
#define errv(str, ...) fprintf(stderr, str "\n", __VA_ARGS__);
@@ -47,13 +47,13 @@ namespace cashew {
struct Value;
struct Ref;
-void dump(const char *str, Ref node, bool pretty=false);
+void dump(const char* str, Ref node, bool pretty = false);
// Reference to a value, plus some operators for convenience
struct Ref {
Value* inst;
- Ref(Value *v=nullptr) : inst(v) {}
+ Ref(Value* v = nullptr) : inst(v) {}
Value* get() { return inst; }
@@ -63,11 +63,16 @@ struct Ref {
Ref& operator[](IString x);
// special conveniences
- bool operator==(const char *str); // comparison to string, which is by value
- bool operator!=(const char *str);
- bool operator==(const IString &str);
- bool operator!=(const IString &str);
- bool operator==(double d) { abort(); return false; } // prevent Ref == number, which is potentially ambiguous; use ->getNumber() == number
+ bool operator==(const char* str); // comparison to string, which is by value
+ bool operator!=(const char* str);
+ bool operator==(const IString& str);
+ bool operator!=(const IString& str);
+ // prevent Ref == number, which is potentially ambiguous; use ->getNumber() ==
+ // number
+ bool operator==(double d) {
+ abort();
+ return false;
+ }
bool operator==(Ref other);
bool operator!(); // check if null, in effect
};
@@ -78,8 +83,7 @@ struct Ref {
// receive an allocator, they all use the global one anyhow
class GlobalMixedArena : public MixedArena {
public:
- template<class T>
- T* alloc() {
+ template<class T> T* alloc() {
auto* ret = static_cast<T*>(allocSpace(sizeof(T), alignof(T)));
new (ret) T();
return ret;
@@ -92,7 +96,8 @@ class ArrayStorage : public ArenaVectorBase<ArrayStorage, Ref> {
public:
void allocate(size_t size) {
allocatedElements = size;
- data = static_cast<Ref*>(arena.allocSpace(sizeof(Ref) * allocatedElements, alignof(Ref)));
+ data = static_cast<Ref*>(
+ arena.allocSpace(sizeof(Ref) * allocatedElements, alignof(Ref)));
}
};
@@ -116,7 +121,9 @@ struct Value {
typedef std::unordered_map<IString, Ref> ObjectStorage;
-#ifdef _MSC_VER // MSVC does not allow unrestricted unions: http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2544.pdf
+ // MSVC does not allow unrestricted unions:
+ // http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2544.pdf
+#ifdef _MSC_VER
IString str;
#endif
union { // TODO: optimize
@@ -124,44 +131,41 @@ struct Value {
IString str;
#endif
double num;
- ArrayStorage *arr;
+ ArrayStorage* arr;
bool boo;
- ObjectStorage *obj;
+ ObjectStorage* obj;
Ref ref;
};
// constructors all copy their input
Value() {}
- explicit Value(const char *s) {
- setString(s);
- }
- explicit Value(double n) {
- setNumber(n);
- }
- explicit Value(ArrayStorage &a) {
+ explicit Value(const char* s) { setString(s); }
+ explicit Value(double n) { setNumber(n); }
+ explicit Value(ArrayStorage& a) {
setArray();
*arr = a;
}
- // no bool constructor - would endanger the double one (int might convert the wrong way)
+ // no bool constructor - would endanger the double one (int might convert the
+ // wrong way)
- ~Value() {
- free();
- }
+ ~Value() { free(); }
void free() {
- if (type == Array) { arr->clear(); }
- else if (type == Object) delete obj;
+ if (type == Array) {
+ arr->clear();
+ } else if (type == Object)
+ delete obj;
type = Null;
num = 0;
}
- Value& setString(const char *s) {
+ Value& setString(const char* s) {
free();
type = String;
str.set(s);
return *this;
}
- Value& setString(const IString &s) {
+ Value& setString(const IString& s) {
free();
type = String;
str.set(s);
@@ -173,14 +177,14 @@ struct Value {
num = n;
return *this;
}
- Value& setArray(ArrayStorage &a) {
+ Value& setArray(ArrayStorage& a) {
free();
type = Array;
arr = arena.alloc<ArrayStorage>();
*arr = a;
return *this;
}
- Value& setArray(size_t size_hint=0) {
+ Value& setArray(size_t size_hint = 0) {
free();
type = Array;
arr = arena.alloc<ArrayStorage>();
@@ -192,7 +196,8 @@ struct Value {
type = Null;
return *this;
}
- Value& setBool(bool b) { // Bool in the name, as otherwise might overload over int
+ // Bool in the name, as otherwise might overload over int
+ Value& setBool(bool b) {
free();
type = Bool;
boo = b;
@@ -209,22 +214,21 @@ struct Value {
bool isString() { return type == String; }
bool isNumber() { return type == Number; }
- bool isArray() { return type == Array; }
- bool isNull() { return type == Null; }
- bool isBool() { return type == Bool; }
+ bool isArray() { return type == Array; }
+ bool isNull() { return type == Null; }
+ bool isBool() { return type == Bool; }
bool isObject() { return type == Object; }
bool isAssign() { return type == Assign_; }
bool isAssignName() { return type == AssignName_; }
- bool isBool(bool b) { return type == Bool && b == boo; } // avoid overloading == as it might overload over int
+ // avoid overloading == as it might overload over int
+ bool isBool(bool b) { return type == Bool && b == boo; }
// convenience function to check if something is an array and
// also has a certain string as the first element. This is a
// very common operation as the first element defines the node
// type for most ast nodes
- bool isArray(IString name) {
- return isArray() && (*this)[0] == name;
- }
+ bool isArray(IString name) { return isArray() && (*this)[0] == name; }
const char* getCString() {
assert(isString());
@@ -282,7 +286,8 @@ struct Value {
}
bool operator==(const Value& other) {
- if (type != other.type) return false;
+ if (type != other.type)
+ return false;
switch (other.type) {
case String:
return str == other.str;
@@ -303,17 +308,22 @@ struct Value {
}
char* parse(char* curr) {
- #define is_json_space(x) (x == 32 || x == 9 || x == 10 || x == 13) /* space, tab, linefeed/newline, or return */
- #define skip() { while (*curr && is_json_space(*curr)) curr++; }
+ /* space, tab, linefeed/newline, or return */
+#define is_json_space(x) (x == 32 || x == 9 || x == 10 || x == 13)
+#define skip() \
+ { \
+ while (*curr && is_json_space(*curr)) \
+ curr++; \
+ }
skip();
if (*curr == '"') {
// String
curr++;
- char *close = strchr(curr, '"');
+ char* close = strchr(curr, '"');
assert(close);
*close = 0; // end this string, and reuse it straight from the input
setString(curr);
- curr = close+1;
+ curr = close + 1;
} else if (*curr == '[') {
// Array
curr++;
@@ -324,7 +334,8 @@ struct Value {
arr->push_back(temp);
curr = temp->parse(curr);
skip();
- if (*curr == ']') break;
+ if (*curr == ']')
+ break;
assert(*curr == ',');
curr++;
skip();
@@ -353,11 +364,11 @@ struct Value {
while (*curr != '}') {
assert(*curr == '"');
curr++;
- char *close = strchr(curr, '"');
+ char* close = strchr(curr, '"');
assert(close);
*close = 0; // end this string, and reuse it straight from the input
IString key(curr);
- curr = close+1;
+ curr = close + 1;
skip();
assert(*curr == ':');
curr++;
@@ -366,7 +377,8 @@ struct Value {
curr = value->parse(curr);
(*obj)[key] = value;
skip();
- if (*curr == '}') break;
+ if (*curr == '}')
+ break;
assert(*curr == ',');
curr++;
skip();
@@ -374,14 +386,14 @@ struct Value {
curr++;
} else {
// Number
- char *after;
+ char* after;
setNumber(strtod(curr, &after));
curr = after;
}
return curr;
}
- void stringify(std::ostream &os, bool pretty=false);
+ void stringify(std::ostream& os, bool pretty = false);
// String operations
@@ -394,14 +406,13 @@ struct Value {
return arr->size();
}
- bool empty() {
- return size() == 0;
- }
+ bool empty() { return size() == 0; }
void setSize(size_t size) {
assert(isArray());
auto old = arr->size();
- if (old != size) arr->resize(size);
+ if (old != size)
+ arr->resize(size);
if (old < size) {
for (auto i = old; i < size; i++) {
(*arr)[i] = arena.alloc<Value>();
@@ -428,7 +439,8 @@ struct Value {
Ref back() {
assert(isArray());
- if (arr->size() == 0) return nullptr;
+ if (arr->size() == 0)
+ return nullptr;
return arr->back();
}
@@ -440,12 +452,13 @@ struct Value {
int indexOf(Ref other) {
assert(isArray());
for (size_t i = 0; i < arr->size(); i++) {
- if (other == (*arr)[i]) return i;
+ if (other == (*arr)[i])
+ return i;
}
return -1;
}
- Ref map(std::function<Ref (Ref node)> func) {
+ Ref map(std::function<Ref(Ref node)> func) {
assert(isArray());
Ref ret = arena.alloc<Value>();
ret->setArray();
@@ -455,13 +468,14 @@ struct Value {
return ret;
}
- Ref filter(std::function<bool (Ref node)> func) {
+ Ref filter(std::function<bool(Ref node)> func) {
assert(isArray());
Ref ret = arena.alloc<Value>();
ret->setArray();
for (size_t i = 0; i < arr->size(); i++) {
Ref curr = (*arr)[i];
- if (func(curr)) ret->push_back(curr);
+ if (func(curr))
+ ret->push_back(curr);
}
return ret;
}
@@ -502,12 +516,8 @@ struct Assign : public Value {
Assign() : Assign(nullptr, nullptr) {}
- Ref& target() {
- return ref;
- }
- Ref& value() {
- return value_;
- }
+ Ref& target() { return ref; }
+ Ref& value() { return value_; }
};
struct AssignName : public Value {
@@ -521,12 +531,8 @@ struct AssignName : public Value {
AssignName() : AssignName(IString(), nullptr) {}
- IString& target() {
- return target_;
- }
- Ref& value() {
- return ref;
- }
+ IString& target() { return target_; }
+ Ref& value() { return ref; }
};
// JS printing support
@@ -534,7 +540,7 @@ struct AssignName : public Value {
struct JSPrinter {
bool pretty, finalize;
- char *buffer = nullptr;
+ char* buffer = nullptr;
size_t size = 0;
size_t used = 0;
@@ -543,11 +549,10 @@ struct JSPrinter {
Ref ast;
- JSPrinter(bool pretty_, bool finalize_, Ref ast_) : pretty(pretty_), finalize(finalize_), ast(ast_) {}
+ JSPrinter(bool pretty_, bool finalize_, Ref ast_)
+ : pretty(pretty_), finalize(finalize_), ast(ast_) {}
- ~JSPrinter() {
- free(buffer);
- }
+ ~JSPrinter() { free(buffer); }
void printAst() {
print(ast);
@@ -557,7 +562,7 @@ struct JSPrinter {
// Utils
- void ensure(int safety=100) {
+ void ensure(int safety = 100) {
if (size >= used + safety) {
return;
}
@@ -569,7 +574,7 @@ struct JSPrinter {
abort();
}
} else {
- char *buf = (char*)realloc(buffer, size);
+ char* buf = (char*)realloc(buffer, size);
if (!buf) {
free(buffer);
errv("Out of memory allocating %zd bytes for output buffer!", size);
@@ -581,38 +586,45 @@ struct JSPrinter {
void emit(char c) {
maybeSpace(c);
- if (!pretty && c == '}' && buffer[used-1] == ';') used--; // optimize ;} into }, the ; is not separating anything
+ if (!pretty && c == '}' && buffer[used - 1] == ';')
+ used--; // optimize ;} into }, the ; is not separating anything
ensure(1);
buffer[used++] = c;
}
- void emit(const char *s) {
+ void emit(const char* s) {
maybeSpace(*s);
int len = strlen(s);
- ensure(len+1);
- strncpy(buffer + used, s, len+1);
+ ensure(len + 1);
+ strncpy(buffer + used, s, len + 1);
used += len;
}
void newline() {
- if (!pretty) return;
+ if (!pretty)
+ return;
emit('\n');
- for (int i = 0; i < indent; i++) emit(' ');
+ for (int i = 0; i < indent; i++)
+ emit(' ');
}
void space() {
- if (pretty) emit(' ');
+ if (pretty)
+ emit(' ');
}
void safeSpace() {
- if (pretty) emit(' ');
- else possibleSpace = true;
+ if (pretty)
+ emit(' ');
+ else
+ possibleSpace = true;
}
void maybeSpace(char s) {
if (possibleSpace) {
possibleSpace = false;
- if (isIdentPart(s)) emit(' ');
+ if (isIdentPart(s))
+ emit(' ');
}
}
@@ -620,22 +632,22 @@ struct JSPrinter {
return node->isArray() && node[0] == TOPLEVEL && node[1]->size() == 0;
}
- bool isDefun(Ref node) {
- return node->isArray() && node[0] == DEFUN;
- }
+ bool isDefun(Ref node) { return node->isArray() && node[0] == DEFUN; }
bool endsInBlock(Ref node) {
- if (node->isArray() && node[0] == BLOCK) return true;
+ if (node->isArray() && node[0] == BLOCK)
+ return true;
// Check for a label on a block
- if (node->isArray() && node[0] == LABEL && endsInBlock(node[2])) return true;
+ if (node->isArray() && node[0] == LABEL && endsInBlock(node[2]))
+ return true;
// Check for an if
- if (node->isArray() && node[0] == IF && endsInBlock(ifHasElse(node) ? node[3] : node[2])) return true;
+ if (node->isArray() && node[0] == IF &&
+ endsInBlock(ifHasElse(node) ? node[3] : node[2]))
+ return true;
return false;
}
- bool isIf(Ref node) {
- return node->isArray() && node[0] == IF;
- }
+ bool isIf(Ref node) { return node->isArray() && node[0] == IF; }
void print(Ref node) {
ensure();
@@ -658,82 +670,119 @@ struct JSPrinter {
IString type = node[0]->getIString();
switch (type.str[0]) {
case 'a': {
- if (type == ARRAY) printArray(node);
- else abort();
+ if (type == ARRAY)
+ printArray(node);
+ else
+ abort();
break;
}
case 'b': {
- if (type == BINARY) printBinary(node);
- else if (type == BLOCK) printBlock(node);
- else if (type == BREAK) printBreak(node);
- else abort();
+ if (type == BINARY)
+ printBinary(node);
+ else if (type == BLOCK)
+ printBlock(node);
+ else if (type == BREAK)
+ printBreak(node);
+ else
+ abort();
break;
}
case 'c': {
- if (type == CALL) printCall(node);
- else if (type == CONDITIONAL) printConditional(node);
- else if (type == CONTINUE) printContinue(node);
- else abort();
+ if (type == CALL)
+ printCall(node);
+ else if (type == CONDITIONAL)
+ printConditional(node);
+ else if (type == CONTINUE)
+ printContinue(node);
+ else
+ abort();
break;
}
case 'd': {
- if (type == DEFUN) printDefun(node);
- else if (type == DO) printDo(node);
- else if (type == DOT) printDot(node);
- else abort();
+ if (type == DEFUN)
+ printDefun(node);
+ else if (type == DO)
+ printDo(node);
+ else if (type == DOT)
+ printDot(node);
+ else
+ abort();
break;
}
case 'i': {
- if (type == IF) printIf(node);
- else abort();
+ if (type == IF)
+ printIf(node);
+ else
+ abort();
break;
}
case 'l': {
- if (type == LABEL) printLabel(node);
- else abort();
+ if (type == LABEL)
+ printLabel(node);
+ else
+ abort();
break;
}
case 'n': {
- if (type == NEW) printNew(node);
- else abort();
+ if (type == NEW)
+ printNew(node);
+ else
+ abort();
break;
}
case 'o': {
- if (type == OBJECT) printObject(node);
+ if (type == OBJECT)
+ printObject(node);
break;
}
case 'r': {
- if (type == RETURN) printReturn(node);
- else abort();
+ if (type == RETURN)
+ printReturn(node);
+ else
+ abort();
break;
}
case 's': {
- if (type == SUB) printSub(node);
- else if (type == SEQ) printSeq(node);
- else if (type == SWITCH) printSwitch(node);
- else if (type == STRING) printString(node);
- else abort();
+ if (type == SUB)
+ printSub(node);
+ else if (type == SEQ)
+ printSeq(node);
+ else if (type == SWITCH)
+ printSwitch(node);
+ else if (type == STRING)
+ printString(node);
+ else
+ abort();
break;
}
case 't': {
- if (type == TOPLEVEL) printToplevel(node);
- else if (type == TRY) printTry(node);
- else abort();
+ if (type == TOPLEVEL)
+ printToplevel(node);
+ else if (type == TRY)
+ printTry(node);
+ else
+ abort();
break;
}
case 'u': {
- if (type == UNARY_PREFIX) printUnaryPrefix(node);
- else abort();
+ if (type == UNARY_PREFIX)
+ printUnaryPrefix(node);
+ else
+ abort();
break;
}
case 'v': {
- if (type == VAR) printVar(node);
- else abort();
+ if (type == VAR)
+ printVar(node);
+ else
+ abort();
break;
}
case 'w': {
- if (type == WHILE) printWhile(node);
- else abort();
+ if (type == WHILE)
+ printWhile(node);
+ else
+ abort();
break;
}
default: {
@@ -744,10 +793,11 @@ struct JSPrinter {
}
// print a node, and if nothing is emitted, emit something instead
- void print(Ref node, const char *otherwise) {
+ void print(Ref node, const char* otherwise) {
auto last = used;
print(node);
- if (used == last) emit(otherwise);
+ if (used == last)
+ emit(otherwise);
}
void printStats(Ref stats) {
@@ -755,8 +805,10 @@ struct JSPrinter {
for (size_t i = 0; i < stats->size(); i++) {
Ref curr = stats[i];
if (!isNothing(curr)) {
- if (first) first = false;
- else newline();
+ if (first)
+ first = false;
+ else
+ newline();
print(curr);
if (!isDefun(curr) && !endsInBlock(curr) && !isIf(curr)) {
emit(';');
@@ -791,7 +843,8 @@ struct JSPrinter {
emit('(');
Ref args = node[2];
for (size_t i = 0; i < args->size(); i++) {
- if (i > 0) (pretty ? emit(", ") : emit(','));
+ if (i > 0)
+ (pretty ? emit(", ") : emit(','));
emit(args[i]->getCString());
}
emit(')');
@@ -820,7 +873,7 @@ struct JSPrinter {
}
void printAssignName(Ref node) {
- auto *assign = node->asAssignName();
+ auto* assign = node->asAssignName();
emit(assign->target().c_str());
space();
emit('=');
@@ -828,11 +881,9 @@ struct JSPrinter {
printChild(assign->value(), node, 1);
}
- void printName(Ref node) {
- emit(node->getCString());
- }
+ void printName(Ref node) { emit(node->getCString()); }
- static char* numToString(double d, bool finalize=true) {
+ static char* numToString(double d, bool finalize = true) {
// If this number is NaN or infinite then things are a bit tricky. In JS we
// want to eventually use `NaN` and/or `Infinity`, but neither of those
// identifiers are valid in asm.js. Instead we have to explicitly import
@@ -843,28 +894,32 @@ struct JSPrinter {
// asm.js code isn't generated any more
if (std::isnan(d)) {
if (std::signbit(d)) {
- return (char*) "-nan";
+ return (char*)"-nan";
} else {
- return (char*) "nan";
+ return (char*)"nan";
}
} else if (!std::isfinite(d)) {
if (std::signbit(d)) {
- return (char*) "-infinity";
+ return (char*)"-infinity";
} else {
- return (char*) "infinity";
+ return (char*)"infinity";
}
}
bool neg = d < 0;
- if (neg) d = -d;
+ if (neg)
+ d = -d;
// try to emit the fewest necessary characters
bool integer = fmod(d, 1) == 0;
- #define BUFFERSIZE 1000
- static char full_storage_f[BUFFERSIZE], full_storage_e[BUFFERSIZE]; // f is normal, e is scientific for float, x for integer
- static char *storage_f = full_storage_f + 1, *storage_e = full_storage_e + 1; // full has one more char, for a possible '-'
+#define BUFFERSIZE 1000
+ // f is normal, e is scientific for float, x for integer
+ static char full_storage_f[BUFFERSIZE], full_storage_e[BUFFERSIZE];
+ // full has one more char, for a possible '-'
+ static char *storage_f = full_storage_f + 1,
+ *storage_e = full_storage_e + 1;
auto err_f = std::numeric_limits<double>::quiet_NaN();
auto err_e = std::numeric_limits<double>::quiet_NaN();
for (int e = 0; e <= 1; e++) {
- char *buffer = e ? storage_e : storage_f;
+ char* buffer = e ? storage_e : storage_f;
double temp;
if (!integer) {
static char format[6];
@@ -881,10 +936,12 @@ struct JSPrinter {
format[4] = e ? 'e' : 'f';
format[5] = 0;
}
- snprintf(buffer, BUFFERSIZE-1, format, d);
+ snprintf(buffer, BUFFERSIZE - 1, format, d);
sscanf(buffer, "%lf", &temp);
- //errv("%.18f, %.18e => %s => %.18f, %.18e (%d), ", d, d, buffer, temp, temp, temp == d);
- if (temp == d) break;
+ // errv("%.18f, %.18e => %s => %.18f, %.18e (%d), ", d, d,
+ // buffer, temp, temp, temp == d);
+ if (temp == d)
+ break;
}
} else {
// integer
@@ -892,7 +949,7 @@ struct JSPrinter {
if (wasm::isUInteger64(d)) {
unsigned long long uu = wasm::toUInteger64(d);
bool asHex = e && !finalize;
- snprintf(buffer, BUFFERSIZE-1, asHex ? "0x%llx" : "%llu", uu);
+ snprintf(buffer, BUFFERSIZE - 1, asHex ? "0x%llx" : "%llu", uu);
if (asHex) {
unsigned long long tempULL;
sscanf(buffer, "%llx", &tempULL);
@@ -902,43 +959,48 @@ struct JSPrinter {
}
} else {
// too large for a machine integer, just use floats
- snprintf(buffer, BUFFERSIZE-1, e ? "%e" : "%.0f", d); // even on integers, e with a dot is useful, e.g. 1.2e+200
+ // even on integers, e with a dot is useful, e.g. 1.2e+200
+ snprintf(buffer, BUFFERSIZE - 1, e ? "%e" : "%.0f", d);
sscanf(buffer, "%lf", &temp);
}
- //errv("%.18f, %.18e => %s => %.18f, %.18e, %llu (%d)\n", d, d, buffer, temp, temp, uu, temp == d);
+ // errv("%.18f, %.18e => %s => %.18f, %.18e, %llu (%d)\n", d,
+ // d, buffer, temp, temp, uu, temp == d);
}
(e ? err_e : err_f) = fabs(temp - d);
- //errv("current attempt: %.18f => %s", d, buffer);
- //assert(temp == d);
- char *dot = strchr(buffer, '.');
+ // errv("current attempt: %.18f => %s", d, buffer);
+ // assert(temp == d);
+ char* dot = strchr(buffer, '.');
if (dot) {
// remove trailing zeros
- char *end = dot+1;
- while (*end >= '0' && *end <= '9') end++;
+ char* end = dot + 1;
+ while (*end >= '0' && *end <= '9')
+ end++;
end--;
while (*end == '0') {
- char *copy = end;
+ char* copy = end;
do {
copy[0] = copy[1];
} while (*copy++ != 0);
end--;
}
- //errv("%.18f => %s", d, buffer);
+ // errv("%.18f => %s", d, buffer);
// remove preceding zeros
while (*buffer == '0') {
- char *copy = buffer;
+ char* copy = buffer;
do {
copy[0] = copy[1];
} while (*copy++ != 0);
}
- //errv("%.18f ===> %s", d, buffer);
+ // errv("%.18f ===> %s", d, buffer);
} else if (!integer || !e) {
// no dot. try to change 12345000 => 12345e3
- char *end = strchr(buffer, 0);
+ char* end = strchr(buffer, 0);
end--;
- char *test = end;
- // remove zeros, and also doubles can use at most 24 digits, we can truncate any extras even if not zero
- while ((*test == '0' || test - buffer > 24) && test > buffer) test--;
+ char* test = end;
+ // remove zeros, and also doubles can use at most 24 digits, we can
+ // truncate any extras even if not zero
+ while ((*test == '0' || test - buffer > 24) && test > buffer)
+ test--;
int num = end - test;
if (num >= 3) {
test++;
@@ -959,10 +1021,11 @@ struct JSPrinter {
}
}
}
- //errv("..current attempt: %.18f => %s", d, buffer);
+ // errv("..current attempt: %.18f => %s", d, buffer);
}
- //fprintf(stderr, "options:\n%s\n%s\n (first? %d)\n", storage_e, storage_f, strlen(storage_e) < strlen(storage_f));
- char *ret;
+ // fprintf(stderr, "options:\n%s\n%s\n (first? %d)\n", storage_e, storage_f,
+ // strlen(storage_e) < strlen(storage_f));
+ char* ret;
if (err_e == err_f) {
ret = strlen(storage_e) < strlen(storage_f) ? storage_e : storage_f;
} else {
@@ -976,7 +1039,7 @@ struct JSPrinter {
}
void printNum(Ref node) {
- if (node->getNumber() < 0 && buffer[used-1] == '-') {
+ if (node->getNumber() < 0 && buffer[used - 1] == '-') {
emit(' '); // cannot join - and - to --, looks like the -- operator
}
emit(numToString(node->getNumber(), finalize));
@@ -1005,28 +1068,37 @@ struct JSPrinter {
}
Ref type = node[0];
if (type == BINARY || type == UNARY_PREFIX) {
- return OperatorClass::getPrecedence(type == BINARY ? OperatorClass::Binary : OperatorClass::Prefix, node[1]->getIString());
+ return OperatorClass::getPrecedence(
+ type == BINARY ? OperatorClass::Binary : OperatorClass::Prefix,
+ node[1]->getIString());
} else if (type == SEQ) {
return OperatorClass::getPrecedence(OperatorClass::Binary, COMMA);
} else if (type == CALL) {
- return parent ? OperatorClass::getPrecedence(OperatorClass::Binary, COMMA) : -1; // call arguments are split by commas, but call itself is safe
+ // call arguments are split by commas, but call itself is safe
+ return parent ? OperatorClass::getPrecedence(OperatorClass::Binary, COMMA)
+ : -1;
} else if (type == CONDITIONAL) {
return OperatorClass::getPrecedence(OperatorClass::Tertiary, QUESTION);
}
- // otherwise, this is something that fixes precedence explicitly, and we can ignore
+ // otherwise, this is something that fixes precedence explicitly, and we can
+ // ignore
return -1; // XXX
}
// check whether we need parens for the child, when rendered in the parent
- // @param childPosition -1 means it is printed to the left of parent, 0 means "anywhere", 1 means right
+ // @param childPosition -1 means it is printed to the left of parent, 0 means
+ // "anywhere", 1 means right
bool needParens(Ref parent, Ref child, int childPosition) {
int parentPrecedence = getPrecedence(parent, true);
int childPrecedence = getPrecedence(child, false);
- if (childPrecedence > parentPrecedence) return true; // child is definitely a danger
- if (childPrecedence < parentPrecedence) return false; // definitely cool
+ if (childPrecedence > parentPrecedence)
+ return true; // child is definitely a danger
+ if (childPrecedence < parentPrecedence)
+ return false; // definitely cool
// equal precedence, so associativity (rtl/ltr) is what matters
- // (except for some exceptions, where multiple operators can combine into confusion)
+ // (except for some exceptions, where multiple operators can combine into
+ // confusion)
if (parent->isArray() && parent[0] == UNARY_PREFIX) {
assert(child[0] == UNARY_PREFIX);
if ((parent[1] == PLUS || parent[1] == MINUS) && child[1] == parent[1]) {
@@ -1034,18 +1106,24 @@ struct JSPrinter {
return true;
}
}
- if (childPosition == 0) return true; // child could be anywhere, so always paren
- if (childPrecedence < 0) return false; // both precedences are safe
+ if (childPosition == 0)
+ return true; // child could be anywhere, so always paren
+ if (childPrecedence < 0)
+ return false; // both precedences are safe
// check if child is on the dangerous side
- if (OperatorClass::getRtl(parentPrecedence)) return childPosition < 0;
- else return childPosition > 0;
+ if (OperatorClass::getRtl(parentPrecedence))
+ return childPosition < 0;
+ else
+ return childPosition > 0;
}
- void printChild(Ref child, Ref parent, int childPosition=0) {
+ void printChild(Ref child, Ref parent, int childPosition = 0) {
bool parens = needParens(parent, child, childPosition);
- if (parens) emit('(');
+ if (parens)
+ emit('(');
print(child);
- if (parens) emit(')');
+ if (parens)
+ emit(')');
}
void printBinary(Ref node) {
@@ -1064,20 +1142,23 @@ struct JSPrinter {
// emit a finalized number
int last = used;
print(node[2]);
- ensure(1); // we temporarily append a 0
- char *curr = buffer + last; // ensure might invalidate
+ ensure(1); // we temporarily append a 0
+ char* curr = buffer + last; // ensure might invalidate
buffer[used] = 0;
- if (strstr(curr, "infinity")) return;
- if (strstr(curr, "nan")) return;
- if (strchr(curr, '.')) return; // already a decimal point, all good
- char *e = strchr(curr, 'e');
+ if (strstr(curr, "infinity"))
+ return;
+ if (strstr(curr, "nan"))
+ return;
+ if (strchr(curr, '.'))
+ return; // already a decimal point, all good
+ char* e = strchr(curr, 'e');
if (!e) {
emit(".0");
return;
}
ensure(3);
curr = buffer + last; // ensure might invalidate
- char *end = strchr(curr, 0);
+ char* end = strchr(curr, 0);
while (end >= e) {
end[2] = end[0];
end--;
@@ -1087,8 +1168,8 @@ struct JSPrinter {
used += 2;
return;
}
- if ((buffer[used-1] == '-' && node[1] == MINUS) ||
- (buffer[used-1] == '+' && node[1] == PLUS)) {
+ if ((buffer[used - 1] == '-' && node[1] == MINUS) ||
+ (buffer[used - 1] == '+' && node[1] == PLUS)) {
emit(' '); // cannot join - and - to --, looks like the -- operator
}
emit(node[1]->getCString());
@@ -1112,7 +1193,8 @@ struct JSPrinter {
emit('(');
Ref args = node[2];
for (size_t i = 0; i < args->size(); i++) {
- if (i > 0) (pretty ? emit(", ") : emit(','));
+ if (i > 0)
+ (pretty ? emit(", ") : emit(','));
printChild(args[i], node, 0);
}
emit(')');
@@ -1156,8 +1238,10 @@ struct JSPrinter {
auto curr = used;
printStats(c[1]);
indent--;
- if (curr != used) newline();
- else used--; // avoid the extra indentation we added tentatively
+ if (curr != used)
+ newline();
+ else
+ used--; // avoid the extra indentation we added tentatively
} else {
newline();
}
@@ -1185,7 +1269,8 @@ struct JSPrinter {
emit("var ");
Ref args = node[1];
for (size_t i = 0; i < args->size(); i++) {
- if (i > 0) (pretty ? emit(", ") : emit(','));
+ if (i > 0)
+ (pretty ? emit(", ") : emit(','));
emit(args[i][0]->getCString());
if (args[i]->size() > 1) {
space();
@@ -1292,7 +1377,8 @@ struct JSPrinter {
emit('[');
Ref args = node[1];
for (size_t i = 0; i < args->size(); i++) {
- if (i > 0) (pretty ? emit(", ") : emit(','));
+ if (i > 0)
+ (pretty ? emit(", ") : emit(','));
print(args[i]);
}
emit(']');
@@ -1309,7 +1395,7 @@ struct JSPrinter {
newline();
}
bool needQuote = false;
- const char *str;
+ const char* str;
if (args[i][0]->isArray()) {
assert(args[i][0][0] == STRING);
// A quoted string.
@@ -1319,7 +1405,7 @@ struct JSPrinter {
// Just a raw string, no quotes.
str = args[i][0]->getCString();
}
- const char *check = str;
+ const char* check = str;
while (*check) {
if (!isalnum(*check) && *check != '_' && *check != '$') {
needQuote = true;
@@ -1327,9 +1413,11 @@ struct JSPrinter {
}
check++;
}
- if (needQuote) emit('"');
+ if (needQuote)
+ emit('"');
emit(str);
- if (needQuote) emit('"');
+ if (needQuote)
+ emit('"');
emit(":");
space();
print(args[i][1]);
@@ -1340,7 +1428,6 @@ struct JSPrinter {
}
};
-
// cashew builder
class ValueBuilder {
@@ -1348,40 +1435,40 @@ class ValueBuilder {
return &arena.alloc<Value>()->setString(s);
}
- static Ref makeNull() {
- return &arena.alloc<Value>()->setNull();
- }
+ static Ref makeNull() { return &arena.alloc<Value>()->setNull(); }
public:
- static Ref makeRawArray(int size_hint=0) {
+ static Ref makeRawArray(int size_hint = 0) {
return &arena.alloc<Value>()->setArray(size_hint);
}
static Ref makeToplevel() {
- return &makeRawArray(2)->push_back(makeRawString(TOPLEVEL))
- .push_back(makeRawArray());
+ return &makeRawArray(2)
+ ->push_back(makeRawString(TOPLEVEL))
+ .push_back(makeRawArray());
}
static Ref makeString(IString str) {
- return &makeRawArray(2)->push_back(makeRawString(STRING))
- .push_back(makeRawString(str));
+ return &makeRawArray(2)
+ ->push_back(makeRawString(STRING))
+ .push_back(makeRawString(str));
}
static Ref makeBlock() {
- return &makeRawArray(2)->push_back(makeRawString(BLOCK))
- .push_back(makeRawArray());
+ return &makeRawArray(2)
+ ->push_back(makeRawString(BLOCK))
+ .push_back(makeRawArray());
}
- static Ref makeName(IString name) {
- return makeRawString(name);
- }
+ static Ref makeName(IString name) { return makeRawString(name); }
static void setBlockContent(Ref target, Ref block) {
if (target[0] == TOPLEVEL) {
target[1]->setArray(block[1]->getArray());
} else if (target[0] == DEFUN) {
target[3]->setArray(block[1]->getArray());
- } else abort();
+ } else
+ abort();
}
static void appendToBlock(Ref block, Ref element) {
@@ -1390,35 +1477,38 @@ public:
}
static Ref makeCall(Ref target) {
- return &makeRawArray(3)->push_back(makeRawString(CALL))
- .push_back(target)
- .push_back(makeRawArray());
+ return &makeRawArray(3)
+ ->push_back(makeRawString(CALL))
+ .push_back(target)
+ .push_back(makeRawArray());
}
static Ref makeCall(Ref target, Ref arg) {
- Ref ret = &makeRawArray(3)->push_back(makeRawString(CALL))
- .push_back(target)
- .push_back(makeRawArray());
+ Ref ret = &makeRawArray(3)
+ ->push_back(makeRawString(CALL))
+ .push_back(target)
+ .push_back(makeRawArray());
ret[2]->push_back(arg);
return ret;
}
static Ref makeCall(IString target) {
- Ref ret = &makeRawArray(3)->push_back(makeRawString(CALL))
- .push_back(makeName(target))
- .push_back(makeRawArray());
+ Ref ret = &makeRawArray(3)
+ ->push_back(makeRawString(CALL))
+ .push_back(makeName(target))
+ .push_back(makeRawArray());
return ret;
}
- template<typename ...Ts>
- static Ref makeCall(IString target, Ts... args) {
+ template<typename... Ts> static Ref makeCall(IString target, Ts... args) {
size_t nArgs = sizeof...(Ts);
Ref callArgs = makeRawArray(nArgs);
Ref argArray[] = {args...};
for (size_t i = 0; i < nArgs; ++i) {
callArgs->push_back(argArray[i]);
}
- return &makeRawArray(3)->push_back(makeRawString(CALL))
- .push_back(makeName(target))
- .push_back(callArgs);
+ return &makeRawArray(3)
+ ->push_back(makeRawString(CALL))
+ .push_back(makeName(target))
+ .push_back(callArgs);
}
static void appendToCall(Ref call, Ref element) {
@@ -1426,59 +1516,57 @@ public:
call[2]->push_back(element);
}
- static Ref makeStatement(Ref contents) {
- return contents;
- }
+ static Ref makeStatement(Ref contents) { return contents; }
static Ref makeDouble(double num) {
return &arena.alloc<Value>()->setNumber(num);
}
- static Ref makeInt(uint32_t num) {
- return makeDouble(double(num));
- }
- static Ref makeInt(int32_t num) {
- return makeDouble(double(num));
- }
- static Ref makeNum(double num) {
- return makeDouble(num);
- }
+ static Ref makeInt(uint32_t num) { return makeDouble(double(num)); }
+ static Ref makeInt(int32_t num) { return makeDouble(double(num)); }
+ static Ref makeNum(double num) { return makeDouble(num); }
static Ref makeUnary(IString op, Ref value) {
- return &makeRawArray(3)->push_back(makeRawString(UNARY_PREFIX))
- .push_back(makeRawString(op))
- .push_back(value);
+ return &makeRawArray(3)
+ ->push_back(makeRawString(UNARY_PREFIX))
+ .push_back(makeRawString(op))
+ .push_back(value);
}
static Ref makeBinary(Ref left, IString op, Ref right) {
if (op == SET) {
if (left->isString()) {
- return &arena.alloc<AssignName>()->setAssignName(left->getIString(), right);
+ return &arena.alloc<AssignName>()->setAssignName(left->getIString(),
+ right);
} else {
return &arena.alloc<Assign>()->setAssign(left, right);
}
} else if (op == COMMA) {
- return &makeRawArray(3)->push_back(makeRawString(SEQ))
- .push_back(left)
- .push_back(right);
+ return &makeRawArray(3)
+ ->push_back(makeRawString(SEQ))
+ .push_back(left)
+ .push_back(right);
} else {
- return &makeRawArray(4)->push_back(makeRawString(BINARY))
- .push_back(makeRawString(op))
- .push_back(left)
- .push_back(right);
+ return &makeRawArray(4)
+ ->push_back(makeRawString(BINARY))
+ .push_back(makeRawString(op))
+ .push_back(left)
+ .push_back(right);
}
}
static Ref makePrefix(IString op, Ref right) {
- return &makeRawArray(3)->push_back(makeRawString(UNARY_PREFIX))
- .push_back(makeRawString(op))
- .push_back(right);
+ return &makeRawArray(3)
+ ->push_back(makeRawString(UNARY_PREFIX))
+ .push_back(makeRawString(op))
+ .push_back(right);
}
static Ref makeFunction(IString name) {
- return &makeRawArray(4)->push_back(makeRawString(DEFUN))
- .push_back(makeRawString(name))
- .push_back(makeRawArray())
- .push_back(makeRawArray());
+ return &makeRawArray(4)
+ ->push_back(makeRawString(DEFUN))
+ .push_back(makeRawString(name))
+ .push_back(makeRawArray())
+ .push_back(makeRawArray());
}
static void appendArgumentToFunction(Ref func, IString arg) {
@@ -1486,101 +1574,115 @@ public:
func[2]->push_back(makeRawString(arg));
}
- static Ref makeVar(bool is_const=false) {
- return &makeRawArray(2)->push_back(makeRawString(VAR))
- .push_back(makeRawArray());
+ static Ref makeVar(bool is_const = false) {
+ return &makeRawArray(2)
+ ->push_back(makeRawString(VAR))
+ .push_back(makeRawArray());
}
static void appendToVar(Ref var, IString name, Ref value) {
assert(var[0] == VAR);
Ref array = &makeRawArray(1)->push_back(makeRawString(name));
- if (!!value) array->push_back(value);
+ if (!!value)
+ array->push_back(value);
var[1]->push_back(array);
}
static Ref makeReturn(Ref value) {
- return &makeRawArray(2)->push_back(makeRawString(RETURN))
- .push_back(!!value ? value : makeNull());
+ return &makeRawArray(2)
+ ->push_back(makeRawString(RETURN))
+ .push_back(!!value ? value : makeNull());
}
static Ref makeIndexing(Ref target, Ref index) {
- return &makeRawArray(3)->push_back(makeRawString(SUB))
- .push_back(target)
- .push_back(index);
+ return &makeRawArray(3)
+ ->push_back(makeRawString(SUB))
+ .push_back(target)
+ .push_back(index);
}
static Ref makeIf(Ref condition, Ref ifTrue, Ref ifFalse) {
- return &makeRawArray(4)->push_back(makeRawString(IF))
- .push_back(condition)
- .push_back(ifTrue)
- .push_back(!!ifFalse ? ifFalse : makeNull());
+ return &makeRawArray(4)
+ ->push_back(makeRawString(IF))
+ .push_back(condition)
+ .push_back(ifTrue)
+ .push_back(!!ifFalse ? ifFalse : makeNull());
}
static Ref makeConditional(Ref condition, Ref ifTrue, Ref ifFalse) {
- return &makeRawArray(4)->push_back(makeRawString(CONDITIONAL))
- .push_back(condition)
- .push_back(ifTrue)
- .push_back(ifFalse);
+ return &makeRawArray(4)
+ ->push_back(makeRawString(CONDITIONAL))
+ .push_back(condition)
+ .push_back(ifTrue)
+ .push_back(ifFalse);
}
static Ref makeSeq(Ref left, Ref right) {
- return &makeRawArray(3)->push_back(makeRawString(SEQ))
- .push_back(left)
- .push_back(right);
+ return &makeRawArray(3)
+ ->push_back(makeRawString(SEQ))
+ .push_back(left)
+ .push_back(right);
}
static Ref makeDo(Ref body, Ref condition) {
- return &makeRawArray(3)->push_back(makeRawString(DO))
- .push_back(condition)
- .push_back(body);
+ return &makeRawArray(3)
+ ->push_back(makeRawString(DO))
+ .push_back(condition)
+ .push_back(body);
}
static Ref makeWhile(Ref condition, Ref body) {
- return &makeRawArray(3)->push_back(makeRawString(WHILE))
- .push_back(condition)
- .push_back(body);
+ return &makeRawArray(3)
+ ->push_back(makeRawString(WHILE))
+ .push_back(condition)
+ .push_back(body);
}
static Ref makeFor(Ref init, Ref condition, Ref inc, Ref body) {
- return &makeRawArray(5)->push_back(makeRawString(FOR))
- .push_back(init)
- .push_back(condition)
- .push_back(inc)
- .push_back(body);
+ return &makeRawArray(5)
+ ->push_back(makeRawString(FOR))
+ .push_back(init)
+ .push_back(condition)
+ .push_back(inc)
+ .push_back(body);
}
static Ref makeBreak(IString label) {
- return &makeRawArray(2)->push_back(makeRawString(BREAK))
- .push_back(!!label ? makeRawString(label) : makeNull());
+ return &makeRawArray(2)
+ ->push_back(makeRawString(BREAK))
+ .push_back(!!label ? makeRawString(label) : makeNull());
}
static Ref makeContinue(IString label) {
- return &makeRawArray(2)->push_back(makeRawString(CONTINUE))
- .push_back(!!label ? makeRawString(label) : makeNull());
+ return &makeRawArray(2)
+ ->push_back(makeRawString(CONTINUE))
+ .push_back(!!label ? makeRawString(label) : makeNull());
}
static Ref makeLabel(IString name, Ref body) {
- return &makeRawArray(3)->push_back(makeRawString(LABEL))
- .push_back(makeRawString(name))
- .push_back(body);
+ return &makeRawArray(3)
+ ->push_back(makeRawString(LABEL))
+ .push_back(makeRawString(name))
+ .push_back(body);
}
static Ref makeSwitch(Ref input) {
- return &makeRawArray(3)->push_back(makeRawString(SWITCH))
- .push_back(input)
- .push_back(makeRawArray());
+ return &makeRawArray(3)
+ ->push_back(makeRawString(SWITCH))
+ .push_back(input)
+ .push_back(makeRawArray());
}
static void appendCaseToSwitch(Ref switch_, Ref arg) {
assert(switch_[0] == SWITCH);
- switch_[2]->push_back(&makeRawArray(2)->push_back(arg)
- .push_back(makeRawArray()));
+ switch_[2]->push_back(
+ &makeRawArray(2)->push_back(arg).push_back(makeRawArray()));
}
static void appendDefaultToSwitch(Ref switch_) {
assert(switch_[0] == SWITCH);
- switch_[2]->push_back(&makeRawArray(2)->push_back(makeNull())
- .push_back(makeRawArray()));
+ switch_[2]->push_back(
+ &makeRawArray(2)->push_back(makeNull()).push_back(makeRawArray()));
}
static void appendCodeToSwitch(Ref switch_, Ref code, bool explicitBlock) {
@@ -1598,20 +1700,21 @@ public:
static Ref makeTry(Ref try_, Ref arg, Ref catch_) {
assert(try_[0] == BLOCK);
assert(catch_[0] == BLOCK);
- return &makeRawArray(3)->push_back(makeRawString(TRY))
- .push_back(try_)
- .push_back(arg)
- .push_back(catch_);
+ return &makeRawArray(3)
+ ->push_back(makeRawString(TRY))
+ .push_back(try_)
+ .push_back(arg)
+ .push_back(catch_);
}
static Ref makeDot(Ref obj, IString key) {
- return &makeRawArray(3)->push_back(makeRawString(DOT))
- .push_back(obj)
- .push_back(makeRawString(key));
+ return &makeRawArray(3)
+ ->push_back(makeRawString(DOT))
+ .push_back(obj)
+ .push_back(makeRawString(key));
}
- template<typename ...Ts>
- static Ref makeDot(Ref obj, Ref key, Ts... args) {
+ template<typename... Ts> static Ref makeDot(Ref obj, Ref key, Ts... args) {
return makeDot(makeDot(obj, key), args...);
}
@@ -1621,13 +1724,13 @@ public:
}
static Ref makeNew(Ref call) {
- return &makeRawArray(2)->push_back(makeRawString(NEW))
- .push_back(call);
+ return &makeRawArray(2)->push_back(makeRawString(NEW)).push_back(call);
}
static Ref makeArray() {
- return &makeRawArray(2)->push_back(makeRawString(ARRAY))
- .push_back(makeRawArray());
+ return &makeRawArray(2)
+ ->push_back(makeRawString(ARRAY))
+ .push_back(makeRawArray());
}
static void appendToArray(Ref array, Ref element) {
@@ -1636,26 +1739,28 @@ public:
}
static Ref makeObject() {
- return &makeRawArray(2)->push_back(makeRawString(OBJECT))
- .push_back(makeRawArray());
+ return &makeRawArray(2)
+ ->push_back(makeRawString(OBJECT))
+ .push_back(makeRawArray());
}
static void appendToObject(Ref array, IString key, Ref value) {
assert(array[0] == OBJECT);
- array[1]->push_back(&makeRawArray(2)->push_back(makeRawString(key))
- .push_back(value));
+ array[1]->push_back(
+ &makeRawArray(2)->push_back(makeRawString(key)).push_back(value));
}
static void appendToObjectWithQuotes(Ref array, IString key, Ref value) {
assert(array[0] == OBJECT);
- array[1]->push_back(&makeRawArray(2)->push_back(makeString(key))
- .push_back(value));
+ array[1]->push_back(
+ &makeRawArray(2)->push_back(makeString(key)).push_back(value));
}
static Ref makeSub(Ref obj, Ref index) {
- return &makeRawArray(2)->push_back(makeRawString(SUB))
- .push_back(obj)
- .push_back(index);
+ return &makeRawArray(2)
+ ->push_back(makeRawString(SUB))
+ .push_back(obj)
+ .push_back(index);
}
static Ref makePtrShift(Ref ptr, int shifts) {
diff --git a/src/emscripten-optimizer/snprintf.h b/src/emscripten-optimizer/snprintf.h
index 86335661d..22c8d8202 100644
--- a/src/emscripten-optimizer/snprintf.h
+++ b/src/emscripten-optimizer/snprintf.h
@@ -19,34 +19,34 @@
#include <stdarg.h>
-// Visual Studio does not support C99, so emulate snprintf support for it manually.
+// Visual Studio does not support C99, so emulate snprintf support for it
+// manually.
#ifdef _MSC_VER
#define snprintf c99_snprintf
-inline int c99_vsnprintf(char* str, size_t size, const char* format, va_list ap)
-{
- int count = -1;
+inline int
+c99_vsnprintf(char* str, size_t size, const char* format, va_list ap) {
+ int count = -1;
- if (size != 0)
- count = _vsnprintf_s(str, size, _TRUNCATE, format, ap);
- if (count == -1)
- count = _vscprintf(format, ap);
+ if (size != 0)
+ count = _vsnprintf_s(str, size, _TRUNCATE, format, ap);
+ if (count == -1)
+ count = _vscprintf(format, ap);
- return count;
+ return count;
}
-inline int c99_snprintf(char* str, size_t size, const char* format, ...)
-{
- int count;
- va_list ap;
+inline int c99_snprintf(char* str, size_t size, const char* format, ...) {
+ int count;
+ va_list ap;
- va_start(ap, format);
- count = c99_vsnprintf(str, size, format, ap);
- va_end(ap);
+ va_start(ap, format);
+ count = c99_vsnprintf(str, size, format, ap);
+ va_end(ap);
- return count;
+ return count;
}
#endif
diff --git a/src/ir/ExpressionAnalyzer.cpp b/src/ir/ExpressionAnalyzer.cpp
index fcbd29665..aaab9050c 100644
--- a/src/ir/ExpressionAnalyzer.cpp
+++ b/src/ir/ExpressionAnalyzer.cpp
@@ -14,19 +14,19 @@
* limitations under the License.
*/
-#include "support/hash.h"
-#include "support/small_vector.h"
-#include "wasm.h"
-#include "wasm-traversal.h"
#include "ir/iteration.h"
#include "ir/load-utils.h"
#include "ir/utils.h"
+#include "support/hash.h"
+#include "support/small_vector.h"
+#include "wasm-traversal.h"
+#include "wasm.h"
namespace wasm {
// Given a stack of expressions, checks if the topmost is used as a result.
-// For example, if the parent is a block and the node is before the last position,
-// it is not used.
+// For example, if the parent is a block and the node is before the last
+// position, it is not used.
bool ExpressionAnalyzer::isResultUsed(ExpressionStack& stack, Function* func) {
for (int i = int(stack.size()) - 2; i >= 0; i--) {
auto* curr = stack[i];
@@ -35,18 +35,22 @@ bool ExpressionAnalyzer::isResultUsed(ExpressionStack& stack, Function* func) {
if (curr->is<Block>()) {
auto* block = curr->cast<Block>();
for (size_t j = 0; j < block->list.size() - 1; j++) {
- if (block->list[j] == above) return false;
+ if (block->list[j] == above)
+ return false;
}
assert(block->list.back() == above);
// continue down
} else if (curr->is<If>()) {
auto* iff = curr->cast<If>();
- if (above == iff->condition) return true;
- if (!iff->ifFalse) return false;
+ if (above == iff->condition)
+ return true;
+ if (!iff->ifFalse)
+ return false;
assert(above == iff->ifTrue || above == iff->ifFalse);
// continue down
} else {
- if (curr->is<Drop>()) return false;
+ if (curr->is<Drop>())
+ return false;
return true; // all other node types use the result
}
}
@@ -62,19 +66,23 @@ bool ExpressionAnalyzer::isResultDropped(ExpressionStack& stack) {
if (curr->is<Block>()) {
auto* block = curr->cast<Block>();
for (size_t j = 0; j < block->list.size() - 1; j++) {
- if (block->list[j] == above) return false;
+ if (block->list[j] == above)
+ return false;
}
assert(block->list.back() == above);
// continue down
} else if (curr->is<If>()) {
auto* iff = curr->cast<If>();
- if (above == iff->condition) return false;
- if (!iff->ifFalse) return false;
+ if (above == iff->condition)
+ return false;
+ if (!iff->ifFalse)
+ return false;
assert(above == iff->ifTrue || above == iff->ifFalse);
// continue down
} else {
- if (curr->is<Drop>()) return true; // dropped
- return false; // all other node types use the result
+ if (curr->is<Drop>())
+ return true; // dropped
+ return false; // all other node types use the result
}
}
return false;
@@ -98,8 +106,7 @@ bool ExpressionAnalyzer::isResultDropped(ExpressionStack& stack) {
namespace {
-template<typename T>
-void visitImmediates(Expression* curr, T& visitor) {
+template<typename T> void visitImmediates(Expression* curr, T& visitor) {
struct ImmediateVisitor : public OverriddenVisitor<ImmediateVisitor> {
T& visitor;
@@ -107,35 +114,22 @@ void visitImmediates(Expression* curr, T& visitor) {
this->visit(curr);
}
- void visitBlock(Block* curr) {
- visitor.visitScopeName(curr->name);
- }
- void visitIf(If* curr) {
- }
- void visitLoop(Loop* curr) {
- visitor.visitScopeName(curr->name);
- }
- void visitBreak(Break* curr) {
- visitor.visitScopeName(curr->name);
- }
+ void visitBlock(Block* curr) { visitor.visitScopeName(curr->name); }
+ void visitIf(If* curr) {}
+ void visitLoop(Loop* curr) { visitor.visitScopeName(curr->name); }
+ void visitBreak(Break* curr) { visitor.visitScopeName(curr->name); }
void visitSwitch(Switch* curr) {
for (auto target : curr->targets) {
visitor.visitScopeName(target);
}
visitor.visitScopeName(curr->default_);
}
- void visitCall(Call* curr) {
- visitor.visitNonScopeName(curr->target);
- }
+ void visitCall(Call* curr) { visitor.visitNonScopeName(curr->target); }
void visitCallIndirect(CallIndirect* curr) {
visitor.visitNonScopeName(curr->fullType);
}
- void visitGetLocal(GetLocal* curr) {
- visitor.visitIndex(curr->index);
- }
- void visitSetLocal(SetLocal* curr) {
- visitor.visitIndex(curr->index);
- }
+ void visitGetLocal(GetLocal* curr) { visitor.visitIndex(curr->index); }
+ void visitSetLocal(SetLocal* curr) { visitor.visitIndex(curr->index); }
void visitGetGlobal(GetGlobal* curr) {
visitor.visitNonScopeName(curr->name);
}
@@ -187,52 +181,37 @@ void visitImmediates(Expression* curr, T& visitor) {
visitor.visitInt(x);
}
}
- void visitSIMDBitselect(SIMDBitselect* curr) {
- }
- void visitSIMDShift(SIMDShift* curr) {
- visitor.visitInt(curr->op);
- }
+ void visitSIMDBitselect(SIMDBitselect* curr) {}
+ void visitSIMDShift(SIMDShift* curr) { visitor.visitInt(curr->op); }
void visitMemoryInit(MemoryInit* curr) {
visitor.visitIndex(curr->segment);
}
- void visitDataDrop(DataDrop* curr) {
- visitor.visitIndex(curr->segment);
- }
- void visitMemoryCopy(MemoryCopy* curr) {
- }
- void visitMemoryFill(MemoryFill* curr) {
- }
- void visitConst(Const* curr) {
- visitor.visitLiteral(curr->value);
- }
- void visitUnary(Unary* curr) {
- visitor.visitInt(curr->op);
- }
- void visitBinary(Binary* curr) {
- visitor.visitInt(curr->op);
- }
- void visitSelect(Select* curr) {
- }
- void visitDrop(Drop* curr) {
- }
- void visitReturn(Return* curr) {
- }
+ void visitDataDrop(DataDrop* curr) { visitor.visitIndex(curr->segment); }
+ void visitMemoryCopy(MemoryCopy* curr) {}
+ void visitMemoryFill(MemoryFill* curr) {}
+ void visitConst(Const* curr) { visitor.visitLiteral(curr->value); }
+ void visitUnary(Unary* curr) { visitor.visitInt(curr->op); }
+ void visitBinary(Binary* curr) { visitor.visitInt(curr->op); }
+ void visitSelect(Select* curr) {}
+ void visitDrop(Drop* curr) {}
+ void visitReturn(Return* curr) {}
void visitHost(Host* curr) {
visitor.visitInt(curr->op);
visitor.visitNonScopeName(curr->nameOperand);
}
- void visitNop(Nop* curr) {
- }
- void visitUnreachable(Unreachable* curr) {
- }
+ void visitNop(Nop* curr) {}
+ void visitUnreachable(Unreachable* curr) {}
} singleton(curr, visitor);
}
} // namespace
-bool ExpressionAnalyzer::flexibleEqual(Expression* left, Expression* right, ExprComparer comparer) {
+bool ExpressionAnalyzer::flexibleEqual(Expression* left,
+ Expression* right,
+ ExprComparer comparer) {
struct Comparer {
- std::map<Name, Name> rightNames; // for each name on the left, the corresponding name on the right
+ // for each name on the left, the corresponding name on the right
+ std::map<Name, Name> rightNames;
std::vector<Expression*> leftStack;
std::vector<Expression*> rightStack;
@@ -259,13 +238,15 @@ bool ExpressionAnalyzer::flexibleEqual(Expression* left, Expression* right, Expr
// Comparison is by value, except for names, which must match.
bool operator==(const Immediates& other) {
- if (scopeNames.size() != other.scopeNames.size()) return false;
+ if (scopeNames.size() != other.scopeNames.size())
+ return false;
for (Index i = 0; i < scopeNames.size(); i++) {
auto leftName = scopeNames[i];
auto rightName = other.scopeNames[i];
auto iter = parent.rightNames.find(leftName);
- // If it's not found, that means it was defined out of the expression being compared,
- // in which case we can just treat it literally - it must be exactly identical.
+ // If it's not found, that means it was defined out of the expression
+ // being compared, in which case we can just treat it literally - it
+ // must be exactly identical.
if (iter != parent.rightNames.end()) {
leftName = iter->second;
}
@@ -273,18 +254,22 @@ bool ExpressionAnalyzer::flexibleEqual(Expression* left, Expression* right, Expr
return false;
}
}
- if (nonScopeNames != other.nonScopeNames) return false;
- if (ints != other.ints) return false;
- if (literals != other.literals) return false;
- if (types != other.types) return false;
- if (indexes != other.indexes) return false;
- if (addresses != other.addresses) return false;
+ if (nonScopeNames != other.nonScopeNames)
+ return false;
+ if (ints != other.ints)
+ return false;
+ if (literals != other.literals)
+ return false;
+ if (types != other.types)
+ return false;
+ if (indexes != other.indexes)
+ return false;
+ if (addresses != other.addresses)
+ return false;
return true;
}
- bool operator!=(const Immediates& other) {
- return !(*this == other);
- }
+ bool operator!=(const Immediates& other) { return !(*this == other); }
void clear() {
scopeNames.clear();
@@ -298,7 +283,8 @@ bool ExpressionAnalyzer::flexibleEqual(Expression* left, Expression* right, Expr
};
bool noteNames(Name left, Name right) {
- if (left.is() != right.is()) return false;
+ if (left.is() != right.is())
+ return false;
if (left.is()) {
assert(rightNames.find(left) == rightNames.end());
rightNames[left] = right;
@@ -307,8 +293,7 @@ bool ExpressionAnalyzer::flexibleEqual(Expression* left, Expression* right, Expr
}
bool compare(Expression* left, Expression* right, ExprComparer comparer) {
- Immediates leftImmediates(*this),
- rightImmediates(*this);
+ Immediates leftImmediates(*this), rightImmediates(*this);
// The empty name is the same on both sides.
rightNames[Name()] = Name();
@@ -321,21 +306,28 @@ bool ExpressionAnalyzer::flexibleEqual(Expression* left, Expression* right, Expr
leftStack.pop_back();
right = rightStack.back();
rightStack.pop_back();
- if (!left != !right) return false;
- if (!left) continue;
- if (comparer(left, right)) continue; // comparison hook, before all the rest
+ if (!left != !right)
+ return false;
+ if (!left)
+ continue;
+ if (comparer(left, right))
+ continue; // comparison hook, before all the rest
// continue with normal structural comparison
- if (left->_id != right->_id) return false;
+ if (left->_id != right->_id)
+ return false;
// Blocks and loops introduce scoping.
if (auto* block = left->dynCast<Block>()) {
- if (!noteNames(block->name, right->cast<Block>()->name)) return false;
+ if (!noteNames(block->name, right->cast<Block>()->name))
+ return false;
} else if (auto* loop = left->dynCast<Loop>()) {
- if (!noteNames(loop->name, right->cast<Loop>()->name)) return false;
+ if (!noteNames(loop->name, right->cast<Loop>()->name))
+ return false;
} else {
// For all other nodes, compare their immediate values
visitImmediates(left, leftImmediates);
visitImmediates(right, rightImmediates);
- if (leftImmediates != rightImmediates) return false;
+ if (leftImmediates != rightImmediates)
+ return false;
leftImmediates.clear();
rightImmediates.clear();
}
@@ -349,10 +341,13 @@ bool ExpressionAnalyzer::flexibleEqual(Expression* left, Expression* right, Expr
rightStack.push_back(child);
counter--;
}
- // The number of child nodes must match (e.g. return has an optional one).
- if (counter != 0) return false;
+ // The number of child nodes must match (e.g. return has an optional
+ // one).
+ if (counter != 0)
+ return false;
}
- if (leftStack.size() > 0 || rightStack.size() > 0) return false;
+ if (leftStack.size() > 0 || rightStack.size() > 0)
+ return false;
return true;
}
};
@@ -366,7 +361,8 @@ HashType ExpressionAnalyzer::hash(Expression* curr) {
HashType digest = 0;
Index internalCounter = 0;
- std::map<Name, Index> internalNames; // for each internal name, its unique id
+ // for each internal name, its unique id
+ std::map<Name, Index> internalNames;
ExpressionStack stack;
void noteScopeName(Name curr) {
@@ -381,7 +377,8 @@ HashType ExpressionAnalyzer::hash(Expression* curr) {
while (stack.size() > 0) {
curr = stack.back();
stack.pop_back();
- if (!curr) continue;
+ if (!curr)
+ continue;
hash(curr->_id);
// we often don't need to hash the type, as it is tied to other values
// we are hashing anyhow, but there are exceptions: for example, a
@@ -413,9 +410,7 @@ HashType ExpressionAnalyzer::hash(Expression* curr) {
}
}
- void hash(HashType hash) {
- digest = rehash(digest, hash);
- }
+ void hash(HashType hash) { digest = rehash(digest, hash); }
void hash64(uint64_t hash) {
digest = rehash(rehash(digest, HashType(hash >> 32)), HashType(hash));
}
@@ -424,28 +419,23 @@ HashType ExpressionAnalyzer::hash(Expression* curr) {
// Names are relative, we give the same hash for
// (block $x (br $x))
// (block $y (br $y))
- static_assert(sizeof(Index) == sizeof(int32_t), "wasm64 will need changes here");
+ static_assert(sizeof(Index) == sizeof(int32_t),
+ "wasm64 will need changes here");
assert(internalNames.find(curr) != internalNames.end());
return hash(internalNames[curr]);
}
- void visitNonScopeName(Name curr) {
- return hash64(uint64_t(curr.str));
- }
- void visitInt(int32_t curr) {
- hash(curr);
- }
- void visitLiteral(Literal curr) {
- hash(std::hash<Literal>()(curr));
- }
- void visitType(Type curr) {
- hash(int32_t(curr));
- }
+ void visitNonScopeName(Name curr) { return hash64(uint64_t(curr.str)); }
+ void visitInt(int32_t curr) { hash(curr); }
+ void visitLiteral(Literal curr) { hash(std::hash<Literal>()(curr)); }
+ void visitType(Type curr) { hash(int32_t(curr)); }
void visitIndex(Index curr) {
- static_assert(sizeof(Index) == sizeof(int32_t), "wasm64 will need changes here");
+ static_assert(sizeof(Index) == sizeof(int32_t),
+ "wasm64 will need changes here");
hash(int32_t(curr));
}
void visitAddress(Address curr) {
- static_assert(sizeof(Address) == sizeof(int32_t), "wasm64 will need changes here");
+ static_assert(sizeof(Address) == sizeof(int32_t),
+ "wasm64 will need changes here");
hash(int32_t(curr));
}
};
diff --git a/src/ir/ExpressionManipulator.cpp b/src/ir/ExpressionManipulator.cpp
index 2b648e077..6d35ef97f 100644
--- a/src/ir/ExpressionManipulator.cpp
+++ b/src/ir/ExpressionManipulator.cpp
@@ -22,156 +22,202 @@ namespace wasm {
namespace ExpressionManipulator {
-Expression* flexibleCopy(Expression* original, Module& wasm, CustomCopier custom) {
+Expression*
+flexibleCopy(Expression* original, Module& wasm, CustomCopier custom) {
struct Copier : public Visitor<Copier, Expression*> {
Module& wasm;
CustomCopier custom;
Builder builder;
- Copier(Module& wasm, CustomCopier custom) : wasm(wasm), custom(custom), builder(wasm) {}
+ Copier(Module& wasm, CustomCopier custom)
+ : wasm(wasm), custom(custom), builder(wasm) {}
Expression* copy(Expression* curr) {
- if (!curr) return nullptr;
+ if (!curr)
+ return nullptr;
auto* ret = custom(curr);
- if (ret) return ret;
+ if (ret)
+ return ret;
return Visitor<Copier, Expression*>::visit(curr);
}
- Expression* visitBlock(Block *curr) {
+ Expression* visitBlock(Block* curr) {
ExpressionList list(wasm.allocator);
for (Index i = 0; i < curr->list.size(); i++) {
list.push_back(copy(curr->list[i]));
}
return builder.makeBlock(curr->name, list, curr->type);
}
- Expression* visitIf(If *curr) {
- return builder.makeIf(copy(curr->condition), copy(curr->ifTrue), copy(curr->ifFalse), curr->type);
+ Expression* visitIf(If* curr) {
+ return builder.makeIf(copy(curr->condition),
+ copy(curr->ifTrue),
+ copy(curr->ifFalse),
+ curr->type);
}
- Expression* visitLoop(Loop *curr) {
+ Expression* visitLoop(Loop* curr) {
return builder.makeLoop(curr->name, copy(curr->body));
}
- Expression* visitBreak(Break *curr) {
- return builder.makeBreak(curr->name, copy(curr->value), copy(curr->condition));
+ Expression* visitBreak(Break* curr) {
+ return builder.makeBreak(
+ curr->name, copy(curr->value), copy(curr->condition));
}
- Expression* visitSwitch(Switch *curr) {
- return builder.makeSwitch(curr->targets, curr->default_, copy(curr->condition), copy(curr->value));
+ Expression* visitSwitch(Switch* curr) {
+ return builder.makeSwitch(curr->targets,
+ curr->default_,
+ copy(curr->condition),
+ copy(curr->value));
}
- Expression* visitCall(Call *curr) {
+ Expression* visitCall(Call* curr) {
auto* ret = builder.makeCall(curr->target, {}, curr->type);
for (Index i = 0; i < curr->operands.size(); i++) {
ret->operands.push_back(copy(curr->operands[i]));
}
return ret;
}
- Expression* visitCallIndirect(CallIndirect *curr) {
- auto* ret = builder.makeCallIndirect(curr->fullType, copy(curr->target), {}, curr->type);
+ Expression* visitCallIndirect(CallIndirect* curr) {
+ auto* ret = builder.makeCallIndirect(
+ curr->fullType, copy(curr->target), {}, curr->type);
for (Index i = 0; i < curr->operands.size(); i++) {
ret->operands.push_back(copy(curr->operands[i]));
}
return ret;
}
- Expression* visitGetLocal(GetLocal *curr) {
+ Expression* visitGetLocal(GetLocal* curr) {
return builder.makeGetLocal(curr->index, curr->type);
}
- Expression* visitSetLocal(SetLocal *curr) {
+ Expression* visitSetLocal(SetLocal* curr) {
if (curr->isTee()) {
return builder.makeTeeLocal(curr->index, copy(curr->value));
} else {
return builder.makeSetLocal(curr->index, copy(curr->value));
}
}
- Expression* visitGetGlobal(GetGlobal *curr) {
+ Expression* visitGetGlobal(GetGlobal* curr) {
return builder.makeGetGlobal(curr->name, curr->type);
}
- Expression* visitSetGlobal(SetGlobal *curr) {
+ Expression* visitSetGlobal(SetGlobal* curr) {
return builder.makeSetGlobal(curr->name, copy(curr->value));
}
- Expression* visitLoad(Load *curr) {
+ Expression* visitLoad(Load* curr) {
if (curr->isAtomic) {
- return builder.makeAtomicLoad(curr->bytes, curr->offset,
- copy(curr->ptr), curr->type);
+ return builder.makeAtomicLoad(
+ curr->bytes, curr->offset, copy(curr->ptr), curr->type);
}
- return builder.makeLoad(curr->bytes, LoadUtils::isSignRelevant(curr) ? curr->signed_ : false, curr->offset, curr->align, copy(curr->ptr), curr->type);
- }
- Expression* visitStore(Store *curr) {
+ return builder.makeLoad(curr->bytes,
+ LoadUtils::isSignRelevant(curr) ? curr->signed_
+ : false,
+ curr->offset,
+ curr->align,
+ copy(curr->ptr),
+ curr->type);
+ }
+ Expression* visitStore(Store* curr) {
if (curr->isAtomic) {
- return builder.makeAtomicStore(curr->bytes, curr->offset, copy(curr->ptr), copy(curr->value), curr->valueType);
+ return builder.makeAtomicStore(curr->bytes,
+ curr->offset,
+ copy(curr->ptr),
+ copy(curr->value),
+ curr->valueType);
}
- return builder.makeStore(curr->bytes, curr->offset, curr->align, copy(curr->ptr), copy(curr->value), curr->valueType);
+ return builder.makeStore(curr->bytes,
+ curr->offset,
+ curr->align,
+ copy(curr->ptr),
+ copy(curr->value),
+ curr->valueType);
}
Expression* visitAtomicRMW(AtomicRMW* curr) {
- return builder.makeAtomicRMW(curr->op, curr->bytes, curr->offset,
- copy(curr->ptr), copy(curr->value), curr->type);
+ return builder.makeAtomicRMW(curr->op,
+ curr->bytes,
+ curr->offset,
+ copy(curr->ptr),
+ copy(curr->value),
+ curr->type);
}
Expression* visitAtomicCmpxchg(AtomicCmpxchg* curr) {
- return builder.makeAtomicCmpxchg(curr->bytes, curr->offset,
- copy(curr->ptr), copy(curr->expected), copy(curr->replacement),
+ return builder.makeAtomicCmpxchg(curr->bytes,
+ curr->offset,
+ copy(curr->ptr),
+ copy(curr->expected),
+ copy(curr->replacement),
curr->type);
}
Expression* visitAtomicWait(AtomicWait* curr) {
- return builder.makeAtomicWait(copy(curr->ptr), copy(curr->expected), copy(curr->timeout), curr->expectedType, curr->offset);
+ return builder.makeAtomicWait(copy(curr->ptr),
+ copy(curr->expected),
+ copy(curr->timeout),
+ curr->expectedType,
+ curr->offset);
}
Expression* visitAtomicNotify(AtomicNotify* curr) {
- return builder.makeAtomicNotify(copy(curr->ptr), copy(curr->notifyCount), curr->offset);
+ return builder.makeAtomicNotify(
+ copy(curr->ptr), copy(curr->notifyCount), curr->offset);
}
Expression* visitSIMDExtract(SIMDExtract* curr) {
return builder.makeSIMDExtract(curr->op, copy(curr->vec), curr->index);
}
Expression* visitSIMDReplace(SIMDReplace* curr) {
- return builder.makeSIMDReplace(curr->op, copy(curr->vec), curr->index, copy(curr->value));
+ return builder.makeSIMDReplace(
+ curr->op, copy(curr->vec), curr->index, copy(curr->value));
}
Expression* visitSIMDShuffle(SIMDShuffle* curr) {
- return builder.makeSIMDShuffle(copy(curr->left), copy(curr->right), curr->mask);
+ return builder.makeSIMDShuffle(
+ copy(curr->left), copy(curr->right), curr->mask);
}
Expression* visitSIMDBitselect(SIMDBitselect* curr) {
- return builder.makeSIMDBitselect(copy(curr->left), copy(curr->right), copy(curr->cond));
+ return builder.makeSIMDBitselect(
+ copy(curr->left), copy(curr->right), copy(curr->cond));
}
Expression* visitSIMDShift(SIMDShift* curr) {
- return builder.makeSIMDShift(curr->op, copy(curr->vec), copy(curr->shift));
+ return builder.makeSIMDShift(
+ curr->op, copy(curr->vec), copy(curr->shift));
}
Expression* visitConst(Const* curr) {
return builder.makeConst(curr->value);
}
Expression* visitMemoryInit(MemoryInit* curr) {
- return builder.makeMemoryInit(curr->segment, copy(curr->dest), copy(curr->offset), copy(curr->size));
+ return builder.makeMemoryInit(
+ curr->segment, copy(curr->dest), copy(curr->offset), copy(curr->size));
}
Expression* visitDataDrop(DataDrop* curr) {
return builder.makeDataDrop(curr->segment);
}
Expression* visitMemoryCopy(MemoryCopy* curr) {
- return builder.makeMemoryCopy(copy(curr->dest), copy(curr->source), copy(curr->size));
+ return builder.makeMemoryCopy(
+ copy(curr->dest), copy(curr->source), copy(curr->size));
}
Expression* visitMemoryFill(MemoryFill* curr) {
- return builder.makeMemoryFill(copy(curr->dest), copy(curr->value), copy(curr->size));
+ return builder.makeMemoryFill(
+ copy(curr->dest), copy(curr->value), copy(curr->size));
}
- Expression* visitUnary(Unary *curr) {
+ Expression* visitUnary(Unary* curr) {
return builder.makeUnary(curr->op, copy(curr->value));
}
- Expression* visitBinary(Binary *curr) {
+ Expression* visitBinary(Binary* curr) {
return builder.makeBinary(curr->op, copy(curr->left), copy(curr->right));
}
- Expression* visitSelect(Select *curr) {
- return builder.makeSelect(copy(curr->condition), copy(curr->ifTrue), copy(curr->ifFalse));
+ Expression* visitSelect(Select* curr) {
+ return builder.makeSelect(
+ copy(curr->condition), copy(curr->ifTrue), copy(curr->ifFalse));
}
- Expression* visitDrop(Drop *curr) {
+ Expression* visitDrop(Drop* curr) {
return builder.makeDrop(copy(curr->value));
}
- Expression* visitReturn(Return *curr) {
+ Expression* visitReturn(Return* curr) {
return builder.makeReturn(copy(curr->value));
}
- Expression* visitHost(Host *curr) {
+ Expression* visitHost(Host* curr) {
std::vector<Expression*> operands;
for (Index i = 0; i < curr->operands.size(); i++) {
operands.push_back(copy(curr->operands[i]));
}
- auto* ret = builder.makeHost(curr->op, curr->nameOperand, std::move(operands));
+ auto* ret =
+ builder.makeHost(curr->op, curr->nameOperand, std::move(operands));
return ret;
}
- Expression* visitNop(Nop *curr) {
- return builder.makeNop();
- }
- Expression* visitUnreachable(Unreachable *curr) {
+ Expression* visitNop(Nop* curr) { return builder.makeNop(); }
+ Expression* visitUnreachable(Unreachable* curr) {
return builder.makeUnreachable();
}
};
@@ -180,7 +226,6 @@ Expression* flexibleCopy(Expression* original, Module& wasm, CustomCopier custom
return copier.copy(original);
}
-
// Splice an item into the middle of a block's list
void spliceIntoBlock(Block* block, Index index, Expression* add) {
auto& list = block->list;
diff --git a/src/ir/LocalGraph.cpp b/src/ir/LocalGraph.cpp
index 1cf883c19..1a2ccc0a2 100644
--- a/src/ir/LocalGraph.cpp
+++ b/src/ir/LocalGraph.cpp
@@ -16,11 +16,11 @@
#include <iterator>
-#include <wasm-builder.h>
-#include <wasm-printing.h>
+#include <cfg/cfg-traversal.h>
#include <ir/find_all.h>
#include <ir/local-graph.h>
-#include <cfg/cfg-traversal.h>
+#include <wasm-builder.h>
+#include <wasm-printing.h>
namespace wasm {
@@ -28,8 +28,10 @@ namespace LocalGraphInternal {
// Information about a basic block.
struct Info {
- std::vector<Expression*> actions; // actions occurring in this block: local.gets and local.sets
- std::unordered_map<Index, SetLocal*> lastSets; // for each index, the last local.set for it
+ // actions occurring in this block: local.gets and local.sets
+ std::vector<Expression*> actions;
+ // for each index, the last local.set for it
+ std::unordered_map<Index, SetLocal*> lastSets;
};
// flow helper class. flows the gets to their sets
@@ -38,7 +40,10 @@ struct Flower : public CFGWalker<Flower, Visitor<Flower>, Info> {
LocalGraph::GetSetses& getSetses;
LocalGraph::Locations& locations;
- Flower(LocalGraph::GetSetses& getSetses, LocalGraph::Locations& locations, Function* func) : getSetses(getSetses), locations(locations) {
+ Flower(LocalGraph::GetSetses& getSetses,
+ LocalGraph::Locations& locations,
+ Function* func)
+ : getSetses(getSetses), locations(locations) {
setFunction(func);
// create the CFG by walking the IR
CFGWalker<Flower, Visitor<Flower>, Info>::doWalkFunction(func);
@@ -46,16 +51,15 @@ struct Flower : public CFGWalker<Flower, Visitor<Flower>, Info> {
flow(func);
}
- BasicBlock* makeBasicBlock() {
- return new BasicBlock();
- }
+ BasicBlock* makeBasicBlock() { return new BasicBlock(); }
// cfg traversal work
static void doVisitGetLocal(Flower* self, Expression** currp) {
auto* curr = (*currp)->cast<GetLocal>();
- // if in unreachable code, skip
- if (!self->currBasicBlock) return;
+ // if in unreachable code, skip
+ if (!self->currBasicBlock)
+ return;
self->currBasicBlock->contents.actions.emplace_back(curr);
self->locations[curr] = currp;
}
@@ -63,27 +67,32 @@ struct Flower : public CFGWalker<Flower, Visitor<Flower>, Info> {
static void doVisitSetLocal(Flower* self, Expression** currp) {
auto* curr = (*currp)->cast<SetLocal>();
// if in unreachable code, skip
- if (!self->currBasicBlock) return;
+ if (!self->currBasicBlock)
+ return;
self->currBasicBlock->contents.actions.emplace_back(curr);
self->currBasicBlock->contents.lastSets[curr->index] = curr;
self->locations[curr] = currp;
}
void flow(Function* func) {
- // This block struct is optimized for this flow process (Minimal information, iteration index).
+ // This block struct is optimized for this flow process (Minimal
+ // information, iteration index).
struct FlowBlock {
- // Last Traversed Iteration: This value helps us to find if this block has been seen while traversing blocks.
- // We compare this value to the current iteration index in order to determine if we already process this block in the current iteration.
- // This speeds up the processing compared to unordered_set or other struct usage. (No need to reset internal values, lookup into container, ...)
+ // Last Traversed Iteration: This value helps us to find if this block has
+ // been seen while traversing blocks. We compare this value to the current
+ // iteration index in order to determine if we already process this block
+ // in the current iteration. This speeds up the processing compared to
+ // unordered_set or other struct usage. (No need to reset internal values,
+ // lookup into container, ...)
size_t lastTraversedIteration;
std::vector<Expression*> actions;
std::vector<FlowBlock*> in;
// Sor each index, the last local.set for it
// The unordered_map from BasicBlock.Info is converted into a vector
- // This speeds up search as there are usually few sets in a block, so just scanning
- // them linearly is efficient, avoiding hash computations (while in Info,
- // it's convenient to have a map so we can assign them easily, where
- // the last one seen overwrites the previous; and, we do that O(1)).
+ // This speeds up search as there are usually few sets in a block, so just
+ // scanning them linearly is efficient, avoiding hash computations (while
+ // in Info, it's convenient to have a map so we can assign them easily,
+ // where the last one seen overwrites the previous; and, we do that O(1)).
std::vector<std::pair<Index, SetLocal*>> lastSets;
};
@@ -92,7 +101,8 @@ struct Flower : public CFGWalker<Flower, Visitor<Flower>, Info> {
allGets.resize(numLocals);
std::vector<FlowBlock*> work;
- // Convert input blocks (basicBlocks) into more efficient flow blocks to improve memory access.
+ // Convert input blocks (basicBlocks) into more efficient flow blocks to
+ // improve memory access.
std::vector<FlowBlock> flowBlocks;
flowBlocks.resize(basicBlocks.size());
@@ -109,15 +119,17 @@ struct Flower : public CFGWalker<Flower, Visitor<Flower>, Info> {
auto& block = basicBlocks[i];
auto& flowBlock = flowBlocks[i];
// Get the equivalent block to entry in the flow list
- if (block.get() == entry) entryFlowBlock = &flowBlock;
+ if (block.get() == entry)
+ entryFlowBlock = &flowBlock;
flowBlock.lastTraversedIteration = NULL_ITERATION;
flowBlock.actions.swap(block->contents.actions);
// Map in block to flow blocks
auto& in = block->in;
flowBlock.in.resize(in.size());
- std::transform(in.begin(), in.end(), flowBlock.in.begin(), [&](BasicBlock* block) {
- return basicToFlowMap[block];
- });
+ std::transform(in.begin(),
+ in.end(),
+ flowBlock.in.begin(),
+ [&](BasicBlock* block) { return basicToFlowMap[block]; });
// Convert unordered_map to vector.
flowBlock.lastSets.reserve(block->contents.lastSets.size());
for (auto set : block->contents.lastSets) {
@@ -159,7 +171,8 @@ struct Flower : public CFGWalker<Flower, Visitor<Flower>, Info> {
// can do that for all gets as a whole, they will get the same results.
for (Index index = 0; index < numLocals; index++) {
auto& gets = allGets[index];
- if (gets.empty()) continue;
+ if (gets.empty())
+ continue;
work.push_back(&block);
// Note that we may need to revisit the later parts of this initial
// block, if we are in a loop, so don't mark it as seen.
@@ -182,9 +195,12 @@ struct Flower : public CFGWalker<Flower, Visitor<Flower>, Info> {
continue;
}
pred->lastTraversedIteration = currentIteration;
- auto lastSet = std::find_if(pred->lastSets.begin(), pred->lastSets.end(), [&](std::pair<Index, SetLocal*>& value) {
- return value.first == index;
- });
+ auto lastSet =
+ std::find_if(pred->lastSets.begin(),
+ pred->lastSets.end(),
+ [&](std::pair<Index, SetLocal*>& value) {
+ return value.first == index;
+ });
if (lastSet != pred->lastSets.end()) {
// There is a set here, apply it, and stop the flow.
for (auto* get : gets) {
@@ -271,9 +287,6 @@ void LocalGraph::computeSSAIndexes() {
}
}
-bool LocalGraph::isSSA(Index x) {
- return SSAIndexes.count(x);
-}
+bool LocalGraph::isSSA(Index x) { return SSAIndexes.count(x); }
} // namespace wasm
-
diff --git a/src/ir/ReFinalize.cpp b/src/ir/ReFinalize.cpp
index e4d5180d1..2bf68970d 100644
--- a/src/ir/ReFinalize.cpp
+++ b/src/ir/ReFinalize.cpp
@@ -51,10 +51,10 @@ void ReFinalize::visitBlock(Block* curr) {
// if concrete, it doesn't matter if we have an unreachable child, and we
// don't need to look at breaks
if (isConcreteType(curr->type)) {
- // make sure our branches make sense for us - we may have just made ourselves
- // concrete for a value flowing out, while branches did not send a value. such
- // branches could not have been actually taken before, that is, there were in
- // unreachable code, but we do still need to fix them up here.
+ // make sure our branches make sense for us - we may have just made
+ // ourselves concrete for a value flowing out, while branches did not send a
+ // value. such branches could not have been actually taken before, that is,
+ // there were in unreachable code, but we do still need to fix them up here.
if (!isConcreteType(old)) {
auto iter = breakValues.find(curr->name);
if (iter != breakValues.end()) {
@@ -91,7 +91,8 @@ void ReFinalize::visitBlock(Block* curr) {
return;
}
}
- if (curr->type == unreachable) return;
+ if (curr->type == unreachable)
+ return;
// type is none, but we might be unreachable
if (curr->type == none) {
for (auto* child : curr->list) {
diff --git a/src/ir/abstract.h b/src/ir/abstract.h
index 1f15bafa1..33c276409 100644
--- a/src/ir/abstract.h
+++ b/src/ir/abstract.h
@@ -29,17 +29,28 @@ enum Op {
// Unary
Neg,
// Binary
- Add, Sub, Mul, DivU, DivS, Rem, RemU, RemS,
- Shl, ShrU, ShrS,
- And, Or, Xor,
+ Add,
+ Sub,
+ Mul,
+ DivU,
+ DivS,
+ Rem,
+ RemU,
+ RemS,
+ Shl,
+ ShrU,
+ ShrS,
+ And,
+ Or,
+ Xor,
// Relational
- Eq, Ne,
+ Eq,
+ Ne,
};
-// Provide a wasm type and an abstract op and get the concrete one. For example, you can
-// provide i32 and Add and receive the specific opcode for a 32-bit addition,
-// AddInt32.
-// If the op does not exist, it returns Invalid.
+// Provide a wasm type and an abstract op and get the concrete one. For example,
+// you can provide i32 and Add and receive the specific opcode for a 32-bit
+// addition, AddInt32. If the op does not exist, it returns Invalid.
inline UnaryOp getUnary(Type type, Op op) {
switch (type) {
case i32: {
@@ -50,15 +61,19 @@ inline UnaryOp getUnary(Type type, Op op) {
}
case f32: {
switch (op) {
- case Neg: return NegFloat32;
- default: return InvalidUnary;
+ case Neg:
+ return NegFloat32;
+ default:
+ return InvalidUnary;
}
break;
}
case f64: {
switch (op) {
- case Neg: return NegFloat64;
- default: return InvalidUnary;
+ case Neg:
+ return NegFloat64;
+ default:
+ return InvalidUnary;
}
break;
}
@@ -78,69 +93,117 @@ inline BinaryOp getBinary(Type type, Op op) {
switch (type) {
case i32: {
switch (op) {
- case Add: return AddInt32;
- case Sub: return SubInt32;
- case Mul: return MulInt32;
- case DivU: return DivUInt32;
- case DivS: return DivSInt32;
- case RemU: return RemUInt32;
- case RemS: return RemSInt32;
- case Shl: return ShlInt32;
- case ShrU: return ShrUInt32;
- case ShrS: return ShrSInt32;
- case And: return AndInt32;
- case Or: return OrInt32;
- case Xor: return XorInt32;
- case Eq: return EqInt32;
- case Ne: return NeInt32;
- default: return InvalidBinary;
+ case Add:
+ return AddInt32;
+ case Sub:
+ return SubInt32;
+ case Mul:
+ return MulInt32;
+ case DivU:
+ return DivUInt32;
+ case DivS:
+ return DivSInt32;
+ case RemU:
+ return RemUInt32;
+ case RemS:
+ return RemSInt32;
+ case Shl:
+ return ShlInt32;
+ case ShrU:
+ return ShrUInt32;
+ case ShrS:
+ return ShrSInt32;
+ case And:
+ return AndInt32;
+ case Or:
+ return OrInt32;
+ case Xor:
+ return XorInt32;
+ case Eq:
+ return EqInt32;
+ case Ne:
+ return NeInt32;
+ default:
+ return InvalidBinary;
}
break;
}
case i64: {
switch (op) {
- case Add: return AddInt64;
- case Sub: return SubInt64;
- case Mul: return MulInt64;
- case DivU: return DivUInt64;
- case DivS: return DivSInt64;
- case RemU: return RemUInt64;
- case RemS: return RemSInt64;
- case Shl: return ShlInt64;
- case ShrU: return ShrUInt64;
- case ShrS: return ShrSInt64;
- case And: return AndInt64;
- case Or: return OrInt64;
- case Xor: return XorInt64;
- case Eq: return EqInt64;
- case Ne: return NeInt64;
- default: return InvalidBinary;
+ case Add:
+ return AddInt64;
+ case Sub:
+ return SubInt64;
+ case Mul:
+ return MulInt64;
+ case DivU:
+ return DivUInt64;
+ case DivS:
+ return DivSInt64;
+ case RemU:
+ return RemUInt64;
+ case RemS:
+ return RemSInt64;
+ case Shl:
+ return ShlInt64;
+ case ShrU:
+ return ShrUInt64;
+ case ShrS:
+ return ShrSInt64;
+ case And:
+ return AndInt64;
+ case Or:
+ return OrInt64;
+ case Xor:
+ return XorInt64;
+ case Eq:
+ return EqInt64;
+ case Ne:
+ return NeInt64;
+ default:
+ return InvalidBinary;
}
break;
}
case f32: {
switch (op) {
- case Add: return AddFloat32;
- case Sub: return SubFloat32;
- case Mul: return MulFloat32;
- case DivU: return DivFloat32;
- case DivS: return DivFloat32;
- case Eq: return EqFloat32;
- case Ne: return NeFloat32;
- default: return InvalidBinary;
+ case Add:
+ return AddFloat32;
+ case Sub:
+ return SubFloat32;
+ case Mul:
+ return MulFloat32;
+ case DivU:
+ return DivFloat32;
+ case DivS:
+ return DivFloat32;
+ case Eq:
+ return EqFloat32;
+ case Ne:
+ return NeFloat32;
+ default:
+ return InvalidBinary;
}
break;
}
case f64: {
switch (op) {
- case Add: return AddFloat64;
- case Sub: return SubFloat64;
- case Mul: return MulFloat64;
- case DivU: return DivFloat64;
- case DivS: return DivFloat64;
- case Eq: return EqFloat64;
- case Ne: return NeFloat64;
- default: return InvalidBinary;
+ case Add:
+ return AddFloat64;
+ case Sub:
+ return SubFloat64;
+ case Mul:
+ return MulFloat64;
+ case DivU:
+ return DivFloat64;
+ case DivS:
+ return DivFloat64;
+ case Eq:
+ return EqFloat64;
+ case Ne:
+ return NeFloat64;
+ default:
+ return InvalidBinary;
}
break;
}
diff --git a/src/ir/bits.h b/src/ir/bits.h
index ec33c4b11..a2b8fcde4 100644
--- a/src/ir/bits.h
+++ b/src/ir/bits.h
@@ -17,9 +17,9 @@
#ifndef wasm_ir_bits_h
#define wasm_ir_bits_h
+#include "ir/literal-utils.h"
#include "support/bits.h"
#include "wasm-builder.h"
-#include "ir/literal-utils.h"
namespace wasm {
@@ -27,17 +27,23 @@ struct Bits {
// get a mask to keep only the low # of bits
static int32_t lowBitMask(int32_t bits) {
uint32_t ret = -1;
- if (bits >= 32) return ret;
+ if (bits >= 32)
+ return ret;
return ret >> (32 - bits);
}
- // checks if the input is a mask of lower bits, i.e., all 1s up to some high bit, and all zeros
- // from there. returns the number of masked bits, or 0 if this is not such a mask
+ // checks if the input is a mask of lower bits, i.e., all 1s up to some high
+ // bit, and all zeros from there. returns the number of masked bits, or 0 if
+ // this is not such a mask
static uint32_t getMaskedBits(uint32_t mask) {
- if (mask == uint32_t(-1)) return 32; // all the bits
- if (mask == 0) return 0; // trivially not a mask
- // otherwise, see if adding one turns this into a 1-bit thing, 00011111 + 1 => 00100000
- if (PopCount(mask + 1) != 1) return 0;
+ if (mask == uint32_t(-1))
+ return 32; // all the bits
+ if (mask == 0)
+ return 0; // trivially not a mask
+ // otherwise, see if adding one turns this into a 1-bit thing, 00011111 + 1
+ // => 00100000
+ if (PopCount(mask + 1) != 1)
+ return 0;
// this is indeed a mask
return 32 - CountLeadingZeroes(mask);
}
@@ -71,12 +77,8 @@ struct Bits {
return builder.makeBinary(
ShrSInt32,
builder.makeBinary(
- ShlInt32,
- value,
- LiteralUtils::makeFromInt32(shifts, i32, wasm)
- ),
- LiteralUtils::makeFromInt32(shifts, i32, wasm)
- );
+ ShlInt32, value, LiteralUtils::makeFromInt32(shifts, i32, wasm)),
+ LiteralUtils::makeFromInt32(shifts, i32, wasm));
}
assert(bytes == 4);
return value; // nothing to do
@@ -88,12 +90,8 @@ struct Bits {
return builder.makeBinary(
ShrSInt64,
builder.makeBinary(
- ShlInt64,
- value,
- LiteralUtils::makeFromInt32(shifts, i64, wasm)
- ),
- LiteralUtils::makeFromInt32(shifts, i64, wasm)
- );
+ ShlInt64, value, LiteralUtils::makeFromInt32(shifts, i64, wasm)),
+ LiteralUtils::makeFromInt32(shifts, i64, wasm));
}
assert(bytes == 8);
return value; // nothing to do
@@ -104,4 +102,3 @@ struct Bits {
} // namespace wasm
#endif // wasm_ir_bits_h
-
diff --git a/src/ir/block-utils.h b/src/ir/block-utils.h
index 968332212..120178a47 100644
--- a/src/ir/block-utils.h
+++ b/src/ir/block-utils.h
@@ -17,51 +17,57 @@
#ifndef wasm_ir_block_h
#define wasm_ir_block_h
-#include "literal.h"
-#include "wasm.h"
#include "ir/branch-utils.h"
#include "ir/effects.h"
+#include "ir/manipulation.h"
+#include "literal.h"
+#include "wasm-builder.h"
+#include "wasm.h"
namespace wasm {
namespace BlockUtils {
- // if a block has just one element, it can often be replaced
- // with that content
- template<typename T>
- inline Expression* simplifyToContents(Block* block, T* parent, bool allowTypeChange = false) {
- auto& list = block->list;
- if (list.size() == 1 && !BranchUtils::BranchSeeker::hasNamed(list[0], block->name)) {
- // just one element. try to replace the block
- auto* singleton = list[0];
- auto sideEffects = EffectAnalyzer(parent->getPassOptions(), singleton).hasSideEffects();
- if (!sideEffects && !isConcreteType(singleton->type)) {
- // no side effects, and singleton is not returning a value, so we can throw away
- // the block and its contents, basically
- return Builder(*parent->getModule()).replaceWithIdenticalType(block);
- } else if (block->type == singleton->type || allowTypeChange) {
- return singleton;
- } else {
- // (side effects +) type change, must be block with declared value but inside is unreachable
- // (if both concrete, must match, and since no name on block, we can't be
- // branched to, so if singleton is unreachable, so is the block)
- assert(isConcreteType(block->type) && singleton->type == unreachable);
- // we could replace with unreachable, but would need to update all
- // the parent's types
- }
- } else if (list.size() == 0) {
- ExpressionManipulator::nop(block);
+// if a block has just one element, it can often be replaced
+// with that content
+template<typename T>
+inline Expression*
+simplifyToContents(Block* block, T* parent, bool allowTypeChange = false) {
+ auto& list = block->list;
+ if (list.size() == 1 &&
+ !BranchUtils::BranchSeeker::hasNamed(list[0], block->name)) {
+ // just one element. try to replace the block
+ auto* singleton = list[0];
+ auto sideEffects =
+ EffectAnalyzer(parent->getPassOptions(), singleton).hasSideEffects();
+ if (!sideEffects && !isConcreteType(singleton->type)) {
+ // no side effects, and singleton is not returning a value, so we can
+ // throw away the block and its contents, basically
+ return Builder(*parent->getModule()).replaceWithIdenticalType(block);
+ } else if (block->type == singleton->type || allowTypeChange) {
+ return singleton;
+ } else {
+ // (side effects +) type change, must be block with declared value but
+ // inside is unreachable (if both concrete, must match, and since no name
+ // on block, we can't be branched to, so if singleton is unreachable, so
+ // is the block)
+ assert(isConcreteType(block->type) && singleton->type == unreachable);
+ // we could replace with unreachable, but would need to update all
+ // the parent's types
}
- return block;
+ } else if (list.size() == 0) {
+ ExpressionManipulator::nop(block);
}
+ return block;
+}
- // similar, but when we allow the type to change while doing so
- template<typename T>
- inline Expression* simplifyToContentsWithPossibleTypeChange(Block* block, T* parent) {
- return simplifyToContents(block, parent, true);
- }
+// similar, but when we allow the type to change while doing so
+template<typename T>
+inline Expression* simplifyToContentsWithPossibleTypeChange(Block* block,
+ T* parent) {
+ return simplifyToContents(block, parent, true);
}
+} // namespace BlockUtils
} // namespace wasm
#endif // wasm_ir_block_h
-
diff --git a/src/ir/branch-utils.h b/src/ir/branch-utils.h
index b9448e590..f62941e15 100644
--- a/src/ir/branch-utils.h
+++ b/src/ir/branch-utils.h
@@ -17,23 +17,24 @@
#ifndef wasm_ir_branch_h
#define wasm_ir_branch_h
-#include "wasm.h"
#include "wasm-traversal.h"
+#include "wasm.h"
namespace wasm {
namespace BranchUtils {
-// Some branches are obviously not actually reachable (e.g. (br $out (unreachable)))
+// Some branches are obviously not actually reachable (e.g. (br $out
+// (unreachable)))
inline bool isBranchReachable(Break* br) {
- return !(br->value && br->value->type == unreachable) &&
+ return !(br->value && br->value->type == unreachable) &&
!(br->condition && br->condition->type == unreachable);
}
inline bool isBranchReachable(Switch* sw) {
- return !(sw->value && sw->value->type == unreachable) &&
- sw->condition->type != unreachable;
+ return !(sw->value && sw->value->type == unreachable) &&
+ sw->condition->type != unreachable;
}
inline bool isBranchReachable(Expression* expr) {
@@ -91,9 +92,7 @@ inline std::set<Name> getExitingBranches(Expression* ast) {
struct Scanner : public PostWalker<Scanner> {
std::set<Name> targets;
- void visitBreak(Break* curr) {
- targets.insert(curr->name);
- }
+ void visitBreak(Break* curr) { targets.insert(curr->name); }
void visitSwitch(Switch* curr) {
for (auto target : curr->targets) {
targets.insert(target);
@@ -156,36 +155,47 @@ struct BranchSeeker : public PostWalker<BranchSeeker> {
void noteFound(Expression* value) {
found++;
- if (found == 1) valueType = unreachable;
- if (!value) valueType = none;
- else if (value->type != unreachable) valueType = value->type;
+ if (found == 1)
+ valueType = unreachable;
+ if (!value)
+ valueType = none;
+ else if (value->type != unreachable)
+ valueType = value->type;
}
- void visitBreak(Break *curr) {
+ void visitBreak(Break* curr) {
if (!named) {
// ignore an unreachable break
- if (curr->condition && curr->condition->type == unreachable) return;
- if (curr->value && curr->value->type == unreachable) return;
+ if (curr->condition && curr->condition->type == unreachable)
+ return;
+ if (curr->value && curr->value->type == unreachable)
+ return;
}
// check the break
- if (curr->name == target) noteFound(curr->value);
+ if (curr->name == target)
+ noteFound(curr->value);
}
- void visitSwitch(Switch *curr) {
+ void visitSwitch(Switch* curr) {
if (!named) {
// ignore an unreachable switch
- if (curr->condition->type == unreachable) return;
- if (curr->value && curr->value->type == unreachable) return;
+ if (curr->condition->type == unreachable)
+ return;
+ if (curr->value && curr->value->type == unreachable)
+ return;
}
// check the switch
for (auto name : curr->targets) {
- if (name == target) noteFound(curr->value);
+ if (name == target)
+ noteFound(curr->value);
}
- if (curr->default_ == target) noteFound(curr->value);
+ if (curr->default_ == target)
+ noteFound(curr->value);
}
static bool hasReachable(Expression* tree, Name target) {
- if (!target.is()) return false;
+ if (!target.is())
+ return false;
BranchSeeker seeker(target);
seeker.named = false;
seeker.walk(tree);
@@ -193,7 +203,8 @@ struct BranchSeeker : public PostWalker<BranchSeeker> {
}
static Index countReachable(Expression* tree, Name target) {
- if (!target.is()) return 0;
+ if (!target.is())
+ return 0;
BranchSeeker seeker(target);
seeker.named = false;
seeker.walk(tree);
@@ -201,14 +212,16 @@ struct BranchSeeker : public PostWalker<BranchSeeker> {
}
static bool hasNamed(Expression* tree, Name target) {
- if (!target.is()) return false;
+ if (!target.is())
+ return false;
BranchSeeker seeker(target);
seeker.walk(tree);
return seeker.found > 0;
}
static Index countNamed(Expression* tree, Name target) {
- if (!target.is()) return 0;
+ if (!target.is())
+ return 0;
BranchSeeker seeker(target);
seeker.walk(tree);
return seeker.found;
@@ -220,4 +233,3 @@ struct BranchSeeker : public PostWalker<BranchSeeker> {
} // namespace wasm
#endif // wasm_ir_branch_h
-
diff --git a/src/ir/cost.h b/src/ir/cost.h
index 5179f80b1..95c2178d9 100644
--- a/src/ir/cost.h
+++ b/src/ir/cost.h
@@ -17,35 +17,31 @@
#ifndef wasm_ir_cost_h
#define wasm_ir_cost_h
-#include <wasm.h>
#include <wasm-traversal.h>
+#include <wasm.h>
namespace wasm {
// Measure the execution cost of an AST. Very handwave-ey
struct CostAnalyzer : public Visitor<CostAnalyzer, Index> {
- CostAnalyzer(Expression* ast) {
- cost = visit(ast);
- }
+ CostAnalyzer(Expression* ast) { cost = visit(ast); }
Index cost;
- Index maybeVisit(Expression* curr) {
- return curr ? visit(curr) : 0;
- }
+ Index maybeVisit(Expression* curr) { return curr ? visit(curr) : 0; }
Index visitBlock(Block* curr) {
Index ret = 0;
- for (auto* child : curr->list) ret += visit(child);
+ for (auto* child : curr->list)
+ ret += visit(child);
return ret;
}
Index visitIf(If* curr) {
- return 1 + visit(curr->condition) + std::max(visit(curr->ifTrue), maybeVisit(curr->ifFalse));
- }
- Index visitLoop(Loop* curr) {
- return 5 * visit(curr->body);
+ return 1 + visit(curr->condition) +
+ std::max(visit(curr->ifTrue), maybeVisit(curr->ifFalse));
}
+ Index visitLoop(Loop* curr) { return 5 * visit(curr->body); }
Index visitBreak(Break* curr) {
return 1 + maybeVisit(curr->value) + maybeVisit(curr->condition);
}
@@ -56,41 +52,29 @@ struct CostAnalyzer : public Visitor<CostAnalyzer, Index> {
// XXX this does not take into account if the call is to an import, which
// may be costlier in general
Index ret = 4;
- for (auto* child : curr->operands) ret += visit(child);
+ for (auto* child : curr->operands)
+ ret += visit(child);
return ret;
}
Index visitCallIndirect(CallIndirect* curr) {
Index ret = 6 + visit(curr->target);
- for (auto* child : curr->operands) ret += visit(child);
+ for (auto* child : curr->operands)
+ ret += visit(child);
return ret;
}
- Index visitGetLocal(GetLocal* curr) {
- return 0;
- }
- Index visitSetLocal(SetLocal* curr) {
- return 1;
- }
- Index visitGetGlobal(GetGlobal* curr) {
- return 1;
- }
- Index visitSetGlobal(SetGlobal* curr) {
- return 2;
- }
+ Index visitGetLocal(GetLocal* curr) { return 0; }
+ Index visitSetLocal(SetLocal* curr) { return 1; }
+ Index visitGetGlobal(GetGlobal* curr) { return 1; }
+ Index visitSetGlobal(SetGlobal* curr) { return 2; }
Index visitLoad(Load* curr) {
return 1 + visit(curr->ptr) + 10 * curr->isAtomic;
}
Index visitStore(Store* curr) {
return 2 + visit(curr->ptr) + visit(curr->value) + 10 * curr->isAtomic;
}
- Index visitAtomicRMW(AtomicRMW* curr) {
- return 100;
- }
- Index visitAtomicCmpxchg(AtomicCmpxchg* curr) {
- return 100;
- }
- Index visitConst(Const* curr) {
- return 1;
- }
+ Index visitAtomicRMW(AtomicRMW* curr) { return 100; }
+ Index visitAtomicCmpxchg(AtomicCmpxchg* curr) { return 100; }
+ Index visitConst(Const* curr) { return 1; }
Index visitUnary(Unary* curr) {
Index ret = 0;
switch (curr->op) {
@@ -151,9 +135,13 @@ struct CostAnalyzer : public Visitor<CostAnalyzer, Index> {
case TruncSatSFloat32ToInt64:
case TruncSatUFloat32ToInt64:
case TruncSatSFloat64ToInt64:
- case TruncSatUFloat64ToInt64: ret = 1; break;
+ case TruncSatUFloat64ToInt64:
+ ret = 1;
+ break;
case SqrtFloat32:
- case SqrtFloat64: ret = 2; break;
+ case SqrtFloat64:
+ ret = 2;
+ break;
case SplatVecI8x16:
case SplatVecI16x8:
case SplatVecI32x4:
@@ -186,188 +174,486 @@ struct CostAnalyzer : public Visitor<CostAnalyzer, Index> {
case ConvertSVecI32x4ToVecF32x4:
case ConvertUVecI32x4ToVecF32x4:
case ConvertSVecI64x2ToVecF64x2:
- case ConvertUVecI64x2ToVecF64x2: return 1;
- case InvalidUnary: WASM_UNREACHABLE();
+ case ConvertUVecI64x2ToVecF64x2:
+ return 1;
+ case InvalidUnary:
+ WASM_UNREACHABLE();
}
return ret + visit(curr->value);
}
Index visitBinary(Binary* curr) {
Index ret = 0;
switch (curr->op) {
- case AddInt32: ret = 1; break;
- case SubInt32: ret = 1; break;
- case MulInt32: ret = 2; break;
- case DivSInt32: ret = 3; break;
- case DivUInt32: ret = 3; break;
- case RemSInt32: ret = 3; break;
- case RemUInt32: ret = 3; break;
- case AndInt32: ret = 1; break;
- case OrInt32: ret = 1; break;
- case XorInt32: ret = 1; break;
- case ShlInt32: ret = 1; break;
- case ShrUInt32: ret = 1; break;
- case ShrSInt32: ret = 1; break;
- case RotLInt32: ret = 1; break;
- case RotRInt32: ret = 1; break;
- case AddInt64: ret = 1; break;
- case SubInt64: ret = 1; break;
- case MulInt64: ret = 2; break;
- case DivSInt64: ret = 3; break;
- case DivUInt64: ret = 3; break;
- case RemSInt64: ret = 3; break;
- case RemUInt64: ret = 3; break;
- case AndInt64: ret = 1; break;
- case OrInt64: ret = 1; break;
- case XorInt64: ret = 1; break;
- case ShlInt64: ret = 1; break;
- case ShrUInt64: ret = 1; break;
- case ShrSInt64: ret = 1; break;
- case RotLInt64: ret = 1; break;
- case RotRInt64: ret = 1; break;
- case AddFloat32: ret = 1; break;
- case SubFloat32: ret = 1; break;
- case MulFloat32: ret = 2; break;
- case DivFloat32: ret = 3; break;
- case CopySignFloat32: ret = 1; break;
- case MinFloat32: ret = 1; break;
- case MaxFloat32: ret = 1; break;
- case AddFloat64: ret = 1; break;
- case SubFloat64: ret = 1; break;
- case MulFloat64: ret = 2; break;
- case DivFloat64: ret = 3; break;
- case CopySignFloat64: ret = 1; break;
- case MinFloat64: ret = 1; break;
- case MaxFloat64: ret = 1; break;
- case LtUInt32: ret = 1; break;
- case LtSInt32: ret = 1; break;
- case LeUInt32: ret = 1; break;
- case LeSInt32: ret = 1; break;
- case GtUInt32: ret = 1; break;
- case GtSInt32: ret = 1; break;
- case GeUInt32: ret = 1; break;
- case GeSInt32: ret = 1; break;
- case LtUInt64: ret = 1; break;
- case LtSInt64: ret = 1; break;
- case LeUInt64: ret = 1; break;
- case LeSInt64: ret = 1; break;
- case GtUInt64: ret = 1; break;
- case GtSInt64: ret = 1; break;
- case GeUInt64: ret = 1; break;
- case GeSInt64: ret = 1; break;
- case LtFloat32: ret = 1; break;
- case GtFloat32: ret = 1; break;
- case LeFloat32: ret = 1; break;
- case GeFloat32: ret = 1; break;
- case LtFloat64: ret = 1; break;
- case GtFloat64: ret = 1; break;
- case LeFloat64: ret = 1; break;
- case GeFloat64: ret = 1; break;
- case EqInt32: ret = 1; break;
- case NeInt32: ret = 1; break;
- case EqInt64: ret = 1; break;
- case NeInt64: ret = 1; break;
- case EqFloat32: ret = 1; break;
- case NeFloat32: ret = 1; break;
- case EqFloat64: ret = 1; break;
- case NeFloat64: ret = 1; break;
- case EqVecI8x16: ret = 1; break;
- case NeVecI8x16: ret = 1; break;
- case LtSVecI8x16: ret = 1; break;
- case LtUVecI8x16: ret = 1; break;
- case LeSVecI8x16: ret = 1; break;
- case LeUVecI8x16: ret = 1; break;
- case GtSVecI8x16: ret = 1; break;
- case GtUVecI8x16: ret = 1; break;
- case GeSVecI8x16: ret = 1; break;
- case GeUVecI8x16: ret = 1; break;
- case EqVecI16x8: ret = 1; break;
- case NeVecI16x8: ret = 1; break;
- case LtSVecI16x8: ret = 1; break;
- case LtUVecI16x8: ret = 1; break;
- case LeSVecI16x8: ret = 1; break;
- case LeUVecI16x8: ret = 1; break;
- case GtSVecI16x8: ret = 1; break;
- case GtUVecI16x8: ret = 1; break;
- case GeSVecI16x8: ret = 1; break;
- case GeUVecI16x8: ret = 1; break;
- case EqVecI32x4: ret = 1; break;
- case NeVecI32x4: ret = 1; break;
- case LtSVecI32x4: ret = 1; break;
- case LtUVecI32x4: ret = 1; break;
- case LeSVecI32x4: ret = 1; break;
- case LeUVecI32x4: ret = 1; break;
- case GtSVecI32x4: ret = 1; break;
- case GtUVecI32x4: ret = 1; break;
- case GeSVecI32x4: ret = 1; break;
- case GeUVecI32x4: ret = 1; break;
- case EqVecF32x4: ret = 1; break;
- case NeVecF32x4: ret = 1; break;
- case LtVecF32x4: ret = 1; break;
- case LeVecF32x4: ret = 1; break;
- case GtVecF32x4: ret = 1; break;
- case GeVecF32x4: ret = 1; break;
- case EqVecF64x2: ret = 1; break;
- case NeVecF64x2: ret = 1; break;
- case LtVecF64x2: ret = 1; break;
- case LeVecF64x2: ret = 1; break;
- case GtVecF64x2: ret = 1; break;
- case GeVecF64x2: ret = 1; break;
- case AndVec128: ret = 1; break;
- case OrVec128: ret = 1; break;
- case XorVec128: ret = 1; break;
- case AddVecI8x16: ret = 1; break;
- case AddSatSVecI8x16: ret = 1; break;
- case AddSatUVecI8x16: ret = 1; break;
- case SubVecI8x16: ret = 1; break;
- case SubSatSVecI8x16: ret = 1; break;
- case SubSatUVecI8x16: ret = 1; break;
- case MulVecI8x16: ret = 2; break;
- case AddVecI16x8: ret = 1; break;
- case AddSatSVecI16x8: ret = 1; break;
- case AddSatUVecI16x8: ret = 1; break;
- case SubVecI16x8: ret = 1; break;
- case SubSatSVecI16x8: ret = 1; break;
- case SubSatUVecI16x8: ret = 1; break;
- case MulVecI16x8: ret = 2; break;
- case AddVecI32x4: ret = 1; break;
- case SubVecI32x4: ret = 1; break;
- case MulVecI32x4: ret = 2; break;
- case AddVecI64x2: ret = 1; break;
- case SubVecI64x2: ret = 1; break;
- case AddVecF32x4: ret = 1; break;
- case SubVecF32x4: ret = 1; break;
- case MulVecF32x4: ret = 2; break;
- case DivVecF32x4: ret = 3; break;
- case MinVecF32x4: ret = 1; break;
- case MaxVecF32x4: ret = 1; break;
- case AddVecF64x2: ret = 1; break;
- case SubVecF64x2: ret = 1; break;
- case MulVecF64x2: ret = 2; break;
- case DivVecF64x2: ret = 3; break;
- case MinVecF64x2: ret = 1; break;
- case MaxVecF64x2: ret = 1; break;
- case InvalidBinary: WASM_UNREACHABLE();
+ case AddInt32:
+ ret = 1;
+ break;
+ case SubInt32:
+ ret = 1;
+ break;
+ case MulInt32:
+ ret = 2;
+ break;
+ case DivSInt32:
+ ret = 3;
+ break;
+ case DivUInt32:
+ ret = 3;
+ break;
+ case RemSInt32:
+ ret = 3;
+ break;
+ case RemUInt32:
+ ret = 3;
+ break;
+ case AndInt32:
+ ret = 1;
+ break;
+ case OrInt32:
+ ret = 1;
+ break;
+ case XorInt32:
+ ret = 1;
+ break;
+ case ShlInt32:
+ ret = 1;
+ break;
+ case ShrUInt32:
+ ret = 1;
+ break;
+ case ShrSInt32:
+ ret = 1;
+ break;
+ case RotLInt32:
+ ret = 1;
+ break;
+ case RotRInt32:
+ ret = 1;
+ break;
+ case AddInt64:
+ ret = 1;
+ break;
+ case SubInt64:
+ ret = 1;
+ break;
+ case MulInt64:
+ ret = 2;
+ break;
+ case DivSInt64:
+ ret = 3;
+ break;
+ case DivUInt64:
+ ret = 3;
+ break;
+ case RemSInt64:
+ ret = 3;
+ break;
+ case RemUInt64:
+ ret = 3;
+ break;
+ case AndInt64:
+ ret = 1;
+ break;
+ case OrInt64:
+ ret = 1;
+ break;
+ case XorInt64:
+ ret = 1;
+ break;
+ case ShlInt64:
+ ret = 1;
+ break;
+ case ShrUInt64:
+ ret = 1;
+ break;
+ case ShrSInt64:
+ ret = 1;
+ break;
+ case RotLInt64:
+ ret = 1;
+ break;
+ case RotRInt64:
+ ret = 1;
+ break;
+ case AddFloat32:
+ ret = 1;
+ break;
+ case SubFloat32:
+ ret = 1;
+ break;
+ case MulFloat32:
+ ret = 2;
+ break;
+ case DivFloat32:
+ ret = 3;
+ break;
+ case CopySignFloat32:
+ ret = 1;
+ break;
+ case MinFloat32:
+ ret = 1;
+ break;
+ case MaxFloat32:
+ ret = 1;
+ break;
+ case AddFloat64:
+ ret = 1;
+ break;
+ case SubFloat64:
+ ret = 1;
+ break;
+ case MulFloat64:
+ ret = 2;
+ break;
+ case DivFloat64:
+ ret = 3;
+ break;
+ case CopySignFloat64:
+ ret = 1;
+ break;
+ case MinFloat64:
+ ret = 1;
+ break;
+ case MaxFloat64:
+ ret = 1;
+ break;
+ case LtUInt32:
+ ret = 1;
+ break;
+ case LtSInt32:
+ ret = 1;
+ break;
+ case LeUInt32:
+ ret = 1;
+ break;
+ case LeSInt32:
+ ret = 1;
+ break;
+ case GtUInt32:
+ ret = 1;
+ break;
+ case GtSInt32:
+ ret = 1;
+ break;
+ case GeUInt32:
+ ret = 1;
+ break;
+ case GeSInt32:
+ ret = 1;
+ break;
+ case LtUInt64:
+ ret = 1;
+ break;
+ case LtSInt64:
+ ret = 1;
+ break;
+ case LeUInt64:
+ ret = 1;
+ break;
+ case LeSInt64:
+ ret = 1;
+ break;
+ case GtUInt64:
+ ret = 1;
+ break;
+ case GtSInt64:
+ ret = 1;
+ break;
+ case GeUInt64:
+ ret = 1;
+ break;
+ case GeSInt64:
+ ret = 1;
+ break;
+ case LtFloat32:
+ ret = 1;
+ break;
+ case GtFloat32:
+ ret = 1;
+ break;
+ case LeFloat32:
+ ret = 1;
+ break;
+ case GeFloat32:
+ ret = 1;
+ break;
+ case LtFloat64:
+ ret = 1;
+ break;
+ case GtFloat64:
+ ret = 1;
+ break;
+ case LeFloat64:
+ ret = 1;
+ break;
+ case GeFloat64:
+ ret = 1;
+ break;
+ case EqInt32:
+ ret = 1;
+ break;
+ case NeInt32:
+ ret = 1;
+ break;
+ case EqInt64:
+ ret = 1;
+ break;
+ case NeInt64:
+ ret = 1;
+ break;
+ case EqFloat32:
+ ret = 1;
+ break;
+ case NeFloat32:
+ ret = 1;
+ break;
+ case EqFloat64:
+ ret = 1;
+ break;
+ case NeFloat64:
+ ret = 1;
+ break;
+ case EqVecI8x16:
+ ret = 1;
+ break;
+ case NeVecI8x16:
+ ret = 1;
+ break;
+ case LtSVecI8x16:
+ ret = 1;
+ break;
+ case LtUVecI8x16:
+ ret = 1;
+ break;
+ case LeSVecI8x16:
+ ret = 1;
+ break;
+ case LeUVecI8x16:
+ ret = 1;
+ break;
+ case GtSVecI8x16:
+ ret = 1;
+ break;
+ case GtUVecI8x16:
+ ret = 1;
+ break;
+ case GeSVecI8x16:
+ ret = 1;
+ break;
+ case GeUVecI8x16:
+ ret = 1;
+ break;
+ case EqVecI16x8:
+ ret = 1;
+ break;
+ case NeVecI16x8:
+ ret = 1;
+ break;
+ case LtSVecI16x8:
+ ret = 1;
+ break;
+ case LtUVecI16x8:
+ ret = 1;
+ break;
+ case LeSVecI16x8:
+ ret = 1;
+ break;
+ case LeUVecI16x8:
+ ret = 1;
+ break;
+ case GtSVecI16x8:
+ ret = 1;
+ break;
+ case GtUVecI16x8:
+ ret = 1;
+ break;
+ case GeSVecI16x8:
+ ret = 1;
+ break;
+ case GeUVecI16x8:
+ ret = 1;
+ break;
+ case EqVecI32x4:
+ ret = 1;
+ break;
+ case NeVecI32x4:
+ ret = 1;
+ break;
+ case LtSVecI32x4:
+ ret = 1;
+ break;
+ case LtUVecI32x4:
+ ret = 1;
+ break;
+ case LeSVecI32x4:
+ ret = 1;
+ break;
+ case LeUVecI32x4:
+ ret = 1;
+ break;
+ case GtSVecI32x4:
+ ret = 1;
+ break;
+ case GtUVecI32x4:
+ ret = 1;
+ break;
+ case GeSVecI32x4:
+ ret = 1;
+ break;
+ case GeUVecI32x4:
+ ret = 1;
+ break;
+ case EqVecF32x4:
+ ret = 1;
+ break;
+ case NeVecF32x4:
+ ret = 1;
+ break;
+ case LtVecF32x4:
+ ret = 1;
+ break;
+ case LeVecF32x4:
+ ret = 1;
+ break;
+ case GtVecF32x4:
+ ret = 1;
+ break;
+ case GeVecF32x4:
+ ret = 1;
+ break;
+ case EqVecF64x2:
+ ret = 1;
+ break;
+ case NeVecF64x2:
+ ret = 1;
+ break;
+ case LtVecF64x2:
+ ret = 1;
+ break;
+ case LeVecF64x2:
+ ret = 1;
+ break;
+ case GtVecF64x2:
+ ret = 1;
+ break;
+ case GeVecF64x2:
+ ret = 1;
+ break;
+ case AndVec128:
+ ret = 1;
+ break;
+ case OrVec128:
+ ret = 1;
+ break;
+ case XorVec128:
+ ret = 1;
+ break;
+ case AddVecI8x16:
+ ret = 1;
+ break;
+ case AddSatSVecI8x16:
+ ret = 1;
+ break;
+ case AddSatUVecI8x16:
+ ret = 1;
+ break;
+ case SubVecI8x16:
+ ret = 1;
+ break;
+ case SubSatSVecI8x16:
+ ret = 1;
+ break;
+ case SubSatUVecI8x16:
+ ret = 1;
+ break;
+ case MulVecI8x16:
+ ret = 2;
+ break;
+ case AddVecI16x8:
+ ret = 1;
+ break;
+ case AddSatSVecI16x8:
+ ret = 1;
+ break;
+ case AddSatUVecI16x8:
+ ret = 1;
+ break;
+ case SubVecI16x8:
+ ret = 1;
+ break;
+ case SubSatSVecI16x8:
+ ret = 1;
+ break;
+ case SubSatUVecI16x8:
+ ret = 1;
+ break;
+ case MulVecI16x8:
+ ret = 2;
+ break;
+ case AddVecI32x4:
+ ret = 1;
+ break;
+ case SubVecI32x4:
+ ret = 1;
+ break;
+ case MulVecI32x4:
+ ret = 2;
+ break;
+ case AddVecI64x2:
+ ret = 1;
+ break;
+ case SubVecI64x2:
+ ret = 1;
+ break;
+ case AddVecF32x4:
+ ret = 1;
+ break;
+ case SubVecF32x4:
+ ret = 1;
+ break;
+ case MulVecF32x4:
+ ret = 2;
+ break;
+ case DivVecF32x4:
+ ret = 3;
+ break;
+ case MinVecF32x4:
+ ret = 1;
+ break;
+ case MaxVecF32x4:
+ ret = 1;
+ break;
+ case AddVecF64x2:
+ ret = 1;
+ break;
+ case SubVecF64x2:
+ ret = 1;
+ break;
+ case MulVecF64x2:
+ ret = 2;
+ break;
+ case DivVecF64x2:
+ ret = 3;
+ break;
+ case MinVecF64x2:
+ ret = 1;
+ break;
+ case MaxVecF64x2:
+ ret = 1;
+ break;
+ case InvalidBinary:
+ WASM_UNREACHABLE();
}
return ret + visit(curr->left) + visit(curr->right);
}
Index visitSelect(Select* curr) {
- return 2 + visit(curr->condition) + visit(curr->ifTrue) + visit(curr->ifFalse);
- }
- Index visitDrop(Drop* curr) {
- return visit(curr->value);
- }
- Index visitReturn(Return* curr) {
- return maybeVisit(curr->value);
- }
- Index visitHost(Host* curr) {
- return 100;
- }
- Index visitNop(Nop* curr) {
- return 0;
- }
- Index visitUnreachable(Unreachable* curr) {
- return 0;
+ return 2 + visit(curr->condition) + visit(curr->ifTrue) +
+ visit(curr->ifFalse);
}
+ Index visitDrop(Drop* curr) { return visit(curr->value); }
+ Index visitReturn(Return* curr) { return maybeVisit(curr->value); }
+ Index visitHost(Host* curr) { return 100; }
+ Index visitNop(Nop* curr) { return 0; }
+ Index visitUnreachable(Unreachable* curr) { return 0; }
};
} // namespace wasm
diff --git a/src/ir/effects.h b/src/ir/effects.h
index e1fa77af0..9a3f29d8a 100644
--- a/src/ir/effects.h
+++ b/src/ir/effects.h
@@ -17,31 +17,38 @@
#ifndef wasm_ir_effects_h
#define wasm_ir_effects_h
+#include "pass.h"
+#include "wasm-traversal.h"
+
namespace wasm {
// Look for side effects, including control flow
// TODO: optimize
-struct EffectAnalyzer : public PostWalker<EffectAnalyzer, OverriddenVisitor<EffectAnalyzer>> {
- EffectAnalyzer(PassOptions& passOptions, Expression *ast = nullptr) {
+struct EffectAnalyzer
+ : public PostWalker<EffectAnalyzer, OverriddenVisitor<EffectAnalyzer>> {
+ EffectAnalyzer(PassOptions& passOptions, Expression* ast = nullptr) {
ignoreImplicitTraps = passOptions.ignoreImplicitTraps;
debugInfo = passOptions.debugInfo;
- if (ast) analyze(ast);
+ if (ast)
+ analyze(ast);
}
bool ignoreImplicitTraps;
bool debugInfo;
- void analyze(Expression *ast) {
+ void analyze(Expression* ast) {
breakNames.clear();
walk(ast);
// if we are left with breaks, they are external
- if (breakNames.size() > 0) branches = true;
+ if (breakNames.size() > 0)
+ branches = true;
}
// Core effect tracking
- bool branches = false; // branches out of this expression, returns, infinite loops, etc
+ // branches out of this expression, returns, infinite loops, etc
+ bool branches = false;
bool calls = false;
std::set<Index> localsRead;
std::set<Index> localsWritten;
@@ -49,30 +56,46 @@ struct EffectAnalyzer : public PostWalker<EffectAnalyzer, OverriddenVisitor<Effe
std::set<Name> globalsWritten;
bool readsMemory = false;
bool writesMemory = false;
- bool implicitTrap = false; // a load or div/rem, which may trap. we ignore trap
- // differences, so it is ok to reorder these, but we can't
- // remove them, as they count as side effects, and we
- // can't move them in a way that would cause other noticeable
- // (global) side effects
- bool isAtomic = false; // An atomic load/store/RMW/Cmpxchg or an operator that
- // has a defined ordering wrt atomics (e.g. grow_memory)
+ // a load or div/rem, which may trap. we ignore trap differences, so it is ok
+ // to reorder these, but we can't remove them, as they count as side effects,
+ // and we can't move them in a way that would cause other noticeable (global)
+ // side effects
+ bool implicitTrap = false;
+ // An atomic load/store/RMW/Cmpxchg or an operator that has a defined ordering
+ // wrt atomics (e.g. grow_memory)
+ bool isAtomic = false;
// Helper functions to check for various effect types
- bool accessesLocal() const { return localsRead.size() + localsWritten.size() > 0; }
- bool accessesGlobal() const { return globalsRead.size() + globalsWritten.size() > 0; }
+ bool accessesLocal() const {
+ return localsRead.size() + localsWritten.size() > 0;
+ }
+ bool accessesGlobal() const {
+ return globalsRead.size() + globalsWritten.size() > 0;
+ }
bool accessesMemory() const { return calls || readsMemory || writesMemory; }
- bool hasGlobalSideEffects() const { return calls || globalsWritten.size() > 0 || writesMemory || isAtomic; }
- bool hasSideEffects() const { return hasGlobalSideEffects() || localsWritten.size() > 0 || branches || implicitTrap; }
- bool hasAnything() const { return branches || calls || accessesLocal() || readsMemory || writesMemory || accessesGlobal() || implicitTrap || isAtomic; }
+ bool hasGlobalSideEffects() const {
+ return calls || globalsWritten.size() > 0 || writesMemory || isAtomic;
+ }
+ bool hasSideEffects() const {
+ return hasGlobalSideEffects() || localsWritten.size() > 0 || branches ||
+ implicitTrap;
+ }
+ bool hasAnything() const {
+ return branches || calls || accessesLocal() || readsMemory ||
+ writesMemory || accessesGlobal() || implicitTrap || isAtomic;
+ }
- bool noticesGlobalSideEffects() { return calls || readsMemory || isAtomic || globalsRead.size(); }
+ bool noticesGlobalSideEffects() {
+ return calls || readsMemory || isAtomic || globalsRead.size();
+ }
// check if we break to anything external from ourselves
bool hasExternalBreakTargets() { return !breakNames.empty(); }
- // checks if these effects would invalidate another set (e.g., if we write, we invalidate someone that reads, they can't be moved past us)
+ // checks if these effects would invalidate another set (e.g., if we write, we
+ // invalidate someone that reads, they can't be moved past us)
bool invalidates(const EffectAnalyzer& other) {
if ((branches && other.hasSideEffects()) ||
(other.branches && hasSideEffects()) ||
@@ -92,25 +115,30 @@ struct EffectAnalyzer : public PostWalker<EffectAnalyzer, OverriddenVisitor<Effe
}
}
for (auto local : localsRead) {
- if (other.localsWritten.count(local)) return true;
+ if (other.localsWritten.count(local))
+ return true;
}
- if ((accessesGlobal() && other.calls) || (other.accessesGlobal() && calls)) {
+ if ((accessesGlobal() && other.calls) ||
+ (other.accessesGlobal() && calls)) {
return true;
}
for (auto global : globalsWritten) {
- if (other.globalsWritten.count(global) || other.globalsRead.count(global)) {
+ if (other.globalsWritten.count(global) ||
+ other.globalsRead.count(global)) {
return true;
}
}
for (auto global : globalsRead) {
- if (other.globalsWritten.count(global)) return true;
+ if (other.globalsWritten.count(global))
+ return true;
}
// we are ok to reorder implicit traps, but not conditionalize them
if ((implicitTrap && other.branches) || (other.implicitTrap && branches)) {
return true;
}
// we can't reorder an implicit trap in a way that alters global state
- if ((implicitTrap && other.hasGlobalSideEffects()) || (other.implicitTrap && hasGlobalSideEffects())) {
+ if ((implicitTrap && other.hasGlobalSideEffects()) ||
+ (other.implicitTrap && hasGlobalSideEffects())) {
return true;
}
return false;
@@ -123,14 +151,19 @@ struct EffectAnalyzer : public PostWalker<EffectAnalyzer, OverriddenVisitor<Effe
writesMemory = writesMemory || other.writesMemory;
implicitTrap = implicitTrap || other.implicitTrap;
isAtomic = isAtomic || other.isAtomic;
- for (auto i : other.localsRead) localsRead.insert(i);
- for (auto i : other.localsWritten) localsWritten.insert(i);
- for (auto i : other.globalsRead) globalsRead.insert(i);
- for (auto i : other.globalsWritten) globalsWritten.insert(i);
+ for (auto i : other.localsRead)
+ localsRead.insert(i);
+ for (auto i : other.localsWritten)
+ localsWritten.insert(i);
+ for (auto i : other.globalsRead)
+ globalsRead.insert(i);
+ for (auto i : other.globalsWritten)
+ globalsWritten.insert(i);
}
- // the checks above happen after the node's children were processed, in the order of execution
- // we must also check for control flow that happens before the children, i.e., loops
+ // the checks above happen after the node's children were processed, in the
+ // order of execution we must also check for control flow that happens before
+ // the children, i.e., loops
bool checkPre(Expression* curr) {
if (curr->is<Loop>()) {
branches = true;
@@ -150,35 +183,35 @@ struct EffectAnalyzer : public PostWalker<EffectAnalyzer, OverriddenVisitor<Effe
std::set<Name> breakNames;
void visitBlock(Block* curr) {
- if (curr->name.is()) breakNames.erase(curr->name); // these were internal breaks
+ if (curr->name.is())
+ breakNames.erase(curr->name); // these were internal breaks
}
void visitIf(If* curr) {}
void visitLoop(Loop* curr) {
- if (curr->name.is()) breakNames.erase(curr->name); // these were internal breaks
+ if (curr->name.is())
+ breakNames.erase(curr->name); // these were internal breaks
// if the loop is unreachable, then there is branching control flow:
- // (1) if the body is unreachable because of a (return), uncaught (br) etc., then we
- // already noted branching, so it is ok to mark it again (if we have *caught*
- // (br)s, then they did not lead to the loop body being unreachable).
- // (same logic applies to blocks)
- // (2) if the loop is unreachable because it only has branches up to the loop
- // top, but no way to get out, then it is an infinite loop, and we consider
- // that a branching side effect (note how the same logic does not apply to
- // blocks).
+ // (1) if the body is unreachable because of a (return), uncaught (br)
+ // etc., then we already noted branching, so it is ok to mark it again
+ // (if we have *caught* (br)s, then they did not lead to the loop body
+ // being unreachable). (same logic applies to blocks)
+ // (2) if the loop is unreachable because it only has branches up to the
+ // loop top, but no way to get out, then it is an infinite loop, and we
+ // consider that a branching side effect (note how the same logic does
+ // not apply to blocks).
if (curr->type == unreachable) {
branches = true;
}
}
- void visitBreak(Break *curr) {
- breakNames.insert(curr->name);
- }
- void visitSwitch(Switch *curr) {
+ void visitBreak(Break* curr) { breakNames.insert(curr->name); }
+ void visitSwitch(Switch* curr) {
for (auto name : curr->targets) {
breakNames.insert(name);
}
breakNames.insert(curr->default_);
}
- void visitCall(Call *curr) {
+ void visitCall(Call* curr) {
calls = true;
if (debugInfo) {
// debugInfo call imports must be preserved very strongly, do not
@@ -187,40 +220,36 @@ struct EffectAnalyzer : public PostWalker<EffectAnalyzer, OverriddenVisitor<Effe
branches = true;
}
}
- void visitCallIndirect(CallIndirect *curr) { calls = true; }
- void visitGetLocal(GetLocal *curr) {
- localsRead.insert(curr->index);
- }
- void visitSetLocal(SetLocal *curr) {
- localsWritten.insert(curr->index);
- }
- void visitGetGlobal(GetGlobal *curr) {
- globalsRead.insert(curr->name);
- }
- void visitSetGlobal(SetGlobal *curr) {
- globalsWritten.insert(curr->name);
- }
- void visitLoad(Load *curr) {
+ void visitCallIndirect(CallIndirect* curr) { calls = true; }
+ void visitGetLocal(GetLocal* curr) { localsRead.insert(curr->index); }
+ void visitSetLocal(SetLocal* curr) { localsWritten.insert(curr->index); }
+ void visitGetGlobal(GetGlobal* curr) { globalsRead.insert(curr->name); }
+ void visitSetGlobal(SetGlobal* curr) { globalsWritten.insert(curr->name); }
+ void visitLoad(Load* curr) {
readsMemory = true;
isAtomic |= curr->isAtomic;
- if (!ignoreImplicitTraps) implicitTrap = true;
+ if (!ignoreImplicitTraps)
+ implicitTrap = true;
}
- void visitStore(Store *curr) {
+ void visitStore(Store* curr) {
writesMemory = true;
isAtomic |= curr->isAtomic;
- if (!ignoreImplicitTraps) implicitTrap = true;
+ if (!ignoreImplicitTraps)
+ implicitTrap = true;
}
void visitAtomicRMW(AtomicRMW* curr) {
readsMemory = true;
writesMemory = true;
isAtomic = true;
- if (!ignoreImplicitTraps) implicitTrap = true;
+ if (!ignoreImplicitTraps)
+ implicitTrap = true;
}
void visitAtomicCmpxchg(AtomicCmpxchg* curr) {
readsMemory = true;
writesMemory = true;
isAtomic = true;
- if (!ignoreImplicitTraps) implicitTrap = true;
+ if (!ignoreImplicitTraps)
+ implicitTrap = true;
}
void visitAtomicWait(AtomicWait* curr) {
readsMemory = true;
@@ -229,16 +258,18 @@ struct EffectAnalyzer : public PostWalker<EffectAnalyzer, OverriddenVisitor<Effe
// write.
writesMemory = true;
isAtomic = true;
- if (!ignoreImplicitTraps) implicitTrap = true;
+ if (!ignoreImplicitTraps)
+ implicitTrap = true;
}
void visitAtomicNotify(AtomicNotify* curr) {
- // AtomicNotify doesn't strictly write memory, but it does modify the waiters
- // list associated with the specified address, which we can think of as a
- // write.
+ // AtomicNotify doesn't strictly write memory, but it does modify the
+ // waiters list associated with the specified address, which we can think of
+ // as a write.
readsMemory = true;
writesMemory = true;
isAtomic = true;
- if (!ignoreImplicitTraps) implicitTrap = true;
+ if (!ignoreImplicitTraps)
+ implicitTrap = true;
};
void visitSIMDExtract(SIMDExtract* curr) {}
void visitSIMDReplace(SIMDReplace* curr) {}
@@ -247,21 +278,25 @@ struct EffectAnalyzer : public PostWalker<EffectAnalyzer, OverriddenVisitor<Effe
void visitSIMDShift(SIMDShift* curr) {}
void visitMemoryInit(MemoryInit* curr) {
writesMemory = true;
- if (!ignoreImplicitTraps) implicitTrap = true;
+ if (!ignoreImplicitTraps)
+ implicitTrap = true;
}
void visitDataDrop(DataDrop* curr) {
// prevent reordering with memory.init
readsMemory = true;
- if (!ignoreImplicitTraps) implicitTrap = true;
+ if (!ignoreImplicitTraps)
+ implicitTrap = true;
}
void visitMemoryCopy(MemoryCopy* curr) {
readsMemory = true;
writesMemory = true;
- if (!ignoreImplicitTraps) implicitTrap = true;
+ if (!ignoreImplicitTraps)
+ implicitTrap = true;
}
void visitMemoryFill(MemoryFill* curr) {
writesMemory = true;
- if (!ignoreImplicitTraps) implicitTrap = true;
+ if (!ignoreImplicitTraps)
+ implicitTrap = true;
}
void visitConst(Const* curr) {}
void visitUnary(Unary* curr) {
@@ -302,20 +337,22 @@ struct EffectAnalyzer : public PostWalker<EffectAnalyzer, OverriddenVisitor<Effe
}
void visitSelect(Select* curr) {}
void visitDrop(Drop* curr) {}
- void visitReturn(Return *curr) { branches = true; }
- void visitHost(Host *curr) {
+ void visitReturn(Return* curr) { branches = true; }
+ void visitHost(Host* curr) {
calls = true;
- // grow_memory modifies the set of valid addresses, and thus can be modeled as modifying memory
+ // grow_memory modifies the set of valid addresses, and thus can be modeled
+ // as modifying memory
writesMemory = true;
// Atomics are also sequentially consistent with grow_memory.
isAtomic = true;
}
void visitNop(Nop* curr) {}
- void visitUnreachable(Unreachable *curr) { branches = true; }
+ void visitUnreachable(Unreachable* curr) { branches = true; }
// Helpers
- static bool canReorder(PassOptions& passOptions, Expression* a, Expression* b) {
+ static bool
+ canReorder(PassOptions& passOptions, Expression* a, Expression* b) {
EffectAnalyzer aEffects(passOptions, a);
EffectAnalyzer bEffects(passOptions, b);
return !aEffects.invalidates(bEffects);
diff --git a/src/ir/equivalent_sets.h b/src/ir/equivalent_sets.h
index dc3e348d2..fc4b1db3d 100644
--- a/src/ir/equivalent_sets.h
+++ b/src/ir/equivalent_sets.h
@@ -31,9 +31,7 @@ struct EquivalentSets {
std::unordered_map<Index, std::shared_ptr<Set>> indexSets;
// Clears the state completely, removing all equivalences.
- void clear() {
- indexSets.clear();
- }
+ void clear() { indexSets.clear(); }
// Resets an index, removing any equivalences between it and others.
void reset(Index index) {
@@ -69,7 +67,8 @@ struct EquivalentSets {
// Checks whether two indexes contain the same data.
bool check(Index a, Index b) {
- if (a == b) return true;
+ if (a == b)
+ return true;
if (auto* set = getEquivalents(a)) {
if (set->find(b) != set->end()) {
return true;
@@ -91,4 +90,3 @@ struct EquivalentSets {
} // namespace wasm
#endif // wasm_ir_equivalent_sets_h
-
diff --git a/src/ir/features.h b/src/ir/features.h
index 505e239a5..6dff96398 100644
--- a/src/ir/features.h
+++ b/src/ir/features.h
@@ -17,10 +17,10 @@
#ifndef wasm_ir_features_h
#define wasm_ir_features_h
-#include <wasm.h>
+#include <ir/iteration.h>
#include <wasm-binary.h>
#include <wasm-traversal.h>
-#include <ir/iteration.h>
+#include <wasm.h>
namespace wasm {
diff --git a/src/ir/find_all.h b/src/ir/find_all.h
index 44dc7a675..1abaab772 100644
--- a/src/ir/find_all.h
+++ b/src/ir/find_all.h
@@ -23,12 +23,12 @@ namespace wasm {
// Find all instances of a certain node type
-template<typename T>
-struct FindAll {
+template<typename T> struct FindAll {
std::vector<T*> list;
FindAll(Expression* ast) {
- struct Finder : public PostWalker<Finder, UnifiedExpressionVisitor<Finder>> {
+ struct Finder
+ : public PostWalker<Finder, UnifiedExpressionVisitor<Finder>> {
std::vector<T*>* list;
void visitExpression(Expression* curr) {
if (curr->is<T>()) {
@@ -44,7 +44,8 @@ struct FindAll {
// Find all pointers to instances of a certain node type
-struct PointerFinder : public PostWalker<PointerFinder, UnifiedExpressionVisitor<PointerFinder>> {
+struct PointerFinder
+ : public PostWalker<PointerFinder, UnifiedExpressionVisitor<PointerFinder>> {
Expression::Id id;
std::vector<Expression**>* list;
void visitExpression(Expression* curr) {
@@ -54,8 +55,7 @@ struct PointerFinder : public PostWalker<PointerFinder, UnifiedExpressionVisitor
}
};
-template<typename T>
-struct FindAllPointers {
+template<typename T> struct FindAllPointers {
std::vector<Expression**> list;
FindAllPointers(Expression* ast) {
@@ -69,4 +69,3 @@ struct FindAllPointers {
} // namespace wasm
#endif // wasm_ir_find_all_h
-
diff --git a/src/ir/flat.h b/src/ir/flat.h
index ed6178ef5..199d5e35e 100644
--- a/src/ir/flat.h
+++ b/src/ir/flat.h
@@ -55,8 +55,9 @@
#ifndef wasm_ir_flat_h
#define wasm_ir_flat_h
-#include "wasm-traversal.h"
#include "ir/iteration.h"
+#include "pass.h"
+#include "wasm-traversal.h"
namespace wasm {
@@ -67,23 +68,29 @@ inline bool isControlFlowStructure(Expression* curr) {
}
inline void verifyFlatness(Function* func) {
- struct VerifyFlatness : public PostWalker<VerifyFlatness, UnifiedExpressionVisitor<VerifyFlatness>> {
+ struct VerifyFlatness
+ : public PostWalker<VerifyFlatness,
+ UnifiedExpressionVisitor<VerifyFlatness>> {
void visitExpression(Expression* curr) {
if (isControlFlowStructure(curr)) {
- verify(!isConcreteType(curr->type), "control flow structures must not flow values");
+ verify(!isConcreteType(curr->type),
+ "control flow structures must not flow values");
} else if (curr->is<SetLocal>()) {
verify(!isConcreteType(curr->type), "tees are not allowed, only sets");
} else {
for (auto* child : ChildIterator(curr)) {
- verify(child->is<Const>() || child->is<GetLocal>() || child->is<Unreachable>(),
- "instructions must only have const, local.get, or unreachable as children");
+ verify(child->is<Const>() || child->is<GetLocal>() ||
+ child->is<Unreachable>(),
+ "instructions must only have const, local.get, or unreachable "
+ "as children");
}
}
}
void verify(bool condition, const char* message) {
if (!condition) {
- Fatal() << "IR must be flat: run --flatten beforehand (" << message << ", in " << getFunction()->name << ')';
+ Fatal() << "IR must be flat: run --flatten beforehand (" << message
+ << ", in " << getFunction()->name << ')';
}
}
};
@@ -91,20 +98,19 @@ inline void verifyFlatness(Function* func) {
VerifyFlatness verifier;
verifier.walkFunction(func);
verifier.setFunction(func);
- verifier.verify(!isConcreteType(func->body->type), "function bodies must not flow values");
+ verifier.verify(!isConcreteType(func->body->type),
+ "function bodies must not flow values");
}
inline void verifyFlatness(Module* module) {
- struct VerifyFlatness : public WalkerPass<PostWalker<VerifyFlatness, UnifiedExpressionVisitor<VerifyFlatness>>> {
+ struct VerifyFlatness
+ : public WalkerPass<
+ PostWalker<VerifyFlatness, UnifiedExpressionVisitor<VerifyFlatness>>> {
bool isFunctionParallel() override { return true; }
- VerifyFlatness* create() override {
- return new VerifyFlatness();
- }
+ VerifyFlatness* create() override { return new VerifyFlatness(); }
- void doVisitFunction(Function* func) {
- verifyFlatness(func);
- }
+ void doVisitFunction(Function* func) { verifyFlatness(func); }
};
PassRunner runner(module);
@@ -113,7 +119,7 @@ inline void verifyFlatness(Module* module) {
runner.run();
}
-} // namespace Fkat
+} // namespace Flat
} // namespace wasm
diff --git a/src/ir/function-type-utils.h b/src/ir/function-type-utils.h
index 3c98cb16b..ee1e95f70 100644
--- a/src/ir/function-type-utils.h
+++ b/src/ir/function-type-utils.h
@@ -17,7 +17,6 @@
#ifndef wasm_ir_function_type_utils_h
#define wasm_ir_function_type_utils_h
-
namespace wasm {
namespace FunctionTypeUtils {
diff --git a/src/ir/function-utils.h b/src/ir/function-utils.h
index 3895b33bf..446bcc8bb 100644
--- a/src/ir/function-utils.h
+++ b/src/ir/function-utils.h
@@ -17,8 +17,8 @@
#ifndef wasm_ir_function_h
#define wasm_ir_function_h
-#include "wasm.h"
#include "ir/utils.h"
+#include "wasm.h"
namespace wasm {
@@ -28,13 +28,18 @@ namespace FunctionUtils {
// everything but their name (which can't be the same, in the same
// module!) - same params, vars, body, result, etc.
inline bool equal(Function* left, Function* right) {
- if (left->getNumParams() != right->getNumParams()) return false;
- if (left->getNumVars() != right->getNumVars()) return false;
+ if (left->getNumParams() != right->getNumParams())
+ return false;
+ if (left->getNumVars() != right->getNumVars())
+ return false;
for (Index i = 0; i < left->getNumLocals(); i++) {
- if (left->getLocalType(i) != right->getLocalType(i)) return false;
+ if (left->getLocalType(i) != right->getLocalType(i))
+ return false;
}
- if (left->result != right->result) return false;
- if (left->type != right->type) return false;
+ if (left->result != right->result)
+ return false;
+ if (left->type != right->type)
+ return false;
if (!left->imported() && !right->imported()) {
return ExpressionAnalyzer::equal(left->body, right->body);
}
@@ -46,4 +51,3 @@ inline bool equal(Function* left, Function* right) {
} // namespace wasm
#endif // wasm_ir_function_h
-
diff --git a/src/ir/global-utils.h b/src/ir/global-utils.h
index fa4cdc44a..b32605805 100644
--- a/src/ir/global-utils.h
+++ b/src/ir/global-utils.h
@@ -20,37 +20,39 @@
#include <algorithm>
#include <vector>
+#include "ir/module-utils.h"
#include "literal.h"
#include "wasm.h"
-#include "ir/module-utils.h"
namespace wasm {
namespace GlobalUtils {
- // find a global initialized to the value of an import, or null if no such global
- inline Global* getGlobalInitializedToImport(Module& wasm, Name module, Name base) {
- // find the import
- Name imported;
- ModuleUtils::iterImportedGlobals(wasm, [&](Global* import) {
- if (import->module == module && import->base == base) {
- imported = import->name;
+// find a global initialized to the value of an import, or null if no such
+// global
+inline Global*
+getGlobalInitializedToImport(Module& wasm, Name module, Name base) {
+ // find the import
+ Name imported;
+ ModuleUtils::iterImportedGlobals(wasm, [&](Global* import) {
+ if (import->module == module && import->base == base) {
+ imported = import->name;
+ }
+ });
+ if (imported.isNull())
+ return nullptr;
+ // find a global inited to it
+ Global* ret = nullptr;
+ ModuleUtils::iterDefinedGlobals(wasm, [&](Global* defined) {
+ if (auto* init = defined->init->dynCast<GetGlobal>()) {
+ if (init->name == imported) {
+ ret = defined;
}
- });
- if (imported.isNull()) return nullptr;
- // find a global inited to it
- Global* ret = nullptr;
- ModuleUtils::iterDefinedGlobals(wasm, [&](Global* defined) {
- if (auto* init = defined->init->dynCast<GetGlobal>()) {
- if (init->name == imported) {
- ret = defined;
- }
- }
- });
- return ret;
- }
+ }
+ });
+ return ret;
}
+} // namespace GlobalUtils
} // namespace wasm
#endif // wasm_ir_global_h
-
diff --git a/src/ir/hashed.h b/src/ir/hashed.h
index 61bf19478..676b82cb4 100644
--- a/src/ir/hashed.h
+++ b/src/ir/hashed.h
@@ -17,9 +17,9 @@
#ifndef _wasm_ir_hashed_h
#define _wasm_ir_hashed_h
+#include "ir/utils.h"
#include "support/hash.h"
#include "wasm.h"
-#include "ir/utils.h"
namespace wasm {
@@ -34,24 +34,26 @@ struct HashedExpression {
}
}
- HashedExpression(const HashedExpression& other) : expr(other.expr), hash(other.hash) {}
+ HashedExpression(const HashedExpression& other)
+ : expr(other.expr), hash(other.hash) {}
};
struct ExpressionHasher {
- HashType operator()(const HashedExpression value) const {
- return value.hash;
- }
+ HashType operator()(const HashedExpression value) const { return value.hash; }
};
struct ExpressionComparer {
bool operator()(const HashedExpression a, const HashedExpression b) const {
- if (a.hash != b.hash) return false;
+ if (a.hash != b.hash)
+ return false;
return ExpressionAnalyzer::equal(a.expr, b.expr);
}
};
template<typename T>
-class HashedExpressionMap : public std::unordered_map<HashedExpression, T, ExpressionHasher, ExpressionComparer> {
+class HashedExpressionMap
+ : public std::
+ unordered_map<HashedExpression, T, ExpressionHasher, ExpressionComparer> {
};
// A pass that hashes all functions
@@ -63,21 +65,19 @@ struct FunctionHasher : public WalkerPass<PostWalker<FunctionHasher>> {
FunctionHasher(Map* output) : output(output) {}
- FunctionHasher* create() override {
- return new FunctionHasher(output);
- }
+ FunctionHasher* create() override { return new FunctionHasher(output); }
static Map createMap(Module* module) {
Map hashes;
for (auto& func : module->functions) {
- hashes[func.get()] = 0; // ensure an entry for each function - we must not modify the map shape in parallel, just the values
+ // ensure an entry for each function - we must not modify the map shape in
+ // parallel, just the values
+ hashes[func.get()] = 0;
}
return hashes;
}
- void doWalkFunction(Function* func) {
- output->at(func) = hashFunction(func);
- }
+ void doWalkFunction(Function* func) { output->at(func) = hashFunction(func); }
static HashType hashFunction(Function* func) {
HashType ret = 0;
@@ -90,7 +90,9 @@ struct FunctionHasher : public WalkerPass<PostWalker<FunctionHasher>> {
ret = rehash(ret, (HashType)type);
}
ret = rehash(ret, (HashType)func->result);
- ret = rehash(ret, HashType(func->type.is() ? std::hash<wasm::Name>{}(func->type) : HashType(0)));
+ ret = rehash(ret,
+ HashType(func->type.is() ? std::hash<wasm::Name>{}(func->type)
+ : HashType(0)));
ret = rehash(ret, (HashType)ExpressionAnalyzer::hash(func->body));
return ret;
}
@@ -102,4 +104,3 @@ private:
} // namespace wasm
#endif // _wasm_ir_hashed_h
-
diff --git a/src/ir/import-utils.h b/src/ir/import-utils.h
index 5f7bbc9ed..950b9bfcb 100644
--- a/src/ir/import-utils.h
+++ b/src/ir/import-utils.h
@@ -61,18 +61,13 @@ struct ImportInfo {
return nullptr;
}
- Index getNumImportedGlobals() {
- return importedGlobals.size();
- }
+ Index getNumImportedGlobals() { return importedGlobals.size(); }
- Index getNumImportedFunctions() {
- return importedFunctions.size();
- }
+ Index getNumImportedFunctions() { return importedFunctions.size(); }
Index getNumImports() {
return getNumImportedGlobals() + getNumImportedFunctions() +
- (wasm.memory.imported() ? 1 : 0) +
- (wasm.table.imported() ? 1 : 0);
+ (wasm.memory.imported() ? 1 : 0) + (wasm.table.imported() ? 1 : 0);
}
Index getNumDefinedGlobals() {
@@ -87,4 +82,3 @@ struct ImportInfo {
} // namespace wasm
#endif // wasm_ir_import_h
-
diff --git a/src/ir/iteration.h b/src/ir/iteration.h
index c6e97d392..289e5fa01 100644
--- a/src/ir/iteration.h
+++ b/src/ir/iteration.h
@@ -17,8 +17,8 @@
#ifndef wasm_ir_iteration_h
#define wasm_ir_iteration_h
-#include "wasm.h"
#include "wasm-traversal.h"
+#include "wasm.h"
namespace wasm {
@@ -39,19 +39,16 @@ class ChildIterator {
const ChildIterator& parent;
Index index;
- Iterator(const ChildIterator& parent, Index index) : parent(parent), index(index) {}
+ Iterator(const ChildIterator& parent, Index index)
+ : parent(parent), index(index) {}
bool operator!=(const Iterator& other) const {
return index != other.index || &parent != &(other.parent);
}
- void operator++() {
- index++;
- }
+ void operator++() { index++; }
- Expression* operator*() {
- return parent.children[index];
- }
+ Expression* operator*() { return parent.children[index]; }
};
public:
@@ -68,7 +65,8 @@ public:
static void scan(Traverser* self, Expression** currp) {
if (!self->scanned) {
self->scanned = true;
- PostWalker<Traverser, UnifiedExpressionVisitor<Traverser>>::scan(self, currp);
+ PostWalker<Traverser, UnifiedExpressionVisitor<Traverser>>::scan(
+ self, currp);
} else {
// This is one of the children. Do not scan further, just note it.
self->children->push_back(*currp);
@@ -80,15 +78,10 @@ public:
traverser.walk(parent);
}
- Iterator begin() const {
- return Iterator(*this, 0);
- }
- Iterator end() const {
- return Iterator(*this, children.size());
- }
+ Iterator begin() const { return Iterator(*this, 0); }
+ Iterator end() const { return Iterator(*this, children.size()); }
};
-} // wasm
+} // namespace wasm
#endif // wasm_ir_iteration_h
-
diff --git a/src/ir/label-utils.h b/src/ir/label-utils.h
index f4fb77697..75c3b3a41 100644
--- a/src/ir/label-utils.h
+++ b/src/ir/label-utils.h
@@ -17,8 +17,8 @@
#ifndef wasm_ir_label_h
#define wasm_ir_label_h
-#include "wasm.h"
#include "wasm-traversal.h"
+#include "wasm.h"
namespace wasm {
@@ -28,9 +28,7 @@ namespace LabelUtils {
// ones without duplicates
class LabelManager : public PostWalker<LabelManager> {
public:
- LabelManager(Function* func) {
- walkFunction(func);
- }
+ LabelManager(Function* func) { walkFunction(func); }
Name getUnique(std::string prefix) {
while (1) {
@@ -42,12 +40,8 @@ public:
}
}
- void visitBlock(Block* curr) {
- labels.insert(curr->name);
- }
- void visitLoop(Loop* curr) {
- labels.insert(curr->name);
- }
+ void visitBlock(Block* curr) { labels.insert(curr->name); }
+ void visitLoop(Loop* curr) { labels.insert(curr->name); }
private:
std::set<Name> labels;
@@ -59,4 +53,3 @@ private:
} // namespace wasm
#endif // wasm_ir_label_h
-
diff --git a/src/ir/load-utils.h b/src/ir/load-utils.h
index 8df4bcde8..36e94d0af 100644
--- a/src/ir/load-utils.h
+++ b/src/ir/load-utils.h
@@ -28,18 +28,16 @@ namespace LoadUtils {
// fill in bits either signed or unsigned wise)
inline bool isSignRelevant(Load* load) {
auto type = load->type;
- if (load->type == unreachable) return false;
+ if (load->type == unreachable)
+ return false;
return !isFloatType(type) && load->bytes < getTypeSize(type);
}
// check if a load can be signed (which some opts want to do)
-inline bool canBeSigned(Load* load) {
- return !load->isAtomic;
-}
+inline bool canBeSigned(Load* load) { return !load->isAtomic; }
} // namespace LoadUtils
} // namespace wasm
#endif // wasm_ir_load_h
-
diff --git a/src/ir/local-graph.h b/src/ir/local-graph.h
index fd6a496c0..ae389c899 100644
--- a/src/ir/local-graph.h
+++ b/src/ir/local-graph.h
@@ -17,6 +17,8 @@
#ifndef wasm_ir_local_graph_h
#define wasm_ir_local_graph_h
+#include "wasm.h"
+
namespace wasm {
//
@@ -41,8 +43,9 @@ struct LocalGraph {
typedef std::map<Expression*, Expression**> Locations;
// externally useful information
- GetSetses getSetses; // the sets affecting each get. a nullptr set means the initial
- // value (0 for a var, the received value for a param)
+ GetSetses getSetses; // the sets affecting each get. a nullptr set means the
+ // initial value (0 for a var, the received value for a
+ // param)
Locations locations; // where each get and set is (for easy replacing)
// Optional: compute the influence graphs between sets and gets
@@ -50,15 +53,18 @@ struct LocalGraph {
void computeInfluences();
- std::unordered_map<GetLocal*, std::unordered_set<SetLocal*>> getInfluences; // for each get, the sets whose values are influenced by that get
- std::unordered_map<SetLocal*, std::unordered_set<GetLocal*>> setInfluences; // for each set, the gets whose values are influenced by that set
+ // for each get, the sets whose values are influenced by that get
+ std::unordered_map<GetLocal*, std::unordered_set<SetLocal*>> getInfluences;
+ // for each set, the gets whose values are influenced by that set
+ std::unordered_map<SetLocal*, std::unordered_set<GetLocal*>> setInfluences;
// Optional: Compute the local indexes that are SSA, in the sense of
// * a single set for all the gets for that local index
- // * the set dominates all the gets (logically implied by the former property)
+ // * the set dominates all the gets (logically implied by the former
+ // property)
// * no other set (aside from the zero-init)
- // The third property is not exactly standard SSA, but is useful since we are not in
- // SSA form in our IR. To see why it matters, consider these:
+ // The third property is not exactly standard SSA, but is useful since we are
+ // not in SSA form in our IR. To see why it matters, consider these:
//
// x = 0 // zero init
// [..]
@@ -67,11 +73,11 @@ struct LocalGraph {
// x = 30 // !!!
// f(y)
//
- // The !!! line violates that property - it is another set for x, and it may interfere
- // say with replacing f(y) with f(x + 20). Instead, if we know the only other possible set for x
- // is the zero init, then things like the !!! line cannot exist, and it is valid to replace
- // f(y) with f(x + 20).
- // (This could be simpler, but in wasm the zero init always exists.)
+ // The !!! line violates that property - it is another set for x, and it may
+ // interfere say with replacing f(y) with f(x + 20). Instead, if we know the
+ // only other possible set for x is the zero init, then things like the !!!
+ // line cannot exist, and it is valid to replace f(y) with f(x + 20). (This
+ // could be simpler, but in wasm the zero init always exists.)
void computeSSAIndexes();
@@ -84,4 +90,3 @@ private:
} // namespace wasm
#endif // wasm_ir_local_graph_h
-
diff --git a/src/ir/local-utils.h b/src/ir/local-utils.h
index beb90d7b3..5d6b660cd 100644
--- a/src/ir/local-utils.h
+++ b/src/ir/local-utils.h
@@ -18,6 +18,7 @@
#define wasm_ir_local_utils_h
#include <ir/effects.h>
+#include <ir/manipulation.h>
namespace wasm {
@@ -25,25 +26,17 @@ struct GetLocalCounter : public PostWalker<GetLocalCounter> {
std::vector<Index> num;
GetLocalCounter() = default;
- GetLocalCounter(Function* func) {
- analyze(func, func->body);
- }
- GetLocalCounter(Function* func, Expression* ast) {
- analyze(func, ast);
- }
+ GetLocalCounter(Function* func) { analyze(func, func->body); }
+ GetLocalCounter(Function* func, Expression* ast) { analyze(func, ast); }
- void analyze(Function* func) {
- analyze(func, func->body);
- }
+ void analyze(Function* func) { analyze(func, func->body); }
void analyze(Function* func, Expression* ast) {
num.resize(func->getNumLocals());
std::fill(num.begin(), num.end(), 0);
walk(ast);
}
- void visitGetLocal(GetLocal *curr) {
- num[curr->index]++;
- }
+ void visitGetLocal(GetLocal* curr) { num[curr->index]++; }
};
// Removes trivially unneeded sets: sets for whom there is no possible get, and
@@ -53,19 +46,23 @@ struct UnneededSetRemover : public PostWalker<UnneededSetRemover> {
GetLocalCounter* getLocalCounter = nullptr;
- UnneededSetRemover(Function* func, PassOptions& passOptions) : passOptions(passOptions) {
+ UnneededSetRemover(Function* func, PassOptions& passOptions)
+ : passOptions(passOptions) {
GetLocalCounter counter(func);
UnneededSetRemover inner(counter, func, passOptions);
removed = inner.removed;
}
- UnneededSetRemover(GetLocalCounter& getLocalCounter, Function* func, PassOptions& passOptions) : passOptions(passOptions), getLocalCounter(&getLocalCounter) {
+ UnneededSetRemover(GetLocalCounter& getLocalCounter,
+ Function* func,
+ PassOptions& passOptions)
+ : passOptions(passOptions), getLocalCounter(&getLocalCounter) {
walk(func->body);
}
bool removed = false;
- void visitSetLocal(SetLocal *curr) {
+ void visitSetLocal(SetLocal* curr) {
// If no possible uses, remove.
if (getLocalCounter->num[curr->index] == 0) {
remove(curr);
@@ -108,4 +105,3 @@ struct UnneededSetRemover : public PostWalker<UnneededSetRemover> {
} // namespace wasm
#endif // wasm_ir_local_utils_h
-
diff --git a/src/ir/localize.h b/src/ir/localize.h
index c910d9f9b..05eadc593 100644
--- a/src/ir/localize.h
+++ b/src/ir/localize.h
@@ -44,4 +44,3 @@ struct Localizer {
} // namespace wasm
#endif // wasm_ir_localizer_h
-
diff --git a/src/ir/manipulation.h b/src/ir/manipulation.h
index 57188ad68..d363fc547 100644
--- a/src/ir/manipulation.h
+++ b/src/ir/manipulation.h
@@ -22,48 +22,45 @@
namespace wasm {
namespace ExpressionManipulator {
- // Re-use a node's memory. This helps avoid allocation when optimizing.
- template<typename InputType, typename OutputType>
- inline OutputType* convert(InputType *input) {
- static_assert(sizeof(OutputType) <= sizeof(InputType),
- "Can only convert to a smaller size Expression node");
- input->~InputType(); // arena-allocaed, so no destructor, but avoid UB.
- OutputType* output = (OutputType*)(input);
- new (output) OutputType;
- return output;
- }
-
- // Convenience method for nop, which is a common conversion
- template<typename InputType>
- inline Nop* nop(InputType* target) {
- return convert<InputType, Nop>(target);
- }
+// Re-use a node's memory. This helps avoid allocation when optimizing.
+template<typename InputType, typename OutputType>
+inline OutputType* convert(InputType* input) {
+ static_assert(sizeof(OutputType) <= sizeof(InputType),
+ "Can only convert to a smaller size Expression node");
+ input->~InputType(); // arena-allocaed, so no destructor, but avoid UB.
+ OutputType* output = (OutputType*)(input);
+ new (output) OutputType;
+ return output;
+}
- // Convert a node that allocates
- template<typename InputType, typename OutputType>
- inline OutputType* convert(InputType *input, MixedArena& allocator) {
- assert(sizeof(OutputType) <= sizeof(InputType));
- input->~InputType(); // arena-allocaed, so no destructor, but avoid UB.
- OutputType* output = (OutputType*)(input);
- new (output) OutputType(allocator);
- return output;
- }
+// Convenience method for nop, which is a common conversion
+template<typename InputType> inline Nop* nop(InputType* target) {
+ return convert<InputType, Nop>(target);
+}
- using CustomCopier = std::function<Expression*(Expression*)>;
- Expression* flexibleCopy(Expression* original, Module& wasm, CustomCopier custom);
+// Convert a node that allocates
+template<typename InputType, typename OutputType>
+inline OutputType* convert(InputType* input, MixedArena& allocator) {
+ assert(sizeof(OutputType) <= sizeof(InputType));
+ input->~InputType(); // arena-allocaed, so no destructor, but avoid UB.
+ OutputType* output = (OutputType*)(input);
+ new (output) OutputType(allocator);
+ return output;
+}
- inline Expression* copy(Expression* original, Module& wasm) {
- auto copy = [](Expression* curr) {
- return nullptr;
- };
- return flexibleCopy(original, wasm, copy);
- }
+using CustomCopier = std::function<Expression*(Expression*)>;
+Expression*
+flexibleCopy(Expression* original, Module& wasm, CustomCopier custom);
- // Splice an item into the middle of a block's list
- void spliceIntoBlock(Block* block, Index index, Expression* add);
+inline Expression* copy(Expression* original, Module& wasm) {
+ auto copy = [](Expression* curr) { return nullptr; };
+ return flexibleCopy(original, wasm, copy);
}
-} // wasm
+// Splice an item into the middle of a block's list
+void spliceIntoBlock(Block* block, Index index, Expression* add);
+} // namespace ExpressionManipulator
-#endif // wams_ir_manipulation_h
+} // namespace wasm
+#endif // wams_ir_manipulation_h
diff --git a/src/ir/memory-utils.h b/src/ir/memory-utils.h
index fbf1f646c..c1edc8ce9 100644
--- a/src/ir/memory-utils.h
+++ b/src/ir/memory-utils.h
@@ -21,153 +21,162 @@
#include <vector>
#include "literal.h"
-#include "wasm.h"
#include "wasm-binary.h"
+#include "wasm.h"
namespace wasm {
namespace MemoryUtils {
- // flattens memory into a single data segment. returns true if successful
- inline bool flatten(Memory& memory) {
- if (memory.segments.size() == 0) return true;
- std::vector<char> data;
- for (auto& segment : memory.segments) {
- if (segment.isPassive) {
- return false;
- }
- auto* offset = segment.offset->dynCast<Const>();
- if (!offset) return false;
- }
- for (auto& segment : memory.segments) {
- auto* offset = segment.offset->dynCast<Const>();
- Index start = offset->value.getInteger();
- Index end = start + segment.data.size();
- if (end > data.size()) {
- data.resize(end);
- }
- std::copy(segment.data.begin(), segment.data.end(), data.begin() + start);
- }
- memory.segments.resize(1);
- memory.segments[0].offset->cast<Const>()->value = Literal(int32_t(0));
- memory.segments[0].data.swap(data);
+// flattens memory into a single data segment. returns true if successful
+inline bool flatten(Memory& memory) {
+ if (memory.segments.size() == 0)
return true;
+ std::vector<char> data;
+ for (auto& segment : memory.segments) {
+ if (segment.isPassive) {
+ return false;
+ }
+ auto* offset = segment.offset->dynCast<Const>();
+ if (!offset)
+ return false;
}
-
- // Ensures that the memory exists (of minimal size).
- inline void ensureExists(Memory& memory) {
- if (!memory.exists) {
- memory.exists = true;
- memory.initial = memory.max = 1;
+ for (auto& segment : memory.segments) {
+ auto* offset = segment.offset->dynCast<Const>();
+ Index start = offset->value.getInteger();
+ Index end = start + segment.data.size();
+ if (end > data.size()) {
+ data.resize(end);
}
+ std::copy(segment.data.begin(), segment.data.end(), data.begin() + start);
+ }
+ memory.segments.resize(1);
+ memory.segments[0].offset->cast<Const>()->value = Literal(int32_t(0));
+ memory.segments[0].data.swap(data);
+ return true;
+}
+
+// Ensures that the memory exists (of minimal size).
+inline void ensureExists(Memory& memory) {
+ if (!memory.exists) {
+ memory.exists = true;
+ memory.initial = memory.max = 1;
}
+}
- // Try to merge segments until they fit into web limitations.
- // Return true if successful.
- inline bool ensureLimitedSegments(Module& module) {
- Memory& memory = module.memory;
- if (memory.segments.size() <= WebLimitations::MaxDataSegments) {
- return true;
- }
+// Try to merge segments until they fit into web limitations.
+// Return true if successful.
+inline bool ensureLimitedSegments(Module& module) {
+ Memory& memory = module.memory;
+ if (memory.segments.size() <= WebLimitations::MaxDataSegments) {
+ return true;
+ }
- // Conservatively refuse to change segments if there might be memory.init
- // and data.drop instructions.
- if (module.features.hasBulkMemory()) {
- return false;
- }
+ // Conservatively refuse to change segments if there might be memory.init
+ // and data.drop instructions.
+ if (module.features.hasBulkMemory()) {
+ return false;
+ }
- auto isEmpty = [](Memory::Segment& segment) {
- return segment.data.size() == 0;
- };
-
- auto isConstantOffset = [](Memory::Segment& segment) {
- return segment.offset && segment.offset->is<Const>();
- };
-
- Index numConstant = 0,
- numDynamic = 0;
- bool hasPassiveSegments = false;
- for (auto& segment : memory.segments) {
- if (!isEmpty(segment)) {
- if (isConstantOffset(segment)) {
- numConstant++;
- } else {
- numDynamic++;
- }
+ auto isEmpty = [](Memory::Segment& segment) {
+ return segment.data.size() == 0;
+ };
+
+ auto isConstantOffset = [](Memory::Segment& segment) {
+ return segment.offset && segment.offset->is<Const>();
+ };
+
+ Index numConstant = 0, numDynamic = 0;
+ bool hasPassiveSegments = false;
+ for (auto& segment : memory.segments) {
+ if (!isEmpty(segment)) {
+ if (isConstantOffset(segment)) {
+ numConstant++;
+ } else {
+ numDynamic++;
}
- hasPassiveSegments |= segment.isPassive;
}
+ hasPassiveSegments |= segment.isPassive;
+ }
- if (hasPassiveSegments) {
- return false;
- }
+ if (hasPassiveSegments) {
+ return false;
+ }
- // check if we have too many dynamic data segments, which we can do nothing about
- auto num = numConstant + numDynamic;
- if (numDynamic + 1 >= WebLimitations::MaxDataSegments) {
- return false;
- }
+ // check if we have too many dynamic data segments, which we can do nothing
+ // about
+ auto num = numConstant + numDynamic;
+ if (numDynamic + 1 >= WebLimitations::MaxDataSegments) {
+ return false;
+ }
- // we'll merge constant segments if we must
- if (numConstant + numDynamic >= WebLimitations::MaxDataSegments) {
- numConstant = WebLimitations::MaxDataSegments - numDynamic - 1;
- num = numConstant + numDynamic;
- assert(num == WebLimitations::MaxDataSegments - 1);
- }
+ // we'll merge constant segments if we must
+ if (numConstant + numDynamic >= WebLimitations::MaxDataSegments) {
+ numConstant = WebLimitations::MaxDataSegments - numDynamic - 1;
+ num = numConstant + numDynamic;
+ assert(num == WebLimitations::MaxDataSegments - 1);
+ }
+
+ std::vector<Memory::Segment> mergedSegments;
+ mergedSegments.reserve(WebLimitations::MaxDataSegments);
- std::vector<Memory::Segment> mergedSegments;
- mergedSegments.reserve(WebLimitations::MaxDataSegments);
+ // drop empty segments and pass through dynamic-offset segments
+ for (auto& segment : memory.segments) {
+ if (isEmpty(segment))
+ continue;
+ if (isConstantOffset(segment))
+ continue;
+ mergedSegments.push_back(segment);
+ }
- // drop empty segments and pass through dynamic-offset segments
- for (auto& segment : memory.segments) {
- if (isEmpty(segment)) continue;
- if (isConstantOffset(segment)) continue;
+ // from here on, we concern ourselves with non-empty constant-offset
+ // segments, the ones which we may need to merge
+ auto isRelevant = [&](Memory::Segment& segment) {
+ return !isEmpty(segment) && isConstantOffset(segment);
+ };
+ for (Index i = 0; i < memory.segments.size(); i++) {
+ auto& segment = memory.segments[i];
+ if (!isRelevant(segment))
+ continue;
+ if (mergedSegments.size() + 2 < WebLimitations::MaxDataSegments) {
mergedSegments.push_back(segment);
+ continue;
}
-
- // from here on, we concern ourselves with non-empty constant-offset
- // segments, the ones which we may need to merge
- auto isRelevant = [&](Memory::Segment& segment) {
- return !isEmpty(segment) && isConstantOffset(segment);
- };
- for (Index i = 0; i < memory.segments.size(); i++) {
- auto& segment = memory.segments[i];
- if (!isRelevant(segment)) continue;
- if (mergedSegments.size() + 2 < WebLimitations::MaxDataSegments) {
- mergedSegments.push_back(segment);
+ // we can emit only one more segment! merge everything into one
+ // start the combined segment at the bottom of them all
+ auto start = segment.offset->cast<Const>()->value.getInteger();
+ for (Index j = i + 1; j < memory.segments.size(); j++) {
+ auto& segment = memory.segments[j];
+ if (!isRelevant(segment))
continue;
+ auto offset = segment.offset->cast<Const>()->value.getInteger();
+ start = std::min(start, offset);
+ }
+ // create the segment and add in all the data
+ auto* c = module.allocator.alloc<Const>();
+ c->value = Literal(int32_t(start));
+ c->type = i32;
+
+ Memory::Segment combined(c);
+ for (Index j = i; j < memory.segments.size(); j++) {
+ auto& segment = memory.segments[j];
+ if (!isRelevant(segment))
+ continue;
+ auto offset = segment.offset->cast<Const>()->value.getInteger();
+ auto needed = offset + segment.data.size() - start;
+ if (combined.data.size() < needed) {
+ combined.data.resize(needed);
}
- // we can emit only one more segment! merge everything into one
- // start the combined segment at the bottom of them all
- auto start = segment.offset->cast<Const>()->value.getInteger();
- for (Index j = i + 1; j < memory.segments.size(); j++) {
- auto& segment = memory.segments[j];
- if (!isRelevant(segment)) continue;
- auto offset = segment.offset->cast<Const>()->value.getInteger();
- start = std::min(start, offset);
- }
- // create the segment and add in all the data
- auto* c = module.allocator.alloc<Const>();
- c->value = Literal(int32_t(start));
- c->type = i32;
-
- Memory::Segment combined(c);
- for (Index j = i; j < memory.segments.size(); j++) {
- auto& segment = memory.segments[j];
- if (!isRelevant(segment)) continue;
- auto offset = segment.offset->cast<Const>()->value.getInteger();
- auto needed = offset + segment.data.size() - start;
- if (combined.data.size() < needed) {
- combined.data.resize(needed);
- }
- std::copy(segment.data.begin(), segment.data.end(), combined.data.begin() + (offset - start));
- }
- mergedSegments.push_back(combined);
- break;
+ std::copy(segment.data.begin(),
+ segment.data.end(),
+ combined.data.begin() + (offset - start));
}
-
- memory.segments.swap(mergedSegments);
- return true;
+ mergedSegments.push_back(combined);
+ break;
}
+
+ memory.segments.swap(mergedSegments);
+ return true;
+}
} // namespace MemoryUtils
} // namespace wasm
diff --git a/src/ir/module-utils.h b/src/ir/module-utils.h
index fe99a458f..5569843fd 100644
--- a/src/ir/module-utils.h
+++ b/src/ir/module-utils.h
@@ -17,10 +17,10 @@
#ifndef wasm_ir_module_h
#define wasm_ir_module_h
-#include "wasm-binary.h"
-#include "wasm.h"
#include "ir/find_all.h"
#include "ir/manipulation.h"
+#include "wasm-binary.h"
+#include "wasm.h"
namespace wasm {
@@ -75,7 +75,8 @@ inline Function* copyFunction(Function* func, Module& out) {
ret->result = func->result;
ret->params = func->params;
ret->vars = func->vars;
- ret->type = Name(); // start with no named type; the names in the other module may differ
+ // start with no named type; the names in the other module may differ
+ ret->type = Name();
ret->localNames = func->localNames;
ret->localIndices = func->localIndices;
ret->debugLocations = func->debugLocations;
@@ -138,8 +139,7 @@ inline void copyModule(Module& in, Module& out) {
// Note that for this to work the functions themselves don't necessarily need
// to exist. For example, it is possible to remove a given function and then
// call this redirect all of its uses.
-template<typename T>
-inline void renameFunctions(Module& wasm, T& map) {
+template<typename T> inline void renameFunctions(Module& wasm, T& map) {
// Update the function itself.
for (auto& pair : map) {
if (Function* F = wasm.getFunctionOrNull(pair.first)) {
@@ -186,36 +186,31 @@ inline void renameFunction(Module& wasm, Name oldName, Name newName) {
// Convenient iteration over imported/non-imported module elements
-template<typename T>
-inline void iterImportedMemories(Module& wasm, T visitor) {
+template<typename T> inline void iterImportedMemories(Module& wasm, T visitor) {
if (wasm.memory.exists && wasm.memory.imported()) {
visitor(&wasm.memory);
}
}
-template<typename T>
-inline void iterDefinedMemories(Module& wasm, T visitor) {
+template<typename T> inline void iterDefinedMemories(Module& wasm, T visitor) {
if (wasm.memory.exists && !wasm.memory.imported()) {
visitor(&wasm.memory);
}
}
-template<typename T>
-inline void iterImportedTables(Module& wasm, T visitor) {
+template<typename T> inline void iterImportedTables(Module& wasm, T visitor) {
if (wasm.table.exists && wasm.table.imported()) {
visitor(&wasm.table);
}
}
-template<typename T>
-inline void iterDefinedTables(Module& wasm, T visitor) {
+template<typename T> inline void iterDefinedTables(Module& wasm, T visitor) {
if (wasm.table.exists && !wasm.table.imported()) {
visitor(&wasm.table);
}
}
-template<typename T>
-inline void iterImportedGlobals(Module& wasm, T visitor) {
+template<typename T> inline void iterImportedGlobals(Module& wasm, T visitor) {
for (auto& import : wasm.globals) {
if (import->imported()) {
visitor(import.get());
@@ -223,8 +218,7 @@ inline void iterImportedGlobals(Module& wasm, T visitor) {
}
}
-template<typename T>
-inline void iterDefinedGlobals(Module& wasm, T visitor) {
+template<typename T> inline void iterDefinedGlobals(Module& wasm, T visitor) {
for (auto& import : wasm.globals) {
if (!import->imported()) {
visitor(import.get());
@@ -241,8 +235,7 @@ inline void iterImportedFunctions(Module& wasm, T visitor) {
}
}
-template<typename T>
-inline void iterDefinedFunctions(Module& wasm, T visitor) {
+template<typename T> inline void iterDefinedFunctions(Module& wasm, T visitor) {
for (auto& import : wasm.functions) {
if (!import->imported()) {
visitor(import.get());
diff --git a/src/ir/parents.h b/src/ir/parents.h
index 71f2ae1d4..3e1f09559 100644
--- a/src/ir/parents.h
+++ b/src/ir/parents.h
@@ -20,25 +20,19 @@
namespace wasm {
struct Parents {
- Parents(Expression* expr) {
- inner.walk(expr);
- }
+ Parents(Expression* expr) { inner.walk(expr); }
- Expression* getParent(Expression* curr) {
- return inner.parentMap[curr];
- }
+ Expression* getParent(Expression* curr) { return inner.parentMap[curr]; }
private:
- struct Inner : public ExpressionStackWalker<Inner, UnifiedExpressionVisitor<Inner>> {
- void visitExpression(Expression* curr) {
- parentMap[curr] = getParent();
- }
+ struct Inner
+ : public ExpressionStackWalker<Inner, UnifiedExpressionVisitor<Inner>> {
+ void visitExpression(Expression* curr) { parentMap[curr] = getParent(); }
- std::map<Expression*, Expression *> parentMap;
+ std::map<Expression*, Expression*> parentMap;
} inner;
};
} // namespace wasm
#endif // wasm_ir_parents_h
-
diff --git a/src/ir/properties.h b/src/ir/properties.h
index 4afe3e909..b664ab008 100644
--- a/src/ir/properties.h
+++ b/src/ir/properties.h
@@ -17,8 +17,8 @@
#ifndef wasm_ir_properties_h
#define wasm_ir_properties_h
-#include "wasm.h"
#include "ir/bits.h"
+#include "wasm.h"
namespace wasm {
@@ -36,7 +36,7 @@ inline bool emitsBoolean(Expression* curr) {
inline bool isSymmetric(Binary* binary) {
switch (binary->op) {
case AddInt32:
- case MulInt32:
+ case MulInt32:
case AndInt32:
case OrInt32:
case XorInt32:
@@ -44,14 +44,16 @@ inline bool isSymmetric(Binary* binary) {
case NeInt32:
case AddInt64:
- case MulInt64:
+ case MulInt64:
case AndInt64:
case OrInt64:
case XorInt64:
case EqInt64:
- case NeInt64: return true;
+ case NeInt64:
+ return true;
- default: return false;
+ default:
+ return false;
}
}
@@ -105,7 +107,8 @@ inline Expression* getAlmostSignExt(Expression* curr) {
if (auto* inner = outer->left->dynCast<Binary>()) {
if (inner->op == ShlInt32) {
if (auto* innerConst = inner->right->dynCast<Const>()) {
- if (Bits::getEffectiveShifts(outerConst) <= Bits::getEffectiveShifts(innerConst)) {
+ if (Bits::getEffectiveShifts(outerConst) <=
+ Bits::getEffectiveShifts(innerConst)) {
return inner->left;
}
}
@@ -121,7 +124,8 @@ inline Expression* getAlmostSignExt(Expression* curr) {
// gets the size of the almost sign-extended value, as well as the
// extra shifts, if any
inline Index getAlmostSignExtBits(Expression* curr, Index& extraShifts) {
- extraShifts = Bits::getEffectiveShifts(curr->cast<Binary>()->left->cast<Binary>()->right) -
+ extraShifts = Bits::getEffectiveShifts(
+ curr->cast<Binary>()->left->cast<Binary>()->right) -
Bits::getEffectiveShifts(curr->cast<Binary>()->right);
return getSignExtBits(curr);
}
@@ -143,7 +147,8 @@ inline Expression* getZeroExtValue(Expression* curr) {
// gets the size of the sign-extended value
inline Index getZeroExtBits(Expression* curr) {
- return Bits::getMaskedBits(curr->cast<Binary>()->right->cast<Const>()->value.geti32());
+ return Bits::getMaskedBits(
+ curr->cast<Binary>()->right->cast<Const>()->value.geti32());
}
// Returns a falling-through value, that is, it looks through a local.tee
@@ -182,9 +187,8 @@ inline Expression* getFallthrough(Expression* curr) {
return curr;
}
-} // Properties
+} // namespace Properties
-} // wasm
+} // namespace wasm
#endif // wasm_ir_properties_h
-
diff --git a/src/ir/table-utils.h b/src/ir/table-utils.h
index 4b3b7005c..d2dc3a7d5 100644
--- a/src/ir/table-utils.h
+++ b/src/ir/table-utils.h
@@ -17,8 +17,8 @@
#ifndef wasm_ir_table_h
#define wasm_ir_table_h
-#include "wasm.h"
#include "wasm-traversal.h"
+#include "wasm.h"
namespace wasm {
diff --git a/src/ir/trapping.h b/src/ir/trapping.h
index 48f485faa..e6eca9e53 100644
--- a/src/ir/trapping.h
+++ b/src/ir/trapping.h
@@ -23,11 +23,7 @@
namespace wasm {
-enum class TrapMode {
- Allow,
- Clamp,
- JS
-};
+enum class TrapMode { Allow, Clamp, JS };
inline void addTrapModePass(PassRunner& runner, TrapMode trapMode) {
if (trapMode == TrapMode::Clamp) {
@@ -39,17 +35,13 @@ inline void addTrapModePass(PassRunner& runner, TrapMode trapMode) {
class TrappingFunctionContainer {
public:
- TrappingFunctionContainer(TrapMode mode, Module &wasm, bool immediate = false)
- : mode(mode),
- wasm(wasm),
- immediate(immediate) { }
+ TrappingFunctionContainer(TrapMode mode, Module& wasm, bool immediate = false)
+ : mode(mode), wasm(wasm), immediate(immediate) {}
bool hasFunction(Name name) {
return functions.find(name) != functions.end();
}
- bool hasImport(Name name) {
- return imports.find(name) != imports.end();
- }
+ bool hasImport(Name name) { return imports.find(name) != imports.end(); }
void addFunction(Function* function) {
functions[function->name] = function;
@@ -66,10 +58,10 @@ public:
void addToModule() {
if (!immediate) {
- for (auto &pair : functions) {
+ for (auto& pair : functions) {
wasm.addFunction(pair.second);
}
- for (auto &pair : imports) {
+ for (auto& pair : imports) {
wasm.addFunction(pair.second);
}
}
@@ -77,17 +69,11 @@ public:
imports.clear();
}
- TrapMode getMode() {
- return mode;
- }
+ TrapMode getMode() { return mode; }
- Module& getModule() {
- return wasm;
- }
+ Module& getModule() { return wasm; }
- std::map<Name, Function*>& getFunctions() {
- return functions;
- }
+ std::map<Name, Function*>& getFunctions() { return functions; }
private:
std::map<Name, Function*> functions;
@@ -98,8 +84,10 @@ private:
bool immediate;
};
-Expression* makeTrappingBinary(Binary* curr, TrappingFunctionContainer &trappingFunctions);
-Expression* makeTrappingUnary(Unary* curr, TrappingFunctionContainer &trappingFunctions);
+Expression* makeTrappingBinary(Binary* curr,
+ TrappingFunctionContainer& trappingFunctions);
+Expression* makeTrappingUnary(Unary* curr,
+ TrappingFunctionContainer& trappingFunctions);
inline TrapMode trapModeFromString(std::string const& str) {
if (str == "allow") {
@@ -110,11 +98,12 @@ inline TrapMode trapModeFromString(std::string const& str) {
return TrapMode::JS;
} else {
throw std::invalid_argument(
- "Unsupported trap mode \"" + str + "\". "
+ "Unsupported trap mode \"" + str +
+ "\". "
"Valid modes are \"allow\", \"js\", and \"clamp\"");
}
}
-} // wasm
+} // namespace wasm
#endif // wasm_ir_trapping_h
diff --git a/src/ir/type-updating.h b/src/ir/type-updating.h
index ba06bccf9..e387483ee 100644
--- a/src/ir/type-updating.h
+++ b/src/ir/type-updating.h
@@ -28,7 +28,9 @@ namespace wasm {
// reaches it
// * altering the type of a child to unreachable can make the parent
// unreachable
-struct TypeUpdater : public ExpressionStackWalker<TypeUpdater, UnifiedExpressionVisitor<TypeUpdater>> {
+struct TypeUpdater
+ : public ExpressionStackWalker<TypeUpdater,
+ UnifiedExpressionVisitor<TypeUpdater>> {
// Part 1: Scanning
// track names to their blocks, so that when we remove a break to
@@ -75,10 +77,13 @@ struct TypeUpdater : public ExpressionStackWalker<TypeUpdater, UnifiedExpression
// note the replacement of one node with another. this should be called
// after performing the replacement.
- // this does *not* look into the node by default. see noteReplacementWithRecursiveRemoval
- // (we don't support recursive addition because in practice we do not create
- // new trees in the passes that use this, they just move around children)
- void noteReplacement(Expression* from, Expression* to, bool recursivelyRemove=false) {
+ // this does *not* look into the node by default. see
+ // noteReplacementWithRecursiveRemoval (we don't support recursive addition
+ // because in practice we do not create new trees in the passes that use this,
+ // they just move around children)
+ void noteReplacement(Expression* from,
+ Expression* to,
+ bool recursivelyRemove = false) {
auto parent = parents[from];
if (recursivelyRemove) {
noteRecursiveRemoval(from);
@@ -109,22 +114,23 @@ struct TypeUpdater : public ExpressionStackWalker<TypeUpdater, UnifiedExpression
// note the removal of a node and all its children
void noteRecursiveRemoval(Expression* curr) {
- struct Recurser : public PostWalker<Recurser, UnifiedExpressionVisitor<Recurser>> {
+ struct Recurser
+ : public PostWalker<Recurser, UnifiedExpressionVisitor<Recurser>> {
TypeUpdater& parent;
Recurser(TypeUpdater& parent, Expression* root) : parent(parent) {
walk(root);
}
- void visitExpression(Expression* curr) {
- parent.noteRemoval(curr);
- }
+ void visitExpression(Expression* curr) { parent.noteRemoval(curr); }
};
Recurser(*this, curr);
}
- void noteAddition(Expression* curr, Expression* parent, Expression* previous = nullptr) {
+ void noteAddition(Expression* curr,
+ Expression* parent,
+ Expression* previous = nullptr) {
assert(parents.find(curr) == parents.end()); // must not already exist
noteRemovalOrAddition(curr, parent);
// if we didn't replace with the exact same type, propagate types up
@@ -188,7 +194,8 @@ struct TypeUpdater : public ExpressionStackWalker<TypeUpdater, UnifiedExpression
// alters the type of a node to a new type.
// this propagates the type change through all the parents.
void changeTypeTo(Expression* curr, Type newType) {
- if (curr->type == newType) return; // nothing to do
+ if (curr->type == newType)
+ return; // nothing to do
curr->type = newType;
propagateTypesUp(curr);
}
@@ -201,11 +208,13 @@ struct TypeUpdater : public ExpressionStackWalker<TypeUpdater, UnifiedExpression
// the one thing we need to do here is propagate unreachability,
// no other change is possible
void propagateTypesUp(Expression* curr) {
- if (curr->type != unreachable) return;
+ if (curr->type != unreachable)
+ return;
while (1) {
auto* child = curr;
curr = parents[child];
- if (!curr) return;
+ if (!curr)
+ return;
// get ready to apply unreachability to this node
if (curr->type == unreachable) {
return; // already unreachable, stop here
@@ -254,9 +263,9 @@ struct TypeUpdater : public ExpressionStackWalker<TypeUpdater, UnifiedExpression
if (curr->type == unreachable) {
return; // no change possible
}
- if (!curr->list.empty() &&
- isConcreteType(curr->list.back()->type)) {
- return; // should keep type due to fallthrough, even if has an unreachable child
+ if (!curr->list.empty() && isConcreteType(curr->list.back()->type)) {
+ // should keep type due to fallthrough, even if has an unreachable child
+ return;
}
for (auto* child : curr->list) {
if (child->type == unreachable) {
diff --git a/src/ir/utils.h b/src/ir/utils.h
index c91698124..9be8947a1 100644
--- a/src/ir/utils.h
+++ b/src/ir/utils.h
@@ -17,22 +17,21 @@
#ifndef wasm_ir_utils_h
#define wasm_ir_utils_h
-#include "wasm.h"
-#include "wasm-traversal.h"
-#include "wasm-builder.h"
-#include "pass.h"
#include "ir/branch-utils.h"
+#include "pass.h"
+#include "wasm-builder.h"
+#include "wasm-traversal.h"
+#include "wasm.h"
namespace wasm {
// Measure the size of an AST
-struct Measurer : public PostWalker<Measurer, UnifiedExpressionVisitor<Measurer>> {
+struct Measurer
+ : public PostWalker<Measurer, UnifiedExpressionVisitor<Measurer>> {
Index size = 0;
- void visitExpression(Expression* curr) {
- size++;
- }
+ void visitExpression(Expression* curr) { size++; }
static Index measure(Expression* tree) {
Measurer measurer;
@@ -43,26 +42,24 @@ struct Measurer : public PostWalker<Measurer, UnifiedExpressionVisitor<Measurer>
struct ExpressionAnalyzer {
// Given a stack of expressions, checks if the topmost is used as a result.
- // For example, if the parent is a block and the node is before the last position,
- // it is not used.
+ // For example, if the parent is a block and the node is before the last
+ // position, it is not used.
static bool isResultUsed(ExpressionStack& stack, Function* func);
// Checks if a value is dropped.
static bool isResultDropped(ExpressionStack& stack);
- // Checks if a break is a simple - no condition, no value, just a plain branching
- static bool isSimple(Break* curr) {
- return !curr->condition && !curr->value;
- }
+ // Checks if a break is a simple - no condition, no value, just a plain
+ // branching
+ static bool isSimple(Break* curr) { return !curr->condition && !curr->value; }
using ExprComparer = std::function<bool(Expression*, Expression*)>;
- static bool flexibleEqual(Expression* left, Expression* right, ExprComparer comparer);
+ static bool
+ flexibleEqual(Expression* left, Expression* right, ExprComparer comparer);
// Compares two expressions for equivalence.
static bool equal(Expression* left, Expression* right) {
- auto comparer = [](Expression* left, Expression* right) {
- return false;
- };
+ auto comparer = [](Expression* left, Expression* right) { return false; };
return flexibleEqual(left, right, comparer);
}
@@ -79,7 +76,8 @@ struct ExpressionAnalyzer {
return flexibleEqual(left, right, comparer);
}
- // hash an expression, ignoring superficial details like specific internal names
+ // hash an expression, ignoring superficial details like specific internal
+ // names
static HashType hash(Expression* curr);
};
@@ -100,15 +98,16 @@ struct ExpressionAnalyzer {
// exist, but the breaks don't declare the type, rather everything
// depends on the block. To avoid looking at the parent or something
// else, just remove such un-taken branches.
-struct ReFinalize : public WalkerPass<PostWalker<ReFinalize, OverriddenVisitor<ReFinalize>>> {
+struct ReFinalize
+ : public WalkerPass<PostWalker<ReFinalize, OverriddenVisitor<ReFinalize>>> {
bool isFunctionParallel() override { return true; }
Pass* create() override { return new ReFinalize; }
ReFinalize() { name = "refinalize"; }
- // block finalization is O(bad) if we do each block by itself, so do it in bulk,
- // tracking break value types so we just do a linear pass
+ // block finalization is O(bad) if we do each block by itself, so do it in
+ // bulk, tracking break value types so we just do a linear pass
std::map<Name, Type> breakValues;
@@ -220,10 +219,10 @@ struct ReFinalizeNode : public OverriddenVisitor<ReFinalizeNode> {
}
};
-// Adds drop() operations where necessary. This lets you not worry about adding drop when
-// generating code.
-// This also refinalizes before and after, as dropping can change types, and depends
-// on types being cleaned up - no unnecessary block/if/loop types (see refinalize)
+// Adds drop() operations where necessary. This lets you not worry about adding
+// drop when generating code. This also refinalizes before and after, as
+// dropping can change types, and depends on types being cleaned up - no
+// unnecessary block/if/loop types (see refinalize)
// TODO: optimize that, interleave them
struct AutoDrop : public WalkerPass<ExpressionStackWalker<AutoDrop>> {
bool isFunctionParallel() override { return true; }
@@ -236,7 +235,8 @@ struct AutoDrop : public WalkerPass<ExpressionStackWalker<AutoDrop>> {
bool acted = false;
if (isConcreteType(child->type)) {
expressionStack.push_back(child);
- if (!ExpressionAnalyzer::isResultUsed(expressionStack, getFunction()) && !ExpressionAnalyzer::isResultDropped(expressionStack)) {
+ if (!ExpressionAnalyzer::isResultUsed(expressionStack, getFunction()) &&
+ !ExpressionAnalyzer::isResultDropped(expressionStack)) {
child = Builder(*getModule()).makeDrop(child);
acted = true;
}
@@ -245,12 +245,11 @@ struct AutoDrop : public WalkerPass<ExpressionStackWalker<AutoDrop>> {
return acted;
}
- void reFinalize() {
- ReFinalizeNode::updateStack(expressionStack);
- }
+ void reFinalize() { ReFinalizeNode::updateStack(expressionStack); }
void visitBlock(Block* curr) {
- if (curr->list.size() == 0) return;
+ if (curr->list.size() == 0)
+ return;
for (Index i = 0; i < curr->list.size() - 1; i++) {
auto* child = curr->list[i];
if (isConcreteType(child->type)) {
@@ -265,9 +264,11 @@ struct AutoDrop : public WalkerPass<ExpressionStackWalker<AutoDrop>> {
void visitIf(If* curr) {
bool acted = false;
- if (maybeDrop(curr->ifTrue)) acted = true;
+ if (maybeDrop(curr->ifTrue))
+ acted = true;
if (curr->ifFalse) {
- if (maybeDrop(curr->ifFalse)) acted = true;
+ if (maybeDrop(curr->ifFalse))
+ acted = true;
}
if (acted) {
reFinalize();
@@ -286,50 +287,31 @@ struct AutoDrop : public WalkerPass<ExpressionStackWalker<AutoDrop>> {
};
struct I64Utilities {
- static Expression* recreateI64(Builder& builder, Expression* low, Expression* high) {
- return
- builder.makeBinary(
- OrInt64,
- builder.makeUnary(
- ExtendUInt32,
- low
- ),
- builder.makeBinary(
- ShlInt64,
- builder.makeUnary(
- ExtendUInt32,
- high
- ),
- builder.makeConst(Literal(int64_t(32)))
- )
- )
- ;
+ static Expression*
+ recreateI64(Builder& builder, Expression* low, Expression* high) {
+ return builder.makeBinary(
+ OrInt64,
+ builder.makeUnary(ExtendUInt32, low),
+ builder.makeBinary(ShlInt64,
+ builder.makeUnary(ExtendUInt32, high),
+ builder.makeConst(Literal(int64_t(32)))));
};
static Expression* recreateI64(Builder& builder, Index low, Index high) {
- return recreateI64(builder, builder.makeGetLocal(low, i32), builder.makeGetLocal(high, i32));
+ return recreateI64(
+ builder, builder.makeGetLocal(low, i32), builder.makeGetLocal(high, i32));
};
static Expression* getI64High(Builder& builder, Index index) {
- return
- builder.makeUnary(
- WrapInt64,
- builder.makeBinary(
- ShrUInt64,
- builder.makeGetLocal(index, i64),
- builder.makeConst(Literal(int64_t(32)))
- )
- )
- ;
+ return builder.makeUnary(
+ WrapInt64,
+ builder.makeBinary(ShrUInt64,
+ builder.makeGetLocal(index, i64),
+ builder.makeConst(Literal(int64_t(32)))));
}
static Expression* getI64Low(Builder& builder, Index index) {
- return
- builder.makeUnary(
- WrapInt64,
- builder.makeGetLocal(index, i64)
- )
- ;
+ return builder.makeUnary(WrapInt64, builder.makeGetLocal(index, i64));
}
};
diff --git a/src/literal.h b/src/literal.h
index 7646b5d29..ff50b2e61 100644
--- a/src/literal.h
+++ b/src/literal.h
@@ -17,12 +17,12 @@
#ifndef wasm_literal_h
#define wasm_literal_h
-#include <iostream>
#include <array>
+#include <iostream>
+#include "compiler-support.h"
#include "support/hash.h"
#include "support/utilities.h"
-#include "compiler-support.h"
#include "wasm-type.h"
namespace wasm {
@@ -40,14 +40,16 @@ public:
Type type;
public:
- Literal() : v128(), type(Type::none) {}
- explicit Literal(Type type) : v128(), type(type) {}
- explicit Literal(int32_t init) : i32(init), type(Type::i32) {}
- explicit Literal(uint32_t init) : i32(init), type(Type::i32) {}
- explicit Literal(int64_t init) : i64(init), type(Type::i64) {}
- explicit Literal(uint64_t init) : i64(init), type(Type::i64) {}
- explicit Literal(float init) : i32(bit_cast<int32_t>(init)), type(Type::f32) {}
- explicit Literal(double init) : i64(bit_cast<int64_t>(init)), type(Type::f64) {}
+ Literal() : v128(), type(Type::none) {}
+ explicit Literal(Type type) : v128(), type(type) {}
+ explicit Literal(int32_t init) : i32(init), type(Type::i32) {}
+ explicit Literal(uint32_t init) : i32(init), type(Type::i32) {}
+ explicit Literal(int64_t init) : i64(init), type(Type::i64) {}
+ explicit Literal(uint64_t init) : i64(init), type(Type::i64) {}
+ explicit Literal(float init)
+ : i32(bit_cast<int32_t>(init)), type(Type::f32) {}
+ explicit Literal(double init)
+ : i64(bit_cast<int64_t>(init)), type(Type::f64) {}
// v128 literal from bytes
explicit Literal(const uint8_t init[16]);
// v128 literal from lane value literals
@@ -61,45 +63,85 @@ public:
inline static Literal makeFromInt32(int32_t x, Type type) {
switch (type) {
- case Type::i32: return Literal(int32_t(x)); break;
- case Type::i64: return Literal(int64_t(x)); break;
- case Type::f32: return Literal(float(x)); break;
- case Type::f64: return Literal(double(x)); break;
- case Type::v128: return Literal(
- std::array<Literal, 4>{{
- Literal(x), Literal(int32_t(0)), Literal(int32_t(0)), Literal(int32_t(0))
- }}
- );
+ case Type::i32:
+ return Literal(int32_t(x));
+ break;
+ case Type::i64:
+ return Literal(int64_t(x));
+ break;
+ case Type::f32:
+ return Literal(float(x));
+ break;
+ case Type::f64:
+ return Literal(double(x));
+ break;
+ case Type::v128:
+ return Literal(std::array<Literal, 4>{{Literal(x),
+ Literal(int32_t(0)),
+ Literal(int32_t(0)),
+ Literal(int32_t(0))}});
case none:
- case unreachable: WASM_UNREACHABLE();
+ case unreachable:
+ WASM_UNREACHABLE();
}
WASM_UNREACHABLE();
}
- inline static Literal makeZero(Type type) {
- return makeFromInt32(0, type);
- }
+ inline static Literal makeZero(Type type) { return makeFromInt32(0, type); }
Literal castToF32();
Literal castToF64();
Literal castToI32();
Literal castToI64();
- int32_t geti32() const { assert(type == Type::i32); return i32; }
- int64_t geti64() const { assert(type == Type::i64); return i64; }
- float getf32() const { assert(type == Type::f32); return bit_cast<float>(i32); }
- double getf64() const { assert(type == Type::f64); return bit_cast<double>(i64); }
+ int32_t geti32() const {
+ assert(type == Type::i32);
+ return i32;
+ }
+ int64_t geti64() const {
+ assert(type == Type::i64);
+ return i64;
+ }
+ float getf32() const {
+ assert(type == Type::f32);
+ return bit_cast<float>(i32);
+ }
+ double getf64() const {
+ assert(type == Type::f64);
+ return bit_cast<double>(i64);
+ }
std::array<uint8_t, 16> getv128() const;
// careful!
- int32_t* geti32Ptr() { assert(type == Type::i32); return &i32; }
- uint8_t* getv128Ptr() { assert(type == Type::v128); return v128; }
- const uint8_t* getv128Ptr() const { assert(type == Type::v128); return v128; }
+ int32_t* geti32Ptr() {
+ assert(type == Type::i32);
+ return &i32;
+ }
+ uint8_t* getv128Ptr() {
+ assert(type == Type::v128);
+ return v128;
+ }
+ const uint8_t* getv128Ptr() const {
+ assert(type == Type::v128);
+ return v128;
+ }
- int32_t reinterpreti32() const { assert(type == Type::f32); return i32; }
- int64_t reinterpreti64() const { assert(type == Type::f64); return i64; }
- float reinterpretf32() const { assert(type == Type::i32); return bit_cast<float>(i32); }
- double reinterpretf64() const { assert(type == Type::i64); return bit_cast<double>(i64); }
+ int32_t reinterpreti32() const {
+ assert(type == Type::f32);
+ return i32;
+ }
+ int64_t reinterpreti64() const {
+ assert(type == Type::f64);
+ return i64;
+ }
+ float reinterpretf32() const {
+ assert(type == Type::i32);
+ return bit_cast<float>(i32);
+ }
+ double reinterpretf64() const {
+ assert(type == Type::i64);
+ return bit_cast<double>(i64);
+ }
int64_t getInteger() const;
double getFloat() const;
@@ -117,7 +159,7 @@ public:
static float setQuietNaN(float f);
static double setQuietNaN(double f);
- static void printFloat(std::ostream &o, float f);
+ static void printFloat(std::ostream& o, float f);
static void printDouble(std::ostream& o, double d);
static void printVec128(std::ostream& o, const std::array<uint8_t, 16>& v);
@@ -204,7 +246,8 @@ public:
std::array<Literal, 4> getLanesF32x4() const;
std::array<Literal, 2> getLanesF64x2() const;
- Literal shuffleV8x16(const Literal& other, const std::array<uint8_t, 16>& mask) const;
+ Literal shuffleV8x16(const Literal& other,
+ const std::array<uint8_t, 16>& mask) const;
Literal splatI8x16() const;
Literal extractLaneSI8x16(uint8_t index) const;
Literal extractLaneUI8x16(uint8_t index) const;
@@ -342,7 +385,7 @@ public:
Literal convertSToF64x2() const;
Literal convertUToF64x2() const;
- private:
+private:
Literal addSatSI8(const Literal& other) const;
Literal addSatUI8(const Literal& other) const;
Literal addSatSI16(const Literal& other) const;
@@ -362,31 +405,35 @@ template<> struct hash<wasm::Literal> {
a.getBits(bytes);
int64_t chunks[2];
memcpy(chunks, bytes, sizeof(chunks));
- return wasm::rehash(
- wasm::rehash(
- uint64_t(hash<size_t>()(size_t(a.type))),
- uint64_t(hash<int64_t>()(chunks[0]))
- ),
- uint64_t(hash<int64_t>()(chunks[1]))
- );
+ return wasm::rehash(wasm::rehash(uint64_t(hash<size_t>()(size_t(a.type))),
+ uint64_t(hash<int64_t>()(chunks[0]))),
+ uint64_t(hash<int64_t>()(chunks[1])));
}
};
template<> struct less<wasm::Literal> {
bool operator()(const wasm::Literal& a, const wasm::Literal& b) const {
- if (a.type < b.type) return true;
- if (a.type > b.type) return false;
+ if (a.type < b.type)
+ return true;
+ if (a.type > b.type)
+ return false;
switch (a.type) {
- case wasm::Type::i32: return a.geti32() < b.geti32();
- case wasm::Type::f32: return a.reinterpreti32() < b.reinterpreti32();
- case wasm::Type::i64: return a.geti64() < b.geti64();
- case wasm::Type::f64: return a.reinterpreti64() < b.reinterpreti64();
- case wasm::Type::v128: return memcmp(a.getv128Ptr(), b.getv128Ptr(), 16) < 0;
+ case wasm::Type::i32:
+ return a.geti32() < b.geti32();
+ case wasm::Type::f32:
+ return a.reinterpreti32() < b.reinterpreti32();
+ case wasm::Type::i64:
+ return a.geti64() < b.geti64();
+ case wasm::Type::f64:
+ return a.reinterpreti64() < b.reinterpreti64();
+ case wasm::Type::v128:
+ return memcmp(a.getv128Ptr(), b.getv128Ptr(), 16) < 0;
case wasm::Type::none:
- case wasm::Type::unreachable: return false;
+ case wasm::Type::unreachable:
+ return false;
}
WASM_UNREACHABLE();
}
};
-}
+} // namespace std
#endif // wasm_literal_h
diff --git a/src/mixed_arena.h b/src/mixed_arena.h
index 5f48f5220..36bf22a5e 100644
--- a/src/mixed_arena.h
+++ b/src/mixed_arena.h
@@ -84,7 +84,8 @@ struct MixedArena {
// Allocate an amount of space with a guaranteed alignment
void* allocSpace(size_t size, size_t align) {
- // the bump allocator data should not be modified by multiple threads at once.
+ // the bump allocator data should not be modified by multiple threads at
+ // once.
auto myId = std::this_thread::get_id();
if (myId != threadId) {
MixedArena* curr = this;
@@ -112,7 +113,8 @@ struct MixedArena {
// otherwise, the cmpxchg updated seen, and we continue to loop
curr = seen;
}
- if (allocated) delete allocated;
+ if (allocated)
+ delete allocated;
return curr->allocSpace(size, align);
}
// First, move the current index in the last chunk to an aligned position.
@@ -121,22 +123,26 @@ struct MixedArena {
// Allocate a new chunk.
auto numChunks = (size + CHUNK_SIZE - 1) / CHUNK_SIZE;
assert(size <= numChunks * CHUNK_SIZE);
- auto* allocation = wasm::aligned_malloc(MAX_ALIGN, numChunks * CHUNK_SIZE);
- if (!allocation) abort();
+ auto* allocation =
+ wasm::aligned_malloc(MAX_ALIGN, numChunks * CHUNK_SIZE);
+ if (!allocation)
+ abort();
chunks.push_back(allocation);
index = 0;
}
uint8_t* ret = static_cast<uint8_t*>(chunks.back());
ret += index;
- index += size; // TODO: if we allocated more than 1 chunk, reuse the remainder, right now we allocate another next time
+ index += size; // TODO: if we allocated more than 1 chunk, reuse the
+ // remainder, right now we allocate another next time
return static_cast<void*>(ret);
}
- template<class T>
- T* alloc() {
- static_assert(alignof(T) <= MAX_ALIGN, "maximum alignment not large enough");
+ template<class T> T* alloc() {
+ static_assert(alignof(T) <= MAX_ALIGN,
+ "maximum alignment not large enough");
auto* ret = static_cast<T*>(allocSpace(sizeof(T), alignof(T)));
- new (ret) T(*this); // allocated objects receive the allocator, so they can allocate more later if necessary
+ new (ret) T(*this); // allocated objects receive the allocator, so they can
+ // allocate more later if necessary
return ret;
}
@@ -149,22 +155,20 @@ struct MixedArena {
~MixedArena() {
clear();
- if (next.load()) delete next.load();
+ if (next.load())
+ delete next.load();
}
};
-
//
// A vector that allocates in an arena.
//
// TODO: specialize on the initial size of the array
-template<typename SubType, typename T>
-class ArenaVectorBase {
+template<typename SubType, typename T> class ArenaVectorBase {
protected:
T* data = nullptr;
- size_t usedElements = 0,
- allocatedElements = 0;
+ size_t usedElements = 0, allocatedElements = 0;
void reallocate(size_t size) {
T* old = data;
@@ -182,13 +186,9 @@ public:
return data[index];
}
- size_t size() const {
- return usedElements;
- }
+ size_t size() const { return usedElements; }
- bool empty() const {
- return size() == 0;
- }
+ bool empty() const { return size() == 0; }
void resize(size_t size) {
if (size > allocatedElements) {
@@ -235,13 +235,9 @@ public:
usedElements -= size;
}
- void erase(Iterator it) {
- erase(it, it + 1);
- }
+ void erase(Iterator it) { erase(it, it + 1); }
- void clear() {
- usedElements = 0;
- }
+ void clear() { usedElements = 0; }
void reserve(size_t size) {
if (size > allocatedElements) {
@@ -249,8 +245,7 @@ public:
}
}
- template<typename ListType>
- void set(const ListType& list) {
+ template<typename ListType> void set(const ListType& list) {
size_t size = list.size();
if (allocatedElements < size) {
static_cast<SubType*>(this)->allocate(size);
@@ -261,9 +256,7 @@ public:
usedElements = size;
}
- void operator=(SubType& other) {
- set(other);
- }
+ void operator=(SubType& other) { set(other); }
void swap(SubType& other) {
data = other.data;
@@ -287,32 +280,25 @@ public:
size_t index;
Iterator() : parent(nullptr), index(0) {}
- Iterator(const SubType* parent, size_t index) : parent(parent), index(index) {}
+ Iterator(const SubType* parent, size_t index)
+ : parent(parent), index(index) {}
bool operator==(const Iterator& other) const {
return index == other.index && parent == other.parent;
}
- bool operator!=(const Iterator& other) const {
- return !(*this == other);
- }
+ bool operator!=(const Iterator& other) const { return !(*this == other); }
bool operator<(const Iterator& other) const {
assert(parent == other.parent);
return index < other.index;
}
- bool operator>(const Iterator& other) const {
- return other < *this;
- }
+ bool operator>(const Iterator& other) const { return other < *this; }
- bool operator<=(const Iterator& other) const {
- return !(other < *this);
- }
+ bool operator<=(const Iterator& other) const { return !(other < *this); }
- bool operator>=(const Iterator& other) const {
- return !(*this < other);
- }
+ bool operator>=(const Iterator& other) const { return !(*this < other); }
Iterator& operator++() {
index++;
@@ -341,17 +327,13 @@ public:
return *this;
}
- Iterator& operator-=(std::ptrdiff_t off) {
- return *this += -off;
- }
+ Iterator& operator-=(std::ptrdiff_t off) { return *this += -off; }
Iterator operator+(std::ptrdiff_t off) const {
return Iterator(*this) += off;
}
- Iterator operator-(std::ptrdiff_t off) const {
- return *this + -off;
- }
+ Iterator operator-(std::ptrdiff_t off) const { return *this + -off; }
std::ptrdiff_t operator-(const Iterator& other) const {
assert(parent == other.parent);
@@ -362,17 +344,11 @@ public:
return it + off;
}
- T& operator*() const {
- return (*parent)[index];
- }
+ T& operator*() const { return (*parent)[index]; }
- T& operator[](std::ptrdiff_t off) const {
- return (*parent)[index + off];
- }
+ T& operator[](std::ptrdiff_t off) const { return (*parent)[index + off]; }
- T* operator->() const {
- return &(*parent)[index];
- }
+ T* operator->() const { return &(*parent)[index]; }
};
Iterator begin() const {
@@ -407,7 +383,8 @@ public:
void allocate(size_t size) {
this->allocatedElements = size;
- this->data = static_cast<T*>(allocator.allocSpace(sizeof(T) * this->allocatedElements, alignof(T)));
+ this->data = static_cast<T*>(
+ allocator.allocSpace(sizeof(T) * this->allocatedElements, alignof(T)));
}
};
diff --git a/src/parsing.h b/src/parsing.h
index 97fc88432..8432b41f2 100644
--- a/src/parsing.h
+++ b/src/parsing.h
@@ -22,13 +22,13 @@
#include <sstream>
#include <string>
-#include "shared-constants.h"
#include "asmjs/shared-constants.h"
#include "mixed_arena.h"
+#include "shared-constants.h"
#include "support/colors.h"
#include "support/utilities.h"
-#include "wasm.h"
#include "wasm-printing.h"
+#include "wasm.h"
namespace wasm {
@@ -38,7 +38,8 @@ struct ParseException {
ParseException() : text("unknown parse error"), line(-1), col(-1) {}
ParseException(std::string text) : text(text), line(-1), col(-1) {}
- ParseException(std::string text, size_t line, size_t col) : text(text), line(line), col(col) {}
+ ParseException(std::string text, size_t line, size_t col)
+ : text(text), line(line), col(col) {}
void dump(std::ostream& o) const {
Colors::magenta(o);
@@ -76,47 +77,63 @@ struct MapParseException {
}
};
-inline Expression* parseConst(cashew::IString s, Type type, MixedArena& allocator) {
- const char *str = s.str;
+inline Expression*
+parseConst(cashew::IString s, Type type, MixedArena& allocator) {
+ const char* str = s.str;
auto ret = allocator.alloc<Const>();
ret->type = type;
if (isFloatType(type)) {
if (s == _INFINITY) {
switch (type) {
- case f32: ret->value = Literal(std::numeric_limits<float>::infinity()); break;
- case f64: ret->value = Literal(std::numeric_limits<double>::infinity()); break;
- default: return nullptr;
+ case f32:
+ ret->value = Literal(std::numeric_limits<float>::infinity());
+ break;
+ case f64:
+ ret->value = Literal(std::numeric_limits<double>::infinity());
+ break;
+ default:
+ return nullptr;
}
- //std::cerr << "make constant " << str << " ==> " << ret->value << '\n';
+ // std::cerr << "make constant " << str << " ==> " << ret->value << '\n';
return ret;
}
if (s == NEG_INFINITY) {
switch (type) {
- case f32: ret->value = Literal(-std::numeric_limits<float>::infinity()); break;
- case f64: ret->value = Literal(-std::numeric_limits<double>::infinity()); break;
- default: return nullptr;
+ case f32:
+ ret->value = Literal(-std::numeric_limits<float>::infinity());
+ break;
+ case f64:
+ ret->value = Literal(-std::numeric_limits<double>::infinity());
+ break;
+ default:
+ return nullptr;
}
- //std::cerr << "make constant " << str << " ==> " << ret->value << '\n';
+ // std::cerr << "make constant " << str << " ==> " << ret->value << '\n';
return ret;
}
if (s == _NAN) {
switch (type) {
- case f32: ret->value = Literal(float(std::nan(""))); break;
- case f64: ret->value = Literal(double(std::nan(""))); break;
- default: return nullptr;
+ case f32:
+ ret->value = Literal(float(std::nan("")));
+ break;
+ case f64:
+ ret->value = Literal(double(std::nan("")));
+ break;
+ default:
+ return nullptr;
}
- //std::cerr << "make constant " << str << " ==> " << ret->value << '\n';
+ // std::cerr << "make constant " << str << " ==> " << ret->value << '\n';
return ret;
}
bool negative = str[0] == '-';
- const char *positive = negative ? str + 1 : str;
+ const char* positive = negative ? str + 1 : str;
if (!negative) {
if (positive[0] == '+') {
positive++;
}
}
if (positive[0] == 'n' && positive[1] == 'a' && positive[2] == 'n') {
- const char * modifier = positive[3] == ':' ? positive + 4 : nullptr;
+ const char* modifier = positive[3] == ':' ? positive + 4 : nullptr;
if (!(modifier ? positive[4] == '0' && positive[5] == 'x' : 1)) {
throw ParseException("bad nan input");
}
@@ -126,13 +143,16 @@ inline Expression* parseConst(cashew::IString s, Type type, MixedArena& allocato
if (modifier) {
std::istringstream istr(modifier);
istr >> std::hex >> pattern;
- if (istr.fail()) throw ParseException("invalid f32 format");
+ if (istr.fail())
+ throw ParseException("invalid f32 format");
pattern |= 0x7f800000U;
} else {
pattern = 0x7fc00000U;
}
- if (negative) pattern |= 0x80000000U;
- if (!std::isnan(bit_cast<float>(pattern))) pattern |= 1U;
+ if (negative)
+ pattern |= 0x80000000U;
+ if (!std::isnan(bit_cast<float>(pattern)))
+ pattern |= 1U;
ret->value = Literal(pattern).castToF32();
break;
}
@@ -141,79 +161,97 @@ inline Expression* parseConst(cashew::IString s, Type type, MixedArena& allocato
if (modifier) {
std::istringstream istr(modifier);
istr >> std::hex >> pattern;
- if (istr.fail()) throw ParseException("invalid f64 format");
+ if (istr.fail())
+ throw ParseException("invalid f64 format");
pattern |= 0x7ff0000000000000ULL;
} else {
pattern = 0x7ff8000000000000UL;
}
- if (negative) pattern |= 0x8000000000000000ULL;
- if (!std::isnan(bit_cast<double>(pattern))) pattern |= 1ULL;
+ if (negative)
+ pattern |= 0x8000000000000000ULL;
+ if (!std::isnan(bit_cast<double>(pattern)))
+ pattern |= 1ULL;
ret->value = Literal(pattern).castToF64();
break;
}
- default: return nullptr;
+ default:
+ return nullptr;
}
- //std::cerr << "make constant " << str << " ==> " << ret->value << '\n';
+ // std::cerr << "make constant " << str << " ==> " << ret->value << '\n';
return ret;
}
if (s == NEG_NAN) {
switch (type) {
- case f32: ret->value = Literal(float(-std::nan(""))); break;
- case f64: ret->value = Literal(double(-std::nan(""))); break;
- default: return nullptr;
+ case f32:
+ ret->value = Literal(float(-std::nan("")));
+ break;
+ case f64:
+ ret->value = Literal(double(-std::nan("")));
+ break;
+ default:
+ return nullptr;
}
- //std::cerr << "make constant " << str << " ==> " << ret->value << '\n';
+ // std::cerr << "make constant " << str << " ==> " << ret->value << '\n';
return ret;
}
}
switch (type) {
case i32: {
- if ((str[0] == '0' && str[1] == 'x') || (str[0] == '-' && str[1] == '0' && str[2] == 'x')) {
+ if ((str[0] == '0' && str[1] == 'x') ||
+ (str[0] == '-' && str[1] == '0' && str[2] == 'x')) {
bool negative = str[0] == '-';
- if (negative) str++;
+ if (negative)
+ str++;
std::istringstream istr(str);
uint32_t temp;
istr >> std::hex >> temp;
- if (istr.fail()) throw ParseException("invalid i32 format");
+ if (istr.fail())
+ throw ParseException("invalid i32 format");
ret->value = Literal(negative ? -temp : temp);
} else {
std::istringstream istr(str[0] == '-' ? str + 1 : str);
uint32_t temp;
istr >> temp;
- if (istr.fail()) throw ParseException("invalid i32 format");
+ if (istr.fail())
+ throw ParseException("invalid i32 format");
ret->value = Literal(str[0] == '-' ? -temp : temp);
}
break;
}
case i64: {
- if ((str[0] == '0' && str[1] == 'x') || (str[0] == '-' && str[1] == '0' && str[2] == 'x')) {
+ if ((str[0] == '0' && str[1] == 'x') ||
+ (str[0] == '-' && str[1] == '0' && str[2] == 'x')) {
bool negative = str[0] == '-';
- if (negative) str++;
+ if (negative)
+ str++;
std::istringstream istr(str);
uint64_t temp;
istr >> std::hex >> temp;
- if (istr.fail()) throw ParseException("invalid i64 format");
+ if (istr.fail())
+ throw ParseException("invalid i64 format");
ret->value = Literal(negative ? -temp : temp);
} else {
std::istringstream istr(str[0] == '-' ? str + 1 : str);
uint64_t temp;
istr >> temp;
- if (istr.fail()) throw ParseException("invalid i64 format");
+ if (istr.fail())
+ throw ParseException("invalid i64 format");
ret->value = Literal(str[0] == '-' ? -temp : temp);
}
break;
}
case f32: {
- char *end;
+ char* end;
ret->value = Literal(strtof(str, &end));
break;
}
case f64: {
- char *end;
+ char* end;
ret->value = Literal(strtod(str, &end));
break;
}
- case v128: WASM_UNREACHABLE();
+ case v128:
+ WASM_UNREACHABLE();
case none:
case unreachable: {
return nullptr;
@@ -222,7 +260,7 @@ inline Expression* parseConst(cashew::IString s, Type type, MixedArena& allocato
if (ret->value.type != type) {
throw ParseException("parsed type does not match expected type");
}
- //std::cerr << "make constant " << str << " ==> " << ret->value << '\n';
+ // std::cerr << "make constant " << str << " ==> " << ret->value << '\n';
return ret;
}
@@ -230,17 +268,20 @@ inline Expression* parseConst(cashew::IString s, Type type, MixedArena& allocato
// the names into unique ones, as required by Binaryen IR.
struct UniqueNameMapper {
std::vector<Name> labelStack;
- std::map<Name, std::vector<Name>> labelMappings; // name in source => stack of uniquified names
+ // name in source => stack of uniquified names
+ std::map<Name, std::vector<Name>> labelMappings;
std::map<Name, Name> reverseLabelMapping; // uniquified name => name in source
Index otherIndex = 0;
Name getPrefixedName(Name prefix) {
- if (reverseLabelMapping.find(prefix) == reverseLabelMapping.end()) return prefix;
+ if (reverseLabelMapping.find(prefix) == reverseLabelMapping.end())
+ return prefix;
// make sure to return a unique name not already on the stack
while (1) {
Name ret = Name(prefix.str + std::to_string(otherIndex++));
- if (reverseLabelMapping.find(ret) == reverseLabelMapping.end()) return ret;
+ if (reverseLabelMapping.find(ret) == reverseLabelMapping.end())
+ return ret;
}
}
@@ -290,24 +331,28 @@ struct UniqueNameMapper {
static void doPreVisitControlFlow(Walker* self, Expression** currp) {
auto* curr = *currp;
if (auto* block = curr->dynCast<Block>()) {
- if (block->name.is()) block->name = self->mapper.pushLabelName(block->name);
+ if (block->name.is())
+ block->name = self->mapper.pushLabelName(block->name);
} else if (auto* loop = curr->dynCast<Loop>()) {
- if (loop->name.is()) loop->name = self->mapper.pushLabelName(loop->name);
+ if (loop->name.is())
+ loop->name = self->mapper.pushLabelName(loop->name);
}
}
static void doPostVisitControlFlow(Walker* self, Expression** currp) {
auto* curr = *currp;
if (auto* block = curr->dynCast<Block>()) {
- if (block->name.is()) self->mapper.popLabelName(block->name);
+ if (block->name.is())
+ self->mapper.popLabelName(block->name);
} else if (auto* loop = curr->dynCast<Loop>()) {
- if (loop->name.is()) self->mapper.popLabelName(loop->name);
+ if (loop->name.is())
+ self->mapper.popLabelName(loop->name);
}
}
- void visitBreak(Break *curr) {
+ void visitBreak(Break* curr) {
curr->name = mapper.sourceToUnique(curr->name);
}
- void visitSwitch(Switch *curr) {
+ void visitSwitch(Switch* curr) {
for (auto& target : curr->targets) {
target = mapper.sourceToUnique(target);
}
diff --git a/src/pass.h b/src/pass.h
index 65bf7bf52..720e5c992 100644
--- a/src/pass.h
+++ b/src/pass.h
@@ -19,10 +19,10 @@
#include <functional>
-#include "wasm.h"
-#include "wasm-traversal.h"
#include "mixed_arena.h"
#include "support/utilities.h"
+#include "wasm-traversal.h"
+#include "wasm.h"
namespace wasm {
@@ -36,9 +36,9 @@ struct PassRegistry {
static PassRegistry* get();
- typedef std::function<Pass* ()> Creator;
+ typedef std::function<Pass*()> Creator;
- void registerPass(const char* name, const char *description, Creator create);
+ void registerPass(const char* name, const char* description, Creator create);
Pass* createPass(std::string name);
std::vector<std::string> getRegisteredNames();
std::string getPassDescription(std::string name);
@@ -50,7 +50,8 @@ private:
std::string description;
Creator create;
PassInfo() = default;
- PassInfo(std::string description, Creator create) : description(description), create(create) {}
+ PassInfo(std::string description, Creator create)
+ : description(description), create(create) {}
};
std::map<std::string, PassInfo> passInfos;
};
@@ -68,13 +69,15 @@ struct PassOptions {
int shrinkLevel = 0;
// Optimize assuming things like div by 0, bad load/store, will not trap.
bool ignoreImplicitTraps = false;
- // Optimize assuming that the low 1K of memory is not valid memory for the application
- // to use. In that case, we can optimize load/store offsets in many cases.
+ // Optimize assuming that the low 1K of memory is not valid memory for the
+ // application to use. In that case, we can optimize load/store offsets in
+ // many cases.
bool lowMemoryUnused = false;
enum { LowMemoryBound = 1024 };
// Whether to try to preserve debug info through, which are special calls.
bool debugInfo = false;
- // Arbitrary string arguments from the commandline, which we forward to passes.
+ // Arbitrary string arguments from the commandline, which we forward to
+ // passes.
std::map<std::string, std::string> arguments;
void setDefaultOptimizationOptions() {
@@ -111,7 +114,8 @@ struct PassRunner {
PassOptions options;
PassRunner(Module* wasm) : wasm(wasm), allocator(&wasm->allocator) {}
- PassRunner(Module* wasm, PassOptions options) : wasm(wasm), allocator(&wasm->allocator), options(options) {}
+ PassRunner(Module* wasm, PassOptions options)
+ : wasm(wasm), allocator(&wasm->allocator), options(options) {}
// no copying, we control |passes|
PassRunner(const PassRunner&) = delete;
@@ -119,30 +123,24 @@ struct PassRunner {
void setDebug(bool debug) {
options.debug = debug;
- options.validateGlobally = debug; // validate everything by default if debugging
- }
- void setDebugInfo(bool debugInfo) {
- options.debugInfo = debugInfo;
+ // validate everything by default if debugging
+ options.validateGlobally = debug;
}
+ void setDebugInfo(bool debugInfo) { options.debugInfo = debugInfo; }
void setValidateGlobally(bool validate) {
options.validateGlobally = validate;
}
void add(std::string passName) {
auto pass = PassRegistry::get()->createPass(passName);
- if (!pass) Fatal() << "Could not find pass: " << passName << "\n";
+ if (!pass)
+ Fatal() << "Could not find pass: " << passName << "\n";
doAdd(pass);
}
- template<class P>
- void add() {
- doAdd(new P());
- }
+ template<class P> void add() { doAdd(new P()); }
- template<class P, class Arg>
- void add(Arg arg){
- doAdd(new P(arg));
- }
+ template<class P, class Arg> void add(Arg arg) { doAdd(new P(arg)); }
// Adds the default set of optimization passes; this is
// what -O does.
@@ -172,26 +170,24 @@ struct PassRunner {
void runOnFunction(Function* func);
// Get the last pass that was already executed of a certain type.
- template<class P>
- P* getLast();
+ template<class P> P* getLast();
~PassRunner();
// When running a pass runner within another pass runner, this
// flag should be set. This influences how pass debugging works,
// and may influence other things in the future too.
- void setIsNested(bool nested) {
- isNested = nested;
- }
+ void setIsNested(bool nested) { isNested = nested; }
- // BINARYEN_PASS_DEBUG is a convenient commandline way to log out the toplevel passes, their times,
- // and validate between each pass.
- // (we don't recurse pass debug into sub-passes, as it doesn't help anyhow and
- // also is bad for e.g. printing which is a pass)
+ // BINARYEN_PASS_DEBUG is a convenient commandline way to log out the toplevel
+ // passes, their times, and validate between each pass.
+ // (we don't recurse pass debug into sub-passes, as it
+ // doesn't help anyhow and also is bad for e.g. printing
+ // which is a pass)
// this method returns whether we are in passDebug mode, and which value:
// 1: run pass by pass, validating in between
- // 2: also save the last pass, so it breakage happens we can print the last one
- // 3: also dump out byn-* files for each pass
+ // 2: also save the last pass, so it breakage happens we can print the last
+ // one 3: also dump out byn-* files for each pass
static int getPassDebug();
protected:
@@ -209,7 +205,7 @@ private:
// invalidates.
// If a function is passed, we operate just on that function;
// otherwise, the whole module.
- void handleAfterEffects(Pass* pass, Function* func=nullptr);
+ void handleAfterEffects(Pass* pass, Function* func = nullptr);
};
//
@@ -224,13 +220,12 @@ public:
virtual void prepareToRun(PassRunner* runner, Module* module) {}
// Implement this with code to run the pass on the whole module
- virtual void run(PassRunner* runner, Module* module) {
- WASM_UNREACHABLE();
- }
+ virtual void run(PassRunner* runner, Module* module) { WASM_UNREACHABLE(); }
// Implement this with code to run the pass on a single function, for
// a function-parallel pass
- virtual void runOnFunction(PassRunner* runner, Module* module, Function* function) {
+ virtual void
+ runOnFunction(PassRunner* runner, Module* module, Function* function) {
WASM_UNREACHABLE();
}
@@ -242,10 +237,10 @@ public:
// if you do not ad global state that could be raced on, your pass could be
// function-parallel.
//
- // Function-parallel passes create an instance of the Walker class per function.
- // That means that you can't rely on Walker object properties to persist across
- // your functions, and you can't expect a new object to be created for each
- // function either (which could be very inefficient).
+ // Function-parallel passes create an instance of the Walker class per
+ // function. That means that you can't rely on Walker object properties to
+ // persist across your functions, and you can't expect a new object to be
+ // created for each function either (which could be very inefficient).
//
// It is valid for function-parallel passes to read (but not modify) global
// module state, like globals or imports. However, reading other functions'
@@ -253,9 +248,9 @@ public:
// adding functions to the module.
virtual bool isFunctionParallel() { return false; }
- // This method is used to create instances per function for a function-parallel
- // pass. You may need to override this if you subclass a Walker, as otherwise
- // this will create the parent class.
+ // This method is used to create instances per function for a
+ // function-parallel pass. You may need to override this if you subclass a
+ // Walker, as otherwise this will create the parent class.
virtual Pass* create() { WASM_UNREACHABLE(); }
// Whether this pass modifies the Binaryen IR in the module. This is true for
@@ -270,8 +265,8 @@ public:
protected:
Pass() = default;
- Pass(Pass &) = default;
- Pass &operator=(const Pass&) = delete;
+ Pass(Pass&) = default;
+ Pass& operator=(const Pass&) = delete;
};
//
@@ -280,7 +275,7 @@ protected:
//
template<typename WalkerType>
class WalkerPass : public Pass, public WalkerType {
- PassRunner *runner;
+ PassRunner* runner;
protected:
typedef WalkerPass<WalkerType> super;
@@ -292,23 +287,18 @@ public:
WalkerType::walkModule(module);
}
- void runOnFunction(PassRunner* runner, Module* module, Function* func) override {
+ void
+ runOnFunction(PassRunner* runner, Module* module, Function* func) override {
setPassRunner(runner);
WalkerType::setModule(module);
WalkerType::walkFunction(func);
}
- PassRunner* getPassRunner() {
- return runner;
- }
+ PassRunner* getPassRunner() { return runner; }
- PassOptions& getPassOptions() {
- return runner->options;
- }
+ PassOptions& getPassOptions() { return runner->options; }
- void setPassRunner(PassRunner* runner_) {
- runner = runner_;
- }
+ void setPassRunner(PassRunner* runner_) { runner = runner_; }
};
} // namespace wasm
diff --git a/src/passes/CoalesceLocals.cpp b/src/passes/CoalesceLocals.cpp
index 621383ca4..a085b61fb 100644
--- a/src/passes/CoalesceLocals.cpp
+++ b/src/passes/CoalesceLocals.cpp
@@ -14,32 +14,31 @@
* limitations under the License.
*/
-
//
// Coalesce locals, in order to reduce the total number of locals. This
// is similar to register allocation, however, there is never any
// spilling, and there isn't a fixed number of locals.
//
-
#include <algorithm>
#include <memory>
#include <unordered_set>
-#include "wasm.h"
-#include "pass.h"
-#include "ir/utils.h"
#include "cfg/liveness-traversal.h"
-#include "wasm-builder.h"
+#include "ir/utils.h"
+#include "pass.h"
#include "support/learning.h"
#include "support/permutations.h"
+#include "wasm-builder.h"
+#include "wasm.h"
#ifdef CFG_PROFILE
#include "support/timing.h"
#endif
namespace wasm {
-struct CoalesceLocals : public WalkerPass<LivenessWalker<CoalesceLocals, Visitor<CoalesceLocals>>> {
+struct CoalesceLocals
+ : public WalkerPass<LivenessWalker<CoalesceLocals, Visitor<CoalesceLocals>>> {
bool isFunctionParallel() override { return true; }
Pass* create() override { return new CoalesceLocals; }
@@ -54,23 +53,30 @@ struct CoalesceLocals : public WalkerPass<LivenessWalker<CoalesceLocals, Visitor
void calculateInterferences(const LocalSet& locals);
- void pickIndicesFromOrder(std::vector<Index>& order, std::vector<Index>& indices);
- void pickIndicesFromOrder(std::vector<Index>& order, std::vector<Index>& indices, Index& removedCopies);
+ void pickIndicesFromOrder(std::vector<Index>& order,
+ std::vector<Index>& indices);
+ void pickIndicesFromOrder(std::vector<Index>& order,
+ std::vector<Index>& indices,
+ Index& removedCopies);
- virtual void pickIndices(std::vector<Index>& indices); // returns a vector of oldIndex => newIndex
+ // returns a vector of oldIndex => newIndex
+ virtual void pickIndices(std::vector<Index>& indices);
void applyIndices(std::vector<Index>& indices, Expression* root);
// interference state
- std::vector<bool> interferences; // canonicalized - accesses should check (low, high)
+ // canonicalized - accesses should check (low, high)
+ std::vector<bool> interferences;
void interfere(Index i, Index j) {
- if (i == j) return;
+ if (i == j)
+ return;
interferences[std::min(i, j) * numLocals + std::max(i, j)] = 1;
}
- void interfereLowHigh(Index low, Index high) { // optimized version where you know that low < high
+ // optimized version where you know that low < high
+ void interfereLowHigh(Index low, Index high) {
assert(low < high);
interferences[low * numLocals + high] = 1;
}
@@ -97,20 +103,25 @@ void CoalesceLocals::doWalkFunction(Function* func) {
applyIndices(indices, func->body);
}
-// A copy on a backedge can be especially costly, forcing us to branch just to do that copy.
-// Add weight to such copies, so we prioritize getting rid of them.
+// A copy on a backedge can be especially costly, forcing us to branch just to
+// do that copy. Add weight to such copies, so we prioritize getting rid of
+// them.
void CoalesceLocals::increaseBackEdgePriorities() {
for (auto* loopTop : loopTops) {
// ignore the first edge, it is the initial entry, we just want backedges
auto& in = loopTop->in;
for (Index i = 1; i < in.size(); i++) {
auto* arrivingBlock = in[i];
- if (arrivingBlock->out.size() > 1) continue; // we just want unconditional branches to the loop top, true phi fragments
+ if (arrivingBlock->out.size() > 1)
+ // we just want unconditional branches to the loop top, true phi
+ // fragments
+ continue;
for (auto& action : arrivingBlock->contents.actions) {
if (action.isSet()) {
auto* set = (*action.origin)->cast<SetLocal>();
if (auto* get = getCopy(set)) {
- // this is indeed a copy, add to the cost (default cost is 2, so this adds 50%, and can mostly break ties)
+ // this is indeed a copy, add to the cost (default cost is 2, so
+ // this adds 50%, and can mostly break ties)
addCopy(set->index, get->index);
}
}
@@ -123,8 +134,10 @@ void CoalesceLocals::calculateInterferences() {
interferences.resize(numLocals * numLocals);
std::fill(interferences.begin(), interferences.end(), false);
for (auto& curr : basicBlocks) {
- if (liveBlocks.count(curr.get()) == 0) continue; // ignore dead blocks
- // everything coming in might interfere, as it might come from a different block
+ if (liveBlocks.count(curr.get()) == 0)
+ continue; // ignore dead blocks
+ // everything coming in might interfere, as it might come from a different
+ // block
auto live = curr->contents.end;
calculateInterferences(live);
// scan through the block itself
@@ -166,18 +179,22 @@ void CoalesceLocals::calculateInterferences(const LocalSet& locals) {
// Indices decision making
-void CoalesceLocals::pickIndicesFromOrder(std::vector<Index>& order, std::vector<Index>& indices) {
+void CoalesceLocals::pickIndicesFromOrder(std::vector<Index>& order,
+ std::vector<Index>& indices) {
Index removedCopies;
pickIndicesFromOrder(order, indices, removedCopies);
}
-void CoalesceLocals::pickIndicesFromOrder(std::vector<Index>& order, std::vector<Index>& indices, Index& removedCopies) {
- // mostly-simple greedy coloring
+void CoalesceLocals::pickIndicesFromOrder(std::vector<Index>& order,
+ std::vector<Index>& indices,
+ Index& removedCopies) {
+// mostly-simple greedy coloring
#if CFG_DEBUG
std::cerr << "\npickIndicesFromOrder on " << getFunction()->name << '\n';
std::cerr << getFunction()->body << '\n';
std::cerr << "order:\n";
- for (auto i : order) std::cerr << i << ' ';
+ for (auto i : order)
+ std::cerr << i << ' ';
std::cerr << '\n';
std::cerr << "interferences:\n";
for (Index i = 0; i < numLocals; i++) {
@@ -204,16 +221,20 @@ void CoalesceLocals::pickIndicesFromOrder(std::vector<Index>& order, std::vector
std::cerr << " $" << i << ": " << totalCopies[i] << '\n';
}
#endif
- // TODO: take into account distribution (99-1 is better than 50-50 with two registers, for gzip)
+ // TODO: take into account distribution (99-1 is better than 50-50 with two
+ // registers, for gzip)
std::vector<Type> types;
- std::vector<bool> newInterferences; // new index * numLocals => list of all interferences of locals merged to it
- std::vector<uint8_t> newCopies; // new index * numLocals => list of all copies of locals merged to it
+ // new index * numLocals => list of all interferences of locals merged to it
+ std::vector<bool> newInterferences;
+ // new index * numLocals => list of all copies of locals merged to it
+ std::vector<uint8_t> newCopies;
indices.resize(numLocals);
types.resize(numLocals);
newInterferences.resize(numLocals * numLocals);
std::fill(newInterferences.begin(), newInterferences.end(), false);
auto numParams = getFunction()->getNumParams();
- newCopies.resize(numParams * numLocals); // start with enough room for the params
+ // start with enough room for the params
+ newCopies.resize(numParams * numLocals);
std::fill(newCopies.begin(), newCopies.end(), 0);
Index nextFree = 0;
removedCopies = 0;
@@ -234,9 +255,12 @@ void CoalesceLocals::pickIndicesFromOrder(std::vector<Index>& order, std::vector
Index found = -1;
uint8_t foundCopies = -1;
for (Index j = 0; j < nextFree; j++) {
- if (!newInterferences[j * numLocals + actual] && getFunction()->getLocalType(actual) == types[j]) {
- // this does not interfere, so it might be what we want. but pick the one eliminating the most copies
- // (we could stop looking forward when there are no more items that have copies anyhow, but it doesn't seem to help)
+ if (!newInterferences[j * numLocals + actual] &&
+ getFunction()->getLocalType(actual) == types[j]) {
+ // this does not interfere, so it might be what we want. but pick the
+ // one eliminating the most copies (we could stop looking forward when
+ // there are no more items that have copies anyhow, but it doesn't seem
+ // to help)
auto currCopies = newCopies[j * numLocals + actual];
if (found == Index(-1) || currCopies > foundCopies) {
indices[actual] = found = j;
@@ -258,46 +282,53 @@ void CoalesceLocals::pickIndicesFromOrder(std::vector<Index>& order, std::vector
#endif
// merge new interferences and copies for the new index
for (Index k = i + 1; k < numLocals; k++) {
- auto j = order[k]; // go in the order, we only need to update for those we will see later
- newInterferences[found * numLocals + j] = newInterferences[found * numLocals + j] | interferes(actual, j);
+ // go in the order, we only need to update for those we will see later
+ auto j = order[k];
+ newInterferences[found * numLocals + j] =
+ newInterferences[found * numLocals + j] | interferes(actual, j);
newCopies[found * numLocals + j] += getCopies(actual, j);
}
}
}
-// given a baseline order, adjust it based on an important order of priorities (higher values
-// are higher priority). The priorities take precedence, unless they are equal and then
-// the original order should be kept.
-std::vector<Index> adjustOrderByPriorities(std::vector<Index>& baseline, std::vector<Index>& priorities) {
+// given a baseline order, adjust it based on an important order of priorities
+// (higher values are higher priority). The priorities take precedence, unless
+// they are equal and then the original order should be kept.
+std::vector<Index> adjustOrderByPriorities(std::vector<Index>& baseline,
+ std::vector<Index>& priorities) {
std::vector<Index> ret = baseline;
std::vector<Index> reversed = makeReversed(baseline);
std::sort(ret.begin(), ret.end(), [&priorities, &reversed](Index x, Index y) {
- return priorities[x] > priorities[y] || (priorities[x] == priorities[y] && reversed[x] < reversed[y]);
+ return priorities[x] > priorities[y] ||
+ (priorities[x] == priorities[y] && reversed[x] < reversed[y]);
});
return ret;
}
void CoalesceLocals::pickIndices(std::vector<Index>& indices) {
- if (numLocals == 0) return;
+ if (numLocals == 0)
+ return;
if (numLocals == 1) {
indices.push_back(0);
return;
}
- // take into account total copies. but we must keep params in place, so give them max priority
+ // take into account total copies. but we must keep params in place, so give
+ // them max priority
auto adjustedTotalCopies = totalCopies;
auto numParams = getFunction()->getNumParams();
for (Index i = 0; i < numParams; i++) {
adjustedTotalCopies[i] = std::numeric_limits<Index>::max();
}
- // first try the natural order. this is less arbitrary than it seems, as the program
- // may have a natural order of locals inherent in it.
+ // first try the natural order. this is less arbitrary than it seems, as the
+ // program may have a natural order of locals inherent in it.
auto order = makeIdentity(numLocals);
order = adjustOrderByPriorities(order, adjustedTotalCopies);
Index removedCopies;
pickIndicesFromOrder(order, indices, removedCopies);
auto maxIndex = *std::max_element(indices.begin(), indices.end());
- // next try the reverse order. this both gives us another chance at something good,
- // and also the very naturalness of the simple order may be quite suboptimal
+ // next try the reverse order. this both gives us another chance at something
+ // good, and also the very naturalness of the simple order may be quite
+ // suboptimal
setIdentity(order);
for (Index i = numParams; i < numLocals; i++) {
order[i] = numParams + numLocals - 1 - i;
@@ -306,15 +337,18 @@ void CoalesceLocals::pickIndices(std::vector<Index>& indices) {
std::vector<Index> reverseIndices;
Index reverseRemovedCopies;
pickIndicesFromOrder(order, reverseIndices, reverseRemovedCopies);
- auto reverseMaxIndex = *std::max_element(reverseIndices.begin(), reverseIndices.end());
- // prefer to remove copies foremost, as it matters more for code size (minus gzip), and
- // improves throughput.
- if (reverseRemovedCopies > removedCopies || (reverseRemovedCopies == removedCopies && reverseMaxIndex < maxIndex)) {
+ auto reverseMaxIndex =
+ *std::max_element(reverseIndices.begin(), reverseIndices.end());
+ // prefer to remove copies foremost, as it matters more for code size (minus
+ // gzip), and improves throughput.
+ if (reverseRemovedCopies > removedCopies ||
+ (reverseRemovedCopies == removedCopies && reverseMaxIndex < maxIndex)) {
indices.swap(reverseIndices);
}
}
-void CoalesceLocals::applyIndices(std::vector<Index>& indices, Expression* root) {
+void CoalesceLocals::applyIndices(std::vector<Index>& indices,
+ Expression* root) {
assert(indices.size() == numLocals);
for (auto& curr : basicBlocks) {
auto& actions = curr->contents.actions;
@@ -325,15 +359,19 @@ void CoalesceLocals::applyIndices(std::vector<Index>& indices, Expression* root)
} else if (action.isSet()) {
auto* set = (*action.origin)->cast<SetLocal>();
set->index = indices[set->index];
- // in addition, we can optimize out redundant copies and ineffective sets
+ // in addition, we can optimize out redundant copies and ineffective
+ // sets
GetLocal* get;
- if ((get = set->value->dynCast<GetLocal>()) && get->index == set->index) {
+ if ((get = set->value->dynCast<GetLocal>()) &&
+ get->index == set->index) {
action.removeCopy();
continue;
}
// remove ineffective actions
if (!action.effective) {
- *action.origin = set->value; // value may have no side effects, further optimizations can eliminate it
+ // value may have no side effects, further optimizations can eliminate
+ // it
+ *action.origin = set->value;
if (!set->isTee()) {
// we need to drop it
Drop* drop = ExpressionManipulator::convert<SetLocal, Drop>(set);
@@ -382,10 +420,12 @@ void CoalesceLocalsWithLearning::pickIndices(std::vector<Index>& indices) {
double getFitness() { return fitness; }
void dump(std::string text) {
std::cout << text + ": ( ";
- for (Index i = 0; i < size(); i++) std::cout << (*this)[i] << " ";
+ for (Index i = 0; i < size(); i++)
+ std::cout << (*this)[i] << " ";
std::cout << ")\n";
std::cout << "of quality: " << getFitness() << "\n";
}
+
private:
double fitness;
};
@@ -405,9 +445,11 @@ void CoalesceLocalsWithLearning::pickIndices(std::vector<Index>& indices) {
// secondarily, it is nice to not reorder locals unnecessarily
double fragment = 1.0 / (2.0 * parent->numLocals);
for (Index i = 0; i < parent->numLocals; i++) {
- if ((*order)[i] == i) fitness += fragment; // boost for each that wasn't moved
+ if ((*order)[i] == i)
+ fitness += fragment; // boost for each that wasn't moved
}
- fitness = (100 * fitness) + removedCopies; // removing copies is a secondary concern
+ // removing copies is a secondary concern
+ fitness = (100 * fitness) + removedCopies;
order->setFitness(fitness);
}
@@ -418,16 +460,19 @@ void CoalesceLocalsWithLearning::pickIndices(std::vector<Index>& indices) {
(*ret)[i] = i;
}
if (first) {
- // as the first guess, use the natural order. this is not arbitrary for two reasons.
- // first, there may be an inherent order in the input (frequent indices are lower,
- // etc.). second, by ensuring we start with the natural order, we ensure we are at
- // least as good as the non-learning variant.
- // TODO: use ::pickIndices from the parent, so we literally get the simpler approach
- // as our first option
+ // as the first guess, use the natural order. this is not arbitrary for
+ // two reasons. first, there may be an inherent order in the input
+ // (frequent indices are lower, etc.). second, by ensuring we start with
+ // the natural order, we ensure we are at least as good as the
+ // non-learning variant.
+ // TODO: use ::pickIndices from the parent, so we literally get the
+ // simpler approach as our first option
first = false;
} else {
// leave params alone, shuffle the rest
- std::shuffle(ret->begin() + parent->getFunction()->getNumParams(), ret->end(), noise);
+ std::shuffle(ret->begin() + parent->getFunction()->getNumParams(),
+ ret->end(),
+ noise);
}
calculateFitness(ret);
#ifdef CFG_LEARN_DEBUG
@@ -455,7 +500,9 @@ void CoalesceLocalsWithLearning::pickIndices(std::vector<Index>& indices) {
// if (i, i + 1) is in reverse order in right, flip them
if (reverseRight[(*ret)[i]] > reverseRight[(*ret)[i + 1]]) {
std::swap((*ret)[i], (*ret)[i + 1]);
- i++; // if we don't skip, we might end up pushing an element all the way to the end, which is not very perturbation-y
+ // if we don't skip, we might end up pushing an element all the way to
+ // the end, which is not very perturbation-y
+ i++;
}
}
calculateFitness(ret);
@@ -475,7 +522,8 @@ void CoalesceLocalsWithLearning::pickIndices(std::vector<Index>& indices) {
std::cout << "[learning for " << getFunction()->name << "]\n";
#endif
auto numVars = this->getFunction()->getNumVars();
- const int GENERATION_SIZE = std::min(Index(numVars * (numVars - 1)), Index(20));
+ const int GENERATION_SIZE =
+ std::min(Index(numVars * (numVars - 1)), Index(20));
Generator generator(this);
GeneticLearner<Order, double, Generator> learner(generator, GENERATION_SIZE);
#ifdef CFG_LEARN_DEBUG
@@ -486,7 +534,8 @@ void CoalesceLocalsWithLearning::pickIndices(std::vector<Index>& indices) {
while (1) {
learner.runGeneration();
auto newBest = learner.getBest()->getFitness();
- if (newBest == oldBest) break; // unlikely we can improve
+ if (newBest == oldBest)
+ break; // unlikely we can improve
oldBest = newBest;
#ifdef CFG_LEARN_DEBUG
learner.getBest()->dump("current best");
@@ -495,16 +544,15 @@ void CoalesceLocalsWithLearning::pickIndices(std::vector<Index>& indices) {
#ifdef CFG_LEARN_DEBUG
learner.getBest()->dump("the best");
#endif
- this->pickIndicesFromOrder(*learner.getBest(), indices); // TODO: cache indices in Orders, at the cost of more memory?
+ // TODO: cache indices in Orders, at the cost of more memory?
+ this->pickIndicesFromOrder(*learner.getBest(), indices);
}
// declare passes
-Pass *createCoalesceLocalsPass() {
- return new CoalesceLocals();
-}
+Pass* createCoalesceLocalsPass() { return new CoalesceLocals(); }
-Pass *createCoalesceLocalsWithLearningPass() {
+Pass* createCoalesceLocalsWithLearningPass() {
return new CoalesceLocalsWithLearning();
}
diff --git a/src/passes/CodeFolding.cpp b/src/passes/CodeFolding.cpp
index a79980cfe..0479472d8 100644
--- a/src/passes/CodeFolding.cpp
+++ b/src/passes/CodeFolding.cpp
@@ -57,28 +57,29 @@
#include <iterator>
-#include "wasm.h"
-#include "pass.h"
-#include "wasm-builder.h"
-#include "ir/utils.h"
#include "ir/branch-utils.h"
#include "ir/effects.h"
#include "ir/label-utils.h"
+#include "ir/utils.h"
+#include "pass.h"
+#include "wasm-builder.h"
+#include "wasm.h"
namespace wasm {
static const Index WORTH_ADDING_BLOCK_TO_REMOVE_THIS_MUCH = 3;
-struct ExpressionMarker : public PostWalker<ExpressionMarker, UnifiedExpressionVisitor<ExpressionMarker>> {
+struct ExpressionMarker
+ : public PostWalker<ExpressionMarker,
+ UnifiedExpressionVisitor<ExpressionMarker>> {
std::set<Expression*>& marked;
- ExpressionMarker(std::set<Expression*>& marked, Expression* expr) : marked(marked) {
+ ExpressionMarker(std::set<Expression*>& marked, Expression* expr)
+ : marked(marked) {
walk(expr);
}
- void visitExpression(Expression* expr) {
- marked.insert(expr);
- }
+ void visitExpression(Expression* expr) { marked.insert(expr); }
};
struct CodeFolding : public WalkerPass<ControlFlowWalker<CodeFolding>> {
@@ -91,15 +92,18 @@ struct CodeFolding : public WalkerPass<ControlFlowWalker<CodeFolding>> {
struct Tail {
Expression* expr; // nullptr if this is a fallthrough
Block* block; // the enclosing block of code we hope to merge at its tail
- Expression** pointer; // for an expr with no parent block, the location it is at, so we can replace it
+ Expression** pointer; // for an expr with no parent block, the location it
+ // is at, so we can replace it
// For a fallthrough
Tail(Block* block) : expr(nullptr), block(block), pointer(nullptr) {}
// For a break
- Tail(Expression* expr, Block* block) : expr(expr), block(block), pointer(nullptr) {
+ Tail(Expression* expr, Block* block)
+ : expr(expr), block(block), pointer(nullptr) {
validate();
}
- Tail(Expression* expr, Expression** pointer) : expr(expr), block(nullptr), pointer(pointer) {}
+ Tail(Expression* expr, Expression** pointer)
+ : expr(expr), block(nullptr), pointer(pointer) {}
bool isFallthrough() const { return expr == nullptr; }
@@ -116,11 +120,13 @@ struct CodeFolding : public WalkerPass<ControlFlowWalker<CodeFolding>> {
// pass state
- std::map<Name, std::vector<Tail>> breakTails; // break target name => tails that reach it
+ std::map<Name, std::vector<Tail>> breakTails; // break target name => tails
+ // that reach it
std::vector<Tail> unreachableTails; // tails leading to (unreachable)
- std::vector<Tail> returnTails; // tails leading to (return)
- std::set<Name> unoptimizables; // break target names that we can't handle
- std::set<Expression*> modifieds; // modified code should not be processed again, wait for next pass
+ std::vector<Tail> returnTails; // tails leading to (return)
+ std::set<Name> unoptimizables; // break target names that we can't handle
+ std::set<Expression*> modifieds; // modified code should not be processed
+ // again, wait for next pass
// walking
@@ -167,20 +173,25 @@ struct CodeFolding : public WalkerPass<ControlFlowWalker<CodeFolding>> {
return;
}
}
- // otherwise, if we have a large value, it might be worth optimizing us as well
+ // otherwise, if we have a large value, it might be worth optimizing us as
+ // well
returnTails.push_back(Tail(curr, getCurrentPointer()));
}
void visitBlock(Block* curr) {
- if (curr->list.empty()) return;
- if (!curr->name.is()) return;
- if (unoptimizables.count(curr->name) > 0) return;
+ if (curr->list.empty())
+ return;
+ if (!curr->name.is())
+ return;
+ if (unoptimizables.count(curr->name) > 0)
+ return;
// we can't optimize a fallthrough value
if (isConcreteType(curr->list.back()->type)) {
return;
}
auto iter = breakTails.find(curr->name);
- if (iter == breakTails.end()) return;
+ if (iter == breakTails.end())
+ return;
// looks promising
auto& tails = iter->second;
// see if there is a fallthrough
@@ -191,23 +202,22 @@ struct CodeFolding : public WalkerPass<ControlFlowWalker<CodeFolding>> {
}
}
if (hasFallthrough) {
- tails.push_back({ Tail(curr) });
+ tails.push_back({Tail(curr)});
}
optimizeExpressionTails(tails, curr);
}
void visitIf(If* curr) {
- if (!curr->ifFalse) return;
+ if (!curr->ifFalse)
+ return;
// if both sides are identical, this is easy to fold
if (ExpressionAnalyzer::equal(curr->ifTrue, curr->ifFalse)) {
Builder builder(*getModule());
// remove if (4 bytes), remove one arm, add drop (1), add block (3),
// so this must be a net savings
markAsModified(curr);
- auto* ret = builder.makeSequence(
- builder.makeDrop(curr->condition),
- curr->ifTrue
- );
+ auto* ret =
+ builder.makeSequence(builder.makeDrop(curr->condition), curr->ifTrue);
// we must ensure we present the same type as the if had
ret->finalize(curr->type);
replaceCurrent(ret);
@@ -237,9 +247,8 @@ struct CodeFolding : public WalkerPass<ControlFlowWalker<CodeFolding>> {
}
// we need nameless blocks, as if there is a name, someone might branch
// to the end, skipping the code we want to merge
- if (left && right &&
- !left->name.is() && !right->name.is()) {
- std::vector<Tail> tails = { Tail(left), Tail(right) };
+ if (left && right && !left->name.is() && !right->name.is()) {
+ std::vector<Tail> tails = {Tail(left), Tail(right)};
optimizeExpressionTails(tails, curr);
}
}
@@ -251,7 +260,8 @@ struct CodeFolding : public WalkerPass<ControlFlowWalker<CodeFolding>> {
anotherPass = false;
super::doWalkFunction(func);
optimizeTerminatingTails(unreachableTails);
- // optimize returns at the end, so we can benefit from a fallthrough if there is a value TODO: separate passes for them?
+ // optimize returns at the end, so we can benefit from a fallthrough if
+ // there is a value TODO: separate passes for them?
optimizeTerminatingTails(returnTails);
// TODO add fallthrough for returns
// TODO optimize returns not in blocks, a big return value can be worth it
@@ -277,7 +287,10 @@ private:
for (auto* item : items) {
auto exiting = BranchUtils::getExitingBranches(item);
std::vector<Name> intersection;
- std::set_intersection(allTargets.begin(), allTargets.end(), exiting.begin(), exiting.end(),
+ std::set_intersection(allTargets.begin(),
+ allTargets.end(),
+ exiting.begin(),
+ exiting.end(),
std::back_inserter(intersection));
if (intersection.size() > 0) {
// anything exiting that is in all targets is something bad
@@ -287,15 +300,18 @@ private:
return true;
}
- // optimize tails that reach the outside of an expression. code that is identical in all
- // paths leading to the block exit can be merged.
+ // optimize tails that reach the outside of an expression. code that is
+ // identical in all paths leading to the block exit can be merged.
template<typename T>
void optimizeExpressionTails(std::vector<Tail>& tails, T* curr) {
- if (tails.size() < 2) return;
+ if (tails.size() < 2)
+ return;
// see if anything is untoward, and we should not do this
for (auto& tail : tails) {
- if (tail.expr && modifieds.count(tail.expr) > 0) return;
- if (modifieds.count(tail.block) > 0) return;
+ if (tail.expr && modifieds.count(tail.expr) > 0)
+ return;
+ if (modifieds.count(tail.block) > 0)
+ return;
// if we were not modified, then we should be valid for processing
tail.validate();
}
@@ -316,7 +332,7 @@ private:
// elements to be worth that extra block (although, there is
// some chance the block would get merged higher up, see later)
std::vector<Expression*> mergeable; // the elements we can merge
- Index num = 0; // how many elements back from the tail to look at
+ Index num = 0; // how many elements back from the tail to look at
Index saved = 0; // how much we can save
while (1) {
// check if this num is still relevant
@@ -329,7 +345,8 @@ private:
break;
}
}
- if (stop) break;
+ if (stop)
+ break;
auto* item = getMergeable(tails[0], num);
for (auto& tail : tails) {
if (!ExpressionAnalyzer::equal(item, getMergeable(tail, num))) {
@@ -338,15 +355,18 @@ private:
break;
}
}
- if (stop) break;
+ if (stop)
+ break;
// we may have found another one we can merge - can we move it?
- if (!canMove({ item }, curr)) break;
+ if (!canMove({item}, curr))
+ break;
// we found another one we can merge
mergeable.push_back(item);
num++;
saved += Measurer::measure(item);
}
- if (saved == 0) return;
+ if (saved == 0)
+ return;
// we may be able to save enough.
if (saved < WORTH_ADDING_BLOCK_TO_REMOVE_THIS_MUCH) {
// it's not obvious we can save enough. see if we get rid
@@ -363,13 +383,16 @@ private:
if (!willEmptyBlock) {
// last chance, if our parent is a block, then it should be
// fine to create a new block here, it will be merged up
- assert(curr == controlFlowStack.back()); // we are an if or a block, at the top
+ // we are an if or a block, at the top
+ assert(curr == controlFlowStack.back());
if (controlFlowStack.size() <= 1) {
return; // no parent at all
- // TODO: if we are the toplevel in the function, then in the binary format
- // we might avoid emitting a block, so the same logic applies here?
+ // TODO: if we are the toplevel in the function, then in the binary
+ // format we might avoid emitting a block, so the same logic
+ // applies here?
}
- auto* parent = controlFlowStack[controlFlowStack.size() - 2]->dynCast<Block>();
+ auto* parent =
+ controlFlowStack[controlFlowStack.size() - 2]->dynCast<Block>();
if (!parent) {
return; // parent is not a block
}
@@ -440,15 +463,23 @@ private:
// deeper merges first.
// returns whether we optimized something.
bool optimizeTerminatingTails(std::vector<Tail>& tails, Index num = 0) {
- if (tails.size() < 2) return false;
- // remove things that are untoward and cannot be optimized
- tails.erase(std::remove_if(tails.begin(), tails.end(), [&](Tail& tail) {
- if (tail.expr && modifieds.count(tail.expr) > 0) return true;
- if (tail.block && modifieds.count(tail.block) > 0) return true;
- // if we were not modified, then we should be valid for processing
- tail.validate();
+ if (tails.size() < 2)
return false;
- }), tails.end());
+ // remove things that are untoward and cannot be optimized
+ tails.erase(
+ std::remove_if(tails.begin(),
+ tails.end(),
+ [&](Tail& tail) {
+ if (tail.expr && modifieds.count(tail.expr) > 0)
+ return true;
+ if (tail.block && modifieds.count(tail.block) > 0)
+ return true;
+ // if we were not modified, then we should be valid for
+ // processing
+ tail.validate();
+ return false;
+ }),
+ tails.end());
// now let's try to find subsets that are mergeable. we don't look hard
// for the most optimal; further passes may find more
// effectiveSize: TODO: special-case fallthrough, matters for returns
@@ -481,7 +512,7 @@ private:
// estimate if a merging is worth the cost
auto worthIt = [&](Index num, std::vector<Tail>& tails) {
auto items = getTailItems(num, tails); // the elements we can merge
- Index saved = 0; // how much we can save
+ Index saved = 0; // how much we can save
for (auto* item : items) {
saved += Measurer::measure(item) * (tails.size() - 1);
}
@@ -496,7 +527,8 @@ private:
cost += WORTH_ADDING_BLOCK_TO_REMOVE_THIS_MUCH;
// if we cannot merge to the end, then we definitely need 2 blocks,
// and a branch
- if (!canMove(items, getFunction()->body)) { // TODO: efficiency, entire body
+ // TODO: efficiency, entire body
+ if (!canMove(items, getFunction()->body)) {
cost += 1 + WORTH_ADDING_BLOCK_TO_REMOVE_THIS_MUCH;
// TODO: to do this, we need to maintain a map of element=>parent,
// so that we can insert the new blocks in the right place
@@ -509,64 +541,86 @@ private:
// let's see if we can merge deeper than num, to num + 1
auto next = tails;
// remove tails that are too short, or that we hit an item we can't handle
- next.erase(std::remove_if(next.begin(), next.end(), [&](Tail& tail) {
- if (effectiveSize(tail) < num + 1) return true;
- auto* newItem = getItem(tail, num);
- // ignore tails that break to outside blocks. we want to move code to
- // the very outermost position, so such code cannot be moved
- // TODO: this should not be a problem in *non*-terminating tails,
- // but double-verify that
- if (EffectAnalyzer(getPassOptions(), newItem).hasExternalBreakTargets()) {
- return true;
- }
- return false;
- }), next.end());
+ next.erase(std::remove_if(next.begin(),
+ next.end(),
+ [&](Tail& tail) {
+ if (effectiveSize(tail) < num + 1)
+ return true;
+ auto* newItem = getItem(tail, num);
+ // ignore tails that break to outside blocks. we
+ // want to move code to the very outermost
+ // position, so such code cannot be moved
+ // TODO: this should not be a problem in
+ // *non*-terminating tails, but
+ // double-verify that
+ if (EffectAnalyzer(getPassOptions(), newItem)
+ .hasExternalBreakTargets()) {
+ return true;
+ }
+ return false;
+ }),
+ next.end());
// if we have enough to investigate, do so
if (next.size() >= 2) {
- // now we want to find a mergeable item - any item that is equal among a subset
+ // now we want to find a mergeable item - any item that is equal among a
+ // subset
std::map<Expression*, HashType> hashes; // expression => hash value
- std::map<HashType, std::vector<Expression*>> hashed; // hash value => expressions with that hash
+ // hash value => expressions with that hash
+ std::map<HashType, std::vector<Expression*>> hashed;
for (auto& tail : next) {
auto* item = getItem(tail, num);
auto hash = hashes[item] = ExpressionAnalyzer::hash(item);
hashed[hash].push_back(item);
}
- // look at each hash value exactly once. we do this in a deterministic order.
+ // look at each hash value exactly once. we do this in a deterministic
+ // order.
std::set<HashType> seen;
for (auto& tail : next) {
auto* item = getItem(tail, num);
auto hash = hashes[item];
- if (seen.count(hash)) continue;
+ if (seen.count(hash))
+ continue;
seen.insert(hash);
auto& items = hashed[hash];
- if (items.size() == 1) continue;
+ if (items.size() == 1)
+ continue;
assert(items.size() > 0);
// look for an item that has another match.
while (items.size() >= 2) {
auto first = items[0];
std::vector<Expression*> others;
- items.erase(std::remove_if(items.begin(), items.end(), [&](Expression* item) {
- if (item == first || // don't bother comparing the first
- ExpressionAnalyzer::equal(item, first)) {
- // equal, keep it
- return false;
- } else {
- // unequal, look at it later
- others.push_back(item);
- return true;
- }
- }), items.end());
+ items.erase(
+ std::remove_if(items.begin(),
+ items.end(),
+ [&](Expression* item) {
+ if (item ==
+ first || // don't bother comparing the first
+ ExpressionAnalyzer::equal(item, first)) {
+ // equal, keep it
+ return false;
+ } else {
+ // unequal, look at it later
+ others.push_back(item);
+ return true;
+ }
+ }),
+ items.end());
if (items.size() >= 2) {
// possible merge here, investigate it
auto* correct = items[0];
auto explore = next;
- explore.erase(std::remove_if(explore.begin(), explore.end(), [&](Tail& tail) {
- auto* item = getItem(tail, num);
- return !ExpressionAnalyzer::equal(item, correct);
- }), explore.end());
- // try to optimize this deeper tail. if we succeed, then stop here, as the
- // changes may influence us. we leave further opts to further passes (as this
- // is rare in practice, it's generally not a perf issue, but TODO optimize)
+ explore.erase(std::remove_if(explore.begin(),
+ explore.end(),
+ [&](Tail& tail) {
+ auto* item = getItem(tail, num);
+ return !ExpressionAnalyzer::equal(
+ item, correct);
+ }),
+ explore.end());
+ // try to optimize this deeper tail. if we succeed, then stop here,
+ // as the changes may influence us. we leave further opts to further
+ // passes (as this is rare in practice, it's generally not a perf
+ // issue, but TODO optimize)
if (optimizeTerminatingTails(explore, num + 1)) {
return true;
}
@@ -578,15 +632,18 @@ private:
// we explored deeper (higher num) options, but perhaps there
// was nothing there while there is something we can do at this level
// but if we are at num == 0, then we found nothing at all
- if (num == 0) return false;
+ if (num == 0)
+ return false;
// if not worth it, stop
- if (!worthIt(num, tails)) return false;
+ if (!worthIt(num, tails))
+ return false;
// this is worth doing, do it!
auto mergeable = getTailItems(num, tails); // the elements we can merge
// since we managed a merge, then it might open up more opportunities later
anotherPass = true;
Builder builder(*getModule());
- LabelUtils::LabelManager labels(getFunction()); // TODO: don't create one per merge, linear in function size
+ // TODO: don't create one per merge, linear in function size
+ LabelUtils::LabelManager labels(getFunction());
Name innerName = labels.getUnique("folding-inner");
for (auto& tail : tails) {
// remove the items we are merging / moving, and add a break
@@ -623,7 +680,8 @@ private:
// rules, and now it won't be toplevel in the function, it can
// change)
auto* toplevel = old->dynCast<Block>();
- if (toplevel) toplevel->finalize();
+ if (toplevel)
+ toplevel->finalize();
if (old->type != unreachable) {
inner->list.push_back(builder.makeReturn(old));
} else {
@@ -649,9 +707,6 @@ private:
}
};
-Pass *createCodeFoldingPass() {
- return new CodeFolding();
-}
+Pass* createCodeFoldingPass() { return new CodeFolding(); }
} // namespace wasm
-
diff --git a/src/passes/CodePushing.cpp b/src/passes/CodePushing.cpp
index 52aab08ad..342cb5182 100644
--- a/src/passes/CodePushing.cpp
+++ b/src/passes/CodePushing.cpp
@@ -19,10 +19,10 @@
// a location behind a condition, where it might not always execute.
//
-#include <wasm.h>
+#include <ir/effects.h>
#include <pass.h>
#include <wasm-builder.h>
-#include <ir/effects.h>
+#include <wasm.h>
namespace wasm {
@@ -50,26 +50,23 @@ struct LocalAnalyzer : public PostWalker<LocalAnalyzer> {
std::fill(sfa.begin() + func->getNumParams(), sfa.end(), true);
walk(func->body);
for (Index i = 0; i < num; i++) {
- if (numSets[i] == 0) sfa[i] = false;
+ if (numSets[i] == 0)
+ sfa[i] = false;
}
}
- bool isSFA(Index i) {
- return sfa[i];
- }
+ bool isSFA(Index i) { return sfa[i]; }
- Index getNumGets(Index i) {
- return numGets[i];
- }
+ Index getNumGets(Index i) { return numGets[i]; }
- void visitGetLocal(GetLocal *curr) {
+ void visitGetLocal(GetLocal* curr) {
if (numSets[curr->index] == 0) {
sfa[curr->index] = false;
}
numGets[curr->index]++;
}
- void visitSetLocal(SetLocal *curr) {
+ void visitSetLocal(SetLocal* curr) {
numSets[curr->index]++;
if (numSets[curr->index] > 1) {
sfa[curr->index] = false;
@@ -86,12 +83,18 @@ class Pusher {
PassOptions& passOptions;
public:
- Pusher(Block* block, LocalAnalyzer& analyzer, std::vector<Index>& numGetsSoFar, PassOptions& passOptions) : list(block->list), analyzer(analyzer), numGetsSoFar(numGetsSoFar), passOptions(passOptions) {
+ Pusher(Block* block,
+ LocalAnalyzer& analyzer,
+ std::vector<Index>& numGetsSoFar,
+ PassOptions& passOptions)
+ : list(block->list), analyzer(analyzer), numGetsSoFar(numGetsSoFar),
+ passOptions(passOptions) {
// Find an optimization segment: from the first pushable thing, to the first
// point past which we want to push. We then push in that range before
// continuing forward.
- Index relevant = list.size() - 1; // we never need to push past a final element, as
- // we couldn't be used after it.
+ // we never need to push past a final element, as we couldn't be used after
+ // it.
+ Index relevant = list.size() - 1;
const Index nothing = -1;
Index i = 0;
Index firstPushable = nothing;
@@ -114,7 +117,8 @@ public:
private:
SetLocal* isPushable(Expression* curr) {
auto* set = curr->dynCast<SetLocal>();
- if (!set) return nullptr;
+ if (!set)
+ return nullptr;
auto index = set->index;
// to be pushable, this must be SFA and the right # of gets,
// but also have no side effects, as it may not execute if pushed.
@@ -133,7 +137,8 @@ private:
if (auto* drop = curr->dynCast<Drop>()) {
curr = drop->value;
}
- if (curr->is<If>()) return true;
+ if (curr->is<If>())
+ return true;
if (auto* br = curr->dynCast<Break>()) {
return !!br->condition;
}
@@ -146,12 +151,14 @@ private:
// forward, that way we can push later things out of the way
// of earlier ones. Once we know all we can push, we push it all
// in one pass, keeping the order of the pushables intact.
- assert(firstPushable != Index(-1) && pushPoint != Index(-1) && firstPushable < pushPoint);
- EffectAnalyzer cumulativeEffects(passOptions); // everything that matters if you want
- // to be pushed past the pushPoint
+ assert(firstPushable != Index(-1) && pushPoint != Index(-1) &&
+ firstPushable < pushPoint);
+ // everything that matters if you want to be pushed past the pushPoint
+ EffectAnalyzer cumulativeEffects(passOptions);
cumulativeEffects.analyze(list[pushPoint]);
- cumulativeEffects.branches = false; // it is ok to ignore the branching here,
- // that is the crucial point of this opt
+ // it is ok to ignore the branching here, that is the crucial point of this
+ // opt
+ cumulativeEffects.branches = false;
std::vector<SetLocal*> toPush;
Index i = pushPoint - 1;
while (1) {
@@ -159,11 +166,11 @@ private:
if (pushable) {
auto iter = pushableEffects.find(pushable);
if (iter == pushableEffects.end()) {
- iter = pushableEffects.emplace(
- std::piecewise_construct,
- std::forward_as_tuple(pushable),
- std::forward_as_tuple(passOptions, pushable)
- ).first;
+ iter = pushableEffects
+ .emplace(std::piecewise_construct,
+ std::forward_as_tuple(pushable),
+ std::forward_as_tuple(passOptions, pushable))
+ .first;
}
auto& effects = iter->second;
if (cumulativeEffects.invalidates(effects)) {
@@ -236,30 +243,26 @@ struct CodePushing : public WalkerPass<PostWalker<CodePushing>> {
walk(func->body);
}
- void visitGetLocal(GetLocal *curr) {
- numGetsSoFar[curr->index]++;
- }
+ void visitGetLocal(GetLocal* curr) { numGetsSoFar[curr->index]++; }
void visitBlock(Block* curr) {
// Pushing code only makes sense if we are size 3 or above: we need
// one element to push, an element to push it past, and an element to use
// what we pushed.
- if (curr->list.size() < 3) return;
- // At this point in the postorder traversal we have gone through all our children.
- // Therefore any variable whose gets seen so far is equal to the total gets must
- // have no further users after this block. And therefore when we see an SFA
- // variable defined here, we know it isn't used before it either, and has just this
- // one assign. So we can push it forward while we don't hit a non-control-flow
- // ordering invalidation issue, since if this isn't a loop, it's fine (we're not
- // used outside), and if it is, we hit the assign before any use (as we can't
- // push it past a use).
+ if (curr->list.size() < 3)
+ return;
+ // At this point in the postorder traversal we have gone through all our
+ // children. Therefore any variable whose gets seen so far is equal to the
+ // total gets must have no further users after this block. And therefore
+ // when we see an SFA variable defined here, we know it isn't used before it
+ // either, and has just this one assign. So we can push it forward while we
+ // don't hit a non-control-flow ordering invalidation issue, since if this
+ // isn't a loop, it's fine (we're not used outside), and if it is, we hit
+ // the assign before any use (as we can't push it past a use).
Pusher pusher(curr, analyzer, numGetsSoFar, getPassOptions());
}
};
-Pass *createCodePushingPass() {
- return new CodePushing();
-}
+Pass* createCodePushingPass() { return new CodePushing(); }
} // namespace wasm
-
diff --git a/src/passes/ConstHoisting.cpp b/src/passes/ConstHoisting.cpp
index 11188a9ba..f67a48645 100644
--- a/src/passes/ConstHoisting.cpp
+++ b/src/passes/ConstHoisting.cpp
@@ -32,10 +32,10 @@
#include <map>
-#include <wasm.h>
#include <pass.h>
#include <wasm-binary.h>
#include <wasm-builder.h>
+#include <wasm.h>
namespace wasm {
@@ -66,16 +66,14 @@ struct ConstHoisting : public WalkerPass<PostWalker<ConstHoisting>> {
if (!prelude.empty()) {
Builder builder(*getModule());
// merge-blocks can optimize this into a single block later in most cases
- curr->body = builder.makeSequence(
- builder.makeBlock(prelude),
- curr->body
- );
+ curr->body = builder.makeSequence(builder.makeBlock(prelude), curr->body);
}
}
private:
bool worthHoisting(Literal value, Index num) {
- if (num < MIN_USES) return false;
+ if (num < MIN_USES)
+ return false;
// measure the size of the constant
Index size = 0;
switch (value.type) {
@@ -112,8 +110,7 @@ private:
return after < before;
}
- template<typename T>
- Index getWrittenSize(const T& thing) {
+ template<typename T> Index getWrittenSize(const T& thing) {
BufferWithRandomAccess buffer;
buffer << thing;
return buffer.size();
@@ -125,10 +122,7 @@ private:
auto type = (*(vec[0]))->type;
Builder builder(*getModule());
auto temp = builder.addVar(getFunction(), type);
- auto* ret = builder.makeSetLocal(
- temp,
- *(vec[0])
- );
+ auto* ret = builder.makeSetLocal(temp, *(vec[0]));
for (auto item : vec) {
*item = builder.makeGetLocal(temp, type);
}
@@ -136,8 +130,6 @@ private:
}
};
-Pass *createConstHoistingPass() {
- return new ConstHoisting();
-}
+Pass* createConstHoistingPass() { return new ConstHoisting(); }
} // namespace wasm
diff --git a/src/passes/DataFlowOpts.cpp b/src/passes/DataFlowOpts.cpp
index 42f01673f..3391359ef 100644
--- a/src/passes/DataFlowOpts.cpp
+++ b/src/passes/DataFlowOpts.cpp
@@ -24,15 +24,15 @@
// --flatten --dfo -Os
//
-#include "wasm.h"
-#include "pass.h"
-#include "wasm-builder.h"
-#include "ir/flat.h"
-#include "ir/utils.h"
-#include "dataflow/node.h"
#include "dataflow/graph.h"
+#include "dataflow/node.h"
#include "dataflow/users.h"
#include "dataflow/utils.h"
+#include "ir/flat.h"
+#include "ir/utils.h"
+#include "pass.h"
+#include "wasm-builder.h"
+#include "wasm.h"
namespace wasm {
@@ -59,8 +59,8 @@ struct DataFlowOpts : public WalkerPass<PostWalker<DataFlowOpts>> {
workLeft.insert(node.get()); // we should try to optimize each node
}
while (!workLeft.empty()) {
- //std::cout << "\n\ndump before work iter\n";
- //dump(graph, std::cout);
+ // std::cout << "\n\ndump before work iter\n";
+ // dump(graph, std::cout);
auto iter = workLeft.begin();
auto* node = *iter;
workLeft.erase(iter);
@@ -81,9 +81,11 @@ struct DataFlowOpts : public WalkerPass<PostWalker<DataFlowOpts>> {
}
void workOn(DataFlow::Node* node) {
- if (node->isConst()) return;
+ if (node->isConst())
+ return;
// If there are no uses, there is no point to work.
- if (nodeUsers.getNumUses(node) == 0) return;
+ if (nodeUsers.getNumUses(node) == 0)
+ return;
// Optimize: Look for nodes that we can easily convert into
// something simpler.
// TODO: we can expressionify and run full normal opts on that,
@@ -110,8 +112,9 @@ struct DataFlowOpts : public WalkerPass<PostWalker<DataFlowOpts>> {
void optimizeExprToConstant(DataFlow::Node* node) {
assert(node->isExpr());
assert(!node->isConst());
- //std::cout << "will optimize an Expr of all constant inputs. before" << '\n';
- //dump(node, std::cout);
+ // std::cout << "will optimize an Expr of all constant inputs. before" <<
+ // '\n';
+ // dump(node, std::cout);
auto* expr = node->expr;
// First, note that some of the expression's children may be
// local.gets that we inferred during SSA analysis as constant.
@@ -132,7 +135,8 @@ struct DataFlowOpts : public WalkerPass<PostWalker<DataFlowOpts>> {
Module temp;
// XXX we should copy expr here, in principle, and definitely will need to
// when we do arbitrarily regenerated expressions
- auto* func = Builder(temp).makeFunction("temp", std::vector<Type>{}, none, std::vector<Type>{}, expr);
+ auto* func = Builder(temp).makeFunction(
+ "temp", std::vector<Type>{}, none, std::vector<Type>{}, expr);
PassRunner runner(&temp);
runner.setIsNested(true);
runner.add("precompute");
@@ -140,7 +144,8 @@ struct DataFlowOpts : public WalkerPass<PostWalker<DataFlowOpts>> {
// Get the optimized thing
auto* result = func->body;
// It may not be a constant, e.g. 0 / 0 does not optimize to 0
- if (!result->is<Const>()) return;
+ if (!result->is<Const>())
+ return;
// All good, copy it.
node->expr = Builder(*getModule()).makeConst(result->cast<Const>()->value);
assert(node->isConst());
@@ -206,7 +211,8 @@ struct DataFlowOpts : public WalkerPass<PostWalker<DataFlowOpts>> {
// should look into TODO
break;
}
- default: WASM_UNREACHABLE();
+ default:
+ WASM_UNREACHABLE();
}
}
// No one is a user of this node after we replaced all the uses.
@@ -244,9 +250,6 @@ struct DataFlowOpts : public WalkerPass<PostWalker<DataFlowOpts>> {
}
};
-Pass *createDataFlowOptsPass() {
- return new DataFlowOpts();
-}
+Pass* createDataFlowOptsPass() { return new DataFlowOpts(); }
} // namespace wasm
-
diff --git a/src/passes/DeadArgumentElimination.cpp b/src/passes/DeadArgumentElimination.cpp
index e4b8eef56..0c6561ef6 100644
--- a/src/passes/DeadArgumentElimination.cpp
+++ b/src/passes/DeadArgumentElimination.cpp
@@ -37,14 +37,14 @@
#include <unordered_map>
#include <unordered_set>
-#include "wasm.h"
-#include "pass.h"
-#include "wasm-builder.h"
#include "cfg/cfg-traversal.h"
#include "ir/effects.h"
#include "ir/module-utils.h"
+#include "pass.h"
#include "passes/opt-utils.h"
#include "support/sorted_vector.h"
+#include "wasm-builder.h"
+#include "wasm.h"
namespace wasm {
@@ -73,14 +73,13 @@ struct DAEBlockInfo {
// If it is both read and written, we just care about the first
// action (if it is read first, that's all the info we are
// looking for; if it is written first, it can't be read later).
- enum LocalUse {
- Read,
- Written
- };
+ enum LocalUse { Read, Written };
std::unordered_map<Index, LocalUse> localUses;
};
-struct DAEScanner : public WalkerPass<CFGWalker<DAEScanner, Visitor<DAEScanner>, DAEBlockInfo>> {
+struct DAEScanner
+ : public WalkerPass<
+ CFGWalker<DAEScanner, Visitor<DAEScanner>, DAEBlockInfo>> {
bool isFunctionParallel() override { return true; }
Pass* create() override { return new DAEScanner(infoMap); }
@@ -131,7 +130,8 @@ struct DAEScanner : public WalkerPass<CFGWalker<DAEScanner, Visitor<DAEScanner>,
void doWalkFunction(Function* func) {
numParams = func->getNumParams();
info = &((*infoMap)[func->name]);
- CFGWalker<DAEScanner, Visitor<DAEScanner>, DAEBlockInfo>::doWalkFunction(func);
+ CFGWalker<DAEScanner, Visitor<DAEScanner>, DAEBlockInfo>::doWalkFunction(
+ func);
// If there are relevant params, check if they are used. (If
// we can't optimize the function anyhow, there's no point.)
if (numParams > 0 && !info->hasUnseenCalls) {
@@ -182,7 +182,8 @@ struct DAEScanner : public WalkerPass<CFGWalker<DAEScanner, Visitor<DAEScanner>,
if (use == DAEBlockInfo::Read) {
usedParams.insert(i);
}
- // Whether it was a read or a write, we can stop looking at that local here.
+ // Whether it was a read or a write, we can stop looking at that local
+ // here.
} else {
remainingIndexes.insert(i);
}
@@ -217,10 +218,10 @@ struct DAE : public Pass {
bool iteration(PassRunner* runner, Module* module) {
DAEFunctionInfoMap infoMap;
- // Ensure they all exist so the parallel threads don't modify the data structure.
- ModuleUtils::iterDefinedFunctions(*module, [&](Function* func) {
- infoMap[func->name];
- });
+ // Ensure they all exist so the parallel threads don't modify the data
+ // structure.
+ ModuleUtils::iterDefinedFunctions(
+ *module, [&](Function* func) { infoMap[func->name]; });
// Check the influence of the table and exports.
for (auto& curr : module->exports) {
if (curr->kind == ExternalKind::Function) {
@@ -287,13 +288,11 @@ struct DAE : public Pass {
}
}
if (value.type != none) {
- // Success! We can just apply the constant in the function, which makes
- // the parameter value unused, which lets us remove it later.
+ // Success! We can just apply the constant in the function, which
+ // makes the parameter value unused, which lets us remove it later.
Builder builder(*module);
func->body = builder.makeSequence(
- builder.makeSetLocal(i, builder.makeConst(value)),
- func->body
- );
+ builder.makeSetLocal(i, builder.makeConst(value)), func->body);
// Mark it as unused, which we know it now is (no point to
// re-scan just for that).
infoMap[name].unusedParams.insert(i);
@@ -308,14 +307,15 @@ struct DAE : public Pass {
auto& calls = pair.second;
auto* func = module->getFunction(name);
auto numParams = func->getNumParams();
- if (numParams == 0) continue;
+ if (numParams == 0)
+ continue;
// Iterate downwards, as we may remove more than one.
Index i = numParams - 1;
while (1) {
if (infoMap[name].unusedParams.has(i)) {
- // Great, it's not used. Check if none of the calls has a param with side
- // effects, as that would prevent us removing them (flattening should
- // have been done earlier).
+ // Great, it's not used. Check if none of the calls has a param with
+ // side effects, as that would prevent us removing them (flattening
+ // should have been done earlier).
bool canRemove = true;
for (auto* call : calls) {
auto* operand = call->operands[i];
@@ -331,13 +331,15 @@ struct DAE : public Pass {
changed.insert(func);
}
}
- if (i == 0) break;
+ if (i == 0)
+ break;
i--;
}
}
- // We can also tell which calls have all their return values dropped. Note that we can't do this
- // if we changed anything so far, as we may have modified allCalls (we can't modify a call site
- // twice in one iteration, once to remove a param, once to drop the return value).
+ // We can also tell which calls have all their return values dropped. Note
+ // that we can't do this if we changed anything so far, as we may have
+ // modified allCalls (we can't modify a call site twice in one iteration,
+ // once to remove a param, once to drop the return value).
if (changed.empty()) {
for (auto& func : module->functions) {
if (func->result == none) {
@@ -363,7 +365,8 @@ struct DAE : public Pass {
continue;
}
removeReturnValue(func.get(), calls, module);
- // TODO Removing a drop may also open optimization opportunities in the callers.
+ // TODO Removing a drop may also open optimization opportunities in the
+ // callers.
changed.insert(func.get());
}
}
@@ -391,15 +394,12 @@ private:
struct LocalUpdater : public PostWalker<LocalUpdater> {
Index removedIndex;
Index newIndex;
- LocalUpdater(Function* func, Index removedIndex, Index newIndex) : removedIndex(removedIndex), newIndex(newIndex) {
+ LocalUpdater(Function* func, Index removedIndex, Index newIndex)
+ : removedIndex(removedIndex), newIndex(newIndex) {
walk(func->body);
}
- void visitGetLocal(GetLocal* curr) {
- updateIndex(curr->index);
- }
- void visitSetLocal(SetLocal* curr) {
- updateIndex(curr->index);
- }
+ void visitGetLocal(GetLocal* curr) { updateIndex(curr->index); }
+ void visitSetLocal(SetLocal* curr) { updateIndex(curr->index); }
void updateIndex(Index& index) {
if (index == removedIndex) {
index = newIndex;
@@ -414,7 +414,8 @@ private:
}
}
- void removeReturnValue(Function* func, std::vector<Call*>& calls, Module* module) {
+ void
+ removeReturnValue(Function* func, std::vector<Call*>& calls, Module* module) {
// Clear the type, which is no longer accurate.
func->type = Name();
func->result = none;
@@ -430,10 +431,7 @@ private:
assert(value);
curr->value = nullptr;
Builder builder(*module);
- replaceCurrent(builder.makeSequence(
- builder.makeDrop(value),
- curr
- ));
+ replaceCurrent(builder.makeSequence(builder.makeDrop(value), curr));
}
} returnUpdater(func, module);
// Remove any value flowing out.
@@ -454,15 +452,12 @@ private:
}
};
-Pass *createDAEPass() {
- return new DAE();
-}
+Pass* createDAEPass() { return new DAE(); }
-Pass *createDAEOptimizingPass() {
+Pass* createDAEOptimizingPass() {
auto* ret = new DAE();
ret->optimize = true;
return ret;
}
} // namespace wasm
-
diff --git a/src/passes/DeadCodeElimination.cpp b/src/passes/DeadCodeElimination.cpp
index a56c88929..d23713060 100644
--- a/src/passes/DeadCodeElimination.cpp
+++ b/src/passes/DeadCodeElimination.cpp
@@ -28,17 +28,18 @@
// have no side effects.
//
-#include <vector>
-#include <wasm.h>
-#include <pass.h>
-#include <wasm-builder.h>
#include <ir/block-utils.h>
#include <ir/branch-utils.h>
#include <ir/type-updating.h>
+#include <pass.h>
+#include <vector>
+#include <wasm-builder.h>
+#include <wasm.h>
namespace wasm {
-struct DeadCodeElimination : public WalkerPass<PostWalker<DeadCodeElimination>> {
+struct DeadCodeElimination
+ : public WalkerPass<PostWalker<DeadCodeElimination>> {
bool isFunctionParallel() override { return true; }
Pass* create() override { return new DeadCodeElimination; }
@@ -48,7 +49,8 @@ struct DeadCodeElimination : public WalkerPass<PostWalker<DeadCodeElimination>>
Expression* replaceCurrent(Expression* expression) {
auto* old = getCurrent();
- if (old == expression) return expression;
+ if (old == expression)
+ return expression;
super::replaceCurrent(expression);
// also update the type updater
typeUpdater.noteReplacement(old, expression);
@@ -79,20 +81,17 @@ struct DeadCodeElimination : public WalkerPass<PostWalker<DeadCodeElimination>>
}
// if a child exists and is unreachable, we can replace ourselves with it
- bool isDead(Expression* child) {
- return child && child->type == unreachable;
- }
+ bool isDead(Expression* child) { return child && child->type == unreachable; }
// a similar check, assumes the child exists
- bool isUnreachable(Expression* child) {
- return child->type == unreachable;
- }
+ bool isUnreachable(Expression* child) { return child->type == unreachable; }
// things that stop control flow
void visitBreak(Break* curr) {
if (isDead(curr->value)) {
- // the condition is evaluated last, so if the value was unreachable, the whole thing is
+ // the condition is evaluated last, so if the value was unreachable, the
+ // whole thing is
replaceCurrent(curr->value);
return;
}
@@ -152,9 +151,7 @@ struct DeadCodeElimination : public WalkerPass<PostWalker<DeadCodeElimination>>
reachable = false;
}
- void visitUnreachable(Unreachable* curr) {
- reachable = false;
- }
+ void visitUnreachable(Unreachable* curr) { reachable = false; }
void visitBlock(Block* curr) {
auto& list = curr->list;
@@ -175,9 +172,11 @@ struct DeadCodeElimination : public WalkerPass<PostWalker<DeadCodeElimination>>
reachableBreaks.erase(curr->name);
}
if (list.size() == 1 && isUnreachable(list[0])) {
- replaceCurrent(BlockUtils::simplifyToContentsWithPossibleTypeChange(curr, this));
+ replaceCurrent(
+ BlockUtils::simplifyToContentsWithPossibleTypeChange(curr, this));
} else {
- // the block may have had a type, but can now be unreachable, which allows more reduction outside
+ // the block may have had a type, but can now be unreachable, which allows
+ // more reduction outside
typeUpdater.maybeUpdateTypeToUnreachable(curr);
}
}
@@ -186,7 +185,8 @@ struct DeadCodeElimination : public WalkerPass<PostWalker<DeadCodeElimination>>
if (curr->name.is()) {
reachableBreaks.erase(curr->name);
}
- if (isUnreachable(curr->body) && !BranchUtils::BranchSeeker::hasNamed(curr->body, curr->name)) {
+ if (isUnreachable(curr->body) &&
+ !BranchUtils::BranchSeeker::hasNamed(curr->body, curr->name)) {
replaceCurrent(curr->body);
return;
}
@@ -194,9 +194,11 @@ struct DeadCodeElimination : public WalkerPass<PostWalker<DeadCodeElimination>>
// ifs need special handling
- std::vector<bool> ifStack; // stack of reachable state, for forking and joining
+ // stack of reachable state, for forking and joining
+ std::vector<bool> ifStack;
- static void doAfterIfCondition(DeadCodeElimination* self, Expression** currp) {
+ static void doAfterIfCondition(DeadCodeElimination* self,
+ Expression** currp) {
self->ifStack.push_back(self->reachable);
}
@@ -209,67 +211,108 @@ struct DeadCodeElimination : public WalkerPass<PostWalker<DeadCodeElimination>>
}
void visitIf(If* curr) {
- // the ifStack has the branch that joins us, either from before if just an if, or the ifTrue if an if-else
+ // the ifStack has the branch that joins us, either from before if just an
+ // if, or the ifTrue if an if-else
reachable = reachable || ifStack.back();
ifStack.pop_back();
if (isUnreachable(curr->condition)) {
replaceCurrent(curr->condition);
}
- // the if may have had a type, but can now be unreachable, which allows more reduction outside
+ // the if may have had a type, but can now be unreachable, which allows more
+ // reduction outside
typeUpdater.maybeUpdateTypeToUnreachable(curr);
}
static void scan(DeadCodeElimination* self, Expression** currp) {
auto* curr = *currp;
if (!self->reachable) {
- // convert to an unreachable safely
- #define DELEGATE(CLASS_TO_VISIT) { \
- auto* parent = self->typeUpdater.parents[curr]; \
- self->typeUpdater.noteRecursiveRemoval(curr); \
- ExpressionManipulator::convert<CLASS_TO_VISIT, Unreachable>(static_cast<CLASS_TO_VISIT*>(curr)); \
- self->typeUpdater.noteAddition(curr, parent); \
- break; \
- }
+// convert to an unreachable safely
+#define DELEGATE(CLASS_TO_VISIT) \
+ { \
+ auto* parent = self->typeUpdater.parents[curr]; \
+ self->typeUpdater.noteRecursiveRemoval(curr); \
+ ExpressionManipulator::convert<CLASS_TO_VISIT, Unreachable>( \
+ static_cast<CLASS_TO_VISIT*>(curr)); \
+ self->typeUpdater.noteAddition(curr, parent); \
+ break; \
+ }
switch (curr->_id) {
- case Expression::Id::BlockId: DELEGATE(Block);
- case Expression::Id::IfId: DELEGATE(If);
- case Expression::Id::LoopId: DELEGATE(Loop);
- case Expression::Id::BreakId: DELEGATE(Break);
- case Expression::Id::SwitchId: DELEGATE(Switch);
- case Expression::Id::CallId: DELEGATE(Call);
- case Expression::Id::CallIndirectId: DELEGATE(CallIndirect);
- case Expression::Id::GetLocalId: DELEGATE(GetLocal);
- case Expression::Id::SetLocalId: DELEGATE(SetLocal);
- case Expression::Id::GetGlobalId: DELEGATE(GetGlobal);
- case Expression::Id::SetGlobalId: DELEGATE(SetGlobal);
- case Expression::Id::LoadId: DELEGATE(Load);
- case Expression::Id::StoreId: DELEGATE(Store);
- case Expression::Id::ConstId: DELEGATE(Const);
- case Expression::Id::UnaryId: DELEGATE(Unary);
- case Expression::Id::BinaryId: DELEGATE(Binary);
- case Expression::Id::SelectId: DELEGATE(Select);
- case Expression::Id::DropId: DELEGATE(Drop);
- case Expression::Id::ReturnId: DELEGATE(Return);
- case Expression::Id::HostId: DELEGATE(Host);
- case Expression::Id::NopId: DELEGATE(Nop);
- case Expression::Id::UnreachableId: break;
- case Expression::Id::AtomicCmpxchgId: DELEGATE(AtomicCmpxchg);
- case Expression::Id::AtomicRMWId: DELEGATE(AtomicRMW);
- case Expression::Id::AtomicWaitId: DELEGATE(AtomicWait);
- case Expression::Id::AtomicNotifyId: DELEGATE(AtomicNotify);
- case Expression::Id::SIMDExtractId: DELEGATE(SIMDExtract);
- case Expression::Id::SIMDReplaceId: DELEGATE(SIMDReplace);
- case Expression::Id::SIMDShuffleId: DELEGATE(SIMDShuffle);
- case Expression::Id::SIMDBitselectId: DELEGATE(SIMDBitselect);
- case Expression::Id::SIMDShiftId: DELEGATE(SIMDShift);
- case Expression::Id::MemoryInitId: DELEGATE(MemoryInit);
- case Expression::Id::DataDropId: DELEGATE(DataDrop);
- case Expression::Id::MemoryCopyId: DELEGATE(MemoryCopy);
- case Expression::Id::MemoryFillId: DELEGATE(MemoryFill);
- case Expression::Id::InvalidId: WASM_UNREACHABLE();
- case Expression::Id::NumExpressionIds: WASM_UNREACHABLE();
+ case Expression::Id::BlockId:
+ DELEGATE(Block);
+ case Expression::Id::IfId:
+ DELEGATE(If);
+ case Expression::Id::LoopId:
+ DELEGATE(Loop);
+ case Expression::Id::BreakId:
+ DELEGATE(Break);
+ case Expression::Id::SwitchId:
+ DELEGATE(Switch);
+ case Expression::Id::CallId:
+ DELEGATE(Call);
+ case Expression::Id::CallIndirectId:
+ DELEGATE(CallIndirect);
+ case Expression::Id::GetLocalId:
+ DELEGATE(GetLocal);
+ case Expression::Id::SetLocalId:
+ DELEGATE(SetLocal);
+ case Expression::Id::GetGlobalId:
+ DELEGATE(GetGlobal);
+ case Expression::Id::SetGlobalId:
+ DELEGATE(SetGlobal);
+ case Expression::Id::LoadId:
+ DELEGATE(Load);
+ case Expression::Id::StoreId:
+ DELEGATE(Store);
+ case Expression::Id::ConstId:
+ DELEGATE(Const);
+ case Expression::Id::UnaryId:
+ DELEGATE(Unary);
+ case Expression::Id::BinaryId:
+ DELEGATE(Binary);
+ case Expression::Id::SelectId:
+ DELEGATE(Select);
+ case Expression::Id::DropId:
+ DELEGATE(Drop);
+ case Expression::Id::ReturnId:
+ DELEGATE(Return);
+ case Expression::Id::HostId:
+ DELEGATE(Host);
+ case Expression::Id::NopId:
+ DELEGATE(Nop);
+ case Expression::Id::UnreachableId:
+ break;
+ case Expression::Id::AtomicCmpxchgId:
+ DELEGATE(AtomicCmpxchg);
+ case Expression::Id::AtomicRMWId:
+ DELEGATE(AtomicRMW);
+ case Expression::Id::AtomicWaitId:
+ DELEGATE(AtomicWait);
+ case Expression::Id::AtomicNotifyId:
+ DELEGATE(AtomicNotify);
+ case Expression::Id::SIMDExtractId:
+ DELEGATE(SIMDExtract);
+ case Expression::Id::SIMDReplaceId:
+ DELEGATE(SIMDReplace);
+ case Expression::Id::SIMDShuffleId:
+ DELEGATE(SIMDShuffle);
+ case Expression::Id::SIMDBitselectId:
+ DELEGATE(SIMDBitselect);
+ case Expression::Id::SIMDShiftId:
+ DELEGATE(SIMDShift);
+ case Expression::Id::MemoryInitId:
+ DELEGATE(MemoryInit);
+ case Expression::Id::DataDropId:
+ DELEGATE(DataDrop);
+ case Expression::Id::MemoryCopyId:
+ DELEGATE(MemoryCopy);
+ case Expression::Id::MemoryFillId:
+ DELEGATE(MemoryFill);
+ case Expression::Id::InvalidId:
+ WASM_UNREACHABLE();
+ case Expression::Id::NumExpressionIds:
+ WASM_UNREACHABLE();
}
- #undef DELEGATE
+#undef DELEGATE
return;
}
if (curr->is<If>()) {
@@ -290,12 +333,12 @@ struct DeadCodeElimination : public WalkerPass<PostWalker<DeadCodeElimination>>
// we don't need to drop unreachable nodes
Expression* drop(Expression* toDrop) {
- if (toDrop->type == unreachable) return toDrop;
+ if (toDrop->type == unreachable)
+ return toDrop;
return Builder(*getModule()).makeDrop(toDrop);
}
- template<typename T>
- Expression* handleCall(T* curr) {
+ template<typename T> Expression* handleCall(T* curr) {
for (Index i = 0; i < curr->operands.size(); i++) {
if (isUnreachable(curr->operands[i])) {
if (i > 0) {
@@ -316,12 +359,11 @@ struct DeadCodeElimination : public WalkerPass<PostWalker<DeadCodeElimination>>
return curr;
}
- void visitCall(Call* curr) {
- handleCall(curr);
- }
+ void visitCall(Call* curr) { handleCall(curr); }
void visitCallIndirect(CallIndirect* curr) {
- if (handleCall(curr) != curr) return;
+ if (handleCall(curr) != curr)
+ return;
if (isUnreachable(curr->target)) {
auto* block = getModule()->allocator.alloc<Block>();
for (auto* operand : curr->operands) {
@@ -356,56 +398,52 @@ struct DeadCodeElimination : public WalkerPass<PostWalker<DeadCodeElimination>>
}
void visitSetLocal(SetLocal* curr) {
- blockifyReachableOperands({ curr->value }, curr->type);
+ blockifyReachableOperands({curr->value}, curr->type);
}
void visitSetGlobal(SetGlobal* curr) {
- blockifyReachableOperands({ curr->value }, curr->type);
+ blockifyReachableOperands({curr->value}, curr->type);
}
void visitLoad(Load* curr) {
- blockifyReachableOperands({ curr->ptr }, curr->type);
+ blockifyReachableOperands({curr->ptr}, curr->type);
}
void visitStore(Store* curr) {
- blockifyReachableOperands({ curr->ptr, curr->value }, curr->type);
+ blockifyReachableOperands({curr->ptr, curr->value}, curr->type);
}
void visitAtomicRMW(AtomicRMW* curr) {
- blockifyReachableOperands({ curr->ptr, curr->value }, curr->type);
+ blockifyReachableOperands({curr->ptr, curr->value}, curr->type);
}
void visitAtomicCmpxchg(AtomicCmpxchg* curr) {
- blockifyReachableOperands({ curr->ptr, curr->expected, curr->replacement }, curr->type);
+ blockifyReachableOperands({curr->ptr, curr->expected, curr->replacement},
+ curr->type);
}
void visitUnary(Unary* curr) {
- blockifyReachableOperands({ curr->value }, curr->type);
+ blockifyReachableOperands({curr->value}, curr->type);
}
void visitBinary(Binary* curr) {
- blockifyReachableOperands({ curr->left, curr->right }, curr->type);
+ blockifyReachableOperands({curr->left, curr->right}, curr->type);
}
void visitSelect(Select* curr) {
- blockifyReachableOperands({ curr->ifTrue, curr->ifFalse, curr->condition }, curr->type);
+ blockifyReachableOperands({curr->ifTrue, curr->ifFalse, curr->condition},
+ curr->type);
}
void visitDrop(Drop* curr) {
- blockifyReachableOperands({ curr->value }, curr->type);
+ blockifyReachableOperands({curr->value}, curr->type);
}
- void visitHost(Host* curr) {
- handleCall(curr);
- }
+ void visitHost(Host* curr) { handleCall(curr); }
- void visitFunction(Function* curr) {
- assert(reachableBreaks.size() == 0);
- }
+ void visitFunction(Function* curr) { assert(reachableBreaks.size() == 0); }
};
-Pass *createDeadCodeEliminationPass() {
- return new DeadCodeElimination();
-}
+Pass* createDeadCodeEliminationPass() { return new DeadCodeElimination(); }
} // namespace wasm
diff --git a/src/passes/Directize.cpp b/src/passes/Directize.cpp
index 3d8fcdfdd..8f75c8f57 100644
--- a/src/passes/Directize.cpp
+++ b/src/passes/Directize.cpp
@@ -22,13 +22,13 @@
#include <unordered_map>
-#include "wasm.h"
-#include "pass.h"
-#include "wasm-builder.h"
-#include "wasm-traversal.h"
#include "asm_v_wasm.h"
#include "ir/table-utils.h"
#include "ir/utils.h"
+#include "pass.h"
+#include "wasm-builder.h"
+#include "wasm-traversal.h"
+#include "wasm.h"
namespace wasm {
@@ -64,11 +64,8 @@ struct FunctionDirectizer : public WalkerPass<PostWalker<FunctionDirectizer>> {
return;
}
// Everything looks good!
- replaceCurrent(Builder(*getModule()).makeCall(
- name,
- curr->operands,
- curr->type
- ));
+ replaceCurrent(
+ Builder(*getModule()).makeCall(name, curr->operands, curr->type));
}
}
@@ -88,25 +85,25 @@ private:
for (auto*& operand : call->operands) {
operand = builder.makeDrop(operand);
}
- replaceCurrent(
- builder.makeSequence(
- builder.makeBlock(call->operands),
- builder.makeUnreachable()
- )
- );
+ replaceCurrent(builder.makeSequence(builder.makeBlock(call->operands),
+ builder.makeUnreachable()));
changedTypes = true;
}
};
struct Directize : public Pass {
void run(PassRunner* runner, Module* module) override {
- if (!module->table.exists) return;
- if (module->table.imported()) return;
+ if (!module->table.exists)
+ return;
+ if (module->table.imported())
+ return;
for (auto& ex : module->exports) {
- if (ex->kind == ExternalKind::Table) return;
+ if (ex->kind == ExternalKind::Table)
+ return;
}
FlatTable flatTable(module->table);
- if (!flatTable.valid) return;
+ if (!flatTable.valid)
+ return;
// The table exists and is constant, so this is possible.
{
PassRunner runner(module);
@@ -119,9 +116,6 @@ struct Directize : public Pass {
} // anonymous namespace
-Pass *createDirectizePass() {
- return new Directize();
-}
+Pass* createDirectizePass() { return new Directize(); }
} // namespace wasm
-
diff --git a/src/passes/DuplicateFunctionElimination.cpp b/src/passes/DuplicateFunctionElimination.cpp
index b7fcb556c..3caa43e1d 100644
--- a/src/passes/DuplicateFunctionElimination.cpp
+++ b/src/passes/DuplicateFunctionElimination.cpp
@@ -20,19 +20,20 @@
// identical when finally lowered into concrete wasm code.
//
-#include "wasm.h"
-#include "pass.h"
-#include "ir/utils.h"
#include "ir/function-utils.h"
#include "ir/hashed.h"
#include "ir/module-utils.h"
+#include "ir/utils.h"
+#include "pass.h"
+#include "wasm.h"
namespace wasm {
struct FunctionReplacer : public WalkerPass<PostWalker<FunctionReplacer>> {
bool isFunctionParallel() override { return true; }
- FunctionReplacer(std::map<Name, Name>* replacements) : replacements(replacements) {}
+ FunctionReplacer(std::map<Name, Name>* replacements)
+ : replacements(replacements) {}
FunctionReplacer* create() override {
return new FunctionReplacer(replacements);
@@ -51,15 +52,17 @@ private:
struct DuplicateFunctionElimination : public Pass {
void run(PassRunner* runner, Module* module) override {
- // Multiple iterations may be necessary: A and B may be identical only after we
- // see the functions C1 and C2 that they call are in fact identical. Rarely, such
- // "chains" can be very long, so we limit how many we do.
+ // Multiple iterations may be necessary: A and B may be identical only after
+ // we see the functions C1 and C2 that they call are in fact identical.
+ // Rarely, such "chains" can be very long, so we limit how many we do.
auto& options = runner->options;
Index limit;
if (options.optimizeLevel >= 3 || options.shrinkLevel >= 1) {
limit = module->functions.size(); // no limit
} else if (options.optimizeLevel >= 2) {
- limit = 10; // 10 passes usually does most of the work, as this is typically logarithmic
+ // 10 passes usually does most of the work, as this is typically
+ // logarithmic
+ limit = 10;
} else {
limit = 1;
}
@@ -82,16 +85,19 @@ struct DuplicateFunctionElimination : public Pass {
for (auto& pair : hashGroups) {
auto& group = pair.second;
Index size = group.size();
- if (size == 1) continue;
- // The groups should be fairly small, and even if a group is large we should
- // have almost all of them identical, so we should not hit actual O(N^2)
- // here unless the hash is quite poor.
+ if (size == 1)
+ continue;
+ // The groups should be fairly small, and even if a group is large we
+ // should have almost all of them identical, so we should not hit actual
+ // O(N^2) here unless the hash is quite poor.
for (Index i = 0; i < size - 1; i++) {
auto* first = group[i];
- if (duplicates.count(first->name)) continue;
+ if (duplicates.count(first->name))
+ continue;
for (Index j = i + 1; j < size; j++) {
auto* second = group[j];
- if (duplicates.count(second->name)) continue;
+ if (duplicates.count(second->name))
+ continue;
if (FunctionUtils::equal(first, second)) {
// great, we can replace the second with the first!
replacements[second->name] = first->name;
@@ -104,9 +110,12 @@ struct DuplicateFunctionElimination : public Pass {
if (replacements.size() > 0) {
// remove the duplicates
auto& v = module->functions;
- v.erase(std::remove_if(v.begin(), v.end(), [&](const std::unique_ptr<Function>& curr) {
- return duplicates.count(curr->name) > 0;
- }), v.end());
+ v.erase(std::remove_if(v.begin(),
+ v.end(),
+ [&](const std::unique_ptr<Function>& curr) {
+ return duplicates.count(curr->name) > 0;
+ }),
+ v.end());
module->updateMaps();
// replace direct calls
PassRunner replacerRunner(module);
@@ -143,7 +152,7 @@ struct DuplicateFunctionElimination : public Pass {
}
};
-Pass *createDuplicateFunctionEliminationPass() {
+Pass* createDuplicateFunctionEliminationPass() {
return new DuplicateFunctionElimination();
}
diff --git a/src/passes/ExtractFunction.cpp b/src/passes/ExtractFunction.cpp
index 8a97ced8e..8942771fe 100644
--- a/src/passes/ExtractFunction.cpp
+++ b/src/passes/ExtractFunction.cpp
@@ -18,14 +18,16 @@
// with (mostly) just the code you want to debug (function-parallel,
// non-lto) passes on.
-#include "wasm.h"
#include "pass.h"
+#include "wasm.h"
namespace wasm {
struct ExtractFunction : public Pass {
void run(PassRunner* runner, Module* module) override {
- Name name = runner->options.getArgument("extract", "ExtractFunction usage: wasm-opt --pass-arg=extract:FUNCTION_NAME");
+ Name name = runner->options.getArgument(
+ "extract",
+ "ExtractFunction usage: wasm-opt --pass-arg=extract:FUNCTION_NAME");
std::cerr << "extracting " << name << "\n";
bool found = false;
for (auto& func : module->functions) {
@@ -58,9 +60,6 @@ struct ExtractFunction : public Pass {
// declare pass
-Pass *createExtractFunctionPass() {
- return new ExtractFunction();
-}
+Pass* createExtractFunctionPass() { return new ExtractFunction(); }
} // namespace wasm
-
diff --git a/src/passes/Flatten.cpp b/src/passes/Flatten.cpp
index df6be947d..a68fc9abe 100644
--- a/src/passes/Flatten.cpp
+++ b/src/passes/Flatten.cpp
@@ -18,13 +18,13 @@
// Flattens code into "Flat IR" form. See ir/flat.h.
//
-#include <wasm.h>
-#include <pass.h>
-#include <wasm-builder.h>
#include <ir/branch-utils.h>
#include <ir/effects.h>
#include <ir/flat.h>
#include <ir/utils.h>
+#include <pass.h>
+#include <wasm-builder.h>
+#include <wasm.h>
namespace wasm {
@@ -43,12 +43,15 @@ namespace wasm {
// Once exception is that we allow an (unreachable) node, which is used
// when we move something unreachable to another place, and need a
// placeholder. We will never reach that (unreachable) anyhow
-struct Flatten : public WalkerPass<ExpressionStackWalker<Flatten, UnifiedExpressionVisitor<Flatten>>> {
+struct Flatten
+ : public WalkerPass<
+ ExpressionStackWalker<Flatten, UnifiedExpressionVisitor<Flatten>>> {
bool isFunctionParallel() override { return true; }
Pass* create() override { return new Flatten; }
- // For each expression, a bunch of expressions that should execute right before it
+ // For each expression, a bunch of expressions that should execute right
+ // before it
std::unordered_map<Expression*, std::vector<Expression*>> preludes;
// Break values are sent through a temp local
@@ -61,7 +64,9 @@ struct Flatten : public WalkerPass<ExpressionStackWalker<Flatten, UnifiedExpress
if (Flat::isControlFlowStructure(curr)) {
// handle control flow explicitly. our children do not have control flow,
// but they do have preludes which we need to set up in the right place
- assert(preludes.find(curr) == preludes.end()); // no one should have given us preludes, they are on the children
+
+ // no one should have given us preludes, they are on the children
+ assert(preludes.find(curr) == preludes.end());
if (auto* block = curr->dynCast<Block>()) {
// make a new list, where each item's preludes are added before it
ExpressionList newList(getModule()->allocator);
@@ -123,7 +128,9 @@ struct Flatten : public WalkerPass<ExpressionStackWalker<Flatten, UnifiedExpress
rep = builder.makeGetLocal(temp, type);
}
iff->ifTrue = getPreludesWithExpression(originalIfTrue, iff->ifTrue);
- if (iff->ifFalse) iff->ifFalse = getPreludesWithExpression(originalIfFalse, iff->ifFalse);
+ if (iff->ifFalse)
+ iff->ifFalse =
+ getPreludesWithExpression(originalIfFalse, iff->ifFalse);
iff->finalize();
if (prelude) {
ReFinalizeNode().visit(prelude);
@@ -204,10 +211,9 @@ struct Flatten : public WalkerPass<ExpressionStackWalker<Flatten, UnifiedExpress
// we don't know which break target will be hit - assign to them all
auto names = BranchUtils::getUniqueTargets(sw);
for (auto name : names) {
- ourPreludes.push_back(builder.makeSetLocal(
- getTempForBreakTarget(name, type),
- builder.makeGetLocal(temp, type)
- ));
+ ourPreludes.push_back(
+ builder.makeSetLocal(getTempForBreakTarget(name, type),
+ builder.makeGetLocal(temp, type)));
}
sw->value = nullptr;
sw->finalize();
@@ -275,9 +281,11 @@ private:
// gets an expression, either by itself, or in a block with some
// preludes (which we use up) for another expression before it
- Expression* getPreludesWithExpression(Expression* preluder, Expression* after) {
+ Expression* getPreludesWithExpression(Expression* preluder,
+ Expression* after) {
auto iter = preludes.find(preluder);
- if (iter == preludes.end()) return after;
+ if (iter == preludes.end())
+ return after;
// we have preludes
auto& thePreludes = iter->second;
auto* ret = Builder(*getModule()).makeBlock(thePreludes);
@@ -294,14 +302,12 @@ private:
if (iter != breakTemps.end()) {
return iter->second;
} else {
- return breakTemps[name] = Builder(*getModule()).addVar(getFunction(), type);
+ return breakTemps[name] =
+ Builder(*getModule()).addVar(getFunction(), type);
}
}
};
-Pass *createFlattenPass() {
- return new Flatten();
-}
+Pass* createFlattenPass() { return new Flatten(); }
} // namespace wasm
-
diff --git a/src/passes/FuncCastEmulation.cpp b/src/passes/FuncCastEmulation.cpp
index 36a2819b2..904b8a202 100644
--- a/src/passes/FuncCastEmulation.cpp
+++ b/src/passes/FuncCastEmulation.cpp
@@ -27,12 +27,12 @@
// This should work even with dynamic linking, however, the number of
// params must be identical, i.e., the "ABI" must match.
-#include <wasm.h>
-#include <wasm-builder.h>
#include <asm_v_wasm.h>
+#include <ir/literal-utils.h>
#include <pass.h>
+#include <wasm-builder.h>
#include <wasm-emscripten.h>
-#include <ir/literal-utils.h>
+#include <wasm.h>
namespace wasm {
@@ -54,10 +54,8 @@ static Expression* toABI(Expression* value, Module* module) {
break;
}
case f32: {
- value = builder.makeUnary(
- ExtendUInt32,
- builder.makeUnary(ReinterpretFloat32, value)
- );
+ value = builder.makeUnary(ExtendUInt32,
+ builder.makeUnary(ReinterpretFloat32, value));
break;
}
case f64: {
@@ -70,10 +68,7 @@ static Expression* toABI(Expression* value, Module* module) {
}
case none: {
// the value is none, but we need a value here
- value = builder.makeSequence(
- value,
- LiteralUtils::makeZero(i64, *module)
- );
+ value = builder.makeSequence(value, LiteralUtils::makeZero(i64, *module));
break;
}
case unreachable: {
@@ -97,10 +92,8 @@ static Expression* fromABI(Expression* value, Type type, Module* module) {
break;
}
case f32: {
- value = builder.makeUnary(
- ReinterpretInt32,
- builder.makeUnary(WrapInt64, value)
- );
+ value = builder.makeUnary(ReinterpretInt32,
+ builder.makeUnary(WrapInt64, value));
break;
}
case f64: {
@@ -122,7 +115,8 @@ static Expression* fromABI(Expression* value, Type type, Module* module) {
return value;
}
-struct ParallelFuncCastEmulation : public WalkerPass<PostWalker<ParallelFuncCastEmulation>> {
+struct ParallelFuncCastEmulation
+ : public WalkerPass<PostWalker<ParallelFuncCastEmulation>> {
bool isFunctionParallel() override { return true; }
Pass* create() override { return new ParallelFuncCastEmulation(ABIType); }
@@ -131,8 +125,8 @@ struct ParallelFuncCastEmulation : public WalkerPass<PostWalker<ParallelFuncCast
void visitCallIndirect(CallIndirect* curr) {
if (curr->operands.size() > NUM_PARAMS) {
- Fatal() << "FuncCastEmulation::NUM_PARAMS needs to be at least " <<
- curr->operands.size();
+ Fatal() << "FuncCastEmulation::NUM_PARAMS needs to be at least "
+ << curr->operands.size();
}
for (Expression*& operand : curr->operands) {
operand = toABI(operand, getModule());
@@ -197,7 +191,8 @@ private:
Name makeThunk(Name name, Module* module) {
Name thunk = std::string("byn$fpcast-emu$") + name.str;
if (module->getFunctionOrNull(thunk)) {
- Fatal() << "FuncCastEmulation::makeThunk seems a thunk name already in use. Was the pass already run on this code?";
+ Fatal() << "FuncCastEmulation::makeThunk seems a thunk name already in "
+ "use. Was the pass already run on this code?";
}
// The item in the table may be a function or a function import.
auto* func = module->getFunction(name);
@@ -206,28 +201,25 @@ private:
Builder builder(*module);
std::vector<Expression*> callOperands;
for (Index i = 0; i < params.size(); i++) {
- callOperands.push_back(fromABI(builder.makeGetLocal(i, i64), params[i], module));
+ callOperands.push_back(
+ fromABI(builder.makeGetLocal(i, i64), params[i], module));
}
auto* call = builder.makeCall(name, callOperands, type);
std::vector<Type> thunkParams;
for (Index i = 0; i < NUM_PARAMS; i++) {
thunkParams.push_back(i64);
}
- auto* thunkFunc = builder.makeFunction(
- thunk,
- std::move(thunkParams),
- i64,
- {}, // no vars
- toABI(call, module)
- );
+ auto* thunkFunc = builder.makeFunction(thunk,
+ std::move(thunkParams),
+ i64,
+ {}, // no vars
+ toABI(call, module));
thunkFunc->type = ABIType;
module->addFunction(thunkFunc);
return thunk;
}
};
-Pass* createFuncCastEmulationPass() {
- return new FuncCastEmulation();
-}
+Pass* createFuncCastEmulationPass() { return new FuncCastEmulation(); }
} // namespace wasm
diff --git a/src/passes/I64ToI32Lowering.cpp b/src/passes/I64ToI32Lowering.cpp
index 731b42d3a..e2d3cc414 100644
--- a/src/passes/I64ToI32Lowering.cpp
+++ b/src/passes/I64ToI32Lowering.cpp
@@ -21,32 +21,31 @@
// global.
//
-#include <algorithm>
-#include "wasm.h"
-#include "pass.h"
-#include "emscripten-optimizer/istring.h"
-#include "support/name.h"
-#include "wasm-builder.h"
#include "abi/js.h"
+#include "asmjs/shared-constants.h"
+#include "emscripten-optimizer/istring.h"
#include "ir/flat.h"
#include "ir/iteration.h"
#include "ir/memory-utils.h"
#include "ir/module-utils.h"
#include "ir/names.h"
-#include "asmjs/shared-constants.h"
+#include "pass.h"
+#include "support/name.h"
+#include "wasm-builder.h"
+#include "wasm.h"
+#include <algorithm>
namespace wasm {
-static Name makeHighName(Name n) {
- return std::string(n.c_str()) + "$hi";
-}
+static Name makeHighName(Name n) { return std::string(n.c_str()) + "$hi"; }
struct I64ToI32Lowering : public WalkerPass<PostWalker<I64ToI32Lowering>> {
struct TempVar {
- TempVar(Index idx, Type ty, I64ToI32Lowering& pass) :
- idx(idx), pass(pass), moved(false), ty(ty) {}
+ TempVar(Index idx, Type ty, I64ToI32Lowering& pass)
+ : idx(idx), pass(pass), moved(false), ty(ty) {}
- TempVar(TempVar&& other) : idx(other), pass(other.pass), moved(false), ty(other.ty) {
+ TempVar(TempVar&& other)
+ : idx(other), pass(other.pass), moved(false), ty(other.ty) {
assert(!other.moved);
other.moved = true;
}
@@ -54,7 +53,8 @@ struct I64ToI32Lowering : public WalkerPass<PostWalker<I64ToI32Lowering>> {
TempVar& operator=(TempVar&& rhs) {
assert(!rhs.moved);
// free overwritten idx
- if (!moved) freeIdx();
+ if (!moved)
+ freeIdx();
idx = rhs.idx;
rhs.moved = true;
moved = false;
@@ -62,7 +62,8 @@ struct I64ToI32Lowering : public WalkerPass<PostWalker<I64ToI32Lowering>> {
}
~TempVar() {
- if (!moved) freeIdx();
+ if (!moved)
+ freeIdx();
}
bool operator==(const TempVar& rhs) {
@@ -81,8 +82,9 @@ struct I64ToI32Lowering : public WalkerPass<PostWalker<I64ToI32Lowering>> {
private:
void freeIdx() {
- auto &freeList = pass.freeTemps[(int) ty];
- assert(std::find(freeList.begin(), freeList.end(), idx) == freeList.end());
+ auto& freeList = pass.freeTemps[(int)ty];
+ assert(std::find(freeList.begin(), freeList.end(), idx) ==
+ freeList.end());
freeList.push_back(idx);
}
@@ -96,19 +98,22 @@ struct I64ToI32Lowering : public WalkerPass<PostWalker<I64ToI32Lowering>> {
// TODO: allow module-level transformations in parallel passes
bool isFunctionParallel() override { return false; }
- Pass* create() override {
- return new I64ToI32Lowering;
- }
+ Pass* create() override { return new I64ToI32Lowering; }
void doWalkModule(Module* module) {
- if (!builder) builder = make_unique<Builder>(*module);
+ if (!builder)
+ builder = make_unique<Builder>(*module);
// add new globals for high bits
for (size_t i = 0, globals = module->globals.size(); i < globals; ++i) {
auto* curr = module->globals[i].get();
- if (curr->type != i64) continue;
+ if (curr->type != i64)
+ continue;
originallyI64Globals.insert(curr->name);
curr->type = i32;
- auto* high = builder->makeGlobal(makeHighName(curr->name), i32, builder->makeConst(Literal(int32_t(0))), Builder::Mutable);
+ auto* high = builder->makeGlobal(makeHighName(curr->name),
+ i32,
+ builder->makeConst(Literal(int32_t(0))),
+ Builder::Mutable);
module->addGlobal(high);
if (curr->imported()) {
Fatal() << "TODO: imported i64 globals";
@@ -157,7 +162,8 @@ struct I64ToI32Lowering : public WalkerPass<PostWalker<I64ToI32Lowering>> {
void doWalkFunction(Function* func) {
Flat::verifyFlatness(func);
// create builder here if this is first entry to module for this object
- if (!builder) builder = make_unique<Builder>(*getModule());
+ if (!builder)
+ builder = make_unique<Builder>(*getModule());
indexMap.clear();
highBitVars.clear();
freeTemps.clear();
@@ -174,9 +180,10 @@ struct I64ToI32Lowering : public WalkerPass<PostWalker<I64ToI32Lowering>> {
Name lowName = oldFunc->getLocalName(i);
Name highName = makeHighName(lowName);
Type paramType = oldFunc->getLocalType(i);
- auto builderFunc = (i < oldFunc->getVarIndexBase()) ?
- Builder::addParam :
- static_cast<Index (*)(Function*, Name, Type)>(Builder::addVar);
+ auto builderFunc =
+ (i < oldFunc->getVarIndexBase())
+ ? Builder::addParam
+ : static_cast<Index (*)(Function*, Name, Type)>(Builder::addVar);
if (paramType == i64) {
builderFunc(func, lowName, i32);
builderFunc(func, highName, i32);
@@ -201,14 +208,9 @@ struct I64ToI32Lowering : public WalkerPass<PostWalker<I64ToI32Lowering>> {
if (hasOutParam(func->body)) {
TempVar highBits = fetchOutParam(func->body);
TempVar lowBits = getTemp();
- SetLocal* setLow = builder->makeSetLocal(
- lowBits,
- func->body
- );
+ SetLocal* setLow = builder->makeSetLocal(lowBits, func->body);
SetGlobal* setHigh = builder->makeSetGlobal(
- INT64_TO_32_HIGH_BITS,
- builder->makeGetLocal(highBits, i32)
- );
+ INT64_TO_32_HIGH_BITS, builder->makeGetLocal(highBits, i32));
GetLocal* getLow = builder->makeGetLocal(lowBits, i32);
func->body = builder->blockify(setLow, setHigh, getLow);
}
@@ -223,7 +225,8 @@ struct I64ToI32Lowering : public WalkerPass<PostWalker<I64ToI32Lowering>> {
template<typename T>
using BuilderFunc = std::function<T*(std::vector<Expression*>&, Type)>;
- // Fixes up a call. If we performed fixups, returns the call; otherwise returns nullptr;
+ // Fixes up a call. If we performed fixups, returns the call; otherwise
+ // returns nullptr;
template<typename T>
T* visitGenericCall(T* curr, BuilderFunc<T> callBuilder) {
bool fixed = false;
@@ -233,7 +236,7 @@ struct I64ToI32Lowering : public WalkerPass<PostWalker<I64ToI32Lowering>> {
if (hasOutParam(e)) {
TempVar argHighBits = fetchOutParam(e);
args.push_back(builder->makeGetLocal(argHighBits, i32));
- fixed = true;
+ fixed = true;
}
}
if (curr->type != i64) {
@@ -244,14 +247,9 @@ struct I64ToI32Lowering : public WalkerPass<PostWalker<I64ToI32Lowering>> {
TempVar lowBits = getTemp();
TempVar highBits = getTemp();
auto* call = callBuilder(args, i32);
- SetLocal* doCall = builder->makeSetLocal(
- lowBits,
- call
- );
+ SetLocal* doCall = builder->makeSetLocal(lowBits, call);
SetLocal* setHigh = builder->makeSetLocal(
- highBits,
- builder->makeGetGlobal(INT64_TO_32_HIGH_BITS, i32)
- );
+ highBits, builder->makeGetGlobal(INT64_TO_32_HIGH_BITS, i32));
GetLocal* getLow = builder->makeGetLocal(lowBits, i32);
Block* result = builder->blockify(doCall, setHigh, getLow);
setOutParam(result, std::move(highBits));
@@ -260,11 +258,9 @@ struct I64ToI32Lowering : public WalkerPass<PostWalker<I64ToI32Lowering>> {
}
void visitCall(Call* curr) {
auto* fixedCall = visitGenericCall<Call>(
- curr,
- [&](std::vector<Expression*>& args, Type ty) {
+ curr, [&](std::vector<Expression*>& args, Type ty) {
return builder->makeCall(curr->target, args, ty);
- }
- );
+ });
// If this was to an import, we need to call the legal version. This assumes
// that legalize-js-interface has been run before.
if (fixedCall && getModule()->getFunction(fixedCall->target)->imported()) {
@@ -275,16 +271,10 @@ struct I64ToI32Lowering : public WalkerPass<PostWalker<I64ToI32Lowering>> {
void visitCallIndirect(CallIndirect* curr) {
visitGenericCall<CallIndirect>(
- curr,
- [&](std::vector<Expression*>& args, Type ty) {
+ curr, [&](std::vector<Expression*>& args, Type ty) {
return builder->makeCallIndirect(
- curr->fullType,
- curr->target,
- args,
- ty
- );
- }
- );
+ curr->fullType, curr->target, args, ty);
+ });
}
void visitGetLocal(GetLocal* curr) {
@@ -297,13 +287,8 @@ struct I64ToI32Lowering : public WalkerPass<PostWalker<I64ToI32Lowering>> {
}
curr->type = i32;
TempVar highBits = getTemp();
- SetLocal *setHighBits = builder->makeSetLocal(
- highBits,
- builder->makeGetLocal(
- mappedIndex + 1,
- i32
- )
- );
+ SetLocal* setHighBits = builder->makeSetLocal(
+ highBits, builder->makeGetLocal(mappedIndex + 1, i32));
Block* result = builder->blockify(setHighBits, curr);
replaceCurrent(result);
setOutParam(result, std::move(highBits));
@@ -315,9 +300,7 @@ struct I64ToI32Lowering : public WalkerPass<PostWalker<I64ToI32Lowering>> {
curr->type = i32;
SetLocal* setLow = builder->makeSetLocal(tmp, curr);
SetLocal* setHigh = builder->makeSetLocal(
- curr->index + 1,
- builder->makeGetLocal(highBits, i32)
- );
+ curr->index + 1, builder->makeGetLocal(highBits, i32));
GetLocal* getLow = builder->makeGetLocal(tmp, i32);
Block* result = builder->blockify(setLow, setHigh, getLow);
replaceCurrent(result);
@@ -337,44 +320,40 @@ struct I64ToI32Lowering : public WalkerPass<PostWalker<I64ToI32Lowering>> {
return;
}
TempVar highBits = fetchOutParam(curr->value);
- auto* setHigh = builder->makeSetLocal(
- mappedIndex + 1,
- builder->makeGetLocal(highBits, i32)
- );
+ auto* setHigh = builder->makeSetLocal(mappedIndex + 1,
+ builder->makeGetLocal(highBits, i32));
Block* result = builder->blockify(curr, setHigh);
replaceCurrent(result);
}
void visitGetGlobal(GetGlobal* curr) {
- if (!getFunction()) return; // if in a global init, skip - we already handled that.
- if (!originallyI64Globals.count(curr->name)) return;
+ if (!getFunction())
+ return; // if in a global init, skip - we already handled that.
+ if (!originallyI64Globals.count(curr->name))
+ return;
curr->type = i32;
TempVar highBits = getTemp();
- SetLocal *setHighBits = builder->makeSetLocal(
- highBits,
- builder->makeGetGlobal(
- makeHighName(curr->name),
- i32
- )
- );
+ SetLocal* setHighBits = builder->makeSetLocal(
+ highBits, builder->makeGetGlobal(makeHighName(curr->name), i32));
Block* result = builder->blockify(setHighBits, curr);
replaceCurrent(result);
setOutParam(result, std::move(highBits));
}
void visitSetGlobal(SetGlobal* curr) {
- if (!originallyI64Globals.count(curr->name)) return;
- if (handleUnreachable(curr)) return;
+ if (!originallyI64Globals.count(curr->name))
+ return;
+ if (handleUnreachable(curr))
+ return;
TempVar highBits = fetchOutParam(curr->value);
auto* setHigh = builder->makeSetGlobal(
- makeHighName(curr->name),
- builder->makeGetLocal(highBits, i32)
- );
+ makeHighName(curr->name), builder->makeGetLocal(highBits, i32));
replaceCurrent(builder->makeSequence(curr, setHigh));
}
void visitLoad(Load* curr) {
- if (curr->type != i64) return;
+ if (curr->type != i64)
+ return;
assert(!curr->isAtomic && "atomic load not implemented");
TempVar lowBits = getTemp();
TempVar highBits = getTemp();
@@ -384,46 +363,37 @@ struct I64ToI32Lowering : public WalkerPass<PostWalker<I64ToI32Lowering>> {
if (curr->bytes == 8) {
loadHigh = builder->makeSetLocal(
highBits,
- builder->makeLoad(
- 4,
- curr->signed_,
- curr->offset + 4,
- 1,
- builder->makeGetLocal(ptrTemp, i32),
- i32
- )
- );
+ builder->makeLoad(4,
+ curr->signed_,
+ curr->offset + 4,
+ 1,
+ builder->makeGetLocal(ptrTemp, i32),
+ i32));
} else if (curr->signed_) {
loadHigh = builder->makeSetLocal(
highBits,
- builder->makeBinary(
- ShrSInt32,
- builder->makeGetLocal(lowBits, i32),
- builder->makeConst(Literal(int32_t(31)))
- )
- );
+ builder->makeBinary(ShrSInt32,
+ builder->makeGetLocal(lowBits, i32),
+ builder->makeConst(Literal(int32_t(31)))));
} else {
- loadHigh = builder->makeSetLocal(
- highBits,
- builder->makeConst(Literal(int32_t(0)))
- );
+ loadHigh = builder->makeSetLocal(highBits,
+ builder->makeConst(Literal(int32_t(0))));
}
curr->type = i32;
curr->bytes = std::min(curr->bytes, uint8_t(4));
curr->align = std::min(uint32_t(curr->align), uint32_t(4));
curr->ptr = builder->makeGetLocal(ptrTemp, i32);
- Block* result = builder->blockify(
- setPtr,
- builder->makeSetLocal(lowBits, curr),
- loadHigh,
- builder->makeGetLocal(lowBits, i32)
- );
+ Block* result = builder->blockify(setPtr,
+ builder->makeSetLocal(lowBits, curr),
+ loadHigh,
+ builder->makeGetLocal(lowBits, i32));
replaceCurrent(result);
setOutParam(result, std::move(highBits));
}
void visitStore(Store* curr) {
- if (!hasOutParam(curr->value)) return;
+ if (!hasOutParam(curr->value))
+ return;
assert(curr->offset + 4 > curr->offset);
assert(!curr->isAtomic && "atomic store not implemented");
TempVar highBits = fetchOutParam(curr->value);
@@ -436,14 +406,13 @@ struct I64ToI32Lowering : public WalkerPass<PostWalker<I64ToI32Lowering>> {
SetLocal* setPtr = builder->makeSetLocal(ptrTemp, curr->ptr);
curr->ptr = builder->makeGetLocal(ptrTemp, i32);
curr->finalize();
- Store* storeHigh = builder->makeStore(
- 4,
- curr->offset + 4,
- 1,
- builder->makeGetLocal(ptrTemp, i32),
- builder->makeGetLocal(highBits, i32),
- i32
- );
+ Store* storeHigh =
+ builder->makeStore(4,
+ curr->offset + 4,
+ 1,
+ builder->makeGetLocal(ptrTemp, i32),
+ builder->makeGetLocal(highBits, i32),
+ i32);
replaceCurrent(builder->blockify(setPtr, curr, storeHigh));
}
}
@@ -457,18 +426,17 @@ struct I64ToI32Lowering : public WalkerPass<PostWalker<I64ToI32Lowering>> {
}
void visitConst(Const* curr) {
- if (!getFunction()) return; // if in a global init, skip - we already handled that.
- if (curr->type != i64) return;
+ if (!getFunction())
+ return; // if in a global init, skip - we already handled that.
+ if (curr->type != i64)
+ return;
TempVar highBits = getTemp();
- Const* lowVal = builder->makeConst(
- Literal(int32_t(curr->value.geti64() & 0xffffffff))
- );
- SetLocal* setHigh = builder->makeSetLocal(
- highBits,
- builder->makeConst(
- Literal(int32_t(uint64_t(curr->value.geti64()) >> 32))
- )
- );
+ Const* lowVal =
+ builder->makeConst(Literal(int32_t(curr->value.geti64() & 0xffffffff)));
+ SetLocal* setHigh =
+ builder->makeSetLocal(highBits,
+ builder->makeConst(Literal(
+ int32_t(uint64_t(curr->value.geti64()) >> 32))));
Block* result = builder->blockify(setHigh, lowVal);
setOutParam(result, std::move(highBits));
replaceCurrent(result);
@@ -480,11 +448,7 @@ struct I64ToI32Lowering : public WalkerPass<PostWalker<I64ToI32Lowering>> {
auto* result = builder->makeUnary(
EqZInt32,
builder->makeBinary(
- OrInt32,
- curr->value,
- builder->makeGetLocal(highBits, i32)
- )
- );
+ OrInt32, curr->value, builder->makeGetLocal(highBits, i32)));
replaceCurrent(result);
}
@@ -493,8 +457,7 @@ struct I64ToI32Lowering : public WalkerPass<PostWalker<I64ToI32Lowering>> {
TempVar highBits = getTemp();
Block* result = builder->blockify(
builder->makeSetLocal(highBits, builder->makeConst(Literal(int32_t(0)))),
- curr->value
- );
+ curr->value);
setOutParam(result, std::move(highBits));
replaceCurrent(result);
}
@@ -506,18 +469,12 @@ struct I64ToI32Lowering : public WalkerPass<PostWalker<I64ToI32Lowering>> {
SetLocal* setLow = builder->makeSetLocal(lowBits, curr->value);
SetLocal* setHigh = builder->makeSetLocal(
highBits,
- builder->makeBinary(
- ShrSInt32,
- builder->makeGetLocal(lowBits, i32),
- builder->makeConst(Literal(int32_t(31)))
- )
- );
+ builder->makeBinary(ShrSInt32,
+ builder->makeGetLocal(lowBits, i32),
+ builder->makeConst(Literal(int32_t(31)))));
- Block* result = builder->blockify(
- setLow,
- setHigh,
- builder->makeGetLocal(lowBits, i32)
- );
+ Block* result =
+ builder->blockify(setLow, setHigh, builder->makeGetLocal(lowBits, i32));
setOutParam(result, std::move(highBits));
replaceCurrent(result);
@@ -533,14 +490,16 @@ struct I64ToI32Lowering : public WalkerPass<PostWalker<I64ToI32Lowering>> {
// Assume that the wasm file assumes the address 0 is invalid and roundtrip
// our f64 through memory at address 0
TempVar highBits = getTemp();
- Block *result = builder->blockify(
- builder->makeCall(ABI::wasm2js::SCRATCH_STORE_F64, { curr->value }, none),
+ Block* result = builder->blockify(
+ builder->makeCall(ABI::wasm2js::SCRATCH_STORE_F64, {curr->value}, none),
builder->makeSetLocal(
highBits,
- builder->makeCall(ABI::wasm2js::SCRATCH_LOAD_I32, { builder->makeConst(Literal(int32_t(1))) }, i32)
- ),
- builder->makeCall(ABI::wasm2js::SCRATCH_LOAD_I32, { builder->makeConst(Literal(int32_t(0))) }, i32)
- );
+ builder->makeCall(ABI::wasm2js::SCRATCH_LOAD_I32,
+ {builder->makeConst(Literal(int32_t(1)))},
+ i32)),
+ builder->makeCall(ABI::wasm2js::SCRATCH_LOAD_I32,
+ {builder->makeConst(Literal(int32_t(0)))},
+ i32));
setOutParam(result, std::move(highBits));
replaceCurrent(result);
MemoryUtils::ensureExists(getModule()->memory);
@@ -551,17 +510,21 @@ struct I64ToI32Lowering : public WalkerPass<PostWalker<I64ToI32Lowering>> {
// Assume that the wasm file assumes the address 0 is invalid and roundtrip
// our i64 through memory at address 0
TempVar highBits = fetchOutParam(curr->value);
- Block *result = builder->blockify(
- builder->makeCall(ABI::wasm2js::SCRATCH_STORE_I32, { builder->makeConst(Literal(int32_t(0))), curr->value }, none),
- builder->makeCall(ABI::wasm2js::SCRATCH_STORE_I32, { builder->makeConst(Literal(int32_t(1))), builder->makeGetLocal(highBits, i32) }, none),
- builder->makeCall(ABI::wasm2js::SCRATCH_LOAD_F64, {}, f64)
- );
+ Block* result = builder->blockify(
+ builder->makeCall(ABI::wasm2js::SCRATCH_STORE_I32,
+ {builder->makeConst(Literal(int32_t(0))), curr->value},
+ none),
+ builder->makeCall(ABI::wasm2js::SCRATCH_STORE_I32,
+ {builder->makeConst(Literal(int32_t(1))),
+ builder->makeGetLocal(highBits, i32)},
+ none),
+ builder->makeCall(ABI::wasm2js::SCRATCH_LOAD_F64, {}, f64));
replaceCurrent(result);
MemoryUtils::ensureExists(getModule()->memory);
ABI::wasm2js::ensureScratchMemoryHelpers(getModule());
}
- void lowerTruncFloatToInt(Unary *curr) {
+ void lowerTruncFloatToInt(Unary* curr) {
// hiBits = if abs(f) >= 1.0 {
// if f > 0.0 {
// (unsigned) min(
@@ -584,9 +547,9 @@ struct I64ToI32Lowering : public WalkerPass<PostWalker<I64ToI32Lowering>> {
switch (curr->op) {
case TruncSFloat32ToInt64:
case TruncUFloat32ToInt64: {
- litZero = Literal((float) 0);
- litOne = Literal((float) 1);
- u32Max = Literal(((float) UINT_MAX) + 1);
+ litZero = Literal((float)0);
+ litOne = Literal((float)1);
+ u32Max = Literal(((float)UINT_MAX) + 1);
trunc = TruncUFloat32ToInt32;
convert = ConvertUInt32ToFloat32;
localType = f32;
@@ -602,9 +565,9 @@ struct I64ToI32Lowering : public WalkerPass<PostWalker<I64ToI32Lowering>> {
}
case TruncSFloat64ToInt64:
case TruncUFloat64ToInt64: {
- litZero = Literal((double) 0);
- litOne = Literal((double) 1);
- u32Max = Literal(((double) UINT_MAX) + 1);
+ litZero = Literal((double)0);
+ litOne = Literal((double)1);
+ u32Max = Literal(((double)UINT_MAX) + 1);
trunc = TruncUFloat64ToInt32;
convert = ConvertUInt32ToFloat64;
localType = f64;
@@ -618,74 +581,63 @@ struct I64ToI32Lowering : public WalkerPass<PostWalker<I64ToI32Lowering>> {
sub = SubFloat64;
break;
}
- default: abort();
+ default:
+ abort();
}
TempVar f = getTemp(localType);
TempVar highBits = getTemp();
- Expression *gtZeroBranch = builder->makeBinary(
- min,
- builder->makeUnary(
- floor,
- builder->makeBinary(
- div,
- builder->makeGetLocal(f, localType),
- builder->makeConst(u32Max)
- )
- ),
- builder->makeBinary(sub, builder->makeConst(u32Max), builder->makeConst(litOne))
- );
- Expression *ltZeroBranch = builder->makeUnary(
- ceil,
+ Expression* gtZeroBranch = builder->makeBinary(
+ min,
+ builder->makeUnary(
+ floor,
+ builder->makeBinary(div,
+ builder->makeGetLocal(f, localType),
+ builder->makeConst(u32Max))),
+ builder->makeBinary(
+ sub, builder->makeConst(u32Max), builder->makeConst(litOne)));
+ Expression* ltZeroBranch = builder->makeUnary(
+ ceil,
+ builder->makeBinary(
+ div,
builder->makeBinary(
- div,
- builder->makeBinary(
- sub,
- builder->makeGetLocal(f, localType),
- builder->makeUnary(convert,
- builder->makeUnary(trunc, builder->makeGetLocal(f, localType))
- )
- ),
- builder->makeConst(u32Max)
- )
- );
-
- If *highBitsCalc = builder->makeIf(
+ sub,
+ builder->makeGetLocal(f, localType),
+ builder->makeUnary(
+ convert,
+ builder->makeUnary(trunc, builder->makeGetLocal(f, localType)))),
+ builder->makeConst(u32Max)));
+
+ If* highBitsCalc = builder->makeIf(
builder->makeBinary(
- gt,
- builder-> makeGetLocal(f, localType),
- builder->makeConst(litZero)
- ),
+ gt, builder->makeGetLocal(f, localType), builder->makeConst(litZero)),
builder->makeUnary(trunc, gtZeroBranch),
- builder->makeUnary(trunc, ltZeroBranch)
- );
- If *highBitsVal = builder->makeIf(
+ builder->makeUnary(trunc, ltZeroBranch));
+ If* highBitsVal = builder->makeIf(
builder->makeBinary(
ge,
builder->makeUnary(abs, builder->makeGetLocal(f, localType)),
- builder->makeConst(litOne)
- ),
+ builder->makeConst(litOne)),
highBitsCalc,
- builder->makeConst(Literal(int32_t(0)))
- );
- Block *result = builder->blockify(
+ builder->makeConst(Literal(int32_t(0))));
+ Block* result = builder->blockify(
builder->makeSetLocal(f, curr->value),
builder->makeSetLocal(highBits, highBitsVal),
- builder->makeUnary(trunc, builder->makeGetLocal(f, localType))
- );
+ builder->makeUnary(trunc, builder->makeGetLocal(f, localType)));
setOutParam(result, std::move(highBits));
replaceCurrent(result);
}
- void lowerConvertIntToFloat(Unary *curr) {
+ void lowerConvertIntToFloat(Unary* curr) {
// Here the same strategy as `emcc` is taken which takes the two halves of
// the 64-bit integer and creates a mathematical expression using float
// arithmetic to reassemble the final floating point value.
//
// For example for i64 -> f32 we generate:
//
- // ((double) (unsigned) lowBits) + ((double) U32_MAX) * ((double) (int) highBits)
+ // ((double) (unsigned) lowBits) +
+ // ((double) U32_MAX) * ((double) (int) highBits)
//
// Mostly just shuffling things around here with coercions and whatnot!
// Note though that all arithmetic is done with f64 to have as much
@@ -704,31 +656,23 @@ struct I64ToI32Lowering : public WalkerPass<PostWalker<I64ToI32Lowering>> {
case ConvertUInt64ToFloat64:
convertHigh = ConvertUInt32ToFloat64;
break;
- default: abort();
+ default:
+ abort();
}
- Expression *result = builder->blockify(
+ Expression* result = builder->blockify(
builder->makeSetLocal(lowBits, curr->value),
- builder->makeSetLocal(
- highResult,
- builder->makeConst(Literal(int32_t(0)))
- ),
+ builder->makeSetLocal(highResult,
+ builder->makeConst(Literal(int32_t(0)))),
builder->makeBinary(
AddFloat64,
- builder->makeUnary(
- ConvertUInt32ToFloat64,
- builder->makeGetLocal(lowBits, i32)
- ),
+ builder->makeUnary(ConvertUInt32ToFloat64,
+ builder->makeGetLocal(lowBits, i32)),
builder->makeBinary(
MulFloat64,
builder->makeConst(Literal((double)UINT_MAX + 1)),
- builder->makeUnary(
- convertHigh,
- builder->makeGetLocal(highBits, i32)
- )
- )
- )
- );
+ builder->makeUnary(convertHigh,
+ builder->makeGetLocal(highBits, i32)))));
switch (curr->op) {
case ConvertSInt64ToFloat32:
@@ -736,52 +680,43 @@ struct I64ToI32Lowering : public WalkerPass<PostWalker<I64ToI32Lowering>> {
result = builder->makeUnary(DemoteFloat64, result);
break;
}
- default: break;
+ default:
+ break;
}
replaceCurrent(result);
}
void lowerCountZeros(Unary* curr) {
- auto lower = [&](Block* result, UnaryOp op32, TempVar&& first, TempVar&& second) {
+ auto lower = [&](Block* result,
+ UnaryOp op32,
+ TempVar&& first,
+ TempVar&& second) {
TempVar highResult = getTemp();
TempVar firstResult = getTemp();
SetLocal* setFirst = builder->makeSetLocal(
firstResult,
- builder->makeUnary(op32, builder->makeGetLocal(first, i32))
- );
+ builder->makeUnary(op32, builder->makeGetLocal(first, i32)));
- Binary* check = builder->makeBinary(
- EqInt32,
- builder->makeGetLocal(firstResult, i32),
- builder->makeConst(Literal(int32_t(32)))
- );
+ Binary* check =
+ builder->makeBinary(EqInt32,
+ builder->makeGetLocal(firstResult, i32),
+ builder->makeConst(Literal(int32_t(32))));
If* conditional = builder->makeIf(
check,
builder->makeBinary(
AddInt32,
builder->makeUnary(op32, builder->makeGetLocal(second, i32)),
- builder->makeConst(Literal(int32_t(32)))
- ),
- builder->makeGetLocal(firstResult, i32)
- );
+ builder->makeConst(Literal(int32_t(32)))),
+ builder->makeGetLocal(firstResult, i32));
SetLocal* setHigh = builder->makeSetLocal(
- highResult,
- builder->makeConst(Literal(int32_t(0)))
- );
+ highResult, builder->makeConst(Literal(int32_t(0))));
setOutParam(result, std::move(highResult));
- replaceCurrent(
- builder->blockify(
- result,
- setFirst,
- setHigh,
- conditional
- )
- );
+ replaceCurrent(builder->blockify(result, setFirst, setHigh, conditional));
};
TempVar highBits = fetchOutParam(curr->value);
@@ -820,32 +755,54 @@ struct I64ToI32Lowering : public WalkerPass<PostWalker<I64ToI32Lowering>> {
case ConvertSInt64ToFloat64:
case ConvertUInt64ToFloat32:
case ConvertUInt64ToFloat64:
- case ReinterpretInt64: return true;
- default: return false;
+ case ReinterpretInt64:
+ return true;
+ default:
+ return false;
}
}
void visitUnary(Unary* curr) {
- if (!unaryNeedsLowering(curr->op)) return;
- if (handleUnreachable(curr)) return;
+ if (!unaryNeedsLowering(curr->op))
+ return;
+ if (handleUnreachable(curr))
+ return;
assert(hasOutParam(curr->value) || curr->type == i64 || curr->type == f64);
switch (curr->op) {
case ClzInt64:
- case CtzInt64: lowerCountZeros(curr); break;
- case EqZInt64: lowerEqZInt64(curr); break;
- case ExtendSInt32: lowerExtendSInt32(curr); break;
- case ExtendUInt32: lowerExtendUInt32(curr); break;
- case WrapInt64: lowerWrapInt64(curr); break;
- case ReinterpretFloat64: lowerReinterpretFloat64(curr); break;
- case ReinterpretInt64: lowerReinterpretInt64(curr); break;
+ case CtzInt64:
+ lowerCountZeros(curr);
+ break;
+ case EqZInt64:
+ lowerEqZInt64(curr);
+ break;
+ case ExtendSInt32:
+ lowerExtendSInt32(curr);
+ break;
+ case ExtendUInt32:
+ lowerExtendUInt32(curr);
+ break;
+ case WrapInt64:
+ lowerWrapInt64(curr);
+ break;
+ case ReinterpretFloat64:
+ lowerReinterpretFloat64(curr);
+ break;
+ case ReinterpretInt64:
+ lowerReinterpretInt64(curr);
+ break;
case TruncSFloat32ToInt64:
case TruncUFloat32ToInt64:
case TruncSFloat64ToInt64:
- case TruncUFloat64ToInt64: lowerTruncFloatToInt(curr); break;
+ case TruncUFloat64ToInt64:
+ lowerTruncFloatToInt(curr);
+ break;
case ConvertSInt64ToFloat32:
case ConvertSInt64ToFloat64:
case ConvertUInt64ToFloat32:
- case ConvertUInt64ToFloat64: lowerConvertIntToFloat(curr); break;
+ case ConvertUInt64ToFloat64:
+ lowerConvertIntToFloat(curr);
+ break;
case PopcntInt64:
std::cerr << "i64.popcnt should already be removed" << std::endl;
WASM_UNREACHABLE();
@@ -855,117 +812,104 @@ struct I64ToI32Lowering : public WalkerPass<PostWalker<I64ToI32Lowering>> {
}
}
- Block* lowerAdd(Block* result, TempVar&& leftLow, TempVar&& leftHigh,
- TempVar&& rightLow, TempVar&& rightHigh) {
+ Block* lowerAdd(Block* result,
+ TempVar&& leftLow,
+ TempVar&& leftHigh,
+ TempVar&& rightLow,
+ TempVar&& rightHigh) {
TempVar lowResult = getTemp();
TempVar highResult = getTemp();
SetLocal* addLow = builder->makeSetLocal(
lowResult,
- builder->makeBinary(
- AddInt32,
- builder->makeGetLocal(leftLow, i32),
- builder->makeGetLocal(rightLow, i32)
- )
- );
+ builder->makeBinary(AddInt32,
+ builder->makeGetLocal(leftLow, i32),
+ builder->makeGetLocal(rightLow, i32)));
SetLocal* addHigh = builder->makeSetLocal(
highResult,
- builder->makeBinary(
- AddInt32,
- builder->makeGetLocal(leftHigh, i32),
- builder->makeGetLocal(rightHigh, i32)
- )
- );
+ builder->makeBinary(AddInt32,
+ builder->makeGetLocal(leftHigh, i32),
+ builder->makeGetLocal(rightHigh, i32)));
SetLocal* carryBit = builder->makeSetLocal(
highResult,
- builder->makeBinary(
- AddInt32,
- builder->makeGetLocal(highResult, i32),
- builder->makeConst(Literal(int32_t(1)))
- )
- );
- If* checkOverflow = builder->makeIf(
- builder->makeBinary(
- LtUInt32,
- builder->makeGetLocal(lowResult, i32),
- builder->makeGetLocal(rightLow, i32)
- ),
- carryBit
- );
+ builder->makeBinary(AddInt32,
+ builder->makeGetLocal(highResult, i32),
+ builder->makeConst(Literal(int32_t(1)))));
+ If* checkOverflow =
+ builder->makeIf(builder->makeBinary(LtUInt32,
+ builder->makeGetLocal(lowResult, i32),
+ builder->makeGetLocal(rightLow, i32)),
+ carryBit);
GetLocal* getLow = builder->makeGetLocal(lowResult, i32);
result = builder->blockify(result, addLow, addHigh, checkOverflow, getLow);
setOutParam(result, std::move(highResult));
return result;
}
- Block* lowerSub(Block* result, TempVar&& leftLow, TempVar&& leftHigh,
- TempVar&& rightLow, TempVar&& rightHigh) {
+ Block* lowerSub(Block* result,
+ TempVar&& leftLow,
+ TempVar&& leftHigh,
+ TempVar&& rightLow,
+ TempVar&& rightHigh) {
TempVar lowResult = getTemp();
TempVar highResult = getTemp();
TempVar borrow = getTemp();
SetLocal* subLow = builder->makeSetLocal(
lowResult,
- builder->makeBinary(
- SubInt32,
- builder->makeGetLocal(leftLow, i32),
- builder->makeGetLocal(rightLow, i32)
- )
- );
+ builder->makeBinary(SubInt32,
+ builder->makeGetLocal(leftLow, i32),
+ builder->makeGetLocal(rightLow, i32)));
SetLocal* borrowBit = builder->makeSetLocal(
borrow,
- builder->makeBinary(
- LtUInt32,
- builder->makeGetLocal(leftLow, i32),
- builder->makeGetLocal(rightLow, i32)
- )
- );
+ builder->makeBinary(LtUInt32,
+ builder->makeGetLocal(leftLow, i32),
+ builder->makeGetLocal(rightLow, i32)));
SetLocal* subHigh1 = builder->makeSetLocal(
highResult,
- builder->makeBinary(
- AddInt32,
- builder->makeGetLocal(borrow, i32),
- builder->makeGetLocal(rightHigh, i32)
- )
- );
+ builder->makeBinary(AddInt32,
+ builder->makeGetLocal(borrow, i32),
+ builder->makeGetLocal(rightHigh, i32)));
SetLocal* subHigh2 = builder->makeSetLocal(
highResult,
- builder->makeBinary(
- SubInt32,
- builder->makeGetLocal(leftHigh, i32),
- builder->makeGetLocal(highResult, i32)
- )
- );
+ builder->makeBinary(SubInt32,
+ builder->makeGetLocal(leftHigh, i32),
+ builder->makeGetLocal(highResult, i32)));
GetLocal* getLow = builder->makeGetLocal(lowResult, i32);
- result = builder->blockify(result, subLow, borrowBit, subHigh1, subHigh2, getLow);
+ result =
+ builder->blockify(result, subLow, borrowBit, subHigh1, subHigh2, getLow);
setOutParam(result, std::move(highResult));
return result;
}
- Block* lowerBitwise(BinaryOp op, Block* result, TempVar&& leftLow,
- TempVar&& leftHigh, TempVar&& rightLow,
+ Block* lowerBitwise(BinaryOp op,
+ Block* result,
+ TempVar&& leftLow,
+ TempVar&& leftHigh,
+ TempVar&& rightLow,
TempVar&& rightHigh) {
BinaryOp op32;
switch (op) {
- case AndInt64: op32 = AndInt32; break;
- case OrInt64: op32 = OrInt32; break;
- case XorInt64: op32 = XorInt32; break;
- default: abort();
+ case AndInt64:
+ op32 = AndInt32;
+ break;
+ case OrInt64:
+ op32 = OrInt32;
+ break;
+ case XorInt64:
+ op32 = XorInt32;
+ break;
+ default:
+ abort();
}
result = builder->blockify(
result,
builder->makeSetLocal(
rightHigh,
- builder->makeBinary(
- op32,
- builder->makeGetLocal(leftHigh, i32),
- builder->makeGetLocal(rightHigh, i32)
- )
- ),
- builder->makeBinary(
- op32,
- builder->makeGetLocal(leftLow, i32),
- builder->makeGetLocal(rightLow, i32)
- )
- );
+ builder->makeBinary(op32,
+ builder->makeGetLocal(leftHigh, i32),
+ builder->makeGetLocal(rightHigh, i32))),
+ builder->makeBinary(op32,
+ builder->makeGetLocal(leftLow, i32),
+ builder->makeGetLocal(rightLow, i32)));
setOutParam(result, std::move(rightHigh));
return result;
}
@@ -974,14 +918,10 @@ struct I64ToI32Lowering : public WalkerPass<PostWalker<I64ToI32Lowering>> {
return builder->blockify(
builder->makeSetLocal(
highBits,
- builder->makeBinary(
- ShlInt32,
- builder->makeGetLocal(leftLow, i32),
- builder->makeGetLocal(shift, i32)
- )
- ),
- builder->makeConst(Literal(int32_t(0)))
- );
+ builder->makeBinary(ShlInt32,
+ builder->makeGetLocal(leftLow, i32),
+ builder->makeGetLocal(shift, i32))),
+ builder->makeConst(Literal(int32_t(0))));
}
// a >> b where `b` >= 32
@@ -994,58 +934,43 @@ struct I64ToI32Lowering : public WalkerPass<PostWalker<I64ToI32Lowering>> {
return builder->blockify(
builder->makeSetLocal(
highBits,
- builder->makeBinary(
- ShrSInt32,
- builder->makeGetLocal(leftHigh, i32),
- builder->makeConst(Literal(int32_t(31)))
- )
- ),
- builder->makeBinary(
- ShrSInt32,
- builder->makeGetLocal(leftHigh, i32),
- builder->makeGetLocal(shift, i32)
- )
- );
+ builder->makeBinary(ShrSInt32,
+ builder->makeGetLocal(leftHigh, i32),
+ builder->makeConst(Literal(int32_t(31))))),
+ builder->makeBinary(ShrSInt32,
+ builder->makeGetLocal(leftHigh, i32),
+ builder->makeGetLocal(shift, i32)));
}
Block* makeLargeShrU(Index highBits, Index leftHigh, Index shift) {
return builder->blockify(
builder->makeSetLocal(highBits, builder->makeConst(Literal(int32_t(0)))),
- builder->makeBinary(
- ShrUInt32,
- builder->makeGetLocal(leftHigh, i32),
- builder->makeGetLocal(shift, i32)
- )
- );
+ builder->makeBinary(ShrUInt32,
+ builder->makeGetLocal(leftHigh, i32),
+ builder->makeGetLocal(shift, i32)));
}
- Block* makeSmallShl(Index highBits, Index leftLow, Index leftHigh,
- Index shift, Binary* shiftMask, Binary* widthLessShift) {
+ Block* makeSmallShl(Index highBits,
+ Index leftLow,
+ Index leftHigh,
+ Index shift,
+ Binary* shiftMask,
+ Binary* widthLessShift) {
Binary* shiftedInBits = builder->makeBinary(
AndInt32,
shiftMask,
builder->makeBinary(
- ShrUInt32,
- builder->makeGetLocal(leftLow, i32),
- widthLessShift
- )
- );
- Binary* shiftHigh = builder->makeBinary(
- ShlInt32,
- builder->makeGetLocal(leftHigh, i32),
- builder->makeGetLocal(shift, i32)
- );
+ ShrUInt32, builder->makeGetLocal(leftLow, i32), widthLessShift));
+ Binary* shiftHigh =
+ builder->makeBinary(ShlInt32,
+ builder->makeGetLocal(leftHigh, i32),
+ builder->makeGetLocal(shift, i32));
return builder->blockify(
builder->makeSetLocal(
- highBits,
- builder->makeBinary(OrInt32, shiftedInBits, shiftHigh)
- ),
- builder->makeBinary(
- ShlInt32,
- builder->makeGetLocal(leftLow, i32),
- builder->makeGetLocal(shift, i32)
- )
- );
+ highBits, builder->makeBinary(OrInt32, shiftedInBits, shiftHigh)),
+ builder->makeBinary(ShlInt32,
+ builder->makeGetLocal(leftLow, i32),
+ builder->makeGetLocal(shift, i32)));
}
// a >> b where `b` < 32
@@ -1054,66 +979,58 @@ struct I64ToI32Lowering : public WalkerPass<PostWalker<I64ToI32Lowering>> {
//
// hi = leftHigh >> b
// lo = (leftLow >>> b) | (leftHigh << (32 - b))
- Block* makeSmallShrS(Index highBits, Index leftLow, Index leftHigh,
- Index shift, Binary* shiftMask, Binary* widthLessShift) {
+ Block* makeSmallShrS(Index highBits,
+ Index leftLow,
+ Index leftHigh,
+ Index shift,
+ Binary* shiftMask,
+ Binary* widthLessShift) {
Binary* shiftedInBits = builder->makeBinary(
ShlInt32,
builder->makeBinary(
- AndInt32,
- shiftMask,
- builder->makeGetLocal(leftHigh, i32)
- ),
- widthLessShift
- );
- Binary* shiftLow = builder->makeBinary(
- ShrUInt32,
- builder->makeGetLocal(leftLow, i32),
- builder->makeGetLocal(shift, i32)
- );
+ AndInt32, shiftMask, builder->makeGetLocal(leftHigh, i32)),
+ widthLessShift);
+ Binary* shiftLow = builder->makeBinary(ShrUInt32,
+ builder->makeGetLocal(leftLow, i32),
+ builder->makeGetLocal(shift, i32));
return builder->blockify(
builder->makeSetLocal(
highBits,
- builder->makeBinary(
- ShrSInt32,
- builder->makeGetLocal(leftHigh, i32),
- builder->makeGetLocal(shift, i32)
- )
- ),
- builder->makeBinary(OrInt32, shiftedInBits, shiftLow)
- );
+ builder->makeBinary(ShrSInt32,
+ builder->makeGetLocal(leftHigh, i32),
+ builder->makeGetLocal(shift, i32))),
+ builder->makeBinary(OrInt32, shiftedInBits, shiftLow));
}
- Block* makeSmallShrU(Index highBits, Index leftLow, Index leftHigh,
- Index shift, Binary* shiftMask, Binary* widthLessShift) {
+ Block* makeSmallShrU(Index highBits,
+ Index leftLow,
+ Index leftHigh,
+ Index shift,
+ Binary* shiftMask,
+ Binary* widthLessShift) {
Binary* shiftedInBits = builder->makeBinary(
ShlInt32,
builder->makeBinary(
- AndInt32,
- shiftMask,
- builder->makeGetLocal(leftHigh, i32)
- ),
- widthLessShift
- );
- Binary* shiftLow = builder->makeBinary(
- ShrUInt32,
- builder->makeGetLocal(leftLow, i32),
- builder->makeGetLocal(shift, i32)
- );
+ AndInt32, shiftMask, builder->makeGetLocal(leftHigh, i32)),
+ widthLessShift);
+ Binary* shiftLow = builder->makeBinary(ShrUInt32,
+ builder->makeGetLocal(leftLow, i32),
+ builder->makeGetLocal(shift, i32));
return builder->blockify(
builder->makeSetLocal(
highBits,
- builder->makeBinary(
- ShrUInt32,
- builder->makeGetLocal(leftHigh, i32),
- builder->makeGetLocal(shift, i32)
- )
- ),
- builder->makeBinary(OrInt32, shiftedInBits, shiftLow)
- );
+ builder->makeBinary(ShrUInt32,
+ builder->makeGetLocal(leftHigh, i32),
+ builder->makeGetLocal(shift, i32))),
+ builder->makeBinary(OrInt32, shiftedInBits, shiftLow));
}
- Block* lowerShift(BinaryOp op, Block* result, TempVar&& leftLow,
- TempVar&& leftHigh, TempVar&& rightLow, TempVar&& rightHigh) {
+ Block* lowerShift(BinaryOp op,
+ Block* result,
+ TempVar&& leftLow,
+ TempVar&& leftHigh,
+ TempVar&& rightLow,
+ TempVar&& rightHigh) {
assert(op == ShlInt64 || op == ShrUInt64 || op == ShrSInt64);
// shift left lowered as:
// if 32 <= rightLow % 64:
@@ -1125,191 +1042,192 @@ struct I64ToI32Lowering : public WalkerPass<PostWalker<I64ToI32Lowering>> {
TempVar shift = getTemp();
SetLocal* setShift = builder->makeSetLocal(
shift,
- builder->makeBinary(
- AndInt32,
- builder->makeGetLocal(rightLow, i32),
- builder->makeConst(Literal(int32_t(32 - 1)))
- )
- );
+ builder->makeBinary(AndInt32,
+ builder->makeGetLocal(rightLow, i32),
+ builder->makeConst(Literal(int32_t(32 - 1)))));
Binary* isLargeShift = builder->makeBinary(
LeUInt32,
builder->makeConst(Literal(int32_t(32))),
- builder->makeBinary(
- AndInt32,
- builder->makeGetLocal(rightLow, i32),
- builder->makeConst(Literal(int32_t(64 - 1)))
- )
- );
+ builder->makeBinary(AndInt32,
+ builder->makeGetLocal(rightLow, i32),
+ builder->makeConst(Literal(int32_t(64 - 1)))));
Block* largeShiftBlock;
switch (op) {
case ShlInt64:
- largeShiftBlock = makeLargeShl(rightHigh, leftLow, shift); break;
+ largeShiftBlock = makeLargeShl(rightHigh, leftLow, shift);
+ break;
case ShrSInt64:
- largeShiftBlock = makeLargeShrS(rightHigh, leftHigh, shift); break;
+ largeShiftBlock = makeLargeShrS(rightHigh, leftHigh, shift);
+ break;
case ShrUInt64:
- largeShiftBlock = makeLargeShrU(rightHigh, leftHigh, shift); break;
- default: abort();
+ largeShiftBlock = makeLargeShrU(rightHigh, leftHigh, shift);
+ break;
+ default:
+ abort();
}
Binary* shiftMask = builder->makeBinary(
SubInt32,
- builder->makeBinary(
- ShlInt32,
- builder->makeConst(Literal(int32_t(1))),
- builder->makeGetLocal(shift, i32)
- ),
- builder->makeConst(Literal(int32_t(1)))
- );
- Binary* widthLessShift = builder->makeBinary(
- SubInt32,
- builder->makeConst(Literal(int32_t(32))),
- builder->makeGetLocal(shift, i32)
- );
+ builder->makeBinary(ShlInt32,
+ builder->makeConst(Literal(int32_t(1))),
+ builder->makeGetLocal(shift, i32)),
+ builder->makeConst(Literal(int32_t(1))));
+ Binary* widthLessShift =
+ builder->makeBinary(SubInt32,
+ builder->makeConst(Literal(int32_t(32))),
+ builder->makeGetLocal(shift, i32));
Block* smallShiftBlock;
- switch(op) {
+ switch (op) {
case ShlInt64: {
- smallShiftBlock = makeSmallShl(rightHigh, leftLow, leftHigh,
- shift, shiftMask, widthLessShift);
+ smallShiftBlock = makeSmallShl(
+ rightHigh, leftLow, leftHigh, shift, shiftMask, widthLessShift);
break;
}
case ShrSInt64: {
- smallShiftBlock = makeSmallShrS(rightHigh, leftLow, leftHigh,
- shift, shiftMask, widthLessShift);
+ smallShiftBlock = makeSmallShrS(
+ rightHigh, leftLow, leftHigh, shift, shiftMask, widthLessShift);
break;
}
case ShrUInt64: {
- smallShiftBlock = makeSmallShrU(rightHigh, leftLow, leftHigh,
- shift, shiftMask, widthLessShift);
+ smallShiftBlock = makeSmallShrU(
+ rightHigh, leftLow, leftHigh, shift, shiftMask, widthLessShift);
break;
}
- default: abort();
+ default:
+ abort();
}
- If* ifLargeShift = builder->makeIf(
- isLargeShift,
- largeShiftBlock,
- smallShiftBlock
- );
+ If* ifLargeShift =
+ builder->makeIf(isLargeShift, largeShiftBlock, smallShiftBlock);
result = builder->blockify(result, setShift, ifLargeShift);
setOutParam(result, std::move(rightHigh));
return result;
}
- Block* lowerEq(Block* result, TempVar&& leftLow, TempVar&& leftHigh,
- TempVar&& rightLow, TempVar&& rightHigh) {
+ Block* lowerEq(Block* result,
+ TempVar&& leftLow,
+ TempVar&& leftHigh,
+ TempVar&& rightLow,
+ TempVar&& rightHigh) {
return builder->blockify(
result,
builder->makeBinary(
AndInt32,
- builder->makeBinary(
- EqInt32,
- builder->makeGetLocal(leftLow, i32),
- builder->makeGetLocal(rightLow, i32)
- ),
- builder->makeBinary(
- EqInt32,
- builder->makeGetLocal(leftHigh, i32),
- builder->makeGetLocal(rightHigh, i32)
- )
- )
- );
+ builder->makeBinary(EqInt32,
+ builder->makeGetLocal(leftLow, i32),
+ builder->makeGetLocal(rightLow, i32)),
+ builder->makeBinary(EqInt32,
+ builder->makeGetLocal(leftHigh, i32),
+ builder->makeGetLocal(rightHigh, i32))));
}
- Block* lowerNe(Block* result, TempVar&& leftLow, TempVar&& leftHigh,
- TempVar&& rightLow, TempVar&& rightHigh) {
+ Block* lowerNe(Block* result,
+ TempVar&& leftLow,
+ TempVar&& leftHigh,
+ TempVar&& rightLow,
+ TempVar&& rightHigh) {
return builder->blockify(
result,
builder->makeBinary(
OrInt32,
- builder->makeBinary(
- NeInt32,
- builder->makeGetLocal(leftLow, i32),
- builder->makeGetLocal(rightLow, i32)
- ),
- builder->makeBinary(
- NeInt32,
- builder->makeGetLocal(leftHigh, i32),
- builder->makeGetLocal(rightHigh, i32)
- )
- )
- );
+ builder->makeBinary(NeInt32,
+ builder->makeGetLocal(leftLow, i32),
+ builder->makeGetLocal(rightLow, i32)),
+ builder->makeBinary(NeInt32,
+ builder->makeGetLocal(leftHigh, i32),
+ builder->makeGetLocal(rightHigh, i32))));
}
- Block* lowerUComp(BinaryOp op, Block* result, TempVar&& leftLow,
- TempVar&& leftHigh, TempVar&& rightLow,
+ Block* lowerUComp(BinaryOp op,
+ Block* result,
+ TempVar&& leftLow,
+ TempVar&& leftHigh,
+ TempVar&& rightLow,
TempVar&& rightHigh) {
BinaryOp highOp, lowOp;
switch (op) {
- case LtUInt64: highOp = LtUInt32; lowOp = LtUInt32; break;
- case LeUInt64: highOp = LtUInt32; lowOp = LeUInt32; break;
- case GtUInt64: highOp = GtUInt32; lowOp = GtUInt32; break;
- case GeUInt64: highOp = GtUInt32; lowOp = GeUInt32; break;
- default: abort();
+ case LtUInt64:
+ highOp = LtUInt32;
+ lowOp = LtUInt32;
+ break;
+ case LeUInt64:
+ highOp = LtUInt32;
+ lowOp = LeUInt32;
+ break;
+ case GtUInt64:
+ highOp = GtUInt32;
+ lowOp = GtUInt32;
+ break;
+ case GeUInt64:
+ highOp = GtUInt32;
+ lowOp = GeUInt32;
+ break;
+ default:
+ abort();
}
- Binary* compHigh = builder->makeBinary(
- highOp,
- builder->makeGetLocal(leftHigh, i32),
- builder->makeGetLocal(rightHigh, i32)
- );
- Binary* eqHigh = builder->makeBinary(
- EqInt32,
- builder->makeGetLocal(leftHigh, i32),
- builder->makeGetLocal(rightHigh, i32)
- );
- Binary* compLow = builder->makeBinary(
- lowOp,
- builder->makeGetLocal(leftLow, i32),
- builder->makeGetLocal(rightLow, i32)
- );
+ Binary* compHigh =
+ builder->makeBinary(highOp,
+ builder->makeGetLocal(leftHigh, i32),
+ builder->makeGetLocal(rightHigh, i32));
+ Binary* eqHigh = builder->makeBinary(EqInt32,
+ builder->makeGetLocal(leftHigh, i32),
+ builder->makeGetLocal(rightHigh, i32));
+ Binary* compLow = builder->makeBinary(lowOp,
+ builder->makeGetLocal(leftLow, i32),
+ builder->makeGetLocal(rightLow, i32));
return builder->blockify(
result,
builder->makeBinary(
- OrInt32,
- compHigh,
- builder->makeBinary(AndInt32, eqHigh, compLow)
- )
- );
+ OrInt32, compHigh, builder->makeBinary(AndInt32, eqHigh, compLow)));
}
- Block* lowerSComp(BinaryOp op, Block* result, TempVar&& leftLow,
- TempVar&& leftHigh, TempVar&& rightLow,
- TempVar&& rightHigh) {
+ Block* lowerSComp(BinaryOp op,
+ Block* result,
+ TempVar&& leftLow,
+ TempVar&& leftHigh,
+ TempVar&& rightLow,
+ TempVar&& rightHigh) {
BinaryOp highOp1, highOp2, lowOp;
switch (op) {
- case LtSInt64: highOp1 = LtSInt32; highOp2 = LeSInt32; lowOp = GeUInt32; break;
- case LeSInt64: highOp1 = LtSInt32; highOp2 = LeSInt32; lowOp = GtUInt32; break;
- case GtSInt64: highOp1 = GtSInt32; highOp2 = GeSInt32; lowOp = LeUInt32; break;
- case GeSInt64: highOp1 = GtSInt32; highOp2 = GeSInt32; lowOp = LtUInt32; break;
- default: abort();
+ case LtSInt64:
+ highOp1 = LtSInt32;
+ highOp2 = LeSInt32;
+ lowOp = GeUInt32;
+ break;
+ case LeSInt64:
+ highOp1 = LtSInt32;
+ highOp2 = LeSInt32;
+ lowOp = GtUInt32;
+ break;
+ case GtSInt64:
+ highOp1 = GtSInt32;
+ highOp2 = GeSInt32;
+ lowOp = LeUInt32;
+ break;
+ case GeSInt64:
+ highOp1 = GtSInt32;
+ highOp2 = GeSInt32;
+ lowOp = LtUInt32;
+ break;
+ default:
+ abort();
}
- Binary* compHigh1 = builder->makeBinary(
- highOp1,
- builder->makeGetLocal(leftHigh, i32),
- builder->makeGetLocal(rightHigh, i32)
- );
- Binary* compHigh2 = builder->makeBinary(
- highOp2,
- builder->makeGetLocal(leftHigh, i32),
- builder->makeGetLocal(rightHigh, i32)
- );
- Binary* compLow = builder->makeBinary(
- lowOp,
- builder->makeGetLocal(leftLow, i32),
- builder->makeGetLocal(rightLow, i32)
- );
- If* lowIf = builder->makeIf(
- compLow,
- builder->makeConst(Literal(int32_t(0))),
- builder->makeConst(Literal(int32_t(1)))
- );
+ Binary* compHigh1 =
+ builder->makeBinary(highOp1,
+ builder->makeGetLocal(leftHigh, i32),
+ builder->makeGetLocal(rightHigh, i32));
+ Binary* compHigh2 =
+ builder->makeBinary(highOp2,
+ builder->makeGetLocal(leftHigh, i32),
+ builder->makeGetLocal(rightHigh, i32));
+ Binary* compLow = builder->makeBinary(lowOp,
+ builder->makeGetLocal(leftLow, i32),
+ builder->makeGetLocal(rightLow, i32));
+ If* lowIf = builder->makeIf(compLow,
+ builder->makeConst(Literal(int32_t(0))),
+ builder->makeConst(Literal(int32_t(1))));
If* highIf2 = builder->makeIf(
- compHigh2,
- lowIf,
- builder->makeConst(Literal(int32_t(0)))
- );
+ compHigh2, lowIf, builder->makeConst(Literal(int32_t(0))));
If* highIf1 = builder->makeIf(
- compHigh1,
- builder->makeConst(Literal(int32_t(1))),
- highIf2
- );
+ compHigh1, builder->makeConst(Literal(int32_t(1))), highIf2);
return builder->blockify(result, highIf1);
}
@@ -1339,14 +1257,18 @@ struct I64ToI32Lowering : public WalkerPass<PostWalker<I64ToI32Lowering>> {
case GtSInt64:
case GtUInt64:
case GeSInt64:
- case GeUInt64: return true;
- default: return false;
+ case GeUInt64:
+ return true;
+ default:
+ return false;
}
}
void visitBinary(Binary* curr) {
- if (handleUnreachable(curr)) return;
- if (!binaryNeedsLowering(curr->op)) return;
+ if (handleUnreachable(curr))
+ return;
+ if (!binaryNeedsLowering(curr->op))
+ return;
// left and right reachable, lower normally
TempVar leftLow = getTemp();
TempVar leftHigh = fetchOutParam(curr->left);
@@ -1357,15 +1279,19 @@ struct I64ToI32Lowering : public WalkerPass<PostWalker<I64ToI32Lowering>> {
Block* result = builder->blockify(setLeft, setRight);
switch (curr->op) {
case AddInt64: {
- replaceCurrent(
- lowerAdd(result, std::move(leftLow), std::move(leftHigh),
- std::move(rightLow), std::move(rightHigh)));
+ replaceCurrent(lowerAdd(result,
+ std::move(leftLow),
+ std::move(leftHigh),
+ std::move(rightLow),
+ std::move(rightHigh)));
break;
}
case SubInt64: {
- replaceCurrent(
- lowerSub(result, std::move(leftLow), std::move(leftHigh),
- std::move(rightLow), std::move(rightHigh)));
+ replaceCurrent(lowerSub(result,
+ std::move(leftLow),
+ std::move(leftHigh),
+ std::move(rightLow),
+ std::move(rightHigh)));
break;
}
case MulInt64:
@@ -1375,59 +1301,69 @@ struct I64ToI32Lowering : public WalkerPass<PostWalker<I64ToI32Lowering>> {
case RemUInt64:
case RotLInt64:
case RotRInt64:
- std::cerr << "should have been removed by now " << curr->op << std::endl;
+ std::cerr << "should have been removed by now " << curr->op
+ << std::endl;
WASM_UNREACHABLE();
case AndInt64:
case OrInt64:
case XorInt64: {
- replaceCurrent(
- lowerBitwise(curr->op, result, std::move(leftLow),
- std::move(leftHigh), std::move(rightLow),
- std::move(rightHigh))
- );
+ replaceCurrent(lowerBitwise(curr->op,
+ result,
+ std::move(leftLow),
+ std::move(leftHigh),
+ std::move(rightLow),
+ std::move(rightHigh)));
break;
}
case ShlInt64:
case ShrSInt64:
case ShrUInt64: {
- replaceCurrent(
- lowerShift(curr->op, result, std::move(leftLow), std::move(leftHigh),
- std::move(rightLow), std::move(rightHigh))
- );
+ replaceCurrent(lowerShift(curr->op,
+ result,
+ std::move(leftLow),
+ std::move(leftHigh),
+ std::move(rightLow),
+ std::move(rightHigh)));
break;
}
case EqInt64: {
- replaceCurrent(
- lowerEq(result, std::move(leftLow), std::move(leftHigh),
- std::move(rightLow), std::move(rightHigh))
- );
+ replaceCurrent(lowerEq(result,
+ std::move(leftLow),
+ std::move(leftHigh),
+ std::move(rightLow),
+ std::move(rightHigh)));
break;
}
case NeInt64: {
- replaceCurrent(
- lowerNe(result, std::move(leftLow), std::move(leftHigh),
- std::move(rightLow), std::move(rightHigh))
- );
+ replaceCurrent(lowerNe(result,
+ std::move(leftLow),
+ std::move(leftHigh),
+ std::move(rightLow),
+ std::move(rightHigh)));
break;
}
case LtSInt64:
case LeSInt64:
case GtSInt64:
case GeSInt64:
- replaceCurrent(
- lowerSComp(curr->op, result, std::move(leftLow), std::move(leftHigh),
- std::move(rightLow), std::move(rightHigh))
- );
- break;
+ replaceCurrent(lowerSComp(curr->op,
+ result,
+ std::move(leftLow),
+ std::move(leftHigh),
+ std::move(rightLow),
+ std::move(rightHigh)));
+ break;
case LtUInt64:
case LeUInt64:
case GtUInt64:
case GeUInt64: {
- replaceCurrent(
- lowerUComp(curr->op, result, std::move(leftLow), std::move(leftHigh),
- std::move(rightLow), std::move(rightHigh))
- );
+ replaceCurrent(lowerUComp(curr->op,
+ result,
+ std::move(leftLow),
+ std::move(leftHigh),
+ std::move(rightLow),
+ std::move(rightHigh)));
break;
}
default: {
@@ -1438,7 +1374,8 @@ struct I64ToI32Lowering : public WalkerPass<PostWalker<I64ToI32Lowering>> {
}
void visitSelect(Select* curr) {
- if (handleUnreachable(curr)) return;
+ if (handleUnreachable(curr))
+ return;
if (!hasOutParam(curr->ifTrue)) {
assert(!hasOutParam(curr->ifFalse));
return;
@@ -1452,40 +1389,33 @@ struct I64ToI32Lowering : public WalkerPass<PostWalker<I64ToI32Lowering>> {
builder->makeSetLocal(
lowBits,
builder->makeSelect(
- builder->makeGetLocal(cond, i32),
- curr->ifTrue,
- curr->ifFalse
- )
- ),
+ builder->makeGetLocal(cond, i32), curr->ifTrue, curr->ifFalse)),
builder->makeSetLocal(
highBits,
builder->makeSelect(
builder->makeGetLocal(cond, i32),
builder->makeGetLocal(fetchOutParam(curr->ifTrue), i32),
- builder->makeGetLocal(fetchOutParam(curr->ifFalse), i32)
- )
- ),
- builder->makeGetLocal(lowBits, i32)
- );
+ builder->makeGetLocal(fetchOutParam(curr->ifFalse), i32))),
+ builder->makeGetLocal(lowBits, i32));
setOutParam(result, std::move(highBits));
replaceCurrent(result);
}
void visitDrop(Drop* curr) {
- if (!hasOutParam(curr->value)) return;
+ if (!hasOutParam(curr->value))
+ return;
// free temp var
fetchOutParam(curr->value);
}
void visitReturn(Return* curr) {
- if (!hasOutParam(curr->value)) return;
+ if (!hasOutParam(curr->value))
+ return;
TempVar lowBits = getTemp();
TempVar highBits = fetchOutParam(curr->value);
SetLocal* setLow = builder->makeSetLocal(lowBits, curr->value);
SetGlobal* setHigh = builder->makeSetGlobal(
- INT64_TO_32_HIGH_BITS,
- builder->makeGetLocal(highBits, i32)
- );
+ INT64_TO_32_HIGH_BITS, builder->makeGetLocal(highBits, i32));
curr->value = builder->makeGetLocal(lowBits, i32);
Block* result = builder->blockify(setLow, setHigh, curr);
replaceCurrent(result);
@@ -1502,7 +1432,7 @@ private:
TempVar getTemp(Type ty = i32) {
Index ret;
- auto &freeList = freeTemps[(int) ty];
+ auto& freeList = freeTemps[(int)ty];
if (freeList.size() > 0) {
ret = freeList.back();
freeList.pop_back();
@@ -1538,7 +1468,8 @@ private:
// unconditionally before themselves, so it is not valid for an if,
// in particular.
bool handleUnreachable(Expression* curr) {
- if (curr->type != unreachable) return false;
+ if (curr->type != unreachable)
+ return false;
std::vector<Expression*> children;
bool hasUnreachable = false;
for (auto* child : ChildIterator(curr)) {
@@ -1549,7 +1480,8 @@ private:
}
children.push_back(child);
}
- if (!hasUnreachable) return false;
+ if (!hasUnreachable)
+ return false;
// This has an unreachable child, so we can replace it with
// the children.
auto* block = builder->makeBlock(children);
@@ -1559,8 +1491,6 @@ private:
}
};
-Pass *createI64ToI32LoweringPass() {
- return new I64ToI32Lowering();
-}
+Pass* createI64ToI32LoweringPass() { return new I64ToI32Lowering(); }
-}
+} // namespace wasm
diff --git a/src/passes/Inlining.cpp b/src/passes/Inlining.cpp
index f801662e0..681109af8 100644
--- a/src/passes/Inlining.cpp
+++ b/src/passes/Inlining.cpp
@@ -32,14 +32,14 @@
#include <atomic>
-#include "wasm.h"
-#include "pass.h"
-#include "wasm-builder.h"
#include "ir/literal-utils.h"
#include "ir/module-utils.h"
#include "ir/utils.h"
#include "parsing.h"
+#include "pass.h"
#include "passes/opt-utils.h"
+#include "wasm-builder.h"
+#include "wasm.h"
namespace wasm {
@@ -79,25 +79,30 @@ struct FunctionInfo {
bool worthInlining(PassOptions& options) {
// if it's big, it's just not worth doing (TODO: investigate more)
- if (size > FLEXIBLE_SIZE_LIMIT) return false;
+ if (size > FLEXIBLE_SIZE_LIMIT)
+ return false;
// if it's so small we have a guarantee that after we optimize the
// size will not increase, inline it
- if (size <= INLINING_OPTIMIZING_WILL_DECREASE_SIZE_LIMIT) return true;
+ if (size <= INLINING_OPTIMIZING_WILL_DECREASE_SIZE_LIMIT)
+ return true;
// if it has one use, then inlining it would likely reduce code size
// since we are just moving code around, + optimizing, so worth it
// if small enough that we are pretty sure its ok
- if (calls == 1 && !usedGlobally && size <= CAREFUL_SIZE_LIMIT) return true;
+ if (calls == 1 && !usedGlobally && size <= CAREFUL_SIZE_LIMIT)
+ return true;
// more than one use, so we can't eliminate it after inlining,
// so only worth it if we really care about speed and don't care
// about size, and if it's lightweight so a good candidate for
// speeding us up.
- return options.optimizeLevel >= 3 && options.shrinkLevel == 0 && lightweight;
+ return options.optimizeLevel >= 3 && options.shrinkLevel == 0 &&
+ lightweight;
}
};
typedef std::unordered_map<Name, FunctionInfo> NameInfoMap;
-struct FunctionInfoScanner : public WalkerPass<PostWalker<FunctionInfoScanner>> {
+struct FunctionInfoScanner
+ : public WalkerPass<PostWalker<FunctionInfoScanner>> {
bool isFunctionParallel() override { return true; }
FunctionInfoScanner(NameInfoMap* infos) : infos(infos) {}
@@ -112,7 +117,8 @@ struct FunctionInfoScanner : public WalkerPass<PostWalker<FunctionInfoScanner>>
}
void visitCall(Call* curr) {
- assert(infos->count(curr->target) > 0); // can't add a new element in parallel
+ // can't add a new element in parallel
+ assert(infos->count(curr->target) > 0);
(*infos)[curr->target].calls++;
// having a call is not lightweight
(*infos)[getFunction()->name].lightweight = false;
@@ -130,12 +136,14 @@ struct InliningAction {
Expression** callSite;
Function* contents;
- InliningAction(Expression** callSite, Function* contents) : callSite(callSite), contents(contents) {}
+ InliningAction(Expression** callSite, Function* contents)
+ : callSite(callSite), contents(contents) {}
};
struct InliningState {
std::unordered_set<Name> worthInlining;
- std::unordered_map<Name, std::vector<InliningAction>> actionsForFunction; // function name => actions that can be performed in it
+ // function name => actions that can be performed in it
+ std::unordered_map<Name, std::vector<InliningAction>> actionsForFunction;
};
struct Planner : public WalkerPass<PostWalker<Planner>> {
@@ -143,30 +151,27 @@ struct Planner : public WalkerPass<PostWalker<Planner>> {
Planner(InliningState* state) : state(state) {}
- Planner* create() override {
- return new Planner(state);
- }
+ Planner* create() override { return new Planner(state); }
void visitCall(Call* curr) {
// plan to inline if we know this is valid to inline, and if the call is
// actually performed - if it is dead code, it's pointless to inline.
// we also cannot inline ourselves.
- if (state->worthInlining.count(curr->target) &&
- curr->type != unreachable &&
+ if (state->worthInlining.count(curr->target) && curr->type != unreachable &&
curr->target != getFunction()->name) {
- // nest the call in a block. that way the location of the pointer to the call will not
- // change even if we inline multiple times into the same function, otherwise
- // call1(call2()) might be a problem
+ // nest the call in a block. that way the location of the pointer to the
+ // call will not change even if we inline multiple times into the same
+ // function, otherwise call1(call2()) might be a problem
auto* block = Builder(*getModule()).makeBlock(curr);
replaceCurrent(block);
- assert(state->actionsForFunction.count(getFunction()->name) > 0); // can't add a new element in parallel
- state->actionsForFunction[getFunction()->name].emplace_back(&block->list[0], getModule()->getFunction(curr->target));
+ // can't add a new element in parallel
+ assert(state->actionsForFunction.count(getFunction()->name) > 0);
+ state->actionsForFunction[getFunction()->name].emplace_back(
+ &block->list[0], getModule()->getFunction(curr->target));
}
}
- void doWalkFunction(Function* func) {
- walk(func->body);
- }
+ void doWalkFunction(Function* func) { walk(func->body); }
private:
InliningState* state;
@@ -174,7 +179,8 @@ private:
// Core inlining logic. Modifies the outside function (adding locals as
// needed), and returns the inlined code.
-static Expression* doInlining(Module* module, Function* into, InliningAction& action) {
+static Expression*
+doInlining(Module* module, Function* into, InliningAction& action) {
Function* from = action.contents;
auto* call = (*action.callSite)->cast<Call>();
Builder builder(*module);
@@ -204,11 +210,15 @@ static Expression* doInlining(Module* module, Function* into, InliningAction& ac
}
// assign the operands into the params
for (Index i = 0; i < from->params.size(); i++) {
- block->list.push_back(builder.makeSetLocal(updater.localMapping[i], call->operands[i]));
+ block->list.push_back(
+ builder.makeSetLocal(updater.localMapping[i], call->operands[i]));
}
- // zero out the vars (as we may be in a loop, and may depend on their zero-init value
+ // zero out the vars (as we may be in a loop, and may depend on their
+ // zero-init value
for (Index i = 0; i < from->vars.size(); i++) {
- block->list.push_back(builder.makeSetLocal(updater.localMapping[from->getVarIndexBase() + i], LiteralUtils::makeZero(from->vars[i], *module)));
+ block->list.push_back(
+ builder.makeSetLocal(updater.localMapping[from->getVarIndexBase() + i],
+ LiteralUtils::makeZero(from->vars[i], *module)));
}
// generate and update the inlined contents
auto* contents = ExpressionManipulator::copy(from->body, *module);
@@ -246,7 +256,8 @@ struct Inlining : public Pass {
// can look like it is worth inlining)
while (iterationNumber <= numFunctions) {
#ifdef INLINING_DEBUG
- std::cout << "inlining loop iter " << iterationNumber << " (numFunctions: " << numFunctions << ")\n";
+ std::cout << "inlining loop iter " << iterationNumber
+ << " (numFunctions: " << numFunctions << ")\n";
#endif
calculateInfos(module);
if (!iteration(runner, module)) {
@@ -258,7 +269,8 @@ struct Inlining : public Pass {
void calculateInfos(Module* module) {
infos.clear();
- // fill in info, as we operate on it in parallel (each function to its own entry)
+ // fill in info, as we operate on it in parallel (each function to its own
+ // entry)
for (auto& func : module->functions) {
infos[func->name];
}
@@ -288,8 +300,10 @@ struct Inlining : public Pass {
state.worthInlining.insert(func->name);
}
});
- if (state.worthInlining.size() == 0) return false;
- // fill in actionsForFunction, as we operate on it in parallel (each function to its own entry)
+ if (state.worthInlining.size() == 0)
+ return false;
+ // fill in actionsForFunction, as we operate on it in parallel (each
+ // function to its own entry)
for (auto& func : module->functions) {
state.actionsForFunction[func->name];
}
@@ -302,20 +316,23 @@ struct Inlining : public Pass {
}
// perform inlinings TODO: parallelize
std::unordered_map<Name, Index> inlinedUses; // how many uses we inlined
- std::unordered_set<Function*> inlinedInto; // which functions were inlined into
+ // which functions were inlined into
+ std::unordered_set<Function*> inlinedInto;
for (auto& func : module->functions) {
// if we've inlined a function, don't inline into it in this iteration,
// avoid risk of races
// note that we do not risk stalling progress, as each iteration() will
// inline at least one call before hitting this
- if (inlinedUses.count(func->name)) continue;
+ if (inlinedUses.count(func->name))
+ continue;
for (auto& action : state.actionsForFunction[func->name]) {
auto* inlinedFunction = action.contents;
// if we've inlined into a function, don't inline it in this iteration,
// avoid risk of races
// note that we do not risk stalling progress, as each iteration() will
// inline at least one call before hitting this
- if (inlinedInto.count(inlinedFunction)) continue;
+ if (inlinedInto.count(inlinedFunction))
+ continue;
Name inlinedName = inlinedFunction->name;
#ifdef INLINING_DEBUG
std::cout << "inline " << inlinedName << " into " << func->name << '\n';
@@ -335,23 +352,28 @@ struct Inlining : public Pass {
}
// remove functions that we no longer need after inlining
auto& funcs = module->functions;
- funcs.erase(std::remove_if(funcs.begin(), funcs.end(), [&](const std::unique_ptr<Function>& curr) {
- auto name = curr->name;
- auto& info = infos[name];
- bool canRemove = inlinedUses.count(name) && inlinedUses[name] == info.calls && !info.usedGlobally;
+ funcs.erase(std::remove_if(funcs.begin(),
+ funcs.end(),
+ [&](const std::unique_ptr<Function>& curr) {
+ auto name = curr->name;
+ auto& info = infos[name];
+ bool canRemove =
+ inlinedUses.count(name) &&
+ inlinedUses[name] == info.calls &&
+ !info.usedGlobally;
#ifdef INLINING_DEBUG
- if (canRemove) std::cout << "removing " << name << '\n';
+ if (canRemove)
+ std::cout << "removing " << name << '\n';
#endif
- return canRemove;
- }), funcs.end());
+ return canRemove;
+ }),
+ funcs.end());
// return whether we did any work
return inlinedUses.size() > 0;
}
};
-Pass* createInliningPass() {
- return new Inlining();
-}
+Pass* createInliningPass() { return new Inlining(); }
Pass* createInliningOptimizingPass() {
auto* ret = new Inlining();
@@ -360,4 +382,3 @@ Pass* createInliningOptimizingPass() {
}
} // namespace wasm
-
diff --git a/src/passes/InstrumentLocals.cpp b/src/passes/InstrumentLocals.cpp
index 6b44af0ad..3845b0fee 100644
--- a/src/passes/InstrumentLocals.cpp
+++ b/src/passes/InstrumentLocals.cpp
@@ -43,13 +43,13 @@
// )
// )
-#include <wasm.h>
-#include <wasm-builder.h>
-#include <pass.h>
-#include "shared-constants.h"
-#include "asmjs/shared-constants.h"
#include "asm_v_wasm.h"
+#include "asmjs/shared-constants.h"
#include "ir/function-type-utils.h"
+#include "shared-constants.h"
+#include <pass.h>
+#include <wasm-builder.h>
+#include <wasm.h>
namespace wasm {
@@ -68,59 +68,71 @@ struct InstrumentLocals : public WalkerPass<PostWalker<InstrumentLocals>> {
Builder builder(*getModule());
Name import;
switch (curr->type) {
- case i32: import = get_i32; break;
- case i64: return; // TODO
- case f32: import = get_f32; break;
- case f64: import = get_f64; break;
- case v128: assert(false && "v128 not implemented yet");
- case none: WASM_UNREACHABLE();
- case unreachable: WASM_UNREACHABLE();
+ case i32:
+ import = get_i32;
+ break;
+ case i64:
+ return; // TODO
+ case f32:
+ import = get_f32;
+ break;
+ case f64:
+ import = get_f64;
+ break;
+ case v128:
+ assert(false && "v128 not implemented yet");
+ case none:
+ WASM_UNREACHABLE();
+ case unreachable:
+ WASM_UNREACHABLE();
}
replaceCurrent(
- builder.makeCall(
- import,
- {
- builder.makeConst(Literal(int32_t(id++))),
- builder.makeConst(Literal(int32_t(curr->index))),
- curr
- },
- curr->type
- )
- );
+ builder.makeCall(import,
+ {builder.makeConst(Literal(int32_t(id++))),
+ builder.makeConst(Literal(int32_t(curr->index))),
+ curr},
+ curr->type));
}
void visitSetLocal(SetLocal* curr) {
Builder builder(*getModule());
Name import;
switch (curr->value->type) {
- case i32: import = set_i32; break;
- case i64: return; // TODO
- case f32: import = set_f32; break;
- case f64: import = set_f64; break;
- case v128: assert(false && "v128 not implemented yet");
- case unreachable: return; // nothing to do here
- case none: WASM_UNREACHABLE();
+ case i32:
+ import = set_i32;
+ break;
+ case i64:
+ return; // TODO
+ case f32:
+ import = set_f32;
+ break;
+ case f64:
+ import = set_f64;
+ break;
+ case v128:
+ assert(false && "v128 not implemented yet");
+ case unreachable:
+ return; // nothing to do here
+ case none:
+ WASM_UNREACHABLE();
}
- curr->value = builder.makeCall(
- import,
- {
- builder.makeConst(Literal(int32_t(id++))),
- builder.makeConst(Literal(int32_t(curr->index))),
- curr->value
- },
- curr->value->type
- );
+ curr->value =
+ builder.makeCall(import,
+ {builder.makeConst(Literal(int32_t(id++))),
+ builder.makeConst(Literal(int32_t(curr->index))),
+ curr->value},
+ curr->value->type);
}
void visitModule(Module* curr) {
- addImport(curr, get_i32, "iiii");
- addImport(curr, get_i64, "jiij");
- addImport(curr, get_f32, "fiif");
- addImport(curr, get_f64, "diid");
- addImport(curr, set_i32, "iiii");
- addImport(curr, set_i64, "jiij");
- addImport(curr, set_f32, "fiif");
- addImport(curr, set_f64, "diid");
+ addImport(curr, get_i32, "iiii");
+ addImport(curr, get_i64, "jiij");
+ addImport(curr, get_f32, "fiif");
+ addImport(curr, get_f64, "diid");
+ addImport(curr, set_i32, "iiii");
+ addImport(curr, set_i64, "jiij");
+ addImport(curr, set_f32, "fiif");
+ addImport(curr, set_f64, "diid");
}
private:
@@ -138,8 +150,6 @@ private:
}
};
-Pass* createInstrumentLocalsPass() {
- return new InstrumentLocals();
-}
+Pass* createInstrumentLocalsPass() { return new InstrumentLocals(); }
} // namespace wasm
diff --git a/src/passes/InstrumentMemory.cpp b/src/passes/InstrumentMemory.cpp
index a929478df..4a479db34 100644
--- a/src/passes/InstrumentMemory.cpp
+++ b/src/passes/InstrumentMemory.cpp
@@ -52,26 +52,26 @@
// )
// )
-#include <wasm.h>
-#include <wasm-builder.h>
-#include <pass.h>
-#include "shared-constants.h"
-#include "asmjs/shared-constants.h"
#include "asm_v_wasm.h"
+#include "asmjs/shared-constants.h"
#include "ir/function-type-utils.h"
+#include "shared-constants.h"
+#include <pass.h>
+#include <wasm-builder.h>
+#include <wasm.h>
namespace wasm {
-static Name load_ptr("load_ptr"),
- load_val_i32("load_val_i32"),
- load_val_i64("load_val_i64"),
- load_val_f32("load_val_f32"),
- load_val_f64("load_val_f64"),
- store_ptr("store_ptr"),
- store_val_i32("store_val_i32"),
- store_val_i64("store_val_i64"),
- store_val_f32("store_val_f32"),
- store_val_f64("store_val_f64");
+static Name load_ptr("load_ptr");
+static Name load_val_i32("load_val_i32");
+static Name load_val_i64("load_val_i64");
+static Name load_val_f32("load_val_f32");
+static Name load_val_f64("load_val_f64");
+static Name store_ptr("store_ptr");
+static Name store_val_i32("store_val_i32");
+static Name store_val_i64("store_val_i64");
+static Name store_val_f32("store_val_f32");
+static Name store_val_f64("store_val_f64");
// TODO: Add support for atomicRMW/cmpxchg
@@ -79,66 +79,74 @@ struct InstrumentMemory : public WalkerPass<PostWalker<InstrumentMemory>> {
void visitLoad(Load* curr) {
id++;
Builder builder(*getModule());
- curr->ptr = builder.makeCall(load_ptr,
- {
- builder.makeConst(Literal(int32_t(id))),
- builder.makeConst(Literal(int32_t(curr->bytes))),
- builder.makeConst(Literal(int32_t(curr->offset.addr))),
- curr->ptr
- },
- i32
- );
+ curr->ptr =
+ builder.makeCall(load_ptr,
+ {builder.makeConst(Literal(int32_t(id))),
+ builder.makeConst(Literal(int32_t(curr->bytes))),
+ builder.makeConst(Literal(int32_t(curr->offset.addr))),
+ curr->ptr},
+ i32);
Name target;
switch (curr->type) {
- case i32: target = load_val_i32; break;
- case i64: target = load_val_i64; break;
- case f32: target = load_val_f32; break;
- case f64: target = load_val_f64; break;
- default: return; // TODO: other types, unreachable, etc.
+ case i32:
+ target = load_val_i32;
+ break;
+ case i64:
+ target = load_val_i64;
+ break;
+ case f32:
+ target = load_val_f32;
+ break;
+ case f64:
+ target = load_val_f64;
+ break;
+ default:
+ return; // TODO: other types, unreachable, etc.
}
- replaceCurrent(builder.makeCall(target,
- {
- builder.makeConst(Literal(int32_t(id))),
- curr
- },
- curr->type
- ));
+ replaceCurrent(builder.makeCall(
+ target, {builder.makeConst(Literal(int32_t(id))), curr}, curr->type));
}
void visitStore(Store* curr) {
id++;
Builder builder(*getModule());
- curr->ptr = builder.makeCall(store_ptr,
- { builder.makeConst(Literal(int32_t(id))),
- builder.makeConst(Literal(int32_t(curr->bytes))),
- builder.makeConst(Literal(int32_t(curr->offset.addr))),
- curr->ptr },
- i32
- );
+ curr->ptr =
+ builder.makeCall(store_ptr,
+ {builder.makeConst(Literal(int32_t(id))),
+ builder.makeConst(Literal(int32_t(curr->bytes))),
+ builder.makeConst(Literal(int32_t(curr->offset.addr))),
+ curr->ptr},
+ i32);
Name target;
switch (curr->value->type) {
- case i32: target = store_val_i32; break;
- case i64: target = store_val_i64; break;
- case f32: target = store_val_f32; break;
- case f64: target = store_val_f64; break;
- default: return; // TODO: other types, unreachable, etc.
+ case i32:
+ target = store_val_i32;
+ break;
+ case i64:
+ target = store_val_i64;
+ break;
+ case f32:
+ target = store_val_f32;
+ break;
+ case f64:
+ target = store_val_f64;
+ break;
+ default:
+ return; // TODO: other types, unreachable, etc.
}
- curr->value = builder.makeCall(target,
- {
- builder.makeConst(Literal(int32_t(id))),
- curr->value
- },
- curr->value->type
- );
+ curr->value =
+ builder.makeCall(target,
+ {builder.makeConst(Literal(int32_t(id))), curr->value},
+ curr->value->type);
}
- void visitModule(Module *curr) {
- addImport(curr, load_ptr, "iiiii");
- addImport(curr, load_val_i32, "iii");
- addImport(curr, load_val_i64, "jij");
- addImport(curr, load_val_f32, "fif");
- addImport(curr, load_val_f64, "did");
- addImport(curr, store_ptr, "iiiii");
+ void visitModule(Module* curr) {
+ addImport(curr, load_ptr, "iiiii");
+ addImport(curr, load_val_i32, "iii");
+ addImport(curr, load_val_i64, "jij");
+ addImport(curr, load_val_f32, "fif");
+ addImport(curr, load_val_f64, "did");
+ addImport(curr, store_ptr, "iiiii");
addImport(curr, store_val_i32, "iii");
addImport(curr, store_val_i64, "jij");
addImport(curr, store_val_f32, "fif");
@@ -148,7 +156,7 @@ struct InstrumentMemory : public WalkerPass<PostWalker<InstrumentMemory>> {
private:
Index id;
- void addImport(Module *curr, Name name, std::string sig) {
+ void addImport(Module* curr, Name name, std::string sig) {
auto import = new Function;
import->name = name;
import->module = ENV;
@@ -160,8 +168,6 @@ private:
}
};
-Pass *createInstrumentMemoryPass() {
- return new InstrumentMemory();
-}
+Pass* createInstrumentMemoryPass() { return new InstrumentMemory(); }
} // namespace wasm
diff --git a/src/passes/LegalizeJSInterface.cpp b/src/passes/LegalizeJSInterface.cpp
index cde4373f8..324590427 100644
--- a/src/passes/LegalizeJSInterface.cpp
+++ b/src/passes/LegalizeJSInterface.cpp
@@ -30,17 +30,17 @@
// table even to a signature that is not legal.
//
-#include <utility>
-#include "wasm.h"
-#include "pass.h"
#include "asm_v_wasm.h"
-#include "shared-constants.h"
#include "asmjs/shared-constants.h"
-#include "wasm-builder.h"
#include "ir/function-type-utils.h"
#include "ir/import-utils.h"
#include "ir/literal-utils.h"
#include "ir/utils.h"
+#include "pass.h"
+#include "shared-constants.h"
+#include "wasm-builder.h"
+#include "wasm.h"
+#include <utility>
namespace wasm {
@@ -71,8 +71,9 @@ struct LegalizeJSInterface : public Pass {
if (im->imported() && isIllegal(im) && shouldBeLegalized(im)) {
auto funcName = makeLegalStubForCalledImport(im, module);
illegalImportsToLegal[im->name] = funcName;
- // we need to use the legalized version in the table, as the import from JS
- // is legal for JS. Our stub makes it look like a native wasm function.
+ // we need to use the legalized version in the table, as the import from
+ // JS is legal for JS. Our stub makes it look like a native wasm
+ // function.
for (auto& segment : module->table.segments) {
for (auto& name : segment.data) {
if (name == im->name) {
@@ -87,23 +88,32 @@ struct LegalizeJSInterface : public Pass {
module->removeFunction(pair.first);
}
- // fix up imports: call_import of an illegal must be turned to a call of a legal
+ // fix up imports: call_import of an illegal must be turned to a call of a
+ // legal
struct FixImports : public WalkerPass<PostWalker<FixImports>> {
bool isFunctionParallel() override { return true; }
- Pass* create() override { return new FixImports(illegalImportsToLegal); }
+ Pass* create() override {
+ return new FixImports(illegalImportsToLegal);
+ }
std::map<Name, Name>* illegalImportsToLegal;
- FixImports(std::map<Name, Name>* illegalImportsToLegal) : illegalImportsToLegal(illegalImportsToLegal) {}
+ FixImports(std::map<Name, Name>* illegalImportsToLegal)
+ : illegalImportsToLegal(illegalImportsToLegal) {}
void visitCall(Call* curr) {
auto iter = illegalImportsToLegal->find(curr->target);
- if (iter == illegalImportsToLegal->end()) return;
-
- if (iter->second == getFunction()->name) return; // inside the stub function itself, is the one safe place to do the call
- replaceCurrent(Builder(*getModule()).makeCall(iter->second, curr->operands, curr->type));
+ if (iter == illegalImportsToLegal->end())
+ return;
+
+ if (iter->second == getFunction()->name)
+ // inside the stub function itself, is the one safe place to do the
+ // call
+ return;
+ replaceCurrent(Builder(*getModule())
+ .makeCall(iter->second, curr->operands, curr->type));
}
};
@@ -118,29 +128,32 @@ private:
// map of illegal to legal names for imports
std::map<Name, Name> illegalImportsToLegal;
- template<typename T>
- bool isIllegal(T* t) {
+ template<typename T> bool isIllegal(T* t) {
for (auto param : t->params) {
- if (param == i64) return true;
+ if (param == i64)
+ return true;
}
return t->result == i64;
}
// Check if an export should be legalized.
bool shouldBeLegalized(Export* ex, Function* func) {
- if (full) return true;
+ if (full)
+ return true;
// We are doing minimal legalization - just what JS needs.
return ex->name.startsWith("dynCall_");
}
// Check if an import should be legalized.
bool shouldBeLegalized(Function* im) {
- if (full) return true;
+ if (full)
+ return true;
// We are doing minimal legalization - just what JS needs.
return im->module == ENV && im->base.startsWith("invoke_");
}
- // JS calls the export, so it must call a legal stub that calls the actual wasm function
+ // JS calls the export, so it must call a legal stub that calls the actual
+ // wasm function
Name makeLegalStub(Function* func, Module* module) {
Builder builder(*module);
auto* legal = new Function();
@@ -152,11 +165,13 @@ private:
for (auto param : func->params) {
if (param == i64) {
- call->operands.push_back(I64Utilities::recreateI64(builder, legal->params.size(), legal->params.size() + 1));
+ call->operands.push_back(I64Utilities::recreateI64(
+ builder, legal->params.size(), legal->params.size() + 1));
legal->params.push_back(i32);
legal->params.push_back(i32);
} else {
- call->operands.push_back(builder.makeGetLocal(legal->params.size(), param));
+ call->operands.push_back(
+ builder.makeGetLocal(legal->params.size(), param));
legal->params.push_back(param);
}
}
@@ -167,7 +182,8 @@ private:
auto index = Builder::addVar(legal, Name(), i64);
auto* block = builder.makeBlock();
block->list.push_back(builder.makeSetLocal(index, call));
- block->list.push_back(builder.makeCall(f->name, {I64Utilities::getI64High(builder, index)}, none));
+ block->list.push_back(builder.makeCall(
+ f->name, {I64Utilities::getI64High(builder, index)}, none));
block->list.push_back(I64Utilities::getI64Low(builder, index));
block->finalize();
legal->body = block;
@@ -183,11 +199,12 @@ private:
return legal->name;
}
- // wasm calls the import, so it must call a stub that calls the actual legal JS import
+ // wasm calls the import, so it must call a stub that calls the actual legal
+ // JS import
Name makeLegalStubForCalledImport(Function* im, Module* module) {
Builder builder(*module);
auto type = make_unique<FunctionType>();
- type->name = Name(std::string("legaltype$") + im->name.str);
+ type->name = Name(std::string("legaltype$") + im->name.str);
auto legal = make_unique<Function>();
legal->name = Name(std::string("legalimport$") + im->name.str);
legal->module = im->module;
@@ -203,12 +220,15 @@ private:
for (auto param : imFunctionType->params) {
if (param == i64) {
- call->operands.push_back(I64Utilities::getI64Low(builder, func->params.size()));
- call->operands.push_back(I64Utilities::getI64High(builder, func->params.size()));
+ call->operands.push_back(
+ I64Utilities::getI64Low(builder, func->params.size()));
+ call->operands.push_back(
+ I64Utilities::getI64High(builder, func->params.size()));
type->params.push_back(i32);
type->params.push_back(i32);
} else {
- call->operands.push_back(builder.makeGetLocal(func->params.size(), param));
+ call->operands.push_back(
+ builder.makeGetLocal(func->params.size(), param));
type->params.push_back(param);
}
func->params.push_back(param);
@@ -241,7 +261,8 @@ private:
return funcName;
}
- static Function* getFunctionOrImport(Module* module, Name name, std::string sig) {
+ static Function*
+ getFunctionOrImport(Module* module, Name name, std::string sig) {
// First look for the function by name
if (Function* f = module->getFunctionOrNull(name)) {
return f;
@@ -264,13 +285,10 @@ private:
}
};
-Pass *createLegalizeJSInterfacePass() {
- return new LegalizeJSInterface(true);
-}
+Pass* createLegalizeJSInterfacePass() { return new LegalizeJSInterface(true); }
-Pass *createLegalizeJSInterfaceMinimallyPass() {
+Pass* createLegalizeJSInterfaceMinimallyPass() {
return new LegalizeJSInterface(false);
}
} // namespace wasm
-
diff --git a/src/passes/LimitSegments.cpp b/src/passes/LimitSegments.cpp
index 521969a28..0ea70f53d 100644
--- a/src/passes/LimitSegments.cpp
+++ b/src/passes/LimitSegments.cpp
@@ -26,14 +26,11 @@ struct LimitSegments : public Pass {
void run(PassRunner* runner, Module* module) override {
if (!MemoryUtils::ensureLimitedSegments(*module)) {
std::cerr << "Unable to merge segments. "
- << "wasm VMs may not accept this binary"
- << std::endl;
+ << "wasm VMs may not accept this binary" << std::endl;
}
}
};
-Pass *createLimitSegmentsPass() {
- return new LimitSegments();
-}
+Pass* createLimitSegmentsPass() { return new LimitSegments(); }
} // namespace wasm
diff --git a/src/passes/LocalCSE.cpp b/src/passes/LocalCSE.cpp
index 1338c6571..d582c8275 100644
--- a/src/passes/LocalCSE.cpp
+++ b/src/passes/LocalCSE.cpp
@@ -37,15 +37,15 @@
#include <algorithm>
#include <memory>
-#include <wasm.h>
-#include <wasm-builder.h>
-#include <wasm-traversal.h>
-#include <pass.h>
+#include "ir/flat.h"
#include <ir/cost.h>
#include <ir/effects.h>
#include <ir/equivalent_sets.h>
-#include "ir/flat.h"
#include <ir/hashed.h>
+#include <pass.h>
+#include <wasm-builder.h>
+#include <wasm-traversal.h>
+#include <wasm.h>
namespace wasm {
@@ -60,7 +60,8 @@ struct LocalCSE : public WalkerPass<LinearExecutionWalker<LocalCSE>> {
Index index; // the local we are assigned to, local.get that to reuse us
EffectAnalyzer effects;
- UsableInfo(Expression* value, Index index, PassOptions& passOptions) : value(value), index(index), effects(passOptions, value) {}
+ UsableInfo(Expression* value, Index index, PassOptions& passOptions)
+ : value(value), index(index), effects(passOptions, value) {}
};
// a list of usables in a linear execution trace
@@ -183,11 +184,13 @@ struct LocalCSE : public WalkerPass<LinearExecutionWalker<LocalCSE>> {
if (iter != usables.end()) {
// already exists in the table, this is good to reuse
auto& info = iter->second;
- set->value = Builder(*getModule()).makeGetLocal(info.index, value->type);
+ set->value =
+ Builder(*getModule()).makeGetLocal(info.index, value->type);
anotherPass = true;
} else {
// not in table, add this, maybe we can help others later
- usables.emplace(std::make_pair(hashed, UsableInfo(value, set->index, getPassOptions())));
+ usables.emplace(std::make_pair(
+ hashed, UsableInfo(value, set->index, getPassOptions())));
}
}
} else if (auto* get = curr->dynCast<GetLocal>()) {
@@ -227,8 +230,6 @@ struct LocalCSE : public WalkerPass<LinearExecutionWalker<LocalCSE>> {
}
};
-Pass *createLocalCSEPass() {
- return new LocalCSE();
-}
+Pass* createLocalCSEPass() { return new LocalCSE(); }
} // namespace wasm
diff --git a/src/passes/LogExecution.cpp b/src/passes/LogExecution.cpp
index abdaa8d23..7bfee7c24 100644
--- a/src/passes/LogExecution.cpp
+++ b/src/passes/LogExecution.cpp
@@ -28,26 +28,22 @@
// value.
//
-#include <wasm.h>
-#include <wasm-builder.h>
-#include <pass.h>
-#include "shared-constants.h"
-#include "asmjs/shared-constants.h"
#include "asm_v_wasm.h"
+#include "asmjs/shared-constants.h"
#include "ir/function-type-utils.h"
+#include "shared-constants.h"
+#include <pass.h>
+#include <wasm-builder.h>
+#include <wasm.h>
namespace wasm {
Name LOGGER("log_execution");
struct LogExecution : public WalkerPass<PostWalker<LogExecution>> {
- void visitLoop(Loop* curr) {
- curr->body = makeLogCall(curr->body);
- }
+ void visitLoop(Loop* curr) { curr->body = makeLogCall(curr->body); }
- void visitReturn(Return* curr) {
- replaceCurrent(makeLogCall(curr));
- }
+ void visitReturn(Return* curr) { replaceCurrent(makeLogCall(curr)); }
void visitFunction(Function* curr) {
if (curr->imported()) {
@@ -61,7 +57,7 @@ struct LogExecution : public WalkerPass<PostWalker<LogExecution>> {
curr->body = makeLogCall(curr->body);
}
- void visitModule(Module *curr) {
+ void visitModule(Module* curr) {
// Add the import
auto import = new Function;
import->name = LOGGER;
@@ -79,17 +75,11 @@ private:
Builder builder(*getModule());
return builder.makeSequence(
builder.makeCall(
- LOGGER,
- { builder.makeConst(Literal(int32_t(id++))) },
- none
- ),
- curr
- );
+ LOGGER, {builder.makeConst(Literal(int32_t(id++)))}, none),
+ curr);
}
};
-Pass *createLogExecutionPass() {
- return new LogExecution();
-}
+Pass* createLogExecutionPass() { return new LogExecution(); }
} // namespace wasm
diff --git a/src/passes/LoopInvariantCodeMotion.cpp b/src/passes/LoopInvariantCodeMotion.cpp
index aec2f7ce5..e9f376bd3 100644
--- a/src/passes/LoopInvariantCodeMotion.cpp
+++ b/src/passes/LoopInvariantCodeMotion.cpp
@@ -24,16 +24,17 @@
#include <unordered_map>
-#include "wasm.h"
-#include "pass.h"
-#include "wasm-builder.h"
-#include "ir/local-graph.h"
#include "ir/effects.h"
#include "ir/find_all.h"
+#include "ir/local-graph.h"
+#include "pass.h"
+#include "wasm-builder.h"
+#include "wasm.h"
namespace wasm {
-struct LoopInvariantCodeMotion : public WalkerPass<ExpressionStackWalker<LoopInvariantCodeMotion>> {
+struct LoopInvariantCodeMotion
+ : public WalkerPass<ExpressionStackWalker<LoopInvariantCodeMotion>> {
bool isFunctionParallel() override { return true; }
Pass* create() override { return new LoopInvariantCodeMotion; }
@@ -128,11 +129,12 @@ struct LoopInvariantCodeMotion : public WalkerPass<ExpressionStackWalker<LoopInv
// outside of the loop, in which case everything is good -
// either they are before the loop and constant for us, or
// they are after and don't matter.
- if (effects.localsRead.empty() || !hasGetDependingOnLoopSet(curr, loopSets)) {
- // We have checked if our gets are influenced by sets in the loop, and
- // must also check if our sets interfere with them. To do so, assume
- // temporarily that we are moving curr out; see if any sets remain for
- // its indexes.
+ if (effects.localsRead.empty() ||
+ !hasGetDependingOnLoopSet(curr, loopSets)) {
+ // We have checked if our gets are influenced by sets in the loop,
+ // and must also check if our sets interfere with them. To do so,
+ // assume temporarily that we are moving curr out; see if any sets
+ // remain for its indexes.
FindAll<SetLocal> currSets(curr);
for (auto* set : currSets.list) {
assert(numSetsForIndex[set->index] > 0);
@@ -187,8 +189,8 @@ struct LoopInvariantCodeMotion : public WalkerPass<ExpressionStackWalker<LoopInv
bool interestingToMove(Expression* curr) {
// In theory we could consider blocks, but then heavy nesting of
// switch patterns would be heavy, and almost always pointless.
- if (curr->type != none || curr->is<Nop>() || curr->is<Block>()
- || curr->is<Loop>()) {
+ if (curr->type != none || curr->is<Nop>() || curr->is<Block>() ||
+ curr->is<Loop>()) {
return false;
}
// Don't move copies (set of a get, or set of a tee of a get, etc.),
@@ -206,7 +208,8 @@ struct LoopInvariantCodeMotion : public WalkerPass<ExpressionStackWalker<LoopInv
if (auto* set = curr->dynCast<SetLocal>()) {
while (1) {
auto* next = set->value->dynCast<SetLocal>();
- if (!next) break;
+ if (!next)
+ break;
set = next;
}
if (set->value->is<GetLocal>() || set->value->is<Const>()) {
@@ -223,7 +226,8 @@ struct LoopInvariantCodeMotion : public WalkerPass<ExpressionStackWalker<LoopInv
for (auto* set : sets) {
// nullptr means a parameter or zero-init value;
// no danger to us.
- if (!set) continue;
+ if (!set)
+ continue;
// Check if the set is in the loop. If not, it's either before,
// which is fine, or after, which is also fine - moving curr
// to just outside the loop will preserve those relationships.
@@ -238,9 +242,8 @@ struct LoopInvariantCodeMotion : public WalkerPass<ExpressionStackWalker<LoopInv
}
};
-Pass *createLoopInvariantCodeMotionPass() {
+Pass* createLoopInvariantCodeMotionPass() {
return new LoopInvariantCodeMotion();
}
} // namespace wasm
-
diff --git a/src/passes/MemoryPacking.cpp b/src/passes/MemoryPacking.cpp
index 704f57d89..11dbc1743 100644
--- a/src/passes/MemoryPacking.cpp
+++ b/src/passes/MemoryPacking.cpp
@@ -15,9 +15,9 @@
*/
#include "pass.h"
-#include "wasm.h"
#include "wasm-binary.h"
#include "wasm-builder.h"
+#include "wasm.h"
namespace wasm {
@@ -57,7 +57,8 @@ struct MemoryPacking : public Pass {
};
for (auto& segment : module->memory.segments) {
- if (!isSplittable(segment)) continue;
+ if (!isSplittable(segment))
+ continue;
// skip final zeros
while (segment.data.size() > 0 && segment.data.back() == 0) {
@@ -81,7 +82,7 @@ struct MemoryPacking : public Pass {
start++;
}
Index end = start; // end of data-containing part
- Index next = end; // after zeros we can skip. preserves next >= end
+ Index next = end; // after zeros we can skip. preserves next >= end
if (!shouldSplit()) {
next = end = data.size();
}
@@ -99,7 +100,10 @@ struct MemoryPacking : public Pass {
}
}
if (end != start) {
- packed.emplace_back(Builder(*module).makeConst(Literal(int32_t(base + start))), &data[start], end - start);
+ packed.emplace_back(
+ Builder(*module).makeConst(Literal(int32_t(base + start))),
+ &data[start],
+ end - start);
}
start = next;
}
@@ -109,8 +113,6 @@ struct MemoryPacking : public Pass {
}
};
-Pass *createMemoryPackingPass() {
- return new MemoryPacking();
-}
+Pass* createMemoryPackingPass() { return new MemoryPacking(); }
} // namespace wasm
diff --git a/src/passes/MergeBlocks.cpp b/src/passes/MergeBlocks.cpp
index 38e9fc6a2..8df35abd2 100644
--- a/src/passes/MergeBlocks.cpp
+++ b/src/passes/MergeBlocks.cpp
@@ -72,21 +72,23 @@
// single outside block.
//
-#include <wasm.h>
-#include <pass.h>
-#include <wasm-builder.h>
#include <ir/branch-utils.h>
#include <ir/effects.h>
#include <ir/utils.h>
+#include <pass.h>
+#include <wasm-builder.h>
+#include <wasm.h>
namespace wasm {
// Looks for reasons we can't remove the values from breaks to an origin
-// For example, if there is a switch targeting us, we can't do it - we can't remove the value from other targets
+// For example, if there is a switch targeting us, we can't do it - we can't
+// remove the value from other targets
struct ProblemFinder : public ControlFlowWalker<ProblemFinder> {
Name origin;
bool foundProblem = false;
- // count br_ifs, and dropped br_ifs. if they don't match, then a br_if flow value is used, and we can't drop it
+ // count br_ifs, and dropped br_ifs. if they don't match, then a br_if flow
+ // value is used, and we can't drop it
Index brIfs = 0;
Index droppedBrIfs = 0;
PassOptions& passOptions;
@@ -158,8 +160,10 @@ struct BreakValueDropper : public ControlFlowWalker<BreakValueDropper> {
}
void visitDrop(Drop* curr) {
- // if we dropped a br_if whose value we removed, then we are now dropping a (block (drop value) (br_if)) with type none, which does not need a drop
- // likewise, unreachable does not need to be dropped, so we just leave drops of concrete values
+ // if we dropped a br_if whose value we removed, then we are now dropping a
+ // (block (drop value) (br_if)) with type none, which does not need a drop
+ // likewise, unreachable does not need to be dropped, so we just leave drops
+ // of concrete values
if (!isConcreteType(curr->value->type)) {
replaceCurrent(curr->value);
}
@@ -188,7 +192,8 @@ static bool hasDeadCode(Block* block) {
}
// core block optimizer routine
-static void optimizeBlock(Block* curr, Module* module, PassOptions& passOptions) {
+static void
+optimizeBlock(Block* curr, Module* module, PassOptions& passOptions) {
auto& list = curr->list;
// Main merging loop.
bool more = true;
@@ -205,7 +210,8 @@ static void optimizeBlock(Block* curr, Module* module, PassOptions& passOptions)
Loop* loop = nullptr;
// To to handle a non-block child.
if (!childBlock) {
- // if we have a child that is (drop (block ..)) then we can move the drop into the block, and remove br values. this allows more merging,
+ // if we have a child that is (drop (block ..)) then we can move the
+ // drop into the block, and remove br values. this allows more merging,
if (auto* drop = list[i]->dynCast<Drop>()) {
childBlock = drop->value->dynCast<Block>();
if (childBlock) {
@@ -253,13 +259,16 @@ static void optimizeBlock(Block* curr, Module* module, PassOptions& passOptions)
}
}
// If no block, we can't do anything.
- if (!childBlock) continue;
+ if (!childBlock)
+ continue;
auto& childList = childBlock->list;
auto childSize = childList.size();
- if (childSize == 0) continue;
- // If the child has items after an unreachable, ignore it - dce should have
- // been run, and we prefer to not handle the complexity here.
- if (hasDeadCode(childBlock)) continue;
+ if (childSize == 0)
+ continue;
+ // If the child has items after an unreachable, ignore it - dce should
+ // have been run, and we prefer to not handle the complexity here.
+ if (hasDeadCode(childBlock))
+ continue;
// In some cases we can remove only the head or the tail of the block,
// and must keep some things in the child block.
Index keepStart = childSize;
@@ -295,8 +304,9 @@ static void optimizeBlock(Block* curr, Module* module, PassOptions& passOptions)
break;
}
}
- // If we can only do part of the block, and if the block has a flowing value, we
- // would need special handling for that - not worth it, probably TODO
+ // If we can only do part of the block, and if the block has a flowing
+ // value, we would need special handling for that - not worth it,
+ // probably TODO
// FIXME is this not handled by the drop later down?
if (keepEnd < childSize && isConcreteType(childList.back()->type)) {
continue;
@@ -304,7 +314,8 @@ static void optimizeBlock(Block* curr, Module* module, PassOptions& passOptions)
}
// Maybe there's nothing to do, if we must keep it all in the
// child anyhow.
- if (keepStart == 0 && keepEnd == childSize) continue;
+ if (keepStart == 0 && keepEnd == childSize)
+ continue;
// There is something to do!
bool keepingPart = keepStart < keepEnd;
// Create a new merged list, and fill in the code before the
@@ -393,31 +404,45 @@ struct MergeBlocks : public WalkerPass<PostWalker<MergeBlocks>> {
// (..other..children..)
// )
// )
- // at which point the block is on the outside and potentially mergeable with an outer block
- Block* optimize(Expression* curr, Expression*& child, Block* outer = nullptr, Expression** dependency1 = nullptr, Expression** dependency2 = nullptr) {
- if (!child) return outer;
+ // at which point the block is on the outside and potentially mergeable with
+ // an outer block
+ Block* optimize(Expression* curr,
+ Expression*& child,
+ Block* outer = nullptr,
+ Expression** dependency1 = nullptr,
+ Expression** dependency2 = nullptr) {
+ if (!child)
+ return outer;
if ((dependency1 && *dependency1) || (dependency2 && *dependency2)) {
- // there are dependencies, things we must be reordered through. make sure no problems there
+ // there are dependencies, things we must be reordered through. make sure
+ // no problems there
EffectAnalyzer childEffects(getPassOptions(), child);
- if (dependency1 && *dependency1 && EffectAnalyzer(getPassOptions(), *dependency1).invalidates(childEffects)) return outer;
- if (dependency2 && *dependency2 && EffectAnalyzer(getPassOptions(), *dependency2).invalidates(childEffects)) return outer;
+ if (dependency1 && *dependency1 &&
+ EffectAnalyzer(getPassOptions(), *dependency1)
+ .invalidates(childEffects))
+ return outer;
+ if (dependency2 && *dependency2 &&
+ EffectAnalyzer(getPassOptions(), *dependency2)
+ .invalidates(childEffects))
+ return outer;
}
if (auto* block = child->dynCast<Block>()) {
if (!block->name.is() && block->list.size() >= 2) {
- // if we move around unreachable code, type changes could occur. avoid that, as
- // anyhow it means we should have run dce before getting here
+ // if we move around unreachable code, type changes could occur. avoid
+ // that, as anyhow it means we should have run dce before getting here
if (curr->type == none && hasUnreachableChild(block)) {
- // moving the block to the outside would replace a none with an unreachable
+ // moving the block to the outside would replace a none with an
+ // unreachable
return outer;
}
auto* back = block->list.back();
if (back->type == unreachable) {
- // curr is not reachable, dce could remove it; don't try anything fancy
- // here
+ // curr is not reachable, dce could remove it; don't try anything
+ // fancy here
return outer;
}
- // we are going to replace the block with the final element, so they should
- // be identically typed
+ // we are going to replace the block with the final element, so they
+ // should be identically typed
if (block->type != back->type) {
return outer;
}
@@ -443,18 +468,10 @@ struct MergeBlocks : public WalkerPass<PostWalker<MergeBlocks>> {
return outer;
}
- void visitUnary(Unary* curr) {
- optimize(curr, curr->value);
- }
- void visitSetLocal(SetLocal* curr) {
- optimize(curr, curr->value);
- }
- void visitLoad(Load* curr) {
- optimize(curr, curr->ptr);
- }
- void visitReturn(Return* curr) {
- optimize(curr, curr->value);
- }
+ void visitUnary(Unary* curr) { optimize(curr, curr->value); }
+ void visitSetLocal(SetLocal* curr) { optimize(curr, curr->value); }
+ void visitLoad(Load* curr) { optimize(curr, curr->ptr); }
+ void visitReturn(Return* curr) { optimize(curr, curr->value); }
void visitBinary(Binary* curr) {
optimize(curr, curr->right, optimize(curr, curr->left), &curr->left);
@@ -466,15 +483,20 @@ struct MergeBlocks : public WalkerPass<PostWalker<MergeBlocks>> {
optimize(curr, curr->value, optimize(curr, curr->ptr), &curr->ptr);
}
void optimizeTernary(Expression* curr,
- Expression*& first, Expression*& second, Expression*& third) {
+ Expression*& first,
+ Expression*& second,
+ Expression*& third) {
// TODO: for now, just stop when we see any side effect. instead, we could
// check effects carefully for reordering
Block* outer = nullptr;
- if (EffectAnalyzer(getPassOptions(), first).hasSideEffects()) return;
+ if (EffectAnalyzer(getPassOptions(), first).hasSideEffects())
+ return;
outer = optimize(curr, first, outer);
- if (EffectAnalyzer(getPassOptions(), second).hasSideEffects()) return;
+ if (EffectAnalyzer(getPassOptions(), second).hasSideEffects())
+ return;
outer = optimize(curr, second, outer);
- if (EffectAnalyzer(getPassOptions(), third).hasSideEffects()) return;
+ if (EffectAnalyzer(getPassOptions(), third).hasSideEffects())
+ return;
optimize(curr, third, outer);
}
void visitAtomicCmpxchg(AtomicCmpxchg* curr) {
@@ -485,9 +507,7 @@ struct MergeBlocks : public WalkerPass<PostWalker<MergeBlocks>> {
optimizeTernary(curr, curr->ifTrue, curr->ifFalse, curr->condition);
}
- void visitDrop(Drop* curr) {
- optimize(curr, curr->value);
- }
+ void visitDrop(Drop* curr) { optimize(curr, curr->value); }
void visitBreak(Break* curr) {
optimize(curr, curr->condition, optimize(curr, curr->value), &curr->value);
@@ -496,33 +516,31 @@ struct MergeBlocks : public WalkerPass<PostWalker<MergeBlocks>> {
optimize(curr, curr->condition, optimize(curr, curr->value), &curr->value);
}
- template<typename T>
- void handleCall(T* curr) {
+ template<typename T> void handleCall(T* curr) {
Block* outer = nullptr;
for (Index i = 0; i < curr->operands.size(); i++) {
- if (EffectAnalyzer(getPassOptions(), curr->operands[i]).hasSideEffects()) return;
+ if (EffectAnalyzer(getPassOptions(), curr->operands[i]).hasSideEffects())
+ return;
outer = optimize(curr, curr->operands[i], outer);
}
return;
}
- void visitCall(Call* curr) {
- handleCall(curr);
- }
+ void visitCall(Call* curr) { handleCall(curr); }
void visitCallIndirect(CallIndirect* curr) {
Block* outer = nullptr;
for (Index i = 0; i < curr->operands.size(); i++) {
- if (EffectAnalyzer(getPassOptions(), curr->operands[i]).hasSideEffects()) return;
+ if (EffectAnalyzer(getPassOptions(), curr->operands[i]).hasSideEffects())
+ return;
outer = optimize(curr, curr->operands[i], outer);
}
- if (EffectAnalyzer(getPassOptions(), curr->target).hasSideEffects()) return;
+ if (EffectAnalyzer(getPassOptions(), curr->target).hasSideEffects())
+ return;
optimize(curr, curr->target, outer);
}
};
-Pass *createMergeBlocksPass() {
- return new MergeBlocks();
-}
+Pass* createMergeBlocksPass() { return new MergeBlocks(); }
} // namespace wasm
diff --git a/src/passes/MergeLocals.cpp b/src/passes/MergeLocals.cpp
index 4092e1ea8..fe9f4bb86 100644
--- a/src/passes/MergeLocals.cpp
+++ b/src/passes/MergeLocals.cpp
@@ -28,7 +28,7 @@
// (i32.const 100)
// (local.get $x)
// )
-//
+//
// If that assignment of $y is never used again, everything is fine. But if
// if is, then the live range of $y does not end in that get, and will
// necessarily overlap with that of $x - making them appear to interfere
@@ -46,14 +46,16 @@
// TODO: investigate more
//
-#include <wasm.h>
+#include <ir/local-graph.h>
#include <pass.h>
#include <wasm-builder.h>
-#include <ir/local-graph.h>
+#include <wasm.h>
namespace wasm {
-struct MergeLocals : public WalkerPass<PostWalker<MergeLocals, UnifiedExpressionVisitor<MergeLocals>>> {
+struct MergeLocals
+ : public WalkerPass<
+ PostWalker<MergeLocals, UnifiedExpressionVisitor<MergeLocals>>> {
bool isFunctionParallel() override { return true; }
Pass* create() override { return new MergeLocals(); }
@@ -94,12 +96,14 @@ struct MergeLocals : public WalkerPass<PostWalker<MergeLocals, UnifiedExpression
}
void optimizeCopies() {
- if (copies.empty()) return;
+ if (copies.empty())
+ return;
// compute all dependencies
LocalGraph preGraph(getFunction());
preGraph.computeInfluences();
// optimize each copy
- std::unordered_map<SetLocal*, SetLocal*> optimizedToCopy, optimizedToTrivial;
+ std::unordered_map<SetLocal*, SetLocal*> optimizedToCopy,
+ optimizedToTrivial;
for (auto* copy : copies) {
auto* trivial = copy->value->cast<SetLocal>();
bool canOptimizeToCopy = false;
@@ -108,8 +112,8 @@ struct MergeLocals : public WalkerPass<PostWalker<MergeLocals, UnifiedExpression
canOptimizeToCopy = true;
for (auto* influencedGet : trivialInfluences) {
// this get uses the trivial write, so it uses the value in the copy.
- // however, it may depend on other writes too, if there is a merge/phi,
- // and in that case we can't do anything
+ // however, it may depend on other writes too, if there is a
+ // merge/phi, and in that case we can't do anything
assert(influencedGet->index == trivial->index);
if (preGraph.getSetses[influencedGet].size() == 1) {
// this is ok
@@ -127,14 +131,17 @@ struct MergeLocals : public WalkerPass<PostWalker<MergeLocals, UnifiedExpression
}
optimizedToCopy[copy] = trivial;
} else {
- // alternatively, we can try to remove the conflict in the opposite way: given
+ // alternatively, we can try to remove the conflict in the opposite way:
+ // given
// (local.set $x
// (local.get $y)
// )
- // we can look for uses of $x that could instead be uses of $y. this extends
- // $y's live range, but if it removes the conflict between $x and $y, it may be
- // worth it
- if (!trivialInfluences.empty()) { // if the trivial set we added has influences, it means $y lives on
+ // we can look for uses of $x that could instead be uses of $y. this
+ // extends $y's live range, but if it removes the conflict between $x
+ // and $y, it may be worth it
+
+ // if the trivial set we added has influences, it means $y lives on
+ if (!trivialInfluences.empty()) {
auto& copyInfluences = preGraph.setInfluences[copy];
if (!copyInfluences.empty()) {
bool canOptimizeToTrivial = true;
@@ -212,9 +219,6 @@ struct MergeLocals : public WalkerPass<PostWalker<MergeLocals, UnifiedExpression
}
};
-Pass *createMergeLocalsPass() {
- return new MergeLocals();
-}
+Pass* createMergeLocalsPass() { return new MergeLocals(); }
} // namespace wasm
-
diff --git a/src/passes/Metrics.cpp b/src/passes/Metrics.cpp
index 8717a86b7..0baca3e8b 100644
--- a/src/passes/Metrics.cpp
+++ b/src/passes/Metrics.cpp
@@ -16,22 +16,23 @@
#include <algorithm>
#include <iomanip>
+#include <ir/module-utils.h>
#include <pass.h>
#include <support/colors.h>
-#include <wasm.h>
#include <wasm-binary.h>
-#include <ir/module-utils.h>
+#include <wasm.h>
using namespace std;
namespace wasm {
-typedef map<const char *, int> Counts;
+typedef map<const char*, int> Counts;
static Counts lastCounts;
// Prints metrics between optimization passes.
-struct Metrics : public WalkerPass<PostWalker<Metrics, UnifiedExpressionVisitor<Metrics>>> {
+struct Metrics
+ : public WalkerPass<PostWalker<Metrics, UnifiedExpressionVisitor<Metrics>>> {
bool modifiesBinaryenIR() override { return false; }
bool byFunction;
@@ -56,9 +57,8 @@ struct Metrics : public WalkerPass<PostWalker<Metrics, UnifiedExpressionVisitor<
for (auto& curr : module->exports) {
visitExport(curr.get());
}
- ModuleUtils::iterDefinedGlobals(*module, [&](Global* curr) {
- walkGlobal(curr);
- });
+ ModuleUtils::iterDefinedGlobals(*module,
+ [&](Global* curr) { walkGlobal(curr); });
walkTable(&module->table);
walkMemory(&module->memory);
@@ -70,14 +70,14 @@ struct Metrics : public WalkerPass<PostWalker<Metrics, UnifiedExpressionVisitor<
// add memory and table
if (module->memory.exists) {
Index size = 0;
- for (auto& segment: module->memory.segments) {
+ for (auto& segment : module->memory.segments) {
size += segment.data.size();
}
counts["[memory-data]"] = size;
}
if (module->table.exists) {
Index size = 0;
- for (auto& segment: module->table.segments) {
+ for (auto& segment : module->table.segments) {
size += segment.data.size();
}
counts["[table-data]"] = size;
@@ -96,13 +96,15 @@ struct Metrics : public WalkerPass<PostWalker<Metrics, UnifiedExpressionVisitor<
counts.clear();
walkFunction(func);
counts["[vars]"] = func->getNumVars();
- counts["[binary-bytes]"] = writer.tableOfContents.functionBodies[binaryIndex++].size;
+ counts["[binary-bytes]"] =
+ writer.tableOfContents.functionBodies[binaryIndex++].size;
printCounts(std::string("func: ") + func->name.str);
});
// print for each export how much code size is due to it, i.e.,
// how much the module could shrink without it.
auto sizeAfterGlobalCleanup = [](Module* module) {
- PassRunner runner(module, PassOptions::getWithDefaultOptimizationOptions());
+ PassRunner runner(module,
+ PassOptions::getWithDefaultOptimizationOptions());
runner.setIsNested(true);
runner.addDefaultGlobalOptimizationPostPasses(); // remove stuff
runner.run();
@@ -118,13 +120,16 @@ struct Metrics : public WalkerPass<PostWalker<Metrics, UnifiedExpressionVisitor<
baseline = sizeAfterGlobalCleanup(&test);
}
for (auto& exp : module->exports) {
- // create a test module where we remove the export and then see how much can be removed thanks to that
+ // create a test module where we remove the export and then see how much
+ // can be removed thanks to that
Module test;
ModuleUtils::copyModule(*module, test);
test.removeExport(exp->name);
counts.clear();
- counts["[removable-bytes-without-it]"] = baseline - sizeAfterGlobalCleanup(&test);
- printCounts(std::string("export: ") + exp->name.str + " (" + exp->value.str + ')');
+ counts["[removable-bytes-without-it]"] =
+ baseline - sizeAfterGlobalCleanup(&test);
+ printCounts(std::string("export: ") + exp->name.str + " (" +
+ exp->value.str + ')');
}
// check how much size depends on the start method
if (!module->start.isNull()) {
@@ -132,7 +137,8 @@ struct Metrics : public WalkerPass<PostWalker<Metrics, UnifiedExpressionVisitor<
ModuleUtils::copyModule(*module, test);
test.start = Name();
counts.clear();
- counts["[removable-bytes-without-it]"] = baseline - sizeAfterGlobalCleanup(&test);
+ counts["[removable-bytes-without-it]"] =
+ baseline - sizeAfterGlobalCleanup(&test);
printCounts(std::string("start: ") + module->start.str);
}
// can't compare detailed info between passes yet
@@ -153,7 +159,7 @@ struct Metrics : public WalkerPass<PostWalker<Metrics, UnifiedExpressionVisitor<
}
void printCounts(std::string title) {
- ostream &o = cout;
+ ostream& o = cout;
vector<const char*> keys;
// add total
int total = 0;
@@ -173,9 +179,9 @@ struct Metrics : public WalkerPass<PostWalker<Metrics, UnifiedExpressionVisitor<
o << title << "\n";
for (auto* key : keys) {
auto value = counts[key];
- if (value == 0 && key[0] != '[') continue;
- o << " " << left << setw(15) << key << ": " << setw(8)
- << value;
+ if (value == 0 && key[0] != '[')
+ continue;
+ o << " " << left << setw(15) << key << ": " << setw(8) << value;
if (lastCounts.count(key)) {
int before = lastCounts[key];
int after = value;
@@ -195,12 +201,8 @@ struct Metrics : public WalkerPass<PostWalker<Metrics, UnifiedExpressionVisitor<
}
};
-Pass* createMetricsPass() {
- return new Metrics(false);
-}
+Pass* createMetricsPass() { return new Metrics(false); }
-Pass* createFunctionMetricsPass() {
- return new Metrics(true);
-}
+Pass* createFunctionMetricsPass() { return new Metrics(true); }
} // namespace wasm
diff --git a/src/passes/MinifyImportsAndExports.cpp b/src/passes/MinifyImportsAndExports.cpp
index 007f4b629..23dd2a21a 100644
--- a/src/passes/MinifyImportsAndExports.cpp
+++ b/src/passes/MinifyImportsAndExports.cpp
@@ -32,12 +32,12 @@
#include <string>
#include <unordered_set>
-#include <wasm.h>
-#include <pass.h>
-#include <shared-constants.h>
#include <asmjs/shared-constants.h>
#include <ir/import-utils.h>
#include <ir/module-utils.h>
+#include <pass.h>
+#include <shared-constants.h>
+#include <wasm.h>
namespace wasm {
@@ -45,7 +45,8 @@ struct MinifyImportsAndExports : public Pass {
bool minifyExports;
public:
- explicit MinifyImportsAndExports(bool minifyExports):minifyExports(minifyExports) {}
+ explicit MinifyImportsAndExports(bool minifyExports)
+ : minifyExports(minifyExports) {}
private:
// Generates minified names that are valid in JS.
@@ -53,8 +54,8 @@ private:
class MinifiedNames {
public:
MinifiedNames() {
- // Reserved words in JS up to size 4 - size 5 and above would mean we use an astronomical
- // number of symbols, which is not realistic anyhow.
+ // Reserved words in JS up to size 4 - size 5 and above would mean we use
+ // an astronomical number of symbols, which is not realistic anyhow.
reserved.insert("do");
reserved.insert("if");
reserved.insert("in");
@@ -71,7 +72,8 @@ private:
reserved.insert("this");
reserved.insert("with");
- validInitialChars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_$";
+ validInitialChars =
+ "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_$";
validLaterChars = validInitialChars + "0123456789";
minifiedState.push_back(0);
@@ -120,14 +122,16 @@ private:
size_t i = 0;
while (1) {
minifiedState[i]++;
- if (minifiedState[i] < (i == 0 ? validInitialChars : validLaterChars).size()) {
+ if (minifiedState[i] <
+ (i == 0 ? validInitialChars : validLaterChars).size()) {
break;
}
// Overflow.
minifiedState[i] = 0;
i++;
if (i == minifiedState.size()) {
- minifiedState.push_back(-1); // will become 0 after increment in next loop head
+ // will become 0 after increment in next loop head
+ minifiedState.push_back(-1);
}
}
}
@@ -170,11 +174,9 @@ private:
}
};
-Pass *createMinifyImportsPass() {
- return new MinifyImportsAndExports(false);
-}
+Pass* createMinifyImportsPass() { return new MinifyImportsAndExports(false); }
-Pass *createMinifyImportsAndExportsPass() {
+Pass* createMinifyImportsAndExportsPass() {
return new MinifyImportsAndExports(true);
}
diff --git a/src/passes/NameList.cpp b/src/passes/NameList.cpp
index 6b1d528e4..1051a31d1 100644
--- a/src/passes/NameList.cpp
+++ b/src/passes/NameList.cpp
@@ -18,24 +18,22 @@
// Write out the name list of the module, similar to `nm`.
//
-#include "wasm.h"
-#include "pass.h"
#include "ir/module-utils.h"
#include "ir/utils.h"
+#include "pass.h"
+#include "wasm.h"
namespace wasm {
struct NameList : public Pass {
void run(PassRunner* runner, Module* module) override {
ModuleUtils::iterDefinedFunctions(*module, [&](Function* func) {
- std::cout << " " << func->name << " : " << Measurer::measure(func->body) << '\n';
+ std::cout << " " << func->name << " : "
+ << Measurer::measure(func->body) << '\n';
});
}
};
-Pass *createNameListPass() {
- return new NameList();
-}
+Pass* createNameListPass() { return new NameList(); }
} // namespace wasm
-
diff --git a/src/passes/NoExitRuntime.cpp b/src/passes/NoExitRuntime.cpp
index 05dd639c9..680b91b23 100644
--- a/src/passes/NoExitRuntime.cpp
+++ b/src/passes/NoExitRuntime.cpp
@@ -20,10 +20,10 @@
// run.
//
+#include <asmjs/shared-constants.h>
#include <pass.h>
-#include <wasm.h>
#include <wasm-builder.h>
-#include <asmjs/shared-constants.h>
+#include <wasm.h>
using namespace std;
@@ -34,27 +34,23 @@ struct NoExitRuntime : public WalkerPass<PostWalker<NoExitRuntime>> {
Pass* create() override { return new NoExitRuntime; }
- // Remove all possible manifestations of atexit, across asm2wasm and llvm wasm backend.
- std::array<Name, 4> ATEXIT_NAMES = {{ "___cxa_atexit",
- "__cxa_atexit",
- "_atexit",
- "atexit" }};
+ // Remove all possible manifestations of atexit, across asm2wasm and llvm wasm
+ // backend.
+ std::array<Name, 4> ATEXIT_NAMES = {
+ {"___cxa_atexit", "__cxa_atexit", "_atexit", "atexit"}};
void visitCall(Call* curr) {
auto* import = getModule()->getFunctionOrNull(curr->target);
- if (!import || !import->imported() || import->module != ENV) return;
+ if (!import || !import->imported() || import->module != ENV)
+ return;
for (auto name : ATEXIT_NAMES) {
if (name == import->base) {
- replaceCurrent(
- Builder(*getModule()).replaceWithIdenticalType(curr)
- );
+ replaceCurrent(Builder(*getModule()).replaceWithIdenticalType(curr));
}
}
}
};
-Pass* createNoExitRuntimePass() {
- return new NoExitRuntime();
-}
+Pass* createNoExitRuntimePass() { return new NoExitRuntime(); }
} // namespace wasm
diff --git a/src/passes/OptimizeAddedConstants.cpp b/src/passes/OptimizeAddedConstants.cpp
index e2cfb1418..b8d011cfb 100644
--- a/src/passes/OptimizeAddedConstants.cpp
+++ b/src/passes/OptimizeAddedConstants.cpp
@@ -15,9 +15,9 @@
*/
//
-// Optimize added constants into load/store offsets. This requires the assumption
-// that low memory is unused, so that we can replace an add (which might wrap)
-// with a load/store offset (which does not).
+// Optimize added constants into load/store offsets. This requires the
+// assumption that low memory is unused, so that we can replace an add (which
+// might wrap) with a load/store offset (which does not).
//
// The propagate option also propagates offsets across set/get local pairs.
//
@@ -30,20 +30,22 @@
// speed, and may lead to code size reductions elsewhere by using fewer locals.
//
-#include <wasm.h>
-#include <pass.h>
-#include <wasm-builder.h>
#include <ir/local-graph.h>
#include <ir/local-utils.h>
#include <ir/parents.h>
+#include <pass.h>
+#include <wasm-builder.h>
+#include <wasm.h>
namespace wasm {
-template<typename P, typename T>
-class MemoryAccessOptimizer {
+template<typename P, typename T> class MemoryAccessOptimizer {
public:
- MemoryAccessOptimizer(P* parent, T* curr, Module* module, LocalGraph* localGraph) :
- parent(parent), curr(curr), module(module), localGraph(localGraph) {}
+ MemoryAccessOptimizer(P* parent,
+ T* curr,
+ Module* module,
+ LocalGraph* localGraph)
+ : parent(parent), curr(curr), module(module), localGraph(localGraph) {}
// Tries to optimize, and returns whether we propagated a change.
bool optimize() {
@@ -78,18 +80,20 @@ public:
auto& sets = localGraph->getSetses[get];
if (sets.size() == 1) {
auto* set = *sets.begin();
- // May be a zero-init (in which case, we can ignore it). Must also be valid
- // to propagate, as checked earlier in the parent.
+ // May be a zero-init (in which case, we can ignore it). Must also be
+ // valid to propagate, as checked earlier in the parent.
if (set && parent->isPropagatable(set)) {
auto* value = set->value;
if (auto* add = value->template dynCast<Binary>()) {
if (add->op == AddInt32) {
// We can optimize on either side, but only if both we find
// a constant *and* the other side cannot change in the middle.
- // TODO If it could change, we may add a new local to capture the
- // old value.
- if (tryToOptimizePropagatedAdd(add->right, add->left, get, set) ||
- tryToOptimizePropagatedAdd(add->left, add->right, get, set)) {
+ // TODO If it could change, we may add a new local to capture
+ // the old value.
+ if (tryToOptimizePropagatedAdd(
+ add->right, add->left, get, set) ||
+ tryToOptimizePropagatedAdd(
+ add->left, add->right, get, set)) {
return true;
}
}
@@ -153,7 +157,10 @@ private:
return false;
}
- bool tryToOptimizePropagatedAdd(Expression* oneSide, Expression* otherSide, GetLocal* ptr, SetLocal* set) {
+ bool tryToOptimizePropagatedAdd(Expression* oneSide,
+ Expression* otherSide,
+ GetLocal* ptr,
+ SetLocal* set) {
if (auto* c = oneSide->template dynCast<Const>()) {
if (otherSide->template is<Const>()) {
// Both sides are constant - this is not optimized code, ignore.
@@ -171,16 +178,17 @@ private:
//
// load(x, offset=10)
//
- // If the other side is a get, we may be able to prove that we can just use that same
- // local, if both it and the pointer are in SSA form. In that case,
+ // If the other side is a get, we may be able to prove that we can just
+ // use that same local, if both it and the pointer are in SSA form. In
+ // that case,
//
// y = .. // single assignment that dominates all uses
// x = y + 10 // single assignment that dominates all uses
// [..]
// load(x) => load(y, offset=10)
//
- // This is valid since dominance is transitive, so y's definition dominates the load,
- // and it is ok to replace x with y + 10 there.
+ // This is valid since dominance is transitive, so y's definition
+ // dominates the load, and it is ok to replace x with y + 10 there.
Index index = -1;
bool canReuseIndex = false;
if (auto* get = otherSide->template dynCast<GetLocal>()) {
@@ -228,7 +236,10 @@ private:
}
};
-struct OptimizeAddedConstants : public WalkerPass<PostWalker<OptimizeAddedConstants, UnifiedExpressionVisitor<OptimizeAddedConstants>>> {
+struct OptimizeAddedConstants
+ : public WalkerPass<
+ PostWalker<OptimizeAddedConstants,
+ UnifiedExpressionVisitor<OptimizeAddedConstants>>> {
bool isFunctionParallel() override { return true; }
bool propagate;
@@ -238,14 +249,16 @@ struct OptimizeAddedConstants : public WalkerPass<PostWalker<OptimizeAddedConsta
Pass* create() override { return new OptimizeAddedConstants(propagate); }
void visitLoad(Load* curr) {
- MemoryAccessOptimizer<OptimizeAddedConstants, Load> optimizer(this, curr, getModule(), localGraph.get());
+ MemoryAccessOptimizer<OptimizeAddedConstants, Load> optimizer(
+ this, curr, getModule(), localGraph.get());
if (optimizer.optimize()) {
propagated = true;
}
}
void visitStore(Store* curr) {
- MemoryAccessOptimizer<OptimizeAddedConstants, Store> optimizer(this, curr, getModule(), localGraph.get());
+ MemoryAccessOptimizer<OptimizeAddedConstants, Store> optimizer(
+ this, curr, getModule(), localGraph.get());
if (optimizer.optimize()) {
propagated = true;
}
@@ -254,9 +267,10 @@ struct OptimizeAddedConstants : public WalkerPass<PostWalker<OptimizeAddedConsta
void doWalkFunction(Function* func) {
// This pass is only valid under the assumption of unused low memory.
assert(getPassOptions().lowMemoryUnused);
- // Multiple passes may be needed if we have x + 4 + 8 etc. (nested structs in C
- // can cause this, but it's rare). Note that we only need that for the propagation
- // case (as 4 + 8 would be optimized directly if it were adjacent).
+ // Multiple passes may be needed if we have x + 4 + 8 etc. (nested structs
+ // in C can cause this, but it's rare). Note that we only need that for the
+ // propagation case (as 4 + 8 would be optimized directly if it were
+ // adjacent).
while (1) {
propagated = false;
helperIndexes.clear();
@@ -279,22 +293,21 @@ struct OptimizeAddedConstants : public WalkerPass<PostWalker<OptimizeAddedConsta
}
}
- // For a given expression, store it to a local and return us the local index we can use,
- // in order to get that value someplace else. We are provided not the expression,
- // but the set in which it is in, as the arm of an add that is the set's value (the other
- // arm is a constant, and we are not a constant).
+ // For a given expression, store it to a local and return us the local index
+ // we can use, in order to get that value someplace else. We are provided not
+ // the expression, but the set in which it is in, as the arm of an add that is
+ // the set's value (the other arm is a constant, and we are not a constant).
// We cache these, that is, use a single one for all requests.
Index getHelperIndex(SetLocal* set) {
auto iter = helperIndexes.find(set);
if (iter != helperIndexes.end()) {
return iter->second;
}
- return helperIndexes[set] = Builder(*getModule()).addVar(getFunction(), i32);
+ return helperIndexes[set] =
+ Builder(*getModule()).addVar(getFunction(), i32);
}
- bool isPropagatable(SetLocal* set) {
- return propagatable.count(set);
- }
+ bool isPropagatable(SetLocal* set) { return propagatable.count(set); }
private:
bool propagated;
@@ -305,15 +318,16 @@ private:
std::set<SetLocal*> propagatable;
void findPropagatable() {
- // Conservatively, only propagate if all uses can be removed of the original. That is,
+ // Conservatively, only propagate if all uses can be removed of the
+ // original. That is,
// x = a + 10
// f(x)
// g(x)
// should be optimized to
// f(a, offset=10)
// g(a, offset=10)
- // but if x has other uses, then avoid doing so - we'll be doing that add anyhow, so
- // the load/store offset trick won't actually help.
+ // but if x has other uses, then avoid doing so - we'll be doing that add
+ // anyhow, so the load/store offset trick won't actually help.
Parents parents(getFunction()->body);
for (auto& pair : localGraph->locations) {
auto* location = pair.first;
@@ -323,9 +337,11 @@ private:
if (add->left->is<Const>() || add->right->is<Const>()) {
// Looks like this might be relevant, check all uses.
bool canPropagate = true;
- for (auto* get :localGraph->setInfluences[set]) {
+ for (auto* get : localGraph->setInfluences[set]) {
auto* parent = parents.getParent(get);
- assert(parent); // if this is at the top level, it's the whole body - no set can exist!
+ // if this is at the top level, it's the whole body - no set can
+ // exist!
+ assert(parent);
if (!(parent->is<Load>() || parent->is<Store>())) {
canPropagate = false;
break;
@@ -342,8 +358,8 @@ private:
}
void cleanUpAfterPropagation() {
- // Remove sets that no longer have uses. This allows further propagation by letting
- // us see the accurate amount of uses of each set.
+ // Remove sets that no longer have uses. This allows further propagation by
+ // letting us see the accurate amount of uses of each set.
UnneededSetRemover remover(getFunction(), getPassOptions());
}
@@ -354,7 +370,8 @@ private:
std::map<SetLocal*, Index>& helperIndexes;
Module* module;
- Creator(std::map<SetLocal*, Index>& helperIndexes) : helperIndexes(helperIndexes) {}
+ Creator(std::map<SetLocal*, Index>& helperIndexes)
+ : helperIndexes(helperIndexes) {}
void visitSetLocal(SetLocal* curr) {
auto iter = helperIndexes.find(curr);
@@ -372,11 +389,7 @@ private:
Builder builder(*module);
*target = builder.makeGetLocal(index, i32);
replaceCurrent(
- builder.makeSequence(
- builder.makeSetLocal(index, value),
- curr
- )
- );
+ builder.makeSequence(builder.makeSetLocal(index, value), curr));
}
}
} creator(helperIndexes);
@@ -385,13 +398,12 @@ private:
}
};
-Pass *createOptimizeAddedConstantsPass() {
+Pass* createOptimizeAddedConstantsPass() {
return new OptimizeAddedConstants(false);
}
-Pass *createOptimizeAddedConstantsPropagatePass() {
+Pass* createOptimizeAddedConstantsPropagatePass() {
return new OptimizeAddedConstants(true);
}
} // namespace wasm
-
diff --git a/src/passes/OptimizeInstructions.cpp b/src/passes/OptimizeInstructions.cpp
index c098d0ed7..8a9309554 100644
--- a/src/passes/OptimizeInstructions.cpp
+++ b/src/passes/OptimizeInstructions.cpp
@@ -20,28 +20,29 @@
#include <algorithm>
-#include <wasm.h>
-#include <pass.h>
-#include <wasm-s-parser.h>
-#include <support/threads.h>
#include <ir/abstract.h>
-#include <ir/utils.h>
#include <ir/cost.h>
#include <ir/effects.h>
-#include <ir/manipulation.h>
-#include <ir/properties.h>
#include <ir/literal-utils.h>
#include <ir/load-utils.h>
+#include <ir/manipulation.h>
+#include <ir/properties.h>
+#include <ir/utils.h>
+#include <pass.h>
+#include <support/threads.h>
+#include <wasm-s-parser.h>
+#include <wasm.h>
-// TODO: Use the new sign-extension opcodes where appropriate. This needs to be conditionalized on the availability of atomics.
+// TODO: Use the new sign-extension opcodes where appropriate. This needs to be
+// conditionalized on the availability of atomics.
namespace wasm {
-Name I32_EXPR = "i32.expr",
- I64_EXPR = "i64.expr",
- F32_EXPR = "f32.expr",
- F64_EXPR = "f64.expr",
- ANY_EXPR = "any.expr";
+Name I32_EXPR = "i32.expr";
+Name I64_EXPR = "i64.expr";
+Name F32_EXPR = "f32.expr";
+Name F64_EXPR = "f64.expr";
+Name ANY_EXPR = "any.expr";
// Utilities
@@ -53,28 +54,47 @@ template<typename LocalInfoProvider>
Index getMaxBits(Expression* curr, LocalInfoProvider* localInfoProvider) {
if (auto* const_ = curr->dynCast<Const>()) {
switch (curr->type) {
- case i32: return 32 - const_->value.countLeadingZeroes().geti32();
- case i64: return 64 - const_->value.countLeadingZeroes().geti64();
- default: WASM_UNREACHABLE();
+ case i32:
+ return 32 - const_->value.countLeadingZeroes().geti32();
+ case i64:
+ return 64 - const_->value.countLeadingZeroes().geti64();
+ default:
+ WASM_UNREACHABLE();
}
} else if (auto* binary = curr->dynCast<Binary>()) {
switch (binary->op) {
// 32-bit
- case AddInt32: case SubInt32: case MulInt32:
- case DivSInt32: case DivUInt32: case RemSInt32:
- case RemUInt32: case RotLInt32: case RotRInt32: return 32;
- case AndInt32: return std::min(getMaxBits(binary->left, localInfoProvider), getMaxBits(binary->right, localInfoProvider));
- case OrInt32: case XorInt32: return std::max(getMaxBits(binary->left, localInfoProvider), getMaxBits(binary->right, localInfoProvider));
+ case AddInt32:
+ case SubInt32:
+ case MulInt32:
+ case DivSInt32:
+ case DivUInt32:
+ case RemSInt32:
+ case RemUInt32:
+ case RotLInt32:
+ case RotRInt32:
+ return 32;
+ case AndInt32:
+ return std::min(getMaxBits(binary->left, localInfoProvider),
+ getMaxBits(binary->right, localInfoProvider));
+ case OrInt32:
+ case XorInt32:
+ return std::max(getMaxBits(binary->left, localInfoProvider),
+ getMaxBits(binary->right, localInfoProvider));
case ShlInt32: {
if (auto* shifts = binary->right->dynCast<Const>()) {
- return std::min(Index(32), getMaxBits(binary->left, localInfoProvider) + Bits::getEffectiveShifts(shifts));
+ return std::min(Index(32),
+ getMaxBits(binary->left, localInfoProvider) +
+ Bits::getEffectiveShifts(shifts));
}
return 32;
}
case ShrUInt32: {
if (auto* shift = binary->right->dynCast<Const>()) {
auto maxBits = getMaxBits(binary->left, localInfoProvider);
- auto shifts = std::min(Index(Bits::getEffectiveShifts(shift)), maxBits); // can ignore more shifts than zero us out
+ auto shifts =
+ std::min(Index(Bits::getEffectiveShifts(shift)),
+ maxBits); // can ignore more shifts than zero us out
return std::max(Index(0), maxBits - shifts);
}
return 32;
@@ -82,34 +102,67 @@ Index getMaxBits(Expression* curr, LocalInfoProvider* localInfoProvider) {
case ShrSInt32: {
if (auto* shift = binary->right->dynCast<Const>()) {
auto maxBits = getMaxBits(binary->left, localInfoProvider);
- if (maxBits == 32) return 32;
- auto shifts = std::min(Index(Bits::getEffectiveShifts(shift)), maxBits); // can ignore more shifts than zero us out
+ if (maxBits == 32)
+ return 32;
+ auto shifts =
+ std::min(Index(Bits::getEffectiveShifts(shift)),
+ maxBits); // can ignore more shifts than zero us out
return std::max(Index(0), maxBits - shifts);
}
return 32;
}
// 64-bit TODO
// comparisons
- case EqInt32: case NeInt32: case LtSInt32:
- case LtUInt32: case LeSInt32: case LeUInt32:
- case GtSInt32: case GtUInt32: case GeSInt32:
+ case EqInt32:
+ case NeInt32:
+ case LtSInt32:
+ case LtUInt32:
+ case LeSInt32:
+ case LeUInt32:
+ case GtSInt32:
+ case GtUInt32:
+ case GeSInt32:
case GeUInt32:
- case EqInt64: case NeInt64: case LtSInt64:
- case LtUInt64: case LeSInt64: case LeUInt64:
- case GtSInt64: case GtUInt64: case GeSInt64:
+ case EqInt64:
+ case NeInt64:
+ case LtSInt64:
+ case LtUInt64:
+ case LeSInt64:
+ case LeUInt64:
+ case GtSInt64:
+ case GtUInt64:
+ case GeSInt64:
case GeUInt64:
- case EqFloat32: case NeFloat32:
- case LtFloat32: case LeFloat32: case GtFloat32: case GeFloat32:
- case EqFloat64: case NeFloat64:
- case LtFloat64: case LeFloat64: case GtFloat64: case GeFloat64: return 1;
+ case EqFloat32:
+ case NeFloat32:
+ case LtFloat32:
+ case LeFloat32:
+ case GtFloat32:
+ case GeFloat32:
+ case EqFloat64:
+ case NeFloat64:
+ case LtFloat64:
+ case LeFloat64:
+ case GtFloat64:
+ case GeFloat64:
+ return 1;
default: {}
}
} else if (auto* unary = curr->dynCast<Unary>()) {
switch (unary->op) {
- case ClzInt32: case CtzInt32: case PopcntInt32: return 6;
- case ClzInt64: case CtzInt64: case PopcntInt64: return 7;
- case EqZInt32: case EqZInt64: return 1;
- case WrapInt64: return std::min(Index(32), getMaxBits(unary->value, localInfoProvider));
+ case ClzInt32:
+ case CtzInt32:
+ case PopcntInt32:
+ return 6;
+ case ClzInt64:
+ case CtzInt64:
+ case PopcntInt64:
+ return 7;
+ case EqZInt32:
+ case EqZInt64:
+ return 1;
+ case WrapInt64:
+ return std::min(Index(32), getMaxBits(unary->value, localInfoProvider));
default: {}
}
} else if (auto* set = curr->dynCast<SetLocal>()) {
@@ -125,10 +178,14 @@ Index getMaxBits(Expression* curr, LocalInfoProvider* localInfoProvider) {
}
}
switch (curr->type) {
- case i32: return 32;
- case i64: return 64;
- case unreachable: return 64; // not interesting, but don't crash
- default: WASM_UNREACHABLE();
+ case i32:
+ return 32;
+ case i64:
+ return 64;
+ case unreachable:
+ return 64; // not interesting, but don't crash
+ default:
+ WASM_UNREACHABLE();
}
}
@@ -170,9 +227,11 @@ struct LocalScanner : PostWalker<LocalScanner> {
void visitSetLocal(SetLocal* curr) {
auto* func = getFunction();
- if (func->isParam(curr->index)) return;
+ if (func->isParam(curr->index))
+ return;
auto type = getFunction()->getLocalType(curr->index);
- if (type != i32 && type != i64) return;
+ if (type != i32 && type != i64)
+ return;
// an integer var, worth processing
auto* value = Properties::getFallthrough(curr->value);
auto& info = localInfo[curr->index];
@@ -188,26 +247,32 @@ struct LocalScanner : PostWalker<LocalScanner> {
if (info.signExtedBits == 0) {
info.signExtedBits = signExtBits; // first info we see
} else if (info.signExtedBits != signExtBits) {
- info.signExtedBits = LocalInfo::kUnknown; // contradictory information, give up
+ // contradictory information, give up
+ info.signExtedBits = LocalInfo::kUnknown;
}
}
- // define this for the templated getMaxBits method. we know nothing here yet about locals, so return the maxes
- Index getMaxBitsForLocal(GetLocal* get) {
- return getBitsForType(get->type);
- }
+ // define this for the templated getMaxBits method. we know nothing here yet
+ // about locals, so return the maxes
+ Index getMaxBitsForLocal(GetLocal* get) { return getBitsForType(get->type); }
Index getBitsForType(Type type) {
switch (type) {
- case i32: return 32;
- case i64: return 64;
- default: return -1;
+ case i32:
+ return 32;
+ case i64:
+ return 64;
+ default:
+ return -1;
}
}
};
// Main pass class
-struct OptimizeInstructions : public WalkerPass<PostWalker<OptimizeInstructions, UnifiedExpressionVisitor<OptimizeInstructions>>> {
+struct OptimizeInstructions
+ : public WalkerPass<
+ PostWalker<OptimizeInstructions,
+ UnifiedExpressionVisitor<OptimizeInstructions>>> {
bool isFunctionParallel() override { return true; }
Pass* create() override { return new OptimizeInstructions; }
@@ -229,7 +294,8 @@ struct OptimizeInstructions : public WalkerPass<PostWalker<OptimizeInstructions,
}
void visitExpression(Expression* curr) {
- // we may be able to apply multiple patterns, one may open opportunities that look deeper NB: patterns must not have cycles
+ // we may be able to apply multiple patterns, one may open opportunities
+ // that look deeper NB: patterns must not have cycles
while (1) {
auto* handOptimized = handOptimize(curr);
if (handOptimized) {
@@ -258,14 +324,15 @@ struct OptimizeInstructions : public WalkerPass<PostWalker<OptimizeInstructions,
}
}
- // Optimizations that don't yet fit in the pattern DSL, but could be eventually maybe
+ // Optimizations that don't yet fit in the pattern DSL, but could be
+ // eventually maybe
Expression* handOptimize(Expression* curr) {
// if this contains dead code, don't bother trying to optimize it, the type
- // might change (if might not be unreachable if just one arm is, for example).
- // this optimization pass focuses on actually executing code. the only
- // exceptions are control flow changes
- if (curr->type == unreachable &&
- !curr->is<Break>() && !curr->is<Switch>() && !curr->is<If>()) {
+ // might change (if might not be unreachable if just one arm is, for
+ // example). this optimization pass focuses on actually executing code. the
+ // only exceptions are control flow changes
+ if (curr->type == unreachable && !curr->is<Break>() &&
+ !curr->is<Switch>() && !curr->is<If>()) {
return nullptr;
}
if (auto* binary = curr->dynCast<Binary>()) {
@@ -277,10 +344,13 @@ struct OptimizeInstructions : public WalkerPass<PostWalker<OptimizeInstructions,
auto bits = Properties::getAlmostSignExtBits(binary, extraShifts);
if (extraShifts == 0) {
if (auto* load = Properties::getFallthrough(ext)->dynCast<Load>()) {
- // pattern match a load of 8 bits and a sign extend using a shl of 24 then shr_s of 24 as well, etc.
+ // pattern match a load of 8 bits and a sign extend using a shl of
+ // 24 then shr_s of 24 as well, etc.
if (LoadUtils::canBeSigned(load) &&
- ((load->bytes == 1 && bits == 8) || (load->bytes == 2 && bits == 16))) {
- // if the value falls through, we can't alter the load, as it might be captured in a tee
+ ((load->bytes == 1 && bits == 8) ||
+ (load->bytes == 2 && bits == 16))) {
+ // if the value falls through, we can't alter the load, as it
+ // might be captured in a tee
if (load->signed_ == true || load == ext) {
load->signed_ = true;
return ext;
@@ -289,8 +359,10 @@ struct OptimizeInstructions : public WalkerPass<PostWalker<OptimizeInstructions,
}
}
// if the sign-extend input cannot have a sign bit, we don't need it
- // we also don't need it if it already has an identical-sized sign extend
- if (getMaxBits(ext, this) + extraShifts < bits || isSignExted(ext, bits)) {
+ // we also don't need it if it already has an identical-sized sign
+ // extend
+ if (getMaxBits(ext, this) + extraShifts < bits ||
+ isSignExted(ext, bits)) {
return removeAlmostSignExt(binary);
}
} else if (binary->op == EqInt32 || binary->op == NeInt32) {
@@ -300,34 +372,44 @@ struct OptimizeInstructions : public WalkerPass<PostWalker<OptimizeInstructions,
return Builder(*getModule()).makeUnary(EqZInt32, binary->left);
}
if (auto* ext = Properties::getSignExtValue(binary->left)) {
- // we are comparing a sign extend to a constant, which means we can use a cheaper zext
+ // we are comparing a sign extend to a constant, which means we can
+ // use a cheaper zext
auto bits = Properties::getSignExtBits(binary->left);
binary->left = makeZeroExt(ext, bits);
- // when we replace the sign-ext of the non-constant with a zero-ext, we are forcing
- // the high bits to be all zero, instead of all zero or all one depending on the
- // sign bit. so we may be changing the high bits from all one to all zero:
- // * if the constant value's higher bits are mixed, then it can't be equal anyhow
- // * if they are all zero, we may get a false true if the non-constant's upper bits
- // were one. this can only happen if the non-constant's sign bit is set, so this
- // false true is a risk only if the constant's sign bit is set (otherwise, false).
- // But a constant with a sign bit but with upper bits zero is impossible to be
- // equal to a sign-extended value anyhow, so the entire thing is false.
- // * if they were all one, we may get a false false, if the only difference is in
- // those upper bits. that means we are equal on the other bits, including the sign
- // bit. so we can just mask off the upper bits in the constant value, in this
- // case, forcing them to zero like we do in the zero-extend.
+ // when we replace the sign-ext of the non-constant with a zero-ext,
+ // we are forcing the high bits to be all zero, instead of all zero
+ // or all one depending on the sign bit. so we may be changing the
+ // high bits from all one to all zero:
+ // * if the constant value's higher bits are mixed, then it can't
+ // be equal anyhow
+ // * if they are all zero, we may get a false true if the
+ // non-constant's upper bits were one. this can only happen if
+ // the non-constant's sign bit is set, so this false true is a
+ // risk only if the constant's sign bit is set (otherwise,
+ // false). But a constant with a sign bit but with upper bits
+ // zero is impossible to be equal to a sign-extended value
+ // anyhow, so the entire thing is false.
+ // * if they were all one, we may get a false false, if the only
+ // difference is in those upper bits. that means we are equal on
+ // the other bits, including the sign bit. so we can just mask
+ // off the upper bits in the constant value, in this case,
+ // forcing them to zero like we do in the zero-extend.
int32_t constValue = c->value.geti32();
auto upperConstValue = constValue & ~Bits::lowBitMask(bits);
uint32_t count = PopCount(upperConstValue);
auto constSignBit = constValue & (1 << (bits - 1));
- if ((count > 0 && count < 32 - bits) || (constSignBit && count == 0)) {
- // mixed or [zero upper const bits with sign bit set]; the compared values can never be identical, so
- // force something definitely impossible even after zext
+ if ((count > 0 && count < 32 - bits) ||
+ (constSignBit && count == 0)) {
+ // mixed or [zero upper const bits with sign bit set]; the
+ // compared values can never be identical, so force something
+ // definitely impossible even after zext
assert(bits < 32);
c->value = Literal(int32_t(0x80000000));
- // TODO: if no side effects, we can just replace it all with 1 or 0
+ // TODO: if no side effects, we can just replace it all with 1 or
+ // 0
} else {
- // otherwise, they are all ones, so we can mask them off as mentioned before
+ // otherwise, they are all ones, so we can mask them off as
+ // mentioned before
c->value = c->value.and_(Literal(Bits::lowBitMask(bits)));
}
return binary;
@@ -336,13 +418,15 @@ struct OptimizeInstructions : public WalkerPass<PostWalker<OptimizeInstructions,
if (auto* right = Properties::getSignExtValue(binary->right)) {
auto bits = Properties::getSignExtBits(binary->left);
if (Properties::getSignExtBits(binary->right) == bits) {
- // we are comparing two sign-exts with the same bits, so we may as well replace both with cheaper zexts
+ // we are comparing two sign-exts with the same bits, so we may as
+ // well replace both with cheaper zexts
binary->left = makeZeroExt(left, bits);
binary->right = makeZeroExt(right, bits);
return binary;
}
} else if (auto* load = binary->right->dynCast<Load>()) {
- // we are comparing a load to a sign-ext, we may be able to switch to zext
+ // we are comparing a load to a sign-ext, we may be able to switch
+ // to zext
auto leftBits = Properties::getSignExtBits(binary->left);
if (load->signed_ && leftBits == load->bytes * 8) {
load->signed_ = false;
@@ -352,7 +436,8 @@ struct OptimizeInstructions : public WalkerPass<PostWalker<OptimizeInstructions,
}
} else if (auto* load = binary->left->dynCast<Load>()) {
if (auto* right = Properties::getSignExtValue(binary->right)) {
- // we are comparing a load to a sign-ext, we may be able to switch to zext
+ // we are comparing a load to a sign-ext, we may be able to switch
+ // to zext
auto rightBits = Properties::getSignExtBits(binary->right);
if (load->signed_ && rightBits == load->bytes * 8) {
load->signed_ = false;
@@ -361,7 +446,8 @@ struct OptimizeInstructions : public WalkerPass<PostWalker<OptimizeInstructions,
}
}
}
- // note that both left and right may be consts, but then we let precompute compute the constant result
+ // note that both left and right may be consts, but then we let
+ // precompute compute the constant result
} else if (binary->op == AddInt32) {
// try to get rid of (0 - ..), that is, a zero only used to negate an
// int. an add of a subtract can be flipped in order to remove it:
@@ -382,7 +468,8 @@ struct OptimizeInstructions : public WalkerPass<PostWalker<OptimizeInstructions,
if (sub->op == SubInt32) {
if (auto* subZero = sub->left->dynCast<Const>()) {
if (subZero->value.geti32() == 0) {
- if (EffectAnalyzer::canReorder(getPassOptions(), sub->right, binary->right)) {
+ if (EffectAnalyzer::canReorder(
+ getPassOptions(), sub->right, binary->right)) {
sub->left = binary->right;
return sub;
}
@@ -414,10 +501,12 @@ struct OptimizeInstructions : public WalkerPass<PostWalker<OptimizeInstructions,
}
}
auto* ret = optimizeAddedConstants(binary);
- if (ret) return ret;
+ if (ret)
+ return ret;
} else if (binary->op == SubInt32) {
auto* ret = optimizeAddedConstants(binary);
- if (ret) return ret;
+ if (ret)
+ return ret;
}
// a bunch of operations on a constant right side can be simplified
if (auto* right = binary->right->dynCast<Const>()) {
@@ -443,7 +532,8 @@ struct OptimizeInstructions : public WalkerPass<PostWalker<OptimizeInstructions,
}
// some math operations have trivial results
Expression* ret = optimizeWithConstantOnRight(binary);
- if (ret) return ret;
+ if (ret)
+ return ret;
// the square of some operations can be merged
if (auto* left = binary->left->dynCast<Binary>()) {
if (left->op == binary->op) {
@@ -454,11 +544,13 @@ struct OptimizeInstructions : public WalkerPass<PostWalker<OptimizeInstructions,
} else if (left->op == OrInt32) {
leftRight->value = leftRight->value.or_(right->value);
return left;
- } else if (left->op == ShlInt32 || left->op == ShrUInt32 || left->op == ShrSInt32 ||
- left->op == ShlInt64 || left->op == ShrUInt64 || left->op == ShrSInt64) {
- // shifts only use an effective amount from the constant, so adding must
- // be done carefully
- auto total = Bits::getEffectiveShifts(leftRight) + Bits::getEffectiveShifts(right);
+ } else if (left->op == ShlInt32 || left->op == ShrUInt32 ||
+ left->op == ShrSInt32 || left->op == ShlInt64 ||
+ left->op == ShrUInt64 || left->op == ShrSInt64) {
+ // shifts only use an effective amount from the constant, so
+ // adding must be done carefully
+ auto total = Bits::getEffectiveShifts(leftRight) +
+ Bits::getEffectiveShifts(right);
if (total == Bits::getEffectiveShifts(total, right->type)) {
// no overflow, we can do this
leftRight->value = Literal::makeFromInt32(total, right->type);
@@ -483,7 +575,8 @@ struct OptimizeInstructions : public WalkerPass<PostWalker<OptimizeInstructions,
// a bunch of operations on a constant left side can be simplified
if (binary->left->is<Const>()) {
Expression* ret = optimizeWithConstantOnLeft(binary);
- if (ret) return ret;
+ if (ret)
+ return ret;
}
// bitwise operations
if (binary->op == AndInt32) {
@@ -540,40 +633,89 @@ struct OptimizeInstructions : public WalkerPass<PostWalker<OptimizeInstructions,
if (unary->op == EqZInt32) {
if (auto* inner = unary->value->dynCast<Binary>()) {
switch (inner->op) {
- case EqInt32: inner->op = NeInt32; return inner;
- case NeInt32: inner->op = EqInt32; return inner;
- case LtSInt32: inner->op = GeSInt32; return inner;
- case LtUInt32: inner->op = GeUInt32; return inner;
- case LeSInt32: inner->op = GtSInt32; return inner;
- case LeUInt32: inner->op = GtUInt32; return inner;
- case GtSInt32: inner->op = LeSInt32; return inner;
- case GtUInt32: inner->op = LeUInt32; return inner;
- case GeSInt32: inner->op = LtSInt32; return inner;
- case GeUInt32: inner->op = LtUInt32; return inner;
+ case EqInt32:
+ inner->op = NeInt32;
+ return inner;
+ case NeInt32:
+ inner->op = EqInt32;
+ return inner;
+ case LtSInt32:
+ inner->op = GeSInt32;
+ return inner;
+ case LtUInt32:
+ inner->op = GeUInt32;
+ return inner;
+ case LeSInt32:
+ inner->op = GtSInt32;
+ return inner;
+ case LeUInt32:
+ inner->op = GtUInt32;
+ return inner;
+ case GtSInt32:
+ inner->op = LeSInt32;
+ return inner;
+ case GtUInt32:
+ inner->op = LeUInt32;
+ return inner;
+ case GeSInt32:
+ inner->op = LtSInt32;
+ return inner;
+ case GeUInt32:
+ inner->op = LtUInt32;
+ return inner;
- case EqInt64: inner->op = NeInt64; return inner;
- case NeInt64: inner->op = EqInt64; return inner;
- case LtSInt64: inner->op = GeSInt64; return inner;
- case LtUInt64: inner->op = GeUInt64; return inner;
- case LeSInt64: inner->op = GtSInt64; return inner;
- case LeUInt64: inner->op = GtUInt64; return inner;
- case GtSInt64: inner->op = LeSInt64; return inner;
- case GtUInt64: inner->op = LeUInt64; return inner;
- case GeSInt64: inner->op = LtSInt64; return inner;
- case GeUInt64: inner->op = LtUInt64; return inner;
+ case EqInt64:
+ inner->op = NeInt64;
+ return inner;
+ case NeInt64:
+ inner->op = EqInt64;
+ return inner;
+ case LtSInt64:
+ inner->op = GeSInt64;
+ return inner;
+ case LtUInt64:
+ inner->op = GeUInt64;
+ return inner;
+ case LeSInt64:
+ inner->op = GtSInt64;
+ return inner;
+ case LeUInt64:
+ inner->op = GtUInt64;
+ return inner;
+ case GtSInt64:
+ inner->op = LeSInt64;
+ return inner;
+ case GtUInt64:
+ inner->op = LeUInt64;
+ return inner;
+ case GeSInt64:
+ inner->op = LtSInt64;
+ return inner;
+ case GeUInt64:
+ inner->op = LtUInt64;
+ return inner;
- case EqFloat32: inner->op = NeFloat32; return inner;
- case NeFloat32: inner->op = EqFloat32; return inner;
+ case EqFloat32:
+ inner->op = NeFloat32;
+ return inner;
+ case NeFloat32:
+ inner->op = EqFloat32;
+ return inner;
- case EqFloat64: inner->op = NeFloat64; return inner;
- case NeFloat64: inner->op = EqFloat64; return inner;
+ case EqFloat64:
+ inner->op = NeFloat64;
+ return inner;
+ case NeFloat64:
+ inner->op = EqFloat64;
+ return inner;
default: {}
}
}
// eqz of a sign extension can be of zero-extension
if (auto* ext = Properties::getSignExtValue(unary->value)) {
- // we are comparing a sign extend to a constant, which means we can use a cheaper zext
+ // we are comparing a sign extend to a constant, which means we can
+ // use a cheaper zext
auto bits = Properties::getSignExtBits(unary->value);
unary->value = makeZeroExt(ext, bits);
return unary;
@@ -595,24 +737,26 @@ struct OptimizeInstructions : public WalkerPass<PostWalker<OptimizeInstructions,
std::swap(iff->ifTrue, iff->ifFalse);
}
}
- if (iff->condition->type != unreachable && ExpressionAnalyzer::equal(iff->ifTrue, iff->ifFalse)) {
+ if (iff->condition->type != unreachable &&
+ ExpressionAnalyzer::equal(iff->ifTrue, iff->ifFalse)) {
// sides are identical, fold
- // if we can replace the if with one arm, and no side effects in the condition, do that
- auto needCondition = EffectAnalyzer(getPassOptions(), iff->condition).hasSideEffects();
+ // if we can replace the if with one arm, and no side effects in the
+ // condition, do that
+ auto needCondition =
+ EffectAnalyzer(getPassOptions(), iff->condition).hasSideEffects();
auto typeIsIdentical = iff->ifTrue->type == iff->type;
if (typeIsIdentical && !needCondition) {
return iff->ifTrue;
} else {
Builder builder(*getModule());
if (typeIsIdentical) {
- return builder.makeSequence(
- builder.makeDrop(iff->condition),
- iff->ifTrue
- );
+ return builder.makeSequence(builder.makeDrop(iff->condition),
+ iff->ifTrue);
} else {
- // the types diff. as the condition is reachable, that means the if must be
- // concrete while the arm is not
- assert(isConcreteType(iff->type) && iff->ifTrue->type == unreachable);
+ // the types diff. as the condition is reachable, that means the
+ // if must be concrete while the arm is not
+ assert(isConcreteType(iff->type) &&
+ iff->ifTrue->type == unreachable);
// emit a block with a forced type
auto* ret = builder.makeBlock();
if (needCondition) {
@@ -638,22 +782,24 @@ struct OptimizeInstructions : public WalkerPass<PostWalker<OptimizeInstructions,
}
}
if (auto* c = select->condition->dynCast<Const>()) {
- // constant condition, we can just pick the right side (barring side effects)
+ // constant condition, we can just pick the right side (barring side
+ // effects)
if (c->value.getInteger()) {
- if (!EffectAnalyzer(getPassOptions(), select->ifFalse).hasSideEffects()) {
+ if (!EffectAnalyzer(getPassOptions(), select->ifFalse)
+ .hasSideEffects()) {
return select->ifTrue;
} else {
- // don't bother - we would need to reverse the order using a temp local, which is bad
+ // don't bother - we would need to reverse the order using a temp
+ // local, which is bad
}
} else {
- if (!EffectAnalyzer(getPassOptions(), select->ifTrue).hasSideEffects()) {
+ if (!EffectAnalyzer(getPassOptions(), select->ifTrue)
+ .hasSideEffects()) {
return select->ifFalse;
} else {
Builder builder(*getModule());
- return builder.makeSequence(
- builder.makeDrop(select->ifTrue),
- select->ifFalse
- );
+ return builder.makeSequence(builder.makeDrop(select->ifTrue),
+ select->ifFalse);
}
}
}
@@ -676,10 +822,8 @@ struct OptimizeInstructions : public WalkerPass<PostWalker<OptimizeInstructions,
// can reorder
if (!condition.invalidates(value)) {
Builder builder(*getModule());
- return builder.makeSequence(
- builder.makeDrop(select->condition),
- select->ifTrue
- );
+ return builder.makeSequence(builder.makeDrop(select->condition),
+ select->ifTrue);
}
}
}
@@ -705,8 +849,9 @@ struct OptimizeInstructions : public WalkerPass<PostWalker<OptimizeInstructions,
}
}
} else if (auto* ext = Properties::getSignExtValue(binary)) {
- // if sign extending the exact bit size we store, we can skip the extension
- // if extending something bigger, then we just alter bits we don't save anyhow
+ // if sign extending the exact bit size we store, we can skip the
+ // extension if extending something bigger, then we just alter bits we
+ // don't save anyhow
if (Properties::getSignExtBits(binary) >= Index(store->bytes) * 8) {
store->value = ext;
}
@@ -736,11 +881,13 @@ private:
void canonicalize(Binary* binary) {
assert(Properties::isSymmetric(binary));
auto swap = [&]() {
- assert(EffectAnalyzer::canReorder(getPassOptions(), binary->left, binary->right));
+ assert(EffectAnalyzer::canReorder(
+ getPassOptions(), binary->left, binary->right));
std::swap(binary->left, binary->right);
};
auto maybeSwap = [&]() {
- if (EffectAnalyzer::canReorder(getPassOptions(), binary->left, binary->right)) {
+ if (EffectAnalyzer::canReorder(
+ getPassOptions(), binary->left, binary->right)) {
swap();
}
};
@@ -748,7 +895,8 @@ private:
if (binary->left->is<Const>() && !binary->right->is<Const>()) {
return swap();
}
- if (binary->right->is<Const>()) return;
+ if (binary->right->is<Const>())
+ return;
// Prefer a get on the right.
if (binary->left->is<GetLocal>() && !binary->right->is<GetLocal>()) {
return maybeSwap();
@@ -793,7 +941,8 @@ private:
}
} else if (auto* binary = boolean->dynCast<Binary>()) {
if (binary->op == OrInt32) {
- // an or flowing into a boolean context can consider each input as boolean
+ // an or flowing into a boolean context can consider each input as
+ // boolean
binary->left = optimizeBoolean(binary->left);
binary->right = optimizeBoolean(binary->right);
} else if (binary->op == NeInt32) {
@@ -805,7 +954,8 @@ private:
}
}
if (auto* ext = Properties::getSignExtValue(binary)) {
- // use a cheaper zero-extent, we just care about the boolean value anyhow
+ // use a cheaper zero-extent, we just care about the boolean value
+ // anyhow
return makeZeroExt(ext, Properties::getSignExtBits(binary));
}
} else if (auto* block = boolean->dynCast<Block>()) {
@@ -822,12 +972,14 @@ private:
return boolean;
}
- // find added constants in an expression tree, including multiplied/shifted, and combine them
- // note that we ignore division/shift-right, as rounding makes this nonlinear, so not a valid opt
+ // find added constants in an expression tree, including multiplied/shifted,
+ // and combine them note that we ignore division/shift-right, as rounding
+ // makes this nonlinear, so not a valid opt
Expression* optimizeAddedConstants(Binary* binary) {
uint32_t constant = 0;
std::vector<Const*> constants;
- std::function<void (Expression*, int)> seek = [&](Expression* curr, int mul) {
+ std::function<void(Expression*, int)> seek = [&](Expression* curr,
+ int mul) {
if (auto* c = curr->dynCast<Const>()) {
uint32_t value = c->value.geti32();
if (value != 0) {
@@ -867,7 +1019,8 @@ private:
// find all factors
seek(binary, 1);
if (constants.size() <= 1) {
- // nothing much to do, except for the trivial case of adding/subbing a zero
+ // nothing much to do, except for the trivial case of adding/subbing a
+ // zero
if (auto* c = binary->right->dynCast<Const>()) {
if (c->value.geti32() == 0) {
return binary->left;
@@ -906,19 +1059,24 @@ private:
return;
}
} else if (curr->op == ShlInt32) {
- // shifting a 0 is a 0, or anything by 0 has no effect, all unless the shift has side effects
- if (((left && left->value.geti32() == 0) || (right && Bits::getEffectiveShifts(right) == 0)) &&
+ // shifting a 0 is a 0, or anything by 0 has no effect, all unless the
+ // shift has side effects
+ if (((left && left->value.geti32() == 0) ||
+ (right && Bits::getEffectiveShifts(right) == 0)) &&
!EffectAnalyzer(passOptions, curr->right).hasSideEffects()) {
replaceCurrent(curr->left);
return;
}
} else if (curr->op == MulInt32) {
- // multiplying by zero is a zero, unless the other side has side effects
- if (left && left->value.geti32() == 0 && !EffectAnalyzer(passOptions, curr->right).hasSideEffects()) {
+ // multiplying by zero is a zero, unless the other side has side
+ // effects
+ if (left && left->value.geti32() == 0 &&
+ !EffectAnalyzer(passOptions, curr->right).hasSideEffects()) {
replaceCurrent(left);
return;
}
- if (right && right->value.geti32() == 0 && !EffectAnalyzer(passOptions, curr->left).hasSideEffects()) {
+ if (right && right->value.geti32() == 0 &&
+ !EffectAnalyzer(passOptions, curr->left).hasSideEffects()) {
replaceCurrent(right);
return;
}
@@ -927,50 +1085,58 @@ private:
};
Expression* walked = binary;
ZeroRemover(getPassOptions()).walk(walked);
- if (constant == 0) return walked; // nothing more to do
+ if (constant == 0)
+ return walked; // nothing more to do
if (auto* c = walked->dynCast<Const>()) {
assert(c->value.geti32() == 0);
c->value = Literal(constant);
return c;
}
Builder builder(*getModule());
- return builder.makeBinary(AddInt32,
- walked,
- builder.makeConst(Literal(constant))
- );
+ return builder.makeBinary(
+ AddInt32, walked, builder.makeConst(Literal(constant)));
}
- // expensive1 | expensive2 can be turned into expensive1 ? 1 : expensive2, and
- // expensive | cheap can be turned into cheap ? 1 : expensive,
+ // expensive1 | expensive2 can be turned into expensive1 ? 1 : expensive2,
+ // and expensive | cheap can be turned into cheap ? 1 : expensive,
// so that we can avoid one expensive computation, if it has no side effects.
Expression* conditionalizeExpensiveOnBitwise(Binary* binary) {
// this operation can increase code size, so don't always do it
auto& options = getPassRunner()->options;
- if (options.optimizeLevel < 2 || options.shrinkLevel > 0) return nullptr;
+ if (options.optimizeLevel < 2 || options.shrinkLevel > 0)
+ return nullptr;
const auto MIN_COST = 7;
assert(binary->op == AndInt32 || binary->op == OrInt32);
- if (binary->right->is<Const>()) return nullptr; // trivial
- // bitwise logical operator on two non-numerical values, check if they are boolean
+ if (binary->right->is<Const>())
+ return nullptr; // trivial
+ // bitwise logical operator on two non-numerical values, check if they are
+ // boolean
auto* left = binary->left;
auto* right = binary->right;
- if (!Properties::emitsBoolean(left) || !Properties::emitsBoolean(right)) return nullptr;
+ if (!Properties::emitsBoolean(left) || !Properties::emitsBoolean(right))
+ return nullptr;
auto leftEffects = EffectAnalyzer(getPassOptions(), left);
auto rightEffects = EffectAnalyzer(getPassOptions(), right);
auto leftHasSideEffects = leftEffects.hasSideEffects();
auto rightHasSideEffects = rightEffects.hasSideEffects();
- if (leftHasSideEffects && rightHasSideEffects) return nullptr; // both must execute
+ if (leftHasSideEffects && rightHasSideEffects)
+ return nullptr; // both must execute
// canonicalize with side effects, if any, happening on the left
if (rightHasSideEffects) {
- if (CostAnalyzer(left).cost < MIN_COST) return nullptr; // avoidable code is too cheap
- if (leftEffects.invalidates(rightEffects)) return nullptr; // cannot reorder
+ if (CostAnalyzer(left).cost < MIN_COST)
+ return nullptr; // avoidable code is too cheap
+ if (leftEffects.invalidates(rightEffects))
+ return nullptr; // cannot reorder
std::swap(left, right);
} else if (leftHasSideEffects) {
- if (CostAnalyzer(right).cost < MIN_COST) return nullptr; // avoidable code is too cheap
+ if (CostAnalyzer(right).cost < MIN_COST)
+ return nullptr; // avoidable code is too cheap
} else {
// no side effects, reorder based on cost estimation
auto leftCost = CostAnalyzer(left).cost;
auto rightCost = CostAnalyzer(right).cost;
- if (std::max(leftCost, rightCost) < MIN_COST) return nullptr; // avoidable code is too cheap
+ if (std::max(leftCost, rightCost) < MIN_COST)
+ return nullptr; // avoidable code is too cheap
// canonicalize with expensive code on the right
if (leftCost > rightCost) {
std::swap(left, right);
@@ -979,9 +1145,11 @@ private:
// worth it! perform conditionalization
Builder builder(*getModule());
if (binary->op == OrInt32) {
- return builder.makeIf(left, builder.makeConst(Literal(int32_t(1))), right);
+ return builder.makeIf(
+ left, builder.makeConst(Literal(int32_t(1))), right);
} else { // &
- return builder.makeIf(left, right, builder.makeConst(Literal(int32_t(0))));
+ return builder.makeIf(
+ left, right, builder.makeConst(Literal(int32_t(0))));
}
}
@@ -1015,8 +1183,9 @@ private:
// fold constant factors into the offset
void optimizeMemoryAccess(Expression*& ptr, Address& offset) {
- // ptr may be a const, but it isn't worth folding that in (we still have a const); in fact,
- // it's better to do the opposite for gzip purposes as well as for readability.
+ // ptr may be a const, but it isn't worth folding that in (we still have a
+ // const); in fact, it's better to do the opposite for gzip purposes as well
+ // as for readability.
auto* last = ptr->dynCast<Const>();
if (last) {
// don't do this if it would wrap the pointer
@@ -1058,7 +1227,8 @@ private:
Expression* makeZeroExt(Expression* curr, int32_t bits) {
Builder builder(*getModule());
- return builder.makeBinary(AndInt32, curr, builder.makeConst(Literal(Bits::lowBitMask(bits))));
+ return builder.makeBinary(
+ AndInt32, curr, builder.makeConst(Literal(Bits::lowBitMask(bits))));
}
// given an "almost" sign extend - either a proper one, or it
@@ -1070,7 +1240,8 @@ private:
auto* outerConst = outer->right->cast<Const>();
auto* innerConst = inner->right->cast<Const>();
auto* value = inner->left;
- if (outerConst->value == innerConst->value) return value;
+ if (outerConst->value == innerConst->value)
+ return value;
// add a shift, by reusing the existing node
innerConst->value = innerConst->value.sub(outerConst->value);
return inner;
@@ -1105,7 +1276,8 @@ private:
return binary->left;
} else if ((binary->op == Abstract::getBinary(type, Abstract::Mul) ||
binary->op == Abstract::getBinary(type, Abstract::And)) &&
- !EffectAnalyzer(getPassOptions(), binary->left).hasSideEffects()) {
+ !EffectAnalyzer(getPassOptions(), binary->left)
+ .hasSideEffects()) {
return binary->right;
}
}
@@ -1116,7 +1288,8 @@ private:
if (binary->op == Abstract::getBinary(type, Abstract::And)) {
return binary->left;
} else if (binary->op == Abstract::getBinary(type, Abstract::Or) &&
- !EffectAnalyzer(getPassOptions(), binary->left).hasSideEffects()) {
+ !EffectAnalyzer(getPassOptions(), binary->left)
+ .hasSideEffects()) {
return binary->right;
}
}
@@ -1129,15 +1302,10 @@ private:
if (binary->op == Abstract::getBinary(type, Abstract::Add) ||
binary->op == Abstract::getBinary(type, Abstract::Sub)) {
auto value = right->value.getInteger();
- if (value == 0x40 ||
- value == 0x2000 ||
- value == 0x100000 ||
- value == 0x8000000 ||
- value == 0x400000000LL ||
- value == 0x20000000000LL ||
- value == 0x1000000000000LL ||
- value == 0x80000000000000LL ||
- value == 0x4000000000000000LL) {
+ if (value == 0x40 || value == 0x2000 || value == 0x100000 ||
+ value == 0x8000000 || value == 0x400000000LL ||
+ value == 0x20000000000LL || value == 0x1000000000000LL ||
+ value == 0x80000000000000LL || value == 0x4000000000000000LL) {
right->value = right->value.neg();
if (binary->op == Abstract::getBinary(type, Abstract::Add)) {
binary->op = Abstract::getBinary(type, Abstract::Sub);
@@ -1202,12 +1370,16 @@ private:
left->op == Abstract::getBinary(type, Abstract::Sub)) {
if (auto* leftConst = left->right->dynCast<Const>()) {
if (auto* rightConst = binary->right->dynCast<Const>()) {
- return combineRelationalConstants(binary, left, leftConst, nullptr, rightConst);
+ return combineRelationalConstants(
+ binary, left, leftConst, nullptr, rightConst);
} else if (auto* rightBinary = binary->right->dynCast<Binary>()) {
- if (rightBinary->op == Abstract::getBinary(type, Abstract::Add) ||
- rightBinary->op == Abstract::getBinary(type, Abstract::Sub)) {
+ if (rightBinary->op ==
+ Abstract::getBinary(type, Abstract::Add) ||
+ rightBinary->op ==
+ Abstract::getBinary(type, Abstract::Sub)) {
if (auto* rightConst = rightBinary->right->dynCast<Const>()) {
- return combineRelationalConstants(binary, left, leftConst, rightBinary, rightConst);
+ return combineRelationalConstants(
+ binary, left, leftConst, rightBinary, rightConst);
}
}
}
@@ -1220,9 +1392,13 @@ private:
}
// given a relational binary with a const on both sides, combine the constants
- // left is also a binary, and has a constant; right may be just a constant, in which
- // case right is nullptr
- Expression* combineRelationalConstants(Binary* binary, Binary* left, Const* leftConst, Binary* right, Const* rightConst) {
+ // left is also a binary, and has a constant; right may be just a constant, in
+ // which case right is nullptr
+ Expression* combineRelationalConstants(Binary* binary,
+ Binary* left,
+ Const* leftConst,
+ Binary* right,
+ Const* rightConst) {
auto type = binary->right->type;
// we fold constants to the right
Literal extra = leftConst->value;
@@ -1237,8 +1413,8 @@ private:
return binary;
}
- // given a binary expression with equal children and no side effects in either,
- // we can fold various things
+ // given a binary expression with equal children and no side effects in
+ // either, we can fold various things
// TODO: trinaries, things like (x & (y & x)) ?
Expression* optimizeBinaryWithEqualEffectlessChildren(Binary* binary) {
// TODO add: perhaps worth doing 2*x if x is quite large?
@@ -1246,7 +1422,8 @@ private:
case SubInt32:
case XorInt32:
case SubInt64:
- case XorInt64: return LiteralUtils::makeZero(binary->left->type, *getModule());
+ case XorInt64:
+ return LiteralUtils::makeZero(binary->left->type, *getModule());
case NeInt64:
case LtSInt64:
case LtUInt64:
@@ -1256,11 +1433,13 @@ private:
case LtSInt32:
case LtUInt32:
case GtSInt32:
- case GtUInt32: return LiteralUtils::makeZero(i32, *getModule());
+ case GtUInt32:
+ return LiteralUtils::makeZero(i32, *getModule());
case AndInt32:
case OrInt32:
case AndInt64:
- case OrInt64: return binary->left;
+ case OrInt64:
+ return binary->left;
case EqInt32:
case LeSInt32:
case LeUInt32:
@@ -1270,14 +1449,14 @@ private:
case LeSInt64:
case LeUInt64:
case GeSInt64:
- case GeUInt64: return LiteralUtils::makeFromInt32(1, i32, *getModule());
- default: return nullptr;
+ case GeUInt64:
+ return LiteralUtils::makeFromInt32(1, i32, *getModule());
+ default:
+ return nullptr;
}
}
};
-Pass *createOptimizeInstructionsPass() {
- return new OptimizeInstructions();
-}
+Pass* createOptimizeInstructionsPass() { return new OptimizeInstructions(); }
} // namespace wasm
diff --git a/src/passes/PickLoadSigns.cpp b/src/passes/PickLoadSigns.cpp
index fce50b4bb..f494159a1 100644
--- a/src/passes/PickLoadSigns.cpp
+++ b/src/passes/PickLoadSigns.cpp
@@ -14,9 +14,9 @@
* limitations under the License.
*/
-#include <wasm.h>
-#include <pass.h>
#include <ir/properties.h>
+#include <pass.h>
+#include <wasm.h>
namespace wasm {
@@ -39,7 +39,8 @@ struct PickLoadSigns : public WalkerPass<ExpressionStackWalker<PickLoadSigns>> {
};
std::vector<Usage> usages; // local index => usage
- std::unordered_map<Load*, Index> loads; // loads that write to a local => the local
+ // loads that write to a local => the local
+ std::unordered_map<Load*, Index> loads;
void doWalkFunction(Function* func) {
// prepare
@@ -51,7 +52,8 @@ struct PickLoadSigns : public WalkerPass<ExpressionStackWalker<PickLoadSigns>> {
}
void visitGetLocal(GetLocal* curr) {
- // this is a use. check from the context what it is, signed or unsigned, etc.
+ // this is a use. check from the context what it is, signed or unsigned,
+ // etc.
auto& usage = usages[curr->index];
usage.totalUsages++;
if (expressionStack.size() >= 2) {
@@ -97,9 +99,14 @@ struct PickLoadSigns : public WalkerPass<ExpressionStackWalker<PickLoadSigns>> {
auto& usage = usages[index];
// if we can't optimize, give up
if (usage.totalUsages == 0 || // no usages, so no idea
- usage.signedUsages + usage.unsignedUsages != usage.totalUsages || // non-sign/unsigned usages, so cannot change
- (usage.signedUsages != 0 && usage.signedBits != load->bytes * 8) || // sign usages exist but the wrong size
- (usage.unsignedUsages != 0 && usage.unsignedBits != load->bytes * 8)) { // unsigned usages exist but the wrong size
+ usage.signedUsages + usage.unsignedUsages !=
+ usage.totalUsages || // non-sign/unsigned usages, so cannot change
+ (usage.signedUsages != 0 &&
+ usage.signedBits !=
+ load->bytes * 8) || // sign usages exist but the wrong size
+ (usage.unsignedUsages != 0 &&
+ usage.unsignedBits !=
+ load->bytes * 8)) { // unsigned usages exist but the wrong size
continue;
}
// we can pick the optimal one. our hope is to remove 2 items per
@@ -107,11 +114,8 @@ struct PickLoadSigns : public WalkerPass<ExpressionStackWalker<PickLoadSigns>> {
load->signed_ = usage.signedUsages * 2 >= usage.unsignedUsages;
}
}
-
};
-Pass *createPickLoadSignsPass() {
- return new PickLoadSigns();
-}
+Pass* createPickLoadSignsPass() { return new PickLoadSigns(); }
} // namespace wasm
diff --git a/src/passes/PostEmscripten.cpp b/src/passes/PostEmscripten.cpp
index 7e2bacf25..6c9b84d7c 100644
--- a/src/passes/PostEmscripten.cpp
+++ b/src/passes/PostEmscripten.cpp
@@ -19,11 +19,11 @@
// emscripten output.
//
-#include <wasm.h>
+#include <asmjs/shared-constants.h>
+#include <ir/localize.h>
#include <pass.h>
#include <wasm-builder.h>
-#include <ir/localize.h>
-#include <asmjs/shared-constants.h>
+#include <wasm.h>
namespace wasm {
@@ -35,7 +35,8 @@ struct PostEmscripten : public WalkerPass<PostWalker<PostEmscripten>> {
void visitCall(Call* curr) {
// special asm.js imports can be optimized
auto* func = getModule()->getFunction(curr->target);
- if (!func->imported()) return;
+ if (!func->imported())
+ return;
if (func->module == GLOBAL_MATH) {
if (func->base == POW) {
if (auto* exponent = curr->operands[1]->dynCast<Const>()) {
@@ -43,10 +44,14 @@ struct PostEmscripten : public WalkerPass<PostWalker<PostEmscripten>> {
// This is just a square operation, do a multiply
Localizer localizer(curr->operands[0], getFunction(), getModule());
Builder builder(*getModule());
- replaceCurrent(builder.makeBinary(MulFloat64, localizer.expr, builder.makeGetLocal(localizer.index, localizer.expr->type)));
+ replaceCurrent(builder.makeBinary(
+ MulFloat64,
+ localizer.expr,
+ builder.makeGetLocal(localizer.index, localizer.expr->type)));
} else if (exponent->value == Literal(double(0.5))) {
// This is just a square root operation
- replaceCurrent(Builder(*getModule()).makeUnary(SqrtFloat64, curr->operands[0]));
+ replaceCurrent(
+ Builder(*getModule()).makeUnary(SqrtFloat64, curr->operands[0]));
}
}
}
@@ -54,8 +59,6 @@ struct PostEmscripten : public WalkerPass<PostWalker<PostEmscripten>> {
}
};
-Pass *createPostEmscriptenPass() {
- return new PostEmscripten();
-}
+Pass* createPostEmscriptenPass() { return new PostEmscripten(); }
} // namespace wasm
diff --git a/src/passes/Precompute.cpp b/src/passes/Precompute.cpp
index 565809ddb..074dd832c 100644
--- a/src/passes/Precompute.cpp
+++ b/src/passes/Precompute.cpp
@@ -27,14 +27,14 @@
// looked at.
//
-#include <wasm.h>
-#include <pass.h>
-#include <wasm-builder.h>
-#include <wasm-interpreter.h>
-#include <ir/utils.h>
#include <ir/literal-utils.h>
#include <ir/local-graph.h>
#include <ir/manipulation.h>
+#include <ir/utils.h>
+#include <pass.h>
+#include <wasm-builder.h>
+#include <wasm-interpreter.h>
+#include <wasm.h>
namespace wasm {
@@ -42,38 +42,44 @@ static const Name NOTPRECOMPUTABLE_FLOW("Binaryen|notprecomputable");
typedef std::unordered_map<GetLocal*, Literal> GetValues;
-// Precomputes an expression. Errors if we hit anything that can't be precomputed.
-class PrecomputingExpressionRunner : public ExpressionRunner<PrecomputingExpressionRunner> {
+// Precomputes an expression. Errors if we hit anything that can't be
+// precomputed.
+class PrecomputingExpressionRunner
+ : public ExpressionRunner<PrecomputingExpressionRunner> {
Module* module;
// map gets to constant values, if they are known to be constant
GetValues& getValues;
- // Whether we are trying to precompute down to an expression (which we can do on
- // say 5 + 6) or to a value (which we can't do on a local.tee that flows a 7
- // through it). When we want to replace the expression, we can only do so
- // when it has no side effects. When we don't care about replacing the expression,
- // we just want to know if it will contain a known constant.
+ // Whether we are trying to precompute down to an expression (which we can do
+ // on say 5 + 6) or to a value (which we can't do on a local.tee that flows a
+ // 7 through it). When we want to replace the expression, we can only do so
+ // when it has no side effects. When we don't care about replacing the
+ // expression, we just want to know if it will contain a known constant.
bool replaceExpression;
public:
- PrecomputingExpressionRunner(Module* module, GetValues& getValues, bool replaceExpression) : module(module), getValues(getValues), replaceExpression(replaceExpression) {}
+ PrecomputingExpressionRunner(Module* module,
+ GetValues& getValues,
+ bool replaceExpression)
+ : module(module), getValues(getValues),
+ replaceExpression(replaceExpression) {}
- struct NonstandaloneException {}; // TODO: use a flow with a special name, as this is likely very slow
+ struct NonstandaloneException {
+ }; // TODO: use a flow with a special name, as this is likely very slow
Flow visitLoop(Loop* curr) {
// loops might be infinite, so must be careful
- // but we can't tell if non-infinite, since we don't have state, so loops are just impossible to optimize for now
+ // but we can't tell if non-infinite, since we don't have state, so loops
+ // are just impossible to optimize for now
return Flow(NOTPRECOMPUTABLE_FLOW);
}
- Flow visitCall(Call* curr) {
- return Flow(NOTPRECOMPUTABLE_FLOW);
- }
+ Flow visitCall(Call* curr) { return Flow(NOTPRECOMPUTABLE_FLOW); }
Flow visitCallIndirect(CallIndirect* curr) {
return Flow(NOTPRECOMPUTABLE_FLOW);
}
- Flow visitGetLocal(GetLocal *curr) {
+ Flow visitGetLocal(GetLocal* curr) {
auto iter = getValues.find(curr);
if (iter != getValues.end()) {
auto value = iter->second;
@@ -83,7 +89,7 @@ public:
}
return Flow(NOTPRECOMPUTABLE_FLOW);
}
- Flow visitSetLocal(SetLocal *curr) {
+ Flow visitSetLocal(SetLocal* curr) {
// If we don't need to replace the whole expression, see if there
// is a value flowing through a tee.
if (!replaceExpression) {
@@ -94,56 +100,36 @@ public:
}
return Flow(NOTPRECOMPUTABLE_FLOW);
}
- Flow visitGetGlobal(GetGlobal *curr) {
+ Flow visitGetGlobal(GetGlobal* curr) {
auto* global = module->getGlobal(curr->name);
if (!global->imported() && !global->mutable_) {
return visit(global->init);
}
return Flow(NOTPRECOMPUTABLE_FLOW);
}
- Flow visitSetGlobal(SetGlobal *curr) {
+ Flow visitSetGlobal(SetGlobal* curr) { return Flow(NOTPRECOMPUTABLE_FLOW); }
+ Flow visitLoad(Load* curr) { return Flow(NOTPRECOMPUTABLE_FLOW); }
+ Flow visitStore(Store* curr) { return Flow(NOTPRECOMPUTABLE_FLOW); }
+ Flow visitAtomicRMW(AtomicRMW* curr) { return Flow(NOTPRECOMPUTABLE_FLOW); }
+ Flow visitAtomicCmpxchg(AtomicCmpxchg* curr) {
return Flow(NOTPRECOMPUTABLE_FLOW);
}
- Flow visitLoad(Load *curr) {
- return Flow(NOTPRECOMPUTABLE_FLOW);
- }
- Flow visitStore(Store *curr) {
- return Flow(NOTPRECOMPUTABLE_FLOW);
- }
- Flow visitAtomicRMW(AtomicRMW *curr) {
- return Flow(NOTPRECOMPUTABLE_FLOW);
- }
- Flow visitAtomicCmpxchg(AtomicCmpxchg *curr) {
- return Flow(NOTPRECOMPUTABLE_FLOW);
- }
- Flow visitAtomicWait(AtomicWait *curr) {
- return Flow(NOTPRECOMPUTABLE_FLOW);
- }
- Flow visitAtomicNotify(AtomicNotify *curr) {
- return Flow(NOTPRECOMPUTABLE_FLOW);
- }
- Flow visitMemoryInit(MemoryInit *curr) {
- return Flow(NOTPRECOMPUTABLE_FLOW);
- }
- Flow visitDataDrop(DataDrop *curr) {
- return Flow(NOTPRECOMPUTABLE_FLOW);
- }
- Flow visitMemoryCopy(MemoryCopy *curr) {
- return Flow(NOTPRECOMPUTABLE_FLOW);
- }
- Flow visitMemoryFill(MemoryFill *curr) {
- return Flow(NOTPRECOMPUTABLE_FLOW);
- }
- Flow visitHost(Host *curr) {
+ Flow visitAtomicWait(AtomicWait* curr) { return Flow(NOTPRECOMPUTABLE_FLOW); }
+ Flow visitAtomicNotify(AtomicNotify* curr) {
return Flow(NOTPRECOMPUTABLE_FLOW);
}
+ Flow visitMemoryInit(MemoryInit* curr) { return Flow(NOTPRECOMPUTABLE_FLOW); }
+ Flow visitDataDrop(DataDrop* curr) { return Flow(NOTPRECOMPUTABLE_FLOW); }
+ Flow visitMemoryCopy(MemoryCopy* curr) { return Flow(NOTPRECOMPUTABLE_FLOW); }
+ Flow visitMemoryFill(MemoryFill* curr) { return Flow(NOTPRECOMPUTABLE_FLOW); }
+ Flow visitHost(Host* curr) { return Flow(NOTPRECOMPUTABLE_FLOW); }
- void trap(const char* why) override {
- throw NonstandaloneException();
- }
+ void trap(const char* why) override { throw NonstandaloneException(); }
};
-struct Precompute : public WalkerPass<PostWalker<Precompute, UnifiedExpressionVisitor<Precompute>>> {
+struct Precompute
+ : public WalkerPass<
+ PostWalker<Precompute, UnifiedExpressionVisitor<Precompute>>> {
bool isFunctionParallel() override { return true; }
Pass* create() override { return new Precompute(propagate); }
@@ -175,19 +161,25 @@ struct Precompute : public WalkerPass<PostWalker<Precompute, UnifiedExpressionVi
}
void visitExpression(Expression* curr) {
- // TODO: if local.get, only replace with a constant if we don't care about size...?
- if (curr->is<Const>() || curr->is<Nop>()) return;
+ // TODO: if local.get, only replace with a constant if we don't care about
+ // size...?
+ if (curr->is<Const>() || curr->is<Nop>())
+ return;
// Until engines implement v128.const and we have SIMD-aware optimizations
// that can break large v128.const instructions into smaller consts and
// splats, do not try to precompute v128 expressions.
- if (isVectorType(curr->type)) return;
+ if (isVectorType(curr->type))
+ return;
// try to evaluate this into a const
Flow flow = precomputeExpression(curr);
- if (isVectorType(flow.value.type)) return;
+ if (isVectorType(flow.value.type))
+ return;
if (flow.breaking()) {
- if (flow.breakTo == NOTPRECOMPUTABLE_FLOW) return;
+ if (flow.breakTo == NOTPRECOMPUTABLE_FLOW)
+ return;
if (flow.breakTo == RETURN_FLOW) {
- // this expression causes a return. if it's already a return, reuse the node
+ // this expression causes a return. if it's already a return, reuse the
+ // node
if (auto* ret = curr->dynCast<Return>()) {
if (flow.value.type != none) {
// reuse a const value if there is one
@@ -204,11 +196,13 @@ struct Precompute : public WalkerPass<PostWalker<Precompute, UnifiedExpressionVi
}
} else {
Builder builder(*getModule());
- replaceCurrent(builder.makeReturn(flow.value.type != none ? builder.makeConst(flow.value) : nullptr));
+ replaceCurrent(builder.makeReturn(
+ flow.value.type != none ? builder.makeConst(flow.value) : nullptr));
}
return;
}
- // this expression causes a break, emit it directly. if it's already a br, reuse the node.
+ // this expression causes a break, emit it directly. if it's already a br,
+ // reuse the node.
if (auto* br = curr->dynCast<Break>()) {
br->name = flow.breakTo;
br->condition = nullptr;
@@ -229,7 +223,9 @@ struct Precompute : public WalkerPass<PostWalker<Precompute, UnifiedExpressionVi
br->finalize();
} else {
Builder builder(*getModule());
- replaceCurrent(builder.makeBreak(flow.breakTo, flow.value.type != none ? builder.makeConst(flow.value) : nullptr));
+ replaceCurrent(builder.makeBreak(
+ flow.breakTo,
+ flow.value.type != none ? builder.makeConst(flow.value) : nullptr));
}
return;
}
@@ -252,7 +248,9 @@ private:
// (that we can replace the expression with if replaceExpression is set).
Flow precomputeExpression(Expression* curr, bool replaceExpression = true) {
try {
- return PrecomputingExpressionRunner(getModule(), getValues, replaceExpression).visit(curr);
+ return PrecomputingExpressionRunner(
+ getModule(), getValues, replaceExpression)
+ .visit(curr);
} catch (PrecomputingExpressionRunner::NonstandaloneException&) {
return Flow(NOTPRECOMPUTABLE_FLOW);
}
@@ -292,7 +290,8 @@ private:
auto* curr = pair.first;
work.insert(curr);
}
- std::unordered_map<SetLocal*, Literal> setValues; // the constant value, or none if not a constant
+ // the constant value, or none if not a constant
+ std::unordered_map<SetLocal*, Literal> setValues;
// propagate constant values
while (!work.empty()) {
auto iter = work.begin();
@@ -302,7 +301,8 @@ private:
// mark it as such and add everything it influences to the work list,
// as they may be constant too.
if (auto* set = curr->dynCast<SetLocal>()) {
- if (setValues[set].isConcrete()) continue; // already known constant
+ if (setValues[set].isConcrete())
+ continue; // already known constant
auto value = setValues[set] = precomputeValue(set->value);
if (value.isConcrete()) {
for (auto* get : localGraph.setInfluences[set]) {
@@ -311,7 +311,8 @@ private:
}
} else {
auto* get = curr->cast<GetLocal>();
- if (getValues[get].isConcrete()) continue; // already known constant
+ if (getValues[get].isConcrete())
+ continue; // already known constant
// for this get to have constant value, all sets must agree
Literal value;
bool first = true;
@@ -358,12 +359,8 @@ private:
}
};
-Pass *createPrecomputePass() {
- return new Precompute(false);
-}
+Pass* createPrecomputePass() { return new Precompute(false); }
-Pass *createPrecomputePropagatePass() {
- return new Precompute(true);
-}
+Pass* createPrecomputePropagatePass() { return new Precompute(true); }
} // namespace wasm
diff --git a/src/passes/Print.cpp b/src/passes/Print.cpp
index 29d867d76..405097455 100644
--- a/src/passes/Print.cpp
+++ b/src/passes/Print.cpp
@@ -18,12 +18,12 @@
// Print out text in s-expression format
//
-#include <wasm.h>
-#include <wasm-printing.h>
-#include <wasm-stack.h>
+#include <ir/module-utils.h>
#include <pass.h>
#include <pretty_printing.h>
-#include <ir/module-utils.h>
+#include <wasm-printing.h>
+#include <wasm-stack.h>
+#include <wasm.h>
namespace wasm {
@@ -55,15 +55,14 @@ static Name printableLocal(Index index, Function* func) {
return name;
}
-
// Prints the internal contents of an expression: everything but
// the children.
struct PrintExpressionContents : public Visitor<PrintExpressionContents> {
Function* currFunction = nullptr;
std::ostream& o;
- PrintExpressionContents(Function* currFunction, std::ostream& o) :
- currFunction(currFunction), o(o) {}
+ PrintExpressionContents(Function* currFunction, std::ostream& o)
+ : currFunction(currFunction), o(o) {}
void visitBlock(Block* curr) {
printMedium(o, "block");
@@ -133,7 +132,8 @@ struct PrintExpressionContents : public Visitor<PrintExpressionContents> {
}
void visitLoad(Load* curr) {
prepareColor(o) << printType(curr->type);
- if (curr->isAtomic) o << ".atomic";
+ if (curr->isAtomic)
+ o << ".atomic";
o << ".load";
if (curr->type != unreachable && curr->bytes < getTypeSize(curr->type)) {
if (curr->bytes == 1) {
@@ -157,7 +157,8 @@ struct PrintExpressionContents : public Visitor<PrintExpressionContents> {
}
void visitStore(Store* curr) {
prepareColor(o) << printType(curr->valueType);
- if (curr->isAtomic) o << ".atomic";
+ if (curr->isAtomic)
+ o << ".atomic";
o << ".store";
if (curr->bytes < 4 || (curr->valueType == i64 && curr->bytes < 8)) {
if (curr->bytes == 1) {
@@ -199,12 +200,24 @@ struct PrintExpressionContents : public Visitor<PrintExpressionContents> {
prepareColor(o);
printRMWSize(o, curr->type, curr->bytes);
switch (curr->op) {
- case Add: o << "add"; break;
- case Sub: o << "sub"; break;
- case And: o << "and"; break;
- case Or: o << "or"; break;
- case Xor: o << "xor"; break;
- case Xchg: o << "xchg"; break;
+ case Add:
+ o << "add";
+ break;
+ case Sub:
+ o << "sub";
+ break;
+ case And:
+ o << "and";
+ break;
+ case Or:
+ o << "or";
+ break;
+ case Xor:
+ o << "xor";
+ break;
+ case Xchg:
+ o << "xchg";
+ break;
}
if (curr->type != unreachable && curr->bytes != getTypeSize(curr->type)) {
o << "_u";
@@ -217,7 +230,7 @@ struct PrintExpressionContents : public Visitor<PrintExpressionContents> {
void visitAtomicCmpxchg(AtomicCmpxchg* curr) {
prepareColor(o);
printRMWSize(o, curr->type, curr->bytes);
- o << "cmpxchg";
+ o << "cmpxchg";
if (curr->type != unreachable && curr->bytes != getTypeSize(curr->type)) {
o << "_u";
}
@@ -242,26 +255,54 @@ struct PrintExpressionContents : public Visitor<PrintExpressionContents> {
void visitSIMDExtract(SIMDExtract* curr) {
prepareColor(o);
switch (curr->op) {
- case ExtractLaneSVecI8x16: o << "i8x16.extract_lane_s"; break;
- case ExtractLaneUVecI8x16: o << "i8x16.extract_lane_u"; break;
- case ExtractLaneSVecI16x8: o << "i16x8.extract_lane_s"; break;
- case ExtractLaneUVecI16x8: o << "i16x8.extract_lane_u"; break;
- case ExtractLaneVecI32x4: o << "i32x4.extract_lane"; break;
- case ExtractLaneVecI64x2: o << "i64x2.extract_lane"; break;
- case ExtractLaneVecF32x4: o << "f32x4.extract_lane"; break;
- case ExtractLaneVecF64x2: o << "f64x2.extract_lane"; break;
+ case ExtractLaneSVecI8x16:
+ o << "i8x16.extract_lane_s";
+ break;
+ case ExtractLaneUVecI8x16:
+ o << "i8x16.extract_lane_u";
+ break;
+ case ExtractLaneSVecI16x8:
+ o << "i16x8.extract_lane_s";
+ break;
+ case ExtractLaneUVecI16x8:
+ o << "i16x8.extract_lane_u";
+ break;
+ case ExtractLaneVecI32x4:
+ o << "i32x4.extract_lane";
+ break;
+ case ExtractLaneVecI64x2:
+ o << "i64x2.extract_lane";
+ break;
+ case ExtractLaneVecF32x4:
+ o << "f32x4.extract_lane";
+ break;
+ case ExtractLaneVecF64x2:
+ o << "f64x2.extract_lane";
+ break;
}
o << " " << int(curr->index);
}
void visitSIMDReplace(SIMDReplace* curr) {
prepareColor(o);
switch (curr->op) {
- case ReplaceLaneVecI8x16: o << "i8x16.replace_lane"; break;
- case ReplaceLaneVecI16x8: o << "i16x8.replace_lane"; break;
- case ReplaceLaneVecI32x4: o << "i32x4.replace_lane"; break;
- case ReplaceLaneVecI64x2: o << "i64x2.replace_lane"; break;
- case ReplaceLaneVecF32x4: o << "f32x4.replace_lane"; break;
- case ReplaceLaneVecF64x2: o << "f64x2.replace_lane"; break;
+ case ReplaceLaneVecI8x16:
+ o << "i8x16.replace_lane";
+ break;
+ case ReplaceLaneVecI16x8:
+ o << "i16x8.replace_lane";
+ break;
+ case ReplaceLaneVecI32x4:
+ o << "i32x4.replace_lane";
+ break;
+ case ReplaceLaneVecI64x2:
+ o << "i64x2.replace_lane";
+ break;
+ case ReplaceLaneVecF32x4:
+ o << "f32x4.replace_lane";
+ break;
+ case ReplaceLaneVecF64x2:
+ o << "f64x2.replace_lane";
+ break;
}
o << " " << int(curr->index);
}
@@ -279,18 +320,42 @@ struct PrintExpressionContents : public Visitor<PrintExpressionContents> {
void visitSIMDShift(SIMDShift* curr) {
prepareColor(o);
switch (curr->op) {
- case ShlVecI8x16: o << "i8x16.shl"; break;
- case ShrSVecI8x16: o << "i8x16.shr_s"; break;
- case ShrUVecI8x16: o << "i8x16.shr_u"; break;
- case ShlVecI16x8: o << "i16x8.shl"; break;
- case ShrSVecI16x8: o << "i16x8.shr_s"; break;
- case ShrUVecI16x8: o << "i16x8.shr_u"; break;
- case ShlVecI32x4: o << "i32x4.shl"; break;
- case ShrSVecI32x4: o << "i32x4.shr_s"; break;
- case ShrUVecI32x4: o << "i32x4.shr_u"; break;
- case ShlVecI64x2: o << "i64x2.shl"; break;
- case ShrSVecI64x2: o << "i64x2.shr_s"; break;
- case ShrUVecI64x2: o << "i64x2.shr_u"; break;
+ case ShlVecI8x16:
+ o << "i8x16.shl";
+ break;
+ case ShrSVecI8x16:
+ o << "i8x16.shr_s";
+ break;
+ case ShrUVecI8x16:
+ o << "i8x16.shr_u";
+ break;
+ case ShlVecI16x8:
+ o << "i16x8.shl";
+ break;
+ case ShrSVecI16x8:
+ o << "i16x8.shr_s";
+ break;
+ case ShrUVecI16x8:
+ o << "i16x8.shr_u";
+ break;
+ case ShlVecI32x4:
+ o << "i32x4.shl";
+ break;
+ case ShrSVecI32x4:
+ o << "i32x4.shr_s";
+ break;
+ case ShrUVecI32x4:
+ o << "i32x4.shr_u";
+ break;
+ case ShlVecI64x2:
+ o << "i64x2.shl";
+ break;
+ case ShrSVecI64x2:
+ o << "i64x2.shr_s";
+ break;
+ case ShrUVecI64x2:
+ o << "i64x2.shr_u";
+ break;
}
}
void visitMemoryInit(MemoryInit* curr) {
@@ -309,296 +374,780 @@ struct PrintExpressionContents : public Visitor<PrintExpressionContents> {
prepareColor(o);
o << "memory.fill";
}
- void visitConst(Const* curr) {
- o << curr->value;
- }
+ void visitConst(Const* curr) { o << curr->value; }
void visitUnary(Unary* curr) {
prepareColor(o);
switch (curr->op) {
- case ClzInt32: o << "i32.clz"; break;
- case CtzInt32: o << "i32.ctz"; break;
- case PopcntInt32: o << "i32.popcnt"; break;
- case EqZInt32: o << "i32.eqz"; break;
- case ClzInt64: o << "i64.clz"; break;
- case CtzInt64: o << "i64.ctz"; break;
- case PopcntInt64: o << "i64.popcnt"; break;
- case EqZInt64: o << "i64.eqz"; break;
- case NegFloat32: o << "f32.neg"; break;
- case AbsFloat32: o << "f32.abs"; break;
- case CeilFloat32: o << "f32.ceil"; break;
- case FloorFloat32: o << "f32.floor"; break;
- case TruncFloat32: o << "f32.trunc"; break;
- case NearestFloat32: o << "f32.nearest"; break;
- case SqrtFloat32: o << "f32.sqrt"; break;
- case NegFloat64: o << "f64.neg"; break;
- case AbsFloat64: o << "f64.abs"; break;
- case CeilFloat64: o << "f64.ceil"; break;
- case FloorFloat64: o << "f64.floor"; break;
- case TruncFloat64: o << "f64.trunc"; break;
- case NearestFloat64: o << "f64.nearest"; break;
- case SqrtFloat64: o << "f64.sqrt"; break;
- case ExtendSInt32: o << "i64.extend_i32_s"; break;
- case ExtendUInt32: o << "i64.extend_i32_u"; break;
- case WrapInt64: o << "i32.wrap_i64"; break;
- case TruncSFloat32ToInt32: o << "i32.trunc_f32_s"; break;
- case TruncSFloat32ToInt64: o << "i64.trunc_f32_s"; break;
- case TruncUFloat32ToInt32: o << "i32.trunc_f32_u"; break;
- case TruncUFloat32ToInt64: o << "i64.trunc_f32_u"; break;
- case TruncSFloat64ToInt32: o << "i32.trunc_f64_s"; break;
- case TruncSFloat64ToInt64: o << "i64.trunc_f64_s"; break;
- case TruncUFloat64ToInt32: o << "i32.trunc_f64_u"; break;
- case TruncUFloat64ToInt64: o << "i64.trunc_f64_u"; break;
- case ReinterpretFloat32: o << "i32.reinterpret_f32"; break;
- case ReinterpretFloat64: o << "i64.reinterpret_f64"; break;
- case ConvertUInt32ToFloat32: o << "f32.convert_i32_u"; break;
- case ConvertUInt32ToFloat64: o << "f64.convert_i32_u"; break;
- case ConvertSInt32ToFloat32: o << "f32.convert_i32_s"; break;
- case ConvertSInt32ToFloat64: o << "f64.convert_i32_s"; break;
- case ConvertUInt64ToFloat32: o << "f32.convert_i64_u"; break;
- case ConvertUInt64ToFloat64: o << "f64.convert_i64_u"; break;
- case ConvertSInt64ToFloat32: o << "f32.convert_i64_s"; break;
- case ConvertSInt64ToFloat64: o << "f64.convert_i64_s"; break;
- case PromoteFloat32: o << "f64.promote_f32"; break;
- case DemoteFloat64: o << "f32.demote_f64"; break;
- case ReinterpretInt32: o << "f32.reinterpret_i32"; break;
- case ReinterpretInt64: o << "f64.reinterpret_i64"; break;
- case ExtendS8Int32: o << "i32.extend8_s"; break;
- case ExtendS16Int32: o << "i32.extend16_s"; break;
- case ExtendS8Int64: o << "i64.extend8_s"; break;
- case ExtendS16Int64: o << "i64.extend16_s"; break;
- case ExtendS32Int64: o << "i64.extend32_s"; break;
- case TruncSatSFloat32ToInt32: o << "i32.trunc_sat_f32_s"; break;
- case TruncSatUFloat32ToInt32: o << "i32.trunc_sat_f32_u"; break;
- case TruncSatSFloat64ToInt32: o << "i32.trunc_sat_f64_s"; break;
- case TruncSatUFloat64ToInt32: o << "i32.trunc_sat_f64_u"; break;
- case TruncSatSFloat32ToInt64: o << "i64.trunc_sat_f32_s"; break;
- case TruncSatUFloat32ToInt64: o << "i64.trunc_sat_f32_u"; break;
- case TruncSatSFloat64ToInt64: o << "i64.trunc_sat_f64_s"; break;
- case TruncSatUFloat64ToInt64: o << "i64.trunc_sat_f64_u"; break;
- case SplatVecI8x16: o << "i8x16.splat"; break;
- case SplatVecI16x8: o << "i16x8.splat"; break;
- case SplatVecI32x4: o << "i32x4.splat"; break;
- case SplatVecI64x2: o << "i64x2.splat"; break;
- case SplatVecF32x4: o << "f32x4.splat"; break;
- case SplatVecF64x2: o << "f64x2.splat"; break;
- case NotVec128: o << "v128.not"; break;
- case NegVecI8x16: o << "i8x16.neg"; break;
- case AnyTrueVecI8x16: o << "i8x16.any_true"; break;
- case AllTrueVecI8x16: o << "i8x16.all_true"; break;
- case NegVecI16x8: o << "i16x8.neg"; break;
- case AnyTrueVecI16x8: o << "i16x8.any_true"; break;
- case AllTrueVecI16x8: o << "i16x8.all_true"; break;
- case NegVecI32x4: o << "i32x4.neg"; break;
- case AnyTrueVecI32x4: o << "i32x4.any_true"; break;
- case AllTrueVecI32x4: o << "i32x4.all_true"; break;
- case NegVecI64x2: o << "i64x2.neg"; break;
- case AnyTrueVecI64x2: o << "i64x2.any_true"; break;
- case AllTrueVecI64x2: o << "i64x2.all_true"; break;
- case AbsVecF32x4: o << "f32x4.abs"; break;
- case NegVecF32x4: o << "f32x4.neg"; break;
- case SqrtVecF32x4: o << "f32x4.sqrt"; break;
- case AbsVecF64x2: o << "f64x2.abs"; break;
- case NegVecF64x2: o << "f64x2.neg"; break;
- case SqrtVecF64x2: o << "f64x2.sqrt"; break;
- case TruncSatSVecF32x4ToVecI32x4: o << "i32x4.trunc_sat_f32x4_s"; break;
- case TruncSatUVecF32x4ToVecI32x4: o << "i32x4.trunc_sat_f32x4_u"; break;
- case TruncSatSVecF64x2ToVecI64x2: o << "i64x2.trunc_sat_f64x2_s"; break;
- case TruncSatUVecF64x2ToVecI64x2: o << "i64x2.trunc_sat_f64x2_u"; break;
- case ConvertSVecI32x4ToVecF32x4: o << "f32x4.convert_i32x4_s"; break;
- case ConvertUVecI32x4ToVecF32x4: o << "f32x4.convert_i32x4_u"; break;
- case ConvertSVecI64x2ToVecF64x2: o << "f64x2.convert_i64x2_s"; break;
- case ConvertUVecI64x2ToVecF64x2: o << "f64x2.convert_i64x2_u"; break;
- case InvalidUnary: WASM_UNREACHABLE();
+ case ClzInt32:
+ o << "i32.clz";
+ break;
+ case CtzInt32:
+ o << "i32.ctz";
+ break;
+ case PopcntInt32:
+ o << "i32.popcnt";
+ break;
+ case EqZInt32:
+ o << "i32.eqz";
+ break;
+ case ClzInt64:
+ o << "i64.clz";
+ break;
+ case CtzInt64:
+ o << "i64.ctz";
+ break;
+ case PopcntInt64:
+ o << "i64.popcnt";
+ break;
+ case EqZInt64:
+ o << "i64.eqz";
+ break;
+ case NegFloat32:
+ o << "f32.neg";
+ break;
+ case AbsFloat32:
+ o << "f32.abs";
+ break;
+ case CeilFloat32:
+ o << "f32.ceil";
+ break;
+ case FloorFloat32:
+ o << "f32.floor";
+ break;
+ case TruncFloat32:
+ o << "f32.trunc";
+ break;
+ case NearestFloat32:
+ o << "f32.nearest";
+ break;
+ case SqrtFloat32:
+ o << "f32.sqrt";
+ break;
+ case NegFloat64:
+ o << "f64.neg";
+ break;
+ case AbsFloat64:
+ o << "f64.abs";
+ break;
+ case CeilFloat64:
+ o << "f64.ceil";
+ break;
+ case FloorFloat64:
+ o << "f64.floor";
+ break;
+ case TruncFloat64:
+ o << "f64.trunc";
+ break;
+ case NearestFloat64:
+ o << "f64.nearest";
+ break;
+ case SqrtFloat64:
+ o << "f64.sqrt";
+ break;
+ case ExtendSInt32:
+ o << "i64.extend_i32_s";
+ break;
+ case ExtendUInt32:
+ o << "i64.extend_i32_u";
+ break;
+ case WrapInt64:
+ o << "i32.wrap_i64";
+ break;
+ case TruncSFloat32ToInt32:
+ o << "i32.trunc_f32_s";
+ break;
+ case TruncSFloat32ToInt64:
+ o << "i64.trunc_f32_s";
+ break;
+ case TruncUFloat32ToInt32:
+ o << "i32.trunc_f32_u";
+ break;
+ case TruncUFloat32ToInt64:
+ o << "i64.trunc_f32_u";
+ break;
+ case TruncSFloat64ToInt32:
+ o << "i32.trunc_f64_s";
+ break;
+ case TruncSFloat64ToInt64:
+ o << "i64.trunc_f64_s";
+ break;
+ case TruncUFloat64ToInt32:
+ o << "i32.trunc_f64_u";
+ break;
+ case TruncUFloat64ToInt64:
+ o << "i64.trunc_f64_u";
+ break;
+ case ReinterpretFloat32:
+ o << "i32.reinterpret_f32";
+ break;
+ case ReinterpretFloat64:
+ o << "i64.reinterpret_f64";
+ break;
+ case ConvertUInt32ToFloat32:
+ o << "f32.convert_i32_u";
+ break;
+ case ConvertUInt32ToFloat64:
+ o << "f64.convert_i32_u";
+ break;
+ case ConvertSInt32ToFloat32:
+ o << "f32.convert_i32_s";
+ break;
+ case ConvertSInt32ToFloat64:
+ o << "f64.convert_i32_s";
+ break;
+ case ConvertUInt64ToFloat32:
+ o << "f32.convert_i64_u";
+ break;
+ case ConvertUInt64ToFloat64:
+ o << "f64.convert_i64_u";
+ break;
+ case ConvertSInt64ToFloat32:
+ o << "f32.convert_i64_s";
+ break;
+ case ConvertSInt64ToFloat64:
+ o << "f64.convert_i64_s";
+ break;
+ case PromoteFloat32:
+ o << "f64.promote_f32";
+ break;
+ case DemoteFloat64:
+ o << "f32.demote_f64";
+ break;
+ case ReinterpretInt32:
+ o << "f32.reinterpret_i32";
+ break;
+ case ReinterpretInt64:
+ o << "f64.reinterpret_i64";
+ break;
+ case ExtendS8Int32:
+ o << "i32.extend8_s";
+ break;
+ case ExtendS16Int32:
+ o << "i32.extend16_s";
+ break;
+ case ExtendS8Int64:
+ o << "i64.extend8_s";
+ break;
+ case ExtendS16Int64:
+ o << "i64.extend16_s";
+ break;
+ case ExtendS32Int64:
+ o << "i64.extend32_s";
+ break;
+ case TruncSatSFloat32ToInt32:
+ o << "i32.trunc_sat_f32_s";
+ break;
+ case TruncSatUFloat32ToInt32:
+ o << "i32.trunc_sat_f32_u";
+ break;
+ case TruncSatSFloat64ToInt32:
+ o << "i32.trunc_sat_f64_s";
+ break;
+ case TruncSatUFloat64ToInt32:
+ o << "i32.trunc_sat_f64_u";
+ break;
+ case TruncSatSFloat32ToInt64:
+ o << "i64.trunc_sat_f32_s";
+ break;
+ case TruncSatUFloat32ToInt64:
+ o << "i64.trunc_sat_f32_u";
+ break;
+ case TruncSatSFloat64ToInt64:
+ o << "i64.trunc_sat_f64_s";
+ break;
+ case TruncSatUFloat64ToInt64:
+ o << "i64.trunc_sat_f64_u";
+ break;
+ case SplatVecI8x16:
+ o << "i8x16.splat";
+ break;
+ case SplatVecI16x8:
+ o << "i16x8.splat";
+ break;
+ case SplatVecI32x4:
+ o << "i32x4.splat";
+ break;
+ case SplatVecI64x2:
+ o << "i64x2.splat";
+ break;
+ case SplatVecF32x4:
+ o << "f32x4.splat";
+ break;
+ case SplatVecF64x2:
+ o << "f64x2.splat";
+ break;
+ case NotVec128:
+ o << "v128.not";
+ break;
+ case NegVecI8x16:
+ o << "i8x16.neg";
+ break;
+ case AnyTrueVecI8x16:
+ o << "i8x16.any_true";
+ break;
+ case AllTrueVecI8x16:
+ o << "i8x16.all_true";
+ break;
+ case NegVecI16x8:
+ o << "i16x8.neg";
+ break;
+ case AnyTrueVecI16x8:
+ o << "i16x8.any_true";
+ break;
+ case AllTrueVecI16x8:
+ o << "i16x8.all_true";
+ break;
+ case NegVecI32x4:
+ o << "i32x4.neg";
+ break;
+ case AnyTrueVecI32x4:
+ o << "i32x4.any_true";
+ break;
+ case AllTrueVecI32x4:
+ o << "i32x4.all_true";
+ break;
+ case NegVecI64x2:
+ o << "i64x2.neg";
+ break;
+ case AnyTrueVecI64x2:
+ o << "i64x2.any_true";
+ break;
+ case AllTrueVecI64x2:
+ o << "i64x2.all_true";
+ break;
+ case AbsVecF32x4:
+ o << "f32x4.abs";
+ break;
+ case NegVecF32x4:
+ o << "f32x4.neg";
+ break;
+ case SqrtVecF32x4:
+ o << "f32x4.sqrt";
+ break;
+ case AbsVecF64x2:
+ o << "f64x2.abs";
+ break;
+ case NegVecF64x2:
+ o << "f64x2.neg";
+ break;
+ case SqrtVecF64x2:
+ o << "f64x2.sqrt";
+ break;
+ case TruncSatSVecF32x4ToVecI32x4:
+ o << "i32x4.trunc_sat_f32x4_s";
+ break;
+ case TruncSatUVecF32x4ToVecI32x4:
+ o << "i32x4.trunc_sat_f32x4_u";
+ break;
+ case TruncSatSVecF64x2ToVecI64x2:
+ o << "i64x2.trunc_sat_f64x2_s";
+ break;
+ case TruncSatUVecF64x2ToVecI64x2:
+ o << "i64x2.trunc_sat_f64x2_u";
+ break;
+ case ConvertSVecI32x4ToVecF32x4:
+ o << "f32x4.convert_i32x4_s";
+ break;
+ case ConvertUVecI32x4ToVecF32x4:
+ o << "f32x4.convert_i32x4_u";
+ break;
+ case ConvertSVecI64x2ToVecF64x2:
+ o << "f64x2.convert_i64x2_s";
+ break;
+ case ConvertUVecI64x2ToVecF64x2:
+ o << "f64x2.convert_i64x2_u";
+ break;
+ case InvalidUnary:
+ WASM_UNREACHABLE();
}
}
void visitBinary(Binary* curr) {
prepareColor(o);
switch (curr->op) {
- case AddInt32: o << "i32.add"; break;
- case SubInt32: o << "i32.sub"; break;
- case MulInt32: o << "i32.mul"; break;
- case DivSInt32: o << "i32.div_s"; break;
- case DivUInt32: o << "i32.div_u"; break;
- case RemSInt32: o << "i32.rem_s"; break;
- case RemUInt32: o << "i32.rem_u"; break;
- case AndInt32: o << "i32.and"; break;
- case OrInt32: o << "i32.or"; break;
- case XorInt32: o << "i32.xor"; break;
- case ShlInt32: o << "i32.shl"; break;
- case ShrUInt32: o << "i32.shr_u"; break;
- case ShrSInt32: o << "i32.shr_s"; break;
- case RotLInt32: o << "i32.rotl"; break;
- case RotRInt32: o << "i32.rotr"; break;
- case EqInt32: o << "i32.eq"; break;
- case NeInt32: o << "i32.ne"; break;
- case LtSInt32: o << "i32.lt_s"; break;
- case LtUInt32: o << "i32.lt_u"; break;
- case LeSInt32: o << "i32.le_s"; break;
- case LeUInt32: o << "i32.le_u"; break;
- case GtSInt32: o << "i32.gt_s"; break;
- case GtUInt32: o << "i32.gt_u"; break;
- case GeSInt32: o << "i32.ge_s"; break;
- case GeUInt32: o << "i32.ge_u"; break;
+ case AddInt32:
+ o << "i32.add";
+ break;
+ case SubInt32:
+ o << "i32.sub";
+ break;
+ case MulInt32:
+ o << "i32.mul";
+ break;
+ case DivSInt32:
+ o << "i32.div_s";
+ break;
+ case DivUInt32:
+ o << "i32.div_u";
+ break;
+ case RemSInt32:
+ o << "i32.rem_s";
+ break;
+ case RemUInt32:
+ o << "i32.rem_u";
+ break;
+ case AndInt32:
+ o << "i32.and";
+ break;
+ case OrInt32:
+ o << "i32.or";
+ break;
+ case XorInt32:
+ o << "i32.xor";
+ break;
+ case ShlInt32:
+ o << "i32.shl";
+ break;
+ case ShrUInt32:
+ o << "i32.shr_u";
+ break;
+ case ShrSInt32:
+ o << "i32.shr_s";
+ break;
+ case RotLInt32:
+ o << "i32.rotl";
+ break;
+ case RotRInt32:
+ o << "i32.rotr";
+ break;
+ case EqInt32:
+ o << "i32.eq";
+ break;
+ case NeInt32:
+ o << "i32.ne";
+ break;
+ case LtSInt32:
+ o << "i32.lt_s";
+ break;
+ case LtUInt32:
+ o << "i32.lt_u";
+ break;
+ case LeSInt32:
+ o << "i32.le_s";
+ break;
+ case LeUInt32:
+ o << "i32.le_u";
+ break;
+ case GtSInt32:
+ o << "i32.gt_s";
+ break;
+ case GtUInt32:
+ o << "i32.gt_u";
+ break;
+ case GeSInt32:
+ o << "i32.ge_s";
+ break;
+ case GeUInt32:
+ o << "i32.ge_u";
+ break;
- case AddInt64: o << "i64.add"; break;
- case SubInt64: o << "i64.sub"; break;
- case MulInt64: o << "i64.mul"; break;
- case DivSInt64: o << "i64.div_s"; break;
- case DivUInt64: o << "i64.div_u"; break;
- case RemSInt64: o << "i64.rem_s"; break;
- case RemUInt64: o << "i64.rem_u"; break;
- case AndInt64: o << "i64.and"; break;
- case OrInt64: o << "i64.or"; break;
- case XorInt64: o << "i64.xor"; break;
- case ShlInt64: o << "i64.shl"; break;
- case ShrUInt64: o << "i64.shr_u"; break;
- case ShrSInt64: o << "i64.shr_s"; break;
- case RotLInt64: o << "i64.rotl"; break;
- case RotRInt64: o << "i64.rotr"; break;
- case EqInt64: o << "i64.eq"; break;
- case NeInt64: o << "i64.ne"; break;
- case LtSInt64: o << "i64.lt_s"; break;
- case LtUInt64: o << "i64.lt_u"; break;
- case LeSInt64: o << "i64.le_s"; break;
- case LeUInt64: o << "i64.le_u"; break;
- case GtSInt64: o << "i64.gt_s"; break;
- case GtUInt64: o << "i64.gt_u"; break;
- case GeSInt64: o << "i64.ge_s"; break;
- case GeUInt64: o << "i64.ge_u"; break;
+ case AddInt64:
+ o << "i64.add";
+ break;
+ case SubInt64:
+ o << "i64.sub";
+ break;
+ case MulInt64:
+ o << "i64.mul";
+ break;
+ case DivSInt64:
+ o << "i64.div_s";
+ break;
+ case DivUInt64:
+ o << "i64.div_u";
+ break;
+ case RemSInt64:
+ o << "i64.rem_s";
+ break;
+ case RemUInt64:
+ o << "i64.rem_u";
+ break;
+ case AndInt64:
+ o << "i64.and";
+ break;
+ case OrInt64:
+ o << "i64.or";
+ break;
+ case XorInt64:
+ o << "i64.xor";
+ break;
+ case ShlInt64:
+ o << "i64.shl";
+ break;
+ case ShrUInt64:
+ o << "i64.shr_u";
+ break;
+ case ShrSInt64:
+ o << "i64.shr_s";
+ break;
+ case RotLInt64:
+ o << "i64.rotl";
+ break;
+ case RotRInt64:
+ o << "i64.rotr";
+ break;
+ case EqInt64:
+ o << "i64.eq";
+ break;
+ case NeInt64:
+ o << "i64.ne";
+ break;
+ case LtSInt64:
+ o << "i64.lt_s";
+ break;
+ case LtUInt64:
+ o << "i64.lt_u";
+ break;
+ case LeSInt64:
+ o << "i64.le_s";
+ break;
+ case LeUInt64:
+ o << "i64.le_u";
+ break;
+ case GtSInt64:
+ o << "i64.gt_s";
+ break;
+ case GtUInt64:
+ o << "i64.gt_u";
+ break;
+ case GeSInt64:
+ o << "i64.ge_s";
+ break;
+ case GeUInt64:
+ o << "i64.ge_u";
+ break;
- case AddFloat32: o << "f32.add"; break;
- case SubFloat32: o << "f32.sub"; break;
- case MulFloat32: o << "f32.mul"; break;
- case DivFloat32: o << "f32.div"; break;
- case CopySignFloat32: o << "f32.copysign"; break;
- case MinFloat32: o << "f32.min"; break;
- case MaxFloat32: o << "f32.max"; break;
- case EqFloat32: o << "f32.eq"; break;
- case NeFloat32: o << "f32.ne"; break;
- case LtFloat32: o << "f32.lt"; break;
- case LeFloat32: o << "f32.le"; break;
- case GtFloat32: o << "f32.gt"; break;
- case GeFloat32: o << "f32.ge"; break;
+ case AddFloat32:
+ o << "f32.add";
+ break;
+ case SubFloat32:
+ o << "f32.sub";
+ break;
+ case MulFloat32:
+ o << "f32.mul";
+ break;
+ case DivFloat32:
+ o << "f32.div";
+ break;
+ case CopySignFloat32:
+ o << "f32.copysign";
+ break;
+ case MinFloat32:
+ o << "f32.min";
+ break;
+ case MaxFloat32:
+ o << "f32.max";
+ break;
+ case EqFloat32:
+ o << "f32.eq";
+ break;
+ case NeFloat32:
+ o << "f32.ne";
+ break;
+ case LtFloat32:
+ o << "f32.lt";
+ break;
+ case LeFloat32:
+ o << "f32.le";
+ break;
+ case GtFloat32:
+ o << "f32.gt";
+ break;
+ case GeFloat32:
+ o << "f32.ge";
+ break;
- case AddFloat64: o << "f64.add"; break;
- case SubFloat64: o << "f64.sub"; break;
- case MulFloat64: o << "f64.mul"; break;
- case DivFloat64: o << "f64.div"; break;
- case CopySignFloat64: o << "f64.copysign"; break;
- case MinFloat64: o << "f64.min"; break;
- case MaxFloat64: o << "f64.max"; break;
- case EqFloat64: o << "f64.eq"; break;
- case NeFloat64: o << "f64.ne"; break;
- case LtFloat64: o << "f64.lt"; break;
- case LeFloat64: o << "f64.le"; break;
- case GtFloat64: o << "f64.gt"; break;
- case GeFloat64: o << "f64.ge"; break;
+ case AddFloat64:
+ o << "f64.add";
+ break;
+ case SubFloat64:
+ o << "f64.sub";
+ break;
+ case MulFloat64:
+ o << "f64.mul";
+ break;
+ case DivFloat64:
+ o << "f64.div";
+ break;
+ case CopySignFloat64:
+ o << "f64.copysign";
+ break;
+ case MinFloat64:
+ o << "f64.min";
+ break;
+ case MaxFloat64:
+ o << "f64.max";
+ break;
+ case EqFloat64:
+ o << "f64.eq";
+ break;
+ case NeFloat64:
+ o << "f64.ne";
+ break;
+ case LtFloat64:
+ o << "f64.lt";
+ break;
+ case LeFloat64:
+ o << "f64.le";
+ break;
+ case GtFloat64:
+ o << "f64.gt";
+ break;
+ case GeFloat64:
+ o << "f64.ge";
+ break;
- case EqVecI8x16: o << "i8x16.eq"; break;
- case NeVecI8x16: o << "i8x16.ne"; break;
- case LtSVecI8x16: o << "i8x16.lt_s"; break;
- case LtUVecI8x16: o << "i8x16.lt_u"; break;
- case GtSVecI8x16: o << "i8x16.gt_s"; break;
- case GtUVecI8x16: o << "i8x16.gt_u"; break;
- case LeSVecI8x16: o << "i8x16.le_s"; break;
- case LeUVecI8x16: o << "i8x16.le_u"; break;
- case GeSVecI8x16: o << "i8x16.ge_s"; break;
- case GeUVecI8x16: o << "i8x16.ge_u"; break;
- case EqVecI16x8: o << "i16x8.eq"; break;
- case NeVecI16x8: o << "i16x8.ne"; break;
- case LtSVecI16x8: o << "i16x8.lt_s"; break;
- case LtUVecI16x8: o << "i16x8.lt_u"; break;
- case GtSVecI16x8: o << "i16x8.gt_s"; break;
- case GtUVecI16x8: o << "i16x8.gt_u"; break;
- case LeSVecI16x8: o << "i16x8.le_s"; break;
- case LeUVecI16x8: o << "i16x8.le_u"; break;
- case GeSVecI16x8: o << "i16x8.ge_s"; break;
- case GeUVecI16x8: o << "i16x8.ge_u"; break;
- case EqVecI32x4: o << "i32x4.eq"; break;
- case NeVecI32x4: o << "i32x4.ne"; break;
- case LtSVecI32x4: o << "i32x4.lt_s"; break;
- case LtUVecI32x4: o << "i32x4.lt_u"; break;
- case GtSVecI32x4: o << "i32x4.gt_s"; break;
- case GtUVecI32x4: o << "i32x4.gt_u"; break;
- case LeSVecI32x4: o << "i32x4.le_s"; break;
- case LeUVecI32x4: o << "i32x4.le_u"; break;
- case GeSVecI32x4: o << "i32x4.ge_s"; break;
- case GeUVecI32x4: o << "i32x4.ge_u"; break;
- case EqVecF32x4: o << "f32x4.eq"; break;
- case NeVecF32x4: o << "f32x4.ne"; break;
- case LtVecF32x4: o << "f32x4.lt"; break;
- case GtVecF32x4: o << "f32x4.gt"; break;
- case LeVecF32x4: o << "f32x4.le"; break;
- case GeVecF32x4: o << "f32x4.ge"; break;
- case EqVecF64x2: o << "f64x2.eq"; break;
- case NeVecF64x2: o << "f64x2.ne"; break;
- case LtVecF64x2: o << "f64x2.lt"; break;
- case GtVecF64x2: o << "f64x2.gt"; break;
- case LeVecF64x2: o << "f64x2.le"; break;
- case GeVecF64x2: o << "f64x2.ge"; break;
+ case EqVecI8x16:
+ o << "i8x16.eq";
+ break;
+ case NeVecI8x16:
+ o << "i8x16.ne";
+ break;
+ case LtSVecI8x16:
+ o << "i8x16.lt_s";
+ break;
+ case LtUVecI8x16:
+ o << "i8x16.lt_u";
+ break;
+ case GtSVecI8x16:
+ o << "i8x16.gt_s";
+ break;
+ case GtUVecI8x16:
+ o << "i8x16.gt_u";
+ break;
+ case LeSVecI8x16:
+ o << "i8x16.le_s";
+ break;
+ case LeUVecI8x16:
+ o << "i8x16.le_u";
+ break;
+ case GeSVecI8x16:
+ o << "i8x16.ge_s";
+ break;
+ case GeUVecI8x16:
+ o << "i8x16.ge_u";
+ break;
+ case EqVecI16x8:
+ o << "i16x8.eq";
+ break;
+ case NeVecI16x8:
+ o << "i16x8.ne";
+ break;
+ case LtSVecI16x8:
+ o << "i16x8.lt_s";
+ break;
+ case LtUVecI16x8:
+ o << "i16x8.lt_u";
+ break;
+ case GtSVecI16x8:
+ o << "i16x8.gt_s";
+ break;
+ case GtUVecI16x8:
+ o << "i16x8.gt_u";
+ break;
+ case LeSVecI16x8:
+ o << "i16x8.le_s";
+ break;
+ case LeUVecI16x8:
+ o << "i16x8.le_u";
+ break;
+ case GeSVecI16x8:
+ o << "i16x8.ge_s";
+ break;
+ case GeUVecI16x8:
+ o << "i16x8.ge_u";
+ break;
+ case EqVecI32x4:
+ o << "i32x4.eq";
+ break;
+ case NeVecI32x4:
+ o << "i32x4.ne";
+ break;
+ case LtSVecI32x4:
+ o << "i32x4.lt_s";
+ break;
+ case LtUVecI32x4:
+ o << "i32x4.lt_u";
+ break;
+ case GtSVecI32x4:
+ o << "i32x4.gt_s";
+ break;
+ case GtUVecI32x4:
+ o << "i32x4.gt_u";
+ break;
+ case LeSVecI32x4:
+ o << "i32x4.le_s";
+ break;
+ case LeUVecI32x4:
+ o << "i32x4.le_u";
+ break;
+ case GeSVecI32x4:
+ o << "i32x4.ge_s";
+ break;
+ case GeUVecI32x4:
+ o << "i32x4.ge_u";
+ break;
+ case EqVecF32x4:
+ o << "f32x4.eq";
+ break;
+ case NeVecF32x4:
+ o << "f32x4.ne";
+ break;
+ case LtVecF32x4:
+ o << "f32x4.lt";
+ break;
+ case GtVecF32x4:
+ o << "f32x4.gt";
+ break;
+ case LeVecF32x4:
+ o << "f32x4.le";
+ break;
+ case GeVecF32x4:
+ o << "f32x4.ge";
+ break;
+ case EqVecF64x2:
+ o << "f64x2.eq";
+ break;
+ case NeVecF64x2:
+ o << "f64x2.ne";
+ break;
+ case LtVecF64x2:
+ o << "f64x2.lt";
+ break;
+ case GtVecF64x2:
+ o << "f64x2.gt";
+ break;
+ case LeVecF64x2:
+ o << "f64x2.le";
+ break;
+ case GeVecF64x2:
+ o << "f64x2.ge";
+ break;
- case AndVec128: o << "v128.and"; break;
- case OrVec128: o << "v128.or"; break;
- case XorVec128: o << "v128.xor"; break;
+ case AndVec128:
+ o << "v128.and";
+ break;
+ case OrVec128:
+ o << "v128.or";
+ break;
+ case XorVec128:
+ o << "v128.xor";
+ break;
- case AddVecI8x16: o << "i8x16.add"; break;
- case AddSatSVecI8x16: o << "i8x16.add_saturate_s"; break;
- case AddSatUVecI8x16: o << "i8x16.add_saturate_u"; break;
- case SubVecI8x16: o << "i8x16.sub"; break;
- case SubSatSVecI8x16: o << "i8x16.sub_saturate_s"; break;
- case SubSatUVecI8x16: o << "i8x16.sub_saturate_u"; break;
- case MulVecI8x16: o << "i8x16.mul"; break;
- case AddVecI16x8: o << "i16x8.add"; break;
- case AddSatSVecI16x8: o << "i16x8.add_saturate_s"; break;
- case AddSatUVecI16x8: o << "i16x8.add_saturate_u"; break;
- case SubVecI16x8: o << "i16x8.sub"; break;
- case SubSatSVecI16x8: o << "i16x8.sub_saturate_s"; break;
- case SubSatUVecI16x8: o << "i16x8.sub_saturate_u"; break;
- case MulVecI16x8: o << "i16x8.mul"; break;
- case AddVecI32x4: o << "i32x4.add"; break;
- case SubVecI32x4: o << "i32x4.sub"; break;
- case MulVecI32x4: o << "i32x4.mul"; break;
- case AddVecI64x2: o << "i64x2.add"; break;
- case SubVecI64x2: o << "i64x2.sub"; break;
+ case AddVecI8x16:
+ o << "i8x16.add";
+ break;
+ case AddSatSVecI8x16:
+ o << "i8x16.add_saturate_s";
+ break;
+ case AddSatUVecI8x16:
+ o << "i8x16.add_saturate_u";
+ break;
+ case SubVecI8x16:
+ o << "i8x16.sub";
+ break;
+ case SubSatSVecI8x16:
+ o << "i8x16.sub_saturate_s";
+ break;
+ case SubSatUVecI8x16:
+ o << "i8x16.sub_saturate_u";
+ break;
+ case MulVecI8x16:
+ o << "i8x16.mul";
+ break;
+ case AddVecI16x8:
+ o << "i16x8.add";
+ break;
+ case AddSatSVecI16x8:
+ o << "i16x8.add_saturate_s";
+ break;
+ case AddSatUVecI16x8:
+ o << "i16x8.add_saturate_u";
+ break;
+ case SubVecI16x8:
+ o << "i16x8.sub";
+ break;
+ case SubSatSVecI16x8:
+ o << "i16x8.sub_saturate_s";
+ break;
+ case SubSatUVecI16x8:
+ o << "i16x8.sub_saturate_u";
+ break;
+ case MulVecI16x8:
+ o << "i16x8.mul";
+ break;
+ case AddVecI32x4:
+ o << "i32x4.add";
+ break;
+ case SubVecI32x4:
+ o << "i32x4.sub";
+ break;
+ case MulVecI32x4:
+ o << "i32x4.mul";
+ break;
+ case AddVecI64x2:
+ o << "i64x2.add";
+ break;
+ case SubVecI64x2:
+ o << "i64x2.sub";
+ break;
- case AddVecF32x4: o << "f32x4.add"; break;
- case SubVecF32x4: o << "f32x4.sub"; break;
- case MulVecF32x4: o << "f32x4.mul"; break;
- case DivVecF32x4: o << "f32x4.div"; break;
- case MinVecF32x4: o << "f32x4.min"; break;
- case MaxVecF32x4: o << "f32x4.max"; break;
- case AddVecF64x2: o << "f64x2.add"; break;
- case SubVecF64x2: o << "f64x2.sub"; break;
- case MulVecF64x2: o << "f64x2.mul"; break;
- case DivVecF64x2: o << "f64x2.div"; break;
- case MinVecF64x2: o << "f64x2.min"; break;
- case MaxVecF64x2: o << "f64x2.max"; break;
+ case AddVecF32x4:
+ o << "f32x4.add";
+ break;
+ case SubVecF32x4:
+ o << "f32x4.sub";
+ break;
+ case MulVecF32x4:
+ o << "f32x4.mul";
+ break;
+ case DivVecF32x4:
+ o << "f32x4.div";
+ break;
+ case MinVecF32x4:
+ o << "f32x4.min";
+ break;
+ case MaxVecF32x4:
+ o << "f32x4.max";
+ break;
+ case AddVecF64x2:
+ o << "f64x2.add";
+ break;
+ case SubVecF64x2:
+ o << "f64x2.sub";
+ break;
+ case MulVecF64x2:
+ o << "f64x2.mul";
+ break;
+ case DivVecF64x2:
+ o << "f64x2.div";
+ break;
+ case MinVecF64x2:
+ o << "f64x2.min";
+ break;
+ case MaxVecF64x2:
+ o << "f64x2.max";
+ break;
- case InvalidBinary: WASM_UNREACHABLE();
+ case InvalidBinary:
+ WASM_UNREACHABLE();
}
restoreNormalColor(o);
}
- void visitSelect(Select* curr) {
- prepareColor(o) << "select";
- }
- void visitDrop(Drop* curr) {
- printMedium(o, "drop");
- }
- void visitReturn(Return* curr) {
- printMedium(o, "return");
- }
+ void visitSelect(Select* curr) { prepareColor(o) << "select"; }
+ void visitDrop(Drop* curr) { printMedium(o, "drop"); }
+ void visitReturn(Return* curr) { printMedium(o, "return"); }
void visitHost(Host* curr) {
switch (curr->op) {
- case CurrentMemory: printMedium(o, "current_memory"); break;
- case GrowMemory: printMedium(o, "grow_memory"); break;
+ case CurrentMemory:
+ printMedium(o, "current_memory");
+ break;
+ case GrowMemory:
+ printMedium(o, "grow_memory");
+ break;
}
}
- void visitNop(Nop* curr) {
- printMinor(o, "nop");
- }
- void visitUnreachable(Unreachable* curr) {
- printMinor(o, "unreachable");
- }
+ void visitNop(Nop* curr) { printMinor(o, "nop"); }
+ void visitUnreachable(Unreachable* curr) { printMinor(o, "unreachable"); }
};
// Prints an expression in s-expr format, including both the
@@ -608,8 +1157,8 @@ struct PrintSExpression : public Visitor<PrintSExpression> {
unsigned indent = 0;
bool minify;
- const char *maybeSpace;
- const char *maybeNewLine;
+ const char* maybeSpace;
+ const char* maybeNewLine;
bool full = false; // whether to not elide nodes in output when possible
// (like implicit blocks) and to emit types
@@ -625,16 +1174,18 @@ struct PrintSExpression : public Visitor<PrintSExpression> {
PrintSExpression(std::ostream& o) : o(o) {
setMinify(false);
- if (!full) full = isFullForced();
+ if (!full)
+ full = isFullForced();
}
- void printDebugLocation(const Function::DebugLocation &location) {
+ void printDebugLocation(const Function::DebugLocation& location) {
if (lastPrintedLocation == location) {
return;
}
lastPrintedLocation = location;
auto fileName = currModule->debugInfoFileNames[location.fileIndex];
- o << ";;@ " << fileName << ":" << location.lineNumber << ":" << location.columnNumber << '\n';
+ o << ";;@ " << fileName << ":" << location.lineNumber << ":"
+ << location.columnNumber << '\n';
doIndent(o, indent);
}
@@ -663,7 +1214,8 @@ struct PrintSExpression : public Visitor<PrintSExpression> {
void setFull(bool full_) { full = full_; }
void incIndent() {
- if (minify) return;
+ if (minify)
+ return;
o << '\n';
indent++;
}
@@ -675,7 +1227,7 @@ struct PrintSExpression : public Visitor<PrintSExpression> {
}
o << ')';
}
- void printFullLine(Expression *expression) {
+ void printFullLine(Expression* expression) {
!minify && doIndent(o, indent);
if (full) {
o << "[" << printType(expression->type) << "] ";
@@ -685,7 +1237,8 @@ struct PrintSExpression : public Visitor<PrintSExpression> {
}
void visitBlock(Block* curr) {
- // special-case Block, because Block nesting (in their first element) can be incredibly deep
+ // special-case Block, because Block nesting (in their first element) can be
+ // incredibly deep
std::vector<Block*> stack;
while (1) {
if (stack.size() > 0) {
@@ -743,13 +1296,17 @@ struct PrintSExpression : public Visitor<PrintSExpression> {
incIndent();
printFullLine(curr->condition);
// ifTrue and False have implict blocks, avoid printing them if possible
- if (!full && curr->ifTrue->is<Block>() && curr->ifTrue->dynCast<Block>()->name.isNull() && curr->ifTrue->dynCast<Block>()->list.size() == 1) {
+ if (!full && curr->ifTrue->is<Block>() &&
+ curr->ifTrue->dynCast<Block>()->name.isNull() &&
+ curr->ifTrue->dynCast<Block>()->list.size() == 1) {
printFullLine(curr->ifTrue->dynCast<Block>()->list.back());
} else {
printFullLine(curr->ifTrue);
}
if (curr->ifFalse) {
- if (!full && curr->ifFalse->is<Block>() && curr->ifFalse->dynCast<Block>()->name.isNull() && curr->ifFalse->dynCast<Block>()->list.size() == 1) {
+ if (!full && curr->ifFalse->is<Block>() &&
+ curr->ifFalse->dynCast<Block>()->name.isNull() &&
+ curr->ifFalse->dynCast<Block>()->list.size() == 1) {
printFullLine(curr->ifFalse->dynCast<Block>()->list.back());
} else {
printFullLine(curr->ifFalse);
@@ -795,7 +1352,8 @@ struct PrintSExpression : public Visitor<PrintSExpression> {
}
incIndent();
}
- if (curr->value && !curr->value->is<Nop>()) printFullLine(curr->value);
+ if (curr->value && !curr->value->is<Nop>())
+ printFullLine(curr->value);
if (curr->condition) {
printFullLine(curr->condition);
}
@@ -805,13 +1363,13 @@ struct PrintSExpression : public Visitor<PrintSExpression> {
o << '(';
PrintExpressionContents(currFunction, o).visit(curr);
incIndent();
- if (curr->value && !curr->value->is<Nop>()) printFullLine(curr->value);
+ if (curr->value && !curr->value->is<Nop>())
+ printFullLine(curr->value);
printFullLine(curr->condition);
decIndent();
}
- template<typename CallBase>
- void printCallOperands(CallBase* curr) {
+ template<typename CallBase> void printCallOperands(CallBase* curr) {
if (curr->operands.size() > 0) {
incIndent();
for (auto operand : curr->operands) {
@@ -895,7 +1453,7 @@ struct PrintSExpression : public Visitor<PrintSExpression> {
decIndent();
}
void visitAtomicWait(AtomicWait* curr) {
- o << '(' ;
+ o << '(';
PrintExpressionContents(currFunction, o).visit(curr);
restoreNormalColor(o);
incIndent();
@@ -1060,7 +1618,8 @@ struct PrintSExpression : public Visitor<PrintSExpression> {
// Module-level visitors
void visitFunctionType(FunctionType* curr, Name* internalName = nullptr) {
o << "(func";
- if (internalName) o << ' ' << *internalName;
+ if (internalName)
+ o << ' ' << *internalName;
if (curr->params.size() > 0) {
o << maybeSpace;
o << '(';
@@ -1082,11 +1641,20 @@ struct PrintSExpression : public Visitor<PrintSExpression> {
printMedium(o, "export ");
printText(o, curr->name.str) << " (";
switch (curr->kind) {
- case ExternalKind::Function: o << "func"; break;
- case ExternalKind::Table: o << "table"; break;
- case ExternalKind::Memory: o << "memory"; break;
- case ExternalKind::Global: o << "global"; break;
- case ExternalKind::Invalid: WASM_UNREACHABLE();
+ case ExternalKind::Function:
+ o << "func";
+ break;
+ case ExternalKind::Table:
+ o << "table";
+ break;
+ case ExternalKind::Memory:
+ o << "memory";
+ break;
+ case ExternalKind::Global:
+ o << "global";
+ break;
+ case ExternalKind::Invalid:
+ WASM_UNREACHABLE();
}
o << ' ';
printName(curr->value, o) << "))";
@@ -1140,7 +1708,7 @@ struct PrintSExpression : public Visitor<PrintSExpression> {
void visitImportedFunction(Function* curr) {
doIndent(o, indent);
currFunction = curr;
- lastPrintedLocation = { 0, 0, 0 };
+ lastPrintedLocation = {0, 0, 0};
o << '(';
emitImportHeader(curr);
if (curr->type.is()) {
@@ -1155,7 +1723,7 @@ struct PrintSExpression : public Visitor<PrintSExpression> {
void visitDefinedFunction(Function* curr) {
doIndent(o, indent);
currFunction = curr;
- lastPrintedLocation = { 0, 0, 0 };
+ lastPrintedLocation = {0, 0, 0};
if (currFunction->prologLocation.size()) {
printDebugLocation(*currFunction->prologLocation.begin());
}
@@ -1180,7 +1748,8 @@ struct PrintSExpression : public Visitor<PrintSExpression> {
for (size_t i = 0; i < curr->params.size(); i++) {
o << maybeSpace;
o << '(';
- printMinor(o, "param ") << printableLocal(i, currFunction) << ' ' << printType(curr->getLocalType(i)) << ')';
+ printMinor(o, "param ") << printableLocal(i, currFunction) << ' '
+ << printType(curr->getLocalType(i)) << ')';
}
}
if (curr->result != none) {
@@ -1192,14 +1761,17 @@ struct PrintSExpression : public Visitor<PrintSExpression> {
for (size_t i = curr->getVarIndexBase(); i < curr->getNumLocals(); i++) {
doIndent(o, indent);
o << '(';
- printMinor(o, "local ") << printableLocal(i, currFunction) << ' ' << printType(curr->getLocalType(i)) << ')';
+ printMinor(o, "local ") << printableLocal(i, currFunction) << ' '
+ << printType(curr->getLocalType(i)) << ')';
o << maybeNewLine;
}
// Print the body.
if (!printStackIR || !curr->stackIR) {
- // It is ok to emit a block here, as a function can directly contain a list, even if our
- // ast avoids that for simplicity. We can just do that optimization here..
- if (!full && curr->body->is<Block>() && curr->body->cast<Block>()->name.isNull()) {
+ // It is ok to emit a block here, as a function can directly contain a
+ // list, even if our ast avoids that for simplicity. We can just do that
+ // optimization here..
+ if (!full && curr->body->is<Block>() &&
+ curr->body->cast<Block>()->name.isNull()) {
Block* block = curr->body->cast<Block>();
for (auto item : block->list) {
printFullLine(item);
@@ -1211,8 +1783,10 @@ struct PrintSExpression : public Visitor<PrintSExpression> {
// Print the stack IR.
WasmPrinter::printStackIR(curr->stackIR.get(), o, curr);
}
- if (currFunction->epilogLocation.size() && lastPrintedLocation != *currFunction->epilogLocation.begin()) {
- // Print last debug location: mix of decIndent and printDebugLocation logic.
+ if (currFunction->epilogLocation.size() &&
+ lastPrintedLocation != *currFunction->epilogLocation.begin()) {
+ // Print last debug location: mix of decIndent and printDebugLocation
+ // logic.
doIndent(o, indent);
if (!minify) {
indent--;
@@ -1229,11 +1803,13 @@ struct PrintSExpression : public Visitor<PrintSExpression> {
printMedium(o, "table") << ' ';
printName(curr->name, o) << ' ';
o << curr->initial;
- if (curr->hasMax()) o << ' ' << curr->max;
+ if (curr->hasMax())
+ o << ' ' << curr->max;
o << " funcref)";
}
void visitTable(Table* curr) {
- if (!curr->exists) return;
+ if (!curr->exists)
+ return;
if (curr->imported()) {
doIndent(o, indent);
o << '(';
@@ -1247,7 +1823,8 @@ struct PrintSExpression : public Visitor<PrintSExpression> {
}
for (auto& segment : curr->segments) {
// Don't print empty segments
- if (segment.data.empty()) continue;
+ if (segment.data.empty())
+ continue;
doIndent(o, indent);
o << '(';
printMajor(o, "elem ");
@@ -1268,12 +1845,15 @@ struct PrintSExpression : public Visitor<PrintSExpression> {
printMedium(o, "shared ");
}
o << curr->initial;
- if (curr->hasMax()) o << ' ' << curr->max;
- if (curr->shared) o << ")";
+ if (curr->hasMax())
+ o << ' ' << curr->max;
+ if (curr->shared)
+ o << ")";
o << ")";
}
void visitMemory(Memory* curr) {
- if (!curr->exists) return;
+ if (!curr->exists)
+ return;
if (curr->imported()) {
doIndent(o, indent);
o << '(';
@@ -1298,19 +1878,35 @@ struct PrintSExpression : public Visitor<PrintSExpression> {
for (size_t i = 0; i < segment.data.size(); i++) {
unsigned char c = segment.data[i];
switch (c) {
- case '\n': o << "\\n"; break;
- case '\r': o << "\\0d"; break;
- case '\t': o << "\\t"; break;
- case '\f': o << "\\0c"; break;
- case '\b': o << "\\08"; break;
- case '\\': o << "\\\\"; break;
- case '"' : o << "\\\""; break;
- case '\'' : o << "\\'"; break;
+ case '\n':
+ o << "\\n";
+ break;
+ case '\r':
+ o << "\\0d";
+ break;
+ case '\t':
+ o << "\\t";
+ break;
+ case '\f':
+ o << "\\0c";
+ break;
+ case '\b':
+ o << "\\08";
+ break;
+ case '\\':
+ o << "\\\\";
+ break;
+ case '"':
+ o << "\\\"";
+ break;
+ case '\'':
+ o << "\\'";
+ break;
default: {
if (c >= 32 && c < 127) {
o << c;
} else {
- o << std::hex << '\\' << (c/16) << (c%16) << std::dec;
+ o << std::hex << '\\' << (c / 16) << (c % 16) << std::dec;
}
}
}
@@ -1331,27 +1927,20 @@ struct PrintSExpression : public Visitor<PrintSExpression> {
visitFunctionType(child.get());
o << ")" << maybeNewLine;
}
- ModuleUtils::iterImportedMemories(*curr, [&](Memory* memory) {
- visitMemory(memory);
- });
- ModuleUtils::iterImportedTables(*curr, [&](Table* table) {
- visitTable(table);
- });
- ModuleUtils::iterImportedGlobals(*curr, [&](Global* global) {
- visitGlobal(global);
- });
- ModuleUtils::iterImportedFunctions(*curr, [&](Function* func) {
- visitFunction(func);
- });
- ModuleUtils::iterDefinedMemories(*curr, [&](Memory* memory) {
- visitMemory(memory);
- });
- ModuleUtils::iterDefinedTables(*curr, [&](Table* table) {
- visitTable(table);
- });
- ModuleUtils::iterDefinedGlobals(*curr, [&](Global* global) {
- visitGlobal(global);
- });
+ ModuleUtils::iterImportedMemories(
+ *curr, [&](Memory* memory) { visitMemory(memory); });
+ ModuleUtils::iterImportedTables(*curr,
+ [&](Table* table) { visitTable(table); });
+ ModuleUtils::iterImportedGlobals(
+ *curr, [&](Global* global) { visitGlobal(global); });
+ ModuleUtils::iterImportedFunctions(
+ *curr, [&](Function* func) { visitFunction(func); });
+ ModuleUtils::iterDefinedMemories(
+ *curr, [&](Memory* memory) { visitMemory(memory); });
+ ModuleUtils::iterDefinedTables(*curr,
+ [&](Table* table) { visitTable(table); });
+ ModuleUtils::iterDefinedGlobals(
+ *curr, [&](Global* global) { visitGlobal(global); });
for (auto& child : curr->exports) {
doIndent(o, indent);
visitExport(child.get());
@@ -1363,12 +1952,12 @@ struct PrintSExpression : public Visitor<PrintSExpression> {
printMedium(o, "start") << ' ' << curr->start << ')';
o << maybeNewLine;
}
- ModuleUtils::iterDefinedFunctions(*curr, [&](Function* func) {
- visitFunction(func);
- });
+ ModuleUtils::iterDefinedFunctions(
+ *curr, [&](Function* func) { visitFunction(func); });
for (auto& section : curr->userSections) {
doIndent(o, indent);
- o << ";; custom section \"" << section.name << "\", size " << section.data.size();
+ o << ";; custom section \"" << section.name << "\", size "
+ << section.data.size();
o << maybeNewLine;
}
decIndent();
@@ -1394,9 +1983,7 @@ public:
}
};
-Pass *createPrinterPass() {
- return new Printer();
-}
+Pass* createPrinterPass() { return new Printer(); }
// Prints out a minified module
@@ -1412,9 +1999,7 @@ public:
}
};
-Pass *createMinifiedPrinterPass() {
- return new MinifiedPrinter();
-}
+Pass* createMinifiedPrinterPass() { return new MinifiedPrinter(); }
// Prints out a module withough elision, i.e., the full ast
@@ -1430,9 +2015,7 @@ public:
}
};
-Pass *createFullPrinterPass() {
- return new FullPrinter();
-}
+Pass* createFullPrinterPass() { return new FullPrinter(); }
// Print Stack IR (if present)
@@ -1448,9 +2031,7 @@ public:
}
};
-Pass* createPrintStackIRPass() {
- return new PrintStackIR();
-}
+Pass* createPrintStackIRPass() { return new PrintStackIR(); }
// Print individual expressions
@@ -1466,7 +2047,10 @@ std::ostream& WasmPrinter::printModule(Module* module) {
return printModule(module, std::cout);
}
-std::ostream& WasmPrinter::printExpression(Expression* expression, std::ostream& o, bool minify, bool full) {
+std::ostream& WasmPrinter::printExpression(Expression* expression,
+ std::ostream& o,
+ bool minify,
+ bool full) {
if (!expression) {
o << "(null expression)";
return o;
@@ -1481,7 +2065,8 @@ std::ostream& WasmPrinter::printExpression(Expression* expression, std::ostream&
return o;
}
-std::ostream& WasmPrinter::printStackInst(StackInst* inst, std::ostream& o, Function* func) {
+std::ostream&
+WasmPrinter::printStackInst(StackInst* inst, std::ostream& o, Function* func) {
switch (inst->op) {
case StackInst::Basic: {
PrintExpressionContents(func, o).visit(inst->origin);
@@ -1503,12 +2088,14 @@ std::ostream& WasmPrinter::printStackInst(StackInst* inst, std::ostream& o, Func
o << "else";
break;
}
- default: WASM_UNREACHABLE();
+ default:
+ WASM_UNREACHABLE();
}
return o;
}
-std::ostream& WasmPrinter::printStackIR(StackIR* ir, std::ostream& o, Function* func) {
+std::ostream&
+WasmPrinter::printStackIR(StackIR* ir, std::ostream& o, Function* func) {
size_t indent = func ? 2 : 0;
auto doIndent = [&indent, &o]() {
for (size_t j = 0; j < indent; j++) {
@@ -1517,7 +2104,8 @@ std::ostream& WasmPrinter::printStackIR(StackIR* ir, std::ostream& o, Function*
};
for (Index i = 0; i < (*ir).size(); i++) {
auto* inst = (*ir)[i];
- if (!inst) continue;
+ if (!inst)
+ continue;
switch (inst->op) {
case StackInst::Basic: {
doIndent();
@@ -1548,7 +2136,8 @@ std::ostream& WasmPrinter::printStackIR(StackIR* ir, std::ostream& o, Function*
doIndent();
break;
}
- default: WASM_UNREACHABLE();
+ default:
+ WASM_UNREACHABLE();
}
std::cout << '\n';
}
diff --git a/src/passes/PrintCallGraph.cpp b/src/passes/PrintCallGraph.cpp
index 2a82b7aa1..7df5a8875 100644
--- a/src/passes/PrintCallGraph.cpp
+++ b/src/passes/PrintCallGraph.cpp
@@ -15,17 +15,17 @@
*/
//
-// Prints the call graph in .dot format. You can use http://www.graphviz.org/ to view .dot files.
+// Prints the call graph in .dot format. You can use http://www.graphviz.org/ to
+// view .dot files.
//
-
-#include <memory>
#include <iomanip>
+#include <memory>
-#include "wasm.h"
-#include "pass.h"
#include "ir/module-utils.h"
#include "ir/utils.h"
+#include "pass.h"
+#include "wasm.h"
namespace wasm {
@@ -33,7 +33,7 @@ struct PrintCallGraph : public Pass {
bool modifiesBinaryenIR() override { return false; }
void run(PassRunner* runner, Module* module) override {
- std::ostream &o = std::cout;
+ std::ostream& o = std::cout;
o << "digraph call {\n"
" rankdir = LR;\n"
" subgraph cluster_key {\n"
@@ -42,35 +42,40 @@ struct PrintCallGraph : public Pass {
" label = \"Key\";\n"
" \"Import\" [style=\"filled\", fillcolor=\"turquoise\"];\n"
" \"Export\" [style=\"filled\", fillcolor=\"gray\"];\n"
- " \"Indirect Target\" [style=\"filled, rounded\", fillcolor=\"white\"];\n"
- " \"A\" -> \"B\" [style=\"filled, rounded\", label = \"Direct Call\"];\n"
+ " \"Indirect Target\" [style=\"filled, rounded\", "
+ "fillcolor=\"white\"];\n"
+ " \"A\" -> \"B\" [style=\"filled, rounded\", label = \"Direct "
+ "Call\"];\n"
" }\n\n"
" node [shape=box, fontname=courier, fontsize=10];\n";
// Defined functions
ModuleUtils::iterDefinedFunctions(*module, [&](Function* curr) {
- std::cout << " \"" << curr->name << "\" [style=\"filled\", fillcolor=\"white\"];\n";
+ std::cout << " \"" << curr->name
+ << "\" [style=\"filled\", fillcolor=\"white\"];\n";
});
// Imported functions
ModuleUtils::iterImportedFunctions(*module, [&](Function* curr) {
- o << " \"" << curr->name << "\" [style=\"filled\", fillcolor=\"turquoise\"];\n";
+ o << " \"" << curr->name
+ << "\" [style=\"filled\", fillcolor=\"turquoise\"];\n";
});
// Exports
for (auto& curr : module->exports) {
if (curr->kind == ExternalKind::Function) {
Function* func = module->getFunction(curr->value);
- o << " \"" << func->name << "\" [style=\"filled\", fillcolor=\"gray\"];\n";
+ o << " \"" << func->name
+ << "\" [style=\"filled\", fillcolor=\"gray\"];\n";
}
}
struct CallPrinter : public PostWalker<CallPrinter> {
- Module *module;
- Function *currFunction;
+ Module* module;
+ Function* currFunction;
std::set<Name> visitedTargets; // Used to avoid printing duplicate edges.
std::vector<Function*> allIndirectTargets;
- CallPrinter(Module *module) : module(module) {
+ CallPrinter(Module* module) : module(module) {
// Walk function bodies.
ModuleUtils::iterDefinedFunctions(*module, [&](Function* curr) {
currFunction = curr;
@@ -78,11 +83,13 @@ struct PrintCallGraph : public Pass {
walk(curr->body);
});
}
- void visitCall(Call *curr) {
+ void visitCall(Call* curr) {
auto* target = module->getFunction(curr->target);
- if (visitedTargets.count(target->name) > 0) return;
+ if (visitedTargets.count(target->name) > 0)
+ return;
visitedTargets.insert(target->name);
- std::cout << " \"" << currFunction->name << "\" -> \"" << target->name << "\"; // call\n";
+ std::cout << " \"" << currFunction->name << "\" -> \"" << target->name
+ << "\"; // call\n";
}
};
CallPrinter printer(module);
@@ -99,8 +106,6 @@ struct PrintCallGraph : public Pass {
}
};
-Pass *createPrintCallGraphPass() {
- return new PrintCallGraph();
-}
+Pass* createPrintCallGraphPass() { return new PrintCallGraph(); }
} // namespace wasm
diff --git a/src/passes/PrintFeatures.cpp b/src/passes/PrintFeatures.cpp
index 9c7172eee..53ef6676f 100644
--- a/src/passes/PrintFeatures.cpp
+++ b/src/passes/PrintFeatures.cpp
@@ -18,9 +18,9 @@
// Print out the feature options corresponding to enabled features
//
-#include "wasm.h"
-#include "wasm-features.h"
#include "pass.h"
+#include "wasm-features.h"
+#include "wasm.h"
namespace wasm {
@@ -32,8 +32,6 @@ struct PrintFeatures : public Pass {
}
};
-Pass* createPrintFeaturesPass() {
- return new PrintFeatures();
-}
+Pass* createPrintFeaturesPass() { return new PrintFeatures(); }
} // namespace wasm
diff --git a/src/passes/ReReloop.cpp b/src/passes/ReReloop.cpp
index 760bab2b5..3a7c2ad87 100644
--- a/src/passes/ReReloop.cpp
+++ b/src/passes/ReReloop.cpp
@@ -23,13 +23,13 @@
#include <memory>
-#include "wasm.h"
-#include "wasm-builder.h"
-#include "wasm-traversal.h"
-#include "pass.h"
#include "cfg/Relooper.h"
#include "ir/flat.h"
#include "ir/utils.h"
+#include "pass.h"
+#include "wasm-builder.h"
+#include "wasm-traversal.h"
+#include "wasm.h"
#ifdef RERELOOP_DEBUG
#include <wasm-printing.h>
@@ -62,21 +62,13 @@ struct ReReloop final : public Pass {
return currCFGBlock = curr;
}
- CFG::Block* startCFGBlock() {
- return setCurrCFGBlock(makeCFGBlock());
- }
+ CFG::Block* startCFGBlock() { return setCurrCFGBlock(makeCFGBlock()); }
- CFG::Block* getCurrCFGBlock() {
- return currCFGBlock;
- }
+ CFG::Block* getCurrCFGBlock() { return currCFGBlock; }
- Block* getCurrBlock() {
- return currCFGBlock->Code->cast<Block>();
- }
+ Block* getCurrBlock() { return currCFGBlock->Code->cast<Block>(); }
- void finishBlock() {
- getCurrBlock()->finalize();
- }
+ void finishBlock() { getCurrBlock()->finalize(); }
// break handling
@@ -86,19 +78,21 @@ struct ReReloop final : public Pass {
breakTargets[name] = target;
}
- CFG::Block* getBreakTarget(Name name) {
- return breakTargets[name];
- }
+ CFG::Block* getBreakTarget(Name name) { return breakTargets[name]; }
// branch handling
- void addBranch(CFG::Block* from, CFG::Block* to, Expression* condition = nullptr) {
+ void
+ addBranch(CFG::Block* from, CFG::Block* to, Expression* condition = nullptr) {
from->AddBranchTo(to, condition);
}
- void addSwitchBranch(CFG::Block* from, CFG::Block* to, const std::set<Index>& values) {
+ void addSwitchBranch(CFG::Block* from,
+ CFG::Block* to,
+ const std::set<Index>& values) {
std::vector<Index> list;
- for (auto i : values) list.push_back(i);
+ for (auto i : values)
+ list.push_back(i);
from->AddSwitchBranchTo(to, std::move(list));
}
@@ -107,9 +101,7 @@ struct ReReloop final : public Pass {
struct Task {
ReReloop& parent;
Task(ReReloop& parent) : parent(parent) {}
- virtual void run() {
- WASM_UNREACHABLE();
- }
+ virtual void run() { WASM_UNREACHABLE(); }
};
typedef std::shared_ptr<Task> TaskPtr;
@@ -120,9 +112,7 @@ struct ReReloop final : public Pass {
TriageTask(ReReloop& parent, Expression* curr) : Task(parent), curr(curr) {}
- void run() override {
- parent.triage(curr);
- }
+ void run() override { parent.triage(curr); }
};
struct BlockTask final : public Task {
@@ -183,10 +173,12 @@ struct ReReloop final : public Pass {
parent.addBranch(task->condition, ifTrueBegin, curr->condition);
if (curr->ifFalse) {
parent.stack.push_back(task);
- parent.stack.push_back(std::make_shared<TriageTask>(parent, curr->ifFalse));
+ parent.stack.push_back(
+ std::make_shared<TriageTask>(parent, curr->ifFalse));
}
parent.stack.push_back(task);
- parent.stack.push_back(std::make_shared<TriageTask>(parent, curr->ifTrue));
+ parent.stack.push_back(
+ std::make_shared<TriageTask>(parent, curr->ifTrue));
}
void run() override {
@@ -194,7 +186,8 @@ struct ReReloop final : public Pass {
// end of ifTrue
ifTrueEnd = parent.getCurrCFGBlock();
auto* after = parent.startCFGBlock();
- parent.addBranch(condition, after); // if condition was false, go after the ifTrue, to ifFalse or outside
+ // if condition was false, go after the ifTrue, to ifFalse or outside
+ parent.addBranch(condition, after);
if (!curr->ifFalse) {
parent.addBranch(ifTrueEnd, after);
}
@@ -213,9 +206,11 @@ struct ReReloop final : public Pass {
struct BreakTask : public Task {
static void handle(ReReloop& parent, Break* curr) {
- // add the branch. note how if the condition is false, it is the right value there as well
+ // add the branch. note how if the condition is false, it is the right
+ // value there as well
auto* before = parent.getCurrCFGBlock();
- parent.addBranch(before, parent.getBreakTarget(curr->name), curr->condition);
+ parent.addBranch(
+ before, parent.getBreakTarget(curr->name), curr->condition);
if (curr->condition) {
auto* after = parent.startCFGBlock();
parent.addBranch(before, after);
@@ -238,12 +233,14 @@ struct ReReloop final : public Pass {
targetValues[targets[i]].insert(i);
}
for (auto& iter : targetValues) {
- parent.addSwitchBranch(before, parent.getBreakTarget(iter.first), iter.second);
+ parent.addSwitchBranch(
+ before, parent.getBreakTarget(iter.first), iter.second);
}
- // the default may be among the targets, in which case, we can't add it simply as
- // it would be a duplicate, so create a temp block
+ // the default may be among the targets, in which case, we can't add it
+ // simply as it would be a duplicate, so create a temp block
if (targetValues.count(curr->default_) == 0) {
- parent.addSwitchBranch(before, parent.getBreakTarget(curr->default_), std::set<Index>());
+ parent.addSwitchBranch(
+ before, parent.getBreakTarget(curr->default_), std::set<Index>());
} else {
auto* temp = parent.startCFGBlock();
parent.addSwitchBranch(before, temp, std::set<Index>());
@@ -297,7 +294,9 @@ struct ReReloop final : public Pass {
// TODO: optimize with this?
}
- void runOnFunction(PassRunner* runner, Module* module, Function* function) override {
+ void runOnFunction(PassRunner* runner,
+ Module* module,
+ Function* function) override {
Flat::verifyFlatness(function);
// since control flow is flattened, this is pretty simple
@@ -316,15 +315,14 @@ struct ReReloop final : public Pass {
// finish the current block
finishBlock();
// blocks that do not have any exits are dead ends in the relooper. we need
- // to make sure that are in fact dead ends, and do not flow control anywhere.
- // add a return as needed
+ // to make sure that are in fact dead ends, and do not flow control
+ // anywhere. add a return as needed
for (auto* cfgBlock : relooper->Blocks) {
auto* block = cfgBlock->Code->cast<Block>();
if (cfgBlock->BranchesOut.empty() && block->type != unreachable) {
- block->list.push_back(
- function->result == none ? (Expression*)builder->makeReturn()
- : (Expression*)builder->makeUnreachable()
- );
+ block->list.push_back(function->result == none
+ ? (Expression*)builder->makeReturn()
+ : (Expression*)builder->makeUnreachable());
block->finalize();
}
}
@@ -356,10 +354,8 @@ struct ReReloop final : public Pass {
// code, for example, which could be optimized out later
// but isn't yet), then make sure it has a proper type
if (function->result != none && function->body->type == none) {
- function->body = builder.makeSequence(
- function->body,
- builder.makeUnreachable()
- );
+ function->body =
+ builder.makeSequence(function->body, builder.makeUnreachable());
}
}
// TODO: should this be in the relooper itself?
@@ -367,8 +363,6 @@ struct ReReloop final : public Pass {
}
};
-Pass *createReReloopPass() {
- return new ReReloop();
-}
+Pass* createReReloopPass() { return new ReReloop(); }
} // namespace wasm
diff --git a/src/passes/RedundantSetElimination.cpp b/src/passes/RedundantSetElimination.cpp
index 6f39fce9f..e03020da0 100644
--- a/src/passes/RedundantSetElimination.cpp
+++ b/src/passes/RedundantSetElimination.cpp
@@ -33,13 +33,13 @@
// here).
//
-#include <wasm.h>
-#include <pass.h>
-#include <wasm-builder.h>
#include <cfg/cfg-traversal.h>
#include <ir/literal-utils.h>
#include <ir/utils.h>
+#include <pass.h>
#include <support/unique_deferring_queue.h>
+#include <wasm-builder.h>
+#include <wasm.h>
namespace wasm {
@@ -57,7 +57,10 @@ struct Info {
std::vector<Expression**> setps;
};
-struct RedundantSetElimination : public WalkerPass<CFGWalker<RedundantSetElimination, Visitor<RedundantSetElimination>, Info>> {
+struct RedundantSetElimination
+ : public WalkerPass<CFGWalker<RedundantSetElimination,
+ Visitor<RedundantSetElimination>,
+ Info>> {
bool isFunctionParallel() override { return true; }
Pass* create() override { return new RedundantSetElimination(); }
@@ -66,7 +69,8 @@ struct RedundantSetElimination : public WalkerPass<CFGWalker<RedundantSetElimina
// cfg traversal work
- static void doVisitSetLocal(RedundantSetElimination* self, Expression** currp) {
+ static void doVisitSetLocal(RedundantSetElimination* self,
+ Expression** currp) {
if (self->currBasicBlock) {
self->currBasicBlock->contents.setps.push_back(currp);
}
@@ -77,7 +81,8 @@ struct RedundantSetElimination : public WalkerPass<CFGWalker<RedundantSetElimina
void doWalkFunction(Function* func) {
numLocals = func->getNumLocals();
// create the CFG by walking the IR
- CFGWalker<RedundantSetElimination, Visitor<RedundantSetElimination>, Info>::doWalkFunction(func);
+ CFGWalker<RedundantSetElimination, Visitor<RedundantSetElimination>, Info>::
+ doWalkFunction(func);
// flow values across blocks
flowValues(func);
// remove redundant sets
@@ -88,8 +93,10 @@ struct RedundantSetElimination : public WalkerPass<CFGWalker<RedundantSetElimina
Index nextValue = 1; // 0 is reserved for the "unseen value"
std::unordered_map<Literal, Index> literalValues; // each constant has a value
- std::unordered_map<Expression*, Index> expressionValues; // each value can have a value
- std::unordered_map<BasicBlock*, std::unordered_map<Index, Index>> blockMergeValues; // each block has values for each merge
+ std::unordered_map<Expression*, Index>
+ expressionValues; // each value can have a value
+ std::unordered_map<BasicBlock*, std::unordered_map<Index, Index>>
+ blockMergeValues; // each block has values for each merge
Index getUnseenValue() { // we haven't seen this location yet
return 0;
@@ -130,17 +137,20 @@ struct RedundantSetElimination : public WalkerPass<CFGWalker<RedundantSetElimina
return iter->second;
}
#ifdef RSE_DEBUG
- std::cout << "new block-merge value for " << block << " : " << index << '\n';
+ std::cout << "new block-merge value for " << block << " : " << index
+ << '\n';
#endif
return mergeValues[index] = getUniqueValue();
}
bool isBlockMergeValue(BasicBlock* block, Index index, Index value) {
auto iter = blockMergeValues.find(block);
- if (iter == blockMergeValues.end()) return false;
+ if (iter == blockMergeValues.end())
+ return false;
auto& mergeValues = iter->second;
auto iter2 = mergeValues.find(index);
- if (iter2 == mergeValues.end()) return false;
+ if (iter2 == mergeValues.end())
+ return false;
return value == iter2->second;
}
@@ -172,7 +182,8 @@ struct RedundantSetElimination : public WalkerPass<CFGWalker<RedundantSetElimina
#endif
start[i] = getUniqueValue();
} else {
- start[i] = getLiteralValue(Literal::makeZero(func->getLocalType(i)));
+ start[i] =
+ getLiteralValue(Literal::makeZero(func->getLocalType(i)));
}
}
} else {
@@ -274,7 +285,8 @@ struct RedundantSetElimination : public WalkerPass<CFGWalker<RedundantSetElimina
#ifdef RSE_DEBUG
dump("start", curr->contents.start);
#endif
- // flow values through it, then add those we can reach if they need an update.
+ // flow values through it, then add those we can reach if they need an
+ // update.
auto currValues = curr->contents.start; // we'll modify this as we go
auto& setps = curr->contents.setps;
for (auto** setp : setps) {
@@ -351,7 +363,8 @@ struct RedundantSetElimination : public WalkerPass<CFGWalker<RedundantSetElimina
}
}
for (Index i = 0; i < block->contents.start.size(); i++) {
- std::cout << " start[" << i << "] = " << block->contents.start[i] << '\n';
+ std::cout << " start[" << i << "] = " << block->contents.start[i]
+ << '\n';
}
for (auto** setp : block->contents.setps) {
std::cout << " " << *setp << '\n';
@@ -370,7 +383,7 @@ struct RedundantSetElimination : public WalkerPass<CFGWalker<RedundantSetElimina
} // namespace
-Pass *createRedundantSetEliminationPass() {
+Pass* createRedundantSetEliminationPass() {
return new RedundantSetElimination();
}
diff --git a/src/passes/RelooperJumpThreading.cpp b/src/passes/RelooperJumpThreading.cpp
index db865d1bb..9fcf7a4a8 100644
--- a/src/passes/RelooperJumpThreading.cpp
+++ b/src/passes/RelooperJumpThreading.cpp
@@ -19,14 +19,13 @@
// This assumes the very specific output the fastcomp relooper emits,
// including the name of the 'label' variable.
-#include "wasm.h"
-#include "pass.h"
-#include "ir/utils.h"
#include "ir/manipulation.h"
+#include "ir/utils.h"
+#include "pass.h"
+#include "wasm.h"
namespace wasm {
-
static Name LABEL("label");
static Name getInnerName(int i) {
@@ -38,13 +37,17 @@ static Name getOuterName(int i) {
}
static If* isLabelCheckingIf(Expression* curr, Index labelIndex) {
- if (!curr) return nullptr;
+ if (!curr)
+ return nullptr;
auto* iff = curr->dynCast<If>();
- if (!iff) return nullptr;
+ if (!iff)
+ return nullptr;
auto* condition = iff->condition->dynCast<Binary>();
- if (!(condition && condition->op == EqInt32)) return nullptr;
+ if (!(condition && condition->op == EqInt32))
+ return nullptr;
auto* left = condition->left->dynCast<GetLocal>();
- if (!(left && left->index == labelIndex)) return nullptr;
+ if (!(left && left->index == labelIndex))
+ return nullptr;
return iff;
}
@@ -53,10 +56,13 @@ static Index getCheckedLabelValue(If* iff) {
}
static SetLocal* isLabelSettingSetLocal(Expression* curr, Index labelIndex) {
- if (!curr) return nullptr;
+ if (!curr)
+ return nullptr;
auto* set = curr->dynCast<SetLocal>();
- if (!set) return nullptr;
- if (set->index != labelIndex) return nullptr;
+ if (!set)
+ return nullptr;
+ if (set->index != labelIndex)
+ return nullptr;
return set;
}
@@ -69,7 +75,10 @@ struct LabelUseFinder : public PostWalker<LabelUseFinder> {
std::map<Index, Index>& checks; // label value => number of checks on it
std::map<Index, Index>& sets; // label value => number of sets to it
- LabelUseFinder(Index labelIndex, std::map<Index, Index>& checks, std::map<Index, Index>& sets) : labelIndex(labelIndex), checks(checks), sets(sets) {}
+ LabelUseFinder(Index labelIndex,
+ std::map<Index, Index>& checks,
+ std::map<Index, Index>& sets)
+ : labelIndex(labelIndex), checks(checks), sets(sets) {}
void visitIf(If* curr) {
if (isLabelCheckingIf(curr, labelIndex)) {
@@ -84,7 +93,8 @@ struct LabelUseFinder : public PostWalker<LabelUseFinder> {
}
};
-struct RelooperJumpThreading : public WalkerPass<ExpressionStackWalker<RelooperJumpThreading>> {
+struct RelooperJumpThreading
+ : public WalkerPass<ExpressionStackWalker<RelooperJumpThreading>> {
bool isFunctionParallel() override { return true; }
Pass* create() override { return new RelooperJumpThreading; }
@@ -98,9 +108,11 @@ struct RelooperJumpThreading : public WalkerPass<ExpressionStackWalker<RelooperJ
void visitBlock(Block* curr) {
// look for the if label == X pattern
auto& list = curr->list;
- if (list.size() == 0) return;
+ if (list.size() == 0)
+ return;
for (Index i = 0; i < list.size() - 1; i++) {
- // once we see something that might be irreducible, we must skip that if and the rest of the dependents
+ // once we see something that might be irreducible, we must skip that if
+ // and the rest of the dependents
bool irreducible = false;
Index origin = i;
for (Index j = i + 1; j < list.size(); j++) {
@@ -113,15 +125,20 @@ struct RelooperJumpThreading : public WalkerPass<ExpressionStackWalker<RelooperJ
i++;
continue;
}
- // if the next element is a block, it may be the holding block of label-checking ifs
+ // if the next element is a block, it may be the holding block of
+ // label-checking ifs
if (auto* holder = list[j]->dynCast<Block>()) {
if (holder->list.size() > 0) {
if (If* iff = isLabelCheckingIf(holder->list[0], labelIndex)) {
irreducible |= hasIrreducibleControlFlow(iff, list[origin]);
if (!irreducible) {
- // this is indeed a holder. we can process the ifs, and must also move
- // the block to enclose the origin, so it is properly reachable
- assert(holder->list.size() == 1); // must be size 1, a relooper multiple will have its own label, and is an if-else sequence and nothing more
+ // this is indeed a holder. we can process the ifs, and must
+ // also move the block to enclose the origin, so it is properly
+ // reachable
+
+ // must be size 1, a relooper multiple will have its own label,
+ // and is an if-else sequence and nothing more
+ assert(holder->list.size() == 1);
optimizeJumpsToLabelCheck(list[origin], iff);
holder->list[0] = list[origin];
list[origin] = holder;
@@ -155,13 +172,13 @@ struct RelooperJumpThreading : public WalkerPass<ExpressionStackWalker<RelooperJ
}
private:
-
bool hasIrreducibleControlFlow(If* iff, Expression* origin) {
- // Gather the checks in this if chain. If all the label values checked are only set in origin,
- // then since origin is right before us, this is not irreducible - we can replace all sets
- // in origin with jumps forward to us, and since there is nothing else, this is safe and complete.
- // We must also have the property that there is just one check for the label value, as otherwise
- // node splitting has complicated things.
+ // Gather the checks in this if chain. If all the label values checked are
+ // only set in origin, then since origin is right before us, this is not
+ // irreducible - we can replace all sets in origin with jumps forward to us,
+ // and since there is nothing else, this is safe and complete. We must also
+ // have the property that there is just one check for the label value, as
+ // otherwise node splitting has complicated things.
std::map<Index, Index> labelChecksInOrigin;
std::map<Index, Index> labelSetsInOrigin;
LabelUseFinder finder(labelIndex, labelChecksInOrigin, labelSetsInOrigin);
@@ -169,23 +186,27 @@ private:
while (iff) {
auto num = getCheckedLabelValue(iff);
assert(labelChecks[num] > 0);
- if (labelChecks[num] > 1) return true; // checked more than once, somewhere in function
+ if (labelChecks[num] > 1)
+ return true; // checked more than once, somewhere in function
assert(labelChecksInOrigin[num] == 0);
if (labelSetsInOrigin[num] != labelSets[num]) {
assert(labelSetsInOrigin[num] < labelSets[num]);
// the label is set outside of the origin
- // if the only other location is inside the if body, then it is ok - it must be in a loop
- // and returning to the top of the loop body, so we don't need to do anything for that
- // label setting anyhow
+ // if the only other location is inside the if body, then it is ok - it
+ // must be in a loop and returning to the top of the loop body, so we
+ // don't need to do anything for that label setting anyhow
std::map<Index, Index> labelChecksInIfTrue;
std::map<Index, Index> labelSetsInIfTrue;
- LabelUseFinder finder(labelIndex, labelChecksInIfTrue, labelSetsInIfTrue);
+ LabelUseFinder finder(
+ labelIndex, labelChecksInIfTrue, labelSetsInIfTrue);
finder.walk(iff->ifTrue);
if (labelSetsInOrigin[num] + labelSetsInIfTrue[num] < labelSets[num]) {
- // label set somewhere we can't see now, could be irreducible control flow
- // TODO: one case where this happens is instead of an if-chain, we have
- // ifs and a switch on label|0, in separate elements. perhaps not
- // emitting switches on label|0 in the relooper would avoid that.
+ // label set somewhere we can't see now, could be irreducible control
+ // flow
+ // TODO: one case where this happens is instead of an if-chain, we
+ // have ifs and a switch on label|0, in separate elements.
+ // perhaps not emitting switches on label|0 in the relooper
+ // would avoid that.
return true;
}
}
@@ -195,19 +216,23 @@ private:
}
// optimizes jumps to a label check
- // * origin is where the jumps originate, and also where we should write our output
+ // * origin is where the jumps originate, and also where we should write our
+ // output
// * iff is the if
void optimizeJumpsToLabelCheck(Expression*& origin, If* iff) {
Index nameCounter = newNameCounter++;
Index num = getCheckedLabelValue(iff);
// create a new block for this jump target
Builder builder(*getModule());
- // origin is where all jumps to this target must come from - the element right before this if
- // we break out of inner to reach the target. instead of flowing out of normally, we break out of the outer, so we skip the target.
+ // origin is where all jumps to this target must come from - the element
+ // right before this if we break out of inner to reach the target. instead
+ // of flowing out of normally, we break out of the outer, so we skip the
+ // target.
auto innerName = getInnerName(nameCounter);
auto outerName = getOuterName(nameCounter);
auto* ifFalse = iff->ifFalse;
- // all assignments of label to the target can be replaced with breaks to the target, via innerName
+ // all assignments of label to the target can be replaced with breaks to the
+ // target, via innerName
struct JumpUpdater : public PostWalker<JumpUpdater> {
Index labelIndex;
Index targetNum;
@@ -228,7 +253,8 @@ private:
updater.setModule(getModule());
updater.walk(origin);
// restructure code
- auto* inner = builder.blockifyWithName(origin, innerName, builder.makeBreak(outerName));
+ auto* inner =
+ builder.blockifyWithName(origin, innerName, builder.makeBreak(outerName));
auto* outer = builder.makeSequence(inner, iff->ifTrue);
outer->name = outerName;
origin = outer;
@@ -241,9 +267,6 @@ private:
// declare pass
-Pass *createRelooperJumpThreadingPass() {
- return new RelooperJumpThreading();
-}
+Pass* createRelooperJumpThreadingPass() { return new RelooperJumpThreading(); }
} // namespace wasm
-
diff --git a/src/passes/RemoveImports.cpp b/src/passes/RemoveImports.cpp
index e70cbb3ac..a3ca45b16 100644
--- a/src/passes/RemoveImports.cpp
+++ b/src/passes/RemoveImports.cpp
@@ -22,14 +22,14 @@
// look at all the rest of the code).
//
-#include "wasm.h"
-#include "pass.h"
#include "ir/module-utils.h"
+#include "pass.h"
+#include "wasm.h"
namespace wasm {
struct RemoveImports : public WalkerPass<PostWalker<RemoveImports>> {
- void visitCall(Call *curr) {
+ void visitCall(Call* curr) {
auto* func = getModule()->getFunction(curr->target);
if (!func->imported()) {
return;
@@ -44,19 +44,16 @@ struct RemoveImports : public WalkerPass<PostWalker<RemoveImports>> {
}
}
- void visitModule(Module *curr) {
+ void visitModule(Module* curr) {
std::vector<Name> names;
- ModuleUtils::iterImportedFunctions(*curr, [&](Function* func) {
- names.push_back(func->name);
- });
+ ModuleUtils::iterImportedFunctions(
+ *curr, [&](Function* func) { names.push_back(func->name); });
for (auto& name : names) {
curr->removeFunction(name);
}
}
};
-Pass *createRemoveImportsPass() {
- return new RemoveImports();
-}
+Pass* createRemoveImportsPass() { return new RemoveImports(); }
} // namespace wasm
diff --git a/src/passes/RemoveMemory.cpp b/src/passes/RemoveMemory.cpp
index 33d9e6da5..399a32933 100644
--- a/src/passes/RemoveMemory.cpp
+++ b/src/passes/RemoveMemory.cpp
@@ -18,8 +18,8 @@
// Removeds memory segments, leaving only code in the module.
//
-#include <wasm.h>
#include <pass.h>
+#include <wasm.h>
namespace wasm {
@@ -29,8 +29,6 @@ struct RemoveMemory : public Pass {
}
};
-Pass *createRemoveMemoryPass() {
- return new RemoveMemory();
-}
+Pass* createRemoveMemoryPass() { return new RemoveMemory(); }
} // namespace wasm
diff --git a/src/passes/RemoveNonJSOps.cpp b/src/passes/RemoveNonJSOps.cpp
index fc3e42185..26ede65c5 100644
--- a/src/passes/RemoveNonJSOps.cpp
+++ b/src/passes/RemoveNonJSOps.cpp
@@ -27,17 +27,17 @@
// after walking the current module.
//
-#include <wasm.h>
#include <pass.h>
+#include <wasm.h>
-#include "asmjs/shared-constants.h"
-#include "wasm-builder.h"
-#include "wasm-s-parser.h"
#include "abi/js.h"
+#include "asmjs/shared-constants.h"
+#include "ir/find_all.h"
#include "ir/memory-utils.h"
#include "ir/module-utils.h"
-#include "ir/find_all.h"
#include "passes/intrinsics-module.h"
+#include "wasm-builder.h"
+#include "wasm-s-parser.h"
namespace wasm {
@@ -56,7 +56,8 @@ struct RemoveNonJSOpsPass : public WalkerPass<PostWalker<RemoveNonJSOpsPass>> {
// Discover all of the intrinsics that we need to inject, lowering all
// operations to intrinsic calls while we're at it.
- if (!builder) builder = make_unique<Builder>(*module);
+ if (!builder)
+ builder = make_unique<Builder>(*module);
PostWalker<RemoveNonJSOpsPass>::doWalkModule(module);
if (neededIntrinsics.size() == 0) {
@@ -86,7 +87,7 @@ struct RemoveNonJSOpsPass : public WalkerPass<PostWalker<RemoveNonJSOpsPass>> {
// Recursively probe all needed intrinsics for transitively used
// functions. This is building up a set of functions we'll link into our
// module.
- for (auto &name : neededIntrinsics) {
+ for (auto& name : neededIntrinsics) {
addNeededFunctions(intrinsicsModule, name, neededFunctions);
}
neededIntrinsics.clear();
@@ -94,10 +95,11 @@ struct RemoveNonJSOpsPass : public WalkerPass<PostWalker<RemoveNonJSOpsPass>> {
// Link in everything that wasn't already linked in. After we've done the
// copy we then walk the function to rewrite any non-js operations it has
// as well.
- for (auto &name : neededFunctions) {
+ for (auto& name : neededFunctions) {
auto* func = module->getFunctionOrNull(name);
if (!func) {
- func = ModuleUtils::copyFunction(intrinsicsModule.getFunction(name), *module);
+ func = ModuleUtils::copyFunction(intrinsicsModule.getFunction(name),
+ *module);
}
doWalkFunction(func);
}
@@ -123,7 +125,7 @@ struct RemoveNonJSOpsPass : public WalkerPass<PostWalker<RemoveNonJSOpsPass>> {
}
}
- void addNeededFunctions(Module &m, Name name, std::set<Name> &needed) {
+ void addNeededFunctions(Module& m, Name name, std::set<Name>& needed) {
if (needed.count(name)) {
return;
}
@@ -140,7 +142,8 @@ struct RemoveNonJSOpsPass : public WalkerPass<PostWalker<RemoveNonJSOpsPass>> {
}
void doWalkFunction(Function* func) {
- if (!builder) builder = make_unique<Builder>(*getModule());
+ if (!builder)
+ builder = make_unique<Builder>(*getModule());
PostWalker<RemoveNonJSOpsPass>::doWalkFunction(func);
}
@@ -224,10 +227,12 @@ struct RemoveNonJSOpsPass : public WalkerPass<PostWalker<RemoveNonJSOpsPass>> {
name = WASM_I64_UREM;
break;
- default: return;
+ default:
+ return;
}
neededIntrinsics.insert(name);
- replaceCurrent(builder->makeCall(name, {curr->left, curr->right}, curr->type));
+ replaceCurrent(
+ builder->makeCall(name, {curr->left, curr->right}, curr->type));
}
void rewriteCopysign(Binary* curr) {
@@ -253,33 +258,20 @@ struct RemoveNonJSOpsPass : public WalkerPass<PostWalker<RemoveNonJSOpsPass>> {
otherBits = Literal((uint64_t(1) << 63) - 1);
break;
- default: return;
+ default:
+ return;
}
- replaceCurrent(
- builder->makeUnary(
- int2float,
- builder->makeBinary(
- bitOr,
- builder->makeBinary(
- bitAnd,
- builder->makeUnary(
- float2int,
- curr->left
- ),
- builder->makeConst(otherBits)
- ),
- builder->makeBinary(
- bitAnd,
- builder->makeUnary(
- float2int,
- curr->right
- ),
- builder->makeConst(signBit)
- )
- )
- )
- );
+ replaceCurrent(builder->makeUnary(
+ int2float,
+ builder->makeBinary(
+ bitOr,
+ builder->makeBinary(bitAnd,
+ builder->makeUnary(float2int, curr->left),
+ builder->makeConst(otherBits)),
+ builder->makeBinary(bitAnd,
+ builder->makeUnary(float2int, curr->right),
+ builder->makeConst(signBit)))));
}
void visitUnary(Unary* curr) {
@@ -313,7 +305,8 @@ struct RemoveNonJSOpsPass : public WalkerPass<PostWalker<RemoveNonJSOpsPass>> {
functionCall = WASM_CTZ32;
break;
- default: return;
+ default:
+ return;
}
neededIntrinsics.insert(functionCall);
replaceCurrent(builder->makeCall(functionCall, {curr->value}, curr->type));
@@ -324,9 +317,6 @@ struct RemoveNonJSOpsPass : public WalkerPass<PostWalker<RemoveNonJSOpsPass>> {
}
};
-Pass* createRemoveNonJSOpsPass() {
- return new RemoveNonJSOpsPass();
-}
+Pass* createRemoveNonJSOpsPass() { return new RemoveNonJSOpsPass(); }
} // namespace wasm
-
diff --git a/src/passes/RemoveUnusedBrs.cpp b/src/passes/RemoveUnusedBrs.cpp
index 614503581..4b5c9613e 100644
--- a/src/passes/RemoveUnusedBrs.cpp
+++ b/src/passes/RemoveUnusedBrs.cpp
@@ -18,26 +18,31 @@
// Removes branches for which we go to where they go anyhow
//
-#include <wasm.h>
-#include <pass.h>
-#include <parsing.h>
#include <ir/branch-utils.h>
#include <ir/cost.h>
#include <ir/effects.h>
#include <ir/utils.h>
+#include <parsing.h>
+#include <pass.h>
#include <wasm-builder.h>
+#include <wasm.h>
namespace wasm {
// to turn an if into a br-if, we must be able to reorder the
// condition and possible value, and the possible value must
// not have side effects (as they would run unconditionally)
-static bool canTurnIfIntoBrIf(Expression* ifCondition, Expression* brValue, PassOptions& options) {
+static bool canTurnIfIntoBrIf(Expression* ifCondition,
+ Expression* brValue,
+ PassOptions& options) {
// if the if isn't even reached, this is all dead code anyhow
- if (ifCondition->type == unreachable) return false;
- if (!brValue) return true;
+ if (ifCondition->type == unreachable)
+ return false;
+ if (!brValue)
+ return true;
EffectAnalyzer value(options, brValue);
- if (value.hasSideEffects()) return false;
+ if (value.hasSideEffects())
+ return false;
return !EffectAnalyzer(options, ifCondition).invalidates(value);
}
@@ -50,8 +55,8 @@ struct RemoveUnusedBrs : public WalkerPass<PostWalker<RemoveUnusedBrs>> {
typedef std::vector<Expression**> Flows;
- // list of breaks that are currently flowing. if they reach their target without
- // interference, they can be removed (or their value forwarded TODO)
+ // list of breaks that are currently flowing. if they reach their target
+ // without interference, they can be removed (or their value forwarded TODO)
Flows flows;
// a stack for if-else contents, we merge their outputs
@@ -160,23 +165,22 @@ struct RemoveUnusedBrs : public WalkerPass<PostWalker<RemoveUnusedBrs>> {
}
}
- void stopFlow() {
- flows.clear();
- }
+ void stopFlow() { flows.clear(); }
void removeValueFlow(Flows& currFlows) {
- currFlows.erase(std::remove_if(currFlows.begin(), currFlows.end(), [&](Expression** currp) {
- auto* curr = *currp;
- if (auto* ret = curr->dynCast<Return>()) {
- return ret->value;
- }
- return curr->cast<Break>()->value;
- }), currFlows.end());
+ currFlows.erase(std::remove_if(currFlows.begin(),
+ currFlows.end(),
+ [&](Expression** currp) {
+ auto* curr = *currp;
+ if (auto* ret = curr->dynCast<Return>()) {
+ return ret->value;
+ }
+ return curr->cast<Break>()->value;
+ }),
+ currFlows.end());
}
- void stopValueFlow() {
- removeValueFlow(flows);
- }
+ void stopValueFlow() { removeValueFlow(flows); }
static void clear(RemoveUnusedBrs* self, Expression** currp) {
self->flows.clear();
@@ -186,20 +190,20 @@ struct RemoveUnusedBrs : public WalkerPass<PostWalker<RemoveUnusedBrs>> {
self->ifStack.push_back(std::move(self->flows));
}
- void visitLoop(Loop* curr) {
- loops.push_back(curr);
- }
+ void visitLoop(Loop* curr) { loops.push_back(curr); }
void optimizeSwitch(Switch* curr) {
// if the final element is the default, we don't need it
while (!curr->targets.empty() && curr->targets.back() == curr->default_) {
curr->targets.pop_back();
}
- // if the first element is the default, we can remove it by shifting everything (which
- // does add a subtraction of a constant, but often that is worth it as the constant can
- // be folded away and/or we remove multiple elements here)
+ // if the first element is the default, we can remove it by shifting
+ // everything (which does add a subtraction of a constant, but often that is
+ // worth it as the constant can be folded away and/or we remove multiple
+ // elements here)
Index removable = 0;
- while (removable < curr->targets.size() && curr->targets[removable] == curr->default_) {
+ while (removable < curr->targets.size() &&
+ curr->targets[removable] == curr->default_) {
removable++;
}
if (removable > 0) {
@@ -208,50 +212,47 @@ struct RemoveUnusedBrs : public WalkerPass<PostWalker<RemoveUnusedBrs>> {
}
curr->targets.resize(curr->targets.size() - removable);
Builder builder(*getModule());
- curr->condition = builder.makeBinary(SubInt32,
- curr->condition,
- builder.makeConst(Literal(int32_t(removable)))
- );
+ curr->condition =
+ builder.makeBinary(SubInt32,
+ curr->condition,
+ builder.makeConst(Literal(int32_t(removable))));
}
- // when there isn't a value, we can do some trivial optimizations without worrying about
- // the value being executed before the condition
- if (curr->value) return;
+ // when there isn't a value, we can do some trivial optimizations without
+ // worrying about the value being executed before the condition
+ if (curr->value)
+ return;
if (curr->targets.size() == 0) {
// a switch with just a default always goes there
Builder builder(*getModule());
- replaceCurrent(builder.makeSequence(
- builder.makeDrop(curr->condition),
- builder.makeBreak(curr->default_)
- ));
+ replaceCurrent(builder.makeSequence(builder.makeDrop(curr->condition),
+ builder.makeBreak(curr->default_)));
} else if (curr->targets.size() == 1) {
// a switch with two options is basically an if
Builder builder(*getModule());
- replaceCurrent(builder.makeIf(
- curr->condition,
- builder.makeBreak(curr->default_),
- builder.makeBreak(curr->targets.front())
- ));
+ replaceCurrent(builder.makeIf(curr->condition,
+ builder.makeBreak(curr->default_),
+ builder.makeBreak(curr->targets.front())));
} else {
- // there are also some other cases where we want to convert a switch into ifs,
- // especially if the switch is large and we are focusing on size.
- // an especially egregious case is a switch like this:
- // [a b b [..] b b c] with default b
- // (which may be arrived at after we trim away excess default values on both
- // sides). in this case, we really have 3 values in a simple form, so it is the
- // next logical case after handling 1 and 2 values right above here.
- // to optimize this, we must add a local + a bunch of nodes (if*2, tee, eq,
- // get, const, break*3), so the table must be big enough for it to make sense
+ // there are also some other cases where we want to convert a switch into
+ // ifs, especially if the switch is large and we are focusing on size. an
+ // especially egregious case is a switch like this: [a b b [..] b b c]
+ // with default b (which may be arrived at after we trim away excess
+ // default values on both sides). in this case, we really have 3 values in
+ // a simple form, so it is the next logical case after handling 1 and 2
+ // values right above here. to optimize this, we must add a local + a
+ // bunch of nodes (if*2, tee, eq, get, const, break*3), so the table must
+ // be big enough for it to make sense
- // How many targets we need when shrinking. This is literally the size at which
- // the transformation begins to be smaller.
+ // How many targets we need when shrinking. This is literally the size at
+ // which the transformation begins to be smaller.
const uint32_t MIN_SHRINK = 13;
- // How many targets we need when not shrinking, in which case, 2 ifs may be slower,
- // so we do this when the table is ridiculously large for one with just 3 values
- // in it.
+ // How many targets we need when not shrinking, in which case, 2 ifs may
+ // be slower, so we do this when the table is ridiculously large for one
+ // with just 3 values in it.
const uint32_t MIN_GENERAL = 128;
auto shrink = getPassRunner()->options.shrinkLevel > 0;
- if ((curr->targets.size() >= MIN_SHRINK && shrink) ||
+ if ((curr->targets.size() >= MIN_SHRINK && shrink) ||
(curr->targets.size() >= MIN_GENERAL && !shrink)) {
for (Index i = 1; i < curr->targets.size() - 1; i++) {
if (curr->targets[i] != curr->default_) {
@@ -262,25 +263,24 @@ struct RemoveUnusedBrs : public WalkerPass<PostWalker<RemoveUnusedBrs>> {
Builder builder(*getModule());
auto temp = builder.addVar(getFunction(), i32);
Expression* z;
- replaceCurrent(z = builder.makeIf(
- builder.makeTeeLocal(temp, curr->condition),
- builder.makeIf(
- builder.makeBinary(EqInt32,
- builder.makeGetLocal(temp, i32),
- builder.makeConst(Literal(int32_t(curr->targets.size() - 1)))
- ),
- builder.makeBreak(curr->targets.back()),
- builder.makeBreak(curr->default_)
- ),
- builder.makeBreak(curr->targets.front())
- ));
+ replaceCurrent(
+ z = builder.makeIf(
+ builder.makeTeeLocal(temp, curr->condition),
+ builder.makeIf(builder.makeBinary(EqInt32,
+ builder.makeGetLocal(temp, i32),
+ builder.makeConst(Literal(int32_t(
+ curr->targets.size() - 1)))),
+ builder.makeBreak(curr->targets.back()),
+ builder.makeBreak(curr->default_)),
+ builder.makeBreak(curr->targets.front())));
}
}
}
void visitIf(If* curr) {
if (!curr->ifFalse) {
- // if without an else. try to reduce if (condition) br => br_if (condition)
+ // if without an else. try to reduce if (condition) br => br_if
+ // (condition)
Break* br = curr->ifTrue->dynCast<Break>();
if (br && !br->condition) { // TODO: if there is a condition, join them
if (canTurnIfIntoBrIf(curr->condition, br->value, getPassOptions())) {
@@ -291,9 +291,9 @@ struct RemoveUnusedBrs : public WalkerPass<PostWalker<RemoveUnusedBrs>> {
}
}
}
- // TODO: if-else can be turned into a br_if as well, if one of the sides is a dead end
- // we handle the case of a returned value to a local.set later down, see
- // visitSetLocal.
+ // TODO: if-else can be turned into a br_if as well, if one of the sides is
+ // a dead end we handle the case of a returned value to a local.set
+ // later down, see visitSetLocal.
}
// override scan to add a pre and a post check task to all nodes
@@ -309,9 +309,11 @@ struct RemoveUnusedBrs : public WalkerPass<PostWalker<RemoveUnusedBrs>> {
}
self->pushTask(doVisitIf, currp);
if (iff->ifFalse) {
- // we need to join up if-else control flow, and clear after the condition
+ // we need to join up if-else control flow, and clear after the
+ // condition
self->pushTask(scan, &iff->ifFalse);
- self->pushTask(saveIfTrue, currp); // safe the ifTrue flow, we'll join it later
+ // safe the ifTrue flow, we'll join it later
+ self->pushTask(saveIfTrue, currp);
}
self->pushTask(scan, &iff->ifTrue);
self->pushTask(clear, currp); // clear all flow after the condition
@@ -342,24 +344,32 @@ struct RemoveUnusedBrs : public WalkerPass<PostWalker<RemoveUnusedBrs>> {
// helpful, as it shortens the logical loop. it is also good to generate
// an if-else instead of an if, as it might allow an eqz to be removed
// by flipping arms)
- if (!loop->name.is()) return false;
+ if (!loop->name.is())
+ return false;
auto* block = loop->body->dynCast<Block>();
- if (!block) return false;
+ if (!block)
+ return false;
// does the last element break to the top of the loop?
auto& list = block->list;
- if (list.size() <= 1) return false;
+ if (list.size() <= 1)
+ return false;
auto* last = list.back()->dynCast<Break>();
- if (!last || !ExpressionAnalyzer::isSimple(last) || last->name != loop->name) return false;
- // last is a simple break to the top of the loop. if we can conditionalize it,
- // it won't block things from flowing out and not needing breaks to do so.
+ if (!last || !ExpressionAnalyzer::isSimple(last) ||
+ last->name != loop->name)
+ return false;
+ // last is a simple break to the top of the loop. if we can conditionalize
+ // it, it won't block things from flowing out and not needing breaks to do
+ // so.
Index i = list.size() - 2;
Builder builder(*getModule());
while (1) {
auto* curr = list[i];
if (auto* iff = curr->dynCast<If>()) {
- // let's try to move the code going to the top of the loop into the if-else
+ // let's try to move the code going to the top of the loop into the
+ // if-else
if (!iff->ifFalse) {
- // we need the ifTrue to break, so it cannot reach the code we want to move
+ // we need the ifTrue to break, so it cannot reach the code we want to
+ // move
if (iff->ifTrue->type == unreachable) {
iff->ifFalse = builder.stealSlice(block, i + 1, list.size());
iff->finalize();
@@ -367,20 +377,25 @@ struct RemoveUnusedBrs : public WalkerPass<PostWalker<RemoveUnusedBrs>> {
return true;
}
} else {
- // this is already an if-else. if one side is a dead end, we can append to the other, if
- // there is no returned value to concern us
- assert(!isConcreteType(iff->type)); // can't be, since in the middle of a block
+ // this is already an if-else. if one side is a dead end, we can
+ // append to the other, if there is no returned value to concern us
- // ensures the first node is a block, if it isn't already, and merges in the second,
- // either as a single element or, if a block, by appending to the first block. this
- // keeps the order of operations in place, that is, the appended element will be
- // executed after the first node's elements
- auto blockifyMerge = [&](Expression* any, Expression* append) -> Block* {
+ // can't be, since in the middle of a block
+ assert(!isConcreteType(iff->type));
+
+ // ensures the first node is a block, if it isn't already, and merges
+ // in the second, either as a single element or, if a block, by
+ // appending to the first block. this keeps the order of operations in
+ // place, that is, the appended element will be executed after the
+ // first node's elements
+ auto blockifyMerge = [&](Expression* any,
+ Expression* append) -> Block* {
Block* block = nullptr;
- if (any) block = any->dynCast<Block>();
- // if the first isn't a block, or it's a block with a name (so we might
- // branch to the end, and so can't append to it, we might skip that code!)
- // then make a new block
+ if (any)
+ block = any->dynCast<Block>();
+ // if the first isn't a block, or it's a block with a name (so we
+ // might branch to the end, and so can't append to it, we might skip
+ // that code!) then make a new block
if (!block || block->name.is()) {
block = builder.makeBlock(any);
} else {
@@ -399,12 +414,14 @@ struct RemoveUnusedBrs : public WalkerPass<PostWalker<RemoveUnusedBrs>> {
};
if (iff->ifTrue->type == unreachable) {
- iff->ifFalse = blockifyMerge(iff->ifFalse, builder.stealSlice(block, i + 1, list.size()));
+ iff->ifFalse = blockifyMerge(
+ iff->ifFalse, builder.stealSlice(block, i + 1, list.size()));
iff->finalize();
block->finalize();
return true;
} else if (iff->ifFalse->type == unreachable) {
- iff->ifTrue = blockifyMerge(iff->ifTrue, builder.stealSlice(block, i + 1, list.size()));
+ iff->ifTrue = blockifyMerge(
+ iff->ifTrue, builder.stealSlice(block, i + 1, list.size()));
iff->finalize();
block->finalize();
return true;
@@ -415,7 +432,8 @@ struct RemoveUnusedBrs : public WalkerPass<PostWalker<RemoveUnusedBrs>> {
// br_if is similar to if.
if (brIf->condition && !brIf->value && brIf->name != loop->name) {
if (i == list.size() - 2) {
- // there is the br_if, and then the br to the top, so just flip them and the condition
+ // there is the br_if, and then the br to the top, so just flip them
+ // and the condition
brIf->condition = builder.makeUnary(EqZInt32, brIf->condition);
last->name = brIf->name;
brIf->name = loop->name;
@@ -428,11 +446,18 @@ struct RemoveUnusedBrs : public WalkerPass<PostWalker<RemoveUnusedBrs>> {
// we can convert the br_if to an if. this has a cost, though,
// so only do it if it looks useful, which it definitely is if
// (a) $somewhere is straight out (so the br out vanishes), and
- // (b) this br_if is the only branch to that block (so the block will vanish)
- if (brIf->name == block->name && BranchUtils::BranchSeeker::countNamed(block, block->name) == 1) {
- // note that we could drop the last element here, it is a br we know for sure is removable,
- // but telling stealSlice to steal all to the end is more efficient, it can just truncate.
- list[i] = builder.makeIf(brIf->condition, builder.makeBreak(brIf->name), builder.stealSlice(block, i + 1, list.size()));
+ // (b) this br_if is the only branch to that block (so the block
+ // will vanish)
+ if (brIf->name == block->name &&
+ BranchUtils::BranchSeeker::countNamed(block, block->name) ==
+ 1) {
+ // note that we could drop the last element here, it is a br we
+ // know for sure is removable, but telling stealSlice to steal all
+ // to the end is more efficient, it can just truncate.
+ list[i] =
+ builder.makeIf(brIf->condition,
+ builder.makeBreak(brIf->name),
+ builder.stealSlice(block, i + 1, list.size()));
return true;
}
}
@@ -443,7 +468,8 @@ struct RemoveUnusedBrs : public WalkerPass<PostWalker<RemoveUnusedBrs>> {
if (EffectAnalyzer(getPassOptions(), curr).branches) {
return false;
}
- if (i == 0) return false;
+ if (i == 0)
+ return false;
i--;
}
}
@@ -453,11 +479,11 @@ struct RemoveUnusedBrs : public WalkerPass<PostWalker<RemoveUnusedBrs>> {
bool worked = false;
void visitBlock(Block* curr) {
- // If the block has a single child which is a loop, and the block is named,
- // then it is the exit for the loop. It's better to move it into the loop,
- // where it can be better optimized by other passes.
- // Similar logic for ifs: if the block is an exit for the if, we can
- // move the block in, consider for example:
+ // If the block has a single child which is a loop, and the block is
+ // named, then it is the exit for the loop. It's better to move it into
+ // the loop, where it can be better optimized by other passes. Similar
+ // logic for ifs: if the block is an exit for the if, we can move the
+ // block in, consider for example:
// (block $label
// (if (..condition1..)
// (block
@@ -484,27 +510,31 @@ struct RemoveUnusedBrs : public WalkerPass<PostWalker<RemoveUnusedBrs>> {
worked = true;
} else if (auto* iff = curr->list[0]->dynCast<If>()) {
// The label can't be used in the condition.
- if (BranchUtils::BranchSeeker::countNamed(iff->condition, curr->name) == 0) {
- // We can move the block into either arm, if there are no uses in the other.
+ if (BranchUtils::BranchSeeker::countNamed(iff->condition,
+ curr->name) == 0) {
+ // We can move the block into either arm, if there are no uses in
+ // the other.
Expression** target = nullptr;
- if (!iff->ifFalse ||
- BranchUtils::BranchSeeker::countNamed(iff->ifFalse, curr->name) == 0) {
+ if (!iff->ifFalse || BranchUtils::BranchSeeker::countNamed(
+ iff->ifFalse, curr->name) == 0) {
target = &iff->ifTrue;
- } else if (BranchUtils::BranchSeeker::countNamed(iff->ifTrue, curr->name) == 0) {
+ } else if (BranchUtils::BranchSeeker::countNamed(
+ iff->ifTrue, curr->name) == 0) {
target = &iff->ifFalse;
}
if (target) {
curr->list[0] = *target;
*target = curr;
- // The block used to contain the if, and may have changed type from unreachable
- // to none, for example, if the if has an unreachable condition but the arm
- // is not unreachable.
+ // The block used to contain the if, and may have changed type
+ // from unreachable to none, for example, if the if has an
+ // unreachable condition but the arm is not unreachable.
curr->finalize();
iff->finalize();
replaceCurrent(iff);
worked = true;
- // Note that the type might change, e.g. if the if condition is unreachable
- // but the block that was on the outside had a break.
+ // Note that the type might change, e.g. if the if condition is
+ // unreachable but the block that was on the outside had a
+ // break.
}
}
}
@@ -526,10 +556,12 @@ struct RemoveUnusedBrs : public WalkerPass<PostWalker<RemoveUnusedBrs>> {
anotherCycle = false;
super::doWalkFunction(func);
assert(ifStack.empty());
- // flows may contain returns, which are flowing out and so can be optimized
+ // flows may contain returns, which are flowing out and so can be
+ // optimized
for (Index i = 0; i < flows.size(); i++) {
auto* flow = (*flows[i])->dynCast<Return>();
- if (!flow) continue;
+ if (!flow)
+ continue;
if (!flow->value) {
// return => nop
ExpressionManipulator::nop(flow);
@@ -541,7 +573,8 @@ struct RemoveUnusedBrs : public WalkerPass<PostWalker<RemoveUnusedBrs>> {
}
}
flows.clear();
- // optimize loops (we don't do it while tracking flows, as they can interfere)
+ // optimize loops (we don't do it while tracking flows, as they can
+ // interfere)
for (auto* loop : loops) {
anotherCycle |= optimizeLoop(loop);
}
@@ -557,7 +590,8 @@ struct RemoveUnusedBrs : public WalkerPass<PostWalker<RemoveUnusedBrs>> {
// thread trivial jumps
struct JumpThreader : public ControlFlowWalker<JumpThreader> {
- // map of all value-less breaks and switches going to a block (and not a loop)
+ // map of all value-less breaks and switches going to a block (and not a
+ // loop)
std::map<Block*, std::vector<Expression*>> branchesToBlock;
bool worked = false;
@@ -582,19 +616,25 @@ struct RemoveUnusedBrs : public WalkerPass<PostWalker<RemoveUnusedBrs>> {
void visitBlock(Block* curr) {
auto& list = curr->list;
if (list.size() == 1 && curr->name.is()) {
- // if this block has just one child, a sub-block, then jumps to the former are jumps to us, really
+ // if this block has just one child, a sub-block, then jumps to the
+ // former are jumps to us, really
if (auto* child = list[0]->dynCast<Block>()) {
- // the two blocks must have the same type for us to update the branch, as otherwise
- // one block may be unreachable and the other concrete, so one might lack a value
- if (child->name.is() && child->name != curr->name && child->type == curr->type) {
+ // the two blocks must have the same type for us to update the
+ // branch, as otherwise one block may be unreachable and the other
+ // concrete, so one might lack a value
+ if (child->name.is() && child->name != curr->name &&
+ child->type == curr->type) {
redirectBranches(child, curr->name);
}
}
} else if (list.size() == 2) {
- // if this block has two children, a child-block and a simple jump, then jumps to child-block can be replaced with jumps to the new target
+ // if this block has two children, a child-block and a simple jump,
+ // then jumps to child-block can be replaced with jumps to the new
+ // target
auto* child = list[0]->dynCast<Block>();
auto* jump = list[1]->dynCast<Break>();
- if (child && child->name.is() && jump && ExpressionAnalyzer::isSimple(jump)) {
+ if (child && child->name.is() && jump &&
+ ExpressionAnalyzer::isSimple(jump)) {
redirectBranches(child, jump->name);
}
}
@@ -607,7 +647,8 @@ struct RemoveUnusedBrs : public WalkerPass<PostWalker<RemoveUnusedBrs>> {
worked = true;
}
}
- // if the jump is to another block then we can update the list, and maybe push it even more later
+ // if the jump is to another block then we can update the list, and
+ // maybe push it even more later
if (auto* newTarget = findBreakTarget(to)->dynCast<Block>()) {
for (auto* branch : branches) {
branchesToBlock[newTarget].push_back(branch);
@@ -637,18 +678,27 @@ struct RemoveUnusedBrs : public WalkerPass<PostWalker<RemoveUnusedBrs>> {
FinalOptimizer(PassOptions& passOptions) : passOptions(passOptions) {}
void visitBlock(Block* curr) {
- // if a block has an if br else br, we can un-conditionalize the latter, allowing
- // the if to become a br_if.
- // * note that if not in a block already, then we need to create a block for this, so not useful otherwise
- // * note that this only happens at the end of a block, as code after the if is dead
- // * note that we do this at the end, because un-conditionalizing can interfere with optimizeLoop()ing.
+ // if a block has an if br else br, we can un-conditionalize the latter,
+ // allowing the if to become a br_if.
+ // * note that if not in a block already, then we need to create a block
+ // for this, so not useful otherwise
+ // * note that this only happens at the end of a block, as code after
+ // the if is dead
+ // * note that we do this at the end, because un-conditionalizing can
+ // interfere with optimizeLoop()ing.
auto& list = curr->list;
for (Index i = 0; i < list.size(); i++) {
auto* iff = list[i]->dynCast<If>();
- if (!iff || !iff->ifFalse) continue; // if it lacked an if-false, it would already be a br_if, as that's the easy case
+ if (!iff || !iff->ifFalse)
+ // if it lacked an if-false, it would already be a br_if, as that's
+ // the easy case
+ continue;
auto* ifTrueBreak = iff->ifTrue->dynCast<Break>();
- if (ifTrueBreak && !ifTrueBreak->condition && canTurnIfIntoBrIf(iff->condition, ifTrueBreak->value, passOptions)) {
- // we are an if-else where the ifTrue is a break without a condition, so we can do this
+ if (ifTrueBreak && !ifTrueBreak->condition &&
+ canTurnIfIntoBrIf(
+ iff->condition, ifTrueBreak->value, passOptions)) {
+ // we are an if-else where the ifTrue is a break without a
+ // condition, so we can do this
ifTrueBreak->condition = iff->condition;
ifTrueBreak->finalize();
list[i] = Builder(*getModule()).dropIfConcretelyTyped(ifTrueBreak);
@@ -657,8 +707,11 @@ struct RemoveUnusedBrs : public WalkerPass<PostWalker<RemoveUnusedBrs>> {
}
// otherwise, perhaps we can flip the if
auto* ifFalseBreak = iff->ifFalse->dynCast<Break>();
- if (ifFalseBreak && !ifFalseBreak->condition && canTurnIfIntoBrIf(iff->condition, ifFalseBreak->value, passOptions)) {
- ifFalseBreak->condition = Builder(*getModule()).makeUnary(EqZInt32, iff->condition);
+ if (ifFalseBreak && !ifFalseBreak->condition &&
+ canTurnIfIntoBrIf(
+ iff->condition, ifFalseBreak->value, passOptions)) {
+ ifFalseBreak->condition =
+ Builder(*getModule()).makeUnary(EqZInt32, iff->condition);
ifFalseBreak->finalize();
list[i] = Builder(*getModule()).dropIfConcretelyTyped(ifFalseBreak);
ExpressionManipulator::spliceIntoBlock(curr, i + 1, iff->ifTrue);
@@ -669,22 +722,26 @@ struct RemoveUnusedBrs : public WalkerPass<PostWalker<RemoveUnusedBrs>> {
// combine/optimize adjacent br_ifs + a br (maybe _if) right after it
for (Index i = 0; i < list.size() - 1; i++) {
auto* br1 = list[i]->dynCast<Break>();
- // avoid unreachable brs, as they are dead code anyhow, and after merging
- // them the outer scope could need type changes
- if (!br1 || !br1->condition || br1->type == unreachable) continue;
+ // avoid unreachable brs, as they are dead code anyhow, and after
+ // merging them the outer scope could need type changes
+ if (!br1 || !br1->condition || br1->type == unreachable)
+ continue;
assert(!br1->value);
auto* br2 = list[i + 1]->dynCast<Break>();
- if (!br2 || br1->name != br2->name) continue;
+ if (!br2 || br1->name != br2->name)
+ continue;
assert(!br2->value); // same target as previous, which has no value
// a br_if and then a br[_if] with the same target right after it
if (br2->condition) {
if (shrink && br2->type != unreachable) {
- // Join adjacent br_ifs to the same target, making one br_if with
- // a "selectified" condition that executes both.
- if (!EffectAnalyzer(passOptions, br2->condition).hasSideEffects()) {
+ // Join adjacent br_ifs to the same target, making one br_if
+ // with a "selectified" condition that executes both.
+ if (!EffectAnalyzer(passOptions, br2->condition)
+ .hasSideEffects()) {
// it's ok to execute them both, do it
Builder builder(*getModule());
- br1->condition = builder.makeBinary(OrInt32, br1->condition, br2->condition);
+ br1->condition =
+ builder.makeBinary(OrInt32, br1->condition, br2->condition);
ExpressionManipulator::nop(br2);
}
}
@@ -706,12 +763,9 @@ struct RemoveUnusedBrs : public WalkerPass<PostWalker<RemoveUnusedBrs>> {
if (BranchUtils::getUniqueTargets(curr).size() == 1) {
// This switch has just one target no matter what; replace with a br.
Builder builder(*getModule());
- replaceCurrent(
- builder.makeSequence(
- builder.makeDrop(curr->condition), // might have side effects
- builder.makeBreak(curr->default_, curr->value)
- )
- );
+ replaceCurrent(builder.makeSequence(
+ builder.makeDrop(curr->condition), // might have side effects
+ builder.makeBreak(curr->default_, curr->value)));
}
}
@@ -754,36 +808,32 @@ struct RemoveUnusedBrs : public WalkerPass<PostWalker<RemoveUnusedBrs>> {
} else {
br = list[0]->dynCast<Break>();
}
- // Check if the br is conditional and goes to the block. It may or may not have
- // a value, depending on if it was dropped or not.
- // If the type is unreachable that means it is not actually reached,
- // which we can ignore.
- if (br && br->condition && br->name == curr->name && br->type != unreachable) {
+ // Check if the br is conditional and goes to the block. It may or may
+ // not have a value, depending on if it was dropped or not. If the
+ // type is unreachable that means it is not actually reached, which we
+ // can ignore.
+ if (br && br->condition && br->name == curr->name &&
+ br->type != unreachable) {
if (BranchUtils::BranchSeeker::countNamed(curr, curr->name) == 1) {
// no other breaks to that name, so we can do this
if (!drop) {
assert(!br->value);
Builder builder(*getModule());
replaceCurrent(builder.makeIf(
- builder.makeUnary(EqZInt32, br->condition),
- curr
- ));
+ builder.makeUnary(EqZInt32, br->condition), curr));
ExpressionManipulator::nop(br);
curr->finalize(curr->type);
} else {
- // If the items we move around have side effects, we can't do this.
+ // If the items we move around have side effects, we can't do
+ // this.
// TODO: we could use a select, in some cases..?
if (!EffectAnalyzer(passOptions, br->value).hasSideEffects() &&
- !EffectAnalyzer(passOptions, br->condition).hasSideEffects()) {
+ !EffectAnalyzer(passOptions, br->condition)
+ .hasSideEffects()) {
ExpressionManipulator::nop(list[0]);
Builder builder(*getModule());
replaceCurrent(
- builder.makeIf(
- br->condition,
- br->value,
- curr
- )
- );
+ builder.makeIf(br->condition, br->value, curr));
}
}
}
@@ -800,20 +850,20 @@ struct RemoveUnusedBrs : public WalkerPass<PostWalker<RemoveUnusedBrs>> {
// Convert an if into a select, if possible and beneficial to do so.
Select* selectify(If* iff) {
- if (!iff->ifFalse ||
- !isConcreteType(iff->ifTrue->type) ||
+ if (!iff->ifFalse || !isConcreteType(iff->ifTrue->type) ||
!isConcreteType(iff->ifFalse->type)) {
return nullptr;
}
- // This is always helpful for code size, but can be a tradeoff with performance
- // as we run both code paths. So when shrinking we always try to do this, but
- // otherwise must consider more carefully.
+ // This is always helpful for code size, but can be a tradeoff with
+ // performance as we run both code paths. So when shrinking we always
+ // try to do this, but otherwise must consider more carefully.
if (!passOptions.shrinkLevel) {
// Consider the cost of executing all the code unconditionally
const auto MAX_COST = 7;
- auto total = CostAnalyzer(iff->ifTrue).cost +
- CostAnalyzer(iff->ifFalse).cost;
- if (total >= MAX_COST) return nullptr;
+ auto total =
+ CostAnalyzer(iff->ifTrue).cost + CostAnalyzer(iff->ifFalse).cost;
+ if (total >= MAX_COST)
+ return nullptr;
}
// Check if side effects allow this.
EffectAnalyzer condition(passOptions, iff->condition);
@@ -822,11 +872,8 @@ struct RemoveUnusedBrs : public WalkerPass<PostWalker<RemoveUnusedBrs>> {
if (!ifTrue.hasSideEffects()) {
EffectAnalyzer ifFalse(passOptions, iff->ifFalse);
if (!ifFalse.hasSideEffects()) {
- return Builder(*getModule()).makeSelect(
- iff->condition,
- iff->ifTrue,
- iff->ifFalse
- );
+ return Builder(*getModule())
+ .makeSelect(iff->condition, iff->ifTrue, iff->ifFalse);
}
}
}
@@ -842,8 +889,10 @@ struct RemoveUnusedBrs : public WalkerPass<PostWalker<RemoveUnusedBrs>> {
}
void optimizeSetIf(Expression** currp) {
- if (optimizeSetIfWithBrArm(currp)) return;
- if (optimizeSetIfWithCopyArm(currp)) return;
+ if (optimizeSetIfWithBrArm(currp))
+ return;
+ if (optimizeSetIfWithCopyArm(currp))
+ return;
}
// If one arm is a br, we prefer a br_if and the set later:
@@ -865,33 +914,33 @@ struct RemoveUnusedBrs : public WalkerPass<PostWalker<RemoveUnusedBrs>> {
bool optimizeSetIfWithBrArm(Expression** currp) {
auto* set = (*currp)->cast<SetLocal>();
auto* iff = set->value->dynCast<If>();
- if (!iff ||
- !isConcreteType(iff->type) ||
+ if (!iff || !isConcreteType(iff->type) ||
!isConcreteType(iff->condition->type)) {
return false;
}
- auto tryToOptimize = [&](Expression* one, Expression* two, bool flipCondition) {
- if (one->type == unreachable && two->type != unreachable) {
- if (auto* br = one->dynCast<Break>()) {
- if (ExpressionAnalyzer::isSimple(br)) {
- // Wonderful, do it!
- Builder builder(*getModule());
- if (flipCondition) {
- builder.flip(iff);
+ auto tryToOptimize =
+ [&](Expression* one, Expression* two, bool flipCondition) {
+ if (one->type == unreachable && two->type != unreachable) {
+ if (auto* br = one->dynCast<Break>()) {
+ if (ExpressionAnalyzer::isSimple(br)) {
+ // Wonderful, do it!
+ Builder builder(*getModule());
+ if (flipCondition) {
+ builder.flip(iff);
+ }
+ br->condition = iff->condition;
+ br->finalize();
+ set->value = two;
+ auto* block = builder.makeSequence(br, set);
+ *currp = block;
+ // Recurse on the set, which now has a new value.
+ optimizeSetIf(&block->list[1]);
+ return true;
}
- br->condition = iff->condition;
- br->finalize();
- set->value = two;
- auto* block = builder.makeSequence(br, set);
- *currp = block;
- // Recurse on the set, which now has a new value.
- optimizeSetIf(&block->list[1]);
- return true;
}
}
- }
- return false;
- };
+ return false;
+ };
return tryToOptimize(iff->ifTrue, iff->ifFalse, false) ||
tryToOptimize(iff->ifFalse, iff->ifTrue, true);
}
@@ -940,8 +989,7 @@ struct RemoveUnusedBrs : public WalkerPass<PostWalker<RemoveUnusedBrs>> {
bool optimizeSetIfWithCopyArm(Expression** currp) {
auto* set = (*currp)->cast<SetLocal>();
auto* iff = set->value->dynCast<If>();
- if (!iff ||
- !isConcreteType(iff->type) ||
+ if (!iff || !isConcreteType(iff->type) ||
!isConcreteType(iff->condition->type)) {
return false;
}
@@ -955,7 +1003,8 @@ struct RemoveUnusedBrs : public WalkerPass<PostWalker<RemoveUnusedBrs>> {
get = nullptr;
}
}
- if (!get) return false;
+ if (!get)
+ return false;
// We can do it!
bool tee = set->isTee();
assert(set->index == get->index);
@@ -969,9 +1018,8 @@ struct RemoveUnusedBrs : public WalkerPass<PostWalker<RemoveUnusedBrs>> {
if (tee) {
set->setTee(false);
// We need a block too.
- replacement = builder.makeSequence(
- iff,
- get // reuse the get
+ replacement = builder.makeSequence(iff,
+ get // reuse the get
);
}
*currp = replacement;
@@ -996,10 +1044,12 @@ struct RemoveUnusedBrs : public WalkerPass<PostWalker<RemoveUnusedBrs>> {
// )
// TODO: consider also looking at <= etc. and not just eq
void tablify(Block* block) {
- auto &list = block->list;
- if (list.size() <= 1) return;
+ auto& list = block->list;
+ if (list.size() <= 1)
+ return;
- // Heuristics. These are slightly inspired by the constants from the asm.js backend.
+ // Heuristics. These are slightly inspired by the constants from the
+ // asm.js backend.
// How many br_ifs we need to see to consider doing this
const uint32_t MIN_NUM = 3;
@@ -1009,35 +1059,51 @@ struct RemoveUnusedBrs : public WalkerPass<PostWalker<RemoveUnusedBrs>> {
// this is high, we allow larger ranges.
const uint32_t NUM_TO_RANGE_FACTOR = 3;
- // check if the input is a proper br_if on an i32.eq of a condition value to a const,
- // and the const is in the proper range, [0-int32_max), to avoid overflow concerns.
- // returns the br_if if so, or nullptr otherwise
- auto getProperBrIf = [](Expression* curr) -> Break*{
+ // check if the input is a proper br_if on an i32.eq of a condition
+ // value to a const, and the const is in the proper range,
+ // [0-int32_max), to avoid overflow concerns. returns the br_if if so,
+ // or nullptr otherwise
+ auto getProperBrIf = [](Expression* curr) -> Break* {
auto* br = curr->dynCast<Break>();
- if (!br) return nullptr;
- if (!br->condition || br->value) return nullptr;
- if (br->type != none) return nullptr; // no value, so can be unreachable or none. ignore unreachable ones, dce will clean it up
+ if (!br)
+ return nullptr;
+ if (!br->condition || br->value)
+ return nullptr;
+ if (br->type != none)
+ // no value, so can be unreachable or none. ignore unreachable ones,
+ // dce will clean it up
+ return nullptr;
auto* binary = br->condition->dynCast<Binary>();
- if (!binary) return nullptr;
- if (binary->op != EqInt32) return nullptr;
+ if (!binary)
+ return nullptr;
+ if (binary->op != EqInt32)
+ return nullptr;
auto* c = binary->right->dynCast<Const>();
- if (!c) return nullptr;
+ if (!c)
+ return nullptr;
uint32_t value = c->value.geti32();
- if (value >= uint32_t(std::numeric_limits<int32_t>::max())) return nullptr;
+ if (value >= uint32_t(std::numeric_limits<int32_t>::max()))
+ return nullptr;
return br;
};
// check if the input is a proper br_if
// and returns the condition if so, or nullptr otherwise
- auto getProperBrIfConditionValue = [&getProperBrIf](Expression* curr) -> Expression* {
+ auto getProperBrIfConditionValue =
+ [&getProperBrIf](Expression* curr) -> Expression* {
auto* br = getProperBrIf(curr);
- if (!br) return nullptr;
+ if (!br)
+ return nullptr;
return br->condition->cast<Binary>()->left;
};
// returns the constant value, as a uint32_t
- auto getProperBrIfConstant = [&getProperBrIf](Expression* curr) -> uint32_t {
- return getProperBrIf(curr)->condition->cast<Binary>()->right->cast<Const>()->value.geti32();
+ auto getProperBrIfConstant =
+ [&getProperBrIf](Expression* curr) -> uint32_t {
+ return getProperBrIf(curr)
+ ->condition->cast<Binary>()
+ ->right->cast<Const>()
+ ->value.geti32();
};
Index start = 0;
while (start < list.size() - 1) {
@@ -1046,23 +1112,25 @@ struct RemoveUnusedBrs : public WalkerPass<PostWalker<RemoveUnusedBrs>> {
start++;
continue;
}
- // if the condition has side effects, we can't replace many appearances of it
- // with a single one
+ // if the condition has side effects, we can't replace many
+ // appearances of it with a single one
if (EffectAnalyzer(passOptions, conditionValue).hasSideEffects()) {
start++;
continue;
}
- // look for a "run" of br_ifs with all the same conditionValue, and having
- // unique constants (an overlapping constant could be handled, just the first
- // branch is taken, but we can't remove the other br_if (it may be the only
- // branch keeping a block reachable), which may make this bad for code size.
+ // look for a "run" of br_ifs with all the same conditionValue, and
+ // having unique constants (an overlapping constant could be handled,
+ // just the first branch is taken, but we can't remove the other br_if
+ // (it may be the only branch keeping a block reachable), which may
+ // make this bad for code size.
Index end = start + 1;
std::unordered_set<uint32_t> usedConstants;
usedConstants.insert(getProperBrIfConstant(list[start]));
while (end < list.size() &&
- ExpressionAnalyzer::equal(getProperBrIfConditionValue(list[end]),
- conditionValue)) {
- if (!usedConstants.insert(getProperBrIfConstant(list[end])).second) {
+ ExpressionAnalyzer::equal(
+ getProperBrIfConditionValue(list[end]), conditionValue)) {
+ if (!usedConstants.insert(getProperBrIfConstant(list[end]))
+ .second) {
// this constant already appeared
break;
}
@@ -1081,8 +1149,7 @@ struct RemoveUnusedBrs : public WalkerPass<PostWalker<RemoveUnusedBrs>> {
}
uint32_t range = max - min;
// decision time
- if (range <= MAX_RANGE &&
- range <= num * NUM_TO_RANGE_FACTOR) {
+ if (range <= MAX_RANGE && range <= num * NUM_TO_RANGE_FACTOR) {
// great! let's do this
std::unordered_set<Name> usedNames;
for (Index i = start; i < end; i++) {
@@ -1093,7 +1160,8 @@ struct RemoveUnusedBrs : public WalkerPass<PostWalker<RemoveUnusedBrs>> {
Index i = 0;
while (1) {
defaultName = "tablify|" + std::to_string(i++);
- if (usedNames.count(defaultName) == 0) break;
+ if (usedNames.count(defaultName) == 0)
+ break;
}
std::vector<Name> table;
for (Index i = start; i < end; i++) {
@@ -1103,26 +1171,21 @@ struct RemoveUnusedBrs : public WalkerPass<PostWalker<RemoveUnusedBrs>> {
while (table.size() <= index) {
table.push_back(defaultName);
}
- assert(table[index] == defaultName); // we should have made sure there are no overlaps
+ // we should have made sure there are no overlaps
+ assert(table[index] == defaultName);
table[index] = name;
}
Builder builder(*getModule());
// the table and condition are offset by the min
if (min != 0) {
- conditionValue = builder.makeBinary(
- SubInt32,
- conditionValue,
- builder.makeConst(Literal(int32_t(min)))
- );
+ conditionValue =
+ builder.makeBinary(SubInt32,
+ conditionValue,
+ builder.makeConst(Literal(int32_t(min))));
}
list[end - 1] = builder.makeBlock(
defaultName,
- builder.makeSwitch(
- table,
- defaultName,
- conditionValue
- )
- );
+ builder.makeSwitch(table, defaultName, conditionValue));
for (Index i = start; i < end - 1; i++) {
ExpressionManipulator::nop(list[i]);
}
@@ -1145,8 +1208,6 @@ struct RemoveUnusedBrs : public WalkerPass<PostWalker<RemoveUnusedBrs>> {
}
};
-Pass *createRemoveUnusedBrsPass() {
- return new RemoveUnusedBrs();
-}
+Pass* createRemoveUnusedBrsPass() { return new RemoveUnusedBrs(); }
} // namespace wasm
diff --git a/src/passes/RemoveUnusedModuleElements.cpp b/src/passes/RemoveUnusedModuleElements.cpp
index e91fafcba..3338bb756 100644
--- a/src/passes/RemoveUnusedModuleElements.cpp
+++ b/src/passes/RemoveUnusedModuleElements.cpp
@@ -20,21 +20,17 @@
// and remove if unneeded)
//
-
#include <memory>
-#include "wasm.h"
-#include "pass.h"
+#include "asm_v_wasm.h"
#include "ir/module-utils.h"
#include "ir/utils.h"
-#include "asm_v_wasm.h"
+#include "pass.h"
+#include "wasm.h"
namespace wasm {
-enum class ModuleElementKind {
- Function,
- Global
-};
+enum class ModuleElementKind { Function, Global };
typedef std::pair<ModuleElementKind, Name> ModuleElement;
@@ -48,7 +44,8 @@ struct ReachabilityAnalyzer : public PostWalker<ReachabilityAnalyzer> {
bool usesMemory = false;
bool usesTable = false;
- ReachabilityAnalyzer(Module* module, const std::vector<ModuleElement>& roots) : module(module) {
+ ReachabilityAnalyzer(Module* module, const std::vector<ModuleElement>& roots)
+ : module(module) {
queue = roots;
// Globals used in memory/table init expressions are also roots
for (auto& segment : module->memory.segments) {
@@ -83,55 +80,36 @@ struct ReachabilityAnalyzer : public PostWalker<ReachabilityAnalyzer> {
}
void visitCall(Call* curr) {
- if (reachable.count(ModuleElement(ModuleElementKind::Function, curr->target)) == 0) {
+ if (reachable.count(
+ ModuleElement(ModuleElementKind::Function, curr->target)) == 0) {
queue.emplace_back(ModuleElementKind::Function, curr->target);
}
}
- void visitCallIndirect(CallIndirect* curr) {
- usesTable = true;
- }
+ void visitCallIndirect(CallIndirect* curr) { usesTable = true; }
void visitGetGlobal(GetGlobal* curr) {
- if (reachable.count(ModuleElement(ModuleElementKind::Global, curr->name)) == 0) {
+ if (reachable.count(ModuleElement(ModuleElementKind::Global, curr->name)) ==
+ 0) {
queue.emplace_back(ModuleElementKind::Global, curr->name);
}
}
void visitSetGlobal(SetGlobal* curr) {
- if (reachable.count(ModuleElement(ModuleElementKind::Global, curr->name)) == 0) {
+ if (reachable.count(ModuleElement(ModuleElementKind::Global, curr->name)) ==
+ 0) {
queue.emplace_back(ModuleElementKind::Global, curr->name);
}
}
- void visitLoad(Load* curr) {
- usesMemory = true;
- }
- void visitStore(Store* curr) {
- usesMemory = true;
- }
- void visitAtomicCmpxchg(AtomicCmpxchg* curr) {
- usesMemory = true;
- }
- void visitAtomicRMW(AtomicRMW* curr) {
- usesMemory = true;
- }
- void visitAtomicWait(AtomicWait* curr) {
- usesMemory = true;
- }
- void visitAtomicNotify(AtomicNotify* curr) {
- usesMemory = true;
- }
- void visitMemoryInit(MemoryInit* curr) {
- usesMemory = true;
- }
- void visitDataDrop(DataDrop* curr) {
- usesMemory = true;
- }
- void visitMemoryCopy(MemoryCopy* curr) {
- usesMemory = true;
- }
- void visitMemoryFill(MemoryFill* curr) {
- usesMemory = true;
- }
+ void visitLoad(Load* curr) { usesMemory = true; }
+ void visitStore(Store* curr) { usesMemory = true; }
+ void visitAtomicCmpxchg(AtomicCmpxchg* curr) { usesMemory = true; }
+ void visitAtomicRMW(AtomicRMW* curr) { usesMemory = true; }
+ void visitAtomicWait(AtomicWait* curr) { usesMemory = true; }
+ void visitAtomicNotify(AtomicNotify* curr) { usesMemory = true; }
+ void visitMemoryInit(MemoryInit* curr) { usesMemory = true; }
+ void visitDataDrop(DataDrop* curr) { usesMemory = true; }
+ void visitMemoryCopy(MemoryCopy* curr) { usesMemory = true; }
+ void visitMemoryFill(MemoryFill* curr) { usesMemory = true; }
void visitHost(Host* curr) {
if (curr->op == CurrentMemory || curr->op == GrowMemory) {
usesMemory = true;
@@ -156,15 +134,14 @@ struct FunctionTypeAnalyzer : public PostWalker<FunctionTypeAnalyzer> {
}
}
- void visitCallIndirect(CallIndirect* curr) {
- indirectCalls.push_back(curr);
- }
+ void visitCallIndirect(CallIndirect* curr) { indirectCalls.push_back(curr); }
};
struct RemoveUnusedModuleElements : public Pass {
bool rootAllFunctions;
- RemoveUnusedModuleElements(bool rootAllFunctions) : rootAllFunctions(rootAllFunctions) {}
+ RemoveUnusedModuleElements(bool rootAllFunctions)
+ : rootAllFunctions(rootAllFunctions) {}
void run(PassRunner* runner, Module* module) override {
optimizeGlobalsAndFunctions(module);
@@ -223,21 +200,32 @@ struct RemoveUnusedModuleElements : public Pass {
// Remove unreachable elements.
{
auto& v = module->functions;
- v.erase(std::remove_if(v.begin(), v.end(), [&](const std::unique_ptr<Function>& curr) {
- return analyzer.reachable.count(ModuleElement(ModuleElementKind::Function, curr->name)) == 0;
- }), v.end());
+ v.erase(std::remove_if(v.begin(),
+ v.end(),
+ [&](const std::unique_ptr<Function>& curr) {
+ return analyzer.reachable.count(ModuleElement(
+ ModuleElementKind::Function,
+ curr->name)) == 0;
+ }),
+ v.end());
}
{
auto& v = module->globals;
- v.erase(std::remove_if(v.begin(), v.end(), [&](const std::unique_ptr<Global>& curr) {
- return analyzer.reachable.count(ModuleElement(ModuleElementKind::Global, curr->name)) == 0;
- }), v.end());
+ v.erase(std::remove_if(v.begin(),
+ v.end(),
+ [&](const std::unique_ptr<Global>& curr) {
+ return analyzer.reachable.count(
+ ModuleElement(ModuleElementKind::Global,
+ curr->name)) == 0;
+ }),
+ v.end());
}
module->updateMaps();
// Handle the memory and table
if (!exportsMemory && !analyzer.usesMemory) {
if (!importsMemory) {
- // The memory is unobservable to the outside, we can remove the contents.
+ // The memory is unobservable to the outside, we can remove the
+ // contents.
module->memory.segments.clear();
}
if (module->memory.segments.empty()) {
@@ -268,7 +256,8 @@ struct RemoveUnusedModuleElements : public Pass {
std::unordered_map<std::string, FunctionType*> canonicals;
std::unordered_set<FunctionType*> needed;
auto canonicalize = [&](Name name) {
- if (!name.is()) return name;
+ if (!name.is())
+ return name;
FunctionType* type = module->getFunctionType(name);
auto sig = getSig(type);
auto iter = canonicals.find(sig);
@@ -291,9 +280,13 @@ struct RemoveUnusedModuleElements : public Pass {
call->fullType = canonicalize(call->fullType);
}
// remove no-longer used types
- module->functionTypes.erase(std::remove_if(module->functionTypes.begin(), module->functionTypes.end(), [&needed](std::unique_ptr<FunctionType>& type) {
- return needed.count(type.get()) == 0;
- }), module->functionTypes.end());
+ module->functionTypes.erase(
+ std::remove_if(module->functionTypes.begin(),
+ module->functionTypes.end(),
+ [&needed](std::unique_ptr<FunctionType>& type) {
+ return needed.count(type.get()) == 0;
+ }),
+ module->functionTypes.end());
module->updateMaps();
}
};
diff --git a/src/passes/RemoveUnusedNames.cpp b/src/passes/RemoveUnusedNames.cpp
index e5aaf5509..86db53b0c 100644
--- a/src/passes/RemoveUnusedNames.cpp
+++ b/src/passes/RemoveUnusedNames.cpp
@@ -19,8 +19,8 @@
// merge names when possible (by merging their blocks)
//
-#include <wasm.h>
#include <pass.h>
+#include <wasm.h>
namespace wasm {
@@ -33,11 +33,9 @@ struct RemoveUnusedNames : public WalkerPass<PostWalker<RemoveUnusedNames>> {
// a parent block, we know if it was branched to
std::map<Name, std::set<Expression*>> branchesSeen;
- void visitBreak(Break *curr) {
- branchesSeen[curr->name].insert(curr);
- }
+ void visitBreak(Break* curr) { branchesSeen[curr->name].insert(curr); }
- void visitSwitch(Switch *curr) {
+ void visitSwitch(Switch* curr) {
for (auto name : curr->targets) {
branchesSeen[name].insert(curr);
}
@@ -54,20 +52,24 @@ struct RemoveUnusedNames : public WalkerPass<PostWalker<RemoveUnusedNames>> {
}
}
- void visitBlock(Block *curr) {
+ void visitBlock(Block* curr) {
if (curr->name.is() && curr->list.size() == 1) {
auto* child = curr->list[0]->dynCast<Block>();
if (child && child->name.is() && child->type == curr->type) {
- // we have just one child, this block, so breaking out of it goes to the same place as breaking out of us, we just need one name (and block)
+ // we have just one child, this block, so breaking out of it goes to the
+ // same place as breaking out of us, we just need one name (and block)
auto& branches = branchesSeen[curr->name];
for (auto* branch : branches) {
if (Break* br = branch->dynCast<Break>()) {
- if (br->name == curr->name) br->name = child->name;
+ if (br->name == curr->name)
+ br->name = child->name;
} else if (Switch* sw = branch->dynCast<Switch>()) {
for (auto& target : sw->targets) {
- if (target == curr->name) target = child->name;
+ if (target == curr->name)
+ target = child->name;
}
- if (sw->default_ == curr->name) sw->default_ = child->name;
+ if (sw->default_ == curr->name)
+ sw->default_ = child->name;
} else {
WASM_UNREACHABLE();
}
@@ -79,20 +81,16 @@ struct RemoveUnusedNames : public WalkerPass<PostWalker<RemoveUnusedNames>> {
handleBreakTarget(curr->name);
}
- void visitLoop(Loop *curr) {
+ void visitLoop(Loop* curr) {
handleBreakTarget(curr->name);
if (!curr->name.is()) {
replaceCurrent(curr->body);
}
}
- void visitFunction(Function *curr) {
- assert(branchesSeen.empty());
- }
+ void visitFunction(Function* curr) { assert(branchesSeen.empty()); }
};
-Pass *createRemoveUnusedNamesPass() {
- return new RemoveUnusedNames();
-}
+Pass* createRemoveUnusedNamesPass() { return new RemoveUnusedNames(); }
} // namespace wasm
diff --git a/src/passes/ReorderFunctions.cpp b/src/passes/ReorderFunctions.cpp
index 5312ee90a..5cd70c20f 100644
--- a/src/passes/ReorderFunctions.cpp
+++ b/src/passes/ReorderFunctions.cpp
@@ -22,16 +22,15 @@
// This may incur a tradeoff, though, as while it reduces binary size, it may
// increase gzip size. This might be because the new order has the functions in
// a less beneficial position for compression, that is, mutually-compressible
-// functions are no longer together (when they were before, in the original order,
-// the has some natural tendency one way or the other). TODO: investigate
+// functions are no longer together (when they were before, in the original
+// order, the has some natural tendency one way or the other). TODO: investigate
// similarity ordering here.
//
-
#include <memory>
-#include <wasm.h>
#include <pass.h>
+#include <wasm.h>
namespace wasm {
@@ -42,12 +41,11 @@ struct CallCountScanner : public WalkerPass<PostWalker<CallCountScanner>> {
CallCountScanner(NameCountMap* counts) : counts(counts) {}
- CallCountScanner* create() override {
- return new CallCountScanner(counts);
- }
+ CallCountScanner* create() override { return new CallCountScanner(counts); }
void visitCall(Call* curr) {
- assert(counts->count(curr->target) > 0); // can't add a new element in parallel
+ // can't add a new element in parallel
+ assert(counts->count(curr->target) > 0);
(*counts)[curr->target]++;
}
@@ -58,7 +56,8 @@ private:
struct ReorderFunctions : public Pass {
void run(PassRunner* runner, Module* module) override {
NameCountMap counts;
- // fill in info, as we operate on it in parallel (each function to its own entry)
+ // fill in info, as we operate on it in parallel (each function to its own
+ // entry)
for (auto& func : module->functions) {
counts[func->name];
}
@@ -82,19 +81,18 @@ struct ReorderFunctions : public Pass {
}
}
// sort
- std::sort(module->functions.begin(), module->functions.end(), [&counts](
- const std::unique_ptr<Function>& a,
- const std::unique_ptr<Function>& b) -> bool {
- if (counts[a->name] == counts[b->name]) {
- return strcmp(a->name.str, b->name.str) > 0;
- }
- return counts[a->name] > counts[b->name];
- });
+ std::sort(module->functions.begin(),
+ module->functions.end(),
+ [&counts](const std::unique_ptr<Function>& a,
+ const std::unique_ptr<Function>& b) -> bool {
+ if (counts[a->name] == counts[b->name]) {
+ return strcmp(a->name.str, b->name.str) > 0;
+ }
+ return counts[a->name] > counts[b->name];
+ });
}
};
-Pass *createReorderFunctionsPass() {
- return new ReorderFunctions();
-}
+Pass* createReorderFunctionsPass() { return new ReorderFunctions(); }
} // namespace wasm
diff --git a/src/passes/ReorderLocals.cpp b/src/passes/ReorderLocals.cpp
index fe4f775e9..45796c0aa 100644
--- a/src/passes/ReorderLocals.cpp
+++ b/src/passes/ReorderLocals.cpp
@@ -24,8 +24,8 @@
#include <memory>
-#include <wasm.h>
#include <pass.h>
+#include <wasm.h>
namespace wasm {
@@ -35,27 +35,32 @@ struct ReorderLocals : public WalkerPass<PostWalker<ReorderLocals>> {
Pass* create() override { return new ReorderLocals; }
std::map<Index, Index> counts; // local => times it is used
- std::map<Index, Index> firstUses; // local => index in the list of which local is first seen
+ // local => index in the list of which local is first seen
+ std::map<Index, Index> firstUses;
- void visitFunction(Function *curr) {
+ void visitFunction(Function* curr) {
Index num = curr->getNumLocals();
std::vector<Index> newToOld;
for (size_t i = 0; i < num; i++) {
newToOld.push_back(i);
}
// sort, keeping params in front (where they will not be moved)
- sort(newToOld.begin(), newToOld.end(), [this, curr](Index a, Index b) -> bool {
- if (curr->isParam(a) && !curr->isParam(b)) return true;
- if (curr->isParam(b) && !curr->isParam(a)) return false;
- if (curr->isParam(b) && curr->isParam(a)) {
- return a < b;
- }
- if (counts[a] == counts[b]) {
- if (counts[a] == 0) return a < b;
- return firstUses[a] < firstUses[b];
- }
- return counts[a] > counts[b];
- });
+ sort(
+ newToOld.begin(), newToOld.end(), [this, curr](Index a, Index b) -> bool {
+ if (curr->isParam(a) && !curr->isParam(b))
+ return true;
+ if (curr->isParam(b) && !curr->isParam(a))
+ return false;
+ if (curr->isParam(b) && curr->isParam(a)) {
+ return a < b;
+ }
+ if (counts[a] == counts[b]) {
+ if (counts[a] == 0)
+ return a < b;
+ return firstUses[a] < firstUses[b];
+ }
+ return counts[a] > counts[b];
+ });
// sorting left params in front, perhaps slightly reordered. verify and fix.
for (size_t i = 0; i < curr->params.size(); i++) {
assert(newToOld[i] < curr->params.size());
@@ -90,15 +95,16 @@ struct ReorderLocals : public WalkerPass<PostWalker<ReorderLocals>> {
Function* func;
std::vector<Index>& oldToNew;
- ReIndexer(Function* func, std::vector<Index>& oldToNew) : func(func), oldToNew(oldToNew) {}
+ ReIndexer(Function* func, std::vector<Index>& oldToNew)
+ : func(func), oldToNew(oldToNew) {}
- void visitGetLocal(GetLocal *curr) {
+ void visitGetLocal(GetLocal* curr) {
if (func->isVar(curr->index)) {
curr->index = oldToNew[curr->index];
}
}
- void visitSetLocal(SetLocal *curr) {
+ void visitSetLocal(SetLocal* curr) {
if (func->isVar(curr->index)) {
curr->index = oldToNew[curr->index];
}
@@ -120,14 +126,14 @@ struct ReorderLocals : public WalkerPass<PostWalker<ReorderLocals>> {
}
}
- void visitGetLocal(GetLocal *curr) {
+ void visitGetLocal(GetLocal* curr) {
counts[curr->index]++;
if (firstUses.count(curr->index) == 0) {
firstUses[curr->index] = firstUses.size();
}
}
- void visitSetLocal(SetLocal *curr) {
+ void visitSetLocal(SetLocal* curr) {
counts[curr->index]++;
if (firstUses.count(curr->index) == 0) {
firstUses[curr->index] = firstUses.size();
@@ -135,8 +141,6 @@ struct ReorderLocals : public WalkerPass<PostWalker<ReorderLocals>> {
}
};
-Pass *createReorderLocalsPass() {
- return new ReorderLocals();
-}
+Pass* createReorderLocalsPass() { return new ReorderLocals(); }
} // namespace wasm
diff --git a/src/passes/SSAify.cpp b/src/passes/SSAify.cpp
index 1ed3b976f..2f0f9439c 100644
--- a/src/passes/SSAify.cpp
+++ b/src/passes/SSAify.cpp
@@ -50,13 +50,13 @@
#include <iterator>
-#include "wasm.h"
-#include "pass.h"
-#include "wasm-builder.h"
-#include "support/permutations.h"
#include "ir/find_all.h"
#include "ir/literal-utils.h"
#include "ir/local-graph.h"
+#include "pass.h"
+#include "support/permutations.h"
+#include "wasm-builder.h"
+#include "wasm.h"
namespace wasm {
@@ -77,9 +77,11 @@ struct SSAify : public Pass {
Module* module;
Function* func;
- std::vector<Expression*> functionPrepends; // things we add to the function prologue
+ // things we add to the function prologue
+ std::vector<Expression*> functionPrepends;
- void runOnFunction(PassRunner* runner, Module* module_, Function* func_) override {
+ void
+ runOnFunction(PassRunner* runner, Module* module_, Function* func_) override {
module = module_;
func = func_;
LocalGraph graph(func);
@@ -87,7 +89,8 @@ struct SSAify : public Pass {
graph.computeSSAIndexes();
// create new local indexes, one for each set
createNewIndexes(graph);
- // we now know the sets for each get, and can compute get indexes and handle phis
+ // we now know the sets for each get, and can compute get indexes and handle
+ // phis
computeGetsAndPhis(graph);
// add prepends to function
addPrepends();
@@ -96,9 +99,9 @@ struct SSAify : public Pass {
void createNewIndexes(LocalGraph& graph) {
FindAll<SetLocal> sets(func->body);
for (auto* set : sets.list) {
- // Indexes already in SSA form do not need to be modified - there is already
- // just one set for that index. Otherwise, use a new index, unless merges
- // are disallowed.
+ // Indexes already in SSA form do not need to be modified - there is
+ // already just one set for that index. Otherwise, use a new index, unless
+ // merges are disallowed.
if (!graph.isSSA(set->index) && (allowMerges || !hasMerges(set, graph))) {
set->index = addLocal(func->getLocalType(set->index));
}
@@ -132,12 +135,14 @@ struct SSAify : public Pass {
// leave it, it's fine
} else {
// zero it out
- (*graph.locations[get]) = LiteralUtils::makeZero(get->type, *module);
+ (*graph.locations[get]) =
+ LiteralUtils::makeZero(get->type, *module);
}
}
continue;
}
- if (!allowMerges) continue;
+ if (!allowMerges)
+ continue;
// more than 1 set, need a phi: a new local written to at each of the sets
auto new_ = addLocal(get->type);
auto old = get->index;
@@ -148,10 +153,7 @@ struct SSAify : public Pass {
if (set) {
// a set exists, just add a tee of its value
auto* value = set->value;
- auto* tee = builder.makeTeeLocal(
- new_,
- value
- );
+ auto* tee = builder.makeTeeLocal(new_, value);
set->value = tee;
// the value may have been something we tracked the location
// of. if so, update that, since we moved it into the tee
@@ -165,9 +167,7 @@ struct SSAify : public Pass {
// we add a set with the proper
// param value at the beginning of the function
auto* set = builder.makeSetLocal(
- new_,
- builder.makeGetLocal(old, func->getLocalType(old))
- );
+ new_, builder.makeGetLocal(old, func->getLocalType(old)));
functionPrepends.push_back(set);
} else {
// this is a zero init, so we don't need to do anything actually
@@ -177,9 +177,7 @@ struct SSAify : public Pass {
}
}
- Index addLocal(Type type) {
- return Builder::addVar(func, type);
- }
+ Index addLocal(Type type) { return Builder::addVar(func, type); }
void addPrepends() {
if (functionPrepends.size() > 0) {
@@ -195,13 +193,8 @@ struct SSAify : public Pass {
}
};
-Pass* createSSAifyPass() {
- return new SSAify(true);
-}
+Pass* createSSAifyPass() { return new SSAify(true); }
-Pass* createSSAifyNoMergePass() {
- return new SSAify(false);
-}
+Pass* createSSAifyNoMergePass() { return new SSAify(false); }
} // namespace wasm
-
diff --git a/src/passes/SafeHeap.cpp b/src/passes/SafeHeap.cpp
index 738a201ee..a293ee5e9 100644
--- a/src/passes/SafeHeap.cpp
+++ b/src/passes/SafeHeap.cpp
@@ -20,21 +20,21 @@
// top of sbrk()-addressible memory, and incorrect alignment notation.
//
-#include "wasm.h"
-#include "pass.h"
#include "asm_v_wasm.h"
#include "asmjs/shared-constants.h"
-#include "wasm-builder.h"
#include "ir/bits.h"
#include "ir/function-type-utils.h"
#include "ir/import-utils.h"
#include "ir/load-utils.h"
+#include "pass.h"
+#include "wasm-builder.h"
+#include "wasm.h"
namespace wasm {
-const Name DYNAMICTOP_PTR_IMPORT("DYNAMICTOP_PTR"),
- SEGFAULT_IMPORT("segfault"),
- ALIGNFAULT_IMPORT("alignfault");
+const Name DYNAMICTOP_PTR_IMPORT("DYNAMICTOP_PTR");
+const Name SEGFAULT_IMPORT("segfault");
+const Name ALIGNFAULT_IMPORT("alignfault");
static Name getLoadName(Load* curr) {
std::string ret = "SAFE_HEAP_LOAD_";
@@ -69,34 +69,30 @@ struct AccessInstrumenter : public WalkerPass<PostWalker<AccessInstrumenter>> {
AccessInstrumenter* create() override { return new AccessInstrumenter; }
void visitLoad(Load* curr) {
- if (curr->type == unreachable) return;
+ if (curr->type == unreachable)
+ return;
Builder builder(*getModule());
replaceCurrent(
- builder.makeCall(
- getLoadName(curr),
- {
- curr->ptr,
- builder.makeConst(Literal(int32_t(curr->offset))),
- },
- curr->type
- )
- );
+ builder.makeCall(getLoadName(curr),
+ {
+ curr->ptr,
+ builder.makeConst(Literal(int32_t(curr->offset))),
+ },
+ curr->type));
}
void visitStore(Store* curr) {
- if (curr->type == unreachable) return;
+ if (curr->type == unreachable)
+ return;
Builder builder(*getModule());
replaceCurrent(
- builder.makeCall(
- getStoreName(curr),
- {
- curr->ptr,
- builder.makeConst(Literal(int32_t(curr->offset))),
- curr->value,
- },
- none
- )
- );
+ builder.makeCall(getStoreName(curr),
+ {
+ curr->ptr,
+ builder.makeConst(Literal(int32_t(curr->offset))),
+ curr->value,
+ },
+ none));
}
};
@@ -156,32 +152,35 @@ struct SafeHeap : public Pass {
}
}
- bool isPossibleAtomicOperation(Index align, Index bytes, bool shared, Type type) {
+ bool
+ isPossibleAtomicOperation(Index align, Index bytes, bool shared, Type type) {
return align == bytes && shared && isIntegerType(type);
}
void addGlobals(Module* module, FeatureSet features) {
// load funcs
Load load;
- for (auto type : { i32, i64, f32, f64, v128 }) {
- if (type == v128 && !features.hasSIMD()) continue;
+ for (auto type : {i32, i64, f32, f64, v128}) {
+ if (type == v128 && !features.hasSIMD())
+ continue;
load.type = type;
- for (Index bytes : { 1, 2, 4, 8, 16 }) {
+ for (Index bytes : {1, 2, 4, 8, 16}) {
load.bytes = bytes;
- if (bytes > getTypeSize(type) ||
- (type == f32 && bytes != 4) ||
- (type == f64 && bytes != 8) ||
- (type == v128 && bytes != 16)) continue;
- for (auto signed_ : { true, false }) {
+ if (bytes > getTypeSize(type) || (type == f32 && bytes != 4) ||
+ (type == f64 && bytes != 8) || (type == v128 && bytes != 16))
+ continue;
+ for (auto signed_ : {true, false}) {
load.signed_ = signed_;
- if (isFloatType(type) && signed_) continue;
- for (Index align : { 1, 2, 4, 8, 16 }) {
+ if (isFloatType(type) && signed_)
+ continue;
+ for (Index align : {1, 2, 4, 8, 16}) {
load.align = align;
- if (align > bytes) continue;
- for (auto isAtomic : { true, false }) {
+ if (align > bytes)
+ continue;
+ for (auto isAtomic : {true, false}) {
load.isAtomic = isAtomic;
- if (isAtomic &&
- !isPossibleAtomicOperation(align, bytes, module->memory.shared, type)) {
+ if (isAtomic && !isPossibleAtomicOperation(
+ align, bytes, module->memory.shared, type)) {
continue;
}
addLoadFunc(load, module);
@@ -192,23 +191,26 @@ struct SafeHeap : public Pass {
}
// store funcs
Store store;
- for (auto valueType : { i32, i64, f32, f64, v128 }) {
- if (valueType == v128 && !features.hasSIMD()) continue;
+ for (auto valueType : {i32, i64, f32, f64, v128}) {
+ if (valueType == v128 && !features.hasSIMD())
+ continue;
store.valueType = valueType;
store.type = none;
- for (Index bytes : { 1, 2, 4, 8, 16 }) {
+ for (Index bytes : {1, 2, 4, 8, 16}) {
store.bytes = bytes;
if (bytes > getTypeSize(valueType) ||
(valueType == f32 && bytes != 4) ||
(valueType == f64 && bytes != 8) ||
- (valueType == v128 && bytes != 16)) continue;
- for (Index align : { 1, 2, 4, 8, 16 }) {
+ (valueType == v128 && bytes != 16))
+ continue;
+ for (Index align : {1, 2, 4, 8, 16}) {
store.align = align;
- if (align > bytes) continue;
- for (auto isAtomic : { true, false }) {
+ if (align > bytes)
+ continue;
+ for (auto isAtomic : {true, false}) {
store.isAtomic = isAtomic;
- if (isAtomic &&
- !isPossibleAtomicOperation(align, bytes, module->memory.shared, valueType)) {
+ if (isAtomic && !isPossibleAtomicOperation(
+ align, bytes, module->memory.shared, valueType)) {
continue;
}
addStoreFunc(store, module);
@@ -221,34 +223,25 @@ struct SafeHeap : public Pass {
// creates a function for a particular style of load
void addLoadFunc(Load style, Module* module) {
auto name = getLoadName(&style);
- if (module->getFunctionOrNull(name)) return;
+ if (module->getFunctionOrNull(name))
+ return;
auto* func = new Function;
func->name = name;
func->params.push_back(i32); // pointer
func->params.push_back(i32); // offset
- func->vars.push_back(i32); // pointer + offset
+ func->vars.push_back(i32); // pointer + offset
func->result = style.type;
Builder builder(*module);
auto* block = builder.makeBlock();
- block->list.push_back(
- builder.makeSetLocal(
- 2,
- builder.makeBinary(
- AddInt32,
- builder.makeGetLocal(0, i32),
- builder.makeGetLocal(1, i32)
- )
- )
- );
+ block->list.push_back(builder.makeSetLocal(
+ 2,
+ builder.makeBinary(
+ AddInt32, builder.makeGetLocal(0, i32), builder.makeGetLocal(1, i32))));
// check for reading past valid memory: if pointer + offset + bytes
- block->list.push_back(
- makeBoundsCheck(style.type, builder, 2, style.bytes)
- );
+ block->list.push_back(makeBoundsCheck(style.type, builder, 2, style.bytes));
// check proper alignment
if (style.align > 1) {
- block->list.push_back(
- makeAlignCheck(style.align, builder, 2)
- );
+ block->list.push_back(makeAlignCheck(style.align, builder, 2));
}
// do the load
auto* load = module->allocator.alloc<Load>();
@@ -269,35 +262,27 @@ struct SafeHeap : public Pass {
// creates a function for a particular type of store
void addStoreFunc(Store style, Module* module) {
auto name = getStoreName(&style);
- if (module->getFunctionOrNull(name)) return;
+ if (module->getFunctionOrNull(name))
+ return;
auto* func = new Function;
func->name = name;
- func->params.push_back(i32); // pointer
- func->params.push_back(i32); // offset
+ func->params.push_back(i32); // pointer
+ func->params.push_back(i32); // offset
func->params.push_back(style.valueType); // value
- func->vars.push_back(i32); // pointer + offset
+ func->vars.push_back(i32); // pointer + offset
func->result = none;
Builder builder(*module);
auto* block = builder.makeBlock();
- block->list.push_back(
- builder.makeSetLocal(
- 3,
- builder.makeBinary(
- AddInt32,
- builder.makeGetLocal(0, i32),
- builder.makeGetLocal(1, i32)
- )
- )
- );
+ block->list.push_back(builder.makeSetLocal(
+ 3,
+ builder.makeBinary(
+ AddInt32, builder.makeGetLocal(0, i32), builder.makeGetLocal(1, i32))));
// check for reading past valid memory: if pointer + offset + bytes
block->list.push_back(
- makeBoundsCheck(style.valueType, builder, 3, style.bytes)
- );
+ makeBoundsCheck(style.valueType, builder, 3, style.bytes));
// check proper alignment
if (style.align > 1) {
- block->list.push_back(
- makeAlignCheck(style.align, builder, 3)
- );
+ block->list.push_back(makeAlignCheck(style.align, builder, 3));
}
// do the store
auto* store = module->allocator.alloc<Store>();
@@ -312,45 +297,33 @@ struct SafeHeap : public Pass {
Expression* makeAlignCheck(Address align, Builder& builder, Index local) {
return builder.makeIf(
- builder.makeBinary(
- AndInt32,
- builder.makeGetLocal(local, i32),
- builder.makeConst(Literal(int32_t(align - 1)))
- ),
- builder.makeCall(alignfault, {}, none)
- );
+ builder.makeBinary(AndInt32,
+ builder.makeGetLocal(local, i32),
+ builder.makeConst(Literal(int32_t(align - 1)))),
+ builder.makeCall(alignfault, {}, none));
}
- Expression* makeBoundsCheck(Type type, Builder& builder, Index local, Index bytes) {
+ Expression*
+ makeBoundsCheck(Type type, Builder& builder, Index local, Index bytes) {
auto upperOp = options.lowMemoryUnused ? LtUInt32 : EqInt32;
auto upperBound = options.lowMemoryUnused ? PassOptions::LowMemoryBound : 0;
return builder.makeIf(
builder.makeBinary(
OrInt32,
- builder.makeBinary(
- upperOp,
- builder.makeGetLocal(local, i32),
- builder.makeConst(Literal(int32_t(upperBound)))
- ),
+ builder.makeBinary(upperOp,
+ builder.makeGetLocal(local, i32),
+ builder.makeConst(Literal(int32_t(upperBound)))),
builder.makeBinary(
GtUInt32,
- builder.makeBinary(
- AddInt32,
- builder.makeGetLocal(local, i32),
- builder.makeConst(Literal(int32_t(bytes)))
- ),
- builder.makeLoad(4, false, 0, 4,
- builder.makeGetGlobal(dynamicTopPtr, i32), i32
- )
- )
- ),
- builder.makeCall(segfault, {}, none)
- );
+ builder.makeBinary(AddInt32,
+ builder.makeGetLocal(local, i32),
+ builder.makeConst(Literal(int32_t(bytes)))),
+ builder.makeLoad(
+ 4, false, 0, 4, builder.makeGetGlobal(dynamicTopPtr, i32), i32))),
+ builder.makeCall(segfault, {}, none));
}
};
-Pass *createSafeHeapPass() {
- return new SafeHeap();
-}
+Pass* createSafeHeapPass() { return new SafeHeap(); }
} // namespace wasm
diff --git a/src/passes/SimplifyLocals.cpp b/src/passes/SimplifyLocals.cpp
index 8007d92ff..f366c7085 100644
--- a/src/passes/SimplifyLocals.cpp
+++ b/src/passes/SimplifyLocals.cpp
@@ -46,33 +46,40 @@
// removing redundant locals.
//
-#include <wasm.h>
-#include <wasm-builder.h>
-#include <wasm-traversal.h>
-#include <pass.h>
+#include "ir/equivalent_sets.h"
#include <ir/branch-utils.h>
-#include <ir/local-utils.h>
#include <ir/effects.h>
-#include "ir/equivalent_sets.h"
#include <ir/find_all.h>
+#include <ir/local-utils.h>
#include <ir/manipulation.h>
+#include <pass.h>
+#include <wasm-builder.h>
+#include <wasm-traversal.h>
+#include <wasm.h>
namespace wasm {
// Main class
-template<bool allowTee = true, bool allowStructure = true, bool allowNesting = true>
-struct SimplifyLocals : public WalkerPass<LinearExecutionWalker<SimplifyLocals<allowTee, allowStructure, allowNesting>>> {
+template<bool allowTee = true,
+ bool allowStructure = true,
+ bool allowNesting = true>
+struct SimplifyLocals
+ : public WalkerPass<LinearExecutionWalker<
+ SimplifyLocals<allowTee, allowStructure, allowNesting>>> {
bool isFunctionParallel() override { return true; }
- Pass* create() override { return new SimplifyLocals<allowTee, allowStructure, allowNesting>(); }
+ Pass* create() override {
+ return new SimplifyLocals<allowTee, allowStructure, allowNesting>();
+ }
// information for a local.set we can sink
struct SinkableInfo {
Expression** item;
EffectAnalyzer effects;
- SinkableInfo(Expression** item, PassOptions& passOptions) : item(item), effects(passOptions, *item) {}
+ SinkableInfo(Expression** item, PassOptions& passOptions)
+ : item(item), effects(passOptions, *item) {}
};
// a list of sinkables in a linear execution trace
@@ -112,7 +119,9 @@ struct SimplifyLocals : public WalkerPass<LinearExecutionWalker<SimplifyLocals<a
// local => # of local.gets for it
GetLocalCounter getCounter;
- static void doNoteNonLinear(SimplifyLocals<allowTee, allowStructure, allowNesting>* self, Expression** currp) {
+ static void
+ doNoteNonLinear(SimplifyLocals<allowTee, allowStructure, allowNesting>* self,
+ Expression** currp) {
// Main processing.
auto* curr = *currp;
if (curr->is<Break>()) {
@@ -121,12 +130,14 @@ struct SimplifyLocals : public WalkerPass<LinearExecutionWalker<SimplifyLocals<a
// value means the block already has a return value
self->unoptimizableBlocks.insert(br->name);
} else {
- self->blockBreaks[br->name].push_back({ currp, std::move(self->sinkables) });
+ self->blockBreaks[br->name].push_back(
+ {currp, std::move(self->sinkables)});
}
} else if (curr->is<Block>()) {
return; // handled in visitBlock
} else if (curr->is<If>()) {
- assert(!curr->cast<If>()->ifFalse); // if-elses are handled by doNoteIf* methods
+ assert(!curr->cast<If>()
+ ->ifFalse); // if-elses are handled by doNoteIf* methods
} else if (curr->is<Switch>()) {
auto* sw = curr->cast<Switch>();
auto targets = BranchUtils::getUniqueTargets(sw);
@@ -138,13 +149,17 @@ struct SimplifyLocals : public WalkerPass<LinearExecutionWalker<SimplifyLocals<a
self->sinkables.clear();
}
- static void doNoteIfCondition(SimplifyLocals<allowTee, allowStructure, allowNesting>* self, Expression** currp) {
+ static void doNoteIfCondition(
+ SimplifyLocals<allowTee, allowStructure, allowNesting>* self,
+ Expression** currp) {
// we processed the condition of this if-else, and now control flow branches
// into either the true or the false sides
self->sinkables.clear();
}
- static void doNoteIfTrue(SimplifyLocals<allowTee, allowStructure, allowNesting>* self, Expression** currp) {
+ static void
+ doNoteIfTrue(SimplifyLocals<allowTee, allowStructure, allowNesting>* self,
+ Expression** currp) {
auto* iff = (*currp)->dynCast<If>();
if (iff->ifFalse) {
// We processed the ifTrue side of this if-else, save it on the stack.
@@ -159,7 +174,9 @@ struct SimplifyLocals : public WalkerPass<LinearExecutionWalker<SimplifyLocals<a
}
}
- static void doNoteIfFalse(SimplifyLocals<allowTee, allowStructure, allowNesting>* self, Expression** currp) {
+ static void
+ doNoteIfFalse(SimplifyLocals<allowTee, allowStructure, allowNesting>* self,
+ Expression** currp) {
// we processed the ifFalse side of this if-else, we can now try to
// mere with the ifTrue side and optimize a return value, if possible
auto* iff = (*currp)->cast<If>();
@@ -199,13 +216,16 @@ struct SimplifyLocals : public WalkerPass<LinearExecutionWalker<SimplifyLocals<a
}
}
- void visitGetLocal(GetLocal *curr) {
+ void visitGetLocal(GetLocal* curr) {
auto found = sinkables.find(curr->index);
if (found != sinkables.end()) {
- auto* set = (*found->second.item)->template cast<SetLocal>(); // the set we may be sinking
+ auto* set = (*found->second.item)
+ ->template cast<SetLocal>(); // the set we may be sinking
bool oneUse = firstCycle || getCounter.num[curr->index] == 1;
- auto* get = set->value->template dynCast<GetLocal>(); // the set's value may be a get (i.e., the set is a copy)
- // if nesting is not allowed, and this might cause nesting, check if the sink would cause such a thing
+ // the set's value may be a get (i.e., the set is a copy)
+ auto* get = set->value->template dynCast<GetLocal>();
+ // if nesting is not allowed, and this might cause nesting, check if the
+ // sink would cause such a thing
if (!allowNesting) {
// a get is always ok to sink
if (!get) {
@@ -213,8 +233,8 @@ struct SimplifyLocals : public WalkerPass<LinearExecutionWalker<SimplifyLocals<a
assert(expressionStack[expressionStack.size() - 1] == curr);
auto* parent = expressionStack[expressionStack.size() - 2];
bool parentIsSet = parent->template is<SetLocal>();
- // if the parent of this get is a set, we can sink into the set's value,
- // it would not be nested.
+ // if the parent of this get is a set, we can sink into the set's
+ // value, it would not be nested.
if (!parentIsSet) {
return;
}
@@ -273,7 +293,9 @@ struct SimplifyLocals : public WalkerPass<LinearExecutionWalker<SimplifyLocals<a
// a sink would cause nesting
ExpressionStack expressionStack;
- static void visitPre(SimplifyLocals<allowTee, allowStructure, allowNesting>* self, Expression** currp) {
+ static void
+ visitPre(SimplifyLocals<allowTee, allowStructure, allowNesting>* self,
+ Expression** currp) {
Expression* curr = *currp;
EffectAnalyzer effects(self->getPassOptions());
@@ -286,14 +308,16 @@ struct SimplifyLocals : public WalkerPass<LinearExecutionWalker<SimplifyLocals<a
}
}
- static void visitPost(SimplifyLocals<allowTee, allowStructure, allowNesting>* self, Expression** currp) {
+ static void
+ visitPost(SimplifyLocals<allowTee, allowStructure, allowNesting>* self,
+ Expression** currp) {
// perform main SetLocal processing here, since we may be the result of
// replaceCurrent, i.e., the visitor was not called.
auto* set = (*currp)->dynCast<SetLocal>();
if (set) {
- // if we see a set that was already potentially-sinkable, then the previous
- // store is dead, leave just the value
+ // if we see a set that was already potentially-sinkable, then the
+ // previous store is dead, leave just the value
auto found = self->sinkables.find(set->index);
if (found != self->sinkables.end()) {
auto* previous = (*found->second.item)->template cast<SetLocal>();
@@ -315,7 +339,8 @@ struct SimplifyLocals : public WalkerPass<LinearExecutionWalker<SimplifyLocals<a
if (set && self->canSink(set)) {
Index index = set->index;
assert(self->sinkables.count(index) == 0);
- self->sinkables.emplace(std::make_pair(index, SinkableInfo(currp, self->getPassOptions())));
+ self->sinkables.emplace(
+ std::make_pair(index, SinkableInfo(currp, self->getPassOptions())));
}
if (!allowNesting) {
@@ -325,9 +350,12 @@ struct SimplifyLocals : public WalkerPass<LinearExecutionWalker<SimplifyLocals<a
bool canSink(SetLocal* set) {
// we can never move a tee
- if (set->isTee()) return false;
- // if in the first cycle, or not allowing tees, then we cannot sink if >1 use as that would make a tee
- if ((firstCycle || !allowTee) && getCounter.num[set->index] > 1) return false;
+ if (set->isTee())
+ return false;
+ // if in the first cycle, or not allowing tees, then we cannot sink if >1
+ // use as that would make a tee
+ if ((firstCycle || !allowTee) && getCounter.num[set->index] > 1)
+ return false;
return true;
}
@@ -338,13 +366,16 @@ struct SimplifyLocals : public WalkerPass<LinearExecutionWalker<SimplifyLocals<a
void optimizeLoopReturn(Loop* loop) {
// If there is a sinkable thing in an eligible loop, we can optimize
// it in a trivial way to the outside of the loop.
- if (loop->type != none) return;
- if (sinkables.empty()) return;
+ if (loop->type != none)
+ return;
+ if (sinkables.empty())
+ return;
Index goodIndex = sinkables.begin()->first;
// Ensure we have a place to write the return values for, if not, we
// need another cycle.
auto* block = loop->body->dynCast<Block>();
- if (!block || block->name.is() || block->list.size() == 0 || !block->list.back()->is<Nop>()) {
+ if (!block || block->name.is() || block->list.size() == 0 ||
+ !block->list.back()->is<Nop>()) {
loopsToEnlarge.push_back(loop);
return;
}
@@ -371,8 +402,12 @@ struct SimplifyLocals : public WalkerPass<LinearExecutionWalker<SimplifyLocals<a
}
auto breaks = std::move(blockBreaks[block->name]);
blockBreaks.erase(block->name);
- if (breaks.size() == 0) return; // block has no branches TODO we might optimize trivial stuff here too
- assert(!(*breaks[0].brp)->template cast<Break>()->value); // block does not already have a return value (if one break has one, they all do)
+ if (breaks.size() == 0)
+ // block has no branches TODO we might optimize trivial stuff here too
+ return;
+ // block does not already have a return value (if one break has one, they
+ // all do)
+ assert(!(*breaks[0].brp)->template cast<Break>()->value);
// look for a local.set that is present in them all
bool found = false;
Index sharedIndex = -1;
@@ -391,7 +426,8 @@ struct SimplifyLocals : public WalkerPass<LinearExecutionWalker<SimplifyLocals<a
break;
}
}
- if (!found) return;
+ if (!found)
+ return;
// If one of our brs is a br_if, then we will give it a value. since
// the value executes before the condition, it is dangerous if we are
// moving code out of the condition,
@@ -446,7 +482,8 @@ struct SimplifyLocals : public WalkerPass<LinearExecutionWalker<SimplifyLocals<a
blocksToEnlarge.push_back(block);
return;
}
- // move block local.set's value to the end, in return position, and nop the set
+ // move block local.set's value to the end, in return position, and nop the
+ // set
auto* blockSetLocalPointer = sinkables.at(sharedIndex).item;
auto* value = (*blockSetLocalPointer)->template cast<SetLocal>()->value;
block->list[block->list.size() - 1] = value;
@@ -458,13 +495,16 @@ struct SimplifyLocals : public WalkerPass<LinearExecutionWalker<SimplifyLocals<a
auto* brp = breaks[j].brp;
auto* br = (*brp)->template cast<Break>();
assert(!br->value);
- // if the break is conditional, then we must set the value here - if the break is not reached, we must still have the new value in the local
+ // if the break is conditional, then we must set the value here - if the
+ // break is not reached, we must still have the new value in the local
auto* set = (*breakSetLocalPointer)->template cast<SetLocal>();
if (br->condition) {
br->value = set;
set->setTee(true);
- *breakSetLocalPointer = this->getModule()->allocator.template alloc<Nop>();
- // in addition, as this is a conditional br that now has a value, it now returns a value, so it must be dropped
+ *breakSetLocalPointer =
+ this->getModule()->allocator.template alloc<Nop>();
+ // in addition, as this is a conditional br that now has a value, it now
+ // returns a value, so it must be dropped
br->finalize();
*brp = Builder(*this->getModule()).makeDrop(br);
} else {
@@ -473,7 +513,8 @@ struct SimplifyLocals : public WalkerPass<LinearExecutionWalker<SimplifyLocals<a
}
}
// finally, create a local.set on the block itself
- auto* newSetLocal = Builder(*this->getModule()).makeSetLocal(sharedIndex, block);
+ auto* newSetLocal =
+ Builder(*this->getModule()).makeSetLocal(sharedIndex, block);
this->replaceCurrent(newSetLocal);
sinkables.clear();
anotherCycle = true;
@@ -484,7 +525,8 @@ struct SimplifyLocals : public WalkerPass<LinearExecutionWalker<SimplifyLocals<a
assert(iff->ifFalse);
// if this if already has a result, or is unreachable code, we have
// nothing to do
- if (iff->type != none) return;
+ if (iff->type != none)
+ return;
// We now have the sinkables from both sides of the if, and can look
// for something to sink. That is either a shared index on both sides,
// *or* if one side is unreachable, we can sink anything from the other,
@@ -527,35 +569,42 @@ struct SimplifyLocals : public WalkerPass<LinearExecutionWalker<SimplifyLocals<a
}
}
}
- if (!found) return;
+ if (!found)
+ return;
// great, we can optimize!
// ensure we have a place to write the return values for, if not, we
// need another cycle
- auto* ifTrueBlock = iff->ifTrue->dynCast<Block>();
+ auto* ifTrueBlock = iff->ifTrue->dynCast<Block>();
if (iff->ifTrue->type != unreachable) {
- if (!ifTrueBlock || ifTrueBlock->name.is() || ifTrueBlock->list.size() == 0 || !ifTrueBlock->list.back()->is<Nop>()) {
+ if (!ifTrueBlock || ifTrueBlock->name.is() ||
+ ifTrueBlock->list.size() == 0 ||
+ !ifTrueBlock->list.back()->is<Nop>()) {
ifsToEnlarge.push_back(iff);
return;
}
}
auto* ifFalseBlock = iff->ifFalse->dynCast<Block>();
if (iff->ifFalse->type != unreachable) {
- if (!ifFalseBlock || ifFalseBlock->name.is() || ifFalseBlock->list.size() == 0 || !ifFalseBlock->list.back()->is<Nop>()) {
+ if (!ifFalseBlock || ifFalseBlock->name.is() ||
+ ifFalseBlock->list.size() == 0 ||
+ !ifFalseBlock->list.back()->is<Nop>()) {
ifsToEnlarge.push_back(iff);
return;
}
}
// all set, go
if (iff->ifTrue->type != unreachable) {
- auto *ifTrueItem = ifTrue.at(goodIndex).item;
- ifTrueBlock->list[ifTrueBlock->list.size() - 1] = (*ifTrueItem)->template cast<SetLocal>()->value;
+ auto* ifTrueItem = ifTrue.at(goodIndex).item;
+ ifTrueBlock->list[ifTrueBlock->list.size() - 1] =
+ (*ifTrueItem)->template cast<SetLocal>()->value;
ExpressionManipulator::nop(*ifTrueItem);
ifTrueBlock->finalize();
assert(ifTrueBlock->type != none);
}
if (iff->ifFalse->type != unreachable) {
- auto *ifFalseItem = ifFalse.at(goodIndex).item;
- ifFalseBlock->list[ifFalseBlock->list.size() - 1] = (*ifFalseItem)->template cast<SetLocal>()->value;
+ auto* ifFalseItem = ifFalse.at(goodIndex).item;
+ ifFalseBlock->list[ifFalseBlock->list.size() - 1] =
+ (*ifFalseItem)->template cast<SetLocal>()->value;
ExpressionManipulator::nop(*ifFalseItem);
ifFalseBlock->finalize();
assert(ifFalseBlock->type != none);
@@ -563,7 +612,8 @@ struct SimplifyLocals : public WalkerPass<LinearExecutionWalker<SimplifyLocals<a
iff->finalize(); // update type
assert(iff->type != none);
// finally, create a local.set on the iff itself
- auto* newSetLocal = Builder(*this->getModule()).makeSetLocal(goodIndex, iff);
+ auto* newSetLocal =
+ Builder(*this->getModule()).makeSetLocal(goodIndex, iff);
*currp = newSetLocal;
anotherCycle = true;
}
@@ -592,14 +642,17 @@ struct SimplifyLocals : public WalkerPass<LinearExecutionWalker<SimplifyLocals<a
// arm into a one-sided if.
void optimizeIfReturn(If* iff, Expression** currp) {
// If this if is unreachable code, we have nothing to do.
- if (iff->type != none || iff->ifTrue->type != none) return;
+ if (iff->type != none || iff->ifTrue->type != none)
+ return;
// Anything sinkable is good for us.
- if (sinkables.empty()) return;
+ if (sinkables.empty())
+ return;
Index goodIndex = sinkables.begin()->first;
// Ensure we have a place to write the return values for, if not, we
// need another cycle.
auto* ifTrueBlock = iff->ifTrue->dynCast<Block>();
- if (!ifTrueBlock || ifTrueBlock->name.is() || ifTrueBlock->list.size() == 0 || !ifTrueBlock->list.back()->is<Nop>()) {
+ if (!ifTrueBlock || ifTrueBlock->name.is() ||
+ ifTrueBlock->list.size() == 0 || !ifTrueBlock->list.back()->is<Nop>()) {
ifsToEnlarge.push_back(iff);
return;
}
@@ -625,7 +678,8 @@ struct SimplifyLocals : public WalkerPass<LinearExecutionWalker<SimplifyLocals<a
}
// override scan to add a pre and a post check task to all nodes
- static void scan(SimplifyLocals<allowTee, allowStructure, allowNesting>* self, Expression** currp) {
+ static void scan(SimplifyLocals<allowTee, allowStructure, allowNesting>* self,
+ Expression** currp) {
self->pushTask(visitPost, currp);
auto* curr = *currp;
@@ -633,15 +687,29 @@ struct SimplifyLocals : public WalkerPass<LinearExecutionWalker<SimplifyLocals<a
if (auto* iff = curr->dynCast<If>()) {
// handle if in a special manner, using the ifStack for if-elses etc.
if (iff->ifFalse) {
- self->pushTask(SimplifyLocals<allowTee, allowStructure, allowNesting>::doNoteIfFalse, currp);
- self->pushTask(SimplifyLocals<allowTee, allowStructure, allowNesting>::scan, &iff->ifFalse);
+ self->pushTask(
+ SimplifyLocals<allowTee, allowStructure, allowNesting>::doNoteIfFalse,
+ currp);
+ self->pushTask(
+ SimplifyLocals<allowTee, allowStructure, allowNesting>::scan,
+ &iff->ifFalse);
}
- self->pushTask(SimplifyLocals<allowTee, allowStructure, allowNesting>::doNoteIfTrue, currp);
- self->pushTask(SimplifyLocals<allowTee, allowStructure, allowNesting>::scan, &iff->ifTrue);
- self->pushTask(SimplifyLocals<allowTee, allowStructure, allowNesting>::doNoteIfCondition, currp);
- self->pushTask(SimplifyLocals<allowTee, allowStructure, allowNesting>::scan, &iff->condition);
+ self->pushTask(
+ SimplifyLocals<allowTee, allowStructure, allowNesting>::doNoteIfTrue,
+ currp);
+ self->pushTask(
+ SimplifyLocals<allowTee, allowStructure, allowNesting>::scan,
+ &iff->ifTrue);
+ self->pushTask(SimplifyLocals<allowTee, allowStructure, allowNesting>::
+ doNoteIfCondition,
+ currp);
+ self->pushTask(
+ SimplifyLocals<allowTee, allowStructure, allowNesting>::scan,
+ &iff->condition);
} else {
- WalkerPass<LinearExecutionWalker<SimplifyLocals<allowTee, allowStructure, allowNesting>>>::scan(self, currp);
+ WalkerPass<LinearExecutionWalker<
+ SimplifyLocals<allowTee, allowStructure, allowNesting>>>::scan(self,
+ currp);
}
self->pushTask(visitPre, currp);
@@ -685,11 +753,14 @@ struct SimplifyLocals : public WalkerPass<LinearExecutionWalker<SimplifyLocals<a
bool runMainOptimizations(Function* func) {
anotherCycle = false;
- WalkerPass<LinearExecutionWalker<SimplifyLocals<allowTee, allowStructure, allowNesting>>>::doWalkFunction(func);
+ WalkerPass<LinearExecutionWalker<
+ SimplifyLocals<allowTee, allowStructure, allowNesting>>>::
+ doWalkFunction(func);
// enlarge blocks that were marked, for the next round
if (blocksToEnlarge.size() > 0) {
for (auto* block : blocksToEnlarge) {
- block->list.push_back(this->getModule()->allocator.template alloc<Nop>());
+ block->list.push_back(
+ this->getModule()->allocator.template alloc<Nop>());
}
blocksToEnlarge.clear();
anotherCycle = true;
@@ -697,16 +768,22 @@ struct SimplifyLocals : public WalkerPass<LinearExecutionWalker<SimplifyLocals<a
// enlarge ifs that were marked, for the next round
if (ifsToEnlarge.size() > 0) {
for (auto* iff : ifsToEnlarge) {
- auto ifTrue = Builder(*this->getModule()).blockifyWithName(iff->ifTrue, Name());
+ auto ifTrue =
+ Builder(*this->getModule()).blockifyWithName(iff->ifTrue, Name());
iff->ifTrue = ifTrue;
- if (ifTrue->list.size() == 0 || !ifTrue->list.back()->template is<Nop>()) {
- ifTrue->list.push_back(this->getModule()->allocator.template alloc<Nop>());
+ if (ifTrue->list.size() == 0 ||
+ !ifTrue->list.back()->template is<Nop>()) {
+ ifTrue->list.push_back(
+ this->getModule()->allocator.template alloc<Nop>());
}
if (iff->ifFalse) {
- auto ifFalse = Builder(*this->getModule()).blockifyWithName(iff->ifFalse, Name());
+ auto ifFalse =
+ Builder(*this->getModule()).blockifyWithName(iff->ifFalse, Name());
iff->ifFalse = ifFalse;
- if (ifFalse->list.size() == 0 || !ifFalse->list.back()->template is<Nop>()) {
- ifFalse->list.push_back(this->getModule()->allocator.template alloc<Nop>());
+ if (ifFalse->list.size() == 0 ||
+ !ifFalse->list.back()->template is<Nop>()) {
+ ifFalse->list.push_back(
+ this->getModule()->allocator.template alloc<Nop>());
}
}
}
@@ -716,10 +793,13 @@ struct SimplifyLocals : public WalkerPass<LinearExecutionWalker<SimplifyLocals<a
// enlarge loops that were marked, for the next round
if (loopsToEnlarge.size() > 0) {
for (auto* loop : loopsToEnlarge) {
- auto block = Builder(*this->getModule()).blockifyWithName(loop->body, Name());
+ auto block =
+ Builder(*this->getModule()).blockifyWithName(loop->body, Name());
loop->body = block;
- if (block->list.size() == 0 || !block->list.back()->template is<Nop>()) {
- block->list.push_back(this->getModule()->allocator.template alloc<Nop>());
+ if (block->list.size() == 0 ||
+ !block->list.back()->template is<Nop>()) {
+ block->list.push_back(
+ this->getModule()->allocator.template alloc<Nop>());
}
}
loopsToEnlarge.clear();
@@ -750,7 +830,8 @@ struct SimplifyLocals : public WalkerPass<LinearExecutionWalker<SimplifyLocals<a
// )
// )
// will inhibit us creating an if return value.
- struct EquivalentOptimizer : public LinearExecutionWalker<EquivalentOptimizer> {
+ struct EquivalentOptimizer
+ : public LinearExecutionWalker<EquivalentOptimizer> {
std::vector<Index>* numGetLocals;
bool removeEquivalentSets;
Module* module;
@@ -760,13 +841,14 @@ struct SimplifyLocals : public WalkerPass<LinearExecutionWalker<SimplifyLocals<a
// We track locals containing the same value.
EquivalentSets equivalences;
- static void doNoteNonLinear(EquivalentOptimizer* self, Expression** currp) {
- // TODO do this across non-linear paths too, in coalesce-locals perhaps? (would inhibit structure
- // opts here, though.
+ static void doNoteNonLinear(EquivalentOptimizer* self,
+ Expression** currp) {
+ // TODO do this across non-linear paths too, in coalesce-locals perhaps?
+ // (would inhibit structure opts here, though.
self->equivalences.clear();
}
- void visitSetLocal(SetLocal *curr) {
+ void visitSetLocal(SetLocal* curr) {
// Remove trivial copies, even through a tee
auto* value = curr->value;
while (auto* subSet = value->dynCast<SetLocal>()) {
@@ -794,14 +876,14 @@ struct SimplifyLocals : public WalkerPass<LinearExecutionWalker<SimplifyLocals<a
}
}
- void visitGetLocal(GetLocal *curr) {
+ void visitGetLocal(GetLocal* curr) {
// Canonicalize gets: if some are equivalent, then we can pick more
// then one, and other passes may benefit from having more uniformity.
if (auto* set = equivalences.getEquivalents(curr->index)) {
// Pick the index with the most uses - maximizing the chance to
// lower one's uses to zero.
- // Helper method that returns the # of gets *ignoring the current get*,
- // as we want to see what is best overall, treating this one as
+ // Helper method that returns the # of gets *ignoring the current
+ // get*, as we want to see what is best overall, treating this one as
// to be decided upon.
auto getNumGetsIgnoringCurr = [&](Index index) {
auto ret = (*numGetLocals)[index];
@@ -821,8 +903,8 @@ struct SimplifyLocals : public WalkerPass<LinearExecutionWalker<SimplifyLocals<a
assert(best != Index(-1));
// Due to ordering, the best index may be different from us but have
// the same # of locals - make sure we actually improve.
- if (best != curr->index &&
- getNumGetsIgnoringCurr(best) > getNumGetsIgnoringCurr(curr->index)) {
+ if (best != curr->index && getNumGetsIgnoringCurr(best) >
+ getNumGetsIgnoringCurr(curr->index)) {
// Update the get counts.
(*numGetLocals)[best]++;
assert((*numGetLocals)[curr->index] >= 1);
@@ -850,23 +932,21 @@ struct SimplifyLocals : public WalkerPass<LinearExecutionWalker<SimplifyLocals<a
}
};
-Pass *createSimplifyLocalsPass() {
- return new SimplifyLocals<true, true>();
-}
+Pass* createSimplifyLocalsPass() { return new SimplifyLocals<true, true>(); }
-Pass *createSimplifyLocalsNoTeePass() {
+Pass* createSimplifyLocalsNoTeePass() {
return new SimplifyLocals<false, true>();
}
-Pass *createSimplifyLocalsNoStructurePass() {
+Pass* createSimplifyLocalsNoStructurePass() {
return new SimplifyLocals<true, false>();
}
-Pass *createSimplifyLocalsNoTeeNoStructurePass() {
+Pass* createSimplifyLocalsNoTeeNoStructurePass() {
return new SimplifyLocals<false, false>();
}
-Pass *createSimplifyLocalsNoNestingPass() {
+Pass* createSimplifyLocalsNoNestingPass() {
return new SimplifyLocals<false, false, false>();
}
diff --git a/src/passes/Souperify.cpp b/src/passes/Souperify.cpp
index f6700a698..1cc3037fe 100644
--- a/src/passes/Souperify.cpp
+++ b/src/passes/Souperify.cpp
@@ -35,15 +35,15 @@
// directly, without the need for *-propagate techniques.
//
-#include "wasm.h"
-#include "pass.h"
-#include "wasm-builder.h"
+#include "dataflow/graph.h"
+#include "dataflow/node.h"
+#include "dataflow/utils.h"
#include "ir/flat.h"
#include "ir/local-graph.h"
#include "ir/utils.h"
-#include "dataflow/node.h"
-#include "dataflow/graph.h"
-#include "dataflow/utils.h"
+#include "pass.h"
+#include "wasm-builder.h"
+#include "wasm.h"
namespace wasm {
@@ -62,7 +62,8 @@ struct UseFinder {
// (or rather, their values) that contain a get that uses that value.
// There may also be non-set uses of the value, for example in a drop
// or a return. We represent those with a nullptr, meaning "other".
- std::vector<Expression*> getUses(Expression* origin, Graph& graph, LocalGraph& localGraph) {
+ std::vector<Expression*>
+ getUses(Expression* origin, Graph& graph, LocalGraph& localGraph) {
if (debug() >= 2) {
std::cout << "getUses\n" << origin << '\n';
}
@@ -80,9 +81,13 @@ struct UseFinder {
// There may be loops of sets with copies between them.
std::unordered_set<SetLocal*> seenSets;
- void addSetUses(SetLocal* set, Graph& graph, LocalGraph& localGraph, std::vector<Expression*>& ret) {
+ void addSetUses(SetLocal* set,
+ Graph& graph,
+ LocalGraph& localGraph,
+ std::vector<Expression*>& ret) {
// If already handled, nothing to do here.
- if (seenSets.count(set)) return;
+ if (seenSets.count(set))
+ return;
seenSets.insert(set);
// Find all the uses of that set.
auto& gets = localGraph.setInfluences[set];
@@ -165,7 +170,12 @@ struct Trace {
// The local information graph. Used to check if a node has external uses.
LocalGraph& localGraph;
- Trace(Graph& graph, Node* toInfer, std::unordered_set<Node*>& excludeAsChildren, LocalGraph& localGraph) : graph(graph), toInfer(toInfer), excludeAsChildren(excludeAsChildren), localGraph(localGraph) {
+ Trace(Graph& graph,
+ Node* toInfer,
+ std::unordered_set<Node*>& excludeAsChildren,
+ LocalGraph& localGraph)
+ : graph(graph), toInfer(toInfer), excludeAsChildren(excludeAsChildren),
+ localGraph(localGraph) {
if (debug() >= 2) {
std::cout << "\nstart a trace (in " << graph.func->name << ")\n";
}
@@ -180,7 +190,8 @@ struct Trace {
}
// Pull in all the dependencies, starting from the value itself.
add(toInfer, 0);
- if (bad) return;
+ if (bad)
+ return;
// If we are trivial before adding pcs, we are still trivial, and
// can ignore this.
auto sizeBeforePathConditions = nodes.size();
@@ -238,7 +249,8 @@ struct Trace {
// If we've gone too deep, emit a var instead.
// Do the same if this is a node we should exclude from traces.
if (depth >= depthLimit || nodes.size() >= totalLimit ||
- (node != toInfer && excludeAsChildren.find(node) != excludeAsChildren.end())) {
+ (node != toInfer &&
+ excludeAsChildren.find(node) != excludeAsChildren.end())) {
auto type = node->getWasmType();
assert(isConcreteType(type));
auto* var = Node::makeVar(type);
@@ -293,7 +305,8 @@ struct Trace {
bad = true;
return nullptr;
}
- default: WASM_UNREACHABLE();
+ default:
+ WASM_UNREACHABLE();
}
// Assert on no cycles
assert(addedNodes.find(node) == addedNodes.end());
@@ -319,7 +332,9 @@ struct Trace {
// curr is a child of parent, and parent has a Block which we are
// give as 'node'. Add a path condition for reaching the child.
- void addPathTo(Expression* parent, Expression* curr, std::vector<Node*> conditions) {
+ void addPathTo(Expression* parent,
+ Expression* curr,
+ std::vector<Node*> conditions) {
if (auto* iff = parent->dynCast<If>()) {
Index index;
if (curr == iff->ifTrue) {
@@ -340,9 +355,7 @@ struct Trace {
}
}
- bool isBad() {
- return bad;
- }
+ bool isBad() { return bad; }
static bool isTraceable(Node* node) {
if (!node->origin) {
@@ -372,7 +385,8 @@ struct Trace {
}
}
for (auto& node : nodes) {
- if (node == toInfer) continue;
+ if (node == toInfer)
+ continue;
if (auto* origin = node->origin) {
auto uses = UseFinder().getUses(origin, graph, localGraph);
for (auto* use : uses) {
@@ -407,7 +421,8 @@ struct Printer {
std::cout << "\n; start LHS (in " << graph.func->name << ")\n";
// Index the nodes.
for (auto* node : trace.nodes) {
- if (!node->isCond()) { // pcs and blockpcs are not instructions and do not need to be indexed
+ // pcs and blockpcs are not instructions and do not need to be indexed
+ if (!node->isCond()) {
auto index = indexing.size();
indexing[node] = index;
}
@@ -440,7 +455,8 @@ struct Printer {
assert(node);
switch (node->type) {
case Node::Type::Var: {
- std::cout << "%" << indexing[node] << ":" << printType(node->wasmType) << " = var";
+ std::cout << "%" << indexing[node] << ":" << printType(node->wasmType)
+ << " = var";
break; // nothing more to add
}
case Node::Type::Expr: {
@@ -464,18 +480,21 @@ struct Printer {
break;
}
case Node::Type::Cond: {
- std::cout << "blockpc %" << indexing[node->getValue(0)] << ' ' << node->index << ' ';
+ std::cout << "blockpc %" << indexing[node->getValue(0)] << ' '
+ << node->index << ' ';
printInternal(node->getValue(1));
std::cout << " 1:i1";
break;
}
case Node::Type::Block: {
- std::cout << "%" << indexing[node] << " = block " << node->values.size();
+ std::cout << "%" << indexing[node] << " = block "
+ << node->values.size();
break;
}
case Node::Type::Zext: {
auto* child = node->getValue(0);
- std::cout << "%" << indexing[node] << ':' << printType(child->getWasmType());
+ std::cout << "%" << indexing[node] << ':'
+ << printType(child->getWasmType());
std::cout << " = zext ";
printInternal(child);
break;
@@ -484,10 +503,12 @@ struct Printer {
std::cout << "!!!BAD!!!";
WASM_UNREACHABLE();
}
- default: WASM_UNREACHABLE();
+ default:
+ WASM_UNREACHABLE();
}
if (node->isExpr() || node->isPhi()) {
- if (node->origin != trace.toInfer->origin && trace.hasExternalUses.count(node) > 0) {
+ if (node->origin != trace.toInfer->origin &&
+ trace.hasExternalUses.count(node) > 0) {
std::cout << " (hasExternalUses)";
printedHasExternalUses = true;
}
@@ -523,12 +544,19 @@ struct Printer {
} else if (auto* unary = curr->dynCast<Unary>()) {
switch (unary->op) {
case ClzInt32:
- case ClzInt64: std::cout << "ctlz"; break;
+ case ClzInt64:
+ std::cout << "ctlz";
+ break;
case CtzInt32:
- case CtzInt64: std::cout << "cttz"; break;
+ case CtzInt64:
+ std::cout << "cttz";
+ break;
case PopcntInt32:
- case PopcntInt64: std::cout << "ctpop"; break;
- default: WASM_UNREACHABLE();
+ case PopcntInt64:
+ std::cout << "ctpop";
+ break;
+ default:
+ WASM_UNREACHABLE();
}
std::cout << ' ';
auto* value = node->getValue(0);
@@ -536,48 +564,91 @@ struct Printer {
} else if (auto* binary = curr->dynCast<Binary>()) {
switch (binary->op) {
case AddInt32:
- case AddInt64: std::cout << "add"; break;
+ case AddInt64:
+ std::cout << "add";
+ break;
case SubInt32:
- case SubInt64: std::cout << "sub"; break;
+ case SubInt64:
+ std::cout << "sub";
+ break;
case MulInt32:
- case MulInt64: std::cout << "mul"; break;
+ case MulInt64:
+ std::cout << "mul";
+ break;
case DivSInt32:
- case DivSInt64: std::cout << "sdiv"; break;
+ case DivSInt64:
+ std::cout << "sdiv";
+ break;
case DivUInt32:
- case DivUInt64: std::cout << "udiv"; break;
+ case DivUInt64:
+ std::cout << "udiv";
+ break;
case RemSInt32:
- case RemSInt64: std::cout << "srem"; break;
+ case RemSInt64:
+ std::cout << "srem";
+ break;
case RemUInt32:
- case RemUInt64: std::cout << "urem"; break;
+ case RemUInt64:
+ std::cout << "urem";
+ break;
case AndInt32:
- case AndInt64: std::cout << "and"; break;
+ case AndInt64:
+ std::cout << "and";
+ break;
case OrInt32:
- case OrInt64: std::cout << "or"; break;
+ case OrInt64:
+ std::cout << "or";
+ break;
case XorInt32:
- case XorInt64: std::cout << "xor"; break;
+ case XorInt64:
+ std::cout << "xor";
+ break;
case ShlInt32:
- case ShlInt64: std::cout << "shl"; break;
+ case ShlInt64:
+ std::cout << "shl";
+ break;
case ShrUInt32:
- case ShrUInt64: std::cout << "lshr"; break;
+ case ShrUInt64:
+ std::cout << "lshr";
+ break;
case ShrSInt32:
- case ShrSInt64: std::cout << "ashr"; break;
+ case ShrSInt64:
+ std::cout << "ashr";
+ break;
case RotLInt32:
- case RotLInt64: std::cout << "rotl"; break;
+ case RotLInt64:
+ std::cout << "rotl";
+ break;
case RotRInt32:
- case RotRInt64: std::cout << "rotr"; break;
+ case RotRInt64:
+ std::cout << "rotr";
+ break;
case EqInt32:
- case EqInt64: std::cout << "eq"; break;
+ case EqInt64:
+ std::cout << "eq";
+ break;
case NeInt32:
- case NeInt64: std::cout << "ne"; break;
+ case NeInt64:
+ std::cout << "ne";
+ break;
case LtSInt32:
- case LtSInt64: std::cout << "slt"; break;
+ case LtSInt64:
+ std::cout << "slt";
+ break;
case LtUInt32:
- case LtUInt64: std::cout << "ult"; break;
+ case LtUInt64:
+ std::cout << "ult";
+ break;
case LeSInt32:
- case LeSInt64: std::cout << "sle"; break;
+ case LeSInt64:
+ std::cout << "sle";
+ break;
case LeUInt32:
- case LeUInt64: std::cout << "ule"; break;
- default: WASM_UNREACHABLE();
+ case LeUInt64:
+ std::cout << "ule";
+ break;
+ default:
+ WASM_UNREACHABLE();
}
std::cout << ' ';
auto* left = node->getValue(0);
@@ -616,11 +687,13 @@ struct Printer {
}
}
if (allInputsIdentical(node)) {
- std::cout << "^^ suspicious identical inputs! missing optimization in " << graph.func->name << "? ^^\n";
+ std::cout << "^^ suspicious identical inputs! missing optimization in "
+ << graph.func->name << "? ^^\n";
return;
}
if (!node->isPhi() && allInputsConstant(node)) {
- std::cout << "^^ suspicious constant inputs! missing optimization in " << graph.func->name << "? ^^\n";
+ std::cout << "^^ suspicious constant inputs! missing optimization in "
+ << graph.func->name << "? ^^\n";
return;
}
}
@@ -642,7 +715,8 @@ struct Souperify : public WalkerPass<PostWalker<Souperify>> {
// Build the data-flow IR.
DataFlow::Graph graph;
graph.build(func, getModule());
- if (debug() >= 2) dump(graph, std::cout);
+ if (debug() >= 2)
+ dump(graph, std::cout);
// Build the local graph data structure.
LocalGraph localGraph(func);
localGraph.computeInfluences();
@@ -653,7 +727,8 @@ struct Souperify : public WalkerPass<PostWalker<Souperify>> {
auto* node = nodePtr.get();
if (node->origin) {
// TODO: work for identical origins could be saved
- auto uses = DataFlow::UseFinder().getUses(node->origin, graph, localGraph);
+ auto uses =
+ DataFlow::UseFinder().getUses(node->origin, graph, localGraph);
if (debug() >= 2) {
std::cout << "following node has " << uses.size() << " uses\n";
dump(node, std::cout);
@@ -681,12 +756,8 @@ struct Souperify : public WalkerPass<PostWalker<Souperify>> {
}
};
-Pass *createSouperifyPass() {
- return new Souperify(false);
-}
+Pass* createSouperifyPass() { return new Souperify(false); }
-Pass *createSouperifySingleUsePass() {
- return new Souperify(true);
-}
+Pass* createSouperifySingleUsePass() { return new Souperify(true); }
} // namespace wasm
diff --git a/src/passes/SpillPointers.cpp b/src/passes/SpillPointers.cpp
index 36c2ae948..75fa72652 100644
--- a/src/passes/SpillPointers.cpp
+++ b/src/passes/SpillPointers.cpp
@@ -14,7 +14,6 @@
* limitations under the License.
*/
-
//
// Spills values that might be pointers to the C stack. This allows
// Boehm-style GC to see them properly.
@@ -26,16 +25,17 @@
// * There is currently no check that there is enough stack space.
//
-#include "wasm.h"
-#include "pass.h"
-#include "cfg/liveness-traversal.h"
-#include "wasm-builder.h"
#include "abi/abi.h"
#include "abi/stack.h"
+#include "cfg/liveness-traversal.h"
+#include "pass.h"
+#include "wasm-builder.h"
+#include "wasm.h"
namespace wasm {
-struct SpillPointers : public WalkerPass<LivenessWalker<SpillPointers, Visitor<SpillPointers>>> {
+struct SpillPointers
+ : public WalkerPass<LivenessWalker<SpillPointers, Visitor<SpillPointers>>> {
bool isFunctionParallel() override { return true; }
Pass* create() override { return new SpillPointers; }
@@ -48,21 +48,18 @@ struct SpillPointers : public WalkerPass<LivenessWalker<SpillPointers, Visitor<S
std::unordered_map<Expression**, Expression**> actualPointers;
// note calls in basic blocks
- template<typename T>
- void visitSpillable(T* curr) {
- // if in unreachable code, ignore
- if (!currBasicBlock) return;
+ template<typename T> void visitSpillable(T* curr) {
+ // if in unreachable code, ignore
+ if (!currBasicBlock)
+ return;
auto* pointer = getCurrentPointer();
currBasicBlock->contents.actions.emplace_back(pointer);
- actualPointers[pointer] = pointer; // starts out as correct, may change later
+ // starts out as correct, may change later
+ actualPointers[pointer] = pointer;
}
- void visitCall(Call* curr) {
- visitSpillable(curr);
- }
- void visitCallIndirect(CallIndirect* curr) {
- visitSpillable(curr);
- }
+ void visitCall(Call* curr) { visitSpillable(curr); }
+ void visitCallIndirect(CallIndirect* curr) { visitSpillable(curr); }
// main entry point
@@ -73,7 +70,7 @@ struct SpillPointers : public WalkerPass<LivenessWalker<SpillPointers, Visitor<S
// map pointers to their offset in the spill area
typedef std::unordered_map<Index, Index> PointerMap;
-
+
void spillPointers() {
// we only care about possible pointers
auto* func = getFunction();
@@ -88,7 +85,8 @@ struct SpillPointers : public WalkerPass<LivenessWalker<SpillPointers, Visitor<S
bool spilled = false;
Index spillLocal = -1;
for (auto& curr : basicBlocks) {
- if (liveBlocks.count(curr.get()) == 0) continue; // ignore dead blocks
+ if (liveBlocks.count(curr.get()) == 0)
+ continue; // ignore dead blocks
auto& liveness = curr->contents;
auto& actions = liveness.actions;
Index lastCall = -1;
@@ -98,7 +96,8 @@ struct SpillPointers : public WalkerPass<LivenessWalker<SpillPointers, Visitor<S
lastCall = i;
}
}
- if (lastCall == Index(-1)) continue; // nothing to see here
+ if (lastCall == Index(-1))
+ continue; // nothing to see here
// scan through the block, spilling around the calls
// TODO: we can filter on pointerMap everywhere
LocalSet live = liveness.end;
@@ -119,12 +118,15 @@ struct SpillPointers : public WalkerPass<LivenessWalker<SpillPointers, Visitor<S
// we now have a call + the information about which locals
// should be spilled
if (!spilled) {
- // prepare stack support: get a pointer to stack space big enough for all our data
+ // prepare stack support: get a pointer to stack space big enough
+ // for all our data
spillLocal = Builder::addVar(func, ABI::PointerType);
spilled = true;
}
- auto* pointer = actualPointers[action.origin]; // the origin was seen at walk, but the thing may have moved
- spillPointersAroundCall(pointer, toSpill, spillLocal, pointerMap, func, getModule());
+ // the origin was seen at walk, but the thing may have moved
+ auto* pointer = actualPointers[action.origin];
+ spillPointersAroundCall(
+ pointer, toSpill, spillLocal, pointerMap, func, getModule());
}
} else {
WASM_UNREACHABLE();
@@ -133,13 +135,22 @@ struct SpillPointers : public WalkerPass<LivenessWalker<SpillPointers, Visitor<S
}
if (spilled) {
// get the stack space, and set the local to it
- ABI::getStackSpace(spillLocal, func, getTypeSize(ABI::PointerType) * pointerMap.size(), *getModule());
+ ABI::getStackSpace(spillLocal,
+ func,
+ getTypeSize(ABI::PointerType) * pointerMap.size(),
+ *getModule());
}
}
- void spillPointersAroundCall(Expression** origin, std::vector<Index>& toSpill, Index spillLocal, PointerMap& pointerMap, Function* func, Module* module) {
+ void spillPointersAroundCall(Expression** origin,
+ std::vector<Index>& toSpill,
+ Index spillLocal,
+ PointerMap& pointerMap,
+ Function* func,
+ Module* module) {
auto* call = *origin;
- if (call->type == unreachable) return; // the call is never reached anyhow, ignore
+ if (call->type == unreachable)
+ return; // the call is never reached anyhow, ignore
Builder builder(*module);
auto* block = builder.makeBlock();
// move the operands into locals, as we must spill after they are executed
@@ -168,14 +179,13 @@ struct SpillPointers : public WalkerPass<LivenessWalker<SpillPointers, Visitor<S
}
// add the spills
for (auto index : toSpill) {
- block->list.push_back(builder.makeStore(
- getTypeSize(ABI::PointerType),
- pointerMap[index],
- getTypeSize(ABI::PointerType),
- builder.makeGetLocal(spillLocal, ABI::PointerType),
- builder.makeGetLocal(index, ABI::PointerType),
- ABI::PointerType
- ));
+ block->list.push_back(
+ builder.makeStore(getTypeSize(ABI::PointerType),
+ pointerMap[index],
+ getTypeSize(ABI::PointerType),
+ builder.makeGetLocal(spillLocal, ABI::PointerType),
+ builder.makeGetLocal(index, ABI::PointerType),
+ ABI::PointerType));
}
// add the (modified) call
block->list.push_back(call);
@@ -184,8 +194,6 @@ struct SpillPointers : public WalkerPass<LivenessWalker<SpillPointers, Visitor<S
}
};
-Pass *createSpillPointersPass() {
- return new SpillPointers();
-}
+Pass* createSpillPointersPass() { return new SpillPointers(); }
} // namespace wasm
diff --git a/src/passes/StackIR.cpp b/src/passes/StackIR.cpp
index a8d66ae42..2506eca27 100644
--- a/src/passes/StackIR.cpp
+++ b/src/passes/StackIR.cpp
@@ -18,11 +18,11 @@
// Operations on Stack IR.
//
-#include "wasm.h"
-#include "pass.h"
-#include "wasm-stack.h"
#include "ir/iteration.h"
#include "ir/local-graph.h"
+#include "pass.h"
+#include "wasm-stack.h"
+#include "wasm.h"
namespace wasm {
@@ -43,23 +43,16 @@ struct GenerateStackIR : public WalkerPass<PostWalker<GenerateStackIR>> {
Module* module;
Parent(Module* module) : module(module) {}
- Module* getModule() {
- return module;
- }
+ Module* getModule() { return module; }
void writeDebugLocation(Expression* curr, Function* func) {
WASM_UNREACHABLE();
}
- Index getFunctionIndex(Name name) {
- WASM_UNREACHABLE();
- }
- Index getFunctionTypeIndex(Name name) {
- WASM_UNREACHABLE();
- }
- Index getGlobalIndex(Name name) {
- WASM_UNREACHABLE();
- }
+ Index getFunctionIndex(Name name) { WASM_UNREACHABLE(); }
+ Index getFunctionTypeIndex(Name name) { WASM_UNREACHABLE(); }
+ Index getGlobalIndex(Name name) { WASM_UNREACHABLE(); }
} parent(getModule());
- StackWriter<StackWriterMode::Binaryen2Stack, Parent> stackWriter(parent, buffer, false);
+ StackWriter<StackWriterMode::Binaryen2Stack, Parent> stackWriter(
+ parent, buffer, false);
stackWriter.setFunction(func);
stackWriter.visitPossibleBlockContents(func->body);
func->stackIR = make_unique<StackIR>();
@@ -67,9 +60,7 @@ struct GenerateStackIR : public WalkerPass<PostWalker<GenerateStackIR>> {
}
};
-Pass* createGenerateStackIRPass() {
- return new GenerateStackIR();
-}
+Pass* createGenerateStackIRPass() { return new GenerateStackIR(); }
// Optimize
@@ -79,8 +70,8 @@ class StackIROptimizer {
StackIR& insts;
public:
- StackIROptimizer(Function* func, PassOptions& passOptions) :
- func(func), passOptions(passOptions), insts(*func->stackIR.get()) {
+ StackIROptimizer(Function* func, PassOptions& passOptions)
+ : func(func), passOptions(passOptions), insts(*func->stackIR.get()) {
assert(func->stackIR);
}
@@ -103,7 +94,8 @@ private:
bool inUnreachableCode = false;
for (Index i = 0; i < insts.size(); i++) {
auto* inst = insts[i];
- if (!inst) continue;
+ if (!inst)
+ continue;
if (inUnreachableCode) {
// Does the unreachable code end here?
if (isControlFlowBarrier(inst)) {
@@ -151,12 +143,15 @@ private:
#endif
for (Index i = 0; i < insts.size(); i++) {
auto* inst = insts[i];
- if (!inst) continue;
+ if (!inst)
+ continue;
// First, consume values from the stack as required.
auto consumed = getNumConsumedValues(inst);
#ifdef STACK_OPT_DEBUG
- std::cout << " " << i << " : " << *inst << ", " << values.size() << " on stack, will consume " << consumed << "\n ";
- for (auto s : values) std::cout << s << ' ';
+ std::cout << " " << i << " : " << *inst << ", " << values.size()
+ << " on stack, will consume " << consumed << "\n ";
+ for (auto s : values)
+ std::cout << s << ' ';
std::cout << '\n';
#endif
// TODO: currently we run dce before this, but if we didn't, we'd need
@@ -199,7 +194,8 @@ private:
while (1) {
// If there's an actual value in the way, we've failed.
auto index = values[j];
- if (index == null) break;
+ if (index == null)
+ break;
auto* set = insts[index]->origin->cast<SetLocal>();
if (set->index == get->index) {
// This might be a proper set-get pair, where the set is
@@ -228,7 +224,8 @@ private:
}
}
// We failed here. Can we look some more?
- if (j == 0) break;
+ if (j == 0)
+ break;
j--;
}
}
@@ -250,7 +247,8 @@ private:
// a branch to that if body
void removeUnneededBlocks() {
for (auto*& inst : insts) {
- if (!inst) continue;
+ if (!inst)
+ continue;
if (auto* block = inst->origin->dynCast<Block>()) {
if (!BranchUtils::BranchSeeker::hasNamed(block, block->name)) {
// TODO optimize, maybe run remove-unused-names
@@ -272,9 +270,7 @@ private:
case StackInst::LoopEnd: {
return true;
}
- default: {
- return false;
- }
+ default: { return false; }
}
}
@@ -286,9 +282,7 @@ private:
case StackInst::LoopBegin: {
return true;
}
- default: {
- return false;
- }
+ default: { return false; }
}
}
@@ -300,15 +294,11 @@ private:
case StackInst::LoopEnd: {
return true;
}
- default: {
- return false;
- }
+ default: { return false; }
}
}
- bool isControlFlow(StackInst* inst) {
- return inst->op != StackInst::Basic;
- }
+ bool isControlFlow(StackInst* inst) { return inst->op != StackInst::Basic; }
// Remove the instruction at index i. If the instruction
// is control flow, and so has been expanded to multiple
@@ -359,9 +349,6 @@ struct OptimizeStackIR : public WalkerPass<PostWalker<OptimizeStackIR>> {
}
};
-Pass* createOptimizeStackIRPass() {
- return new OptimizeStackIR();
-}
+Pass* createOptimizeStackIRPass() { return new OptimizeStackIR(); }
} // namespace wasm
-
diff --git a/src/passes/Strip.cpp b/src/passes/Strip.cpp
index edc171ab3..e85379003 100644
--- a/src/passes/Strip.cpp
+++ b/src/passes/Strip.cpp
@@ -21,9 +21,9 @@
#include <functional>
-#include "wasm.h"
-#include "wasm-binary.h"
#include "pass.h"
+#include "wasm-binary.h"
+#include "wasm.h"
using namespace std;
@@ -31,7 +31,7 @@ namespace wasm {
struct Strip : public Pass {
// A function that returns true if the method should be removed.
- typedef std::function<bool (UserSection&)> Decider;
+ typedef std::function<bool(UserSection&)> Decider;
Decider decider;
Strip(Decider decider) : decider(decider) {}
@@ -39,14 +39,8 @@ struct Strip : public Pass {
void run(PassRunner* runner, Module* module) override {
// Remove name and debug sections.
auto& sections = module->userSections;
- sections.erase(
- std::remove_if(
- sections.begin(),
- sections.end(),
- decider
- ),
- sections.end()
- );
+ sections.erase(std::remove_if(sections.begin(), sections.end(), decider),
+ sections.end());
// If we're cleaning up debug info, clear on the function and module too.
UserSection temp;
temp.name = BinaryConsts::UserSections::Name;
@@ -60,16 +54,15 @@ struct Strip : public Pass {
}
};
-Pass *createStripDebugPass() {
+Pass* createStripDebugPass() {
return new Strip([&](const UserSection& curr) {
return curr.name == BinaryConsts::UserSections::Name ||
curr.name == BinaryConsts::UserSections::SourceMapUrl ||
- curr.name.find(".debug") == 0 ||
- curr.name.find("reloc..debug") == 0;
+ curr.name.find(".debug") == 0 || curr.name.find("reloc..debug") == 0;
});
}
-Pass *createStripProducersPass() {
+Pass* createStripProducersPass() {
return new Strip([&](const UserSection& curr) {
return curr.name == BinaryConsts::UserSections::Producers;
});
diff --git a/src/passes/StripTargetFeatures.cpp b/src/passes/StripTargetFeatures.cpp
index 8eb7b0b75..542b4a6c1 100644
--- a/src/passes/StripTargetFeatures.cpp
+++ b/src/passes/StripTargetFeatures.cpp
@@ -24,8 +24,6 @@ struct StripTargetFeatures : public Pass {
}
};
-Pass *createStripTargetFeaturesPass() {
- return new StripTargetFeatures();
-}
+Pass* createStripTargetFeaturesPass() { return new StripTargetFeatures(); }
} // namespace wasm
diff --git a/src/passes/TrapMode.cpp b/src/passes/TrapMode.cpp
index e6327479c..b36427138 100644
--- a/src/passes/TrapMode.cpp
+++ b/src/passes/TrapMode.cpp
@@ -26,66 +26,84 @@
#include "ir/trapping.h"
#include "mixed_arena.h"
#include "pass.h"
-#include "wasm.h"
+#include "support/name.h"
#include "wasm-builder.h"
#include "wasm-printing.h"
#include "wasm-type.h"
-#include "support/name.h"
+#include "wasm.h"
namespace wasm {
-Name I64S_REM("i64s-rem"),
- I64U_REM("i64u-rem"),
- I64S_DIV("i64s-div"),
- I64U_DIV("i64u-div");
+Name I64S_REM("i64s-rem");
+Name I64U_REM("i64u-rem");
+Name I64S_DIV("i64s-div");
+Name I64U_DIV("i64u-div");
Name getBinaryFuncName(Binary* curr) {
switch (curr->op) {
- case RemSInt32: return I32S_REM;
- case RemUInt32: return I32U_REM;
- case DivSInt32: return I32S_DIV;
- case DivUInt32: return I32U_DIV;
- case RemSInt64: return I64S_REM;
- case RemUInt64: return I64U_REM;
- case DivSInt64: return I64S_DIV;
- case DivUInt64: return I64U_DIV;
- default: return Name();
+ case RemSInt32:
+ return I32S_REM;
+ case RemUInt32:
+ return I32U_REM;
+ case DivSInt32:
+ return I32S_DIV;
+ case DivUInt32:
+ return I32U_DIV;
+ case RemSInt64:
+ return I64S_REM;
+ case RemUInt64:
+ return I64U_REM;
+ case DivSInt64:
+ return I64S_DIV;
+ case DivUInt64:
+ return I64U_DIV;
+ default:
+ return Name();
}
}
Name getUnaryFuncName(Unary* curr) {
switch (curr->op) {
- case TruncSFloat32ToInt32: return F32_TO_INT;
- case TruncUFloat32ToInt32: return F32_TO_UINT;
- case TruncSFloat32ToInt64: return F32_TO_INT64;
- case TruncUFloat32ToInt64: return F32_TO_UINT64;
- case TruncSFloat64ToInt32: return F64_TO_INT;
- case TruncUFloat64ToInt32: return F64_TO_UINT;
- case TruncSFloat64ToInt64: return F64_TO_INT64;
- case TruncUFloat64ToInt64: return F64_TO_UINT64;
- default: return Name();
+ case TruncSFloat32ToInt32:
+ return F32_TO_INT;
+ case TruncUFloat32ToInt32:
+ return F32_TO_UINT;
+ case TruncSFloat32ToInt64:
+ return F32_TO_INT64;
+ case TruncUFloat32ToInt64:
+ return F32_TO_UINT64;
+ case TruncSFloat64ToInt32:
+ return F64_TO_INT;
+ case TruncUFloat64ToInt32:
+ return F64_TO_UINT;
+ case TruncSFloat64ToInt64:
+ return F64_TO_INT64;
+ case TruncUFloat64ToInt64:
+ return F64_TO_UINT64;
+ default:
+ return Name();
}
}
bool isTruncOpSigned(UnaryOp op) {
switch (op) {
- case TruncUFloat32ToInt32:
- case TruncUFloat32ToInt64:
- case TruncUFloat64ToInt32:
- case TruncUFloat64ToInt64: return false;
- default: return true;
+ case TruncUFloat32ToInt32:
+ case TruncUFloat32ToInt64:
+ case TruncUFloat64ToInt32:
+ case TruncUFloat64ToInt64:
+ return false;
+ default:
+ return true;
}
}
-Function* generateBinaryFunc(Module& wasm, Binary *curr) {
+Function* generateBinaryFunc(Module& wasm, Binary* curr) {
BinaryOp op = curr->op;
Type type = curr->type;
bool isI64 = type == i64;
Builder builder(wasm);
- Expression* result = builder.makeBinary(op,
- builder.makeGetLocal(0, type),
- builder.makeGetLocal(1, type)
- );
+ Expression* result = builder.makeBinary(
+ op, builder.makeGetLocal(0, type), builder.makeGetLocal(1, type));
BinaryOp divSIntOp = isI64 ? DivSInt64 : DivSInt32;
UnaryOp eqZOp = isI64 ? EqZInt64 : EqZInt32;
Literal minLit = isI64 ? Literal(std::numeric_limits<int64_t>::min())
@@ -96,32 +114,24 @@ Function* generateBinaryFunc(Module& wasm, Binary *curr) {
BinaryOp eqOp = isI64 ? EqInt64 : EqInt32;
Literal negLit = isI64 ? Literal(int64_t(-1)) : Literal(int32_t(-1));
result = builder.makeIf(
- builder.makeBinary(AndInt32,
- builder.makeBinary(eqOp,
- builder.makeGetLocal(0, type),
- builder.makeConst(minLit)
- ),
- builder.makeBinary(eqOp,
- builder.makeGetLocal(1, type),
- builder.makeConst(negLit)
- )
- ),
+ builder.makeBinary(
+ AndInt32,
+ builder.makeBinary(
+ eqOp, builder.makeGetLocal(0, type), builder.makeConst(minLit)),
+ builder.makeBinary(
+ eqOp, builder.makeGetLocal(1, type), builder.makeConst(negLit))),
builder.makeConst(zeroLit),
- result
- );
+ result);
}
auto func = new Function;
func->name = getBinaryFuncName(curr);
func->params.push_back(type);
func->params.push_back(type);
func->result = type;
- func->body = builder.makeIf(
- builder.makeUnary(eqZOp,
- builder.makeGetLocal(1, type)
- ),
- builder.makeConst(zeroLit),
- result
- );
+ func->body =
+ builder.makeIf(builder.makeUnary(eqZOp, builder.makeGetLocal(1, type)),
+ builder.makeConst(zeroLit),
+ result);
return func;
}
@@ -134,7 +144,7 @@ void makeClampLimitLiterals(Literal& iMin, Literal& fMin, Literal& fMax) {
fMax = Literal(FloatType(maxVal) + 1);
}
-Function* generateUnaryFunc(Module& wasm, Unary *curr) {
+Function* generateUnaryFunc(Module& wasm, Unary* curr) {
Type type = curr->value->type;
Type retType = curr->type;
UnaryOp truncOp = curr->op;
@@ -148,59 +158,66 @@ Function* generateUnaryFunc(Module& wasm, Unary *curr) {
Literal iMin, fMin, fMax;
switch (truncOp) {
- case TruncSFloat32ToInt32: makeClampLimitLiterals< int32_t, float>(iMin, fMin, fMax); break;
- case TruncUFloat32ToInt32: makeClampLimitLiterals<uint32_t, float>(iMin, fMin, fMax); break;
- case TruncSFloat32ToInt64: makeClampLimitLiterals< int64_t, float>(iMin, fMin, fMax); break;
- case TruncUFloat32ToInt64: makeClampLimitLiterals<uint64_t, float>(iMin, fMin, fMax); break;
- case TruncSFloat64ToInt32: makeClampLimitLiterals< int32_t, double>(iMin, fMin, fMax); break;
- case TruncUFloat64ToInt32: makeClampLimitLiterals<uint32_t, double>(iMin, fMin, fMax); break;
- case TruncSFloat64ToInt64: makeClampLimitLiterals< int64_t, double>(iMin, fMin, fMax); break;
- case TruncUFloat64ToInt64: makeClampLimitLiterals<uint64_t, double>(iMin, fMin, fMax); break;
- default: WASM_UNREACHABLE();
+ case TruncSFloat32ToInt32:
+ makeClampLimitLiterals<int32_t, float>(iMin, fMin, fMax);
+ break;
+ case TruncUFloat32ToInt32:
+ makeClampLimitLiterals<uint32_t, float>(iMin, fMin, fMax);
+ break;
+ case TruncSFloat32ToInt64:
+ makeClampLimitLiterals<int64_t, float>(iMin, fMin, fMax);
+ break;
+ case TruncUFloat32ToInt64:
+ makeClampLimitLiterals<uint64_t, float>(iMin, fMin, fMax);
+ break;
+ case TruncSFloat64ToInt32:
+ makeClampLimitLiterals<int32_t, double>(iMin, fMin, fMax);
+ break;
+ case TruncUFloat64ToInt32:
+ makeClampLimitLiterals<uint32_t, double>(iMin, fMin, fMax);
+ break;
+ case TruncSFloat64ToInt64:
+ makeClampLimitLiterals<int64_t, double>(iMin, fMin, fMax);
+ break;
+ case TruncUFloat64ToInt64:
+ makeClampLimitLiterals<uint64_t, double>(iMin, fMin, fMax);
+ break;
+ default:
+ WASM_UNREACHABLE();
}
auto func = new Function;
func->name = getUnaryFuncName(curr);
func->params.push_back(type);
func->result = retType;
- func->body = builder.makeUnary(truncOp,
- builder.makeGetLocal(0, type)
- );
+ func->body = builder.makeUnary(truncOp, builder.makeGetLocal(0, type));
// too small XXX this is different than asm.js, which does frem. here we
// clamp, which is much simpler/faster, and similar to native builds
- func->body = builder.makeIf(
- builder.makeBinary(leOp,
- builder.makeGetLocal(0, type),
- builder.makeConst(fMin)
- ),
- builder.makeConst(iMin),
- func->body
- );
+ func->body = builder.makeIf(builder.makeBinary(leOp,
+ builder.makeGetLocal(0, type),
+ builder.makeConst(fMin)),
+ builder.makeConst(iMin),
+ func->body);
// too big XXX see above
func->body = builder.makeIf(
- builder.makeBinary(geOp,
- builder.makeGetLocal(0, type),
- builder.makeConst(fMax)
- ),
+ builder.makeBinary(
+ geOp, builder.makeGetLocal(0, type), builder.makeConst(fMax)),
// NB: min here as well. anything out of range => to the min
builder.makeConst(iMin),
- func->body
- );
+ func->body);
// nan
func->body = builder.makeIf(
- builder.makeBinary(neOp,
- builder.makeGetLocal(0, type),
- builder.makeGetLocal(0, type)
- ),
+ builder.makeBinary(
+ neOp, builder.makeGetLocal(0, type), builder.makeGetLocal(0, type)),
// NB: min here as well. anything invalid => to the min
builder.makeConst(iMin),
- func->body
- );
+ func->body);
return func;
}
-void ensureBinaryFunc(Binary* curr, Module& wasm,
- TrappingFunctionContainer &trappingFunctions) {
+void ensureBinaryFunc(Binary* curr,
+ Module& wasm,
+ TrappingFunctionContainer& trappingFunctions) {
Name name = getBinaryFuncName(curr);
if (trappingFunctions.hasFunction(name)) {
return;
@@ -208,8 +225,9 @@ void ensureBinaryFunc(Binary* curr, Module& wasm,
trappingFunctions.addFunction(generateBinaryFunc(wasm, curr));
}
-void ensureUnaryFunc(Unary *curr, Module& wasm,
- TrappingFunctionContainer &trappingFunctions) {
+void ensureUnaryFunc(Unary* curr,
+ Module& wasm,
+ TrappingFunctionContainer& trappingFunctions) {
Name name = getUnaryFuncName(curr);
if (trappingFunctions.hasFunction(name)) {
return;
@@ -217,7 +235,7 @@ void ensureUnaryFunc(Unary *curr, Module& wasm,
trappingFunctions.addFunction(generateUnaryFunc(wasm, curr));
}
-void ensureF64ToI64JSImport(TrappingFunctionContainer &trappingFunctions) {
+void ensureF64ToI64JSImport(TrappingFunctionContainer& trappingFunctions) {
if (trappingFunctions.hasImport(F64_TO_INT)) {
return;
}
@@ -233,7 +251,8 @@ void ensureF64ToI64JSImport(TrappingFunctionContainer &trappingFunctions) {
trappingFunctions.addImport(import);
}
-Expression* makeTrappingBinary(Binary* curr, TrappingFunctionContainer &trappingFunctions) {
+Expression* makeTrappingBinary(Binary* curr,
+ TrappingFunctionContainer& trappingFunctions) {
Name name = getBinaryFuncName(curr);
if (!name.is() || trappingFunctions.getMode() == TrapMode::Allow) {
return curr;
@@ -247,7 +266,8 @@ Expression* makeTrappingBinary(Binary* curr, TrappingFunctionContainer &trapping
return builder.makeCall(name, {curr->left, curr->right}, type);
}
-Expression* makeTrappingUnary(Unary* curr, TrappingFunctionContainer &trappingFunctions) {
+Expression* makeTrappingUnary(Unary* curr,
+ TrappingFunctionContainer& trappingFunctions) {
Name name = getUnaryFuncName(curr);
TrapMode mode = trappingFunctions.getMode();
if (!name.is() || mode == TrapMode::Allow) {
@@ -256,13 +276,15 @@ Expression* makeTrappingUnary(Unary* curr, TrappingFunctionContainer &trappingFu
Module& wasm = trappingFunctions.getModule();
Builder builder(wasm);
- // WebAssembly traps on float-to-int overflows, but asm.js wouldn't, so we must do something
- // We can handle this in one of two ways: clamping, which is fast, or JS, which
- // is precisely like JS but in order to do that we do a slow ffi
- // If i64, there is no "JS" way to handle this, as no i64s in JS, so always clamp if we don't allow traps
- // asm.js doesn't have unsigned f64-to-int, so just use the signed one.
+ // WebAssembly traps on float-to-int overflows, but asm.js wouldn't, so we
+ // must do something We can handle this in one of two ways: clamping, which is
+ // fast, or JS, which is precisely like JS but in order to do that we do a
+ // slow ffi If i64, there is no "JS" way to handle this, as no i64s in JS, so
+ // always clamp if we don't allow traps asm.js doesn't have unsigned
+ // f64-to-int, so just use the signed one.
if (curr->type != i64 && mode == TrapMode::JS) {
- // WebAssembly traps on float-to-int overflows, but asm.js wouldn't, so we must emulate that
+ // WebAssembly traps on float-to-int overflows, but asm.js wouldn't, so we
+ // must emulate that
ensureF64ToI64JSImport(trappingFunctions);
Expression* f64Value = ensureDouble(curr->value, wasm.allocator);
return builder.makeCall(F64_TO_INT, {f64Value}, i32);
@@ -274,14 +296,11 @@ Expression* makeTrappingUnary(Unary* curr, TrappingFunctionContainer &trappingFu
struct TrapModePass : public WalkerPass<PostWalker<TrapModePass>> {
public:
-
// Needs to be non-parallel so that visitModule gets called after visiting
// each node in the module, so we can add the functions that we created.
bool isFunctionParallel() override { return false; }
- TrapModePass(TrapMode mode) : mode(mode) {
- assert(mode != TrapMode::Allow);
- }
+ TrapModePass(TrapMode mode) : mode(mode) { assert(mode != TrapMode::Allow); }
Pass* create() override { return new TrapModePass(mode); }
@@ -293,9 +312,7 @@ public:
replaceCurrent(makeTrappingBinary(curr, *trappingFunctions));
}
- void visitModule(Module* curr) {
- trappingFunctions->addToModule();
- }
+ void visitModule(Module* curr) { trappingFunctions->addToModule(); }
void doWalkModule(Module* module) {
trappingFunctions = make_unique<TrappingFunctionContainer>(mode, *module);
@@ -309,12 +326,8 @@ private:
std::unique_ptr<TrappingFunctionContainer> trappingFunctions;
};
-Pass *createTrapModeClamp() {
- return new TrapModePass(TrapMode::Clamp);
-}
+Pass* createTrapModeClamp() { return new TrapModePass(TrapMode::Clamp); }
-Pass *createTrapModeJS() {
- return new TrapModePass(TrapMode::JS);
-}
+Pass* createTrapModeJS() { return new TrapModePass(TrapMode::JS); }
} // namespace wasm
diff --git a/src/passes/Untee.cpp b/src/passes/Untee.cpp
index 00f2ffe5d..713962aeb 100644
--- a/src/passes/Untee.cpp
+++ b/src/passes/Untee.cpp
@@ -22,9 +22,9 @@
// more effective.
//
-#include <wasm.h>
#include <pass.h>
#include <wasm-builder.h>
+#include <wasm.h>
namespace wasm {
@@ -33,7 +33,7 @@ struct Untee : public WalkerPass<PostWalker<Untee>> {
Pass* create() override { return new Untee; }
- void visitSetLocal(SetLocal *curr) {
+ void visitSetLocal(SetLocal* curr) {
if (curr->isTee()) {
if (curr->value->type == unreachable) {
// we don't reach the tee, just remove it
@@ -41,21 +41,14 @@ struct Untee : public WalkerPass<PostWalker<Untee>> {
} else {
// a normal tee. replace with set and get
Builder builder(*getModule());
- replaceCurrent(
- builder.makeSequence(
- curr,
- builder.makeGetLocal(curr->index, curr->value->type)
- )
- );
+ replaceCurrent(builder.makeSequence(
+ curr, builder.makeGetLocal(curr->index, curr->value->type)));
curr->setTee(false);
}
}
}
};
-Pass *createUnteePass() {
- return new Untee();
-}
+Pass* createUnteePass() { return new Untee(); }
} // namespace wasm
-
diff --git a/src/passes/Vacuum.cpp b/src/passes/Vacuum.cpp
index 08581a3eb..8874ffed2 100644
--- a/src/passes/Vacuum.cpp
+++ b/src/passes/Vacuum.cpp
@@ -18,14 +18,14 @@
// Removes obviously unneeded code
//
-#include <wasm.h>
-#include <pass.h>
-#include <wasm-builder.h>
#include <ir/block-utils.h>
#include <ir/effects.h>
#include <ir/literal-utils.h>
#include <ir/type-updating.h>
#include <ir/utils.h>
+#include <pass.h>
+#include <wasm-builder.h>
+#include <wasm.h>
namespace wasm {
@@ -49,15 +49,17 @@ struct Vacuum : public WalkerPass<ExpressionStackWalker<Vacuum>> {
walk(func->body);
}
- // Returns nullptr if curr is dead, curr if it must stay as is, or another node if it can be replaced.
- // Takes into account:
+ // Returns nullptr if curr is dead, curr if it must stay as is, or another
+ // node if it can be replaced. Takes into account:
// * The result may be used or unused.
// * The type may or may not matter (a drop can drop anything, for example).
Expression* optimize(Expression* curr, bool resultUsed, bool typeMatters) {
auto type = curr->type;
// An unreachable node must not be changed.
- if (type == unreachable) return curr;
- // We iterate on possible replacements. If a replacement changes the type, stop and go back.
+ if (type == unreachable)
+ return curr;
+ // We iterate on possible replacements. If a replacement changes the type,
+ // stop and go back.
auto* prev = curr;
while (1) {
if (typeMatters && curr->type != type) {
@@ -65,12 +67,17 @@ struct Vacuum : public WalkerPass<ExpressionStackWalker<Vacuum>> {
}
prev = curr;
switch (curr->_id) {
- case Expression::Id::NopId: return nullptr; // never needed
+ case Expression::Id::NopId:
+ return nullptr; // never needed
- case Expression::Id::BlockId: return curr; // not always needed, but handled in visitBlock()
- case Expression::Id::IfId: return curr; // not always needed, but handled in visitIf()
- case Expression::Id::LoopId: return curr; // not always needed, but handled in visitLoop()
- case Expression::Id::DropId: return curr; // not always needed, but handled in visitDrop()
+ case Expression::Id::BlockId:
+ return curr; // not always needed, but handled in visitBlock()
+ case Expression::Id::IfId:
+ return curr; // not always needed, but handled in visitIf()
+ case Expression::Id::LoopId:
+ return curr; // not always needed, but handled in visitLoop()
+ case Expression::Id::DropId:
+ return curr; // not always needed, but handled in visitDrop()
case Expression::Id::BreakId:
case Expression::Id::SwitchId:
@@ -81,12 +88,15 @@ struct Vacuum : public WalkerPass<ExpressionStackWalker<Vacuum>> {
case Expression::Id::ReturnId:
case Expression::Id::SetGlobalId:
case Expression::Id::HostId:
- case Expression::Id::UnreachableId: return curr; // always needed
+ case Expression::Id::UnreachableId:
+ return curr; // always needed
case Expression::Id::LoadId: {
// it is ok to remove a load if the result is not used, and it has no
- // side effects (the load itself may trap, if we are not ignoring such things)
- if (!resultUsed && !EffectAnalyzer(getPassOptions(), curr).hasSideEffects()) {
+ // side effects (the load itself may trap, if we are not ignoring such
+ // things)
+ if (!resultUsed &&
+ !EffectAnalyzer(getPassOptions(), curr).hasSideEffects()) {
return curr->cast<Load>()->ptr;
}
return curr;
@@ -94,7 +104,8 @@ struct Vacuum : public WalkerPass<ExpressionStackWalker<Vacuum>> {
case Expression::Id::ConstId:
case Expression::Id::GetLocalId:
case Expression::Id::GetGlobalId: {
- if (!resultUsed) return nullptr;
+ if (!resultUsed)
+ return nullptr;
return curr;
}
@@ -104,15 +115,17 @@ struct Vacuum : public WalkerPass<ExpressionStackWalker<Vacuum>> {
if (resultUsed) {
return curr; // used, keep it
}
- // for unary, binary, and select, we need to check their arguments for side effects,
- // as well as the node itself, as some unaries and binaries have implicit traps
+ // for unary, binary, and select, we need to check their arguments for
+ // side effects, as well as the node itself, as some unaries and
+ // binaries have implicit traps
if (auto* unary = curr->dynCast<Unary>()) {
EffectAnalyzer tester(getPassOptions());
tester.visitUnary(unary);
if (tester.hasSideEffects()) {
return curr;
}
- if (EffectAnalyzer(getPassOptions(), unary->value).hasSideEffects()) {
+ if (EffectAnalyzer(getPassOptions(), unary->value)
+ .hasSideEffects()) {
curr = unary->value;
continue;
} else {
@@ -124,15 +137,18 @@ struct Vacuum : public WalkerPass<ExpressionStackWalker<Vacuum>> {
if (tester.hasSideEffects()) {
return curr;
}
- if (EffectAnalyzer(getPassOptions(), binary->left).hasSideEffects()) {
- if (EffectAnalyzer(getPassOptions(), binary->right).hasSideEffects()) {
+ if (EffectAnalyzer(getPassOptions(), binary->left)
+ .hasSideEffects()) {
+ if (EffectAnalyzer(getPassOptions(), binary->right)
+ .hasSideEffects()) {
return curr; // leave them
} else {
curr = binary->left;
continue;
}
} else {
- if (EffectAnalyzer(getPassOptions(), binary->right).hasSideEffects()) {
+ if (EffectAnalyzer(getPassOptions(), binary->right)
+ .hasSideEffects()) {
curr = binary->right;
continue;
} else {
@@ -140,13 +156,17 @@ struct Vacuum : public WalkerPass<ExpressionStackWalker<Vacuum>> {
}
}
} else {
- // TODO: if two have side effects, we could replace the select with say an add?
+ // TODO: if two have side effects, we could replace the select with
+ // say an add?
auto* select = curr->cast<Select>();
- if (EffectAnalyzer(getPassOptions(), select->ifTrue).hasSideEffects()) {
- if (EffectAnalyzer(getPassOptions(), select->ifFalse).hasSideEffects()) {
+ if (EffectAnalyzer(getPassOptions(), select->ifTrue)
+ .hasSideEffects()) {
+ if (EffectAnalyzer(getPassOptions(), select->ifFalse)
+ .hasSideEffects()) {
return curr; // leave them
} else {
- if (EffectAnalyzer(getPassOptions(), select->condition).hasSideEffects()) {
+ if (EffectAnalyzer(getPassOptions(), select->condition)
+ .hasSideEffects()) {
return curr; // leave them
} else {
curr = select->ifTrue;
@@ -154,15 +174,18 @@ struct Vacuum : public WalkerPass<ExpressionStackWalker<Vacuum>> {
}
}
} else {
- if (EffectAnalyzer(getPassOptions(), select->ifFalse).hasSideEffects()) {
- if (EffectAnalyzer(getPassOptions(), select->condition).hasSideEffects()) {
+ if (EffectAnalyzer(getPassOptions(), select->ifFalse)
+ .hasSideEffects()) {
+ if (EffectAnalyzer(getPassOptions(), select->condition)
+ .hasSideEffects()) {
return curr; // leave them
} else {
curr = select->ifFalse;
continue;
}
} else {
- if (EffectAnalyzer(getPassOptions(), select->condition).hasSideEffects()) {
+ if (EffectAnalyzer(getPassOptions(), select->condition)
+ .hasSideEffects()) {
curr = select->condition;
continue;
} else {
@@ -173,12 +196,13 @@ struct Vacuum : public WalkerPass<ExpressionStackWalker<Vacuum>> {
}
}
- default: return curr; // assume needed
+ default:
+ return curr; // assume needed
}
}
}
- void visitBlock(Block *curr) {
+ void visitBlock(Block* curr) {
// compress out nops and other dead code
int skip = 0;
auto& list = curr->list;
@@ -186,18 +210,20 @@ struct Vacuum : public WalkerPass<ExpressionStackWalker<Vacuum>> {
for (size_t z = 0; z < size; z++) {
auto* child = list[z];
// The last element may be used.
- bool used = z == size - 1 &&
- isConcreteType(curr->type) &&
- ExpressionAnalyzer::isResultUsed(expressionStack, getFunction());
+ bool used =
+ z == size - 1 && isConcreteType(curr->type) &&
+ ExpressionAnalyzer::isResultUsed(expressionStack, getFunction());
auto* optimized = optimize(child, used, true);
if (!optimized) {
if (isConcreteType(child->type)) {
- // We can't just skip a final concrete element, even if it isn't used. Instead,
- // replace it with something that's easy to optimize out (for example, code-folding
- // can merge out identical zeros at the end of if arms).
+ // We can't just skip a final concrete element, even if it isn't used.
+ // Instead, replace it with something that's easy to optimize out (for
+ // example, code-folding can merge out identical zeros at the end of
+ // if arms).
optimized = LiteralUtils::makeZero(child->type, *getModule());
} else if (child->type == unreachable) {
- // Don't try to optimize out an unreachable child (dce can do that properly).
+ // Don't try to optimize out an unreachable child (dce can do that
+ // properly).
optimized = child;
}
}
@@ -232,7 +258,8 @@ struct Vacuum : public WalkerPass<ExpressionStackWalker<Vacuum>> {
list.resize(size - skip);
typeUpdater.maybeUpdateTypeToUnreachable(curr);
}
- // the block may now be a trivial one that we can get rid of and just leave its contents
+ // the block may now be a trivial one that we can get rid of and just leave
+ // its contents
replaceCurrent(BlockUtils::simplifyToContents(curr, this));
}
@@ -275,9 +302,11 @@ struct Vacuum : public WalkerPass<ExpressionStackWalker<Vacuum>> {
} else if (curr->ifTrue->is<Nop>()) {
curr->ifTrue = curr->ifFalse;
curr->ifFalse = nullptr;
- curr->condition = Builder(*getModule()).makeUnary(EqZInt32, curr->condition);
+ curr->condition =
+ Builder(*getModule()).makeUnary(EqZInt32, curr->condition);
} else if (curr->ifTrue->is<Drop>() && curr->ifFalse->is<Drop>()) {
- // instead of dropping both sides, drop the if, if they are the same type
+ // instead of dropping both sides, drop the if, if they are the same
+ // type
auto* left = curr->ifTrue->cast<Drop>()->value;
auto* right = curr->ifFalse->cast<Drop>()->value;
if (left->type == right->type) {
@@ -297,7 +326,8 @@ struct Vacuum : public WalkerPass<ExpressionStackWalker<Vacuum>> {
}
void visitLoop(Loop* curr) {
- if (curr->body->is<Nop>()) ExpressionManipulator::nop(curr);
+ if (curr->body->is<Nop>())
+ ExpressionManipulator::nop(curr);
}
void visitDrop(Drop* curr) {
@@ -314,12 +344,13 @@ struct Vacuum : public WalkerPass<ExpressionStackWalker<Vacuum>> {
replaceCurrent(set);
return;
}
- // if we are dropping a block's return value, we might be able to remove it entirely
+ // if we are dropping a block's return value, we might be able to remove it
+ // entirely
if (auto* block = curr->value->dynCast<Block>()) {
auto* last = block->list.back();
// note that the last element may be concrete but not the block, if the
- // block has an unreachable element in the middle, making the block unreachable
- // despite later elements and in particular the last
+ // block has an unreachable element in the middle, making the block
+ // unreachable despite later elements and in particular the last
if (isConcreteType(last->type) && block->type == last->type) {
last = optimize(last, false, false);
if (!last) {
@@ -338,7 +369,8 @@ struct Vacuum : public WalkerPass<ExpressionStackWalker<Vacuum>> {
block->list.back() = last;
block->list.pop_back();
block->type = none;
- // we don't need the drop anymore, let's see what we have left in the block
+ // we don't need the drop anymore, let's see what we have left in
+ // the block
if (block->list.size() > 1) {
replaceCurrent(block);
} else if (block->list.size() == 1) {
@@ -351,16 +383,20 @@ struct Vacuum : public WalkerPass<ExpressionStackWalker<Vacuum>> {
}
}
}
- // sink a drop into an arm of an if-else if the other arm ends in an unreachable, as it if is a branch, this can make that branch optimizable and more vaccuming possible
+ // sink a drop into an arm of an if-else if the other arm ends in an
+ // unreachable, as it if is a branch, this can make that branch optimizable
+ // and more vaccuming possible
auto* iff = curr->value->dynCast<If>();
if (iff && iff->ifFalse && isConcreteType(iff->type)) {
// reuse the drop in both cases
- if (iff->ifTrue->type == unreachable && isConcreteType(iff->ifFalse->type)) {
+ if (iff->ifTrue->type == unreachable &&
+ isConcreteType(iff->ifFalse->type)) {
curr->value = iff->ifFalse;
iff->ifFalse = curr;
iff->type = none;
replaceCurrent(iff);
- } else if (iff->ifFalse->type == unreachable && isConcreteType(iff->ifTrue->type)) {
+ } else if (iff->ifFalse->type == unreachable &&
+ isConcreteType(iff->ifTrue->type)) {
curr->value = iff->ifTrue;
iff->ifTrue = curr;
iff->type = none;
@@ -376,15 +412,13 @@ struct Vacuum : public WalkerPass<ExpressionStackWalker<Vacuum>> {
} else {
ExpressionManipulator::nop(curr->body);
}
- if (curr->result == none && !EffectAnalyzer(getPassOptions(), curr->body).hasSideEffects()) {
+ if (curr->result == none &&
+ !EffectAnalyzer(getPassOptions(), curr->body).hasSideEffects()) {
ExpressionManipulator::nop(curr->body);
}
}
};
-Pass *createVacuumPass() {
- return new Vacuum();
-}
+Pass* createVacuumPass() { return new Vacuum(); }
} // namespace wasm
-
diff --git a/src/passes/intrinsics-module.h b/src/passes/intrinsics-module.h
index c9a757dc0..e7f7a3a6e 100644
--- a/src/passes/intrinsics-module.h
+++ b/src/passes/intrinsics-module.h
@@ -24,4 +24,3 @@ extern const char* IntrinsicsModuleWast;
} // namespace wasm
#endif // passes_intrinsics_module_h
-
diff --git a/src/passes/opt-utils.h b/src/passes/opt-utils.h
index a880e2623..9ac6da4a2 100644
--- a/src/passes/opt-utils.h
+++ b/src/passes/opt-utils.h
@@ -19,8 +19,8 @@
#include <unordered_set>
-#include <wasm.h>
#include <pass.h>
+#include <wasm.h>
namespace wasm {
@@ -28,7 +28,9 @@ namespace OptUtils {
// Run useful optimizations after inlining new code into a set
// of functions.
-inline void optimizeAfterInlining(std::unordered_set<Function*>& funcs, Module* module, PassRunner* parentRunner) {
+inline void optimizeAfterInlining(std::unordered_set<Function*>& funcs,
+ Module* module,
+ PassRunner* parentRunner) {
// save the full list of functions on the side
std::vector<std::unique_ptr<Function>> all;
all.swap(module->functions);
@@ -39,7 +41,8 @@ inline void optimizeAfterInlining(std::unordered_set<Function*>& funcs, Module*
PassRunner runner(module, parentRunner->options);
runner.setIsNested(true);
runner.setValidateGlobally(false); // not a full valid module
- runner.add("precompute-propagate"); // this is especially useful after inlining
+ // this is especially useful after inlining
+ runner.add("precompute-propagate");
runner.addDefaultFunctionOptimizationPasses(); // do all the usual stuff
runner.run();
// restore all the funcs
diff --git a/src/passes/pass.cpp b/src/passes/pass.cpp
index 41d2026bc..ae940a56d 100644
--- a/src/passes/pass.cpp
+++ b/src/passes/pass.cpp
@@ -17,35 +17,34 @@
#include <chrono>
#include <sstream>
-#include "support/colors.h"
-#include "passes/passes.h"
-#include "pass.h"
-#include "wasm-validator.h"
-#include "wasm-io.h"
#include "ir/hashed.h"
#include "ir/module-utils.h"
+#include "pass.h"
+#include "passes/passes.h"
+#include "support/colors.h"
+#include "wasm-io.h"
+#include "wasm-validator.h"
namespace wasm {
// PassRegistry
-PassRegistry::PassRegistry() {
- registerPasses();
-}
+PassRegistry::PassRegistry() { registerPasses(); }
static PassRegistry singleton;
-PassRegistry* PassRegistry::get() {
- return &singleton;
-}
+PassRegistry* PassRegistry::get() { return &singleton; }
-void PassRegistry::registerPass(const char* name, const char *description, Creator create) {
+void PassRegistry::registerPass(const char* name,
+ const char* description,
+ Creator create) {
assert(passInfos.find(name) == passInfos.end());
passInfos[name] = PassInfo(description, create);
}
Pass* PassRegistry::createPass(std::string name) {
- if (passInfos.find(name) == passInfos.end()) return nullptr;
+ if (passInfos.find(name) == passInfos.end())
+ return nullptr;
auto ret = passInfos[name].create();
ret->name = name;
return ret;
@@ -67,87 +66,234 @@ std::string PassRegistry::getPassDescription(std::string name) {
// PassRunner
void PassRegistry::registerPasses() {
- registerPass("dae", "removes arguments to calls in an lto-like manner", createDAEPass);
- registerPass("dae-optimizing", "removes arguments to calls in an lto-like manner, and optimizes where we removed", createDAEOptimizingPass);
- registerPass("coalesce-locals", "reduce # of locals by coalescing", createCoalesceLocalsPass);
- registerPass("coalesce-locals-learning", "reduce # of locals by coalescing and learning", createCoalesceLocalsWithLearningPass);
- registerPass("code-pushing", "push code forward, potentially making it not always execute", createCodePushingPass);
- registerPass("code-folding", "fold code, merging duplicates", createCodeFoldingPass);
- registerPass("const-hoisting", "hoist repeated constants to a local", createConstHoistingPass);
- registerPass("dce", "removes unreachable code", createDeadCodeEliminationPass);
- registerPass("directize", "turns indirect calls into direct ones", createDirectizePass);
- registerPass("dfo", "optimizes using the DataFlow SSA IR", createDataFlowOptsPass);
- registerPass("duplicate-function-elimination", "removes duplicate functions", createDuplicateFunctionEliminationPass);
- registerPass("extract-function", "leaves just one function (useful for debugging)", createExtractFunctionPass);
- registerPass("flatten", "flattens out code, removing nesting", createFlattenPass);
- registerPass("fpcast-emu", "emulates function pointer casts, allowing incorrect indirect calls to (sometimes) work", createFuncCastEmulationPass);
- registerPass("func-metrics", "reports function metrics", createFunctionMetricsPass);
- registerPass("generate-stack-ir", "generate Stack IR", createGenerateStackIRPass);
- registerPass("inlining", "inline functions (you probably want inlining-optimizing)", createInliningPass);
- registerPass("inlining-optimizing", "inline functions and optimizes where we inlined", createInliningOptimizingPass);
- registerPass("legalize-js-interface", "legalizes i64 types on the import/export boundary", createLegalizeJSInterfacePass);
- registerPass("legalize-js-interface-minimally", "legalizes i64 types on the import/export boundary in a minimal manner, only on things only JS will call", createLegalizeJSInterfaceMinimallyPass);
- registerPass("local-cse", "common subexpression elimination inside basic blocks", createLocalCSEPass);
- registerPass("log-execution", "instrument the build with logging of where execution goes", createLogExecutionPass);
- registerPass("i64-to-i32-lowering", "lower all uses of i64s to use i32s instead", createI64ToI32LoweringPass);
- registerPass("instrument-locals", "instrument the build with code to intercept all loads and stores", createInstrumentLocalsPass);
- registerPass("instrument-memory", "instrument the build with code to intercept all loads and stores", createInstrumentMemoryPass);
- registerPass("licm", "loop invariant code motion", createLoopInvariantCodeMotionPass);
- registerPass("limit-segments", "attempt to merge segments to fit within web limits", createLimitSegmentsPass);
- registerPass("memory-packing", "packs memory into separate segments, skipping zeros", createMemoryPackingPass);
- registerPass("merge-blocks", "merges blocks to their parents", createMergeBlocksPass);
- registerPass("merge-locals", "merges locals when beneficial", createMergeLocalsPass);
+ registerPass(
+ "dae", "removes arguments to calls in an lto-like manner", createDAEPass);
+ registerPass("dae-optimizing",
+ "removes arguments to calls in an lto-like manner, and "
+ "optimizes where we removed",
+ createDAEOptimizingPass);
+ registerPass("coalesce-locals",
+ "reduce # of locals by coalescing",
+ createCoalesceLocalsPass);
+ registerPass("coalesce-locals-learning",
+ "reduce # of locals by coalescing and learning",
+ createCoalesceLocalsWithLearningPass);
+ registerPass("code-pushing",
+ "push code forward, potentially making it not always execute",
+ createCodePushingPass);
+ registerPass(
+ "code-folding", "fold code, merging duplicates", createCodeFoldingPass);
+ registerPass("const-hoisting",
+ "hoist repeated constants to a local",
+ createConstHoistingPass);
+ registerPass(
+ "dce", "removes unreachable code", createDeadCodeEliminationPass);
+ registerPass(
+ "directize", "turns indirect calls into direct ones", createDirectizePass);
+ registerPass(
+ "dfo", "optimizes using the DataFlow SSA IR", createDataFlowOptsPass);
+ registerPass("duplicate-function-elimination",
+ "removes duplicate functions",
+ createDuplicateFunctionEliminationPass);
+ registerPass("extract-function",
+ "leaves just one function (useful for debugging)",
+ createExtractFunctionPass);
+ registerPass(
+ "flatten", "flattens out code, removing nesting", createFlattenPass);
+ registerPass("fpcast-emu",
+ "emulates function pointer casts, allowing incorrect indirect "
+ "calls to (sometimes) work",
+ createFuncCastEmulationPass);
+ registerPass(
+ "func-metrics", "reports function metrics", createFunctionMetricsPass);
+ registerPass(
+ "generate-stack-ir", "generate Stack IR", createGenerateStackIRPass);
+ registerPass("inlining",
+ "inline functions (you probably want inlining-optimizing)",
+ createInliningPass);
+ registerPass("inlining-optimizing",
+ "inline functions and optimizes where we inlined",
+ createInliningOptimizingPass);
+ registerPass("legalize-js-interface",
+ "legalizes i64 types on the import/export boundary",
+ createLegalizeJSInterfacePass);
+ registerPass("legalize-js-interface-minimally",
+ "legalizes i64 types on the import/export boundary in a minimal "
+ "manner, only on things only JS will call",
+ createLegalizeJSInterfaceMinimallyPass);
+ registerPass("local-cse",
+ "common subexpression elimination inside basic blocks",
+ createLocalCSEPass);
+ registerPass("log-execution",
+ "instrument the build with logging of where execution goes",
+ createLogExecutionPass);
+ registerPass("i64-to-i32-lowering",
+ "lower all uses of i64s to use i32s instead",
+ createI64ToI32LoweringPass);
+ registerPass(
+ "instrument-locals",
+ "instrument the build with code to intercept all loads and stores",
+ createInstrumentLocalsPass);
+ registerPass(
+ "instrument-memory",
+ "instrument the build with code to intercept all loads and stores",
+ createInstrumentMemoryPass);
+ registerPass(
+ "licm", "loop invariant code motion", createLoopInvariantCodeMotionPass);
+ registerPass("limit-segments",
+ "attempt to merge segments to fit within web limits",
+ createLimitSegmentsPass);
+ registerPass("memory-packing",
+ "packs memory into separate segments, skipping zeros",
+ createMemoryPackingPass);
+ registerPass(
+ "merge-blocks", "merges blocks to their parents", createMergeBlocksPass);
+ registerPass(
+ "merge-locals", "merges locals when beneficial", createMergeLocalsPass);
registerPass("metrics", "reports metrics", createMetricsPass);
- registerPass("minify-imports", "minifies import names (only those, and not export names), and emits a mapping to the minified ones", createMinifyImportsPass);
- registerPass("minify-imports-and-exports", "minifies both import and export names, and emits a mapping to the minified ones", createMinifyImportsAndExportsPass);
+ registerPass("minify-imports",
+ "minifies import names (only those, and not export names), and "
+ "emits a mapping to the minified ones",
+ createMinifyImportsPass);
+ registerPass("minify-imports-and-exports",
+ "minifies both import and export names, and emits a mapping to "
+ "the minified ones",
+ createMinifyImportsAndExportsPass);
registerPass("nm", "name list", createNameListPass);
- registerPass("no-exit-runtime", "removes calls to atexit(), which is valid if the C runtime will never be exited", createNoExitRuntimePass);
- registerPass("optimize-added-constants", "optimizes added constants into load/store offsets", createOptimizeAddedConstantsPass);
- registerPass("optimize-added-constants-propagate", "optimizes added constants into load/store offsets, propagating them across locals too", createOptimizeAddedConstantsPropagatePass);
- registerPass("optimize-instructions", "optimizes instruction combinations", createOptimizeInstructionsPass);
- registerPass("optimize-stack-ir", "optimize Stack IR", createOptimizeStackIRPass);
- registerPass("pick-load-signs", "pick load signs based on their uses", createPickLoadSignsPass);
- registerPass("post-emscripten", "miscellaneous optimizations for Emscripten-generated code", createPostEmscriptenPass);
- registerPass("precompute", "computes compile-time evaluatable expressions", createPrecomputePass);
- registerPass("precompute-propagate", "computes compile-time evaluatable expressions and propagates them through locals", createPrecomputePropagatePass);
+ registerPass("no-exit-runtime",
+ "removes calls to atexit(), which is valid if the C runtime "
+ "will never be exited",
+ createNoExitRuntimePass);
+ registerPass("optimize-added-constants",
+ "optimizes added constants into load/store offsets",
+ createOptimizeAddedConstantsPass);
+ registerPass("optimize-added-constants-propagate",
+ "optimizes added constants into load/store offsets, propagating "
+ "them across locals too",
+ createOptimizeAddedConstantsPropagatePass);
+ registerPass("optimize-instructions",
+ "optimizes instruction combinations",
+ createOptimizeInstructionsPass);
+ registerPass(
+ "optimize-stack-ir", "optimize Stack IR", createOptimizeStackIRPass);
+ registerPass("pick-load-signs",
+ "pick load signs based on their uses",
+ createPickLoadSignsPass);
+ registerPass("post-emscripten",
+ "miscellaneous optimizations for Emscripten-generated code",
+ createPostEmscriptenPass);
+ registerPass("precompute",
+ "computes compile-time evaluatable expressions",
+ createPrecomputePass);
+ registerPass("precompute-propagate",
+ "computes compile-time evaluatable expressions and propagates "
+ "them through locals",
+ createPrecomputePropagatePass);
registerPass("print", "print in s-expression format", createPrinterPass);
- registerPass("print-minified", "print in minified s-expression format", createMinifiedPrinterPass);
- registerPass("print-features", "print options for enabled features", createPrintFeaturesPass);
- registerPass("print-full", "print in full s-expression format", createFullPrinterPass);
- registerPass("print-call-graph", "print call graph", createPrintCallGraphPass);
- registerPass("print-stack-ir", "print out Stack IR (useful for internal debugging)", createPrintStackIRPass);
- registerPass("relooper-jump-threading", "thread relooper jumps (fastcomp output only)", createRelooperJumpThreadingPass);
- registerPass("remove-non-js-ops", "removes operations incompatible with js", createRemoveNonJSOpsPass);
- registerPass("remove-imports", "removes imports and replaces them with nops", createRemoveImportsPass);
- registerPass("remove-memory", "removes memory segments", createRemoveMemoryPass);
- registerPass("remove-unused-brs", "removes breaks from locations that are not needed", createRemoveUnusedBrsPass);
- registerPass("remove-unused-module-elements", "removes unused module elements", createRemoveUnusedModuleElementsPass);
- registerPass("remove-unused-nonfunction-module-elements", "removes unused module elements that are not functions", createRemoveUnusedNonFunctionModuleElementsPass);
- registerPass("remove-unused-names", "removes names from locations that are never branched to", createRemoveUnusedNamesPass);
- registerPass("reorder-functions", "sorts functions by access frequency", createReorderFunctionsPass);
- registerPass("reorder-locals", "sorts locals by access frequency", createReorderLocalsPass);
- registerPass("rereloop", "re-optimize control flow using the relooper algorithm", createReReloopPass);
- registerPass("rse", "remove redundant local.sets", createRedundantSetEliminationPass);
- registerPass("safe-heap", "instrument loads and stores to check for invalid behavior", createSafeHeapPass);
- registerPass("simplify-locals", "miscellaneous locals-related optimizations", createSimplifyLocalsPass);
- registerPass("simplify-locals-nonesting", "miscellaneous locals-related optimizations (no nesting at all; preserves flatness)", createSimplifyLocalsNoNestingPass);
- registerPass("simplify-locals-notee", "miscellaneous locals-related optimizations (no tees)", createSimplifyLocalsNoTeePass);
- registerPass("simplify-locals-nostructure", "miscellaneous locals-related optimizations (no structure)", createSimplifyLocalsNoStructurePass);
- registerPass("simplify-locals-notee-nostructure", "miscellaneous locals-related optimizations (no tees or structure)", createSimplifyLocalsNoTeeNoStructurePass);
+ registerPass("print-minified",
+ "print in minified s-expression format",
+ createMinifiedPrinterPass);
+ registerPass("print-features",
+ "print options for enabled features",
+ createPrintFeaturesPass);
+ registerPass(
+ "print-full", "print in full s-expression format", createFullPrinterPass);
+ registerPass(
+ "print-call-graph", "print call graph", createPrintCallGraphPass);
+ registerPass("print-stack-ir",
+ "print out Stack IR (useful for internal debugging)",
+ createPrintStackIRPass);
+ registerPass("relooper-jump-threading",
+ "thread relooper jumps (fastcomp output only)",
+ createRelooperJumpThreadingPass);
+ registerPass("remove-non-js-ops",
+ "removes operations incompatible with js",
+ createRemoveNonJSOpsPass);
+ registerPass("remove-imports",
+ "removes imports and replaces them with nops",
+ createRemoveImportsPass);
+ registerPass(
+ "remove-memory", "removes memory segments", createRemoveMemoryPass);
+ registerPass("remove-unused-brs",
+ "removes breaks from locations that are not needed",
+ createRemoveUnusedBrsPass);
+ registerPass("remove-unused-module-elements",
+ "removes unused module elements",
+ createRemoveUnusedModuleElementsPass);
+ registerPass("remove-unused-nonfunction-module-elements",
+ "removes unused module elements that are not functions",
+ createRemoveUnusedNonFunctionModuleElementsPass);
+ registerPass("remove-unused-names",
+ "removes names from locations that are never branched to",
+ createRemoveUnusedNamesPass);
+ registerPass("reorder-functions",
+ "sorts functions by access frequency",
+ createReorderFunctionsPass);
+ registerPass("reorder-locals",
+ "sorts locals by access frequency",
+ createReorderLocalsPass);
+ registerPass("rereloop",
+ "re-optimize control flow using the relooper algorithm",
+ createReReloopPass);
+ registerPass(
+ "rse", "remove redundant local.sets", createRedundantSetEliminationPass);
+ registerPass("safe-heap",
+ "instrument loads and stores to check for invalid behavior",
+ createSafeHeapPass);
+ registerPass("simplify-locals",
+ "miscellaneous locals-related optimizations",
+ createSimplifyLocalsPass);
+ registerPass("simplify-locals-nonesting",
+ "miscellaneous locals-related optimizations (no nesting at all; "
+ "preserves flatness)",
+ createSimplifyLocalsNoNestingPass);
+ registerPass("simplify-locals-notee",
+ "miscellaneous locals-related optimizations (no tees)",
+ createSimplifyLocalsNoTeePass);
+ registerPass("simplify-locals-nostructure",
+ "miscellaneous locals-related optimizations (no structure)",
+ createSimplifyLocalsNoStructurePass);
+ registerPass(
+ "simplify-locals-notee-nostructure",
+ "miscellaneous locals-related optimizations (no tees or structure)",
+ createSimplifyLocalsNoTeeNoStructurePass);
registerPass("souperify", "emit Souper IR in text form", createSouperifyPass);
- registerPass("souperify-single-use", "emit Souper IR in text form (single-use nodes only)", createSouperifySingleUsePass);
- registerPass("spill-pointers", "spill pointers to the C stack (useful for Boehm-style GC)", createSpillPointersPass);
- registerPass("ssa", "ssa-ify variables so that they have a single assignment", createSSAifyPass);
- registerPass("ssa-nomerge", "ssa-ify variables so that they have a single assignment, ignoring merges", createSSAifyNoMergePass);
- registerPass("strip", "deprecated; same as strip-debug", createStripDebugPass);
- registerPass("strip-debug", "strip debug info (including the names section)", createStripDebugPass);
- registerPass("strip-producers", "strip the wasm producers section", createStripProducersPass);
- registerPass("strip-target-features", "strip the wasm target features section", createStripTargetFeaturesPass);
- registerPass("trap-mode-clamp", "replace trapping operations with clamping semantics", createTrapModeClamp);
- registerPass("trap-mode-js", "replace trapping operations with js semantics", createTrapModeJS);
- registerPass("untee", "removes local.tees, replacing them with sets and gets", createUnteePass);
+ registerPass("souperify-single-use",
+ "emit Souper IR in text form (single-use nodes only)",
+ createSouperifySingleUsePass);
+ registerPass("spill-pointers",
+ "spill pointers to the C stack (useful for Boehm-style GC)",
+ createSpillPointersPass);
+ registerPass("ssa",
+ "ssa-ify variables so that they have a single assignment",
+ createSSAifyPass);
+ registerPass(
+ "ssa-nomerge",
+ "ssa-ify variables so that they have a single assignment, ignoring merges",
+ createSSAifyNoMergePass);
+ registerPass(
+ "strip", "deprecated; same as strip-debug", createStripDebugPass);
+ registerPass("strip-debug",
+ "strip debug info (including the names section)",
+ createStripDebugPass);
+ registerPass("strip-producers",
+ "strip the wasm producers section",
+ createStripProducersPass);
+ registerPass("strip-target-features",
+ "strip the wasm target features section",
+ createStripTargetFeaturesPass);
+ registerPass("trap-mode-clamp",
+ "replace trapping operations with clamping semantics",
+ createTrapModeClamp);
+ registerPass("trap-mode-js",
+ "replace trapping operations with js semantics",
+ createTrapModeJS);
+ registerPass("untee",
+ "removes local.tees, replacing them with sets and gets",
+ createUnteePass);
registerPass("vacuum", "removes obviously unneeded code", createVacuumPass);
-// registerPass("lower-i64", "lowers i64 into pairs of i32s", createLowerInt64Pass);
+ // registerPass(
+ // "lower-i64", "lowers i64 into pairs of i32s", createLowerInt64Pass);
}
void PassRunner::addDefaultOptimizationPasses() {
@@ -191,10 +337,13 @@ void PassRunner::addDefaultFunctionOptimizationPasses() {
if (options.optimizeLevel >= 2 || options.shrinkLevel >= 2) {
add("code-pushing");
}
- add("simplify-locals-nostructure"); // don't create if/block return values yet, as coalesce can remove copies that that could inhibit
+ // don't create if/block return values yet, as coalesce can remove copies that
+ // that could inhibit
+ add("simplify-locals-nostructure");
add("vacuum"); // previous pass creates garbage
add("reorder-locals");
- add("remove-unused-brs"); // simplify-locals opens opportunities for optimizations
+ // simplify-locals opens opportunities for optimizations
+ add("remove-unused-brs");
// if we are willing to work hard, also optimize copies before coalescing
if (options.optimizeLevel >= 3 || options.shrinkLevel >= 2) {
add("merge-locals"); // very slow on e.g. sqlite
@@ -209,10 +358,10 @@ void PassRunner::addDefaultFunctionOptimizationPasses() {
if (options.optimizeLevel >= 3 || options.shrinkLevel >= 1) {
add("code-folding");
}
- add("merge-blocks"); // makes remove-unused-brs more effective
- add("remove-unused-brs"); // coalesce-locals opens opportunities
+ add("merge-blocks"); // makes remove-unused-brs more effective
+ add("remove-unused-brs"); // coalesce-locals opens opportunities
add("remove-unused-names"); // remove-unused-brs opens opportunities
- add("merge-blocks"); // clean up remove-unused-brs new blocks
+ add("merge-blocks"); // clean up remove-unused-brs new blocks
// late propagation
if (options.optimizeLevel >= 3 || options.shrinkLevel >= 2) {
add("precompute-propagate");
@@ -237,10 +386,12 @@ void PassRunner::addDefaultGlobalOptimizationPostPasses() {
if (options.optimizeLevel >= 2 || options.shrinkLevel >= 2) {
add("inlining-optimizing");
}
- add("duplicate-function-elimination"); // optimizations show more functions as duplicate
+ // optimizations show more functions as duplicate
+ add("duplicate-function-elimination");
add("remove-unused-module-elements");
add("memory-packing");
- add("directize"); // may allow more inlining/dae/etc., need --converge for that
+ // may allow more inlining/dae/etc., need --converge for that
+ add("directize");
// perform Stack IR optimizations here, at the very end of the
// optimization pipeline
if (options.optimizeLevel >= 2 || options.shrinkLevel >= 1) {
@@ -266,7 +417,8 @@ static void dumpWast(Name name, Module* wasm) {
void PassRunner::run() {
static const int passDebug = getPassDebug();
if (!isNested && (options.debug || passDebug)) {
- // for debug logging purposes, run each pass in full before running the other
+ // for debug logging purposes, run each pass in full before running the
+ // other
auto totalTime = std::chrono::duration<double>(0);
size_t padding = 0;
WasmValidator::Flags validationFlags = WasmValidator::Minimal;
@@ -281,7 +433,8 @@ void PassRunner::run() {
dumpWast("before", wasm);
}
for (auto* pass : passes) {
- // ignoring the time, save a printout of the module before, in case this pass breaks it, so we can print the before and after
+ // ignoring the time, save a printout of the module before, in case this
+ // pass breaks it, so we can print the before and after
std::stringstream moduleBefore;
if (passDebug == 2) {
WasmPrinter::printModule(wasm, moduleBefore);
@@ -294,9 +447,8 @@ void PassRunner::run() {
auto before = std::chrono::steady_clock::now();
if (pass->isFunctionParallel()) {
// function-parallel passes should get a new instance per function
- ModuleUtils::iterDefinedFunctions(*wasm, [&](Function* func) {
- runPassOnFunction(pass, func);
- });
+ ModuleUtils::iterDefinedFunctions(
+ *wasm, [&](Function* func) { runPassOnFunction(pass, func); });
} else {
runPass(pass);
}
@@ -310,9 +462,14 @@ void PassRunner::run() {
if (!WasmValidator().validate(*wasm, validationFlags)) {
WasmPrinter::printModule(wasm);
if (passDebug >= 2) {
- std::cerr << "Last pass (" << pass->name << ") broke validation. Here is the module before: \n" << moduleBefore.str() << "\n";
+ std::cerr << "Last pass (" << pass->name
+ << ") broke validation. Here is the module before: \n"
+ << moduleBefore.str() << "\n";
} else {
- std::cerr << "Last pass (" << pass->name << ") broke validation. Run with BINARYEN_PASS_DEBUG=2 in the env to see the earlier state, or 3 to dump byn-* files for each pass\n";
+ std::cerr << "Last pass (" << pass->name
+ << ") broke validation. Run with BINARYEN_PASS_DEBUG=2 "
+ "in the env to see the earlier state, or 3 to dump "
+ "byn-* files for each pass\n";
}
abort();
}
@@ -321,7 +478,8 @@ void PassRunner::run() {
dumpWast(pass->name, wasm);
}
}
- std::cerr << "[PassRunner] passes took " << totalTime.count() << " seconds." << std::endl;
+ std::cerr << "[PassRunner] passes took " << totalTime.count() << " seconds."
+ << std::endl;
if (options.validate) {
std::cerr << "[PassRunner] (final validation)\n";
if (!WasmValidator().validate(*wasm, validationFlags)) {
@@ -331,14 +489,15 @@ void PassRunner::run() {
}
}
} else {
- // non-debug normal mode, run them in an optimal manner - for locality it is better
- // to run as many passes as possible on a single function before moving to the next
+ // non-debug normal mode, run them in an optimal manner - for locality it is
+ // better to run as many passes as possible on a single function before
+ // moving to the next
std::vector<Pass*> stack;
auto flush = [&]() {
if (stack.size() > 0) {
// run the stack of passes on all the functions, in parallel
size_t num = ThreadPool::get()->size();
- std::vector<std::function<ThreadWorkState ()>> doWorkers;
+ std::vector<std::function<ThreadWorkState()>> doWorkers;
std::atomic<size_t> nextFunction;
nextFunction.store(0);
size_t numFunctions = wasm->functions.size();
@@ -380,7 +539,8 @@ void PassRunner::run() {
void PassRunner::runOnFunction(Function* func) {
if (options.debug) {
- std::cerr << "[PassRunner] running passes on function " << func->name << std::endl;
+ std::cerr << "[PassRunner] running passes on function " << func->name
+ << std::endl;
}
for (auto* pass : passes) {
runPassOnFunction(pass, func);
@@ -425,14 +585,18 @@ struct AfterEffectFunctionChecker {
if (beganWithStackIR && func->stackIR) {
auto after = FunctionHasher::hashFunction(func);
if (after != originalFunctionHash) {
- Fatal() << "[PassRunner] PASS_DEBUG check failed: had Stack IR before and after the pass ran, and the pass modified the main IR, which invalidates Stack IR - pass should have been marked 'modifiesBinaryenIR'";
+ Fatal() << "[PassRunner] PASS_DEBUG check failed: had Stack IR before "
+ "and after the pass ran, and the pass modified the main IR, "
+ "which invalidates Stack IR - pass should have been marked "
+ "'modifiesBinaryenIR'";
}
}
}
};
// Runs checks on the entire module, in a non-function-parallel pass.
-// In particular, in such a pass functions may be removed or renamed, track that.
+// In particular, in such a pass functions may be removed or renamed, track
+// that.
struct AfterEffectModuleChecker {
Module* module;
@@ -473,7 +637,9 @@ struct AfterEffectModuleChecker {
}
void error() {
- Fatal() << "[PassRunner] PASS_DEBUG check failed: had Stack IR before and after the pass ran, and the pass modified global function state - pass should have been marked 'modifiesBinaryenIR'";
+ Fatal() << "[PassRunner] PASS_DEBUG check failed: had Stack IR before and "
+ "after the pass ran, and the pass modified global function "
+ "state - pass should have been marked 'modifiesBinaryenIR'";
}
bool hasAnyStackIR() {
@@ -530,7 +696,8 @@ void PassRunner::handleAfterEffects(Pass* pass, Function* func) {
}
int PassRunner::getPassDebug() {
- static const int passDebug = getenv("BINARYEN_PASS_DEBUG") ? atoi(getenv("BINARYEN_PASS_DEBUG")) : 0;
+ static const int passDebug =
+ getenv("BINARYEN_PASS_DEBUG") ? atoi(getenv("BINARYEN_PASS_DEBUG")) : 0;
return passDebug;
}
diff --git a/src/passes/passes.h b/src/passes/passes.h
index af9141ac9..fc01c1cd5 100644
--- a/src/passes/passes.h
+++ b/src/passes/passes.h
@@ -102,6 +102,6 @@ Pass* createTrapModeJS();
Pass* createUnteePass();
Pass* createVacuumPass();
-}
+} // namespace wasm
#endif
diff --git a/src/pretty_printing.h b/src/pretty_printing.h
index c5d755dcc..5e41a4d2d 100644
--- a/src/pretty_printing.h
+++ b/src/pretty_printing.h
@@ -25,36 +25,36 @@
#include "support/colors.h"
-inline std::ostream &doIndent(std::ostream &o, unsigned indent) {
+inline std::ostream& doIndent(std::ostream& o, unsigned indent) {
for (unsigned i = 0; i < indent; i++) {
o << " ";
}
return o;
}
-inline std::ostream &prepareMajorColor(std::ostream &o) {
+inline std::ostream& prepareMajorColor(std::ostream& o) {
Colors::red(o);
Colors::bold(o);
return o;
}
-inline std::ostream &prepareColor(std::ostream &o) {
+inline std::ostream& prepareColor(std::ostream& o) {
Colors::magenta(o);
Colors::bold(o);
return o;
}
-inline std::ostream &prepareMinorColor(std::ostream &o) {
+inline std::ostream& prepareMinorColor(std::ostream& o) {
Colors::orange(o);
return o;
}
-inline std::ostream &restoreNormalColor(std::ostream &o) {
+inline std::ostream& restoreNormalColor(std::ostream& o) {
Colors::normal(o);
return o;
}
-inline std::ostream& printText(std::ostream &o, const char *str) {
+inline std::ostream& printText(std::ostream& o, const char* str) {
o << '"';
Colors::green(o);
o << str;
@@ -62,21 +62,23 @@ inline std::ostream& printText(std::ostream &o, const char *str) {
return o << '"';
}
-inline std::ostream& printMajor(std::ostream &o, const char *str, bool major=false) {
+inline std::ostream&
+printMajor(std::ostream& o, const char* str, bool major = false) {
prepareMajorColor(o);
o << str;
restoreNormalColor(o);
return o;
}
-inline std::ostream& printMedium(std::ostream &o, const char *str, bool major=false) {
+inline std::ostream&
+printMedium(std::ostream& o, const char* str, bool major = false) {
prepareColor(o);
o << str;
restoreNormalColor(o);
return o;
}
-inline std::ostream& printMinor(std::ostream &o, const char *str) {
+inline std::ostream& printMinor(std::ostream& o, const char* str) {
prepareMinorColor(o);
o << str;
restoreNormalColor(o);
diff --git a/src/shared-constants.h b/src/shared-constants.h
index dbbc25e02..2ce2ab81c 100644
--- a/src/shared-constants.h
+++ b/src/shared-constants.h
@@ -21,46 +21,46 @@
namespace wasm {
-extern Name GROW_WASM_MEMORY,
- WASM_CALL_CTORS,
- MEMORY_BASE,
- TABLE_BASE,
- GET_TEMP_RET0,
- SET_TEMP_RET0,
- NEW_SIZE,
- MODULE,
- START,
- FUNC,
- PARAM,
- RESULT,
- MEMORY,
- DATA,
- PASSIVE,
- EXPORT,
- IMPORT,
- TABLE,
- ELEM,
- LOCAL,
- TYPE,
- CALL,
- CALL_IMPORT,
- CALL_INDIRECT,
- BLOCK,
- BR_IF,
- THEN,
- ELSE,
- _NAN,
- _INFINITY,
- NEG_INFINITY,
- NEG_NAN,
- CASE,
- BR,
- FUNCREF,
- FAKE_RETURN,
- MUT,
- SPECTEST,
- PRINT,
- EXIT;
+extern Name GROW_WASM_MEMORY;
+extern Name WASM_CALL_CTORS;
+extern Name MEMORY_BASE;
+extern Name TABLE_BASE;
+extern Name GET_TEMP_RET0;
+extern Name SET_TEMP_RET0;
+extern Name NEW_SIZE;
+extern Name MODULE;
+extern Name START;
+extern Name FUNC;
+extern Name PARAM;
+extern Name RESULT;
+extern Name MEMORY;
+extern Name DATA;
+extern Name PASSIVE;
+extern Name EXPORT;
+extern Name IMPORT;
+extern Name TABLE;
+extern Name ELEM;
+extern Name LOCAL;
+extern Name TYPE;
+extern Name CALL;
+extern Name CALL_IMPORT;
+extern Name CALL_INDIRECT;
+extern Name BLOCK;
+extern Name BR_IF;
+extern Name THEN;
+extern Name ELSE;
+extern Name _NAN;
+extern Name _INFINITY;
+extern Name NEG_INFINITY;
+extern Name NEG_NAN;
+extern Name CASE;
+extern Name BR;
+extern Name FUNCREF;
+extern Name FAKE_RETURN;
+extern Name MUT;
+extern Name SPECTEST;
+extern Name PRINT;
+extern Name EXIT;
} // namespace wasm
diff --git a/src/shell-interface.h b/src/shell-interface.h
index 4cb5f5349..1bbe97dd9 100644
--- a/src/shell-interface.h
+++ b/src/shell-interface.h
@@ -21,12 +21,12 @@
#ifndef wasm_shell_interface_h
#define wasm_shell_interface_h
-#include "shared-constants.h"
#include "asmjs/shared-constants.h"
+#include "ir/module-utils.h"
+#include "shared-constants.h"
#include "support/name.h"
-#include "wasm.h"
#include "wasm-interpreter.h"
-#include "ir/module-utils.h"
+#include "wasm.h"
namespace wasm {
@@ -44,15 +44,14 @@ struct ShellExternalInterface : ModuleInstance::ExternalInterface {
class Memory {
// Use char because it doesn't run afoul of aliasing rules.
std::vector<char> memory;
- template<typename T>
- static bool aligned(const char* address) {
+ template<typename T> static bool aligned(const char* address) {
static_assert(!(sizeof(T) & (sizeof(T) - 1)), "must be a power of 2");
return 0 == (reinterpret_cast<uintptr_t>(address) & (sizeof(T) - 1));
}
Memory(Memory&) = delete;
Memory& operator=(const Memory&) = delete;
- public:
+ public:
Memory() = default;
void resize(size_t newSize) {
// Ensure the smallest allocation is large enough that most allocators
@@ -68,16 +67,14 @@ struct ShellExternalInterface : ModuleInstance::ExternalInterface {
std::memset(&memory[newSize], 0, minSize - newSize);
}
}
- template<typename T>
- void set(size_t address, T value) {
+ template<typename T> void set(size_t address, T value) {
if (aligned<T>(&memory[address])) {
*reinterpret_cast<T*>(&memory[address]) = value;
} else {
std::memcpy(&memory[address], &value, sizeof(T));
}
}
- template<typename T>
- T get(size_t address) {
+ template<typename T> T get(size_t address) {
if (aligned<T>(&memory[address])) {
return *reinterpret_cast<T*>(&memory[address]);
} else {
@@ -103,17 +100,28 @@ struct ShellExternalInterface : ModuleInstance::ExternalInterface {
ModuleUtils::iterImportedGlobals(wasm, [&](Global* import) {
if (import->module == SPECTEST && import->base == GLOBAL) {
switch (import->type) {
- case i32: globals[import->name] = Literal(int32_t(666)); break;
- case i64: globals[import->name] = Literal(int64_t(666)); break;
- case f32: globals[import->name] = Literal(float(666.6)); break;
- case f64: globals[import->name] = Literal(double(666.6)); break;
- case v128: assert(false && "v128 not implemented yet");
+ case i32:
+ globals[import->name] = Literal(int32_t(666));
+ break;
+ case i64:
+ globals[import->name] = Literal(int64_t(666));
+ break;
+ case f32:
+ globals[import->name] = Literal(float(666.6));
+ break;
+ case f64:
+ globals[import->name] = Literal(double(666.6));
+ break;
+ case v128:
+ assert(false && "v128 not implemented yet");
case none:
- case unreachable: WASM_UNREACHABLE();
+ case unreachable:
+ WASM_UNREACHABLE();
}
}
});
- if (wasm.memory.imported() && wasm.memory.module == SPECTEST && wasm.memory.base == MEMORY) {
+ if (wasm.memory.imported() && wasm.memory.module == SPECTEST &&
+ wasm.memory.base == MEMORY) {
// imported memory has initial 1 and max 2
wasm.memory.initial = 1;
wasm.memory.max = 2;
@@ -135,11 +143,17 @@ struct ShellExternalInterface : ModuleInstance::ExternalInterface {
<< import->name.str;
}
- Literal callTable(Index index, LiteralList& arguments, Type result, ModuleInstance& instance) override {
- if (index >= table.size()) trap("callTable overflow");
+ Literal callTable(Index index,
+ LiteralList& arguments,
+ Type result,
+ ModuleInstance& instance) override {
+ if (index >= table.size())
+ trap("callTable overflow");
auto* func = instance.wasm.getFunctionOrNull(table[index]);
- if (!func) trap("uninitialized table element");
- if (func->params.size() != arguments.size()) trap("callIndirect: bad # of arguments");
+ if (!func)
+ trap("uninitialized table element");
+ if (func->params.size() != arguments.size())
+ trap("callIndirect: bad # of arguments");
for (size_t i = 0; i < func->params.size(); i++) {
if (func->params[i] != arguments[i].type) {
trap("callIndirect: bad argument type");
@@ -167,17 +181,23 @@ struct ShellExternalInterface : ModuleInstance::ExternalInterface {
return memory.get<std::array<uint8_t, 16>>(addr);
}
- void store8(Address addr, int8_t value) override { memory.set<int8_t>(addr, value); }
- void store16(Address addr, int16_t value) override { memory.set<int16_t>(addr, value); }
- void store32(Address addr, int32_t value) override { memory.set<int32_t>(addr, value); }
- void store64(Address addr, int64_t value) override { memory.set<int64_t>(addr, value); }
+ void store8(Address addr, int8_t value) override {
+ memory.set<int8_t>(addr, value);
+ }
+ void store16(Address addr, int16_t value) override {
+ memory.set<int16_t>(addr, value);
+ }
+ void store32(Address addr, int32_t value) override {
+ memory.set<int32_t>(addr, value);
+ }
+ void store64(Address addr, int64_t value) override {
+ memory.set<int64_t>(addr, value);
+ }
void store128(Address addr, const std::array<uint8_t, 16>& value) override {
memory.set<std::array<uint8_t, 16>>(addr, value);
}
- void tableStore(Address addr, Name entry) override {
- table[addr] = entry;
- }
+ void tableStore(Address addr, Name entry) override { table[addr] = entry; }
void growMemory(Address /*oldSize*/, Address newSize) override {
memory.resize(newSize);
@@ -189,6 +209,6 @@ struct ShellExternalInterface : ModuleInstance::ExternalInterface {
}
};
-}
+} // namespace wasm
#endif // wasm_shell_interface_h
diff --git a/src/support/alloc.h b/src/support/alloc.h
index 075896694..d85cbb0f7 100644
--- a/src/support/alloc.h
+++ b/src/support/alloc.h
@@ -35,10 +35,11 @@ inline void* aligned_malloc(size_t align, size_t size) {
#if defined(WIN32) || defined(_WIN32)
_set_errno(0);
void* ret = _aligned_malloc(size, align);
- if (errno == ENOMEM) ret = nullptr;
+ if (errno == ENOMEM)
+ ret = nullptr;
return ret;
#elif defined(__APPLE__)
- void *ptr;
+ void* ptr;
int result = posix_memalign(&ptr, align, size);
return result == 0 ? ptr : nullptr;
#else
@@ -56,4 +57,4 @@ inline void aligned_free(void* ptr) {
} // namespace wasm
-#endif // wasm_support_alloc_h
+#endif // wasm_support_alloc_h
diff --git a/src/support/archive.cpp b/src/support/archive.cpp
index b9ca827e4..66f9c192a 100644
--- a/src/support/archive.cpp
+++ b/src/support/archive.cpp
@@ -16,19 +16,19 @@
#include "support/archive.h"
-#include <cstring>
#include "support/utilities.h"
+#include <cstring>
static const char* const magic = "!<arch>\n";
class ArchiveMemberHeader {
- public:
+public:
uint8_t fileName[16];
uint8_t timestamp[12];
uint8_t UID[6];
uint8_t GID[6];
uint8_t accessMode[8];
- uint8_t size[10]; // Size of data only, not including padding or header
+ uint8_t size[10]; // Size of data only, not including padding or header
uint8_t magic[2];
std::string getName() const;
@@ -42,11 +42,12 @@ std::string ArchiveMemberHeader::getName() const {
// Special name (string table or reference, or symbol table)
endChar = ' ';
} else {
- endChar = '/'; // regular name
+ endChar = '/'; // regular name
}
auto* end =
- static_cast<const uint8_t*>(memchr(fileName, endChar, sizeof(fileName)));
- if (!end) end = fileName + sizeof(fileName);
+ static_cast<const uint8_t*>(memchr(fileName, endChar, sizeof(fileName)));
+ if (!end)
+ end = fileName + sizeof(fileName);
return std::string((char*)(fileName), end - fileName);
}
@@ -60,7 +61,9 @@ uint32_t ArchiveMemberHeader::getSize() const {
return static_cast<uint32_t>(sizeInt);
}
-Archive::Archive(Buffer& b, bool& error) : data(b), symbolTable({nullptr, 0}), stringTable({nullptr, 0}), firstRegularData(nullptr) {
+Archive::Archive(Buffer& b, bool& error)
+ : data(b), symbolTable({nullptr, 0}), stringTable({nullptr, 0}),
+ firstRegularData(nullptr) {
error = false;
if (data.size() < strlen(magic) ||
memcmp(data.data(), magic, strlen(magic))) {
@@ -78,14 +81,16 @@ Archive::Archive(Buffer& b, bool& error) : data(b), symbolTable({nullptr, 0}), s
return;
}
child_iterator end = child_end();
- if (it == end) return; // Empty archive.
+ if (it == end)
+ return; // Empty archive.
const Child* c = &*it;
auto increment = [&]() {
++it;
error = it.hasError();
- if (error) return true;
+ if (error)
+ return true;
c = &*it;
return false;
};
@@ -93,13 +98,15 @@ Archive::Archive(Buffer& b, bool& error) : data(b), symbolTable({nullptr, 0}), s
std::string name = c->getRawName();
if (name == "/") {
symbolTable = c->getBuffer();
- if (increment() || it == end) return;
+ if (increment() || it == end)
+ return;
name = c->getRawName();
}
if (name == "//") {
stringTable = c->getBuffer();
- if (increment() || it == end) return;
+ if (increment() || it == end)
+ return;
setFirstRegular(*c);
return;
}
@@ -112,8 +119,9 @@ Archive::Archive(Buffer& b, bool& error) : data(b), symbolTable({nullptr, 0}), s
}
Archive::Child::Child(const Archive* parent, const uint8_t* data, bool* error)
- : parent(parent), data(data) {
- if (!data) return;
+ : parent(parent), data(data) {
+ if (!data)
+ return;
len = sizeof(ArchiveMemberHeader) + getHeader()->getSize();
startOfFile = sizeof(ArchiveMemberHeader);
}
@@ -129,8 +137,10 @@ std::string Archive::Child::getRawName() const {
}
Archive::Child Archive::Child::getNext(bool& error) const {
- uint32_t nextOffset = len + (len & 1); // Members are aligned to even byte boundaries.
- if ((size_t)(data - (const uint8_t*)parent->data.data() + nextOffset) >= parent->data.size()) { // End of the archive.
+ // Members are aligned to even byte boundaries.
+ uint32_t nextOffset = len + (len & 1);
+ if ((size_t)(data - (const uint8_t*)parent->data.data() + nextOffset) >=
+ parent->data.size()) { // End of the archive.
return Child();
}
return Child(parent, data + nextOffset, &error);
@@ -140,10 +150,10 @@ std::string Archive::Child::getName() const {
std::string name = getRawName();
// Check if it's a special name.
if (name[0] == '/') {
- if (name.size() == 1) { // Linker member.
+ if (name.size() == 1) { // Linker member.
return name;
}
- if (name.size() == 2 && name[1] == '/') { // String table.
+ if (name.size() == 2 && name[1] == '/') { // String table.
return name;
}
// It's a long name.
@@ -170,7 +180,8 @@ std::string Archive::Child::getName() const {
}
Archive::child_iterator Archive::child_begin(bool SkipInternal) const {
- if (data.size() == 0) return child_end();
+ if (data.size() == 0)
+ return child_end();
if (SkipInternal) {
child_iterator it;
@@ -197,7 +208,7 @@ struct Symbol {
++symbolIndex;
}
};
-}
+} // namespace
static uint32_t read32be(const uint8_t* buf) {
return static_cast<uint32_t>(buf[0]) << 24 |
@@ -206,15 +217,20 @@ static uint32_t read32be(const uint8_t* buf) {
}
void Archive::dump() const {
- printf("Archive data %p len %zu, firstRegularData %p\n", data.data(),
- data.size(), firstRegularData);
+ printf("Archive data %p len %zu, firstRegularData %p\n",
+ data.data(),
+ data.size(),
+ firstRegularData);
printf("Symbol table %p, len %u\n", symbolTable.data, symbolTable.len);
printf("string table %p, len %u\n", stringTable.data, stringTable.len);
const uint8_t* buf = symbolTable.data;
if (!buf) {
for (auto c = child_begin(), e = child_end(); c != e; ++c) {
- printf("Child %p, len %u, name %s, size %u\n", c->data, c->len,
- c->getName().c_str(), c->getSize());
+ printf("Child %p, len %u, name %s, size %u\n",
+ c->data,
+ c->len,
+ c->getName().c_str(),
+ c->getSize());
}
return;
}
diff --git a/src/support/archive.h b/src/support/archive.h
index 0ca066ff1..cba7c4fc1 100644
--- a/src/support/archive.h
+++ b/src/support/archive.h
@@ -38,7 +38,7 @@ class Archive {
// because most things in these buffers are not nul-terminated
using Buffer = std::vector<char>;
- public:
+public:
struct SubBuffer {
const uint8_t* data;
uint32_t len;
@@ -56,7 +56,7 @@ class Archive {
}
Child getNext(bool& error) const;
- public:
+ public:
Child(){};
Child(const Archive* parent, const uint8_t* data, bool* error);
// Size of actual member data (no header/padding)
@@ -69,8 +69,8 @@ class Archive {
class child_iterator {
friend class Archive;
Child child;
- bool error = false; // TODO: use std::error_code instead?
- public:
+ bool error = false; // TODO: use std::error_code instead?
+ public:
child_iterator() = default;
explicit child_iterator(bool error) : error(error) {}
child_iterator(const Child& c) : child(c) {}
@@ -94,7 +94,7 @@ class Archive {
child_iterator child_end() const;
void dump() const;
- private:
+private:
void setFirstRegular(const Child& c) { firstRegularData = c.data; }
Buffer& data;
SubBuffer symbolTable;
@@ -102,4 +102,4 @@ class Archive {
const uint8_t* firstRegularData;
};
-#endif // wasm_support_archive_h
+#endif // wasm_support_archive_h
diff --git a/src/support/base64.h b/src/support/base64.h
index 0c87c37c1..8634246a6 100644
--- a/src/support/base64.h
+++ b/src/support/base64.h
@@ -21,20 +21,18 @@
#include <string>
#include <vector>
-inline std::string base64Encode(std::vector<char> &data) {
+inline std::string base64Encode(std::vector<char>& data) {
std::string ret;
size_t i = 0;
- const char* alphabet =
- "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
- "abcdefghijklmnopqrstuvwxyz"
- "0123456789+/";
+ const char* alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
+ "abcdefghijklmnopqrstuvwxyz"
+ "0123456789+/";
while (i + 3 <= data.size()) {
- uint32_t bits =
- (((uint32_t)(uint8_t) data[i + 0]) << 16) |
- (((uint32_t)(uint8_t) data[i + 1]) << 8) |
- (((uint32_t)(uint8_t) data[i + 2]) << 0);
+ uint32_t bits = (((uint32_t)(uint8_t)data[i + 0]) << 16) |
+ (((uint32_t)(uint8_t)data[i + 1]) << 8) |
+ (((uint32_t)(uint8_t)data[i + 2]) << 0);
ret += alphabet[(bits >> 18) & 0x3f];
ret += alphabet[(bits >> 12) & 0x3f];
ret += alphabet[(bits >> 6) & 0x3f];
@@ -43,15 +41,14 @@ inline std::string base64Encode(std::vector<char> &data) {
}
if (i + 2 == data.size()) {
- uint32_t bits =
- (((uint32_t)(uint8_t) data[i + 0]) << 8) |
- (((uint32_t)(uint8_t) data[i + 1]) << 0);
+ uint32_t bits = (((uint32_t)(uint8_t)data[i + 0]) << 8) |
+ (((uint32_t)(uint8_t)data[i + 1]) << 0);
ret += alphabet[(bits >> 10) & 0x3f];
ret += alphabet[(bits >> 4) & 0x3f];
ret += alphabet[(bits << 2) & 0x3f];
ret += '=';
} else if (i + 1 == data.size()) {
- uint32_t bits = (uint32_t)(uint8_t) data[i + 0];
+ uint32_t bits = (uint32_t)(uint8_t)data[i + 0];
ret += alphabet[(bits >> 2) & 0x3f];
ret += alphabet[(bits << 4) & 0x3f];
ret += '=';
diff --git a/src/support/bits.cpp b/src/support/bits.cpp
index 8f28a7fdb..c237807ee 100644
--- a/src/support/bits.cpp
+++ b/src/support/bits.cpp
@@ -15,28 +15,24 @@
*/
#define wasm_support_bits_definitions
-#include "../compiler-support.h"
#include "support/bits.h"
+#include "../compiler-support.h"
namespace wasm {
-template<>
-int PopCount<uint8_t>(uint8_t v) {
+template<> int PopCount<uint8_t>(uint8_t v) {
// Small table lookup.
- static const uint8_t tbl[32] = {
- 0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4,
- 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5
- };
+ static const uint8_t tbl[32] = {0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2,
+ 3, 2, 3, 3, 4, 1, 2, 2, 3, 2, 3,
+ 3, 4, 2, 3, 3, 4, 3, 4, 4, 5};
return tbl[v & 0xf] + tbl[v >> 4];
}
-template<>
-int PopCount<uint16_t>(uint16_t v) {
+template<> int PopCount<uint16_t>(uint16_t v) {
return PopCount((uint8_t)(v & 0xff)) + PopCount((uint8_t)(v >> 8));
}
-template<>
-int PopCount<uint32_t>(uint32_t v) {
+template<> int PopCount<uint32_t>(uint32_t v) {
// See Stanford bithacks, counting bits set in parallel, "best method":
// http://graphics.stanford.edu/~seander/bithacks.html#CountBitsSetParallel
v = v - ((v >> 1) & 0x55555555);
@@ -44,13 +40,11 @@ int PopCount<uint32_t>(uint32_t v) {
return (((v + (v >> 4)) & 0xF0F0F0F) * 0x1010101) >> 24;
}
-template<>
-int PopCount<uint64_t>(uint64_t v) {
+template<> int PopCount<uint64_t>(uint64_t v) {
return PopCount((uint32_t)v) + PopCount((uint32_t)(v >> 32));
}
-template<>
-uint32_t BitReverse<uint32_t>(uint32_t v) {
+template<> uint32_t BitReverse<uint32_t>(uint32_t v) {
// See Hacker's Delight, first edition, figure 7-1.
v = ((v & 0x55555555) << 1) | ((v >> 1) & 0x55555555);
v = ((v & 0x33333333) << 2) | ((v >> 2) & 0x33333333);
@@ -59,33 +53,28 @@ uint32_t BitReverse<uint32_t>(uint32_t v) {
return v;
}
-template<>
-int CountTrailingZeroes<uint32_t>(uint32_t v) {
+template<> int CountTrailingZeroes<uint32_t>(uint32_t v) {
// See Stanford bithacks, count the consecutive zero bits (trailing) on the
// right with multiply and lookup:
// http://graphics.stanford.edu/~seander/bithacks.html#ZerosOnRightMultLookup
- static const uint8_t tbl[32] = {
- 0, 1, 28, 2, 29, 14, 24, 3, 30, 22, 20, 15, 25, 17, 4, 8,
- 31, 27, 13, 23, 21, 19, 16, 7, 26, 12, 18, 6, 11, 5, 10, 9
- };
+ static const uint8_t tbl[32] = {0, 1, 28, 2, 29, 14, 24, 3, 30, 22, 20,
+ 15, 25, 17, 4, 8, 31, 27, 13, 23, 21, 19,
+ 16, 7, 26, 12, 18, 6, 11, 5, 10, 9};
return v ? (int)tbl[((uint32_t)((v & -v) * 0x077CB531U)) >> 27] : 32;
}
-template<>
-int CountTrailingZeroes<uint64_t>(uint64_t v) {
+template<> int CountTrailingZeroes<uint64_t>(uint64_t v) {
return (uint32_t)v ? CountTrailingZeroes((uint32_t)v)
: 32 + CountTrailingZeroes((uint32_t)(v >> 32));
}
-template<>
-int CountLeadingZeroes<uint32_t>(uint32_t v) {
+template<> int CountLeadingZeroes<uint32_t>(uint32_t v) {
// See Stanford bithacks, find the log base 2 of an N-bit integer in
// O(lg(N)) operations with multiply and lookup:
// http://graphics.stanford.edu/~seander/bithacks.html#IntegerLogDeBruijn
- static const uint8_t tbl[32] = {
- 31, 22, 30, 21, 18, 10, 29, 2, 20, 17, 15, 13, 9, 6, 28, 1,
- 23, 19, 11, 3, 16, 14, 7, 24, 12, 4, 8, 25, 5, 26, 27, 0
- };
+ static const uint8_t tbl[32] = {31, 22, 30, 21, 18, 10, 29, 2, 20, 17, 15,
+ 13, 9, 6, 28, 1, 23, 19, 11, 3, 16, 14,
+ 7, 24, 12, 4, 8, 25, 5, 26, 27, 0};
v = v | (v >> 1);
v = v | (v >> 2);
v = v | (v >> 4);
@@ -94,33 +83,46 @@ int CountLeadingZeroes<uint32_t>(uint32_t v) {
return v ? (int)tbl[((uint32_t)(v * 0x07C4ACDDU)) >> 27] : 32;
}
-template<>
-int CountLeadingZeroes<uint64_t>(uint64_t v) {
+template<> int CountLeadingZeroes<uint64_t>(uint64_t v) {
return v >> 32 ? CountLeadingZeroes((uint32_t)(v >> 32))
: 32 + CountLeadingZeroes((uint32_t)v);
}
uint32_t Log2(uint32_t v) {
switch (v) {
- default: WASM_UNREACHABLE();
- case 1: return 0;
- case 2: return 1;
- case 4: return 2;
- case 8: return 3;
- case 16: return 4;
- case 32: return 5;
+ default:
+ WASM_UNREACHABLE();
+ case 1:
+ return 0;
+ case 2:
+ return 1;
+ case 4:
+ return 2;
+ case 8:
+ return 3;
+ case 16:
+ return 4;
+ case 32:
+ return 5;
}
}
uint32_t Pow2(uint32_t v) {
switch (v) {
- case 0: return 1;
- case 1: return 2;
- case 2: return 4;
- case 3: return 8;
- case 4: return 16;
- case 5: return 32;
- default: return 1 << v;
+ case 0:
+ return 1;
+ case 1:
+ return 2;
+ case 2:
+ return 4;
+ case 3:
+ return 8;
+ case 4:
+ return 16;
+ case 5:
+ return 32;
+ default:
+ return 1 << v;
}
}
diff --git a/src/support/bits.h b/src/support/bits.h
index f1dc4364f..f2241bea8 100644
--- a/src/support/bits.h
+++ b/src/support/bits.h
@@ -56,31 +56,23 @@ extern template int CountLeadingZeroes(uint64_t);
// Convenience signed -> unsigned. It usually doesn't make much sense to use bit
// functions on signed types.
-template<typename T>
-int PopCount(T v) {
+template<typename T> int PopCount(T v) {
return PopCount(typename std::make_unsigned<T>::type(v));
}
-template<typename T>
-int CountTrailingZeroes(T v) {
+template<typename T> int CountTrailingZeroes(T v) {
return CountTrailingZeroes(typename std::make_unsigned<T>::type(v));
}
-template<typename T>
-int CountLeadingZeroes(T v) {
+template<typename T> int CountLeadingZeroes(T v) {
return CountLeadingZeroes(typename std::make_unsigned<T>::type(v));
}
-template<typename T>
-bool IsPowerOf2(T v) {
- return v != 0 && PopCount(v) == 1;
-}
+template<typename T> bool IsPowerOf2(T v) { return v != 0 && PopCount(v) == 1; }
-template<typename T, typename U>
-inline static T RotateLeft(T val, U count) {
+template<typename T, typename U> inline static T RotateLeft(T val, U count) {
T mask = sizeof(T) * CHAR_BIT - 1;
count &= mask;
return (val << count) | (val >> (-count & mask));
}
-template<typename T, typename U>
-inline static T RotateRight(T val, U count) {
+template<typename T, typename U> inline static T RotateRight(T val, U count) {
T mask = sizeof(T) * CHAR_BIT - 1;
count &= mask;
return (val >> count) | (val << (-count & mask));
@@ -89,6 +81,6 @@ inline static T RotateRight(T val, U count) {
extern uint32_t Log2(uint32_t v);
extern uint32_t Pow2(uint32_t v);
-} // namespace wasm
+} // namespace wasm
-#endif // wasm_support_bits_h
+#endif // wasm_support_bits_h
diff --git a/src/support/colors.cpp b/src/support/colors.cpp
index 7d78306e0..d0dc5ceb3 100644
--- a/src/support/colors.cpp
+++ b/src/support/colors.cpp
@@ -21,7 +21,7 @@
namespace {
bool colors_disabled = false;
-} // anonymous namespace
+} // anonymous namespace
void Colors::disable() { colors_disabled = true; }
@@ -30,25 +30,27 @@ void Colors::disable() { colors_disabled = true; }
void Colors::outputColorCode(std::ostream& stream, const char* colorCode) {
const static bool has_color = []() {
- return (getenv("COLORS") && getenv("COLORS")[0] == '1') || // forced
+ return (getenv("COLORS") && getenv("COLORS")[0] == '1') || // forced
(isatty(STDOUT_FILENO) &&
- (!getenv("COLORS") || getenv("COLORS")[0] != '0')); // implicit
+ (!getenv("COLORS") || getenv("COLORS")[0] != '0')); // implicit
}();
- if (has_color && !colors_disabled) stream << colorCode;
+ if (has_color && !colors_disabled)
+ stream << colorCode;
}
#elif defined(_WIN32)
-#include <windows.h>
#include <io.h>
#include <iostream>
+#include <windows.h>
-void Colors::outputColorCode(std::ostream&stream, const WORD &colorCode) {
+void Colors::outputColorCode(std::ostream& stream, const WORD& colorCode) {
const static bool has_color = []() {
return _isatty(_fileno(stdout)) &&
- (!getenv("COLORS") || getenv("COLORS")[0] != '0'); // implicit
+ (!getenv("COLORS") || getenv("COLORS")[0] != '0'); // implicit
}();
static HANDLE hStdout = GetStdHandle(STD_OUTPUT_HANDLE);
static HANDLE hStderr = GetStdHandle(STD_ERROR_HANDLE);
if (has_color && !colors_disabled)
- SetConsoleTextAttribute(&stream == &std::cout ? hStdout : hStderr, colorCode);
+ SetConsoleTextAttribute(&stream == &std::cout ? hStdout : hStderr,
+ colorCode);
}
#endif
diff --git a/src/support/colors.h b/src/support/colors.h
index 6761639d9..68a251969 100644
--- a/src/support/colors.h
+++ b/src/support/colors.h
@@ -23,17 +23,21 @@ namespace Colors {
void disable();
#if defined(__linux__) || defined(__APPLE__)
-void outputColorCode(std::ostream& stream, const char *colorCode);
-inline void normal(std::ostream& stream) { outputColorCode(stream,"\033[0m"); }
-inline void red(std::ostream& stream) { outputColorCode(stream,"\033[31m"); }
-inline void magenta(std::ostream& stream) { outputColorCode(stream,"\033[35m"); }
-inline void orange(std::ostream& stream) { outputColorCode(stream,"\033[33m"); }
-inline void grey(std::ostream& stream) { outputColorCode(stream,"\033[37m"); }
-inline void green(std::ostream& stream) { outputColorCode(stream,"\033[32m"); }
-inline void blue(std::ostream& stream) { outputColorCode(stream,"\033[34m"); }
-inline void bold(std::ostream& stream) { outputColorCode(stream,"\033[1m"); }
+void outputColorCode(std::ostream& stream, const char* colorCode);
+inline void normal(std::ostream& stream) { outputColorCode(stream, "\033[0m"); }
+inline void red(std::ostream& stream) { outputColorCode(stream, "\033[31m"); }
+inline void magenta(std::ostream& stream) {
+ outputColorCode(stream, "\033[35m");
+}
+inline void orange(std::ostream& stream) {
+ outputColorCode(stream, "\033[33m");
+}
+inline void grey(std::ostream& stream) { outputColorCode(stream, "\033[37m"); }
+inline void green(std::ostream& stream) { outputColorCode(stream, "\033[32m"); }
+inline void blue(std::ostream& stream) { outputColorCode(stream, "\033[34m"); }
+inline void bold(std::ostream& stream) { outputColorCode(stream, "\033[1m"); }
#elif defined(_WIN32)
-void outputColorCode(std::ostream& stream, const unsigned short &colorCode);
+void outputColorCode(std::ostream& stream, const unsigned short& colorCode);
inline void normal(std::ostream& stream) { outputColorCode(stream, 0x07); }
inline void red(std::ostream& stream) { outputColorCode(stream, 0x0c); }
inline void magenta(std::ostream& stream) { outputColorCode(stream, 0x05); }
@@ -41,7 +45,8 @@ inline void orange(std::ostream& stream) { outputColorCode(stream, 0x06); }
inline void grey(std::ostream& stream) { outputColorCode(stream, 0x08); }
inline void green(std::ostream& stream) { outputColorCode(stream, 0x02); }
inline void blue(std::ostream& stream) { outputColorCode(stream, 0x09); }
-inline void bold(std::ostream& stream) { /* Do nothing */ }
+inline void bold(std::ostream& stream) { /* Do nothing */
+}
#else
inline void normal(std::ostream& stream) {}
inline void red(std::ostream& stream) {}
@@ -52,6 +57,6 @@ inline void green(std::ostream& stream) {}
inline void blue(std::ostream& stream) {}
inline void bold(std::ostream& stream) {}
#endif
-}
+} // namespace Colors
#endif // wasm_support_color_h
diff --git a/src/support/command-line.cpp b/src/support/command-line.cpp
index 6882dda7b..f3b9ffe25 100644
--- a/src/support/command-line.cpp
+++ b/src/support/command-line.cpp
@@ -37,7 +37,8 @@ void printWrap(std::ostream& os, int leftPad, const std::string& content) {
}
os << nextWord;
space -= nextWord.size() + 1;
- if (space > 0) os << ' ';
+ if (space > 0)
+ os << ' ';
nextWord.clear();
if (content[i] == '\n') {
os << '\n';
@@ -48,18 +49,22 @@ void printWrap(std::ostream& os, int leftPad, const std::string& content) {
}
Options::Options(const std::string& command, const std::string& description)
- : debug(false), positional(Arguments::Zero) {
- add("--help", "-h", "Show this help message and exit", Arguments::Zero,
+ : debug(false), positional(Arguments::Zero) {
+ add("--help",
+ "-h",
+ "Show this help message and exit",
+ Arguments::Zero,
[this, command, description](Options* o, const std::string&) {
std::cout << command;
- if (positional != Arguments::Zero) std::cout << ' ' << positionalName;
+ if (positional != Arguments::Zero)
+ std::cout << ' ' << positionalName;
std::cout << "\n\n";
printWrap(std::cout, 0, description);
std::cout << "\n\nOptions:\n";
size_t optionWidth = 0;
for (const auto& o : options) {
optionWidth =
- std::max(optionWidth, o.longName.size() + o.shortName.size());
+ std::max(optionWidth, o.longName.size() + o.shortName.size());
}
for (const auto& o : options) {
bool long_n_short = o.longName.size() != 0 && o.shortName.size() != 0;
@@ -72,20 +77,26 @@ Options::Options(const std::string& command, const std::string& description)
std::cout << '\n';
exit(EXIT_SUCCESS);
});
- add("--debug", "-d", "Print debug information to stderr", Arguments::Zero,
+ add("--debug",
+ "-d",
+ "Print debug information to stderr",
+ Arguments::Zero,
[&](Options* o, const std::string& arguments) { debug = true; });
}
Options::~Options() {}
-Options& Options::add(const std::string& longName, const std::string& shortName,
- const std::string& description, Arguments arguments,
+Options& Options::add(const std::string& longName,
+ const std::string& shortName,
+ const std::string& description,
+ Arguments arguments,
const Action& action) {
options.push_back({longName, shortName, description, arguments, action, 0});
return *this;
}
-Options& Options::add_positional(const std::string& name, Arguments arguments,
+Options& Options::add_positional(const std::string& name,
+ Arguments arguments,
const Action& action) {
positional = arguments;
positionalName = name;
@@ -98,7 +109,8 @@ void Options::parse(int argc, const char* argv[]) {
size_t positionalsSeen = 0;
auto dashes = [](const std::string& s) {
for (size_t i = 0;; ++i) {
- if (s[i] != '-') return i;
+ if (s[i] != '-')
+ return i;
}
};
for (size_t i = 1, e = argc; i != e; ++i) {
@@ -169,7 +181,8 @@ void Options::parse(int argc, const char* argv[]) {
break;
case Arguments::Optional:
if (!argument.size()) {
- if (i + 1 != e) argument = argv[++i];
+ if (i + 1 != e)
+ argument = argv[++i];
}
break;
}
diff --git a/src/support/command-line.h b/src/support/command-line.h
index de773bfa8..82193244e 100644
--- a/src/support/command-line.h
+++ b/src/support/command-line.h
@@ -29,12 +29,11 @@
#include "wasm.h"
-
namespace wasm {
class Options {
- public:
- using Action = std::function<void(Options *, const std::string& )>;
+public:
+ using Action = std::function<void(Options*, const std::string&)>;
enum class Arguments { Zero, One, N, Optional };
bool debug;
@@ -42,17 +41,20 @@ class Options {
Options(const std::string& command, const std::string& description);
~Options();
- Options &add(const std::string& longName, const std::string& shortName,
- const std::string& description, Arguments arguments,
+ Options& add(const std::string& longName,
+ const std::string& shortName,
+ const std::string& description,
+ Arguments arguments,
const Action& action);
- Options &add_positional(const std::string& name, Arguments arguments,
- const Action &action);
- void parse(int argc, const char *argv[]);
+ Options& add_positional(const std::string& name,
+ Arguments arguments,
+ const Action& action);
+ void parse(int argc, const char* argv[]);
- private:
+private:
Options() = delete;
- Options(const Options &) = delete;
- Options &operator=(const Options &) = delete;
+ Options(const Options&) = delete;
+ Options& operator=(const Options&) = delete;
struct Option {
std::string longName;
@@ -68,6 +70,6 @@ class Options {
Action positionalAction;
};
-} // namespace wasm
+} // namespace wasm
#endif // wasm_support_command_line_h
diff --git a/src/support/file.cpp b/src/support/file.cpp
index c10646720..3af7af44b 100644
--- a/src/support/file.cpp
+++ b/src/support/file.cpp
@@ -16,13 +16,14 @@
#include "support/file.h"
-#include <iostream>
-#include <cstdlib>
#include <cstdint>
+#include <cstdlib>
+#include <iostream>
#include <limits>
std::vector<char> wasm::read_stdin(Flags::DebugOption debug) {
- if (debug == Flags::Debug) std::cerr << "Loading stdin..." << std::endl;
+ if (debug == Flags::Debug)
+ std::cerr << "Loading stdin..." << std::endl;
std::vector<char> input;
char c;
while (std::cin.get(c) && !std::cin.eof()) {
@@ -31,13 +32,16 @@ std::vector<char> wasm::read_stdin(Flags::DebugOption debug) {
return input;
}
-
template<typename T>
-T wasm::read_file(const std::string& filename, Flags::BinaryOption binary, Flags::DebugOption debug) {
- if (debug == Flags::Debug) std::cerr << "Loading '" << filename << "'..." << std::endl;
+T wasm::read_file(const std::string& filename,
+ Flags::BinaryOption binary,
+ Flags::DebugOption debug) {
+ if (debug == Flags::Debug)
+ std::cerr << "Loading '" << filename << "'..." << std::endl;
std::ifstream infile;
std::ios_base::openmode flags = std::ifstream::in;
- if (binary == Flags::Binary) flags |= std::ifstream::binary;
+ if (binary == Flags::Binary)
+ flags |= std::ifstream::binary;
infile.open(filename, flags);
if (!infile.is_open()) {
std::cerr << "Failed opening '" << filename << "'" << std::endl;
@@ -46,47 +50,60 @@ T wasm::read_file(const std::string& filename, Flags::BinaryOption binary, Flags
infile.seekg(0, std::ios::end);
std::streampos insize = infile.tellg();
if (uint64_t(insize) >= std::numeric_limits<size_t>::max()) {
- // Building a 32-bit executable where size_t == 32 bits, we are not able to create strings larger than 2^32 bytes in length, so must abort here.
- std::cerr << "Failed opening '" << filename << "': Input file too large: " << insize << " bytes. Try rebuilding in 64-bit mode." << std::endl;
+ // Building a 32-bit executable where size_t == 32 bits, we are not able to
+ // create strings larger than 2^32 bytes in length, so must abort here.
+ std::cerr << "Failed opening '" << filename
+ << "': Input file too large: " << insize
+ << " bytes. Try rebuilding in 64-bit mode." << std::endl;
exit(EXIT_FAILURE);
}
T input(size_t(insize) + (binary == Flags::Binary ? 0 : 1), '\0');
- if (size_t(insize) == 0) return input;
+ if (size_t(insize) == 0)
+ return input;
infile.seekg(0);
infile.read(&input[0], insize);
if (binary == Flags::Text) {
size_t chars = size_t(infile.gcount());
- input.resize(chars+1); // Truncate size to the number of ASCII characters actually read in text mode (which is generally less than the number of bytes on Windows, if \r\n line endings are present)
+ // Truncate size to the number of ASCII characters actually read in text
+ // mode (which is generally less than the number of bytes on Windows, if
+ // \r\n line endings are present)
+ input.resize(chars + 1);
input[chars] = '\0';
}
return input;
}
// Explicit instantiations for the explicit specializations.
-template std::string wasm::read_file<>(const std::string& , Flags::BinaryOption, Flags::DebugOption);
-template std::vector<char> wasm::read_file<>(const std::string& , Flags::BinaryOption, Flags::DebugOption);
+template std::string
+wasm::read_file<>(const std::string&, Flags::BinaryOption, Flags::DebugOption);
+template std::vector<char>
+wasm::read_file<>(const std::string&, Flags::BinaryOption, Flags::DebugOption);
-wasm::Output::Output(const std::string& filename, Flags::BinaryOption binary, Flags::DebugOption debug)
- : outfile(), out([this, filename, binary, debug]() {
- if (filename == "-") {
- return std::cout.rdbuf();
- }
- std::streambuf *buffer;
- if (filename.size()) {
- if (debug == Flags::Debug) std::cerr << "Opening '" << filename << "'" << std::endl;
- auto flags = std::ofstream::out | std::ofstream::trunc;
- if (binary == Flags::Binary) flags |= std::ofstream::binary;
- outfile.open(filename, flags);
- if (!outfile.is_open()) {
- std::cerr << "Failed opening '" << filename << "'" << std::endl;
- exit(EXIT_FAILURE);
- }
- buffer = outfile.rdbuf();
- } else {
- buffer = std::cout.rdbuf();
+wasm::Output::Output(const std::string& filename,
+ Flags::BinaryOption binary,
+ Flags::DebugOption debug)
+ : outfile(), out([this, filename, binary, debug]() {
+ if (filename == "-") {
+ return std::cout.rdbuf();
+ }
+ std::streambuf* buffer;
+ if (filename.size()) {
+ if (debug == Flags::Debug)
+ std::cerr << "Opening '" << filename << "'" << std::endl;
+ auto flags = std::ofstream::out | std::ofstream::trunc;
+ if (binary == Flags::Binary)
+ flags |= std::ofstream::binary;
+ outfile.open(filename, flags);
+ if (!outfile.is_open()) {
+ std::cerr << "Failed opening '" << filename << "'" << std::endl;
+ exit(EXIT_FAILURE);
}
- return buffer;
- }()) {}
+ buffer = outfile.rdbuf();
+ } else {
+ buffer = std::cout.rdbuf();
+ }
+ return buffer;
+ }()) {}
void wasm::copy_file(std::string input, std::string output) {
std::ifstream src(input, std::ios::binary);
diff --git a/src/support/file.h b/src/support/file.h
index cb9c82ca9..67d63315b 100644
--- a/src/support/file.h
+++ b/src/support/file.h
@@ -29,46 +29,41 @@
namespace wasm {
namespace Flags {
- enum BinaryOption {
- Binary,
- Text
- };
- enum DebugOption {
- Debug,
- Release
- };
-}
+enum BinaryOption { Binary, Text };
+enum DebugOption { Debug, Release };
+} // namespace Flags
std::vector<char> read_stdin(Flags::DebugOption);
template<typename T>
-T read_file(const std::string& filename, Flags::BinaryOption binary, Flags::DebugOption debug);
+T read_file(const std::string& filename,
+ Flags::BinaryOption binary,
+ Flags::DebugOption debug);
// Declare the valid explicit specializations.
-extern template std::string read_file<>(const std::string& , Flags::BinaryOption, Flags::DebugOption);
-extern template std::vector<char> read_file<>(const std::string& , Flags::BinaryOption, Flags::DebugOption);
+extern template std::string
+read_file<>(const std::string&, Flags::BinaryOption, Flags::DebugOption);
+extern template std::vector<char>
+read_file<>(const std::string&, Flags::BinaryOption, Flags::DebugOption);
class Output {
- public:
+public:
// An empty filename will open stdout instead.
- Output(const std::string& filename, Flags::BinaryOption binary, Flags::DebugOption debug);
+ Output(const std::string& filename,
+ Flags::BinaryOption binary,
+ Flags::DebugOption debug);
~Output() = default;
- template<typename T>
- std::ostream &operator<<(const T &v) {
- return out << v;
- }
+ template<typename T> std::ostream& operator<<(const T& v) { return out << v; }
- std::ostream& getStream() {
- return out;
- }
+ std::ostream& getStream() { return out; }
std::ostream& write(const char* s, std::streamsize c) {
return out.write(s, c);
}
- private:
+private:
Output() = delete;
- Output(const Output &) = delete;
- Output &operator=(const Output &) = delete;
+ Output(const Output&) = delete;
+ Output& operator=(const Output&) = delete;
std::ofstream outfile;
std::ostream out;
};
@@ -81,4 +76,4 @@ size_t file_size(std::string filename);
} // namespace wasm
-#endif // wasm_support_file_h
+#endif // wasm_support_file_h
diff --git a/src/support/hash.h b/src/support/hash.h
index 98d7ceead..647369ac8 100644
--- a/src/support/hash.h
+++ b/src/support/hash.h
@@ -25,7 +25,8 @@ namespace wasm {
typedef uint32_t HashType;
inline HashType rehash(HashType x, HashType y) {
- // see http://www.cse.yorku.ca/~oz/hash.html and https://stackoverflow.com/a/2595226/1176841
+ // see http://www.cse.yorku.ca/~oz/hash.html and
+ // https://stackoverflow.com/a/2595226/1176841
HashType hash = 5381;
while (x) {
hash = ((hash << 5) + hash) ^ (x & 0xff);
diff --git a/src/support/json.h b/src/support/json.h
index 7ffa1211f..8f2edc04d 100644
--- a/src/support/json.h
+++ b/src/support/json.h
@@ -50,12 +50,8 @@ struct Value {
Ref() = default;
Ref(Value* value) : std::shared_ptr<Value>(value) {}
- Ref& operator[](size_t x) {
- return (*this->get())[x];
- }
- Ref& operator[](IString x) {
- return (*this->get())[x];
- }
+ Ref& operator[](size_t x) { return (*this->get())[x]; }
+ Ref& operator[](IString x) { return (*this->get())[x]; }
};
enum Type {
@@ -72,7 +68,9 @@ struct Value {
typedef std::vector<Ref> ArrayStorage;
typedef std::unordered_map<IString, Ref> ObjectStorage;
-#ifdef _MSC_VER // MSVC does not allow unrestricted unions: http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2544.pdf
+ // MSVC does not allow unrestricted unions:
+ // http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2544.pdf
+#ifdef _MSC_VER
IString str;
#endif
union { // TODO: optimize
@@ -80,29 +78,24 @@ struct Value {
IString str;
#endif
double num = 0;
- ArrayStorage *arr; // manually allocated/freed
+ ArrayStorage* arr; // manually allocated/freed
bool boo;
- ObjectStorage *obj; // manually allocated/freed
+ ObjectStorage* obj; // manually allocated/freed
Ref ref;
};
// constructors all copy their input
Value() {}
- explicit Value(const char *s) : type(Null) {
- setString(s);
- }
- explicit Value(double n) : type(Null) {
- setNumber(n);
- }
- explicit Value(ArrayStorage &a) : type(Null) {
+ explicit Value(const char* s) : type(Null) { setString(s); }
+ explicit Value(double n) : type(Null) { setNumber(n); }
+ explicit Value(ArrayStorage& a) : type(Null) {
setArray();
*arr = a;
}
- // no bool constructor - would endanger the double one (int might convert the wrong way)
+ // no bool constructor - would endanger the double one (int might convert the
+ // wrong way)
- ~Value() {
- free();
- }
+ ~Value() { free(); }
void free() {
if (type == Array) {
@@ -116,13 +109,13 @@ struct Value {
num = 0;
}
- Value& setString(const char *s) {
+ Value& setString(const char* s) {
free();
type = String;
str.set(s);
return *this;
}
- Value& setString(const IString &s) {
+ Value& setString(const IString& s) {
free();
type = String;
str.set(s);
@@ -134,14 +127,14 @@ struct Value {
num = n;
return *this;
}
- Value& setArray(ArrayStorage &a) {
+ Value& setArray(ArrayStorage& a) {
free();
type = Array;
arr = new ArrayStorage;
*arr = a;
return *this;
}
- Value& setArray(size_t size_hint=0) {
+ Value& setArray(size_t size_hint = 0) {
free();
type = Array;
arr = new ArrayStorage;
@@ -153,7 +146,8 @@ struct Value {
type = Null;
return *this;
}
- Value& setBool(bool b) { // Bool in the name, as otherwise might overload over int
+ Value&
+ setBool(bool b) { // Bool in the name, as otherwise might overload over int
free();
type = Bool;
boo = b;
@@ -168,12 +162,14 @@ struct Value {
bool isString() { return type == String; }
bool isNumber() { return type == Number; }
- bool isArray() { return type == Array; }
- bool isNull() { return type == Null; }
- bool isBool() { return type == Bool; }
+ bool isArray() { return type == Array; }
+ bool isNull() { return type == Null; }
+ bool isBool() { return type == Bool; }
bool isObject() { return type == Object; }
- bool isBool(bool b) { return type == Bool && b == boo; } // avoid overloading == as it might overload over int
+ bool isBool(bool b) {
+ return type == Bool && b == boo;
+ } // avoid overloading == as it might overload over int
const char* getCString() {
assert(isString());
@@ -228,7 +224,8 @@ struct Value {
}
bool operator==(const Value& other) {
- if (type != other.type) return false;
+ if (type != other.type)
+ return false;
switch (other.type) {
case String:
return str == other.str;
@@ -249,17 +246,23 @@ struct Value {
}
char* parse(char* curr) {
- #define is_json_space(x) (x == 32 || x == 9 || x == 10 || x == 13) /* space, tab, linefeed/newline, or return */
- #define skip() { while (*curr && is_json_space(*curr)) curr++; }
+#define is_json_space(x) \
+ (x == 32 || x == 9 || x == 10 || \
+ x == 13) /* space, tab, linefeed/newline, or return */
+#define skip() \
+ { \
+ while (*curr && is_json_space(*curr)) \
+ curr++; \
+ }
skip();
if (*curr == '"') {
// String
curr++;
- char *close = strchr(curr, '"');
+ char* close = strchr(curr, '"');
assert(close);
*close = 0; // end this string, and reuse it straight from the input
setString(curr);
- curr = close+1;
+ curr = close + 1;
} else if (*curr == '[') {
// Array
curr++;
@@ -270,7 +273,8 @@ struct Value {
arr->push_back(temp);
curr = temp->parse(curr);
skip();
- if (*curr == ']') break;
+ if (*curr == ']')
+ break;
assert(*curr == ',');
curr++;
skip();
@@ -299,11 +303,11 @@ struct Value {
while (*curr != '}') {
assert(*curr == '"');
curr++;
- char *close = strchr(curr, '"');
+ char* close = strchr(curr, '"');
assert(close);
*close = 0; // end this string, and reuse it straight from the input
IString key(curr);
- curr = close+1;
+ curr = close + 1;
skip();
assert(*curr == ':');
curr++;
@@ -312,7 +316,8 @@ struct Value {
curr = value->parse(curr);
(*obj)[key] = value;
skip();
- if (*curr == '}') break;
+ if (*curr == '}')
+ break;
assert(*curr == ',');
curr++;
skip();
@@ -320,14 +325,14 @@ struct Value {
curr++;
} else {
// Number
- char *after;
+ char* after;
setNumber(strtod(curr, &after));
curr = after;
}
return curr;
}
- void stringify(std::ostream &os, bool pretty=false);
+ void stringify(std::ostream& os, bool pretty = false);
// String operations
@@ -343,7 +348,8 @@ struct Value {
void setSize(size_t size) {
assert(isArray());
auto old = arr->size();
- if (old != size) arr->resize(size);
+ if (old != size)
+ arr->resize(size);
if (old < size) {
for (auto i = old; i < size; i++) {
(*arr)[i] = Ref(new Value());
@@ -370,7 +376,8 @@ struct Value {
Ref back() {
assert(isArray());
- if (arr->size() == 0) return nullptr;
+ if (arr->size() == 0)
+ return nullptr;
return arr->back();
}
diff --git a/src/support/learning.h b/src/support/learning.h
index 8427a2362..0cdd4e929 100644
--- a/src/support/learning.h
+++ b/src/support/learning.h
@@ -33,7 +33,8 @@ namespace wasm {
// The Generator must implement the following:
//
// * Genome* makeRandom(); - make a random element
-// * Genome* makeMixture(Genome* one, Genome* two); - make a new element by mixing two
+// * Genome* makeMixture(Genome* one, Genome* two); - make a new element by
+// mixing two
//
// Fitness is the type of the fitness values, e.g. uint32_t. More is better.
//
@@ -51,19 +52,20 @@ class GeneticLearner {
std::vector<unique_ptr> population;
void sort() {
- std::sort(population.begin(), population.end(), [](const unique_ptr& left, const unique_ptr& right) {
- return left->getFitness() > right->getFitness();
- });
+ std::sort(population.begin(),
+ population.end(),
+ [](const unique_ptr& left, const unique_ptr& right) {
+ return left->getFitness() > right->getFitness();
+ });
}
std::mt19937 noise;
- size_t randomIndex() {
- return noise() % population.size();
- }
+ size_t randomIndex() { return noise() % population.size(); }
public:
- GeneticLearner(Generator& generator, size_t size) : generator(generator), noise(1337) {
+ GeneticLearner(Generator& generator, size_t size)
+ : generator(generator), noise(1337) {
population.resize(size);
for (size_t i = 0; i < size; i++) {
population[i] = unique_ptr(generator.makeRandom());
@@ -71,27 +73,26 @@ public:
sort();
}
- Genome* getBest() {
- return population[0].get();
- }
+ Genome* getBest() { return population[0].get(); }
- unique_ptr acquireBest() {
- return population[0];
- }
+ unique_ptr acquireBest() { return population[0]; }
void runGeneration() {
size_t size = population.size();
- // we have a mix of promoted from the last generation, mixed from the last generation, and random
+ // we have a mix of promoted from the last generation, mixed from the last
+ // generation, and random
const size_t promoted = (25 * size) / 100;
const size_t mixed = (50 * size) / 100;
// promoted just stay in place
- // mixtures are computed, then added back in (as we still need them as we work)
+ // mixtures are computed, then added back in (as we still need them as we
+ // work)
std::vector<unique_ptr> mixtures;
mixtures.resize(mixed);
for (size_t i = 0; i < mixed; i++) {
- mixtures[i] = unique_ptr(generator.makeMixture(population[randomIndex()].get(), population[randomIndex()].get()));
+ mixtures[i] = unique_ptr(generator.makeMixture(
+ population[randomIndex()].get(), population[randomIndex()].get()));
}
for (size_t i = 0; i < mixed; i++) {
population[promoted + i].swap(mixtures[i]);
@@ -106,6 +107,6 @@ public:
}
};
-} // namespace wasm
+} // namespace wasm
-#endif // wasm_learning_h
+#endif // wasm_learning_h
diff --git a/src/support/name.h b/src/support/name.h
index 0a745b2f7..6f17c3ebf 100644
--- a/src/support/name.h
+++ b/src/support/name.h
@@ -41,7 +41,8 @@ struct Name : public cashew::IString {
friend std::ostream& operator<<(std::ostream& o, Name name) {
if (name.str) {
- return o << '$' << name.str; // reference interpreter requires we prefix all names
+ // reference interpreter requires we prefix all names
+ return o << '$' << name.str;
} else {
return o << "(null Name)";
}
@@ -64,5 +65,4 @@ template<> struct hash<wasm::Name> : hash<cashew::IString> {};
} // namespace std
-
#endif // wasm_support_string_h
diff --git a/src/support/path.cpp b/src/support/path.cpp
index 322099a95..7ae68d719 100644
--- a/src/support/path.cpp
+++ b/src/support/path.cpp
@@ -27,7 +27,7 @@ namespace Path {
std::string getPathSeparator() {
// TODO: use c++17's path separator
// http://en.cppreference.com/w/cpp/experimental/fs/path
-#if defined(WIN32) || defined(_WIN32)
+#if defined(WIN32) || defined(_WIN32)
return "\\";
#else
return "/";
@@ -36,7 +36,8 @@ std::string getPathSeparator() {
std::string getBinaryenRoot() {
auto* envVar = getenv("BINARYEN_ROOT");
- if (envVar) return envVar;
+ if (envVar)
+ return envVar;
return ".";
}
@@ -50,9 +51,7 @@ std::string getBinaryenBinDir() {
}
}
-void setBinaryenBinDir(std::string dir) {
- binDir = dir;
-}
+void setBinaryenBinDir(std::string dir) { binDir = dir; }
// Gets the path to a binaryen binary tool, like wasm-opt
std::string getBinaryenBinaryTool(std::string name) {
@@ -62,4 +61,3 @@ std::string getBinaryenBinaryTool(std::string name) {
} // namespace Path
} // namespace wasm
-
diff --git a/src/support/safe_integer.cpp b/src/support/safe_integer.cpp
index ca5052cd2..23ef84b22 100644
--- a/src/support/safe_integer.cpp
+++ b/src/support/safe_integer.cpp
@@ -35,17 +35,18 @@ bool wasm::isSInteger32(double x) {
}
uint32_t wasm::toUInteger32(double x) {
- return std::signbit(x) ? 0 : (x < std::numeric_limits<uint32_t>::max()
- ? (uint32_t)x
- : std::numeric_limits<uint32_t>::max());
+ return std::signbit(x) ? 0
+ : (x < std::numeric_limits<uint32_t>::max()
+ ? (uint32_t)x
+ : std::numeric_limits<uint32_t>::max());
}
int32_t wasm::toSInteger32(double x) {
return (x > std::numeric_limits<int32_t>::min() &&
x < std::numeric_limits<int32_t>::max())
- ? (int32_t)x
- : (std::signbit(x) ? std::numeric_limits<int32_t>::min()
- : std::numeric_limits<int32_t>::max());
+ ? (int32_t)x
+ : (std::signbit(x) ? std::numeric_limits<int32_t>::min()
+ : std::numeric_limits<int32_t>::max());
}
bool wasm::isUInteger64(double x) {
@@ -59,17 +60,18 @@ bool wasm::isSInteger64(double x) {
}
uint64_t wasm::toUInteger64(double x) {
- return std::signbit(x) ? 0 : (x < (double)std::numeric_limits<uint64_t>::max()
- ? (uint64_t)x
- : std::numeric_limits<uint64_t>::max());
+ return std::signbit(x) ? 0
+ : (x < (double)std::numeric_limits<uint64_t>::max()
+ ? (uint64_t)x
+ : std::numeric_limits<uint64_t>::max());
}
int64_t wasm::toSInteger64(double x) {
return (x > (double)std::numeric_limits<int64_t>::min() &&
x < (double)std::numeric_limits<int64_t>::max())
- ? (int64_t)x
- : (std::signbit(x) ? std::numeric_limits<int64_t>::min()
- : std::numeric_limits<int64_t>::max());
+ ? (int64_t)x
+ : (std::signbit(x) ? std::numeric_limits<int64_t>::min()
+ : std::numeric_limits<int64_t>::max());
}
/* 3 32222222 222...00
@@ -116,6 +118,7 @@ bool wasm::isInRangeI64TruncU(int32_t i) {
return (u < 0x5f800000U) || (u >= 0x80000000U && u < 0xbf800000U);
}
+/* clang-format off */
/*
* 6 66655555555 5544...222221...000
* 3 21098765432 1098...432109...210
@@ -139,6 +142,7 @@ bool wasm::isInRangeI64TruncU(int32_t i) {
* 1 11111111111 0000...000000...001 0xfff0000000000001 => -nan(0x1)
* 1 11111111111 1111...111111...111 0xffffffffffffffff => -nan(0xfff...)
*/
+/* clang-format on */
bool wasm::isInRangeI32TruncS(int64_t i) {
uint64_t u = i;
diff --git a/src/support/safe_integer.h b/src/support/safe_integer.h
index 5bd807a18..031c6c323 100644
--- a/src/support/safe_integer.h
+++ b/src/support/safe_integer.h
@@ -41,6 +41,6 @@ bool isInRangeI32TruncU(int64_t i);
bool isInRangeI64TruncS(int64_t i);
bool isInRangeI64TruncU(int64_t i);
-} // namespace wasm
+} // namespace wasm
-#endif // wasm_safe_integer_h
+#endif // wasm_safe_integer_h
diff --git a/src/support/small_vector.h b/src/support/small_vector.h
index e746700bf..dd6afb526 100644
--- a/src/support/small_vector.h
+++ b/src/support/small_vector.h
@@ -29,8 +29,7 @@
namespace wasm {
-template<typename T, size_t N>
-class SmallVector {
+template<typename T, size_t N> class SmallVector {
// fixed-space storage
size_t usedFixed = 0;
std::array<T, N> fixed;
@@ -65,10 +64,9 @@ public:
}
}
- template <typename... ArgTypes>
- void emplace_back(ArgTypes &&... Args) {
+ template<typename... ArgTypes> void emplace_back(ArgTypes&&... Args) {
if (usedFixed < N) {
- new(&fixed[usedFixed++]) T(std::forward<ArgTypes>(Args)...);
+ new (&fixed[usedFixed++]) T(std::forward<ArgTypes>(Args)...);
} else {
flexible.emplace_back(std::forward<ArgTypes>(Args)...);
}
@@ -101,13 +99,9 @@ public:
}
}
- size_t size() const {
- return usedFixed + flexible.size();
- }
+ size_t size() const { return usedFixed + flexible.size(); }
- bool empty() const {
- return size() == 0;
- }
+ bool empty() const { return size() == 0; }
void clear() {
usedFixed = 0;
@@ -115,9 +109,11 @@ public:
}
bool operator==(const SmallVector<T, N>& other) const {
- if (usedFixed != other.usedFixed) return false;
+ if (usedFixed != other.usedFixed)
+ return false;
for (size_t i = 0; i < usedFixed; i++) {
- if (fixed[i] != other.fixed[i]) return false;
+ if (fixed[i] != other.fixed[i])
+ return false;
}
return flexible == other.flexible;
}
@@ -136,15 +132,14 @@ public:
const SmallVector<T, N>* parent;
size_t index;
- Iterator(const SmallVector<T, N>* parent, size_t index) : parent(parent), index(index) {}
+ Iterator(const SmallVector<T, N>* parent, size_t index)
+ : parent(parent), index(index) {}
bool operator!=(const Iterator& other) const {
return index != other.index || parent != other.parent;
}
- void operator++() {
- index++;
- }
+ void operator++() { index++; }
Iterator& operator+=(difference_type off) {
index += off;
@@ -155,9 +150,7 @@ public:
return Iterator(*this) += off;
}
- const value_type operator*() const {
- return (*parent)[index];
- }
+ const value_type operator*() const { return (*parent)[index]; }
};
Iterator begin() const {
diff --git a/src/support/sorted_vector.h b/src/support/sorted_vector.h
index da991ce78..e26d5e3af 100644
--- a/src/support/sorted_vector.h
+++ b/src/support/sorted_vector.h
@@ -61,7 +61,8 @@ struct SortedVector : public std::vector<Index> {
void insert(Index x) {
auto it = std::lower_bound(begin(), end(), x);
- if (it == end()) push_back(x);
+ if (it == end())
+ push_back(x);
else if (*it > x) {
Index i = it - begin();
resize(size() + 1);
@@ -85,8 +86,7 @@ struct SortedVector : public std::vector<Index> {
return it != end() && *it == x;
}
- template<typename T>
- SortedVector& filter(T keep) {
+ template<typename T> SortedVector& filter(T keep) {
size_t skip = 0;
for (size_t i = 0; i < size(); i++) {
if (keep((*this)[i])) {
@@ -107,7 +107,8 @@ struct SortedVector : public std::vector<Index> {
void dump(const char* str = nullptr) const {
std::cout << "SortedVector " << (str ? str : "") << ": ";
- for (auto x : *this) std::cout << x << " ";
+ for (auto x : *this)
+ std::cout << x << " ";
std::cout << '\n';
}
};
diff --git a/src/support/threads.cpp b/src/support/threads.cpp
index 7ae304c4f..785994b4e 100644
--- a/src/support/threads.cpp
+++ b/src/support/threads.cpp
@@ -20,23 +20,29 @@
#include <iostream>
#include <string>
-#include "threads.h"
#include "compiler-support.h"
+#include "threads.h"
#include "utilities.h"
-
// debugging tools
#ifdef BINARYEN_THREAD_DEBUG
static std::mutex debug;
-#define DEBUG_THREAD(x) { std::lock_guard<std::mutex> lock(debug); std::cerr << "[THREAD " << std::this_thread::get_id() << "] " << x; }
-#define DEBUG_POOL(x) { std::lock_guard<std::mutex> lock(debug); std::cerr << "[POOL " << std::this_thread::get_id() << "] " << x; }
+#define DEBUG_THREAD(x) \
+ { \
+ std::lock_guard<std::mutex> lock(debug); \
+ std::cerr << "[THREAD " << std::this_thread::get_id() << "] " << x; \
+ }
+#define DEBUG_POOL(x) \
+ { \
+ std::lock_guard<std::mutex> lock(debug); \
+ std::cerr << "[POOL " << std::this_thread::get_id() << "] " << x; \
+ }
#else
#define DEBUG_THREAD(x)
#define DEBUG_POOL(x)
#endif
-
namespace wasm {
// Thread
@@ -56,7 +62,7 @@ Thread::~Thread() {
thread->join();
}
-void Thread::work(std::function<ThreadWorkState ()> doWork_) {
+void Thread::work(std::function<ThreadWorkState()> doWork_) {
// TODO: fancy work stealing
DEBUG_THREAD("send work to thread\n");
{
@@ -68,7 +74,7 @@ void Thread::work(std::function<ThreadWorkState ()> doWork_) {
}
}
-void Thread::mainLoop(void *self_) {
+void Thread::mainLoop(void* self_) {
auto* self = static_cast<Thread*>(self_);
while (1) {
DEBUG_THREAD("checking for work\n");
@@ -77,7 +83,8 @@ void Thread::mainLoop(void *self_) {
if (self->doWork) {
DEBUG_THREAD("doing work\n");
// run tasks until they are all done
- while (self->doWork() == ThreadWorkState::More) {}
+ while (self->doWork() == ThreadWorkState::More) {
+ }
self->doWork = nullptr;
} else if (self->done) {
DEBUG_THREAD("done\n");
@@ -107,16 +114,19 @@ std::mutex ThreadPool::workMutex;
std::mutex ThreadPool::threadMutex;
void ThreadPool::initialize(size_t num) {
- if (num == 1) return; // no multiple cores, don't create threads
+ if (num == 1)
+ return; // no multiple cores, don't create threads
DEBUG_POOL("initialize()\n");
std::unique_lock<std::mutex> lock(threadMutex);
- ready.store(threads.size()); // initial state before first resetThreadsAreReady()
+ // initial state before first resetThreadsAreReady()
+ ready.store(threads.size());
resetThreadsAreReady();
for (size_t i = 0; i < num; i++) {
try {
threads.emplace_back(make_unique<Thread>(this));
} catch (std::system_error&) {
- // failed to create a thread - don't use multithreading, as if num cores == 1
+ // failed to create a thread - don't use multithreading, as if num cores
+ // == 1
DEBUG_POOL("could not create thread\n");
threads.clear();
return;
@@ -154,14 +164,16 @@ ThreadPool* ThreadPool::get() {
return pool.get();
}
-void ThreadPool::work(std::vector<std::function<ThreadWorkState ()>>& doWorkers) {
+void ThreadPool::work(
+ std::vector<std::function<ThreadWorkState()>>& doWorkers) {
size_t num = threads.size();
// If no multiple cores, or on a side thread, do not use worker threads
if (num == 0) {
// just run sequentially
DEBUG_POOL("work() sequentially\n");
assert(doWorkers.size() > 0);
- while (doWorkers[0]() == ThreadWorkState::More) {}
+ while (doWorkers[0]() == ThreadWorkState::More) {
+ }
return;
}
// run in parallel on threads
@@ -187,9 +199,7 @@ void ThreadPool::work(std::vector<std::function<ThreadWorkState ()>>& doWorkers)
DEBUG_POOL("work() is done\n");
}
-size_t ThreadPool::size() {
- return std::max(size_t(1), threads.size());
-}
+size_t ThreadPool::size() { return std::max(size_t(1), threads.size()); }
bool ThreadPool::isRunning() {
DEBUG_POOL("check if running\n");
@@ -216,4 +226,3 @@ bool ThreadPool::areThreadsReady() {
}
} // namespace wasm
-
diff --git a/src/support/threads.h b/src/support/threads.h
index e76783ebb..8cfa79c87 100644
--- a/src/support/threads.h
+++ b/src/support/threads.h
@@ -33,10 +33,7 @@ namespace wasm {
// The work state of a helper thread - is there more to do,
// or are we finished for now.
-enum class ThreadWorkState {
- More,
- Finished
-};
+enum class ThreadWorkState { More, Finished };
class ThreadPool;
@@ -52,7 +49,7 @@ class Thread {
std::mutex mutex;
std::condition_variable condition;
bool done = false;
- std::function<ThreadWorkState ()> doWork = nullptr;
+ std::function<ThreadWorkState()> doWork = nullptr;
public:
Thread(ThreadPool* parent);
@@ -60,10 +57,10 @@ public:
// Start to do work, calling doWork() until
// it returns false.
- void work(std::function<ThreadWorkState ()> doWork);
+ void work(std::function<ThreadWorkState()> doWork);
private:
- static void mainLoop(void *self);
+ static void mainLoop(void* self);
};
//
@@ -100,7 +97,7 @@ public:
// getTask() (in a thread-safe manner) to get tasks, and
// sends them to workers to be executed. This method
// blocks until all tasks are complete.
- void work(std::vector<std::function<ThreadWorkState ()>>& doWorkers);
+ void work(std::vector<std::function<ThreadWorkState()>>& doWorkers);
size_t size();
@@ -123,9 +120,7 @@ class OnlyOnce {
std::atomic<int> created;
public:
- OnlyOnce() {
- created.store(0);
- }
+ OnlyOnce() { created.store(0); }
void verify() {
auto before = created.fetch_add(1);
@@ -135,4 +130,4 @@ public:
} // namespace wasm
-#endif // wasm_support_threads_h
+#endif // wasm_support_threads_h
diff --git a/src/support/timing.h b/src/support/timing.h
index a8de8de04..0b0430e24 100644
--- a/src/support/timing.h
+++ b/src/support/timing.h
@@ -33,23 +33,19 @@ class Timer {
public:
Timer(std::string name = "") : name(name) {}
- void start() {
- startTime = std::chrono::steady_clock::now();
- }
+ void start() { startTime = std::chrono::steady_clock::now(); }
void stop() {
- total += std::chrono::duration<double>(std::chrono::steady_clock::now() - startTime).count();
+ total += std::chrono::duration<double>(std::chrono::steady_clock::now() -
+ startTime)
+ .count();
}
- double getTotal() {
- return total;
- }
+ double getTotal() { return total; }
- void dump() {
- std::cerr << "<Timer " << name << ": " << getTotal() << ">\n";
- }
+ void dump() { std::cerr << "<Timer " << name << ": " << getTotal() << ">\n"; }
};
} // namespace wasm
-#endif // wasm_support_timing_h
+#endif // wasm_support_timing_h
diff --git a/src/support/unique_deferring_queue.h b/src/support/unique_deferring_queue.h
index eb024e5b8..ad8f3967d 100644
--- a/src/support/unique_deferring_queue.h
+++ b/src/support/unique_deferring_queue.h
@@ -28,8 +28,7 @@
namespace wasm {
-template<typename T>
-struct UniqueDeferredQueue {
+template<typename T> struct UniqueDeferredQueue {
// implemented as an internal queue, plus a map
// that says how many times an element appears. we
// can then skip non-final appearances. this lets us
diff --git a/src/support/utilities.h b/src/support/utilities.h
index 07a163ef9..71d8ce2e0 100644
--- a/src/support/utilities.h
+++ b/src/support/utilities.h
@@ -22,8 +22,8 @@
#include <cassert>
#include <cstdint>
#include <cstring>
-#include <memory>
#include <iostream>
+#include <memory>
#include <type_traits>
#include "support/bits.h"
@@ -53,19 +53,15 @@ inline size_t alignAddr(size_t address, size_t alignment) {
}
template<typename T, typename... Args>
-std::unique_ptr<T> make_unique(Args&&... args)
-{
- return std::unique_ptr<T>(new T(std::forward<Args>(args)...));
+std::unique_ptr<T> make_unique(Args&&... args) {
+ return std::unique_ptr<T>(new T(std::forward<Args>(args)...));
}
// For fatal errors which could arise from input (i.e. not assertion failures)
class Fatal {
- public:
- Fatal() {
- std::cerr << "Fatal: ";
- }
- template<typename T>
- Fatal &operator<<(T arg) {
+public:
+ Fatal() { std::cerr << "Fatal: "; }
+ template<typename T> Fatal& operator<<(T arg) {
std::cerr << arg;
return *this;
}
@@ -78,7 +74,6 @@ class Fatal {
}
};
+} // namespace wasm
-} // namespace wasm
-
-#endif // wasm_support_utilities_h
+#endif // wasm_support_utilities_h
diff --git a/src/tools/asm2wasm.cpp b/src/tools/asm2wasm.cpp
index 547bf4ab1..843106ffd 100644
--- a/src/tools/asm2wasm.cpp
+++ b/src/tools/asm2wasm.cpp
@@ -21,21 +21,21 @@
#include <exception>
#include "ir/trapping.h"
+#include "optimization-options.h"
#include "support/colors.h"
#include "support/command-line.h"
#include "support/file.h"
#include "wasm-builder.h"
-#include "wasm-printing.h"
#include "wasm-io.h"
+#include "wasm-printing.h"
#include "wasm-validator.h"
-#include "optimization-options.h"
#include "asm2wasm.h"
using namespace cashew;
using namespace wasm;
-int main(int argc, const char *argv[]) {
+int main(int argc, const char* argv[]) {
bool legalizeJavaScriptFFI = true;
TrapMode trapMode = TrapMode::JS;
bool wasmOnly = false;
@@ -44,81 +44,138 @@ int main(int argc, const char *argv[]) {
std::string symbolMap;
bool emitBinary = true;
- OptimizationOptions options("asm2wasm", "Translate asm.js files to .wast files");
+ OptimizationOptions options("asm2wasm",
+ "Translate asm.js files to .wast files");
options
- .add("--output", "-o", "Output file (stdout if not specified)",
- Options::Arguments::One,
- [](Options *o, const std::string& argument) {
- o->extra["output"] = argument;
- Colors::disable();
- })
- .add("--mapped-globals", "-n", "Mapped globals", Options::Arguments::One,
- [](Options *o, const std::string& argument) {
- std::cerr << "warning: the --mapped-globals/-m option is deprecated (a mapped globals file is no longer needed as we use wasm globals)" << std::endl;
- })
- .add("--mem-init", "-t", "Import a memory initialization file into the output module", Options::Arguments::One,
- [](Options *o, const std::string& argument) {
- o->extra["mem init"] = argument;
- })
- .add("--mem-base", "-mb", "Set the location to write the memory initialization (--mem-init) file (GLOBAL_BASE in emscripten). If not provided, the __memory_base global import is used.", Options::Arguments::One,
- [](Options *o, const std::string& argument) {
- o->extra["mem base"] = argument;
- })
- .add("--mem-max", "-mm", "Set the maximum size of memory in the wasm module (in bytes). -1 means no limit. Without this, TOTAL_MEMORY is used (as it is used for the initial value), or if memory growth is enabled, no limit is set. This overrides both of those.", Options::Arguments::One,
- [](Options *o, const std::string& argument) {
- o->extra["mem max"] = argument;
- })
- .add("--total-memory", "-m", "Total memory size", Options::Arguments::One,
- [](Options *o, const std::string& argument) {
- o->extra["total memory"] = argument;
- })
- .add("--table-max", "-tM", "Set the maximum size of the table. Without this, it is set depending on how many functions are in the module. -1 means no limit", Options::Arguments::One,
- [](Options *o, const std::string& argument) {
- o->extra["table max"] = argument;
- })
- .add("--no-opts", "-n", "Disable optimization passes (deprecated)", Options::Arguments::Zero,
- [](Options *o, const std::string& ) {
- std::cerr << "--no-opts is deprecated (use -O0, etc.)\n";
- })
- .add("--trap-mode", "",
- "Strategy for handling potentially trapping instructions. Valid "
- "values are \"allow\", \"js\", and \"clamp\"",
- Options::Arguments::One,
- [&trapMode](Options *o, const std::string& argument) {
- try {
- trapMode = trapModeFromString(argument);
- } catch (std::invalid_argument& e) {
- std::cerr << "Error: " << e.what() << "\n";
- exit(EXIT_FAILURE);
- }
- })
- .add("--wasm-only", "-w", "Input is in WebAssembly-only format, and not actually valid asm.js", Options::Arguments::Zero,
- [&wasmOnly](Options *o, const std::string& ) {
- wasmOnly = true;
- })
- .add("--no-legalize-javascript-ffi", "-nj", "Do not fully legalize (i64->i32, f32->f64) the imports and exports for interfacing with JS", Options::Arguments::Zero,
- [&legalizeJavaScriptFFI](Options *o, const std::string& ) {
- legalizeJavaScriptFFI = false;
- })
- .add("--debuginfo", "-g", "Emit names section in wasm binary (or full debuginfo in wast)",
- Options::Arguments::Zero,
- [&](Options *o, const std::string& arguments) { options.passOptions.debugInfo = true; })
- .add("--source-map", "-sm", "Emit source map (if using binary output) to the specified file",
- Options::Arguments::One,
- [&sourceMapFilename](Options *o, const std::string& argument) { sourceMapFilename = argument; })
- .add("--source-map-url", "-su", "Use specified string as source map URL",
- Options::Arguments::One,
- [&sourceMapUrl](Options *o, const std::string& argument) { sourceMapUrl = argument; })
- .add("--symbolmap", "-s", "Emit a symbol map (indexes => names)",
- Options::Arguments::One,
- [&](Options *o, const std::string& argument) { symbolMap = argument; })
- .add("--emit-text", "-S", "Emit text instead of binary for the output file",
- Options::Arguments::Zero,
- [&](Options *o, const std::string& argument) { emitBinary = false; })
- .add_positional("INFILE", Options::Arguments::One,
- [](Options *o, const std::string& argument) {
- o->extra["infile"] = argument;
- });
+ .add("--output",
+ "-o",
+ "Output file (stdout if not specified)",
+ Options::Arguments::One,
+ [](Options* o, const std::string& argument) {
+ o->extra["output"] = argument;
+ Colors::disable();
+ })
+ .add(
+ "--mapped-globals",
+ "-n",
+ "Mapped globals",
+ Options::Arguments::One,
+ [](Options* o, const std::string& argument) {
+ std::cerr
+ << "warning: the --mapped-globals/-m option is deprecated (a mapped "
+ "globals file is no longer needed as we use wasm globals)"
+ << std::endl;
+ })
+ .add("--mem-init",
+ "-t",
+ "Import a memory initialization file into the output module",
+ Options::Arguments::One,
+ [](Options* o, const std::string& argument) {
+ o->extra["mem init"] = argument;
+ })
+ .add("--mem-base",
+ "-mb",
+ "Set the location to write the memory initialization (--mem-init) "
+ "file (GLOBAL_BASE in emscripten). If not provided, the __memory_base "
+ "global import is used.",
+ Options::Arguments::One,
+ [](Options* o, const std::string& argument) {
+ o->extra["mem base"] = argument;
+ })
+ .add("--mem-max",
+ "-mm",
+ "Set the maximum size of memory in the wasm module (in bytes). -1 "
+ "means no limit. Without this, TOTAL_MEMORY is used (as it is used "
+ "for the initial value), or if memory growth is enabled, no limit is "
+ "set. This overrides both of those.",
+ Options::Arguments::One,
+ [](Options* o, const std::string& argument) {
+ o->extra["mem max"] = argument;
+ })
+ .add("--total-memory",
+ "-m",
+ "Total memory size",
+ Options::Arguments::One,
+ [](Options* o, const std::string& argument) {
+ o->extra["total memory"] = argument;
+ })
+ .add("--table-max",
+ "-tM",
+ "Set the maximum size of the table. Without this, it is set depending "
+ "on how many functions are in the module. -1 means no limit",
+ Options::Arguments::One,
+ [](Options* o, const std::string& argument) {
+ o->extra["table max"] = argument;
+ })
+ .add("--no-opts",
+ "-n",
+ "Disable optimization passes (deprecated)",
+ Options::Arguments::Zero,
+ [](Options* o, const std::string&) {
+ std::cerr << "--no-opts is deprecated (use -O0, etc.)\n";
+ })
+ .add("--trap-mode",
+ "",
+ "Strategy for handling potentially trapping instructions. Valid "
+ "values are \"allow\", \"js\", and \"clamp\"",
+ Options::Arguments::One,
+ [&trapMode](Options* o, const std::string& argument) {
+ try {
+ trapMode = trapModeFromString(argument);
+ } catch (std::invalid_argument& e) {
+ std::cerr << "Error: " << e.what() << "\n";
+ exit(EXIT_FAILURE);
+ }
+ })
+ .add("--wasm-only",
+ "-w",
+ "Input is in WebAssembly-only format, and not actually valid asm.js",
+ Options::Arguments::Zero,
+ [&wasmOnly](Options* o, const std::string&) { wasmOnly = true; })
+ .add("--no-legalize-javascript-ffi",
+ "-nj",
+ "Do not fully legalize (i64->i32, f32->f64) the imports and exports "
+ "for interfacing with JS",
+ Options::Arguments::Zero,
+ [&legalizeJavaScriptFFI](Options* o, const std::string&) {
+ legalizeJavaScriptFFI = false;
+ })
+ .add("--debuginfo",
+ "-g",
+ "Emit names section in wasm binary (or full debuginfo in wast)",
+ Options::Arguments::Zero,
+ [&](Options* o, const std::string& arguments) {
+ options.passOptions.debugInfo = true;
+ })
+ .add("--source-map",
+ "-sm",
+ "Emit source map (if using binary output) to the specified file",
+ Options::Arguments::One,
+ [&sourceMapFilename](Options* o, const std::string& argument) {
+ sourceMapFilename = argument;
+ })
+ .add("--source-map-url",
+ "-su",
+ "Use specified string as source map URL",
+ Options::Arguments::One,
+ [&sourceMapUrl](Options* o, const std::string& argument) {
+ sourceMapUrl = argument;
+ })
+ .add("--symbolmap",
+ "-s",
+ "Emit a symbol map (indexes => names)",
+ Options::Arguments::One,
+ [&](Options* o, const std::string& argument) { symbolMap = argument; })
+ .add("--emit-text",
+ "-S",
+ "Emit text instead of binary for the output file",
+ Options::Arguments::Zero,
+ [&](Options* o, const std::string& argument) { emitBinary = false; })
+ .add_positional("INFILE",
+ Options::Arguments::One,
+ [](Options* o, const std::string& argument) {
+ o->extra["infile"] = argument;
+ });
options.parse(argc, argv);
// finalize arguments
@@ -129,32 +186,39 @@ int main(int argc, const char *argv[]) {
if (options.runningDefaultOptimizationPasses()) {
if (options.passes.size() > 1) {
- Fatal() << "asm2wasm can only run default optimization passes (-O, -Ox, etc.), and not specific additional passes";
+ Fatal() << "asm2wasm can only run default optimization passes (-O, -Ox, "
+ "etc.), and not specific additional passes";
}
}
- const auto &tm_it = options.extra.find("total memory");
- size_t totalMemory =
- tm_it == options.extra.end() ? 16 * 1024 * 1024 : atoll(tm_it->second.c_str());
+ const auto& tm_it = options.extra.find("total memory");
+ size_t totalMemory = tm_it == options.extra.end()
+ ? 16 * 1024 * 1024
+ : atoll(tm_it->second.c_str());
if (totalMemory & ~Memory::kPageMask) {
- std::cerr << "Error: total memory size " << totalMemory <<
- " is not a multiple of the 64k wasm page size\n";
+ std::cerr << "Error: total memory size " << totalMemory
+ << " is not a multiple of the 64k wasm page size\n";
exit(EXIT_FAILURE);
}
Asm2WasmPreProcessor pre;
// wasm binaries can contain a names section, but not full debug info --
// debug info is disabled if a map file is not specified with wasm binary
- pre.debugInfo = options.passOptions.debugInfo && (!emitBinary || sourceMapFilename.size());
- auto input(
- read_file<std::vector<char>>(options.extra["infile"], Flags::Text, options.debug ? Flags::Debug : Flags::Release));
- char *start = pre.process(input.data());
+ pre.debugInfo =
+ options.passOptions.debugInfo && (!emitBinary || sourceMapFilename.size());
+ auto input(read_file<std::vector<char>>(options.extra["infile"],
+ Flags::Text,
+ options.debug ? Flags::Debug
+ : Flags::Release));
+ char* start = pre.process(input.data());
- if (options.debug) std::cerr << "parsing..." << std::endl;
+ if (options.debug)
+ std::cerr << "parsing..." << std::endl;
cashew::Parser<Ref, DotZeroValueBuilder> builder;
Ref asmjs = builder.parseToplevel(start);
- if (options.debug) std::cerr << "wasming..." << std::endl;
+ if (options.debug)
+ std::cerr << "wasming..." << std::endl;
Module wasm;
// set up memory
@@ -162,17 +226,19 @@ int main(int argc, const char *argv[]) {
// import mem init file, if provided (do this before compiling the module,
// since the optimizer should see the memory segments)
- const auto &memInit = options.extra.find("mem init");
+ const auto& memInit = options.extra.find("mem init");
if (memInit != options.extra.end()) {
auto filename = memInit->second.c_str();
- auto data(read_file<std::vector<char>>(filename, Flags::Binary, options.debug ? Flags::Debug : Flags::Release));
+ auto data(read_file<std::vector<char>>(
+ filename, Flags::Binary, options.debug ? Flags::Debug : Flags::Release));
// create the memory segment
Expression* init;
- const auto &memBase = options.extra.find("mem base");
+ const auto& memBase = options.extra.find("mem base");
if (memBase == options.extra.end()) {
init = Builder(wasm).makeGetGlobal(MEMORY_BASE, i32);
} else {
- init = Builder(wasm).makeConst(Literal(int32_t(atoi(memBase->second.c_str()))));
+ init = Builder(wasm).makeConst(
+ Literal(int32_t(atoi(memBase->second.c_str()))));
}
wasm.memory.segments.emplace_back(init, data);
}
@@ -181,7 +247,14 @@ int main(int argc, const char *argv[]) {
options.applyFeatures(wasm);
// compile the code
- Asm2WasmBuilder asm2wasm(wasm, pre, options.debug, trapMode, options.passOptions, legalizeJavaScriptFFI, options.runningDefaultOptimizationPasses(), wasmOnly);
+ Asm2WasmBuilder asm2wasm(wasm,
+ pre,
+ options.debug,
+ trapMode,
+ options.passOptions,
+ legalizeJavaScriptFFI,
+ options.runningDefaultOptimizationPasses(),
+ wasmOnly);
asm2wasm.processAsm(asmjs);
// finalize the imported mem init
@@ -194,7 +267,7 @@ int main(int argc, const char *argv[]) {
}
// Set the max memory size, if requested
- const auto &memMax = options.extra.find("mem max");
+ const auto& memMax = options.extra.find("mem max");
if (memMax != options.extra.end()) {
uint64_t max = strtoull(memMax->second.c_str(), nullptr, 10);
if (max != uint64_t(-1)) {
@@ -204,7 +277,7 @@ int main(int argc, const char *argv[]) {
}
}
// Set the table sizes, if requested
- const auto &tableMax = options.extra.find("table max");
+ const auto& tableMax = options.extra.find("table max");
if (tableMax != options.extra.end()) {
int max = atoi(tableMax->second.c_str());
if (max >= 0) {
@@ -221,7 +294,8 @@ int main(int argc, const char *argv[]) {
}
}
- if (options.debug) std::cerr << "emitting..." << std::endl;
+ if (options.debug)
+ std::cerr << "emitting..." << std::endl;
ModuleWriter writer;
writer.setDebug(options.debug);
writer.setDebugInfo(options.passOptions.debugInfo);
@@ -233,5 +307,6 @@ int main(int argc, const char *argv[]) {
}
writer.write(wasm, options.extra["output"]);
- if (options.debug) std::cerr << "done." << std::endl;
+ if (options.debug)
+ std::cerr << "done." << std::endl;
}
diff --git a/src/tools/execution-results.h b/src/tools/execution-results.h
index 554b4eb6c..2a42b941b 100644
--- a/src/tools/execution-results.h
+++ b/src/tools/execution-results.h
@@ -18,9 +18,9 @@
// Shared execution result checking code
//
-#include "wasm.h"
-#include "shell-interface.h"
#include "ir/import-utils.h"
+#include "shell-interface.h"
+#include "wasm.h"
namespace wasm {
@@ -59,9 +59,11 @@ struct ExecutionResults {
LoggingExternalInterface interface(loggings);
try {
ModuleInstance instance(wasm, &interface);
- // execute all exported methods (that are therefore preserved through opts)
+ // execute all exported methods (that are therefore preserved through
+ // opts)
for (auto& exp : wasm.exports) {
- if (exp->kind != ExternalKind::Function) continue;
+ if (exp->kind != ExternalKind::Function)
+ continue;
std::cout << "[fuzz-exec] calling " << exp->name << "\n";
auto* func = wasm.getFunction(exp->value);
if (func->result != none) {
@@ -69,7 +71,8 @@ struct ExecutionResults {
results[exp->name] = run(func, wasm, instance);
// ignore the result if we hit an unreachable and returned no value
if (isConcreteType(results[exp->name].type)) {
- std::cout << "[fuzz-exec] note result: " << exp->name << " => " << results[exp->name] << '\n';
+ std::cout << "[fuzz-exec] note result: " << exp->name << " => "
+ << results[exp->name] << '\n';
}
} else {
// no result, run it anyhow (it might modify memory etc.)
@@ -111,9 +114,7 @@ struct ExecutionResults {
return true;
}
- bool operator!=(ExecutionResults& other) {
- return !((*this) == other);
- }
+ bool operator!=(ExecutionResults& other) { return !((*this) == other); }
Literal run(Function* func, Module& wasm) {
LoggingExternalInterface interface(loggings);
diff --git a/src/tools/fuzzing.h b/src/tools/fuzzing.h
index b7056f964..f5b548ec6 100644
--- a/src/tools/fuzzing.h
+++ b/src/tools/fuzzing.h
@@ -25,12 +25,14 @@ high chance for set at start of loop
high chance of a tee in that case => loop var
*/
-#include <wasm-builder.h>
+#include "ir/memory-utils.h"
#include <ir/find_all.h>
#include <ir/literal-utils.h>
#include <ir/manipulation.h>
-#include "ir/memory-utils.h"
#include <ir/utils.h>
+#include <support/file.h>
+#include <tools/optimization-options.h>
+#include <wasm-builder.h>
namespace wasm {
@@ -38,32 +40,35 @@ namespace wasm {
// evaluation, avoiding UB
struct ThreeArgs {
- Expression *a;
- Expression *b;
- Expression *c;
+ Expression* a;
+ Expression* b;
+ Expression* c;
};
struct UnaryArgs {
UnaryOp a;
- Expression *b;
+ Expression* b;
};
struct BinaryArgs {
BinaryOp a;
- Expression *b;
- Expression *c;
+ Expression* b;
+ Expression* c;
};
// main reader
class TranslateToFuzzReader {
public:
- TranslateToFuzzReader(Module& wasm, std::string& filename) : wasm(wasm), builder(wasm) {
- auto input(read_file<std::vector<char>>(filename, Flags::Binary, Flags::Release));
+ TranslateToFuzzReader(Module& wasm, std::string& filename)
+ : wasm(wasm), builder(wasm) {
+ auto input(
+ read_file<std::vector<char>>(filename, Flags::Binary, Flags::Release));
readData(input);
}
- TranslateToFuzzReader(Module& wasm, std::vector<char> input) : wasm(wasm), builder(wasm) {
+ TranslateToFuzzReader(Module& wasm, std::vector<char> input)
+ : wasm(wasm), builder(wasm) {
readData(input);
}
@@ -80,38 +85,91 @@ public:
options.passOptions.shrinkLevel = upTo(4);
break;
}
- case 5: options.passes.push_back("coalesce-locals"); break;
- case 6: options.passes.push_back("code-pushing"); break;
- case 7: options.passes.push_back("code-folding"); break;
- case 8: options.passes.push_back("dce"); break;
- case 9: options.passes.push_back("duplicate-function-elimination"); break;
- case 10: options.passes.push_back("flatten"); break;
- case 11: options.passes.push_back("inlining"); break;
- case 12: options.passes.push_back("inlining-optimizing"); break;
- case 13: options.passes.push_back("local-cse"); break;
- case 14: options.passes.push_back("memory-packing"); break;
- case 15: options.passes.push_back("merge-blocks"); break;
- case 16: options.passes.push_back("optimize-instructions"); break;
- case 17: options.passes.push_back("pick-load-signs"); break;
- case 18: options.passes.push_back("precompute"); break;
- case 19: options.passes.push_back("precompute-propagate"); break;
- case 20: options.passes.push_back("remove-unused-brs"); break;
- case 21: options.passes.push_back("remove-unused-module-elements"); break;
- case 22: options.passes.push_back("remove-unused-names"); break;
- case 23: options.passes.push_back("reorder-functions"); break;
- case 24: options.passes.push_back("reorder-locals"); break;
+ case 5:
+ options.passes.push_back("coalesce-locals");
+ break;
+ case 6:
+ options.passes.push_back("code-pushing");
+ break;
+ case 7:
+ options.passes.push_back("code-folding");
+ break;
+ case 8:
+ options.passes.push_back("dce");
+ break;
+ case 9:
+ options.passes.push_back("duplicate-function-elimination");
+ break;
+ case 10:
+ options.passes.push_back("flatten");
+ break;
+ case 11:
+ options.passes.push_back("inlining");
+ break;
+ case 12:
+ options.passes.push_back("inlining-optimizing");
+ break;
+ case 13:
+ options.passes.push_back("local-cse");
+ break;
+ case 14:
+ options.passes.push_back("memory-packing");
+ break;
+ case 15:
+ options.passes.push_back("merge-blocks");
+ break;
+ case 16:
+ options.passes.push_back("optimize-instructions");
+ break;
+ case 17:
+ options.passes.push_back("pick-load-signs");
+ break;
+ case 18:
+ options.passes.push_back("precompute");
+ break;
+ case 19:
+ options.passes.push_back("precompute-propagate");
+ break;
+ case 20:
+ options.passes.push_back("remove-unused-brs");
+ break;
+ case 21:
+ options.passes.push_back("remove-unused-module-elements");
+ break;
+ case 22:
+ options.passes.push_back("remove-unused-names");
+ break;
+ case 23:
+ options.passes.push_back("reorder-functions");
+ break;
+ case 24:
+ options.passes.push_back("reorder-locals");
+ break;
case 25: {
options.passes.push_back("flatten");
options.passes.push_back("rereloop");
break;
}
- case 26: options.passes.push_back("simplify-locals"); break;
- case 27: options.passes.push_back("simplify-locals-notee"); break;
- case 28: options.passes.push_back("simplify-locals-nostructure"); break;
- case 29: options.passes.push_back("simplify-locals-notee-nostructure"); break;
- case 30: options.passes.push_back("ssa"); break;
- case 31: options.passes.push_back("vacuum"); break;
- default: WASM_UNREACHABLE();
+ case 26:
+ options.passes.push_back("simplify-locals");
+ break;
+ case 27:
+ options.passes.push_back("simplify-locals-notee");
+ break;
+ case 28:
+ options.passes.push_back("simplify-locals-nostructure");
+ break;
+ case 29:
+ options.passes.push_back("simplify-locals-notee-nostructure");
+ break;
+ case 30:
+ options.passes.push_back("ssa");
+ break;
+ case 31:
+ options.passes.push_back("vacuum");
+ break;
+ default:
+ WASM_UNREACHABLE();
}
}
if (oneIn(2)) {
@@ -124,13 +182,9 @@ public:
std::cout << "shrink level: " << options.passOptions.shrinkLevel << '\n';
}
- void setAllowNaNs(bool allowNaNs_) {
- allowNaNs = allowNaNs_;
- }
+ void setAllowNaNs(bool allowNaNs_) { allowNaNs = allowNaNs_; }
- void setAllowMemory(bool allowMemory_) {
- allowMemory = allowMemory_;
- }
+ void setAllowMemory(bool allowMemory_) { allowMemory = allowMemory_; }
void build() {
if (allowMemory) {
@@ -157,8 +211,10 @@ private:
Module& wasm;
Builder builder;
std::vector<char> bytes; // the input bytes
- size_t pos; // the position in the input
- bool finishedInput; // whether we already cycled through all the input (if so, we should try to finish things off)
+ size_t pos; // the position in the input
+ // whether we already cycled through all the input (if so, we should try to
+ // finish things off)
+ bool finishedInput;
// The maximum amount of params to each function.
static const int MAX_PARAMS = 10;
@@ -176,8 +232,8 @@ private:
static const int BLOCK_FACTOR = 5;
// the memory that we use, a small portion so that we have a good chance of
- // looking at writes (we also look outside of this region with small probability)
- // this should be a power of 2
+ // looking at writes (we also look outside of this region with small
+ // probability) this should be a power of 2
static const int USABLE_MEMORY = 16;
// the number of runtime iterations (function calls, loop backbranches) we
@@ -239,13 +295,9 @@ private:
return temp | uint64_t(get32());
}
- float getFloat() {
- return Literal(get32()).reinterpretf32();
- }
+ float getFloat() { return Literal(get32()).reinterpretf32(); }
- double getDouble() {
- return Literal(get64()).reinterpretf64();
- }
+ double getDouble() { return Literal(get64()).reinterpretf64(); }
void setupMemory() {
// Add memory itself
@@ -274,10 +326,12 @@ private:
auto num = upTo(USABLE_MEMORY * 2);
for (size_t i = 0; i < num; i++) {
auto value = upTo(512);
- wasm.memory.segments[0].data.push_back(value >= 256 ? 0 : (value & 0xff));
+ wasm.memory.segments[0].data.push_back(value >= 256 ? 0
+ : (value & 0xff));
}
}
- // Add memory hasher helper (for the hash, see hash.h). The function looks like:
+ // Add memory hasher helper (for the hash, see hash.h). The function looks
+ // like:
// function hashMemory() {
// hash = 5381;
// hash = ((hash << 5) + hash) ^ mem[0];
@@ -287,31 +341,28 @@ private:
// }
std::vector<Expression*> contents;
contents.push_back(
- builder.makeSetLocal(0, builder.makeConst(Literal(uint32_t(5381))))
- );
+ builder.makeSetLocal(0, builder.makeConst(Literal(uint32_t(5381)))));
for (Index i = 0; i < USABLE_MEMORY; i++) {
- contents.push_back(
- builder.makeSetLocal(0,
- builder.makeBinary(XorInt32,
- builder.makeBinary(AddInt32,
- builder.makeBinary(ShlInt32,
- builder.makeGetLocal(0, i32),
- builder.makeConst(Literal(uint32_t(5)))
- ),
- builder.makeGetLocal(0, i32)
- ),
- builder.makeLoad(1, false, i, 1, builder.makeConst(Literal(uint32_t(0))), i32)
- )
- )
- );
- }
- contents.push_back(
- builder.makeGetLocal(0, i32)
- );
+ contents.push_back(builder.makeSetLocal(
+ 0,
+ builder.makeBinary(
+ XorInt32,
+ builder.makeBinary(
+ AddInt32,
+ builder.makeBinary(ShlInt32,
+ builder.makeGetLocal(0, i32),
+ builder.makeConst(Literal(uint32_t(5)))),
+ builder.makeGetLocal(0, i32)),
+ builder.makeLoad(
+ 1, false, i, 1, builder.makeConst(Literal(uint32_t(0))), i32))));
+ }
+ contents.push_back(builder.makeGetLocal(0, i32));
auto* body = builder.makeBlock(contents);
- auto* hasher = wasm.addFunction(builder.makeFunction("hashMemory", std::vector<Type>{}, i32, { i32 }, body));
+ auto* hasher = wasm.addFunction(builder.makeFunction(
+ "hashMemory", std::vector<Type>{}, i32, {i32}, body));
hasher->type = ensureFunctionType(getSig(hasher), &wasm)->name;
- wasm.addExport(builder.makeExport(hasher->name, hasher->name, ExternalKind::Function));
+ wasm.addExport(
+ builder.makeExport(hasher->name, hasher->name, ExternalKind::Function));
}
void setupTable() {
@@ -323,15 +374,14 @@ private:
void setupGlobals() {
size_t index = 0;
- for (auto type : { i32, i64, f32, f64 }) {
+ for (auto type : {i32, i64, f32, f64}) {
auto num = upTo(3);
for (size_t i = 0; i < num; i++) {
- auto* glob = builder.makeGlobal(
- std::string("global$") + std::to_string(index++),
- type,
- makeConst(type),
- Builder::Mutable
- );
+ auto* glob =
+ builder.makeGlobal(std::string("global$") + std::to_string(index++),
+ type,
+ makeConst(type),
+ Builder::Mutable);
wasm.addGlobal(glob);
globalsByType[type].push_back(glob->name);
}
@@ -340,26 +390,25 @@ private:
void finalizeTable() {
wasm.table.initial = wasm.table.segments[0].data.size();
- wasm.table.max = oneIn(2) ? Address(Table::kUnlimitedSize) : wasm.table.initial;
+ wasm.table.max =
+ oneIn(2) ? Address(Table::kUnlimitedSize) : wasm.table.initial;
}
const Name HANG_LIMIT_GLOBAL = "hangLimit";
void addHangLimitSupport() {
- auto* glob = builder.makeGlobal(
- HANG_LIMIT_GLOBAL,
- i32,
- builder.makeConst(Literal(int32_t(HANG_LIMIT))),
- Builder::Mutable
- );
+ auto* glob =
+ builder.makeGlobal(HANG_LIMIT_GLOBAL,
+ i32,
+ builder.makeConst(Literal(int32_t(HANG_LIMIT))),
+ Builder::Mutable);
wasm.addGlobal(glob);
auto* func = new Function;
func->name = "hangLimitInitializer";
func->result = none;
- func->body = builder.makeSetGlobal(glob->name,
- builder.makeConst(Literal(int32_t(HANG_LIMIT)))
- );
+ func->body = builder.makeSetGlobal(
+ glob->name, builder.makeConst(Literal(int32_t(HANG_LIMIT))));
wasm.addFunction(func);
auto* export_ = new Export;
@@ -370,7 +419,7 @@ private:
}
void addImportLoggingSupport() {
- for (auto type : { i32, i64, f32, f64 }) {
+ for (auto type : {i32, i64, f32, f64}) {
auto* func = new Function;
Name name = std::string("log-") + printType(type);
func->name = name;
@@ -386,21 +435,14 @@ private:
Expression* makeHangLimitCheck() {
return builder.makeSequence(
builder.makeIf(
- builder.makeUnary(
- UnaryOp::EqZInt32,
- builder.makeGetGlobal(HANG_LIMIT_GLOBAL, i32)
- ),
- makeTrivial(unreachable)
- ),
+ builder.makeUnary(UnaryOp::EqZInt32,
+ builder.makeGetGlobal(HANG_LIMIT_GLOBAL, i32)),
+ makeTrivial(unreachable)),
builder.makeSetGlobal(
HANG_LIMIT_GLOBAL,
- builder.makeBinary(
- BinaryOp::SubInt32,
- builder.makeGetGlobal(HANG_LIMIT_GLOBAL, i32),
- builder.makeConst(Literal(int32_t(1)))
- )
- )
- );
+ builder.makeBinary(BinaryOp::SubInt32,
+ builder.makeGetGlobal(HANG_LIMIT_GLOBAL, i32),
+ builder.makeConst(Literal(int32_t(1))))));
}
void addDeNanSupport() {
@@ -411,13 +453,9 @@ private:
func->result = type;
func->body = builder.makeIf(
builder.makeBinary(
- op,
- builder.makeGetLocal(0, type),
- builder.makeGetLocal(0, type)
- ),
+ op, builder.makeGetLocal(0, type), builder.makeGetLocal(0, type)),
builder.makeGetLocal(0, type),
- builder.makeConst(literal)
- );
+ builder.makeConst(literal));
wasm.addFunction(func);
};
add("deNan32", f32, Literal(float(0)), EqFloat32);
@@ -425,11 +463,12 @@ private:
}
Expression* makeDeNanOp(Expression* expr) {
- if (allowNaNs) return expr;
+ if (allowNaNs)
+ return expr;
if (expr->type == f32) {
- return builder.makeCall("deNan32", { expr }, f32);
+ return builder.makeCall("deNan32", {expr}, f32);
} else if (expr->type == f64) {
- return builder.makeCall("deNan64", { expr }, f64);
+ return builder.makeCall("deNan64", {expr}, f64);
}
return expr; // unreachable etc. is fine
}
@@ -444,7 +483,8 @@ private:
// which we try to minimize the risk of
std::vector<Expression*> hangStack;
- std::map<Type, std::vector<Index>> typeLocals; // type => list of locals with that type
+ std::map<Type, std::vector<Index>>
+ typeLocals; // type => list of locals with that type
Function* addFunction() {
LOGGING_PERCENT = upToSquared(100);
@@ -518,23 +558,19 @@ private:
// loop limit
FindAll<Loop> loops(func->body);
for (auto* loop : loops.list) {
- loop->body = builder.makeSequence(
- makeHangLimitCheck(),
- loop->body
- );
+ loop->body = builder.makeSequence(makeHangLimitCheck(), loop->body);
}
// recursion limit
- func->body = builder.makeSequence(
- makeHangLimitCheck(),
- func->body
- );
+ func->body = builder.makeSequence(makeHangLimitCheck(), func->body);
}
void recombine(Function* func) {
// Don't always do this.
- if (oneIn(2)) return;
+ if (oneIn(2))
+ return;
// First, scan and group all expressions by type.
- struct Scanner : public PostWalker<Scanner, UnifiedExpressionVisitor<Scanner>> {
+ struct Scanner
+ : public PostWalker<Scanner, UnifiedExpressionVisitor<Scanner>> {
// A map of all expressions, categorized by type.
std::map<Type, std::vector<Expression*>> exprsByType;
@@ -544,10 +580,11 @@ private:
};
Scanner scanner;
scanner.walk(func->body);
- // Potentially trim the list of possible picks, so replacements are more likely
- // to collide.
+ // Potentially trim the list of possible picks, so replacements are more
+ // likely to collide.
for (auto& pair : scanner.exprsByType) {
- if (oneIn(2)) continue;
+ if (oneIn(2))
+ continue;
auto& list = pair.second;
std::vector<Expression*> trimmed;
size_t num = upToSquared(list.size());
@@ -568,19 +605,22 @@ private:
// Second, with some probability replace an item with another item having
// the same type. (This is not always valid due to nesting of labels, but
// we'll fix that up later.)
- struct Modder : public PostWalker<Modder, UnifiedExpressionVisitor<Modder>> {
+ struct Modder
+ : public PostWalker<Modder, UnifiedExpressionVisitor<Modder>> {
Module& wasm;
Scanner& scanner;
TranslateToFuzzReader& parent;
- Modder(Module& wasm, Scanner& scanner, TranslateToFuzzReader& parent) : wasm(wasm), scanner(scanner), parent(parent) {}
+ Modder(Module& wasm, Scanner& scanner, TranslateToFuzzReader& parent)
+ : wasm(wasm), scanner(scanner), parent(parent) {}
void visitExpression(Expression* curr) {
if (parent.oneIn(10)) {
// Replace it!
auto& candidates = scanner.exprsByType[curr->type];
assert(!candidates.empty()); // this expression itself must be there
- replaceCurrent(ExpressionManipulator::copy(parent.vectorPick(candidates), wasm));
+ replaceCurrent(
+ ExpressionManipulator::copy(parent.vectorPick(candidates), wasm));
}
}
};
@@ -590,12 +630,15 @@ private:
void mutate(Function* func) {
// Don't always do this.
- if (oneIn(2)) return;
- struct Modder : public PostWalker<Modder, UnifiedExpressionVisitor<Modder>> {
+ if (oneIn(2))
+ return;
+ struct Modder
+ : public PostWalker<Modder, UnifiedExpressionVisitor<Modder>> {
Module& wasm;
TranslateToFuzzReader& parent;
- Modder(Module& wasm, TranslateToFuzzReader& parent) : wasm(wasm), parent(parent) {}
+ Modder(Module& wasm, TranslateToFuzzReader& parent)
+ : wasm(wasm), parent(parent) {}
void visitExpression(Expression* curr) {
if (parent.oneIn(10)) {
@@ -617,7 +660,8 @@ private:
Module& wasm;
TranslateToFuzzReader& parent;
- Fixer(Module& wasm, TranslateToFuzzReader& parent) : wasm(wasm), parent(parent) {}
+ Fixer(Module& wasm, TranslateToFuzzReader& parent)
+ : wasm(wasm), parent(parent) {}
// Track seen names to find duplication, which is invalid.
std::set<Name> seen;
@@ -644,14 +688,13 @@ private:
void visitSwitch(Switch* curr) {
for (auto name : curr->targets) {
- if (replaceIfInvalid(name)) return;
+ if (replaceIfInvalid(name))
+ return;
}
replaceIfInvalid(curr->default_);
}
- void visitBreak(Break* curr) {
- replaceIfInvalid(curr->name);
- }
+ void visitBreak(Break* curr) { replaceIfInvalid(curr->name); }
bool replaceIfInvalid(Name target) {
if (!hasBreakTarget(target)) {
@@ -662,24 +705,26 @@ private:
return false;
}
- void replace() {
- replaceCurrent(parent.makeTrivial(getCurrent()->type));
- }
+ void replace() { replaceCurrent(parent.makeTrivial(getCurrent()->type)); }
bool hasBreakTarget(Name name) {
- if (controlFlowStack.empty()) return false;
+ if (controlFlowStack.empty())
+ return false;
Index i = controlFlowStack.size() - 1;
while (1) {
auto* curr = controlFlowStack[i];
if (Block* block = curr->template dynCast<Block>()) {
- if (name == block->name) return true;
+ if (name == block->name)
+ return true;
} else if (Loop* loop = curr->template dynCast<Loop>()) {
- if (name == loop->name) return true;
+ if (name == loop->name)
+ return true;
} else {
// an if, ignorable
assert(curr->template is<If>());
}
- if (i == 0) return false;
+ if (i == 0)
+ return false;
i--;
}
}
@@ -709,7 +754,8 @@ private:
invocations.push_back(makeMemoryHashLogging());
}
}
- if (invocations.empty()) return;
+ if (invocations.empty())
+ return;
auto* invoker = new Function;
invoker->name = func->name.str + std::string("_invoker");
invoker->result = none;
@@ -733,8 +779,7 @@ private:
Expression* make(Type type) {
// when we should stop, emit something small (but not necessarily trivial)
- if (finishedInput ||
- nesting >= 5 * NESTING_LIMIT || // hard limit
+ if (finishedInput || nesting >= 5 * NESTING_LIMIT || // hard limit
(nesting >= NESTING_LIMIT && !oneIn(3))) {
if (isConcreteType(type)) {
if (oneIn(2)) {
@@ -759,9 +804,15 @@ private:
case i64:
case f32:
case f64:
- case v128: ret = _makeConcrete(type); break;
- case none: ret = _makenone(); break;
- case unreachable: ret = _makeunreachable(); break;
+ case v128:
+ ret = _makeConcrete(type);
+ break;
+ case none:
+ ret = _makenone();
+ break;
+ case unreachable:
+ ret = _makeunreachable();
+ break;
}
assert(ret->type == type); // we should create the right type of thing
nesting--;
@@ -770,31 +821,38 @@ private:
Expression* _makeConcrete(Type type) {
auto choice = upTo(100);
- if (choice < 10) return makeConst(type);
- if (choice < 30) return makeSetLocal(type);
- if (choice < 50) return makeGetLocal(type);
- if (choice < 60) return makeBlock(type);
- if (choice < 70) return makeIf(type);
- if (choice < 80) return makeLoop(type);
- if (choice < 90) return makeBreak(type);
+ if (choice < 10)
+ return makeConst(type);
+ if (choice < 30)
+ return makeSetLocal(type);
+ if (choice < 50)
+ return makeGetLocal(type);
+ if (choice < 60)
+ return makeBlock(type);
+ if (choice < 70)
+ return makeIf(type);
+ if (choice < 80)
+ return makeLoop(type);
+ if (choice < 90)
+ return makeBreak(type);
using Self = TranslateToFuzzReader;
auto options = FeatureOptions<Expression* (Self::*)(Type)>()
- .add(FeatureSet::MVP,
- &Self::makeBlock,
- &Self::makeIf,
- &Self::makeLoop,
- &Self::makeBreak,
- &Self::makeCall,
- &Self::makeCallIndirect,
- &Self::makeGetLocal,
- &Self::makeSetLocal,
- &Self::makeLoad,
- &Self::makeConst,
- &Self::makeUnary,
- &Self::makeBinary,
- &Self::makeSelect,
- &Self::makeGetGlobal)
- .add(FeatureSet::SIMD, &Self::makeSIMD);
+ .add(FeatureSet::MVP,
+ &Self::makeBlock,
+ &Self::makeIf,
+ &Self::makeLoop,
+ &Self::makeBreak,
+ &Self::makeCall,
+ &Self::makeCallIndirect,
+ &Self::makeGetLocal,
+ &Self::makeSetLocal,
+ &Self::makeLoad,
+ &Self::makeConst,
+ &Self::makeUnary,
+ &Self::makeBinary,
+ &Self::makeSelect,
+ &Self::makeGetGlobal)
+ .add(FeatureSet::SIMD, &Self::makeSIMD);
if (type == i32 || type == i64) {
options.add(FeatureSet::Atomics, &Self::makeAtomic);
}
@@ -811,46 +869,66 @@ private:
}
}
choice = upTo(100);
- if (choice < 50) return makeSetLocal(none);
- if (choice < 60) return makeBlock(none);
- if (choice < 70) return makeIf(none);
- if (choice < 80) return makeLoop(none);
- if (choice < 90) return makeBreak(none);
+ if (choice < 50)
+ return makeSetLocal(none);
+ if (choice < 60)
+ return makeBlock(none);
+ if (choice < 70)
+ return makeIf(none);
+ if (choice < 80)
+ return makeLoop(none);
+ if (choice < 90)
+ return makeBreak(none);
using Self = TranslateToFuzzReader;
auto options = FeatureOptions<Expression* (Self::*)(Type)>()
- .add(FeatureSet::MVP,
- &Self::makeBlock,
- &Self::makeIf,
- &Self::makeLoop,
- &Self::makeBreak,
- &Self::makeCall,
- &Self::makeCallIndirect,
- &Self::makeSetLocal,
- &Self::makeStore,
- &Self::makeDrop,
- &Self::makeNop,
- &Self::makeSetGlobal)
- .add(FeatureSet::BulkMemory, &Self::makeBulkMemory);
+ .add(FeatureSet::MVP,
+ &Self::makeBlock,
+ &Self::makeIf,
+ &Self::makeLoop,
+ &Self::makeBreak,
+ &Self::makeCall,
+ &Self::makeCallIndirect,
+ &Self::makeSetLocal,
+ &Self::makeStore,
+ &Self::makeDrop,
+ &Self::makeNop,
+ &Self::makeSetGlobal)
+ .add(FeatureSet::BulkMemory, &Self::makeBulkMemory);
return (this->*pick(options))(none);
}
Expression* _makeunreachable() {
switch (upTo(15)) {
- case 0: return makeBlock(unreachable);
- case 1: return makeIf(unreachable);
- case 2: return makeLoop(unreachable);
- case 3: return makeBreak(unreachable);
- case 4: return makeCall(unreachable);
- case 5: return makeCallIndirect(unreachable);
- case 6: return makeSetLocal(unreachable);
- case 7: return makeStore(unreachable);
- case 8: return makeUnary(unreachable);
- case 9: return makeBinary(unreachable);
- case 10: return makeSelect(unreachable);
- case 11: return makeSwitch(unreachable);
- case 12: return makeDrop(unreachable);
- case 13: return makeReturn(unreachable);
- case 14: return makeUnreachable(unreachable);
+ case 0:
+ return makeBlock(unreachable);
+ case 1:
+ return makeIf(unreachable);
+ case 2:
+ return makeLoop(unreachable);
+ case 3:
+ return makeBreak(unreachable);
+ case 4:
+ return makeCall(unreachable);
+ case 5:
+ return makeCallIndirect(unreachable);
+ case 6:
+ return makeSetLocal(unreachable);
+ case 7:
+ return makeStore(unreachable);
+ case 8:
+ return makeUnary(unreachable);
+ case 9:
+ return makeBinary(unreachable);
+ case 10:
+ return makeSelect(unreachable);
+ case 11:
+ return makeSwitch(unreachable);
+ case 12:
+ return makeDrop(unreachable);
+ case 13:
+ return makeReturn(unreachable);
+ case 14:
+ return makeUnreachable(unreachable);
}
WASM_UNREACHABLE();
}
@@ -932,7 +1010,8 @@ private:
// ensure a branch back. also optionally create some loop vars
std::vector<Expression*> list;
list.push_back(makeMaybeBlock(none)); // primary contents
- list.push_back(builder.makeBreak(ret->name, nullptr, makeCondition())); // possible branch back
+ // possible branch back
+ list.push_back(builder.makeBreak(ret->name, nullptr, makeCondition()));
list.push_back(make(type)); // final element, so we have the right type
ret->body = builder.makeBlock(list);
}
@@ -970,13 +1049,15 @@ private:
Expression* makeIf(Type type) {
auto* condition = makeCondition();
hangStack.push_back(nullptr);
- auto* ret = buildIf({ condition, makeMaybeBlock(type), makeMaybeBlock(type) });
+ auto* ret =
+ buildIf({condition, makeMaybeBlock(type), makeMaybeBlock(type)});
hangStack.pop_back();
return ret;
}
Expression* makeBreak(Type type) {
- if (breakableStack.empty()) return makeTrivial(type);
+ if (breakableStack.empty())
+ return makeTrivial(type);
Expression* condition = nullptr;
if (type != unreachable) {
hangStack.push_back(nullptr);
@@ -1029,15 +1110,18 @@ private:
}
switch (conditions) {
case 0: {
- if (!oneIn(4)) continue;
+ if (!oneIn(4))
+ continue;
break;
}
case 1: {
- if (!oneIn(2)) continue;
+ if (!oneIn(2))
+ continue;
break;
}
default: {
- if (oneIn(conditions + 1)) continue;
+ if (oneIn(conditions + 1))
+ continue;
}
}
return builder.makeBreak(name);
@@ -1058,7 +1142,8 @@ private:
if (!wasm.functions.empty() && !oneIn(wasm.functions.size())) {
target = vectorPick(wasm.functions).get();
}
- if (target->result != type) continue;
+ if (target->result != type)
+ continue;
// we found one!
std::vector<Expression*> args;
for (auto argType : target->params) {
@@ -1072,7 +1157,8 @@ private:
Expression* makeCallIndirect(Type type) {
auto& data = wasm.table.segments[0].data;
- if (data.empty()) return make(type);
+ if (data.empty())
+ return make(type);
// look for a call target with the right type
Index start = upTo(data.size());
Index i = start;
@@ -1084,8 +1170,10 @@ private:
break;
}
i++;
- if (i == data.size()) i = 0;
- if (i == start) return make(type);
+ if (i == data.size())
+ i = 0;
+ if (i == start)
+ return make(type);
}
// with high probability, make sure the type is valid otherwise, most are
// going to trap
@@ -1100,17 +1188,13 @@ private:
args.push_back(make(type));
}
func->type = ensureFunctionType(getSig(func), &wasm)->name;
- return builder.makeCallIndirect(
- func->type,
- target,
- args,
- func->result
- );
+ return builder.makeCallIndirect(func->type, target, args, func->result);
}
Expression* makeGetLocal(Type type) {
auto& locals = typeLocals[type];
- if (locals.empty()) return makeConst(type);
+ if (locals.empty())
+ return makeConst(type);
return builder.makeGetLocal(vectorPick(locals), type);
}
@@ -1123,7 +1207,8 @@ private:
valueType = getConcreteType();
}
auto& locals = typeLocals[valueType];
- if (locals.empty()) return makeTrivial(type);
+ if (locals.empty())
+ return makeTrivial(type);
auto* value = make(valueType);
if (tee) {
return builder.makeTeeLocal(vectorPick(locals), value);
@@ -1134,7 +1219,8 @@ private:
Expression* makeGetGlobal(Type type) {
auto& globals = globalsByType[type];
- if (globals.empty()) return makeConst(type);
+ if (globals.empty())
+ return makeConst(type);
return builder.makeGetGlobal(vectorPick(globals), type);
}
@@ -1142,7 +1228,8 @@ private:
assert(type == none);
type = getConcreteType();
auto& globals = globalsByType[type];
- if (globals.empty()) return makeTrivial(none);
+ if (globals.empty())
+ return makeTrivial(none);
auto* value = make(type);
return builder.makeSetGlobal(vectorPick(globals), value);
}
@@ -1153,10 +1240,8 @@ private:
// range. otherwise, most pointers are going to be out of range and
// most memory ops will just trap
if (!oneIn(10)) {
- ret = builder.makeBinary(AndInt32,
- ret,
- builder.makeConst(Literal(int32_t(USABLE_MEMORY - 1)))
- );
+ ret = builder.makeBinary(
+ AndInt32, ret, builder.makeConst(Literal(int32_t(USABLE_MEMORY - 1))));
}
return ret;
}
@@ -1168,19 +1253,29 @@ private:
case i32: {
bool signed_ = get() & 1;
switch (upTo(3)) {
- case 0: return builder.makeLoad(1, signed_, offset, 1, ptr, type);
- case 1: return builder.makeLoad(2, signed_, offset, pick(1, 2), ptr, type);
- case 2: return builder.makeLoad(4, signed_, offset, pick(1, 2, 4), ptr, type);
+ case 0:
+ return builder.makeLoad(1, signed_, offset, 1, ptr, type);
+ case 1:
+ return builder.makeLoad(2, signed_, offset, pick(1, 2), ptr, type);
+ case 2:
+ return builder.makeLoad(
+ 4, signed_, offset, pick(1, 2, 4), ptr, type);
}
WASM_UNREACHABLE();
}
case i64: {
bool signed_ = get() & 1;
switch (upTo(4)) {
- case 0: return builder.makeLoad(1, signed_, offset, 1, ptr, type);
- case 1: return builder.makeLoad(2, signed_, offset, pick(1, 2), ptr, type);
- case 2: return builder.makeLoad(4, signed_, offset, pick(1, 2, 4), ptr, type);
- case 3: return builder.makeLoad(8, signed_, offset, pick(1, 2, 4, 8), ptr, type);
+ case 0:
+ return builder.makeLoad(1, signed_, offset, 1, ptr, type);
+ case 1:
+ return builder.makeLoad(2, signed_, offset, pick(1, 2), ptr, type);
+ case 2:
+ return builder.makeLoad(
+ 4, signed_, offset, pick(1, 2, 4), ptr, type);
+ case 3:
+ return builder.makeLoad(
+ 8, signed_, offset, pick(1, 2, 4, 8), ptr, type);
}
WASM_UNREACHABLE();
}
@@ -1194,19 +1289,24 @@ private:
if (!wasm.features.hasSIMD()) {
return makeTrivial(type);
}
- return builder.makeLoad(16, false, offset, pick(1, 2, 4, 8, 16), ptr, type);
+ return builder.makeLoad(
+ 16, false, offset, pick(1, 2, 4, 8, 16), ptr, type);
}
case none:
- case unreachable: WASM_UNREACHABLE();
+ case unreachable:
+ WASM_UNREACHABLE();
}
WASM_UNREACHABLE();
}
Expression* makeLoad(Type type) {
- if (!allowMemory) return makeTrivial(type);
+ if (!allowMemory)
+ return makeTrivial(type);
auto* ret = makeNonAtomicLoad(type);
- if (type != i32 && type != i64) return ret;
- if (!wasm.features.hasAtomics() || oneIn(2)) return ret;
+ if (type != i32 && type != i64)
+ return ret;
+ if (!wasm.features.hasAtomics() || oneIn(2))
+ return ret;
// make it atomic
auto* load = ret->cast<Load>();
wasm.memory.shared = true;
@@ -1221,11 +1321,19 @@ private:
// make a normal store, then make it unreachable
auto* ret = makeNonAtomicStore(getConcreteType());
auto* store = ret->dynCast<Store>();
- if (!store) return ret;
+ if (!store)
+ return ret;
switch (upTo(3)) {
- case 0: store->ptr = make(unreachable); break;
- case 1: store->value = make(unreachable); break;
- case 2: store->ptr = make(unreachable); store->value = make(unreachable); break;
+ case 0:
+ store->ptr = make(unreachable);
+ break;
+ case 1:
+ store->value = make(unreachable);
+ break;
+ case 2:
+ store->ptr = make(unreachable);
+ store->value = make(unreachable);
+ break;
}
store->finalize();
return store;
@@ -1241,18 +1349,28 @@ private:
switch (type) {
case i32: {
switch (upTo(3)) {
- case 0: return builder.makeStore(1, offset, 1, ptr, value, type);
- case 1: return builder.makeStore(2, offset, pick(1, 2), ptr, value, type);
- case 2: return builder.makeStore(4, offset, pick(1, 2, 4), ptr, value, type);
+ case 0:
+ return builder.makeStore(1, offset, 1, ptr, value, type);
+ case 1:
+ return builder.makeStore(2, offset, pick(1, 2), ptr, value, type);
+ case 2:
+ return builder.makeStore(
+ 4, offset, pick(1, 2, 4), ptr, value, type);
}
WASM_UNREACHABLE();
}
case i64: {
switch (upTo(4)) {
- case 0: return builder.makeStore(1, offset, 1, ptr, value, type);
- case 1: return builder.makeStore(2, offset, pick(1, 2), ptr, value, type);
- case 2: return builder.makeStore(4, offset, pick(1, 2, 4), ptr, value, type);
- case 3: return builder.makeStore(8, offset, pick(1, 2, 4, 8), ptr, value, type);
+ case 0:
+ return builder.makeStore(1, offset, 1, ptr, value, type);
+ case 1:
+ return builder.makeStore(2, offset, pick(1, 2), ptr, value, type);
+ case 2:
+ return builder.makeStore(
+ 4, offset, pick(1, 2, 4), ptr, value, type);
+ case 3:
+ return builder.makeStore(
+ 8, offset, pick(1, 2, 4, 8), ptr, value, type);
}
WASM_UNREACHABLE();
}
@@ -1266,21 +1384,27 @@ private:
if (!wasm.features.hasSIMD()) {
return makeTrivial(type);
}
- return builder.makeStore(16, offset, pick(1, 2, 4, 8, 16), ptr, value, type);
+ return builder.makeStore(
+ 16, offset, pick(1, 2, 4, 8, 16), ptr, value, type);
}
case none:
- case unreachable: WASM_UNREACHABLE();
+ case unreachable:
+ WASM_UNREACHABLE();
}
WASM_UNREACHABLE();
}
Expression* makeStore(Type type) {
- if (!allowMemory) return makeTrivial(type);
+ if (!allowMemory)
+ return makeTrivial(type);
auto* ret = makeNonAtomicStore(type);
auto* store = ret->dynCast<Store>();
- if (!store) return ret;
- if (store->value->type != i32 && store->value->type != i64) return store;
- if (!wasm.features.hasAtomics() || oneIn(2)) return store;
+ if (!store)
+ return ret;
+ if (store->value->type != i32 && store->value->type != i64)
+ return store;
+ if (!wasm.features.hasAtomics() || oneIn(2))
+ return store;
// make it atomic
wasm.memory.shared = true;
store->isAtomic = true;
@@ -1292,25 +1416,50 @@ private:
if (type == v128) {
// generate each lane individually for random lane interpretation
switch (upTo(6)) {
- case 0: return Literal(
- std::array<Literal, 16>{{
- makeLiteral(i32), makeLiteral(i32), makeLiteral(i32), makeLiteral(i32),
- makeLiteral(i32), makeLiteral(i32), makeLiteral(i32), makeLiteral(i32),
- makeLiteral(i32), makeLiteral(i32), makeLiteral(i32), makeLiteral(i32),
- makeLiteral(i32), makeLiteral(i32), makeLiteral(i32), makeLiteral(i32)
- }}
- );
- case 1: return Literal(
- std::array<Literal, 8>{{
- makeLiteral(i32), makeLiteral(i32), makeLiteral(i32), makeLiteral(i32),
- makeLiteral(i32), makeLiteral(i32), makeLiteral(i32), makeLiteral(i32)
- }}
- );
- case 2: return Literal(std::array<Literal, 4>{{makeLiteral(i32), makeLiteral(i32), makeLiteral(i32), makeLiteral(i32)}});
- case 3: return Literal(std::array<Literal, 2>{{makeLiteral(i64), makeLiteral(i64)}});
- case 4: return Literal(std::array<Literal, 4>{{makeLiteral(f32), makeLiteral(f32), makeLiteral(f32), makeLiteral(f32)}});
- case 5: return Literal(std::array<Literal, 2>{{makeLiteral(f64), makeLiteral(f64)}});
- default: WASM_UNREACHABLE();
+ case 0:
+ return Literal(std::array<Literal, 16>{{makeLiteral(i32),
+ makeLiteral(i32),
+ makeLiteral(i32),
+ makeLiteral(i32),
+ makeLiteral(i32),
+ makeLiteral(i32),
+ makeLiteral(i32),
+ makeLiteral(i32),
+ makeLiteral(i32),
+ makeLiteral(i32),
+ makeLiteral(i32),
+ makeLiteral(i32),
+ makeLiteral(i32),
+ makeLiteral(i32),
+ makeLiteral(i32),
+ makeLiteral(i32)}});
+ case 1:
+ return Literal(std::array<Literal, 8>{{makeLiteral(i32),
+ makeLiteral(i32),
+ makeLiteral(i32),
+ makeLiteral(i32),
+ makeLiteral(i32),
+ makeLiteral(i32),
+ makeLiteral(i32),
+ makeLiteral(i32)}});
+ case 2:
+ return Literal(std::array<Literal, 4>{{makeLiteral(i32),
+ makeLiteral(i32),
+ makeLiteral(i32),
+ makeLiteral(i32)}});
+ case 3:
+ return Literal(
+ std::array<Literal, 2>{{makeLiteral(i64), makeLiteral(i64)}});
+ case 4:
+ return Literal(std::array<Literal, 4>{{makeLiteral(f32),
+ makeLiteral(f32),
+ makeLiteral(f32),
+ makeLiteral(f32)}});
+ case 5:
+ return Literal(
+ std::array<Literal, 2>{{makeLiteral(f64), makeLiteral(f64)}});
+ default:
+ WASM_UNREACHABLE();
}
}
@@ -1318,13 +1467,18 @@ private:
case 0: {
// totally random, entire range
switch (type) {
- case i32: return Literal(get32());
- case i64: return Literal(get64());
- case f32: return Literal(getFloat());
- case f64: return Literal(getDouble());
+ case i32:
+ return Literal(get32());
+ case i64:
+ return Literal(get64());
+ case f32:
+ return Literal(getFloat());
+ case f64:
+ return Literal(getDouble());
case v128:
case none:
- case unreachable: WASM_UNREACHABLE();
+ case unreachable:
+ WASM_UNREACHABLE();
}
break;
}
@@ -1332,22 +1486,40 @@ private:
// small range
int64_t small;
switch (upTo(6)) {
- case 0: small = int8_t(get()); break;
- case 1: small = uint8_t(get()); break;
- case 2: small = int16_t(get16()); break;
- case 3: small = uint16_t(get16()); break;
- case 4: small = int32_t(get32()); break;
- case 5: small = uint32_t(get32()); break;
- default: WASM_UNREACHABLE();
+ case 0:
+ small = int8_t(get());
+ break;
+ case 1:
+ small = uint8_t(get());
+ break;
+ case 2:
+ small = int16_t(get16());
+ break;
+ case 3:
+ small = uint16_t(get16());
+ break;
+ case 4:
+ small = int32_t(get32());
+ break;
+ case 5:
+ small = uint32_t(get32());
+ break;
+ default:
+ WASM_UNREACHABLE();
}
switch (type) {
- case i32: return Literal(int32_t(small));
- case i64: return Literal(int64_t(small));
- case f32: return Literal(float(small));
- case f64: return Literal(double(small));
+ case i32:
+ return Literal(int32_t(small));
+ case i64:
+ return Literal(int64_t(small));
+ case f32:
+ return Literal(float(small));
+ case f64:
+ return Literal(double(small));
case v128:
case none:
- case unreachable: WASM_UNREACHABLE();
+ case unreachable:
+ WASM_UNREACHABLE();
}
break;
}
@@ -1355,38 +1527,63 @@ private:
// special values
Literal value;
switch (type) {
- case i32: value = Literal(pick<int32_t>(0,
- std::numeric_limits<int8_t>::min(), std::numeric_limits<int8_t>::max(),
- std::numeric_limits<int16_t>::min(), std::numeric_limits<int16_t>::max(),
- std::numeric_limits<int32_t>::min(), std::numeric_limits<int32_t>::max(),
- std::numeric_limits<uint8_t>::max(),
- std::numeric_limits<uint16_t>::max(),
- std::numeric_limits<uint32_t>::max())); break;
- case i64: value = Literal(pick<int64_t>(0,
- std::numeric_limits<int8_t>::min(), std::numeric_limits<int8_t>::max(),
- std::numeric_limits<int16_t>::min(), std::numeric_limits<int16_t>::max(),
- std::numeric_limits<int32_t>::min(), std::numeric_limits<int32_t>::max(),
- std::numeric_limits<int64_t>::min(), std::numeric_limits<int64_t>::max(),
- std::numeric_limits<uint8_t>::max(),
- std::numeric_limits<uint16_t>::max(),
- std::numeric_limits<uint32_t>::max(),
- std::numeric_limits<uint64_t>::max())); break;
- case f32: value = Literal(pick<float>(0,
- std::numeric_limits<float>::min(), std::numeric_limits<float>::max(),
- std::numeric_limits<int32_t>::min(), std::numeric_limits<int32_t>::max(),
- std::numeric_limits<int64_t>::min(), std::numeric_limits<int64_t>::max(),
- std::numeric_limits<uint32_t>::max(),
- std::numeric_limits<uint64_t>::max())); break;
- case f64: value = Literal(pick<double>(0,
- std::numeric_limits<float>::min(), std::numeric_limits<float>::max(),
- std::numeric_limits<double>::min(), std::numeric_limits<double>::max(),
- std::numeric_limits<int32_t>::min(), std::numeric_limits<int32_t>::max(),
- std::numeric_limits<int64_t>::min(), std::numeric_limits<int64_t>::max(),
- std::numeric_limits<uint32_t>::max(),
- std::numeric_limits<uint64_t>::max())); break;
+ case i32:
+ value =
+ Literal(pick<int32_t>(0,
+ std::numeric_limits<int8_t>::min(),
+ std::numeric_limits<int8_t>::max(),
+ std::numeric_limits<int16_t>::min(),
+ std::numeric_limits<int16_t>::max(),
+ std::numeric_limits<int32_t>::min(),
+ std::numeric_limits<int32_t>::max(),
+ std::numeric_limits<uint8_t>::max(),
+ std::numeric_limits<uint16_t>::max(),
+ std::numeric_limits<uint32_t>::max()));
+ break;
+ case i64:
+ value =
+ Literal(pick<int64_t>(0,
+ std::numeric_limits<int8_t>::min(),
+ std::numeric_limits<int8_t>::max(),
+ std::numeric_limits<int16_t>::min(),
+ std::numeric_limits<int16_t>::max(),
+ std::numeric_limits<int32_t>::min(),
+ std::numeric_limits<int32_t>::max(),
+ std::numeric_limits<int64_t>::min(),
+ std::numeric_limits<int64_t>::max(),
+ std::numeric_limits<uint8_t>::max(),
+ std::numeric_limits<uint16_t>::max(),
+ std::numeric_limits<uint32_t>::max(),
+ std::numeric_limits<uint64_t>::max()));
+ break;
+ case f32:
+ value = Literal(pick<float>(0,
+ std::numeric_limits<float>::min(),
+ std::numeric_limits<float>::max(),
+ std::numeric_limits<int32_t>::min(),
+ std::numeric_limits<int32_t>::max(),
+ std::numeric_limits<int64_t>::min(),
+ std::numeric_limits<int64_t>::max(),
+ std::numeric_limits<uint32_t>::max(),
+ std::numeric_limits<uint64_t>::max()));
+ break;
+ case f64:
+ value = Literal(pick<double>(0,
+ std::numeric_limits<float>::min(),
+ std::numeric_limits<float>::max(),
+ std::numeric_limits<double>::min(),
+ std::numeric_limits<double>::max(),
+ std::numeric_limits<int32_t>::min(),
+ std::numeric_limits<int32_t>::max(),
+ std::numeric_limits<int64_t>::min(),
+ std::numeric_limits<int64_t>::max(),
+ std::numeric_limits<uint32_t>::max(),
+ std::numeric_limits<uint64_t>::max()));
+ break;
case v128:
case none:
- case unreachable: WASM_UNREACHABLE();
+ case unreachable:
+ WASM_UNREACHABLE();
}
// tweak around special values
if (oneIn(3)) { // +- 1
@@ -1401,13 +1598,22 @@ private:
// powers of 2
Literal value;
switch (type) {
- case i32: value = Literal(int32_t(1) << upTo(32)); break;
- case i64: value = Literal(int64_t(1) << upTo(64)); break;
- case f32: value = Literal(float(int64_t(1) << upTo(64))); break;
- case f64: value = Literal(double(int64_t(1) << upTo(64))); break;
+ case i32:
+ value = Literal(int32_t(1) << upTo(32));
+ break;
+ case i64:
+ value = Literal(int64_t(1) << upTo(64));
+ break;
+ case f32:
+ value = Literal(float(int64_t(1) << upTo(64)));
+ break;
+ case f64:
+ value = Literal(double(int64_t(1) << upTo(64)));
+ break;
case v128:
case none:
- case unreachable: WASM_UNREACHABLE();
+ case unreachable:
+ WASM_UNREACHABLE();
}
// maybe negative
if (oneIn(2)) {
@@ -1452,105 +1658,178 @@ private:
case i32: {
auto op = pick(
FeatureOptions<UnaryOp>()
- .add(FeatureSet::MVP, EqZInt32, ClzInt32, CtzInt32, PopcntInt32)
- .add(FeatureSet::Atomics, ExtendS8Int32, ExtendS16Int32)
- );
- return buildUnary({ op, make(i32) });
+ .add(FeatureSet::MVP, EqZInt32, ClzInt32, CtzInt32, PopcntInt32)
+ .add(FeatureSet::Atomics, ExtendS8Int32, ExtendS16Int32));
+ return buildUnary({op, make(i32)});
}
- case i64: return buildUnary({ pick(EqZInt64, WrapInt64), make(i64) });
+ case i64:
+ return buildUnary({pick(EqZInt64, WrapInt64), make(i64)});
case f32: {
- auto op = pick(
- FeatureOptions<UnaryOp>()
- .add(FeatureSet::MVP, TruncSFloat32ToInt32, TruncUFloat32ToInt32, ReinterpretFloat32)
- .add(FeatureSet::TruncSat, TruncSatSFloat32ToInt32, TruncSatUFloat32ToInt32)
- );
- return buildUnary({ op, make(f32) });
+ auto op = pick(FeatureOptions<UnaryOp>()
+ .add(FeatureSet::MVP,
+ TruncSFloat32ToInt32,
+ TruncUFloat32ToInt32,
+ ReinterpretFloat32)
+ .add(FeatureSet::TruncSat,
+ TruncSatSFloat32ToInt32,
+ TruncSatUFloat32ToInt32));
+ return buildUnary({op, make(f32)});
}
case f64: {
- auto op = pick(
- FeatureOptions<UnaryOp>()
- .add(FeatureSet::MVP, TruncSFloat64ToInt32, TruncUFloat64ToInt32)
- .add(FeatureSet::TruncSat, TruncSatSFloat64ToInt32, TruncSatUFloat64ToInt32)
- );
- return buildUnary({ op, make(f64) });
+ auto op = pick(FeatureOptions<UnaryOp>()
+ .add(FeatureSet::MVP,
+ TruncSFloat64ToInt32,
+ TruncUFloat64ToInt32)
+ .add(FeatureSet::TruncSat,
+ TruncSatSFloat64ToInt32,
+ TruncSatUFloat64ToInt32));
+ return buildUnary({op, make(f64)});
}
case v128: {
assert(wasm.features.hasSIMD());
- return buildUnary({ pick(AnyTrueVecI8x16, AllTrueVecI8x16, AnyTrueVecI16x8, AllTrueVecI16x8,
- AnyTrueVecI32x4, AllTrueVecI32x4, AnyTrueVecI64x2, AllTrueVecI64x2),
- make(v128) });
+ return buildUnary({pick(AnyTrueVecI8x16,
+ AllTrueVecI8x16,
+ AnyTrueVecI16x8,
+ AllTrueVecI16x8,
+ AnyTrueVecI32x4,
+ AllTrueVecI32x4,
+ AnyTrueVecI64x2,
+ AllTrueVecI64x2),
+ make(v128)});
}
case none:
- case unreachable: WASM_UNREACHABLE();
+ case unreachable:
+ WASM_UNREACHABLE();
}
WASM_UNREACHABLE();
}
case i64: {
switch (upTo(4)) {
case 0: {
- auto op = pick(
- FeatureOptions<UnaryOp>()
- .add(FeatureSet::MVP, ClzInt64, CtzInt64, PopcntInt64)
- .add(FeatureSet::Atomics, ExtendS8Int64, ExtendS16Int64, ExtendS32Int64)
- );
- return buildUnary({ op, make(i64) });
+ auto op =
+ pick(FeatureOptions<UnaryOp>()
+ .add(FeatureSet::MVP, ClzInt64, CtzInt64, PopcntInt64)
+ .add(FeatureSet::Atomics,
+ ExtendS8Int64,
+ ExtendS16Int64,
+ ExtendS32Int64));
+ return buildUnary({op, make(i64)});
}
- case 1: return buildUnary({ pick(ExtendSInt32, ExtendUInt32), make(i32) });
+ case 1:
+ return buildUnary({pick(ExtendSInt32, ExtendUInt32), make(i32)});
case 2: {
- auto op = pick(
- FeatureOptions<UnaryOp>()
- .add(FeatureSet::MVP, TruncSFloat32ToInt64, TruncUFloat32ToInt64)
- .add(FeatureSet::TruncSat, TruncSatSFloat32ToInt64, TruncSatUFloat32ToInt64)
- );
- return buildUnary({ op, make(f32) });
+ auto op = pick(FeatureOptions<UnaryOp>()
+ .add(FeatureSet::MVP,
+ TruncSFloat32ToInt64,
+ TruncUFloat32ToInt64)
+ .add(FeatureSet::TruncSat,
+ TruncSatSFloat32ToInt64,
+ TruncSatUFloat32ToInt64));
+ return buildUnary({op, make(f32)});
}
case 3: {
- auto op = pick(
- FeatureOptions<UnaryOp>()
- .add(FeatureSet::MVP, TruncSFloat64ToInt64, TruncUFloat64ToInt64, ReinterpretFloat64)
- .add(FeatureSet::TruncSat, TruncSatSFloat64ToInt64, TruncSatUFloat64ToInt64)
- );
- return buildUnary({ op, make(f64) });
+ auto op = pick(FeatureOptions<UnaryOp>()
+ .add(FeatureSet::MVP,
+ TruncSFloat64ToInt64,
+ TruncUFloat64ToInt64,
+ ReinterpretFloat64)
+ .add(FeatureSet::TruncSat,
+ TruncSatSFloat64ToInt64,
+ TruncSatUFloat64ToInt64));
+ return buildUnary({op, make(f64)});
}
}
WASM_UNREACHABLE();
}
case f32: {
switch (upTo(4)) {
- case 0: return makeDeNanOp(buildUnary({ pick(NegFloat32, AbsFloat32, CeilFloat32, FloorFloat32, TruncFloat32, NearestFloat32, SqrtFloat32), make(f32) }));
- case 1: return makeDeNanOp(buildUnary({ pick(ConvertUInt32ToFloat32, ConvertSInt32ToFloat32, ReinterpretInt32), make(i32) }));
- case 2: return makeDeNanOp(buildUnary({ pick(ConvertUInt64ToFloat32, ConvertSInt64ToFloat32), make(i64) }));
- case 3: return makeDeNanOp(buildUnary({ DemoteFloat64, make(f64) }));
+ case 0:
+ return makeDeNanOp(buildUnary({pick(NegFloat32,
+ AbsFloat32,
+ CeilFloat32,
+ FloorFloat32,
+ TruncFloat32,
+ NearestFloat32,
+ SqrtFloat32),
+ make(f32)}));
+ case 1:
+ return makeDeNanOp(buildUnary({pick(ConvertUInt32ToFloat32,
+ ConvertSInt32ToFloat32,
+ ReinterpretInt32),
+ make(i32)}));
+ case 2:
+ return makeDeNanOp(
+ buildUnary({pick(ConvertUInt64ToFloat32, ConvertSInt64ToFloat32),
+ make(i64)}));
+ case 3:
+ return makeDeNanOp(buildUnary({DemoteFloat64, make(f64)}));
}
WASM_UNREACHABLE();
}
case f64: {
switch (upTo(4)) {
- case 0: return makeDeNanOp(buildUnary({ pick(NegFloat64, AbsFloat64, CeilFloat64, FloorFloat64, TruncFloat64, NearestFloat64, SqrtFloat64), make(f64) }));
- case 1: return makeDeNanOp(buildUnary({ pick(ConvertUInt32ToFloat64, ConvertSInt32ToFloat64), make(i32) }));
- case 2: return makeDeNanOp(buildUnary({ pick(ConvertUInt64ToFloat64, ConvertSInt64ToFloat64, ReinterpretInt64), make(i64) }));
- case 3: return makeDeNanOp(buildUnary({ PromoteFloat32, make(f32) }));
+ case 0:
+ return makeDeNanOp(buildUnary({pick(NegFloat64,
+ AbsFloat64,
+ CeilFloat64,
+ FloorFloat64,
+ TruncFloat64,
+ NearestFloat64,
+ SqrtFloat64),
+ make(f64)}));
+ case 1:
+ return makeDeNanOp(
+ buildUnary({pick(ConvertUInt32ToFloat64, ConvertSInt32ToFloat64),
+ make(i32)}));
+ case 2:
+ return makeDeNanOp(buildUnary({pick(ConvertUInt64ToFloat64,
+ ConvertSInt64ToFloat64,
+ ReinterpretInt64),
+ make(i64)}));
+ case 3:
+ return makeDeNanOp(buildUnary({PromoteFloat32, make(f32)}));
}
WASM_UNREACHABLE();
}
case v128: {
assert(wasm.features.hasSIMD());
switch (upTo(5)) {
- case 0: return buildUnary({ pick(SplatVecI8x16, SplatVecI16x8, SplatVecI32x4), make(i32) });
- case 1: return buildUnary({ SplatVecI64x2, make(i64) });
- case 2: return buildUnary({ SplatVecF32x4, make(f32) });
- case 3: return buildUnary({ SplatVecF64x2, make(f64) });
- case 4: return buildUnary({
- pick(NotVec128, NegVecI8x16, NegVecI16x8, NegVecI32x4, NegVecI64x2,
- AbsVecF32x4, NegVecF32x4, SqrtVecF32x4, AbsVecF64x2, NegVecF64x2, SqrtVecF64x2,
- TruncSatSVecF32x4ToVecI32x4, TruncSatUVecF32x4ToVecI32x4, TruncSatSVecF64x2ToVecI64x2, TruncSatUVecF64x2ToVecI64x2,
- ConvertSVecI32x4ToVecF32x4, ConvertUVecI32x4ToVecF32x4, ConvertSVecI64x2ToVecF64x2, ConvertUVecI64x2ToVecF64x2),
- make(v128) });
+ case 0:
+ return buildUnary(
+ {pick(SplatVecI8x16, SplatVecI16x8, SplatVecI32x4), make(i32)});
+ case 1:
+ return buildUnary({SplatVecI64x2, make(i64)});
+ case 2:
+ return buildUnary({SplatVecF32x4, make(f32)});
+ case 3:
+ return buildUnary({SplatVecF64x2, make(f64)});
+ case 4:
+ return buildUnary({pick(NotVec128,
+ NegVecI8x16,
+ NegVecI16x8,
+ NegVecI32x4,
+ NegVecI64x2,
+ AbsVecF32x4,
+ NegVecF32x4,
+ SqrtVecF32x4,
+ AbsVecF64x2,
+ NegVecF64x2,
+ SqrtVecF64x2,
+ TruncSatSVecF32x4ToVecI32x4,
+ TruncSatUVecF32x4ToVecI32x4,
+ TruncSatSVecF64x2ToVecI64x2,
+ TruncSatUVecF64x2ToVecI64x2,
+ ConvertSVecI32x4ToVecF32x4,
+ ConvertUVecI32x4ToVecF32x4,
+ ConvertSVecI64x2ToVecF64x2,
+ ConvertUVecI64x2ToVecF64x2),
+ make(v128)});
}
WASM_UNREACHABLE();
}
case none:
- case unreachable: WASM_UNREACHABLE();
+ case unreachable:
+ WASM_UNREACHABLE();
}
WASM_UNREACHABLE();
}
@@ -1562,7 +1841,8 @@ private:
Expression* makeBinary(Type type) {
if (type == unreachable) {
if (auto* binary = makeBinary(getConcreteType())->dynCast<Binary>()) {
- return makeDeNanOp(buildBinary({ binary->op, make(unreachable), make(unreachable) }));
+ return makeDeNanOp(
+ buildBinary({binary->op, make(unreachable), make(unreachable)}));
}
// give up
return makeTrivial(type);
@@ -1570,37 +1850,193 @@ private:
switch (type) {
case i32: {
switch (upTo(4)) {
- case 0: return buildBinary({ pick(AddInt32, SubInt32, MulInt32, DivSInt32, DivUInt32, RemSInt32, RemUInt32, AndInt32, OrInt32, XorInt32, ShlInt32, ShrUInt32, ShrSInt32, RotLInt32, RotRInt32, EqInt32, NeInt32, LtSInt32, LtUInt32, LeSInt32, LeUInt32, GtSInt32, GtUInt32, GeSInt32, GeUInt32), make(i32), make(i32) });
- case 1: return buildBinary({ pick(EqInt64, NeInt64, LtSInt64, LtUInt64, LeSInt64, LeUInt64, GtSInt64, GtUInt64, GeSInt64, GeUInt64), make(i64), make(i64) });
- case 2: return buildBinary({ pick(EqFloat32, NeFloat32, LtFloat32, LeFloat32, GtFloat32, GeFloat32), make(f32), make(f32) });
- case 3: return buildBinary({ pick(EqFloat64, NeFloat64, LtFloat64, LeFloat64, GtFloat64, GeFloat64), make(f64), make(f64) });
+ case 0:
+ return buildBinary({pick(AddInt32,
+ SubInt32,
+ MulInt32,
+ DivSInt32,
+ DivUInt32,
+ RemSInt32,
+ RemUInt32,
+ AndInt32,
+ OrInt32,
+ XorInt32,
+ ShlInt32,
+ ShrUInt32,
+ ShrSInt32,
+ RotLInt32,
+ RotRInt32,
+ EqInt32,
+ NeInt32,
+ LtSInt32,
+ LtUInt32,
+ LeSInt32,
+ LeUInt32,
+ GtSInt32,
+ GtUInt32,
+ GeSInt32,
+ GeUInt32),
+ make(i32),
+ make(i32)});
+ case 1:
+ return buildBinary({pick(EqInt64,
+ NeInt64,
+ LtSInt64,
+ LtUInt64,
+ LeSInt64,
+ LeUInt64,
+ GtSInt64,
+ GtUInt64,
+ GeSInt64,
+ GeUInt64),
+ make(i64),
+ make(i64)});
+ case 2:
+ return buildBinary({pick(EqFloat32,
+ NeFloat32,
+ LtFloat32,
+ LeFloat32,
+ GtFloat32,
+ GeFloat32),
+ make(f32),
+ make(f32)});
+ case 3:
+ return buildBinary({pick(EqFloat64,
+ NeFloat64,
+ LtFloat64,
+ LeFloat64,
+ GtFloat64,
+ GeFloat64),
+ make(f64),
+ make(f64)});
}
WASM_UNREACHABLE();
}
case i64: {
- return buildBinary({ pick(AddInt64, SubInt64, MulInt64, DivSInt64, DivUInt64, RemSInt64, RemUInt64, AndInt64, OrInt64, XorInt64, ShlInt64, ShrUInt64, ShrSInt64, RotLInt64, RotRInt64), make(i64), make(i64) });
+ return buildBinary({pick(AddInt64,
+ SubInt64,
+ MulInt64,
+ DivSInt64,
+ DivUInt64,
+ RemSInt64,
+ RemUInt64,
+ AndInt64,
+ OrInt64,
+ XorInt64,
+ ShlInt64,
+ ShrUInt64,
+ ShrSInt64,
+ RotLInt64,
+ RotRInt64),
+ make(i64),
+ make(i64)});
}
case f32: {
- return makeDeNanOp(buildBinary({ pick(AddFloat32, SubFloat32, MulFloat32, DivFloat32, CopySignFloat32, MinFloat32, MaxFloat32), make(f32), make(f32) }));
+ return makeDeNanOp(buildBinary({pick(AddFloat32,
+ SubFloat32,
+ MulFloat32,
+ DivFloat32,
+ CopySignFloat32,
+ MinFloat32,
+ MaxFloat32),
+ make(f32),
+ make(f32)}));
}
case f64: {
- return makeDeNanOp(buildBinary({ pick(AddFloat64, SubFloat64, MulFloat64, DivFloat64, CopySignFloat64, MinFloat64, MaxFloat64), make(f64), make(f64) }));
+ return makeDeNanOp(buildBinary({pick(AddFloat64,
+ SubFloat64,
+ MulFloat64,
+ DivFloat64,
+ CopySignFloat64,
+ MinFloat64,
+ MaxFloat64),
+ make(f64),
+ make(f64)}));
}
case v128: {
assert(wasm.features.hasSIMD());
- return buildBinary({
- pick(EqVecI8x16, NeVecI8x16, LtSVecI8x16, LtUVecI8x16, GtSVecI8x16, GtUVecI8x16, LeSVecI8x16, LeUVecI8x16, GeSVecI8x16, GeUVecI8x16,
- EqVecI16x8, NeVecI16x8, LtSVecI16x8, LtUVecI16x8, GtSVecI16x8, GtUVecI16x8, LeSVecI16x8, LeUVecI16x8, GeSVecI16x8, GeUVecI16x8,
- EqVecI32x4, NeVecI32x4, LtSVecI32x4, LtUVecI32x4, GtSVecI32x4, GtUVecI32x4, LeSVecI32x4, LeUVecI32x4, GeSVecI32x4, GeUVecI32x4,
- EqVecF32x4, NeVecF32x4, LtVecF32x4, GtVecF32x4, LeVecF32x4, GeVecF32x4, EqVecF64x2, NeVecF64x2, LtVecF64x2, GtVecF64x2, LeVecF64x2, GeVecF64x2,
- AndVec128, OrVec128, XorVec128, AddVecI8x16, AddSatSVecI8x16, AddSatUVecI8x16, SubVecI8x16, SubSatSVecI8x16, SubSatUVecI8x16, MulVecI8x16,
- AddVecI16x8, AddSatSVecI16x8, AddSatUVecI16x8, SubVecI16x8, SubSatSVecI16x8, SubSatUVecI16x8, MulVecI16x8, AddVecI32x4, SubVecI32x4, MulVecI32x4,
- AddVecI64x2, SubVecI64x2, AddVecF32x4, SubVecF32x4, MulVecF32x4, DivVecF32x4, MinVecF32x4, MaxVecF32x4,
- AddVecF64x2, SubVecF64x2, MulVecF64x2, DivVecF64x2, MinVecF64x2, MaxVecF64x2),
- make(v128), make(v128) });
+ return buildBinary({pick(EqVecI8x16,
+ NeVecI8x16,
+ LtSVecI8x16,
+ LtUVecI8x16,
+ GtSVecI8x16,
+ GtUVecI8x16,
+ LeSVecI8x16,
+ LeUVecI8x16,
+ GeSVecI8x16,
+ GeUVecI8x16,
+ EqVecI16x8,
+ NeVecI16x8,
+ LtSVecI16x8,
+ LtUVecI16x8,
+ GtSVecI16x8,
+ GtUVecI16x8,
+ LeSVecI16x8,
+ LeUVecI16x8,
+ GeSVecI16x8,
+ GeUVecI16x8,
+ EqVecI32x4,
+ NeVecI32x4,
+ LtSVecI32x4,
+ LtUVecI32x4,
+ GtSVecI32x4,
+ GtUVecI32x4,
+ LeSVecI32x4,
+ LeUVecI32x4,
+ GeSVecI32x4,
+ GeUVecI32x4,
+ EqVecF32x4,
+ NeVecF32x4,
+ LtVecF32x4,
+ GtVecF32x4,
+ LeVecF32x4,
+ GeVecF32x4,
+ EqVecF64x2,
+ NeVecF64x2,
+ LtVecF64x2,
+ GtVecF64x2,
+ LeVecF64x2,
+ GeVecF64x2,
+ AndVec128,
+ OrVec128,
+ XorVec128,
+ AddVecI8x16,
+ AddSatSVecI8x16,
+ AddSatUVecI8x16,
+ SubVecI8x16,
+ SubSatSVecI8x16,
+ SubSatUVecI8x16,
+ MulVecI8x16,
+ AddVecI16x8,
+ AddSatSVecI16x8,
+ AddSatUVecI16x8,
+ SubVecI16x8,
+ SubSatSVecI16x8,
+ SubSatUVecI16x8,
+ MulVecI16x8,
+ AddVecI32x4,
+ SubVecI32x4,
+ MulVecI32x4,
+ AddVecI64x2,
+ SubVecI64x2,
+ AddVecF32x4,
+ SubVecF32x4,
+ MulVecF32x4,
+ DivVecF32x4,
+ MinVecF32x4,
+ MaxVecF32x4,
+ AddVecF64x2,
+ SubVecF64x2,
+ MulVecF64x2,
+ DivVecF64x2,
+ MinVecF64x2,
+ MaxVecF64x2),
+ make(v128),
+ make(v128)});
}
case none:
- case unreachable: WASM_UNREACHABLE();
+ case unreachable:
+ WASM_UNREACHABLE();
}
WASM_UNREACHABLE();
}
@@ -1610,12 +2046,13 @@ private:
}
Expression* makeSelect(Type type) {
- return makeDeNanOp(buildSelect({ make(i32), make(type), make(type) }));
+ return makeDeNanOp(buildSelect({make(i32), make(type), make(type)}));
}
Expression* makeSwitch(Type type) {
assert(type == unreachable);
- if (breakableStack.empty()) return make(type);
+ if (breakableStack.empty())
+ return make(type);
// we need to find proper targets to break to; try a bunch
int tries = TRIES;
std::vector<Name> names;
@@ -1639,16 +2076,19 @@ private:
}
auto default_ = names.back();
names.pop_back();
- auto temp1 = make(i32), temp2 = isConcreteType(valueType) ? make(valueType) : nullptr;
+ auto temp1 = make(i32),
+ temp2 = isConcreteType(valueType) ? make(valueType) : nullptr;
return builder.makeSwitch(names, default_, temp1, temp2);
}
Expression* makeDrop(Type type) {
- return builder.makeDrop(make(type == unreachable ? type : getConcreteType()));
+ return builder.makeDrop(
+ make(type == unreachable ? type : getConcreteType()));
}
Expression* makeReturn(Type type) {
- return builder.makeReturn(isConcreteType(func->result) ? make(func->result) : nullptr);
+ return builder.makeReturn(isConcreteType(func->result) ? make(func->result)
+ : nullptr);
}
Expression* makeNop(Type type) {
@@ -1663,7 +2103,8 @@ private:
Expression* makeAtomic(Type type) {
assert(wasm.features.hasAtomics());
- if (!allowMemory) return makeTrivial(type);
+ if (!allowMemory)
+ return makeTrivial(type);
wasm.memory.shared = true;
if (type == i32 && oneIn(2)) {
if (ATOMIC_WAITS && oneIn(2)) {
@@ -1671,7 +2112,8 @@ private:
auto expectedType = pick(i32, i64);
auto* expected = make(expectedType);
auto* timeout = make(i64);
- return builder.makeAtomicWait(ptr, expected, timeout, expectedType, logify(get()));
+ return builder.makeAtomicWait(
+ ptr, expected, timeout, expectedType, logify(get()));
} else {
auto* ptr = makePointer();
auto* count = make(i32);
@@ -1682,35 +2124,62 @@ private:
switch (type) {
case i32: {
switch (upTo(3)) {
- case 0: bytes = 1; break;
- case 1: bytes = pick(1, 2); break;
- case 2: bytes = pick(1, 2, 4); break;
- default: WASM_UNREACHABLE();
+ case 0:
+ bytes = 1;
+ break;
+ case 1:
+ bytes = pick(1, 2);
+ break;
+ case 2:
+ bytes = pick(1, 2, 4);
+ break;
+ default:
+ WASM_UNREACHABLE();
}
break;
}
case i64: {
switch (upTo(4)) {
- case 0: bytes = 1; break;
- case 1: bytes = pick(1, 2); break;
- case 2: bytes = pick(1, 2, 4); break;
- case 3: bytes = pick(1, 2, 4, 8); break;
- default: WASM_UNREACHABLE();
+ case 0:
+ bytes = 1;
+ break;
+ case 1:
+ bytes = pick(1, 2);
+ break;
+ case 2:
+ bytes = pick(1, 2, 4);
+ break;
+ case 3:
+ bytes = pick(1, 2, 4, 8);
+ break;
+ default:
+ WASM_UNREACHABLE();
}
break;
}
- default: WASM_UNREACHABLE();
+ default:
+ WASM_UNREACHABLE();
}
auto offset = logify(get());
auto* ptr = makePointer();
if (oneIn(2)) {
auto* value = make(type);
- return builder.makeAtomicRMW(pick(AtomicRMWOp::Add, AtomicRMWOp::Sub, AtomicRMWOp::And, AtomicRMWOp::Or, AtomicRMWOp::Xor, AtomicRMWOp::Xchg),
- bytes, offset, ptr, value, type);
+ return builder.makeAtomicRMW(pick(AtomicRMWOp::Add,
+ AtomicRMWOp::Sub,
+ AtomicRMWOp::And,
+ AtomicRMWOp::Or,
+ AtomicRMWOp::Xor,
+ AtomicRMWOp::Xchg),
+ bytes,
+ offset,
+ ptr,
+ value,
+ type);
} else {
auto* expected = make(type);
auto* replacement = make(type);
- return builder.makeAtomicCmpxchg(bytes, offset, ptr, expected, replacement, type);
+ return builder.makeAtomicCmpxchg(
+ bytes, offset, ptr, expected, replacement, type);
}
}
@@ -1720,12 +2189,18 @@ private:
return makeSIMDExtract(type);
}
switch (upTo(6)) {
- case 0: return makeUnary(v128);
- case 1: return makeBinary(v128);
- case 2: return makeSIMDReplace();
- case 3: return makeSIMDShuffle();
- case 4: return makeSIMDBitselect();
- case 5: return makeSIMDShift();
+ case 0:
+ return makeUnary(v128);
+ case 1:
+ return makeBinary(v128);
+ case 2:
+ return makeSIMDReplace();
+ case 3:
+ return makeSIMDShuffle();
+ case 4:
+ return makeSIMDBitselect();
+ case 5:
+ return makeSIMDShift();
}
WASM_UNREACHABLE();
}
@@ -1733,43 +2208,87 @@ private:
Expression* makeSIMDExtract(Type type) {
auto op = static_cast<SIMDExtractOp>(0);
switch (type) {
- case i32: op = pick(ExtractLaneSVecI8x16, ExtractLaneUVecI8x16, ExtractLaneSVecI16x8, ExtractLaneUVecI16x8, ExtractLaneVecI32x4); break;
- case i64: op = ExtractLaneVecI64x2; break;
- case f32: op = ExtractLaneVecF32x4; break;
- case f64: op = ExtractLaneVecF64x2; break;
+ case i32:
+ op = pick(ExtractLaneSVecI8x16,
+ ExtractLaneUVecI8x16,
+ ExtractLaneSVecI16x8,
+ ExtractLaneUVecI16x8,
+ ExtractLaneVecI32x4);
+ break;
+ case i64:
+ op = ExtractLaneVecI64x2;
+ break;
+ case f32:
+ op = ExtractLaneVecF32x4;
+ break;
+ case f64:
+ op = ExtractLaneVecF64x2;
+ break;
case v128:
case none:
- case unreachable: WASM_UNREACHABLE();
+ case unreachable:
+ WASM_UNREACHABLE();
}
Expression* vec = make(v128);
uint8_t index = 0;
switch (op) {
case ExtractLaneSVecI8x16:
- case ExtractLaneUVecI8x16: index = upTo(16); break;
+ case ExtractLaneUVecI8x16:
+ index = upTo(16);
+ break;
case ExtractLaneSVecI16x8:
- case ExtractLaneUVecI16x8: index = upTo(8); break;
+ case ExtractLaneUVecI16x8:
+ index = upTo(8);
+ break;
case ExtractLaneVecI32x4:
- case ExtractLaneVecF32x4: index = upTo(4); break;
+ case ExtractLaneVecF32x4:
+ index = upTo(4);
+ break;
case ExtractLaneVecI64x2:
- case ExtractLaneVecF64x2: index = upTo(2); break;
+ case ExtractLaneVecF64x2:
+ index = upTo(2);
+ break;
}
return builder.makeSIMDExtract(op, vec, index);
}
Expression* makeSIMDReplace() {
- SIMDReplaceOp op = pick(ReplaceLaneVecI8x16, ReplaceLaneVecI16x8, ReplaceLaneVecI32x4,
- ReplaceLaneVecI64x2, ReplaceLaneVecF32x4, ReplaceLaneVecF64x2);
+ SIMDReplaceOp op = pick(ReplaceLaneVecI8x16,
+ ReplaceLaneVecI16x8,
+ ReplaceLaneVecI32x4,
+ ReplaceLaneVecI64x2,
+ ReplaceLaneVecF32x4,
+ ReplaceLaneVecF64x2);
Expression* vec = make(v128);
uint8_t index;
Type lane_t;
switch (op) {
- case ReplaceLaneVecI8x16: index = upTo(16); lane_t = i32; break;
- case ReplaceLaneVecI16x8: index = upTo(8); lane_t = i32; break;
- case ReplaceLaneVecI32x4: index = upTo(4); lane_t = i32; break;
- case ReplaceLaneVecI64x2: index = upTo(2); lane_t = i64; break;
- case ReplaceLaneVecF32x4: index = upTo(4); lane_t = f32; break;
- case ReplaceLaneVecF64x2: index = upTo(2); lane_t = f64; break;
- default: WASM_UNREACHABLE();
+ case ReplaceLaneVecI8x16:
+ index = upTo(16);
+ lane_t = i32;
+ break;
+ case ReplaceLaneVecI16x8:
+ index = upTo(8);
+ lane_t = i32;
+ break;
+ case ReplaceLaneVecI32x4:
+ index = upTo(4);
+ lane_t = i32;
+ break;
+ case ReplaceLaneVecI64x2:
+ index = upTo(2);
+ lane_t = i64;
+ break;
+ case ReplaceLaneVecF32x4:
+ index = upTo(4);
+ lane_t = f32;
+ break;
+ case ReplaceLaneVecF64x2:
+ index = upTo(2);
+ lane_t = f64;
+ break;
+ default:
+ WASM_UNREACHABLE();
}
Expression* value = make(lane_t);
return builder.makeSIMDReplace(op, vec, index, value);
@@ -1793,28 +2312,44 @@ private:
}
Expression* makeSIMDShift() {
- SIMDShiftOp op = pick(ShlVecI8x16, ShrSVecI8x16, ShrUVecI8x16, ShlVecI16x8, ShrSVecI16x8, ShrUVecI16x8,
- ShlVecI32x4, ShrSVecI32x4, ShrUVecI32x4, ShlVecI64x2, ShrSVecI64x2, ShrUVecI64x2);
+ SIMDShiftOp op = pick(ShlVecI8x16,
+ ShrSVecI8x16,
+ ShrUVecI8x16,
+ ShlVecI16x8,
+ ShrSVecI16x8,
+ ShrUVecI16x8,
+ ShlVecI32x4,
+ ShrSVecI32x4,
+ ShrUVecI32x4,
+ ShlVecI64x2,
+ ShrSVecI64x2,
+ ShrUVecI64x2);
Expression* vec = make(v128);
Expression* shift = make(i32);
return builder.makeSIMDShift(op, vec, shift);
}
Expression* makeBulkMemory(Type type) {
- if (!allowMemory) return makeTrivial(type);
+ if (!allowMemory)
+ return makeTrivial(type);
assert(wasm.features.hasBulkMemory());
assert(type == none);
switch (upTo(4)) {
- case 0: return makeMemoryInit();
- case 1: return makeDataDrop();
- case 2: return makeMemoryCopy();
- case 3: return makeMemoryFill();
+ case 0:
+ return makeMemoryInit();
+ case 1:
+ return makeDataDrop();
+ case 2:
+ return makeMemoryCopy();
+ case 3:
+ return makeMemoryFill();
}
WASM_UNREACHABLE();
}
Expression* makeMemoryInit() {
- if (!allowMemory) return makeTrivial(none);
+ if (!allowMemory)
+ return makeTrivial(none);
uint32_t segment = upTo(wasm.memory.segments.size());
size_t totalSize = wasm.memory.segments[segment].data.size();
size_t offsetVal = upTo(totalSize);
@@ -1826,12 +2361,14 @@ private:
}
Expression* makeDataDrop() {
- if (!allowMemory) return makeTrivial(none);
+ if (!allowMemory)
+ return makeTrivial(none);
return builder.makeDataDrop(upTo(wasm.memory.segments.size()));
}
Expression* makeMemoryCopy() {
- if (!allowMemory) return makeTrivial(none);
+ if (!allowMemory)
+ return makeTrivial(none);
Expression* dest = makePointer();
Expression* source = makePointer();
Expression* size = make(i32);
@@ -1839,7 +2376,8 @@ private:
}
Expression* makeMemoryFill() {
- if (!allowMemory) return makeTrivial(none);
+ if (!allowMemory)
+ return makeTrivial(none);
Expression* dest = makePointer();
Expression* value = makePointer();
Expression* size = make(i32);
@@ -1850,32 +2388,33 @@ private:
Expression* makeLogging() {
auto type = pick(i32, i64, f32, f64);
- return builder.makeCall(std::string("log-") + printType(type), { make(type) }, none);
+ return builder.makeCall(
+ std::string("log-") + printType(type), {make(type)}, none);
}
Expression* makeMemoryHashLogging() {
auto* hash = builder.makeCall(std::string("hashMemory"), {}, i32);
- return builder.makeCall(std::string("log-i32"), { hash }, none);
+ return builder.makeCall(std::string("log-i32"), {hash}, none);
}
// special getters
Type getType() {
return pick(FeatureOptions<Type>()
- .add(FeatureSet::MVP, i32, i64, f32, f64, none, unreachable)
- .add(FeatureSet::SIMD, v128));
+ .add(FeatureSet::MVP, i32, i64, f32, f64, none, unreachable)
+ .add(FeatureSet::SIMD, v128));
}
Type getReachableType() {
return pick(FeatureOptions<Type>()
- .add(FeatureSet::MVP, i32, i64, f32, f64, none)
- .add(FeatureSet::SIMD, v128));
+ .add(FeatureSet::MVP, i32, i64, f32, f64, none)
+ .add(FeatureSet::SIMD, v128));
}
Type getConcreteType() {
return pick(FeatureOptions<Type>()
- .add(FeatureSet::MVP, i32, i64, f32, f64)
- .add(FeatureSet::SIMD, v128));
+ .add(FeatureSet::MVP, i32, i64, f32, f64)
+ .add(FeatureSet::SIMD, v128));
}
// statistical distributions
@@ -1889,7 +2428,8 @@ private:
// this isn't a perfectly uniform distribution, but it's fast
// and reasonable
Index upTo(Index x) {
- if (x == 0) return 0;
+ if (x == 0)
+ return 0;
Index raw;
if (x <= 255) {
raw = get();
@@ -1904,9 +2444,7 @@ private:
return ret;
}
- bool oneIn(Index x) {
- return upTo(x) == 0;
- }
+ bool oneIn(Index x) { return upTo(x) == 0; }
bool onceEvery(Index x) {
static int counter = 0;
@@ -1916,69 +2454,60 @@ private:
// apply upTo twice, generating a skewed distribution towards
// low values
- Index upToSquared(Index x) {
- return upTo(upTo(x));
- }
+ Index upToSquared(Index x) { return upTo(upTo(x)); }
// pick from a vector
- template<typename T>
- const T& vectorPick(const std::vector<T>& vec) {
+ template<typename T> const T& vectorPick(const std::vector<T>& vec) {
assert(!vec.empty());
auto index = upTo(vec.size());
return vec[index];
}
// pick from a fixed list
- template<typename T, typename... Args>
- T pick(T first, Args... args) {
+ template<typename T, typename... Args> T pick(T first, Args... args) {
auto num = sizeof...(Args) + 1;
auto temp = upTo(num);
return pickGivenNum<T>(temp, first, args...);
}
- template<typename T>
- T pickGivenNum(size_t num, T first) {
+ template<typename T> T pickGivenNum(size_t num, T first) {
assert(num == 0);
return first;
}
- // Trick to avoid a bug in GCC 7.x.
- // Upstream bug report: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=82800
- #define GCC_VERSION (__GNUC__ * 10000 \
- + __GNUC_MINOR__ * 100 \
- + __GNUC_PATCHLEVEL__)
- #if GCC_VERSION > 70000 && GCC_VERSION < 70300
- #pragma GCC diagnostic push
- #pragma GCC diagnostic ignored "-Wmaybe-uninitialized"
- #endif
+// Trick to avoid a bug in GCC 7.x.
+// Upstream bug report: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=82800
+#define GCC_VERSION \
+ (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__)
+#if GCC_VERSION > 70000 && GCC_VERSION < 70300
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wmaybe-uninitialized"
+#endif
template<typename T, typename... Args>
T pickGivenNum(size_t num, T first, Args... args) {
- if (num == 0) return first;
+ if (num == 0)
+ return first;
return pickGivenNum<T>(num - 1, args...);
}
- #if GCC_VERSION > 70000 && GCC_VERSION < 70300
- #pragma GCC diagnostic pop
- #endif
+#if GCC_VERSION > 70000 && GCC_VERSION < 70300
+#pragma GCC diagnostic pop
+#endif
- template<typename T>
- struct FeatureOptions {
- template<typename ...Ts>
+ template<typename T> struct FeatureOptions {
+ template<typename... Ts>
FeatureOptions<T>& add(FeatureSet::Feature feature, T option, Ts... rest) {
options[feature].push_back(option);
return add(feature, rest...);
}
- FeatureOptions<T>& add(FeatureSet::Feature feature) {
- return *this;
- }
+ FeatureOptions<T>& add(FeatureSet::Feature feature) { return *this; }
std::map<FeatureSet::Feature, std::vector<T>> options;
};
- template<typename T>
- const T pick(FeatureOptions<T>& picker) {
+ template<typename T> const T pick(FeatureOptions<T>& picker) {
std::vector<T> matches;
for (const auto& item : picker.options) {
if (wasm.features.has(item.first)) {
@@ -2012,6 +2541,7 @@ private:
} // namespace wasm
-// XXX Switch class has a condition?! is it real? should the node type be the value type if it exists?!
+// XXX Switch class has a condition?! is it real? should the node type be the
+// value type if it exists?!
// TODO copy an existing function and replace just one node in it
diff --git a/src/tools/js-wrapper.h b/src/tools/js-wrapper.h
index 433d6fc5a..e39a015d6 100644
--- a/src/tools/js-wrapper.h
+++ b/src/tools/js-wrapper.h
@@ -28,7 +28,8 @@ static std::string generateJSWrapper(Module& wasm) {
"}\n"
"var tempRet0;\n"
"var binary;\n"
- "if (typeof process === 'object' && typeof require === 'function' /* node.js detection */) {\n"
+ "if (typeof process === 'object' && typeof require === 'function' /* "
+ "node.js detection */) {\n"
" var args = process.argv.slice(2);\n"
" binary = require('fs').readFileSync(args[0]);\n"
" if (!binary.buffer) binary = new Uint8Array(binary);\n"
@@ -59,12 +60,21 @@ static std::string generateJSWrapper(Module& wasm) {
" }\n"
" return ret;\n"
"}\n"
- "var instance = new WebAssembly.Instance(new WebAssembly.Module(binary), {\n"
+ "var instance = new WebAssembly.Instance(new "
+ "WebAssembly.Module(binary), {\n"
" 'fuzzing-support': {\n"
- " 'log-i32': function(x) { console.log('[LoggingExternalInterface logging ' + literal(x, 'i32') + ']') },\n"
- " 'log-i64': function(x, y) { console.log('[LoggingExternalInterface logging ' + literal(x, 'i32') + ' ' + literal(y, 'i32') + ']') },\n" // legalization: two i32s
- " 'log-f32': function(x) { console.log('[LoggingExternalInterface logging ' + literal(x, 'f64') + ']') },\n" // legalization: an f64
- " 'log-f64': function(x) { console.log('[LoggingExternalInterface logging ' + literal(x, 'f64') + ']') },\n"
+ " 'log-i32': function(x) { "
+ "console.log('[LoggingExternalInterface logging ' + literal(x, 'i32') "
+ "+ ']') },\n"
+ " 'log-i64': function(x, y) { "
+ "console.log('[LoggingExternalInterface logging ' + literal(x, 'i32') "
+ "+ ' ' + literal(y, 'i32') + ']') },\n" // legalization: two i32s
+ " 'log-f32': function(x) { "
+ "console.log('[LoggingExternalInterface logging ' + literal(x, 'f64') "
+ "+ ']') },\n" // legalization: an f64
+ " 'log-f64': function(x) { "
+ "console.log('[LoggingExternalInterface logging ' + literal(x, 'f64') "
+ "+ ']') },\n"
" },\n"
" 'env': {\n"
" 'setTempRet0': function(x) { tempRet0 = x },\n"
@@ -73,12 +83,16 @@ static std::string generateJSWrapper(Module& wasm) {
"});\n";
for (auto& exp : wasm.exports) {
auto* func = wasm.getFunctionOrNull(exp->value);
- if (!func) continue; // something exported other than a function
- ret += "if (instance.exports.hangLimitInitializer) instance.exports.hangLimitInitializer();\n";
+ if (!func)
+ continue; // something exported other than a function
+ ret += "if (instance.exports.hangLimitInitializer) "
+ "instance.exports.hangLimitInitializer();\n";
ret += "try {\n";
- ret += std::string(" console.log('[fuzz-exec] calling $") + exp->name.str + "');\n";
+ ret += std::string(" console.log('[fuzz-exec] calling $") + exp->name.str +
+ "');\n";
if (func->result != none) {
- ret += std::string(" console.log('[fuzz-exec] note result: $") + exp->name.str + " => ' + literal(";
+ ret += std::string(" console.log('[fuzz-exec] note result: $") +
+ exp->name.str + " => ' + literal(";
} else {
ret += " ";
}
@@ -110,4 +124,3 @@ static std::string generateJSWrapper(Module& wasm) {
}
} // namespace wasm
-
diff --git a/src/tools/optimization-options.h b/src/tools/optimization-options.h
index cf7c612ea..6fa9aac36 100644
--- a/src/tools/optimization-options.h
+++ b/src/tools/optimization-options.h
@@ -14,6 +14,9 @@
* limitations under the License.
*/
+#ifndef wasm_tools_optimization_options_h
+#define wasm_tools_optimization_options_h
+
#include "tool-options.h"
//
@@ -27,101 +30,137 @@ struct OptimizationOptions : public ToolOptions {
std::vector<std::string> passes;
- OptimizationOptions(const std::string& command, const std::string& description) : ToolOptions(command, description) {
- (*this).add("", "-O", "execute default optimization passes",
- Options::Arguments::Zero,
- [this](Options*, const std::string&) {
- passOptions.setDefaultOptimizationOptions();
- passes.push_back(DEFAULT_OPT_PASSES);
- })
- .add("", "-O0", "execute no optimization passes",
- Options::Arguments::Zero,
- [this](Options*, const std::string&) {
- passOptions.optimizeLevel = 0;
- passOptions.shrinkLevel = 0;
- })
- .add("", "-O1", "execute -O1 optimization passes (quick&useful opts, useful for iteration builds)",
- Options::Arguments::Zero,
- [this](Options*, const std::string&) {
- passOptions.optimizeLevel = 1;
- passOptions.shrinkLevel = 0;
- passes.push_back(DEFAULT_OPT_PASSES);
- })
- .add("", "-O2", "execute -O2 optimization passes (most opts, generally gets most perf)",
- Options::Arguments::Zero,
- [this](Options*, const std::string&) {
- passOptions.optimizeLevel = 2;
- passOptions.shrinkLevel = 0;
- passes.push_back(DEFAULT_OPT_PASSES);
- })
- .add("", "-O3", "execute -O3 optimization passes (spends potentially a lot of time optimizing)",
- Options::Arguments::Zero,
- [this](Options*, const std::string&) {
- passOptions.optimizeLevel = 3;
- passOptions.shrinkLevel = 0;
- passes.push_back(DEFAULT_OPT_PASSES);
- })
- .add("", "-O4", "execute -O4 optimization passes (also flatten the IR, which can take a lot more time and memory, but is useful on more nested / complex / less-optimized input)",
- Options::Arguments::Zero,
- [this](Options*, const std::string&) {
- passOptions.optimizeLevel = 4;
- passOptions.shrinkLevel = 0;
- passes.push_back(DEFAULT_OPT_PASSES);
- })
- .add("", "-Os", "execute default optimization passes, focusing on code size",
- Options::Arguments::Zero,
- [this](Options*, const std::string&) {
- passOptions.optimizeLevel = 2;
- passOptions.shrinkLevel = 1;
- passes.push_back(DEFAULT_OPT_PASSES);
- })
- .add("", "-Oz", "execute default optimization passes, super-focusing on code size",
- Options::Arguments::Zero,
- [this](Options*, const std::string&) {
- passOptions.optimizeLevel = 2;
- passOptions.shrinkLevel = 2;
- passes.push_back(DEFAULT_OPT_PASSES);
- })
- .add("--optimize-level", "-ol", "How much to focus on optimizing code",
- Options::Arguments::One,
- [this](Options* o, const std::string& argument) {
- passOptions.optimizeLevel = atoi(argument.c_str());
- })
- .add("--shrink-level", "-s", "How much to focus on shrinking code size",
- Options::Arguments::One,
- [this](Options* o, const std::string& argument) {
- passOptions.shrinkLevel = atoi(argument.c_str());
- })
- .add("--ignore-implicit-traps", "-iit", "Optimize under the helpful assumption that no surprising traps occur (from load, div/mod, etc.)",
- Options::Arguments::Zero,
- [this](Options*, const std::string&) {
- passOptions.ignoreImplicitTraps = true;
- })
- .add("--low-memory-unused", "-lmu", "Optimize under the helpful assumption that the low 1K of memory is not used by the application",
- Options::Arguments::Zero,
- [this](Options*, const std::string&) {
- passOptions.lowMemoryUnused = true;
- })
- .add("--pass-arg", "-pa", "An argument passed along to optimization passes being run. Must be in the form KEY:VALUE",
- Options::Arguments::N,
- [this](Options*, const std::string& argument) {
- auto colon = argument.find(':');
- if (colon == std::string::npos) {
- Fatal() << "--pass-arg value must be in the form of KEY:VALUE";
- }
- auto key = argument.substr(0, colon);
- auto value = argument.substr(colon + 1);
- passOptions.arguments[key] = value;
- });
+ OptimizationOptions(const std::string& command,
+ const std::string& description)
+ : ToolOptions(command, description) {
+ (*this)
+ .add("",
+ "-O",
+ "execute default optimization passes",
+ Options::Arguments::Zero,
+ [this](Options*, const std::string&) {
+ passOptions.setDefaultOptimizationOptions();
+ passes.push_back(DEFAULT_OPT_PASSES);
+ })
+ .add("",
+ "-O0",
+ "execute no optimization passes",
+ Options::Arguments::Zero,
+ [this](Options*, const std::string&) {
+ passOptions.optimizeLevel = 0;
+ passOptions.shrinkLevel = 0;
+ })
+ .add("",
+ "-O1",
+ "execute -O1 optimization passes (quick&useful opts, useful for "
+ "iteration builds)",
+ Options::Arguments::Zero,
+ [this](Options*, const std::string&) {
+ passOptions.optimizeLevel = 1;
+ passOptions.shrinkLevel = 0;
+ passes.push_back(DEFAULT_OPT_PASSES);
+ })
+ .add(
+ "",
+ "-O2",
+ "execute -O2 optimization passes (most opts, generally gets most perf)",
+ Options::Arguments::Zero,
+ [this](Options*, const std::string&) {
+ passOptions.optimizeLevel = 2;
+ passOptions.shrinkLevel = 0;
+ passes.push_back(DEFAULT_OPT_PASSES);
+ })
+ .add("",
+ "-O3",
+ "execute -O3 optimization passes (spends potentially a lot of time "
+ "optimizing)",
+ Options::Arguments::Zero,
+ [this](Options*, const std::string&) {
+ passOptions.optimizeLevel = 3;
+ passOptions.shrinkLevel = 0;
+ passes.push_back(DEFAULT_OPT_PASSES);
+ })
+ .add("",
+ "-O4",
+ "execute -O4 optimization passes (also flatten the IR, which can "
+ "take a lot more time and memory, but is useful on more nested / "
+ "complex / less-optimized input)",
+ Options::Arguments::Zero,
+ [this](Options*, const std::string&) {
+ passOptions.optimizeLevel = 4;
+ passOptions.shrinkLevel = 0;
+ passes.push_back(DEFAULT_OPT_PASSES);
+ })
+ .add("",
+ "-Os",
+ "execute default optimization passes, focusing on code size",
+ Options::Arguments::Zero,
+ [this](Options*, const std::string&) {
+ passOptions.optimizeLevel = 2;
+ passOptions.shrinkLevel = 1;
+ passes.push_back(DEFAULT_OPT_PASSES);
+ })
+ .add("",
+ "-Oz",
+ "execute default optimization passes, super-focusing on code size",
+ Options::Arguments::Zero,
+ [this](Options*, const std::string&) {
+ passOptions.optimizeLevel = 2;
+ passOptions.shrinkLevel = 2;
+ passes.push_back(DEFAULT_OPT_PASSES);
+ })
+ .add("--optimize-level",
+ "-ol",
+ "How much to focus on optimizing code",
+ Options::Arguments::One,
+ [this](Options* o, const std::string& argument) {
+ passOptions.optimizeLevel = atoi(argument.c_str());
+ })
+ .add("--shrink-level",
+ "-s",
+ "How much to focus on shrinking code size",
+ Options::Arguments::One,
+ [this](Options* o, const std::string& argument) {
+ passOptions.shrinkLevel = atoi(argument.c_str());
+ })
+ .add("--ignore-implicit-traps",
+ "-iit",
+ "Optimize under the helpful assumption that no surprising traps "
+ "occur (from load, div/mod, etc.)",
+ Options::Arguments::Zero,
+ [this](Options*, const std::string&) {
+ passOptions.ignoreImplicitTraps = true;
+ })
+ .add("--low-memory-unused",
+ "-lmu",
+ "Optimize under the helpful assumption that the low 1K of memory is "
+ "not used by the application",
+ Options::Arguments::Zero,
+ [this](Options*, const std::string&) {
+ passOptions.lowMemoryUnused = true;
+ })
+ .add("--pass-arg",
+ "-pa",
+ "An argument passed along to optimization passes being run. Must be "
+ "in the form KEY:VALUE",
+ Options::Arguments::N,
+ [this](Options*, const std::string& argument) {
+ auto colon = argument.find(':');
+ if (colon == std::string::npos) {
+ Fatal() << "--pass-arg value must be in the form of KEY:VALUE";
+ }
+ auto key = argument.substr(0, colon);
+ auto value = argument.substr(colon + 1);
+ passOptions.arguments[key] = value;
+ });
// add passes in registry
for (const auto& p : PassRegistry::get()->getRegisteredNames()) {
(*this).add(
- std::string("--") + p, "", PassRegistry::get()->getPassDescription(p),
+ std::string("--") + p,
+ "",
+ PassRegistry::get()->getPassDescription(p),
Options::Arguments::Zero,
- [this, p](Options*, const std::string&) {
- passes.push_back(p);
- }
- );
+ [this, p](Options*, const std::string&) { passes.push_back(p); });
}
}
@@ -134,13 +173,12 @@ struct OptimizationOptions : public ToolOptions {
return false;
}
- bool runningPasses() {
- return passes.size() > 0;
- }
+ bool runningPasses() { return passes.size() > 0; }
void runPasses(Module& wasm) {
PassRunner passRunner(&wasm, passOptions);
- if (debug) passRunner.setDebug(true);
+ if (debug)
+ passRunner.setDebug(true);
for (auto& pass : passes) {
if (pass == DEFAULT_OPT_PASSES) {
passRunner.addDefaultOptimizationPasses();
@@ -153,3 +191,5 @@ struct OptimizationOptions : public ToolOptions {
};
} // namespace wasm
+
+#endif
diff --git a/src/tools/spec-wrapper.h b/src/tools/spec-wrapper.h
index 77db8a0f4..516ce17a9 100644
--- a/src/tools/spec-wrapper.h
+++ b/src/tools/spec-wrapper.h
@@ -25,18 +25,31 @@ static std::string generateSpecWrapper(Module& wasm) {
std::string ret;
for (auto& exp : wasm.exports) {
auto* func = wasm.getFunctionOrNull(exp->value);
- if (!func) continue; // something exported other than a function
- ret += std::string("(invoke \"hangLimitInitializer\") (invoke \"") + exp->name.str + "\" ";
+ if (!func)
+ continue; // something exported other than a function
+ ret += std::string("(invoke \"hangLimitInitializer\") (invoke \"") +
+ exp->name.str + "\" ";
for (Type param : func->params) {
// zeros in arguments TODO more?
switch (param) {
- case i32: ret += "(i32.const 0)"; break;
- case i64: ret += "(i64.const 0)"; break;
- case f32: ret += "(f32.const 0)"; break;
- case f64: ret += "(f64.const 0)"; break;
- case v128: ret += "(v128.const i32x4 0 0 0 0)"; break;
+ case i32:
+ ret += "(i32.const 0)";
+ break;
+ case i64:
+ ret += "(i64.const 0)";
+ break;
+ case f32:
+ ret += "(f32.const 0)";
+ break;
+ case f64:
+ ret += "(f64.const 0)";
+ break;
+ case v128:
+ ret += "(v128.const i32x4 0 0 0 0)";
+ break;
case none:
- case unreachable: WASM_UNREACHABLE();
+ case unreachable:
+ WASM_UNREACHABLE();
}
ret += " ";
}
diff --git a/src/tools/tool-options.h b/src/tools/tool-options.h
index 02572d72e..1f13063c5 100644
--- a/src/tools/tool-options.h
+++ b/src/tools/tool-options.h
@@ -14,9 +14,12 @@
* limitations under the License.
*/
+#ifndef wasm_tools_tool_options_h
+#define wasm_tools_tool_options_h
+
#include "ir/module-utils.h"
-#include "support/command-line.h"
#include "pass.h"
+#include "support/command-line.h"
//
// Shared optimization options for commandline tools
@@ -28,64 +31,74 @@ struct ToolOptions : public Options {
PassOptions passOptions;
ToolOptions(const std::string& command, const std::string& description)
- : Options(command, description) {
+ : Options(command, description) {
(*this)
- .add("--mvp-features", "-mvp", "Disable all non-MVP features",
- Arguments::Zero,
- [this](Options*, const std::string&) {
- hasFeatureOptions = true;
- enabledFeatures.makeMVP();
- disabledFeatures.setAll();
- })
- .add("--all-features", "-all", "Enable all features",
- Arguments::Zero,
- [this](Options*, const std::string&) {
- hasFeatureOptions = true;
- enabledFeatures.setAll();
- disabledFeatures.makeMVP();
- })
- .add("--detect-features", "",
- "Use features from the target features section, or MVP (default)",
- Arguments::Zero,
- [this](Options*, const std::string&) {
- hasFeatureOptions = true;
- detectFeatures = true;
- enabledFeatures.makeMVP();
- disabledFeatures.makeMVP();
- });
+ .add("--mvp-features",
+ "-mvp",
+ "Disable all non-MVP features",
+ Arguments::Zero,
+ [this](Options*, const std::string&) {
+ hasFeatureOptions = true;
+ enabledFeatures.makeMVP();
+ disabledFeatures.setAll();
+ })
+ .add("--all-features",
+ "-all",
+ "Enable all features",
+ Arguments::Zero,
+ [this](Options*, const std::string&) {
+ hasFeatureOptions = true;
+ enabledFeatures.setAll();
+ disabledFeatures.makeMVP();
+ })
+ .add("--detect-features",
+ "",
+ "Use features from the target features section, or MVP (default)",
+ Arguments::Zero,
+ [this](Options*, const std::string&) {
+ hasFeatureOptions = true;
+ detectFeatures = true;
+ enabledFeatures.makeMVP();
+ disabledFeatures.makeMVP();
+ });
(*this)
- .addFeature(FeatureSet::SignExt, "sign extension operations")
- .addFeature(FeatureSet::Atomics, "atomic operations")
- .addFeature(FeatureSet::MutableGlobals, "mutable globals")
- .addFeature(FeatureSet::TruncSat, "nontrapping float-to-int operations")
- .addFeature(FeatureSet::SIMD, "SIMD operations and types")
- .addFeature(FeatureSet::BulkMemory, "bulk memory operations")
- .add("--no-validation", "-n",
- "Disables validation, assumes inputs are correct",
- Options::Arguments::Zero,
- [this](Options* o, const std::string& argument) {
- passOptions.validate = false;
- });
+ .addFeature(FeatureSet::SignExt, "sign extension operations")
+ .addFeature(FeatureSet::Atomics, "atomic operations")
+ .addFeature(FeatureSet::MutableGlobals, "mutable globals")
+ .addFeature(FeatureSet::TruncSat, "nontrapping float-to-int operations")
+ .addFeature(FeatureSet::SIMD, "SIMD operations and types")
+ .addFeature(FeatureSet::BulkMemory, "bulk memory operations")
+ .add("--no-validation",
+ "-n",
+ "Disables validation, assumes inputs are correct",
+ Options::Arguments::Zero,
+ [this](Options* o, const std::string& argument) {
+ passOptions.validate = false;
+ });
}
ToolOptions& addFeature(FeatureSet::Feature feature,
const std::string& description) {
(*this)
- .add(std::string("--enable-") + FeatureSet::toString(feature), "",
- std::string("Enable ") + description, Arguments::Zero,
- [=](Options*, const std::string&) {
- hasFeatureOptions = true;
- enabledFeatures.set(feature, true);
- disabledFeatures.set(feature, false);
- })
+ .add(std::string("--enable-") + FeatureSet::toString(feature),
+ "",
+ std::string("Enable ") + description,
+ Arguments::Zero,
+ [=](Options*, const std::string&) {
+ hasFeatureOptions = true;
+ enabledFeatures.set(feature, true);
+ disabledFeatures.set(feature, false);
+ })
- .add(std::string("--disable-") + FeatureSet::toString(feature), "",
- std::string("Disable ") + description, Arguments::Zero,
- [=](Options*, const std::string&) {
- hasFeatureOptions = true;
- enabledFeatures.set(feature, false);
- disabledFeatures.set(feature, true);
- });
+ .add(std::string("--disable-") + FeatureSet::toString(feature),
+ "",
+ std::string("Disable ") + description,
+ Arguments::Zero,
+ [=](Options*, const std::string&) {
+ hasFeatureOptions = true;
+ enabledFeatures.set(feature, false);
+ disabledFeatures.set(feature, true);
+ });
return *this;
}
@@ -113,3 +126,5 @@ private:
};
} // namespace wasm
+
+#endif
diff --git a/src/tools/tool-utils.h b/src/tools/tool-utils.h
index a897e01f0..9e010ae3a 100644
--- a/src/tools/tool-utils.h
+++ b/src/tools/tool-utils.h
@@ -34,4 +34,3 @@ inline std::string removeSpecificSuffix(std::string str, std::string suffix) {
}
} // namespace wasm
-
diff --git a/src/tools/wasm-as.cpp b/src/tools/wasm-as.cpp
index 20e51e31f..253a93b3b 100644
--- a/src/tools/wasm-as.cpp
+++ b/src/tools/wasm-as.cpp
@@ -30,61 +30,87 @@
using namespace cashew;
using namespace wasm;
-int main(int argc, const char *argv[]) {
+int main(int argc, const char* argv[]) {
bool debugInfo = false;
std::string symbolMap;
std::string sourceMapFilename;
std::string sourceMapUrl;
- ToolOptions options("wasm-as", "Assemble a .wast (WebAssembly text format) into a .wasm (WebAssembly binary format)");
+ ToolOptions options("wasm-as",
+ "Assemble a .wast (WebAssembly text format) into a .wasm "
+ "(WebAssembly binary format)");
options.extra["validate"] = "wasm";
options
- .add("--output", "-o", "Output file (stdout if not specified)",
- Options::Arguments::One,
- [](Options *o, const std::string& argument) {
- o->extra["output"] = argument;
- Colors::disable();
- })
- .add("--validate", "-v", "Control validation of the output module",
- Options::Arguments::One,
- [](Options *o, const std::string& argument) {
- if (argument != "web" && argument != "none" && argument != "wasm") {
- std::cerr << "Valid arguments for --validate flag are 'wasm', 'web', and 'none'.\n";
- exit(1);
- }
- o->extra["validate"] = argument;
- })
- .add("--debuginfo", "-g", "Emit names section and debug info",
- Options::Arguments::Zero,
- [&](Options *o, const std::string& arguments) { debugInfo = true; })
- .add("--source-map", "-sm", "Emit source map to the specified file",
- Options::Arguments::One,
- [&sourceMapFilename](Options *o, const std::string& argument) { sourceMapFilename = argument; })
- .add("--source-map-url", "-su", "Use specified string as source map URL",
- Options::Arguments::One,
- [&sourceMapUrl](Options *o, const std::string& argument) { sourceMapUrl = argument; })
- .add("--symbolmap", "-s", "Emit a symbol map (indexes => names)",
- Options::Arguments::One,
- [&](Options *o, const std::string& argument) { symbolMap = argument; })
- .add_positional("INFILE", Options::Arguments::One,
- [](Options *o, const std::string& argument) {
- o->extra["infile"] = argument;
- });
+ .add("--output",
+ "-o",
+ "Output file (stdout if not specified)",
+ Options::Arguments::One,
+ [](Options* o, const std::string& argument) {
+ o->extra["output"] = argument;
+ Colors::disable();
+ })
+ .add("--validate",
+ "-v",
+ "Control validation of the output module",
+ Options::Arguments::One,
+ [](Options* o, const std::string& argument) {
+ if (argument != "web" && argument != "none" && argument != "wasm") {
+ std::cerr << "Valid arguments for --validate flag are 'wasm', "
+ "'web', and 'none'.\n";
+ exit(1);
+ }
+ o->extra["validate"] = argument;
+ })
+ .add("--debuginfo",
+ "-g",
+ "Emit names section and debug info",
+ Options::Arguments::Zero,
+ [&](Options* o, const std::string& arguments) { debugInfo = true; })
+ .add("--source-map",
+ "-sm",
+ "Emit source map to the specified file",
+ Options::Arguments::One,
+ [&sourceMapFilename](Options* o, const std::string& argument) {
+ sourceMapFilename = argument;
+ })
+ .add("--source-map-url",
+ "-su",
+ "Use specified string as source map URL",
+ Options::Arguments::One,
+ [&sourceMapUrl](Options* o, const std::string& argument) {
+ sourceMapUrl = argument;
+ })
+ .add("--symbolmap",
+ "-s",
+ "Emit a symbol map (indexes => names)",
+ Options::Arguments::One,
+ [&](Options* o, const std::string& argument) { symbolMap = argument; })
+ .add_positional("INFILE",
+ Options::Arguments::One,
+ [](Options* o, const std::string& argument) {
+ o->extra["infile"] = argument;
+ });
options.parse(argc, argv);
// default output is infile with changed suffix
if (options.extra.find("output") == options.extra.end()) {
- options.extra["output"] = removeSpecificSuffix(options.extra["infile"], ".wast") + ".wasm";
+ options.extra["output"] =
+ removeSpecificSuffix(options.extra["infile"], ".wast") + ".wasm";
}
- auto input(read_file<std::string>(options.extra["infile"], Flags::Text, options.debug ? Flags::Debug : Flags::Release));
+ auto input(
+ read_file<std::string>(options.extra["infile"],
+ Flags::Text,
+ options.debug ? Flags::Debug : Flags::Release));
Module wasm;
try {
- if (options.debug) std::cerr << "s-parsing..." << std::endl;
+ if (options.debug)
+ std::cerr << "s-parsing..." << std::endl;
SExpressionParser parser(const_cast<char*>(input.c_str()));
Element& root = *parser.root;
- if (options.debug) std::cerr << "w-parsing..." << std::endl;
+ if (options.debug)
+ std::cerr << "w-parsing..." << std::endl;
SExpressionWasmBuilder builder(wasm, *root[0]);
} catch (ParseException& p) {
p.dump(std::cerr);
@@ -94,15 +120,19 @@ int main(int argc, const char *argv[]) {
options.applyFeatures(wasm);
if (options.extra["validate"] != "none") {
- if (options.debug) std::cerr << "Validating..." << std::endl;
- if (!wasm::WasmValidator().validate(wasm,
- WasmValidator::Globally | (options.extra["validate"] == "web" ? WasmValidator::Web : 0))) {
+ if (options.debug)
+ std::cerr << "Validating..." << std::endl;
+ if (!wasm::WasmValidator().validate(
+ wasm,
+ WasmValidator::Globally |
+ (options.extra["validate"] == "web" ? WasmValidator::Web : 0))) {
WasmPrinter::printModule(&wasm);
Fatal() << "Error: input module is not valid.\n";
}
}
- if (options.debug) std::cerr << "writing..." << std::endl;
+ if (options.debug)
+ std::cerr << "writing..." << std::endl;
ModuleWriter writer;
writer.setBinary(true);
writer.setDebugInfo(debugInfo);
@@ -115,5 +145,6 @@ int main(int argc, const char *argv[]) {
}
writer.write(wasm, options.extra["output"]);
- if (options.debug) std::cerr << "Done." << std::endl;
+ if (options.debug)
+ std::cerr << "Done." << std::endl;
}
diff --git a/src/tools/wasm-ctor-eval.cpp b/src/tools/wasm-ctor-eval.cpp
index 420ec06ad..2050b3ebc 100644
--- a/src/tools/wasm-ctor-eval.cpp
+++ b/src/tools/wasm-ctor-eval.cpp
@@ -24,19 +24,19 @@
#include <memory>
+#include "ir/global-utils.h"
+#include "ir/import-utils.h"
+#include "ir/literal-utils.h"
+#include "ir/memory-utils.h"
+#include "ir/module-utils.h"
#include "pass.h"
-#include "support/file.h"
#include "support/colors.h"
+#include "support/file.h"
#include "tool-options.h"
-#include "wasm-io.h"
-#include "wasm-interpreter.h"
#include "wasm-builder.h"
+#include "wasm-interpreter.h"
+#include "wasm-io.h"
#include "wasm-validator.h"
-#include "ir/memory-utils.h"
-#include "ir/global-utils.h"
-#include "ir/import-utils.h"
-#include "ir/literal-utils.h"
-#include "ir/module-utils.h"
using namespace wasm;
@@ -57,13 +57,9 @@ class EvallingGlobalManager {
bool sealed = false;
public:
- void addDangerous(Name name) {
- dangerousGlobals.insert(name);
- }
+ void addDangerous(Name name) { dangerousGlobals.insert(name); }
- void seal() {
- sealed = true;
- }
+ void seal() { sealed = true; }
// for equality purposes, we just care about the globals
// and whether they have changed
@@ -78,9 +74,13 @@ public:
if (dangerousGlobals.count(name) > 0) {
std::string extra;
if (name == "___dso_handle") {
- extra = "\nrecommendation: build with -s NO_EXIT_RUNTIME=1 so that calls to atexit that use ___dso_handle are not emitted";
+ extra = "\nrecommendation: build with -s NO_EXIT_RUNTIME=1 so that "
+ "calls to atexit that use ___dso_handle are not emitted";
}
- throw FailToEvalException(std::string("tried to access a dangerous (import-initialized) global: ") + name.str + extra);
+ throw FailToEvalException(
+ std::string(
+ "tried to access a dangerous (import-initialized) global: ") +
+ name.str + extra);
}
return globals[name];
}
@@ -91,14 +91,14 @@ public:
bool found;
Iterator() : found(false) {}
- Iterator(Name name, Literal value) : first(name), second(value), found(true) {}
+ Iterator(Name name, Literal value)
+ : first(name), second(value), found(true) {}
bool operator==(const Iterator& other) {
- return first == other.first && second == other.second && found == other.found;
- }
- bool operator!=(const Iterator& other) {
- return !(*this == other);
+ return first == other.first && second == other.second &&
+ found == other.found;
}
+ bool operator!=(const Iterator& other) { return !(*this == other); }
};
Iterator find(Name name) {
@@ -108,9 +108,7 @@ public:
return Iterator(name, globals[name]);
}
- Iterator end() {
- return Iterator();
- }
+ Iterator end() { return Iterator(); }
};
// Use a ridiculously large stack size.
@@ -125,25 +123,28 @@ static Index STACK_START = 1024 * 1024 * 1024 + STACK_SIZE;
static Index STACK_LOWER_LIMIT = STACK_START - STACK_SIZE;
static Index STACK_UPPER_LIMIT = STACK_START + STACK_SIZE;
-class EvallingModuleInstance : public ModuleInstanceBase<EvallingGlobalManager, EvallingModuleInstance> {
+class EvallingModuleInstance
+ : public ModuleInstanceBase<EvallingGlobalManager, EvallingModuleInstance> {
public:
- EvallingModuleInstance(Module& wasm, ExternalInterface* externalInterface) : ModuleInstanceBase(wasm, externalInterface) {
- // if any global in the module has a non-const constructor, it is using a global import,
- // which we don't have, and is illegal to use
+ EvallingModuleInstance(Module& wasm, ExternalInterface* externalInterface)
+ : ModuleInstanceBase(wasm, externalInterface) {
+ // if any global in the module has a non-const constructor, it is using a
+ // global import, which we don't have, and is illegal to use
ModuleUtils::iterDefinedGlobals(wasm, [&](Global* global) {
if (!global->init->is<Const>()) {
// some constants are ok to use
if (auto* get = global->init->dynCast<GetGlobal>()) {
auto name = get->name;
auto* import = wasm.getGlobal(name);
- if (import->module == Name(ENV) && (
- import->base == STACKTOP || // stack constants are special, we handle them
- import->base == STACK_MAX
- )) {
+ if (import->module == Name(ENV) &&
+ (import->base ==
+ STACKTOP || // stack constants are special, we handle them
+ import->base == STACK_MAX)) {
return; // this is fine
}
}
- // this global is dangerously initialized by an import, so if it is used, we must fail
+ // this global is dangerously initialized by an import, so if it is
+ // used, we must fail
globals.addDangerous(global->name);
}
});
@@ -177,13 +178,15 @@ struct CtorEvalExternalInterface : EvallingModuleInstance::ExternalInterface {
ImportInfo imports(wasm_);
if (auto* stackTop = imports.getImportedGlobal(ENV, STACKTOP)) {
globals[stackTop->name] = Literal(int32_t(STACK_START));
- if (auto* stackTop = GlobalUtils::getGlobalInitializedToImport(wasm_, ENV, STACKTOP)) {
+ if (auto* stackTop =
+ GlobalUtils::getGlobalInitializedToImport(wasm_, ENV, STACKTOP)) {
globals[stackTop->name] = Literal(int32_t(STACK_START));
}
}
if (auto* stackMax = imports.getImportedGlobal(ENV, STACK_MAX)) {
globals[stackMax->name] = Literal(int32_t(STACK_START));
- if (auto* stackMax = GlobalUtils::getGlobalInitializedToImport(wasm_, ENV, STACK_MAX)) {
+ if (auto* stackMax =
+ GlobalUtils::getGlobalInitializedToImport(wasm_, ENV, STACK_MAX)) {
globals[stackMax->name] = Literal(int32_t(STACK_START));
}
}
@@ -203,19 +206,26 @@ struct CtorEvalExternalInterface : EvallingModuleInstance::ExternalInterface {
Literal callImport(Function* import, LiteralList& arguments) override {
std::string extra;
if (import->module == ENV && import->base == "___cxa_atexit") {
- extra = "\nrecommendation: build with -s NO_EXIT_RUNTIME=1 so that calls to atexit are not emitted";
+ extra = "\nrecommendation: build with -s NO_EXIT_RUNTIME=1 so that calls "
+ "to atexit are not emitted";
}
- throw FailToEvalException(std::string("call import: ") + import->module.str + "." + import->base.str + extra);
+ throw FailToEvalException(std::string("call import: ") +
+ import->module.str + "." + import->base.str +
+ extra);
}
- Literal callTable(Index index, LiteralList& arguments, Type result, EvallingModuleInstance& instance) override {
+ Literal callTable(Index index,
+ LiteralList& arguments,
+ Type result,
+ EvallingModuleInstance& instance) override {
// we assume the table is not modified (hmm)
// look through the segments, try to find the function
for (auto& segment : wasm->table.segments) {
Index start;
- // look for the index in this segment. if it has a constant offset, we look in
- // the proper range. if it instead gets a global, we rely on the fact that when
- // not dynamically linking then the table is loaded at offset 0.
+ // look for the index in this segment. if it has a constant offset, we
+ // look in the proper range. if it instead gets a global, we rely on the
+ // fact that when not dynamically linking then the table is loaded at
+ // offset 0.
if (auto* c = segment.offset->dynCast<Const>()) {
start = c->value.getInteger();
} else if (segment.offset->is<GetGlobal>()) {
@@ -226,16 +236,20 @@ struct CtorEvalExternalInterface : EvallingModuleInstance::ExternalInterface {
auto end = start + segment.data.size();
if (start <= index && index < end) {
auto name = segment.data[index - start];
- // if this is one of our functions, we can call it; if it was imported, fail
+ // if this is one of our functions, we can call it; if it was imported,
+ // fail
auto* func = wasm->getFunction(name);
if (!func->imported()) {
return instance.callFunctionInternal(name, arguments);
} else {
- throw FailToEvalException(std::string("callTable on imported function: ") + name.str);
+ throw FailToEvalException(
+ std::string("callTable on imported function: ") + name.str);
}
}
}
- throw FailToEvalException(std::string("callTable on index not found in static segments: ") + std::to_string(index));
+ throw FailToEvalException(
+ std::string("callTable on index not found in static segments: ") +
+ std::to_string(index));
}
int8_t load8s(Address addr) override { return doLoad<int8_t>(addr); }
@@ -247,13 +261,21 @@ struct CtorEvalExternalInterface : EvallingModuleInstance::ExternalInterface {
int64_t load64s(Address addr) override { return doLoad<int64_t>(addr); }
uint64_t load64u(Address addr) override { return doLoad<uint64_t>(addr); }
- void store8(Address addr, int8_t value) override { doStore<int8_t>(addr, value); }
- void store16(Address addr, int16_t value) override { doStore<int16_t>(addr, value); }
- void store32(Address addr, int32_t value) override { doStore<int32_t>(addr, value); }
- void store64(Address addr, int64_t value) override { doStore<int64_t>(addr, value); }
+ void store8(Address addr, int8_t value) override {
+ doStore<int8_t>(addr, value);
+ }
+ void store16(Address addr, int16_t value) override {
+ doStore<int16_t>(addr, value);
+ }
+ void store32(Address addr, int32_t value) override {
+ doStore<int32_t>(addr, value);
+ }
+ void store64(Address addr, int64_t value) override {
+ doStore<int64_t>(addr, value);
+ }
// called during initialization, but we don't keep track of a table
- void tableStore(Address addr, Name value) override { }
+ void tableStore(Address addr, Name value) override {}
void growMemory(Address /*oldSize*/, Address newSize) override {
throw FailToEvalException("grow memory");
@@ -266,8 +288,7 @@ struct CtorEvalExternalInterface : EvallingModuleInstance::ExternalInterface {
private:
// TODO: handle unaligned too, see shell-interface
- template<typename T>
- T* getMemory(Address address) {
+ template<typename T> T* getMemory(Address address) {
// if memory is on the stack, use the stack
if (address >= STACK_LOWER_LIMIT) {
if (address >= STACK_UPPER_LIMIT) {
@@ -283,14 +304,11 @@ private:
std::vector<char> temp;
Builder builder(*wasm);
wasm->memory.segments.push_back(
- Memory::Segment(
- builder.makeConst(Literal(int32_t(0))),
- temp
- )
- );
+ Memory::Segment(builder.makeConst(Literal(int32_t(0))), temp));
}
// memory should already have been flattened
- assert(wasm->memory.segments[0].offset->cast<Const>()->value.getInteger() == 0);
+ assert(wasm->memory.segments[0].offset->cast<Const>()->value.getInteger() ==
+ 0);
auto max = address + sizeof(T);
auto& data = wasm->memory.segments[0].data;
if (max > data.size()) {
@@ -299,14 +317,12 @@ private:
return (T*)(&data[address]);
}
- template<typename T>
- void doStore(Address address, T value) {
+ template<typename T> void doStore(Address address, T value) {
// do a memcpy to avoid undefined behavior if unaligned
memcpy(getMemory<T>(address), &value, sizeof(T));
}
- template<typename T>
- T doLoad(Address address) {
+ template<typename T> T doLoad(Address address) {
// do a memcpy to avoid undefined behavior if unaligned
T ret;
memcpy(&ret, getMemory<T>(address), sizeof(T));
@@ -337,7 +353,7 @@ void evalCtors(Module& wasm, std::vector<std::string> ctors) {
// snapshot globals (note that STACKTOP might be modified, but should
// be returned, so that works out)
auto globalsBefore = instance.globals;
- Export *ex = wasm.getExportOrNull(ctor);
+ Export* ex = wasm.getExportOrNull(ctor);
if (!ex) {
Fatal() << "export not found: " << ctor;
}
@@ -366,7 +382,8 @@ void evalCtors(Module& wasm, std::vector<std::string> ctors) {
}
} catch (FailToEvalException& fail) {
// that's it, we failed to even create the instance
- std::cerr << " ...stopping since could not create module instance: " << fail.why << "\n";
+ std::cerr << " ...stopping since could not create module instance: "
+ << fail.why << "\n";
return;
}
}
@@ -382,37 +399,50 @@ int main(int argc, const char* argv[]) {
bool debugInfo = false;
std::string ctorsString;
- ToolOptions options("wasm-ctor-eval", "Execute C++ global constructors ahead of time");
+ ToolOptions options("wasm-ctor-eval",
+ "Execute C++ global constructors ahead of time");
options
- .add("--output", "-o", "Output file (stdout if not specified)",
- Options::Arguments::One,
- [](Options* o, const std::string& argument) {
- o->extra["output"] = argument;
- Colors::disable();
- })
- .add("--emit-text", "-S", "Emit text instead of binary for the output file",
- Options::Arguments::Zero,
- [&](Options *o, const std::string& argument) { emitBinary = false; })
- .add("--debuginfo", "-g", "Emit names section and debug info",
- Options::Arguments::Zero,
- [&](Options *o, const std::string& arguments) { debugInfo = true; })
- .add("--ctors", "-c", "Comma-separated list of global constructor functions to evaluate",
- Options::Arguments::One,
- [&](Options* o, const std::string& argument) {
- ctorsString = argument;
- })
- .add_positional("INFILE", Options::Arguments::One,
- [](Options* o, const std::string& argument) {
- o->extra["infile"] = argument;
- });
+ .add("--output",
+ "-o",
+ "Output file (stdout if not specified)",
+ Options::Arguments::One,
+ [](Options* o, const std::string& argument) {
+ o->extra["output"] = argument;
+ Colors::disable();
+ })
+ .add("--emit-text",
+ "-S",
+ "Emit text instead of binary for the output file",
+ Options::Arguments::Zero,
+ [&](Options* o, const std::string& argument) { emitBinary = false; })
+ .add("--debuginfo",
+ "-g",
+ "Emit names section and debug info",
+ Options::Arguments::Zero,
+ [&](Options* o, const std::string& arguments) { debugInfo = true; })
+ .add(
+ "--ctors",
+ "-c",
+ "Comma-separated list of global constructor functions to evaluate",
+ Options::Arguments::One,
+ [&](Options* o, const std::string& argument) { ctorsString = argument; })
+ .add_positional("INFILE",
+ Options::Arguments::One,
+ [](Options* o, const std::string& argument) {
+ o->extra["infile"] = argument;
+ });
options.parse(argc, argv);
- auto input(read_file<std::string>(options.extra["infile"], Flags::Text, options.debug ? Flags::Debug : Flags::Release));
+ auto input(
+ read_file<std::string>(options.extra["infile"],
+ Flags::Text,
+ options.debug ? Flags::Debug : Flags::Release));
Module wasm;
{
- if (options.debug) std::cerr << "reading...\n";
+ if (options.debug)
+ std::cerr << "reading...\n";
ModuleReader reader;
reader.setDebug(options.debug);
@@ -453,7 +483,8 @@ int main(int argc, const char* argv[]) {
}
if (options.extra.count("output") > 0) {
- if (options.debug) std::cerr << "writing..." << std::endl;
+ if (options.debug)
+ std::cerr << "writing..." << std::endl;
ModuleWriter writer;
writer.setDebug(options.debug);
writer.setBinary(emitBinary);
diff --git a/src/tools/wasm-dis.cpp b/src/tools/wasm-dis.cpp
index 3ff6819a5..5b9cb9804 100644
--- a/src/tools/wasm-dis.cpp
+++ b/src/tools/wasm-dis.cpp
@@ -27,25 +27,37 @@
using namespace cashew;
using namespace wasm;
-int main(int argc, const char *argv[]) {
+int main(int argc, const char* argv[]) {
std::string sourceMapFilename;
- Options options("wasm-dis", "Un-assemble a .wasm (WebAssembly binary format) into a .wast (WebAssembly text format)");
- options.add("--output", "-o", "Output file (stdout if not specified)",
- Options::Arguments::One,
- [](Options *o, const std::string& argument) {
- o->extra["output"] = argument;
- Colors::disable();
- })
- .add("--source-map", "-sm", "Consume source map from the specified file to add location information",
- Options::Arguments::One,
- [&sourceMapFilename](Options *o, const std::string& argument) { sourceMapFilename = argument; })
- .add_positional("INFILE", Options::Arguments::One,
- [](Options *o, const std::string& argument) {
- o->extra["infile"] = argument;
- });
+ Options options("wasm-dis",
+ "Un-assemble a .wasm (WebAssembly binary format) into a "
+ ".wast (WebAssembly text format)");
+ options
+ .add("--output",
+ "-o",
+ "Output file (stdout if not specified)",
+ Options::Arguments::One,
+ [](Options* o, const std::string& argument) {
+ o->extra["output"] = argument;
+ Colors::disable();
+ })
+ .add(
+ "--source-map",
+ "-sm",
+ "Consume source map from the specified file to add location information",
+ Options::Arguments::One,
+ [&sourceMapFilename](Options* o, const std::string& argument) {
+ sourceMapFilename = argument;
+ })
+ .add_positional("INFILE",
+ Options::Arguments::One,
+ [](Options* o, const std::string& argument) {
+ o->extra["infile"] = argument;
+ });
options.parse(argc, argv);
- if (options.debug) std::cerr << "parsing binary..." << std::endl;
+ if (options.debug)
+ std::cerr << "parsing binary..." << std::endl;
Module wasm;
try {
ModuleReader().readBinary(options.extra["infile"], wasm, sourceMapFilename);
@@ -59,10 +71,14 @@ int main(int argc, const char *argv[]) {
Fatal() << "error in parsing wasm source mapping";
}
- if (options.debug) std::cerr << "Printing..." << std::endl;
- Output output(options.extra["output"], Flags::Text, options.debug ? Flags::Debug : Flags::Release);
+ if (options.debug)
+ std::cerr << "Printing..." << std::endl;
+ Output output(options.extra["output"],
+ Flags::Text,
+ options.debug ? Flags::Debug : Flags::Release);
WasmPrinter::printModule(&wasm, output.getStream());
output << '\n';
- if (options.debug) std::cerr << "Done." << std::endl;
+ if (options.debug)
+ std::cerr << "Done." << std::endl;
}
diff --git a/src/tools/wasm-emscripten-finalize.cpp b/src/tools/wasm-emscripten-finalize.cpp
index 46fb0533b..a23ba1c5a 100644
--- a/src/tools/wasm-emscripten-finalize.cpp
+++ b/src/tools/wasm-emscripten-finalize.cpp
@@ -21,6 +21,7 @@
#include <exception>
+#include "abi/js.h"
#include "ir/trapping.h"
#include "support/colors.h"
#include "support/file.h"
@@ -30,12 +31,11 @@
#include "wasm-io.h"
#include "wasm-printing.h"
#include "wasm-validator.h"
-#include "abi/js.h"
using namespace cashew;
using namespace wasm;
-int main(int argc, const char *argv[]) {
+int main(int argc, const char* argv[]) {
const uint64_t INVALID_BASE = -1;
std::string infile;
@@ -53,60 +53,86 @@ int main(int argc, const char *argv[]) {
ToolOptions options("wasm-emscripten-finalize",
"Performs Emscripten-specific transforms on .wasm files");
options
- .add("--output", "-o", "Output file",
- Options::Arguments::One,
- [&outfile](Options*, const std::string& argument) {
- outfile = argument;
- Colors::disable();
- })
- .add("--debuginfo", "-g",
- "Emit names section in wasm binary (or full debuginfo in wast)",
- Options::Arguments::Zero,
- [&debugInfo](Options *, const std::string &) {
- debugInfo = true;
- })
- .add("--emit-text", "-S", "Emit text instead of binary for the output file",
- Options::Arguments::Zero,
- [&emitBinary](Options*, const std::string& ) {
- emitBinary = false;
- })
- .add("--global-base", "", "The address at which static globals were placed",
- Options::Arguments::One,
- [&globalBase](Options*, const std::string&argument ) {
- globalBase = std::stoull(argument);
- })
- .add("--initial-stack-pointer", "", "The initial location of the stack pointer",
- Options::Arguments::One,
- [&initialStackPointer](Options*, const std::string&argument ) {
- initialStackPointer = std::stoull(argument);
- })
- .add("--side-module", "", "Input is an emscripten side module",
- Options::Arguments::Zero,
- [&isSideModule](Options *o, const std::string& argument) {
- isSideModule = true;
- })
- .add("--input-source-map", "-ism", "Consume source map from the specified file",
- Options::Arguments::One,
- [&inputSourceMapFilename](Options *o, const std::string& argument) { inputSourceMapFilename = argument; })
- .add("--no-legalize-javascript-ffi", "-nj", "Do not fully legalize (i64->i32, "
- "f32->f64) the imports and exports for interfacing with JS",
- Options::Arguments::Zero,
- [&legalizeJavaScriptFFI](Options *o, const std::string& ) {
- legalizeJavaScriptFFI = false;
- })
- .add("--output-source-map", "-osm", "Emit source map to the specified file",
- Options::Arguments::One,
- [&outputSourceMapFilename](Options *o, const std::string& argument) { outputSourceMapFilename = argument; })
- .add("--output-source-map-url", "-osu", "Emit specified string as source map URL",
- Options::Arguments::One,
- [&outputSourceMapUrl](Options *o, const std::string& argument) { outputSourceMapUrl = argument; })
- .add("--separate-data-segments", "", "Separate data segments to a file",
- Options::Arguments::One,
- [&dataSegmentFile](Options *o, const std::string& argument) { dataSegmentFile = argument;})
- .add_positional("INFILE", Options::Arguments::One,
- [&infile](Options *o, const std::string& argument) {
- infile = argument;
- });
+ .add("--output",
+ "-o",
+ "Output file",
+ Options::Arguments::One,
+ [&outfile](Options*, const std::string& argument) {
+ outfile = argument;
+ Colors::disable();
+ })
+ .add("--debuginfo",
+ "-g",
+ "Emit names section in wasm binary (or full debuginfo in wast)",
+ Options::Arguments::Zero,
+ [&debugInfo](Options*, const std::string&) { debugInfo = true; })
+ .add("--emit-text",
+ "-S",
+ "Emit text instead of binary for the output file",
+ Options::Arguments::Zero,
+ [&emitBinary](Options*, const std::string&) { emitBinary = false; })
+ .add("--global-base",
+ "",
+ "The address at which static globals were placed",
+ Options::Arguments::One,
+ [&globalBase](Options*, const std::string& argument) {
+ globalBase = std::stoull(argument);
+ })
+ .add("--initial-stack-pointer",
+ "",
+ "The initial location of the stack pointer",
+ Options::Arguments::One,
+ [&initialStackPointer](Options*, const std::string& argument) {
+ initialStackPointer = std::stoull(argument);
+ })
+ .add("--side-module",
+ "",
+ "Input is an emscripten side module",
+ Options::Arguments::Zero,
+ [&isSideModule](Options* o, const std::string& argument) {
+ isSideModule = true;
+ })
+ .add("--input-source-map",
+ "-ism",
+ "Consume source map from the specified file",
+ Options::Arguments::One,
+ [&inputSourceMapFilename](Options* o, const std::string& argument) {
+ inputSourceMapFilename = argument;
+ })
+ .add("--no-legalize-javascript-ffi",
+ "-nj",
+ "Do not fully legalize (i64->i32, "
+ "f32->f64) the imports and exports for interfacing with JS",
+ Options::Arguments::Zero,
+ [&legalizeJavaScriptFFI](Options* o, const std::string&) {
+ legalizeJavaScriptFFI = false;
+ })
+ .add("--output-source-map",
+ "-osm",
+ "Emit source map to the specified file",
+ Options::Arguments::One,
+ [&outputSourceMapFilename](Options* o, const std::string& argument) {
+ outputSourceMapFilename = argument;
+ })
+ .add("--output-source-map-url",
+ "-osu",
+ "Emit specified string as source map URL",
+ Options::Arguments::One,
+ [&outputSourceMapUrl](Options* o, const std::string& argument) {
+ outputSourceMapUrl = argument;
+ })
+ .add("--separate-data-segments",
+ "",
+ "Separate data segments to a file",
+ Options::Arguments::One,
+ [&dataSegmentFile](Options* o, const std::string& argument) {
+ dataSegmentFile = argument;
+ })
+ .add_positional("INFILE",
+ Options::Arguments::One,
+ [&infile](Options* o, const std::string& argument) {
+ infile = argument;
+ });
options.parse(argc, argv);
if (infile == "") {
@@ -167,10 +193,12 @@ int main(int argc, const char *argv[]) {
std::vector<Name> initializerFunctions;
if (wasm.table.imported()) {
- if (wasm.table.base != "table") wasm.table.base = Name("table");
+ if (wasm.table.base != "table")
+ wasm.table.base = Name("table");
}
if (wasm.memory.imported()) {
- if (wasm.table.base != "memory") wasm.memory.base = Name("memory");
+ if (wasm.table.base != "memory")
+ wasm.memory.base = Name("memory");
}
wasm.updateMaps();
@@ -204,13 +232,13 @@ int main(int argc, const char *argv[]) {
passRunner.setDebugInfo(debugInfo);
passRunner.add(ABI::getLegalizationPass(
legalizeJavaScriptFFI ? ABI::LegalizationLevel::Full
- : ABI::LegalizationLevel::Minimal
- ));
+ : ABI::LegalizationLevel::Minimal));
passRunner.run();
}
// Substantial changes to the wasm are done, enough to create the metadata.
- std::string metadata = generator.generateEmscriptenMetadata(dataSize, initializerFunctions);
+ std::string metadata =
+ generator.generateEmscriptenMetadata(dataSize, initializerFunctions);
// Finally, separate out data segments if relevant (they may have been needed
// for metadata).
diff --git a/src/tools/wasm-metadce.cpp b/src/tools/wasm-metadce.cpp
index adb623ea0..a6f5bb012 100644
--- a/src/tools/wasm-metadce.cpp
+++ b/src/tools/wasm-metadce.cpp
@@ -26,14 +26,14 @@
#include <memory>
+#include "ir/module-utils.h"
#include "pass.h"
+#include "support/colors.h"
#include "support/command-line.h"
#include "support/file.h"
#include "support/json.h"
-#include "support/colors.h"
-#include "wasm-io.h"
#include "wasm-builder.h"
-#include "ir/module-utils.h"
+#include "wasm-io.h"
using namespace wasm;
@@ -51,9 +51,10 @@ struct MetaDCEGraph {
std::unordered_map<Name, DCENode> nodes;
std::unordered_set<Name> roots;
- std::unordered_map<Name, Name> exportToDCENode; // export exported name => DCE name
+ // export exported name => DCE name
+ std::unordered_map<Name, Name> exportToDCENode;
std::unordered_map<Name, Name> functionToDCENode; // function name => DCE name
- std::unordered_map<Name, Name> globalToDCENode; // global name => DCE name
+ std::unordered_map<Name, Name> globalToDCENode; // global name => DCE name
std::unordered_map<Name, Name> DCENodeToExport; // reverse maps
std::unordered_map<Name, Name> DCENodeToFunction;
@@ -79,18 +80,20 @@ struct MetaDCEGraph {
return getImportId(imp->module, imp->base);
}
- std::unordered_map<Name, Name> importIdToDCENode; // import module.base => DCE name
+ // import module.base => DCE name
+ std::unordered_map<Name, Name> importIdToDCENode;
Module& wasm;
MetaDCEGraph(Module& wasm) : wasm(wasm) {}
- // populate the graph with info from the wasm, integrating with potentially-existing
- // nodes for imports and exports that the graph may already contain.
+ // populate the graph with info from the wasm, integrating with
+ // potentially-existing nodes for imports and exports that the graph may
+ // already contain.
void scanWebAssembly() {
// Add an entry for everything we might need ahead of time, so parallel work
- // does not alter parent state, just adds to things pointed by it, independently
- // (each thread will add for one function, etc.)
+ // does not alter parent state, just adds to things pointed by it,
+ // independently (each thread will add for one function, etc.)
ModuleUtils::iterDefinedFunctions(wasm, [&](Function* func) {
auto dceName = getName("func", func->name.str);
DCENodeToFunction[dceName] = func->name;
@@ -103,7 +106,8 @@ struct MetaDCEGraph {
globalToDCENode[global->name] = dceName;
nodes[dceName] = DCENode(dceName);
});
- // only process function and global imports - the table and memory are always there
+ // only process function and global imports - the table and memory are
+ // always there
ModuleUtils::iterImportedFunctions(wasm, [&](Function* import) {
auto id = getImportId(import->module, import->base);
if (importIdToDCENode.find(id) == importIdToDCENode.end()) {
@@ -131,13 +135,15 @@ struct MetaDCEGraph {
if (!wasm.getFunction(exp->value)->imported()) {
node.reaches.push_back(functionToDCENode[exp->value]);
} else {
- node.reaches.push_back(importIdToDCENode[getFunctionImportId(exp->value)]);
+ node.reaches.push_back(
+ importIdToDCENode[getFunctionImportId(exp->value)]);
}
} else if (exp->kind == ExternalKind::Global) {
if (!wasm.getGlobal(exp->value)->imported()) {
node.reaches.push_back(globalToDCENode[exp->value]);
} else {
- node.reaches.push_back(importIdToDCENode[getGlobalImportId(exp->value)]);
+ node.reaches.push_back(
+ importIdToDCENode[getGlobalImportId(exp->value)]);
}
}
}
@@ -145,14 +151,11 @@ struct MetaDCEGraph {
// if we provide a parent DCE name, that is who can reach what we see
// if none is provided, then it is something we must root
struct InitScanner : public PostWalker<InitScanner> {
- InitScanner(MetaDCEGraph* parent, Name parentDceName) : parent(parent), parentDceName(parentDceName) {}
+ InitScanner(MetaDCEGraph* parent, Name parentDceName)
+ : parent(parent), parentDceName(parentDceName) {}
- void visitGetGlobal(GetGlobal* curr) {
- handleGlobal(curr->name);
- }
- void visitSetGlobal(SetGlobal* curr) {
- handleGlobal(curr->name);
- }
+ void visitGetGlobal(GetGlobal* curr) { handleGlobal(curr->name); }
+ void visitSetGlobal(SetGlobal* curr) { handleGlobal(curr->name); }
private:
MetaDCEGraph* parent;
@@ -206,34 +209,29 @@ struct MetaDCEGraph {
Scanner(MetaDCEGraph* parent) : parent(parent) {}
- Scanner* create() override {
- return new Scanner(parent);
- }
+ Scanner* create() override { return new Scanner(parent); }
void visitCall(Call* curr) {
if (!getModule()->getFunction(curr->target)->imported()) {
- parent->nodes[parent->functionToDCENode[getFunction()->name]].reaches.push_back(
- parent->functionToDCENode[curr->target]
- );
+ parent->nodes[parent->functionToDCENode[getFunction()->name]]
+ .reaches.push_back(parent->functionToDCENode[curr->target]);
} else {
assert(parent->functionToDCENode.count(getFunction()->name) > 0);
- parent->nodes[parent->functionToDCENode[getFunction()->name]].reaches.push_back(
- parent->importIdToDCENode[parent->getFunctionImportId(curr->target)]
- );
+ parent->nodes[parent->functionToDCENode[getFunction()->name]]
+ .reaches.push_back(
+ parent
+ ->importIdToDCENode[parent->getFunctionImportId(curr->target)]);
}
}
- void visitGetGlobal(GetGlobal* curr) {
- handleGlobal(curr->name);
- }
- void visitSetGlobal(SetGlobal* curr) {
- handleGlobal(curr->name);
- }
+ void visitGetGlobal(GetGlobal* curr) { handleGlobal(curr->name); }
+ void visitSetGlobal(SetGlobal* curr) { handleGlobal(curr->name); }
private:
MetaDCEGraph* parent;
void handleGlobal(Name name) {
- if (!getFunction()) return; // non-function stuff (initializers) are handled separately
+ if (!getFunction())
+ return; // non-function stuff (initializers) are handled separately
Name dceName;
if (!getModule()->getGlobal(name)->imported()) {
// its a global
@@ -242,7 +240,8 @@ struct MetaDCEGraph {
// it's an import.
dceName = parent->importIdToDCENode[parent->getGlobalImportId(name)];
}
- parent->nodes[parent->functionToDCENode[getFunction()->name]].reaches.push_back(dceName);
+ parent->nodes[parent->functionToDCENode[getFunction()->name]]
+ .reaches.push_back(dceName);
}
};
@@ -256,7 +255,8 @@ private:
// gets a unique name for the graph
Name getName(std::string prefix1, std::string prefix2) {
while (1) {
- auto curr = Name(prefix1 + '$' + prefix2 + '$' + std::to_string(nameIndex++));
+ auto curr =
+ Name(prefix1 + '$' + prefix2 + '$' + std::to_string(nameIndex++));
if (nodes.find(curr) == nodes.end()) {
return curr;
}
@@ -305,7 +305,8 @@ public:
// Now they are gone, standard optimization passes can do the rest!
PassRunner passRunner(&wasm);
passRunner.add("remove-unused-module-elements");
- passRunner.add("reorder-functions"); // removing functions may alter the optimum order, as # of calls can change
+ // removing functions may alter the optimum order, as # of calls can change
+ passRunner.add("reorder-functions");
passRunner.run();
}
@@ -344,7 +345,8 @@ public:
std::cout << " is import " << importMap[name] << '\n';
}
if (DCENodeToExport.find(name) != DCENodeToExport.end()) {
- std::cout << " is export " << DCENodeToExport[name].str << ", " << wasm.getExport(DCENodeToExport[name])->value << '\n';
+ std::cout << " is export " << DCENodeToExport[name].str << ", "
+ << wasm.getExport(DCENodeToExport[name])->value << '\n';
}
if (DCENodeToFunction.find(name) != DCENodeToFunction.end()) {
std::cout << " is function " << DCENodeToFunction[name] << '\n';
@@ -372,86 +374,99 @@ int main(int argc, const char* argv[]) {
std::string graphFile;
bool dump = false;
- Options options("wasm-metadce", "This tool performs dead code elimination (DCE) on a larger space "
- "that the wasm module is just a part of. For example, if you have "
- "JS and wasm that are connected, this can DCE the combined graph. "
- "By doing so, it is able to eliminate wasm module exports, which "
- "otherwise regular optimizations cannot.\n\n"
- "This tool receives a representation of the reachability graph "
- "that the wasm module resides in, which contains abstract nodes "
- "and connections showing what they reach. Some of those nodes "
- "can represent the wasm module's imports and exports. The tool "
- "then completes the graph by adding the internal parts of the "
- "module, and does DCE on the entire thing.\n\n"
- "This tool will output a wasm module with dead code eliminated, "
- "and metadata describing the things in the rest of the graph "
- "that can be eliminated as well.\n\n"
- "The graph description file should represent the graph in the following "
- "JSON-like notation (note, this is not true JSON, things like "
- "comments, escaping, single-quotes, etc. are not supported):\n\n"
- " [\n"
- " {\n"
- " \"name\": \"entity1\",\n"
- " \"reaches\": [\"entity2, \"entity3\"],\n"
- " \"root\": true\n"
- " },\n"
- " {\n"
- " \"name\": \"entity2\",\n"
- " \"reaches\": [\"entity1, \"entity4\"]\n"
- " },\n"
- " {\n"
- " \"name\": \"entity3\",\n"
- " \"reaches\": [\"entity1\"],\n"
- " \"export\": \"export1\"\n"
- " },\n"
- " {\n"
- " \"name\": \"entity4\",\n"
- " \"import\": [\"module\", \"import1\"]\n"
- " },\n"
- " ]\n\n"
- "Each entity has a name and an optional list of the other "
- "entities it reaches. It can also be marked as a root, "
- "export (with the export string), or import (with the "
- "module and import strings). DCE then computes what is "
- "reachable from the roots.");
+ Options options(
+ "wasm-metadce",
+ "This tool performs dead code elimination (DCE) on a larger space "
+ "that the wasm module is just a part of. For example, if you have "
+ "JS and wasm that are connected, this can DCE the combined graph. "
+ "By doing so, it is able to eliminate wasm module exports, which "
+ "otherwise regular optimizations cannot.\n\n"
+ "This tool receives a representation of the reachability graph "
+ "that the wasm module resides in, which contains abstract nodes "
+ "and connections showing what they reach. Some of those nodes "
+ "can represent the wasm module's imports and exports. The tool "
+ "then completes the graph by adding the internal parts of the "
+ "module, and does DCE on the entire thing.\n\n"
+ "This tool will output a wasm module with dead code eliminated, "
+ "and metadata describing the things in the rest of the graph "
+ "that can be eliminated as well.\n\n"
+ "The graph description file should represent the graph in the following "
+ "JSON-like notation (note, this is not true JSON, things like "
+ "comments, escaping, single-quotes, etc. are not supported):\n\n"
+ " [\n"
+ " {\n"
+ " \"name\": \"entity1\",\n"
+ " \"reaches\": [\"entity2, \"entity3\"],\n"
+ " \"root\": true\n"
+ " },\n"
+ " {\n"
+ " \"name\": \"entity2\",\n"
+ " \"reaches\": [\"entity1, \"entity4\"]\n"
+ " },\n"
+ " {\n"
+ " \"name\": \"entity3\",\n"
+ " \"reaches\": [\"entity1\"],\n"
+ " \"export\": \"export1\"\n"
+ " },\n"
+ " {\n"
+ " \"name\": \"entity4\",\n"
+ " \"import\": [\"module\", \"import1\"]\n"
+ " },\n"
+ " ]\n\n"
+ "Each entity has a name and an optional list of the other "
+ "entities it reaches. It can also be marked as a root, "
+ "export (with the export string), or import (with the "
+ "module and import strings). DCE then computes what is "
+ "reachable from the roots.");
options
- .add("--output", "-o", "Output file (stdout if not specified)",
- Options::Arguments::One,
- [](Options* o, const std::string& argument) {
- o->extra["output"] = argument;
- Colors::disable();
- })
- .add("--emit-text", "-S", "Emit text instead of binary for the output file",
- Options::Arguments::Zero,
- [&](Options *o, const std::string& argument) { emitBinary = false; })
- .add("--debuginfo", "-g", "Emit names section and debug info",
- Options::Arguments::Zero,
- [&](Options *o, const std::string& arguments) { debugInfo = true; })
- .add("--graph-file", "-f", "Filename of the graph description file",
- Options::Arguments::One,
- [&](Options* o, const std::string& argument) {
- graphFile = argument;
- })
- .add("--dump", "-d", "Dump the combined graph file (useful for debugging)",
- Options::Arguments::Zero,
- [&](Options *o, const std::string& arguments) { dump = true; })
- .add_positional("INFILE", Options::Arguments::One,
- [](Options* o, const std::string& argument) {
- o->extra["infile"] = argument;
- });
+ .add("--output",
+ "-o",
+ "Output file (stdout if not specified)",
+ Options::Arguments::One,
+ [](Options* o, const std::string& argument) {
+ o->extra["output"] = argument;
+ Colors::disable();
+ })
+ .add("--emit-text",
+ "-S",
+ "Emit text instead of binary for the output file",
+ Options::Arguments::Zero,
+ [&](Options* o, const std::string& argument) { emitBinary = false; })
+ .add("--debuginfo",
+ "-g",
+ "Emit names section and debug info",
+ Options::Arguments::Zero,
+ [&](Options* o, const std::string& arguments) { debugInfo = true; })
+ .add("--graph-file",
+ "-f",
+ "Filename of the graph description file",
+ Options::Arguments::One,
+ [&](Options* o, const std::string& argument) { graphFile = argument; })
+ .add("--dump",
+ "-d",
+ "Dump the combined graph file (useful for debugging)",
+ Options::Arguments::Zero,
+ [&](Options* o, const std::string& arguments) { dump = true; })
+ .add_positional("INFILE",
+ Options::Arguments::One,
+ [](Options* o, const std::string& argument) {
+ o->extra["infile"] = argument;
+ });
options.parse(argc, argv);
if (graphFile.size() == 0) {
Fatal() << "no graph file provided.";
}
- auto input(read_file<std::string>(options.extra["infile"], Flags::Text, Flags::Release));
+ auto input(read_file<std::string>(
+ options.extra["infile"], Flags::Text, Flags::Release));
Module wasm;
{
- if (options.debug) std::cerr << "reading...\n";
+ if (options.debug)
+ std::cerr << "reading...\n";
ModuleReader reader;
reader.setDebug(options.debug);
@@ -463,32 +478,36 @@ int main(int argc, const char* argv[]) {
}
}
- auto graphInput(read_file<std::string>(graphFile, Flags::Text, Flags::Release));
+ auto graphInput(
+ read_file<std::string>(graphFile, Flags::Text, Flags::Release));
auto* copy = strdup(graphInput.c_str());
json::Value outside;
outside.parse(copy);
// parse the JSON into our graph, doing all the JSON parsing here, leaving
// the abstract computation for the class itself
- const json::IString NAME("name"),
- REACHES("reaches"),
- ROOT("root"),
- EXPORT("export"),
- IMPORT("import");
+ const json::IString NAME("name");
+ const json::IString REACHES("reaches");
+ const json::IString ROOT("root");
+ const json::IString EXPORT("export");
+ const json::IString IMPORT("import");
MetaDCEGraph graph(wasm);
if (!outside.isArray()) {
- Fatal() << "input graph must be a JSON array of nodes. see --help for the form";
+ Fatal()
+ << "input graph must be a JSON array of nodes. see --help for the form";
}
auto size = outside.size();
for (size_t i = 0; i < size; i++) {
json::Ref ref = outside[i];
if (!ref->isObject()) {
- Fatal() << "nodes in input graph must be JSON objects. see --help for the form";
+ Fatal()
+ << "nodes in input graph must be JSON objects. see --help for the form";
}
if (!ref->has(NAME)) {
- Fatal() << "nodes in input graph must have a name. see --help for the form";
+ Fatal()
+ << "nodes in input graph must have a name. see --help for the form";
}
DCENode node(ref[NAME]->getIString());
if (ref->has(REACHES)) {
@@ -500,7 +519,8 @@ int main(int argc, const char* argv[]) {
for (size_t j = 0; j < size; j++) {
json::Ref name = reaches[j];
if (!name->isString()) {
- Fatal() << "node.reaches items must be strings. see --help for the form";
+ Fatal()
+ << "node.reaches items must be strings. see --help for the form";
}
node.reaches.push_back(name->getIString());
}
@@ -508,22 +528,26 @@ int main(int argc, const char* argv[]) {
if (ref->has(ROOT)) {
json::Ref root = ref[ROOT];
if (!root->isBool() || !root->getBool()) {
- Fatal() << "node.root, if it exists, must be true. see --help for the form";
+ Fatal()
+ << "node.root, if it exists, must be true. see --help for the form";
}
graph.roots.insert(node.name);
}
if (ref->has(EXPORT)) {
json::Ref exp = ref[EXPORT];
if (!exp->isString()) {
- Fatal() << "node.export, if it exists, must be a string. see --help for the form";
+ Fatal() << "node.export, if it exists, must be a string. see --help "
+ "for the form";
}
graph.exportToDCENode[exp->getIString()] = node.name;
graph.DCENodeToExport[node.name] = exp->getIString();
}
if (ref->has(IMPORT)) {
json::Ref imp = ref[IMPORT];
- if (!imp->isArray() || imp->size() != 2 || !imp[0]->isString() || !imp[1]->isString()) {
- Fatal() << "node.import, if it exists, must be an array of two strings. see --help for the form";
+ if (!imp->isArray() || imp->size() != 2 || !imp[0]->isString() ||
+ !imp[1]->isString()) {
+ Fatal() << "node.import, if it exists, must be an array of two "
+ "strings. see --help for the form";
}
auto id = graph.getImportId(imp[0]->getIString(), imp[1]->getIString());
graph.importIdToDCENode[id] = node.name;
diff --git a/src/tools/wasm-opt.cpp b/src/tools/wasm-opt.cpp
index 519713298..e9f369d22 100644
--- a/src/tools/wasm-opt.cpp
+++ b/src/tools/wasm-opt.cpp
@@ -21,21 +21,21 @@
#include <memory>
+#include "execution-results.h"
+#include "fuzzing.h"
+#include "js-wrapper.h"
+#include "optimization-options.h"
#include "pass.h"
+#include "shell-interface.h"
+#include "spec-wrapper.h"
#include "support/command-line.h"
#include "support/file.h"
+#include "wasm-binary.h"
+#include "wasm-interpreter.h"
+#include "wasm-io.h"
#include "wasm-printing.h"
#include "wasm-s-parser.h"
#include "wasm-validator.h"
-#include "wasm-io.h"
-#include "wasm-interpreter.h"
-#include "wasm-binary.h"
-#include "shell-interface.h"
-#include "optimization-options.h"
-#include "execution-results.h"
-#include "fuzzing.h"
-#include "js-wrapper.h"
-#include "spec-wrapper.h"
using namespace wasm;
@@ -45,7 +45,7 @@ std::string runCommand(std::string command) {
std::string output;
const int MAX_BUFFER = 1024;
char buffer[MAX_BUFFER];
- FILE *stream = popen(command.c_str(), "r");
+ FILE* stream = popen(command.c_str(), "r");
while (fgets(buffer, MAX_BUFFER, stream) != NULL) {
output.append(buffer);
}
@@ -81,69 +81,130 @@ int main(int argc, const char* argv[]) {
OptimizationOptions options("wasm-opt", "Read, write, and optimize files");
options
- .add("--output", "-o", "Output file (stdout if not specified)",
- Options::Arguments::One,
- [](Options* o, const std::string& argument) {
- o->extra["output"] = argument;
- Colors::disable();
- })
- .add("--emit-text", "-S", "Emit text instead of binary for the output file",
- Options::Arguments::Zero,
- [&](Options *o, const std::string& argument) { emitBinary = false; })
- .add("--debuginfo", "-g", "Emit names section and debug info",
- Options::Arguments::Zero,
- [&](Options *o, const std::string& arguments) { debugInfo = true; })
- .add("--converge", "-c", "Run passes to convergence, continuing while binary size decreases",
- Options::Arguments::Zero,
- [&](Options *o, const std::string& arguments) { converge = true; })
- .add("--fuzz-exec-before", "-feh", "Execute functions before optimization, helping fuzzing find bugs",
- Options::Arguments::Zero,
- [&](Options *o, const std::string& arguments) { fuzzExecBefore = true; })
- .add("--fuzz-exec", "-fe", "Execute functions before and after optimization, helping fuzzing find bugs",
- Options::Arguments::Zero,
- [&](Options *o, const std::string& arguments) { fuzzExecBefore = fuzzExecAfter = true; })
- .add("--fuzz-binary", "-fb", "Convert to binary and back after optimizations and before fuzz-exec, helping fuzzing find binary format bugs",
- Options::Arguments::Zero,
- [&](Options *o, const std::string& arguments) { fuzzBinary = true; })
- .add("--extra-fuzz-command", "-efc", "An extra command to run on the output before and after optimizing. The output is compared between the two, and an error occurs if they are not equal",
- Options::Arguments::One,
- [&](Options *o, const std::string& arguments) { extraFuzzCommand = arguments; })
- .add("--translate-to-fuzz", "-ttf", "Translate the input into a valid wasm module *somehow*, useful for fuzzing",
- Options::Arguments::Zero,
- [&](Options *o, const std::string& arguments) { translateToFuzz = true; })
- .add("--fuzz-passes", "-fp", "Pick a random set of passes to run, useful for fuzzing. this depends on translate-to-fuzz (it picks the passes from the input)",
- Options::Arguments::Zero,
- [&](Options *o, const std::string& arguments) { fuzzPasses = true; })
- .add("--no-fuzz-nans", "", "don't emit NaNs when fuzzing, and remove them at runtime as well (helps avoid nondeterminism between VMs)",
- Options::Arguments::Zero,
- [&](Options *o, const std::string& arguments) { fuzzNaNs = false; })
- .add("--no-fuzz-memory", "", "don't emit memory ops when fuzzing",
- Options::Arguments::Zero,
- [&](Options *o, const std::string& arguments) { fuzzMemory = false; })
- .add("--emit-js-wrapper", "-ejw", "Emit a JavaScript wrapper file that can run the wasm with some test values, useful for fuzzing",
- Options::Arguments::One,
- [&](Options *o, const std::string& arguments) { emitJSWrapper = arguments; })
- .add("--emit-spec-wrapper", "-esw", "Emit a wasm spec interpreter wrapper file that can run the wasm with some test values, useful for fuzzing",
- Options::Arguments::One,
- [&](Options *o, const std::string& arguments) { emitSpecWrapper = arguments; })
- .add("--input-source-map", "-ism", "Consume source map from the specified file",
- Options::Arguments::One,
- [&inputSourceMapFilename](Options *o, const std::string& argument) { inputSourceMapFilename = argument; })
- .add("--output-source-map", "-osm", "Emit source map to the specified file",
- Options::Arguments::One,
- [&outputSourceMapFilename](Options *o, const std::string& argument) { outputSourceMapFilename = argument; })
- .add("--output-source-map-url", "-osu", "Emit specified string as source map URL",
- Options::Arguments::One,
- [&outputSourceMapUrl](Options *o, const std::string& argument) { outputSourceMapUrl = argument; })
- .add_positional("INFILE", Options::Arguments::One,
- [](Options* o, const std::string& argument) {
- o->extra["infile"] = argument;
- });
+ .add("--output",
+ "-o",
+ "Output file (stdout if not specified)",
+ Options::Arguments::One,
+ [](Options* o, const std::string& argument) {
+ o->extra["output"] = argument;
+ Colors::disable();
+ })
+ .add("--emit-text",
+ "-S",
+ "Emit text instead of binary for the output file",
+ Options::Arguments::Zero,
+ [&](Options* o, const std::string& argument) { emitBinary = false; })
+ .add("--debuginfo",
+ "-g",
+ "Emit names section and debug info",
+ Options::Arguments::Zero,
+ [&](Options* o, const std::string& arguments) { debugInfo = true; })
+ .add("--converge",
+ "-c",
+ "Run passes to convergence, continuing while binary size decreases",
+ Options::Arguments::Zero,
+ [&](Options* o, const std::string& arguments) { converge = true; })
+ .add(
+ "--fuzz-exec-before",
+ "-feh",
+ "Execute functions before optimization, helping fuzzing find bugs",
+ Options::Arguments::Zero,
+ [&](Options* o, const std::string& arguments) { fuzzExecBefore = true; })
+ .add("--fuzz-exec",
+ "-fe",
+ "Execute functions before and after optimization, helping fuzzing "
+ "find bugs",
+ Options::Arguments::Zero,
+ [&](Options* o, const std::string& arguments) {
+ fuzzExecBefore = fuzzExecAfter = true;
+ })
+ .add("--fuzz-binary",
+ "-fb",
+ "Convert to binary and back after optimizations and before fuzz-exec, "
+ "helping fuzzing find binary format bugs",
+ Options::Arguments::Zero,
+ [&](Options* o, const std::string& arguments) { fuzzBinary = true; })
+ .add("--extra-fuzz-command",
+ "-efc",
+ "An extra command to run on the output before and after optimizing. "
+ "The output is compared between the two, and an error occurs if they "
+ "are not equal",
+ Options::Arguments::One,
+ [&](Options* o, const std::string& arguments) {
+ extraFuzzCommand = arguments;
+ })
+ .add(
+ "--translate-to-fuzz",
+ "-ttf",
+ "Translate the input into a valid wasm module *somehow*, useful for "
+ "fuzzing",
+ Options::Arguments::Zero,
+ [&](Options* o, const std::string& arguments) { translateToFuzz = true; })
+ .add("--fuzz-passes",
+ "-fp",
+ "Pick a random set of passes to run, useful for fuzzing. this depends "
+ "on translate-to-fuzz (it picks the passes from the input)",
+ Options::Arguments::Zero,
+ [&](Options* o, const std::string& arguments) { fuzzPasses = true; })
+ .add("--no-fuzz-nans",
+ "",
+ "don't emit NaNs when fuzzing, and remove them at runtime as well "
+ "(helps avoid nondeterminism between VMs)",
+ Options::Arguments::Zero,
+ [&](Options* o, const std::string& arguments) { fuzzNaNs = false; })
+ .add("--no-fuzz-memory",
+ "",
+ "don't emit memory ops when fuzzing",
+ Options::Arguments::Zero,
+ [&](Options* o, const std::string& arguments) { fuzzMemory = false; })
+ .add("--emit-js-wrapper",
+ "-ejw",
+ "Emit a JavaScript wrapper file that can run the wasm with some test "
+ "values, useful for fuzzing",
+ Options::Arguments::One,
+ [&](Options* o, const std::string& arguments) {
+ emitJSWrapper = arguments;
+ })
+ .add("--emit-spec-wrapper",
+ "-esw",
+ "Emit a wasm spec interpreter wrapper file that can run the wasm with "
+ "some test values, useful for fuzzing",
+ Options::Arguments::One,
+ [&](Options* o, const std::string& arguments) {
+ emitSpecWrapper = arguments;
+ })
+ .add("--input-source-map",
+ "-ism",
+ "Consume source map from the specified file",
+ Options::Arguments::One,
+ [&inputSourceMapFilename](Options* o, const std::string& argument) {
+ inputSourceMapFilename = argument;
+ })
+ .add("--output-source-map",
+ "-osm",
+ "Emit source map to the specified file",
+ Options::Arguments::One,
+ [&outputSourceMapFilename](Options* o, const std::string& argument) {
+ outputSourceMapFilename = argument;
+ })
+ .add("--output-source-map-url",
+ "-osu",
+ "Emit specified string as source map URL",
+ Options::Arguments::One,
+ [&outputSourceMapUrl](Options* o, const std::string& argument) {
+ outputSourceMapUrl = argument;
+ })
+ .add_positional("INFILE",
+ Options::Arguments::One,
+ [](Options* o, const std::string& argument) {
+ o->extra["infile"] = argument;
+ });
options.parse(argc, argv);
Module wasm;
- if (options.debug) std::cerr << "reading...\n";
+ if (options.debug)
+ std::cerr << "reading...\n";
if (!translateToFuzz) {
ModuleReader reader;
@@ -159,7 +220,8 @@ int main(int argc, const char* argv[]) {
std::cerr << '\n';
Fatal() << "error in parsing wasm source map";
} catch (std::bad_alloc&) {
- Fatal() << "error in building module, std::bad_alloc (possibly invalid request for silly amounts of memory)";
+ Fatal() << "error in building module, std::bad_alloc (possibly invalid "
+ "request for silly amounts of memory)";
}
options.applyFeatures(wasm);
@@ -218,7 +280,9 @@ int main(int argc, const char* argv[]) {
std::string firstOutput;
if (extraFuzzCommand.size() > 0 && options.extra.count("output") > 0) {
- if (options.debug) std::cerr << "writing binary before opts, for extra fuzz command..." << std::endl;
+ if (options.debug)
+ std::cerr << "writing binary before opts, for extra fuzz command..."
+ << std::endl;
ModuleWriter writer;
writer.setDebug(options.debug);
writer.setBinary(emitBinary);
@@ -252,12 +316,12 @@ int main(int argc, const char* argv[]) {
}
if (options.runningPasses()) {
- if (options.debug) std::cerr << "running passes...\n";
+ if (options.debug)
+ std::cerr << "running passes...\n";
auto runPasses = [&]() {
options.runPasses(*curr);
if (options.passOptions.validate) {
- bool valid =
- WasmValidator().validate(*curr);
+ bool valid = WasmValidator().validate(*curr);
if (!valid) {
WasmPrinter::printModule(&*curr);
}
@@ -276,10 +340,13 @@ int main(int argc, const char* argv[]) {
};
auto lastSize = getSize();
while (1) {
- if (options.debug) std::cerr << "running iteration for convergence (" << lastSize << ")...\n";
+ if (options.debug)
+ std::cerr << "running iteration for convergence (" << lastSize
+ << ")...\n";
runPasses();
auto currSize = getSize();
- if (currSize >= lastSize) break;
+ if (currSize >= lastSize)
+ break;
lastSize = currSize;
}
}
@@ -292,7 +359,8 @@ int main(int argc, const char* argv[]) {
if (options.extra.count("output") == 0) {
std::cerr << "(no output file specified, not emitting output)\n";
} else {
- if (options.debug) std::cerr << "writing..." << std::endl;
+ if (options.debug)
+ std::cerr << "writing..." << std::endl;
ModuleWriter writer;
writer.setDebug(options.debug);
writer.setBinary(emitBinary);
@@ -305,7 +373,8 @@ int main(int argc, const char* argv[]) {
if (extraFuzzCommand.size() > 0) {
auto secondOutput = runCommand(extraFuzzCommand);
- std::cout << "[extra-fuzz-command second output:]\n" << firstOutput << '\n';
+ std::cout << "[extra-fuzz-command second output:]\n"
+ << firstOutput << '\n';
if (firstOutput != secondOutput) {
std::cerr << "extra fuzz command output differs\n";
abort();
diff --git a/src/tools/wasm-reduce.cpp b/src/tools/wasm-reduce.cpp
index e064abbcb..87f64c1ae 100644
--- a/src/tools/wasm-reduce.cpp
+++ b/src/tools/wasm-reduce.cpp
@@ -23,22 +23,22 @@
// much more debuggable manner).
//
-#include <memory>
#include <cstdio>
#include <cstdlib>
+#include <memory>
+#include "ir/branch-utils.h"
+#include "ir/iteration.h"
+#include "ir/literal-utils.h"
+#include "ir/properties.h"
#include "pass.h"
-#include "support/command-line.h"
#include "support/colors.h"
+#include "support/command-line.h"
#include "support/file.h"
#include "support/path.h"
#include "support/timing.h"
-#include "wasm-io.h"
#include "wasm-builder.h"
-#include "ir/branch-utils.h"
-#include "ir/iteration.h"
-#include "ir/literal-utils.h"
-#include "ir/properties.h"
+#include "wasm-io.h"
#include "wasm-validator.h"
#ifdef _WIN32
#ifndef NOMINMAX
@@ -50,18 +50,18 @@ std::string GetLastErrorStdStr() {
DWORD error = GetLastError();
if (error) {
LPVOID lpMsgBuf;
- DWORD bufLen = FormatMessage(
- FORMAT_MESSAGE_ALLOCATE_BUFFER |
- FORMAT_MESSAGE_FROM_SYSTEM |
- FORMAT_MESSAGE_IGNORE_INSERTS,
- NULL,
- error,
- MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
- (LPTSTR) &lpMsgBuf,
- 0, NULL );
+ DWORD bufLen = FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER |
+ FORMAT_MESSAGE_FROM_SYSTEM |
+ FORMAT_MESSAGE_IGNORE_INSERTS,
+ NULL,
+ error,
+ MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
+ (LPTSTR)&lpMsgBuf,
+ 0,
+ NULL);
if (bufLen) {
LPCSTR lpMsgStr = (LPCSTR)lpMsgBuf;
- std::string result(lpMsgStr, lpMsgStr+bufLen);
+ std::string result(lpMsgStr, lpMsgStr + bufLen);
LocalFree(lpMsgBuf);
return result;
}
@@ -80,9 +80,7 @@ struct ProgramResult {
double time;
ProgramResult() = default;
- ProgramResult(std::string command) {
- getFromExecution(command);
- }
+ ProgramResult(std::string command) { getFromExecution(command); }
#ifdef _WIN32
void getFromExecution(std::string command) {
@@ -100,9 +98,9 @@ struct ProgramResult {
// Create a pipe for the child process's STDOUT.
!CreatePipe(&hChildStd_OUT_Rd, &hChildStd_OUT_Wr, &saAttr, 0) ||
// Ensure the read handle to the pipe for STDOUT is not inherited.
- !SetHandleInformation(hChildStd_OUT_Rd, HANDLE_FLAG_INHERIT, 0)
- ) {
- Fatal() << "CreatePipe \"" << command << "\" failed: " << GetLastErrorStdStr() << ".\n";
+ !SetHandleInformation(hChildStd_OUT_Rd, HANDLE_FLAG_INHERIT, 0)) {
+ Fatal() << "CreatePipe \"" << command
+ << "\" failed: " << GetLastErrorStdStr() << ".\n";
}
STARTUPINFO si;
@@ -116,18 +114,19 @@ struct ProgramResult {
ZeroMemory(&pi, sizeof(pi));
// Start the child process.
- if (!CreateProcess(NULL, // No module name (use command line)
- (LPSTR)command.c_str(),// Command line
- NULL, // Process handle not inheritable
- NULL, // Thread handle not inheritable
- TRUE, // Set handle inheritance to TRUE
- 0, // No creation flags
- NULL, // Use parent's environment block
- NULL, // Use parent's starting directory
- &si, // Pointer to STARTUPINFO structure
- &pi ) // Pointer to PROCESS_INFORMATION structure
+ if (!CreateProcess(NULL, // No module name (use command line)
+ (LPSTR)command.c_str(), // Command line
+ NULL, // Process handle not inheritable
+ NULL, // Thread handle not inheritable
+ TRUE, // Set handle inheritance to TRUE
+ 0, // No creation flags
+ NULL, // Use parent's environment block
+ NULL, // Use parent's starting directory
+ &si, // Pointer to STARTUPINFO structure
+ &pi) // Pointer to PROCESS_INFORMATION structure
) {
- Fatal() << "CreateProcess \"" << command << "\" failed: " << GetLastErrorStdStr() << ".\n";
+ Fatal() << "CreateProcess \"" << command
+ << "\" failed: " << GetLastErrorStdStr() << ".\n";
}
// Wait until child process exits.
@@ -156,8 +155,10 @@ struct ProgramResult {
PeekNamedPipe(hChildStd_OUT_Rd, NULL, 0, NULL, &dwTotal, NULL);
while (dwTotalRead < dwTotal) {
- bSuccess = ReadFile(hChildStd_OUT_Rd, chBuf, BUFSIZE - 1, &dwRead, NULL);
- if (!bSuccess || dwRead == 0) break;
+ bSuccess =
+ ReadFile(hChildStd_OUT_Rd, chBuf, BUFSIZE - 1, &dwRead, NULL);
+ if (!bSuccess || dwRead == 0)
+ break;
chBuf[dwRead] = 0;
dwTotalRead += dwRead;
output.append(chBuf);
@@ -166,7 +167,7 @@ struct ProgramResult {
timer.stop();
time = timer.getTotal();
}
-#else // POSIX
+#else // POSIX
// runs the command and notes the output
// TODO: also stderr, not just stdout?
void getFromExecution(std::string command) {
@@ -174,10 +175,15 @@ struct ProgramResult {
timer.start();
// do this using just core stdio.h and stdlib.h, for portability
// sadly this requires two invokes
- code = system(("timeout " + std::to_string(timeout) + "s " + command + " > /dev/null 2> /dev/null").c_str());
+ code = system(("timeout " + std::to_string(timeout) + "s " + command +
+ " > /dev/null 2> /dev/null")
+ .c_str());
const int MAX_BUFFER = 1024;
char buffer[MAX_BUFFER];
- FILE *stream = popen(("timeout " + std::to_string(timeout) + "s " + command + " 2> /dev/null").c_str(), "r");
+ FILE* stream = popen(
+ ("timeout " + std::to_string(timeout) + "s " + command + " 2> /dev/null")
+ .c_str(),
+ "r");
while (fgets(buffer, MAX_BUFFER, stream) != NULL) {
output.append(buffer);
}
@@ -190,16 +196,13 @@ struct ProgramResult {
bool operator==(ProgramResult& other) {
return code == other.code && output == other.output;
}
- bool operator!=(ProgramResult& other) {
- return !(*this == other);
- }
+ bool operator!=(ProgramResult& other) { return !(*this == other); }
- bool failed() {
- return code != 0;
- }
+ bool failed() { return code != 0; }
void dump(std::ostream& o) {
- o << "[ProgramResult] code: " << code << " stdout: \n" << output << "[====]\nin " << time << " seconds\n[/ProgramResult]\n";
+ o << "[ProgramResult] code: " << code << " stdout: \n"
+ << output << "[====]\nin " << time << " seconds\n[/ProgramResult]\n";
}
};
@@ -210,7 +213,7 @@ inline std::ostream& operator<<(std::ostream& o, ProgramResult& result) {
return o;
}
-}
+} // namespace std
ProgramResult expected;
@@ -219,14 +222,22 @@ ProgramResult expected;
// case we may try again but much later.
static std::unordered_set<Name> functionsWeTriedToRemove;
-struct Reducer : public WalkerPass<PostWalker<Reducer, UnifiedExpressionVisitor<Reducer>>> {
+struct Reducer
+ : public WalkerPass<PostWalker<Reducer, UnifiedExpressionVisitor<Reducer>>> {
std::string command, test, working;
bool binary, deNan, verbose, debugInfo;
// test is the file we write to that the command will operate on
// working is the current temporary state, the reduction so far
- Reducer(std::string command, std::string test, std::string working, bool binary, bool deNan, bool verbose, bool debugInfo) :
- command(command), test(test), working(working), binary(binary), deNan(deNan), verbose(verbose), debugInfo(debugInfo) {}
+ Reducer(std::string command,
+ std::string test,
+ std::string working,
+ bool binary,
+ bool deNan,
+ bool verbose,
+ bool debugInfo)
+ : command(command), test(test), working(working), binary(binary),
+ deNan(deNan), verbose(verbose), debugInfo(debugInfo) {}
// runs passes in order to reduce, until we can't reduce any more
// the criterion here is wasm binary size
@@ -261,28 +272,32 @@ struct Reducer : public WalkerPass<PostWalker<Reducer, UnifiedExpressionVisitor<
"--reorder-locals",
"--simplify-locals --vacuum",
"--strip",
- "--vacuum"
- };
+ "--vacuum"};
auto oldSize = file_size(working);
bool more = true;
while (more) {
- //std::cerr << "| starting passes loop iteration\n";
+ // std::cerr << "| starting passes loop iteration\n";
more = false;
- // try both combining with a generic shrink (so minor pass overhead is compensated for), and without
+ // try both combining with a generic shrink (so minor pass overhead is
+ // compensated for), and without
for (auto pass : passes) {
std::string currCommand = Path::getBinaryenBinaryTool("wasm-opt") + " ";
// TODO(tlively): -all should be replaced with an option to use the
// existing feature set, once implemented.
currCommand += working + " -all -o " + test + " " + pass;
- if (debugInfo) currCommand += " -g ";
- if (verbose) std::cerr << "| trying pass command: " << currCommand << "\n";
+ if (debugInfo)
+ currCommand += " -g ";
+ if (verbose)
+ std::cerr << "| trying pass command: " << currCommand << "\n";
if (!ProgramResult(currCommand).failed()) {
auto newSize = file_size(test);
if (newSize < oldSize) {
// the pass didn't fail, and the size looks smaller, so promising
// see if it is still has the property we are preserving
if (ProgramResult(command) == expected) {
- std::cerr << "| command \"" << currCommand << "\" succeeded, reduced size to " << newSize << ", and preserved the property\n";
+ std::cerr << "| command \"" << currCommand
+ << "\" succeeded, reduced size to " << newSize
+ << ", and preserved the property\n";
copy_file(test, working);
more = true;
oldSize = newSize;
@@ -291,7 +306,8 @@ struct Reducer : public WalkerPass<PostWalker<Reducer, UnifiedExpressionVisitor<
}
}
}
- if (verbose) std::cerr << "| done with passes for now\n";
+ if (verbose)
+ std::cerr << "| done with passes for now\n";
}
// does one pass of slow and destructive reduction. returns whether it
@@ -311,7 +327,9 @@ struct Reducer : public WalkerPass<PostWalker<Reducer, UnifiedExpressionVisitor<
// size should be as expected, and output should be as expected
ProgramResult result;
if (!writeAndTestReduction(result)) {
- std::cerr << "\n|! WARNING: writing before destructive reduction fails, very unlikely reduction can work\n" << result << '\n';
+ std::cerr << "\n|! WARNING: writing before destructive reduction fails, "
+ "very unlikely reduction can work\n"
+ << result << '\n';
}
// destroy!
walkModule(getModule());
@@ -381,15 +399,18 @@ struct Reducer : public WalkerPass<PostWalker<Reducer, UnifiedExpressionVisitor<
return false;
}
auto* curr = getCurrent();
- //std::cerr << "try " << curr << " => " << with << '\n';
- if (curr->type != with->type) return false;
- if (!shouldTryToReduce()) return false;
+ // std::cerr << "try " << curr << " => " << with << '\n';
+ if (curr->type != with->type)
+ return false;
+ if (!shouldTryToReduce())
+ return false;
replaceCurrent(with);
if (!writeAndTestReduction()) {
replaceCurrent(curr);
return false;
}
- std::cerr << "| tryToReplaceCurrent succeeded (in " << getLocation() << ")\n";
+ std::cerr << "| tryToReplaceCurrent succeeded (in " << getLocation()
+ << ")\n";
noteReduction();
return true;
}
@@ -404,38 +425,45 @@ struct Reducer : public WalkerPass<PostWalker<Reducer, UnifiedExpressionVisitor<
if (!isOkReplacement(with)) {
return false;
}
- if (child->type != with->type) return false;
- if (!shouldTryToReduce()) return false;
+ if (child->type != with->type)
+ return false;
+ if (!shouldTryToReduce())
+ return false;
auto* before = child;
child = with;
if (!writeAndTestReduction()) {
child = before;
return false;
}
- std::cerr << "| tryToReplaceChild succeeded (in " << getLocation() << ")\n";
- //std::cerr << "| " << before << " => " << with << '\n';
+ std::cerr << "| tryToReplaceChild succeeded (in " << getLocation()
+ << ")\n";
+ // std::cerr << "| " << before << " => " << with << '\n';
noteReduction();
return true;
}
std::string getLocation() {
- if (getFunction()) return getFunction()->name.str;
+ if (getFunction())
+ return getFunction()->name.str;
return "(non-function context)";
}
- // visitors. in each we try to remove code in a destructive and nontrivial way.
- // "nontrivial" means something that optimization passes can't achieve, since we
- // don't need to duplicate work that they do
+ // visitors. in each we try to remove code in a destructive and nontrivial
+ // way. "nontrivial" means something that optimization passes can't achieve,
+ // since we don't need to duplicate work that they do
void visitExpression(Expression* curr) {
// type-based reductions
if (curr->type == none) {
- if (tryToReduceCurrentToNop()) return;
+ if (tryToReduceCurrentToNop())
+ return;
} else if (isConcreteType(curr->type)) {
- if (tryToReduceCurrentToConst()) return;
+ if (tryToReduceCurrentToConst())
+ return;
} else {
assert(curr->type == unreachable);
- if (tryToReduceCurrentToUnreachable()) return;
+ if (tryToReduceCurrentToUnreachable())
+ return;
}
// specific reductions
if (auto* iff = curr->dynCast<If>()) {
@@ -472,11 +500,14 @@ struct Reducer : public WalkerPass<PostWalker<Reducer, UnifiedExpressionVisitor<
}
}
} else if (auto* block = curr->dynCast<Block>()) {
- if (!shouldTryToReduce()) return;
+ if (!shouldTryToReduce())
+ return;
// replace a singleton
auto& list = block->list;
- if (list.size() == 1 && !BranchUtils::BranchSeeker::hasNamed(block, block->name)) {
- if (tryToReplaceCurrent(block->list[0])) return;
+ if (list.size() == 1 &&
+ !BranchUtils::BranchSeeker::hasNamed(block, block->name)) {
+ if (tryToReplaceCurrent(block->list[0]))
+ return;
}
// try to get rid of nops
Index i = 0;
@@ -504,7 +535,8 @@ struct Reducer : public WalkerPass<PostWalker<Reducer, UnifiedExpressionVisitor<
}
return; // nothing more to do
} else if (auto* loop = curr->dynCast<Loop>()) {
- if (shouldTryToReduce() && !BranchUtils::BranchSeeker::hasNamed(loop, loop->name)) {
+ if (shouldTryToReduce() &&
+ !BranchUtils::BranchSeeker::hasNamed(loop, loop->name)) {
tryToReplaceCurrent(loop->body);
}
return; // nothing more to do
@@ -512,73 +544,116 @@ struct Reducer : public WalkerPass<PostWalker<Reducer, UnifiedExpressionVisitor<
// Finally, try to replace with a child.
for (auto* child : ChildIterator(curr)) {
if (isConcreteType(child->type) && curr->type == none) {
- if (tryToReplaceCurrent(builder->makeDrop(child))) return;
+ if (tryToReplaceCurrent(builder->makeDrop(child)))
+ return;
} else {
- if (tryToReplaceCurrent(child)) return;
+ if (tryToReplaceCurrent(child))
+ return;
}
}
// If that didn't work, try to replace with a child + a unary conversion
if (isConcreteType(curr->type) &&
!curr->is<Unary>()) { // but not if it's already unary
for (auto* child : ChildIterator(curr)) {
- if (child->type == curr->type) continue; // already tried
- if (!isConcreteType(child->type)) continue; // no conversion
+ if (child->type == curr->type)
+ continue; // already tried
+ if (!isConcreteType(child->type))
+ continue; // no conversion
Expression* fixed = nullptr;
switch (curr->type) {
case i32: {
switch (child->type) {
- case i32: WASM_UNREACHABLE();
- case i64: fixed = builder->makeUnary(WrapInt64, child); break;
- case f32: fixed = builder->makeUnary(TruncSFloat32ToInt32, child); break;
- case f64: fixed = builder->makeUnary(TruncSFloat64ToInt32, child); break;
- case v128: continue; // v128 not implemented yet
+ case i32:
+ WASM_UNREACHABLE();
+ case i64:
+ fixed = builder->makeUnary(WrapInt64, child);
+ break;
+ case f32:
+ fixed = builder->makeUnary(TruncSFloat32ToInt32, child);
+ break;
+ case f64:
+ fixed = builder->makeUnary(TruncSFloat64ToInt32, child);
+ break;
+ case v128:
+ continue; // v128 not implemented yet
case none:
- case unreachable: WASM_UNREACHABLE();
+ case unreachable:
+ WASM_UNREACHABLE();
}
break;
}
case i64: {
switch (child->type) {
- case i32: fixed = builder->makeUnary(ExtendSInt32, child); break;
- case i64: WASM_UNREACHABLE();
- case f32: fixed = builder->makeUnary(TruncSFloat32ToInt64, child); break;
- case f64: fixed = builder->makeUnary(TruncSFloat64ToInt64, child); break;
- case v128: continue; // v128 not implemented yet
+ case i32:
+ fixed = builder->makeUnary(ExtendSInt32, child);
+ break;
+ case i64:
+ WASM_UNREACHABLE();
+ case f32:
+ fixed = builder->makeUnary(TruncSFloat32ToInt64, child);
+ break;
+ case f64:
+ fixed = builder->makeUnary(TruncSFloat64ToInt64, child);
+ break;
+ case v128:
+ continue; // v128 not implemented yet
case none:
- case unreachable: WASM_UNREACHABLE();
+ case unreachable:
+ WASM_UNREACHABLE();
}
break;
}
case f32: {
switch (child->type) {
- case i32: fixed = builder->makeUnary(ConvertSInt32ToFloat32, child); break;
- case i64: fixed = builder->makeUnary(ConvertSInt64ToFloat32, child); break;
- case f32: WASM_UNREACHABLE();
- case f64: fixed = builder->makeUnary(DemoteFloat64, child); break;
- case v128: continue; // v128 not implemented yet
+ case i32:
+ fixed = builder->makeUnary(ConvertSInt32ToFloat32, child);
+ break;
+ case i64:
+ fixed = builder->makeUnary(ConvertSInt64ToFloat32, child);
+ break;
+ case f32:
+ WASM_UNREACHABLE();
+ case f64:
+ fixed = builder->makeUnary(DemoteFloat64, child);
+ break;
+ case v128:
+ continue; // v128 not implemented yet
case none:
- case unreachable: WASM_UNREACHABLE();
+ case unreachable:
+ WASM_UNREACHABLE();
}
break;
}
case f64: {
switch (child->type) {
- case i32: fixed = builder->makeUnary(ConvertSInt32ToFloat64, child); break;
- case i64: fixed = builder->makeUnary(ConvertSInt64ToFloat64, child); break;
- case f32: fixed = builder->makeUnary(PromoteFloat32, child); break;
- case f64: WASM_UNREACHABLE();
- case v128: continue; // v128 not implemented yet
+ case i32:
+ fixed = builder->makeUnary(ConvertSInt32ToFloat64, child);
+ break;
+ case i64:
+ fixed = builder->makeUnary(ConvertSInt64ToFloat64, child);
+ break;
+ case f32:
+ fixed = builder->makeUnary(PromoteFloat32, child);
+ break;
+ case f64:
+ WASM_UNREACHABLE();
+ case v128:
+ continue; // v128 not implemented yet
case none:
- case unreachable: WASM_UNREACHABLE();
+ case unreachable:
+ WASM_UNREACHABLE();
}
break;
}
- case v128: continue; // v128 not implemented yet
+ case v128:
+ continue; // v128 not implemented yet
case none:
- case unreachable: WASM_UNREACHABLE();
+ case unreachable:
+ WASM_UNREACHABLE();
}
assert(fixed->type == curr->type);
- if (tryToReplaceCurrent(fixed)) return;
+ if (tryToReplaceCurrent(fixed))
+ return;
}
}
}
@@ -609,7 +684,8 @@ struct Reducer : public WalkerPass<PostWalker<Reducer, UnifiedExpressionVisitor<
first = item;
break;
}
- if (!first.isNull()) break;
+ if (!first.isNull())
+ break;
}
visitSegmented(curr, first, 100);
}
@@ -627,12 +703,15 @@ struct Reducer : public WalkerPass<PostWalker<Reducer, UnifiedExpressionVisitor<
bool shrank = false;
for (auto& segment : curr->segments) {
auto& data = segment.data;
- size_t skip = 1; // when we succeed, try to shrink by more and more, similar to bisection
+ // when we succeed, try to shrink by more and more, similar to bisection
+ size_t skip = 1;
for (size_t i = 0; i < data.size() && !data.empty(); i++) {
- if (!justShrank && !shouldTryToReduce(bonus)) continue;
+ if (!justShrank && !shouldTryToReduce(bonus))
+ continue;
auto save = data;
for (size_t j = 0; j < skip; j++) {
- if (!data.empty()) data.pop_back();
+ if (!data.empty())
+ data.pop_back();
}
auto justShrank = writeAndTestReduction();
if (justShrank) {
@@ -648,10 +727,13 @@ struct Reducer : public WalkerPass<PostWalker<Reducer, UnifiedExpressionVisitor<
}
// the "opposite" of shrinking: copy a 'zero' element
for (auto& segment : curr->segments) {
- if (segment.data.empty()) continue;
+ if (segment.data.empty())
+ continue;
for (auto& item : segment.data) {
- if (!shouldTryToReduce(bonus)) continue;
- if (item == zero) continue;
+ if (!shouldTryToReduce(bonus))
+ continue;
+ if (item == zero)
+ continue;
auto save = item;
item = zero;
if (writeAndTestReduction()) {
@@ -678,23 +760,27 @@ struct Reducer : public WalkerPass<PostWalker<Reducer, UnifiedExpressionVisitor<
functionNames.push_back(func->name);
}
size_t skip = 1;
- // If we just removed some functions in the previous iteration, keep trying to remove more
- // as this is one of the most efficient ways to reduce.
+ // If we just removed some functions in the previous iteration, keep trying
+ // to remove more as this is one of the most efficient ways to reduce.
bool justRemoved = false;
for (size_t i = 0; i < functionNames.size(); i++) {
if (!justRemoved &&
functionsWeTriedToRemove.count(functionNames[i]) == 1 &&
- !shouldTryToReduce(std::max((factor / 100) + 1, 1000))) continue;
+ !shouldTryToReduce(std::max((factor / 100) + 1, 1000)))
+ continue;
std::vector<Name> names;
- for (size_t j = 0; names.size() < skip && i + j < functionNames.size(); j++) {
+ for (size_t j = 0; names.size() < skip && i + j < functionNames.size();
+ j++) {
auto name = functionNames[i + j];
if (module->getFunctionOrNull(name)) {
names.push_back(name);
functionsWeTriedToRemove.insert(name);
}
}
- if (names.size() == 0) continue;
- std::cout << "| try to remove " << names.size() << " functions (skip: " << skip << ")\n";
+ if (names.size() == 0)
+ continue;
+ std::cout << "| try to remove " << names.size()
+ << " functions (skip: " << skip << ")\n";
justRemoved = tryToRemoveFunctions(names);
if (justRemoved) {
noteReduction(names.size());
@@ -712,9 +798,11 @@ struct Reducer : public WalkerPass<PostWalker<Reducer, UnifiedExpressionVisitor<
}
skip = 1;
for (size_t i = 0; i < exports.size(); i++) {
- if (!shouldTryToReduce(std::max((factor / 100) + 1, 1000))) continue;
+ if (!shouldTryToReduce(std::max((factor / 100) + 1, 1000)))
+ continue;
std::vector<Export> currExports;
- for (size_t j = 0; currExports.size() < skip && i + j < exports.size(); j++) {
+ for (size_t j = 0; currExports.size() < skip && i + j < exports.size();
+ j++) {
auto exp = exports[i + j];
if (module->getExportOrNull(exp.name)) {
currExports.push_back(exp);
@@ -736,7 +824,8 @@ struct Reducer : public WalkerPass<PostWalker<Reducer, UnifiedExpressionVisitor<
}
// If we are left with a single function that is not exported or used in
// a table, that is useful as then we can change the return type.
- if (module->functions.size() == 1 && module->exports.empty() && module->table.segments.empty()) {
+ if (module->functions.size() == 1 && module->exports.empty() &&
+ module->table.segments.empty()) {
auto* func = module->functions[0].get();
// We can't remove something that might have breaks to it.
if (!func->imported() && !Properties::isNamedControlFlow(func->body)) {
@@ -773,7 +862,8 @@ struct Reducer : public WalkerPass<PostWalker<Reducer, UnifiedExpressionVisitor<
}
// remove all references to them
- struct FunctionReferenceRemover : public PostWalker<FunctionReferenceRemover> {
+ struct FunctionReferenceRemover
+ : public PostWalker<FunctionReferenceRemover> {
std::unordered_set<Name> names;
std::vector<Name> exportsToRemove;
@@ -801,9 +891,11 @@ struct Reducer : public WalkerPass<PostWalker<Reducer, UnifiedExpressionVisitor<
break;
}
}
- if (!other.isNull()) break;
+ if (!other.isNull())
+ break;
}
- if (other.isNull()) return; // we failed to find a replacement
+ if (other.isNull())
+ return; // we failed to find a replacement
for (auto& segment : curr->segments) {
for (auto& name : segment.data) {
if (names.count(name)) {
@@ -822,7 +914,8 @@ struct Reducer : public WalkerPass<PostWalker<Reducer, UnifiedExpressionVisitor<
FunctionReferenceRemover referenceRemover(names);
referenceRemover.walkModule(module.get());
- if (WasmValidator().validate(*module, WasmValidator::Globally | WasmValidator::Quiet) &&
+ if (WasmValidator().validate(
+ *module, WasmValidator::Globally | WasmValidator::Quiet) &&
writeAndTestReduction()) {
std::cerr << "| removed " << names.size() << " functions\n";
return true;
@@ -836,8 +929,10 @@ struct Reducer : public WalkerPass<PostWalker<Reducer, UnifiedExpressionVisitor<
// try to replace condition with always true and always false
void handleCondition(Expression*& condition) {
- if (!condition) return;
- if (condition->is<Const>()) return;
+ if (!condition)
+ return;
+ if (condition->is<Const>())
+ return;
auto* c = builder->makeConst(Literal(int32_t(0)));
if (!tryToReplaceChild(condition, c)) {
c->value = Literal(int32_t(1));
@@ -847,7 +942,8 @@ struct Reducer : public WalkerPass<PostWalker<Reducer, UnifiedExpressionVisitor<
bool tryToReduceCurrentToNop() {
auto* curr = getCurrent();
- if (curr->is<Nop>()) return false;
+ if (curr->is<Nop>())
+ return false;
// try to replace with a trivial value
Nop nop;
if (tryToReplaceCurrent(&nop)) {
@@ -860,10 +956,12 @@ struct Reducer : public WalkerPass<PostWalker<Reducer, UnifiedExpressionVisitor<
// try to replace a concrete value with a trivial constant
bool tryToReduceCurrentToConst() {
auto* curr = getCurrent();
- if (curr->is<Const>()) return false;
+ if (curr->is<Const>())
+ return false;
// try to replace with a trivial value
Const* c = builder->makeConst(Literal(int32_t(0)));
- if (tryToReplaceCurrent(c)) return true;
+ if (tryToReplaceCurrent(c))
+ return true;
c->value = Literal::makeFromInt32(1, curr->type);
c->type = curr->type;
return tryToReplaceCurrent(c);
@@ -871,7 +969,8 @@ struct Reducer : public WalkerPass<PostWalker<Reducer, UnifiedExpressionVisitor<
bool tryToReduceCurrentToUnreachable() {
auto* curr = getCurrent();
- if (curr->is<Unreachable>()) return false;
+ if (curr->is<Unreachable>())
+ return false;
// try to replace with a trivial value
Unreachable un;
if (tryToReplaceCurrent(&un)) {
@@ -889,76 +988,87 @@ struct Reducer : public WalkerPass<PostWalker<Reducer, UnifiedExpressionVisitor<
int main(int argc, const char* argv[]) {
std::string input, test, working, command;
- bool binary = true,
- deNan = false,
- verbose = false,
- debugInfo = false,
+ bool binary = true, deNan = false, verbose = false, debugInfo = false,
force = false;
- Options options("wasm-reduce", "Reduce a wasm file to a smaller one that has the same behavior on a given command");
+ Options options("wasm-reduce",
+ "Reduce a wasm file to a smaller one that has the same "
+ "behavior on a given command");
options
- .add("--command", "-cmd", "The command to run on the test, that we want to reduce while keeping the command's output identical. "
- "We look at the command's return code and stdout here (TODO: stderr), "
- "and we reduce while keeping those unchanged.",
- Options::Arguments::One,
- [&](Options* o, const std::string& argument) {
- command = argument;
- })
- .add("--test", "-t", "Test file (this will be written to to test, the given command should read it when we call it)",
- Options::Arguments::One,
- [&](Options* o, const std::string& argument) {
- test = argument;
- })
- .add("--working", "-w", "Working file (this will contain the current good state while doing temporary computations, "
- "and will contain the final best result at the end)",
- Options::Arguments::One,
- [&](Options* o, const std::string& argument) {
- working = argument;
- })
- .add("--binaries", "-b", "binaryen binaries location (bin/ directory)",
- Options::Arguments::One,
- [&](Options* o, const std::string& argument) {
- // Add separator just in case
- Path::setBinaryenBinDir(argument + Path::getPathSeparator());
- })
- .add("--text", "-S", "Emit intermediate files as text, instead of binary (also make sure the test and working files have a .wat or .wast suffix)",
- Options::Arguments::Zero,
- [&](Options* o, const std::string& argument) {
- binary = false;
- })
- .add("--denan", "", "Avoid nans when reducing",
- Options::Arguments::Zero,
- [&](Options* o, const std::string& argument) {
- deNan = true;
- })
- .add("--verbose", "-v", "Verbose output mode",
- Options::Arguments::Zero,
- [&](Options* o, const std::string& argument) {
- verbose = true;
- })
- .add("--debugInfo", "-g", "Keep debug info in binaries",
- Options::Arguments::Zero,
- [&](Options* o, const std::string& argument) {
- debugInfo = true;
- })
- .add("--force", "-f", "Force the reduction attempt, ignoring problems that imply it is unlikely to succeed",
- Options::Arguments::Zero,
- [&](Options* o, const std::string& argument) {
- force = true;
- })
- .add("--timeout", "-to", "A timeout to apply to each execution of the command, in seconds (default: 2)",
- Options::Arguments::One,
- [&](Options* o, const std::string& argument) {
- timeout = atoi(argument.c_str());
- std::cout << "|applying timeout: " << timeout << "\n";
- })
- .add_positional("INFILE", Options::Arguments::One,
- [&](Options* o, const std::string& argument) {
- input = argument;
- });
+ .add("--command",
+ "-cmd",
+ "The command to run on the test, that we want to reduce while keeping "
+ "the command's output identical. "
+ "We look at the command's return code and stdout here (TODO: stderr), "
+ "and we reduce while keeping those unchanged.",
+ Options::Arguments::One,
+ [&](Options* o, const std::string& argument) { command = argument; })
+ .add("--test",
+ "-t",
+ "Test file (this will be written to to test, the given command should "
+ "read it when we call it)",
+ Options::Arguments::One,
+ [&](Options* o, const std::string& argument) { test = argument; })
+ .add("--working",
+ "-w",
+ "Working file (this will contain the current good state while doing "
+ "temporary computations, "
+ "and will contain the final best result at the end)",
+ Options::Arguments::One,
+ [&](Options* o, const std::string& argument) { working = argument; })
+ .add("--binaries",
+ "-b",
+ "binaryen binaries location (bin/ directory)",
+ Options::Arguments::One,
+ [&](Options* o, const std::string& argument) {
+ // Add separator just in case
+ Path::setBinaryenBinDir(argument + Path::getPathSeparator());
+ })
+ .add("--text",
+ "-S",
+ "Emit intermediate files as text, instead of binary (also make sure "
+ "the test and working files have a .wat or .wast suffix)",
+ Options::Arguments::Zero,
+ [&](Options* o, const std::string& argument) { binary = false; })
+ .add("--denan",
+ "",
+ "Avoid nans when reducing",
+ Options::Arguments::Zero,
+ [&](Options* o, const std::string& argument) { deNan = true; })
+ .add("--verbose",
+ "-v",
+ "Verbose output mode",
+ Options::Arguments::Zero,
+ [&](Options* o, const std::string& argument) { verbose = true; })
+ .add("--debugInfo",
+ "-g",
+ "Keep debug info in binaries",
+ Options::Arguments::Zero,
+ [&](Options* o, const std::string& argument) { debugInfo = true; })
+ .add("--force",
+ "-f",
+ "Force the reduction attempt, ignoring problems that imply it is "
+ "unlikely to succeed",
+ Options::Arguments::Zero,
+ [&](Options* o, const std::string& argument) { force = true; })
+ .add("--timeout",
+ "-to",
+ "A timeout to apply to each execution of the command, in seconds "
+ "(default: 2)",
+ Options::Arguments::One,
+ [&](Options* o, const std::string& argument) {
+ timeout = atoi(argument.c_str());
+ std::cout << "|applying timeout: " << timeout << "\n";
+ })
+ .add_positional(
+ "INFILE",
+ Options::Arguments::One,
+ [&](Options* o, const std::string& argument) { input = argument; });
options.parse(argc, argv);
- if (test.size() == 0) Fatal() << "test file not provided\n";
- if (working.size() == 0) Fatal() << "working file not provided\n";
+ if (test.size() == 0)
+ Fatal() << "test file not provided\n";
+ if (working.size() == 0)
+ Fatal() << "working file not provided\n";
if (!binary) {
Colors::disable();
@@ -979,15 +1089,20 @@ int main(int argc, const char* argv[]) {
auto stopIfNotForced = [&](std::string message, ProgramResult& result) {
std::cerr << "|! " << message << '\n' << result << '\n';
if (!force) {
- Fatal() << "|! stopping, as it is very unlikely reduction can succeed (use -f to ignore this check)";
+ Fatal() << "|! stopping, as it is very unlikely reduction can succeed "
+ "(use -f to ignore this check)";
}
};
if (expected.time + 1 >= timeout) {
- stopIfNotForced("execution time is dangerously close to the timeout - you should probably increase the timeout", expected);
+ stopIfNotForced("execution time is dangerously close to the timeout - you "
+ "should probably increase the timeout",
+ expected);
}
- std::cerr << "|checking that command has different behavior on invalid binary (this verifies that the test file is used by the command)\n";
+ std::cerr
+ << "|checking that command has different behavior on invalid binary (this "
+ "verifies that the test file is used by the command)\n";
{
{
std::ofstream dst(test, std::ios::binary);
@@ -995,24 +1110,31 @@ int main(int argc, const char* argv[]) {
}
ProgramResult result(command);
if (result == expected) {
- stopIfNotForced("running command on an invalid module should give different results", result);
+ stopIfNotForced(
+ "running command on an invalid module should give different results",
+ result);
}
}
- std::cerr << "|checking that command has expected behavior on canonicalized (read-written) binary\n";
+ std::cerr << "|checking that command has expected behavior on canonicalized "
+ "(read-written) binary\n";
{
// read and write it
// TODO(tlively): -all should be replaced with an option to use the existing
// feature set, once implemented.
- auto cmd = Path::getBinaryenBinaryTool("wasm-opt") + " " + input + " -all -o " + test;
- if (!binary) cmd += " -S";
+ auto cmd = Path::getBinaryenBinaryTool("wasm-opt") + " " + input +
+ " -all -o " + test;
+ if (!binary)
+ cmd += " -S";
ProgramResult readWrite(cmd);
if (readWrite.failed()) {
stopIfNotForced("failed to read and write the binary", readWrite);
} else {
ProgramResult result(command);
if (result != expected) {
- stopIfNotForced("running command on the canonicalized module should give the same results", result);
+ stopIfNotForced("running command on the canonicalized module should "
+ "give the same results",
+ result);
}
}
}
@@ -1044,13 +1166,15 @@ int main(int argc, const char* argv[]) {
std::cerr << "| after pass reduction: " << newSize << "\n";
// always stop after a pass reduction attempt, for final cleanup
- if (stopping) break;
+ if (stopping)
+ break;
// check if the full cycle (destructive/passes) has helped or not
if (lastPostPassesSize && newSize >= lastPostPassesSize) {
std::cerr << "| progress has stopped, skipping to the end\n";
if (factor == 1) {
- // this is after doing work with factor 1, so after the remaining work, stop
+ // this is after doing work with factor 1, so after the remaining work,
+ // stop
stopping = true;
} else {
// just try to remove all we can and finish up
@@ -1059,9 +1183,10 @@ int main(int argc, const char* argv[]) {
}
lastPostPassesSize = newSize;
- // if destructive reductions lead to useful proportionate pass reductions, keep
- // going at the same factor, as pass reductions are far faster
- std::cerr << "| pass progress: " << passProgress << ", last destructive: " << lastDestructiveReductions << '\n';
+ // if destructive reductions lead to useful proportionate pass reductions,
+ // keep going at the same factor, as pass reductions are far faster
+ std::cerr << "| pass progress: " << passProgress
+ << ", last destructive: " << lastDestructiveReductions << '\n';
if (passProgress >= 4 * lastDestructiveReductions) {
// don't change
std::cerr << "| progress is good, do not quickly decrease factor\n";
@@ -1083,16 +1208,19 @@ int main(int argc, const char* argv[]) {
while (1) {
std::cerr << "| reduce destructively... (factor: " << factor << ")\n";
lastDestructiveReductions = reducer.reduceDestructively(factor);
- if (lastDestructiveReductions > 0) break;
+ if (lastDestructiveReductions > 0)
+ break;
// we failed to reduce destructively
if (factor == 1) {
stopping = true;
break;
}
- factor = std::max(1, factor / 4); // quickly now, try to find *something* we can reduce
+ factor = std::max(
+ 1, factor / 4); // quickly now, try to find *something* we can reduce
}
- std::cerr << "| destructive reduction led to size: " << file_size(working) << '\n';
+ std::cerr << "| destructive reduction led to size: " << file_size(working)
+ << '\n';
}
std::cerr << "|finished, final size: " << file_size(working) << "\n";
copy_file(working, test); // just to avoid confusion
diff --git a/src/tools/wasm-shell.cpp b/src/tools/wasm-shell.cpp
index 0c95b39ea..6141b1a37 100644
--- a/src/tools/wasm-shell.cpp
+++ b/src/tools/wasm-shell.cpp
@@ -35,13 +35,13 @@
using namespace cashew;
using namespace wasm;
-Name ASSERT_RETURN("assert_return"),
- ASSERT_TRAP("assert_trap"),
- ASSERT_INVALID("assert_invalid"),
- ASSERT_MALFORMED("assert_malformed"),
- ASSERT_UNLINKABLE("assert_unlinkable"),
- INVOKE("invoke"),
- GET("get");
+Name ASSERT_RETURN("assert_return");
+Name ASSERT_TRAP("assert_trap");
+Name ASSERT_INVALID("assert_invalid");
+Name ASSERT_MALFORMED("assert_malformed");
+Name ASSERT_UNLINKABLE("assert_unlinkable");
+Name INVOKE("invoke");
+Name GET("get");
// Modules named in the file
@@ -60,7 +60,10 @@ struct Operation {
Name name;
LiteralList arguments;
- Operation(Element& element, ModuleInstance* instanceInit, SExpressionWasmBuilder& builder) : instance(instanceInit) {
+ Operation(Element& element,
+ ModuleInstance* instanceInit,
+ SExpressionWasmBuilder& builder)
+ : instance(instanceInit) {
operation = element[0]->str();
Index i = 1;
if (element.size() >= 3 && element[2]->isStr()) {
@@ -87,14 +90,19 @@ struct Operation {
}
};
-static void run_asserts(Name moduleName, size_t* i, bool* checked, Module* wasm,
+static void run_asserts(Name moduleName,
+ size_t* i,
+ bool* checked,
+ Module* wasm,
Element* root,
SExpressionWasmBuilder* builder,
Name entry) {
ModuleInstance* instance = nullptr;
if (wasm) {
- auto tempInterface = wasm::make_unique<ShellExternalInterface>(); // prefix make_unique to work around visual studio bugs
- auto tempInstance = wasm::make_unique<ModuleInstance>(*wasm, tempInterface.get());
+ // prefix make_unique to work around visual studio bugs
+ auto tempInterface = wasm::make_unique<ShellExternalInterface>();
+ auto tempInstance =
+ wasm::make_unique<ModuleInstance>(*wasm, tempInterface.get());
interfaces[moduleName].swap(tempInterface);
instances[moduleName].swap(tempInstance);
instance = instances[moduleName].get();
@@ -117,7 +125,8 @@ static void run_asserts(Name moduleName, size_t* i, bool* checked, Module* wasm,
while (*i < root->size()) {
Element& curr = *(*root)[*i];
IString id = curr[0]->str();
- if (id == MODULE) break;
+ if (id == MODULE)
+ break;
*checked = true;
Colors::red(std::cerr);
std::cerr << *i << '/' << (root->size() - 1);
@@ -128,15 +137,15 @@ static void run_asserts(Name moduleName, size_t* i, bool* checked, Module* wasm,
Colors::green(std::cerr);
std::cerr << " [line: " << curr.line << "]\n";
Colors::normal(std::cerr);
- if (id == ASSERT_INVALID || id == ASSERT_MALFORMED || id == ASSERT_UNLINKABLE) {
+ if (id == ASSERT_INVALID || id == ASSERT_MALFORMED ||
+ id == ASSERT_UNLINKABLE) {
// a module invalidity test
Module wasm;
bool invalid = false;
std::unique_ptr<SExpressionWasmBuilder> builder;
try {
builder = std::unique_ptr<SExpressionWasmBuilder>(
- new SExpressionWasmBuilder(wasm, *curr[1])
- );
+ new SExpressionWasmBuilder(wasm, *curr[1]));
} catch (const ParseException&) {
invalid = true;
}
@@ -147,7 +156,8 @@ static void run_asserts(Name moduleName, size_t* i, bool* checked, Module* wasm,
if (!invalid && id == ASSERT_UNLINKABLE) {
// validate "instantiating" the mdoule
auto reportUnknownImport = [&](Importable* import) {
- std::cerr << "unknown import: " << import->module << '.' << import->base << '\n';
+ std::cerr << "unknown import: " << import->module << '.'
+ << import->base << '\n';
invalid = true;
};
ModuleUtils::iterImportedGlobals(wasm, reportUnknownImport);
@@ -168,7 +178,8 @@ static void run_asserts(Name moduleName, size_t* i, bool* checked, Module* wasm,
for (auto name : segment.data) {
// spec tests consider it illegal to use spectest.print in a table
if (auto* import = wasm.getFunction(name)) {
- if (import->imported() && import->module == SPECTEST && import->base == PRINT) {
+ if (import->imported() && import->module == SPECTEST &&
+ import->base == PRINT) {
std::cerr << "cannot put spectest.print in table\n";
invalid = true;
}
@@ -201,10 +212,8 @@ static void run_asserts(Name moduleName, size_t* i, bool* checked, Module* wasm,
if (id == ASSERT_RETURN) {
assert(!trapped);
if (curr.size() >= 3) {
- Literal expected = builder
- ->parseExpression(*curr[2])
- ->dynCast<Const>()
- ->value;
+ Literal expected =
+ builder->parseExpression(*curr[2])->dynCast<Const>()->value;
std::cerr << "seen " << result << ", expected " << expected << '\n';
if (expected != result) {
std::cout << "unexpected, should be identical\n";
@@ -219,7 +228,8 @@ static void run_asserts(Name moduleName, size_t* i, bool* checked, Module* wasm,
}
}
}
- if (id == ASSERT_TRAP) assert(trapped);
+ if (id == ASSERT_TRAP)
+ assert(trapped);
}
*i += 1;
}
@@ -235,37 +245,44 @@ int main(int argc, const char* argv[]) {
Options options("wasm-shell", "Execute .wast files");
options
- .add(
- "--entry", "-e", "Call the entry point after parsing the module",
- Options::Arguments::One,
- [&entry](Options*, const std::string& argument) { entry = argument; })
- .add(
- "--skip", "-s", "Skip input on certain lines (comma-separated-list)",
- Options::Arguments::One,
- [&skipped](Options*, const std::string& argument) {
- size_t i = 0;
- while (i < argument.size()) {
- auto ending = argument.find(',', i);
- if (ending == std::string::npos) {
- ending = argument.size();
- }
- auto sub = argument.substr(i, ending - i);
- skipped.insert(atoi(sub.c_str()));
- i = ending + 1;
- }
- })
- .add_positional("INFILE", Options::Arguments::One,
- [](Options* o, const std::string& argument) {
- o->extra["infile"] = argument;
- });
+ .add("--entry",
+ "-e",
+ "Call the entry point after parsing the module",
+ Options::Arguments::One,
+ [&entry](Options*, const std::string& argument) { entry = argument; })
+ .add("--skip",
+ "-s",
+ "Skip input on certain lines (comma-separated-list)",
+ Options::Arguments::One,
+ [&skipped](Options*, const std::string& argument) {
+ size_t i = 0;
+ while (i < argument.size()) {
+ auto ending = argument.find(',', i);
+ if (ending == std::string::npos) {
+ ending = argument.size();
+ }
+ auto sub = argument.substr(i, ending - i);
+ skipped.insert(atoi(sub.c_str()));
+ i = ending + 1;
+ }
+ })
+ .add_positional("INFILE",
+ Options::Arguments::One,
+ [](Options* o, const std::string& argument) {
+ o->extra["infile"] = argument;
+ });
options.parse(argc, argv);
- auto input(read_file<std::vector<char>>(options.extra["infile"], Flags::Text, options.debug ? Flags::Debug : Flags::Release));
+ auto input(read_file<std::vector<char>>(options.extra["infile"],
+ Flags::Text,
+ options.debug ? Flags::Debug
+ : Flags::Release));
bool checked = false;
try {
- if (options.debug) std::cerr << "parsing text to s-expressions...\n";
+ if (options.debug)
+ std::cerr << "parsing text to s-expressions...\n";
SExpressionParser parser(input.data());
Element& root = *parser.root;
@@ -282,13 +299,15 @@ int main(int argc, const char* argv[]) {
}
IString id = curr[0]->str();
if (id == MODULE) {
- if (options.debug) std::cerr << "parsing s-expressions to wasm...\n";
+ if (options.debug)
+ std::cerr << "parsing s-expressions to wasm...\n";
Colors::green(std::cerr);
std::cerr << "BUILDING MODULE [line: " << curr.line << "]\n";
Colors::normal(std::cerr);
auto module = wasm::make_unique<Module>();
Name moduleName;
- auto builder = wasm::make_unique<SExpressionWasmBuilder>(*module, *root[i], &moduleName);
+ auto builder = wasm::make_unique<SExpressionWasmBuilder>(
+ *module, *root[i], &moduleName);
builders[moduleName].swap(builder);
modules[moduleName].swap(module);
i++;
@@ -298,7 +317,13 @@ int main(int argc, const char* argv[]) {
WasmPrinter::printModule(modules[moduleName].get());
}
assert(valid);
- run_asserts(moduleName, &i, &checked, modules[moduleName].get(), &root, builders[moduleName].get(), entry);
+ run_asserts(moduleName,
+ &i,
+ &checked,
+ modules[moduleName].get(),
+ &root,
+ builders[moduleName].get(),
+ entry);
} else {
run_asserts(Name(), &i, &checked, nullptr, &root, nullptr, entry);
}
diff --git a/src/tools/wasm2js.cpp b/src/tools/wasm2js.cpp
index 84aa9f024..3d5f484da 100644
--- a/src/tools/wasm2js.cpp
+++ b/src/tools/wasm2js.cpp
@@ -18,13 +18,14 @@
// wasm2js console tool
//
+#include "wasm2js.h"
+#include "optimization-options.h"
+#include "pass.h"
#include "support/colors.h"
#include "support/command-line.h"
#include "support/file.h"
#include "wasm-s-parser.h"
#include "wasm2js.h"
-#include "optimization-options.h"
-#include "pass.h"
using namespace cashew;
using namespace wasm;
@@ -34,8 +35,8 @@ using namespace wasm;
namespace {
static void optimizeWasm(Module& wasm, PassOptions options) {
- // Perform various optimizations that will be good for JS, but would not be great
- // for wasm in general
+ // Perform various optimizations that will be good for JS, but would not be
+ // great for wasm in general
struct OptimizeForJS : public WalkerPass<PostWalker<OptimizeForJS>> {
bool isFunctionParallel() override { return true; }
@@ -60,14 +61,12 @@ static void optimizeWasm(Module& wasm, PassOptions options) {
runner.run();
}
-template<typename T>
-static void printJS(Ref ast, T& output) {
+template<typename T> static void printJS(Ref ast, T& output) {
JSPrinter jser(true, true, ast);
jser.printAst();
output << jser.buffer << std::endl;
}
-
// Traversals
struct TraverseInfo {
@@ -102,7 +101,9 @@ private:
};
// Traverse, calling visit after the children
-static void traversePrePost(Ref node, std::function<void (Ref)> visitPre, std::function<void (Ref)> visitPost) {
+static void traversePrePost(Ref node,
+ std::function<void(Ref)> visitPre,
+ std::function<void(Ref)> visitPost) {
std::vector<TraverseInfo> stack;
stack.push_back(TraverseInfo(node));
while (!stack.empty()) {
@@ -123,7 +124,7 @@ static void traversePrePost(Ref node, std::function<void (Ref)> visitPre, std::f
}
}
-static void traversePost(Ref node, std::function<void (Ref)> visit) {
+static void traversePost(Ref node, std::function<void(Ref)> visit) {
traversePrePost(node, [](Ref node) {}, visit);
}
@@ -131,24 +132,28 @@ static void optimizeJS(Ref ast) {
// helpers
auto isOrZero = [](Ref node) {
- return node->isArray() && !node->empty() && node[0] == BINARY && node[1] == OR && node[3]->isNumber() && node[3]->getNumber() == 0;
+ return node->isArray() && !node->empty() && node[0] == BINARY &&
+ node[1] == OR && node[3]->isNumber() && node[3]->getNumber() == 0;
};
auto isPlus = [](Ref node) {
- return node->isArray() && !node->empty() && node[0] == UNARY_PREFIX && node[1] == PLUS;
+ return node->isArray() && !node->empty() && node[0] == UNARY_PREFIX &&
+ node[1] == PLUS;
};
auto isBitwise = [](Ref node) {
if (node->isArray() && !node->empty() && node[0] == BINARY) {
auto op = node[1];
- return op == OR || op == AND || op == XOR || op == RSHIFT || op == TRSHIFT || op == LSHIFT;
+ return op == OR || op == AND || op == XOR || op == RSHIFT ||
+ op == TRSHIFT || op == LSHIFT;
}
return false;
};
// x >> 0 => x | 0
traversePost(ast, [](Ref node) {
- if (node->isArray() && !node->empty() && node[0] == BINARY && node[1] == RSHIFT && node[3]->isNumber()) {
+ if (node->isArray() && !node->empty() && node[0] == BINARY &&
+ node[1] == RSHIFT && node[3]->isNumber()) {
if (node[3]->getNumber() == 0) {
node[1]->setString(OR);
}
@@ -190,60 +195,69 @@ static void optimizeJS(Ref ast) {
// XXX IString invalid("__wasm2js$INVALID_LABEL__");
std::vector<Ref> breakCapturers;
std::vector<Ref> continueCapturers;
- std::unordered_map<IString, Ref> labelToValue; // maps the label to the loop/etc.
+ std::unordered_map<IString, Ref>
+ labelToValue; // maps the label to the loop/etc.
std::unordered_set<Value*> labelled; // all things with a label on them.
Value INVALID;
- traversePrePost(ast, [&](Ref node) {
- if (node->isArray() && !node->empty()) {
- if (node[0] == LABEL) {
- auto label = node[1]->getIString();
- labelToValue[label] = node[2];
- labelled.insert(node[2].get());
- } else if (node[0] == WHILE || node[0] == DO || node[0] == FOR) {
- breakCapturers.push_back(node);
- continueCapturers.push_back(node);
- } else if (node[0] == cashew::BLOCK) {
- if (labelled.count(node.get())) {
- // Cannot break to a block without the label.
- breakCapturers.push_back(Ref(&INVALID));
+ traversePrePost(
+ ast,
+ [&](Ref node) {
+ if (node->isArray() && !node->empty()) {
+ if (node[0] == LABEL) {
+ auto label = node[1]->getIString();
+ labelToValue[label] = node[2];
+ labelled.insert(node[2].get());
+ } else if (node[0] == WHILE || node[0] == DO || node[0] == FOR) {
+ breakCapturers.push_back(node);
+ continueCapturers.push_back(node);
+ } else if (node[0] == cashew::BLOCK) {
+ if (labelled.count(node.get())) {
+ // Cannot break to a block without the label.
+ breakCapturers.push_back(Ref(&INVALID));
+ }
+ } else if (node[0] == SWITCH) {
+ breakCapturers.push_back(node);
}
- } else if (node[0] == SWITCH) {
- breakCapturers.push_back(node);
}
- }
- }, [&](Ref node) {
- if (node->isArray() && !node->empty()) {
- if (node[0] == LABEL) {
- auto label = node[1]->getIString();
- labelToValue.erase(label);
- labelled.erase(node[2].get());
- } else if (node[0] == WHILE || node[0] == DO || node[0] == FOR) {
- breakCapturers.pop_back();
- continueCapturers.pop_back();
- } else if (node[0] == cashew::BLOCK) {
- if (labelled.count(node.get())) {
- breakCapturers.pop_back();
- }
- } else if (node[0] == SWITCH) {
- breakCapturers.pop_back();
- } else if (node[0] == BREAK || node[0] == CONTINUE) {
- if (!node[1]->isNull()) {
+ },
+ [&](Ref node) {
+ if (node->isArray() && !node->empty()) {
+ if (node[0] == LABEL) {
auto label = node[1]->getIString();
- assert(labelToValue.count(label));
- auto& capturers = node[0] == BREAK ? breakCapturers : continueCapturers;
- assert(!capturers.empty());
- if (capturers.back() == labelToValue[label]) {
- // Success, the break/continue goes exactly where we would if we
- // didn't have the label!
- node[1]->setNull();
+ labelToValue.erase(label);
+ labelled.erase(node[2].get());
+ } else if (node[0] == WHILE || node[0] == DO || node[0] == FOR) {
+ breakCapturers.pop_back();
+ continueCapturers.pop_back();
+ } else if (node[0] == cashew::BLOCK) {
+ if (labelled.count(node.get())) {
+ breakCapturers.pop_back();
+ }
+ } else if (node[0] == SWITCH) {
+ breakCapturers.pop_back();
+ } else if (node[0] == BREAK || node[0] == CONTINUE) {
+ if (!node[1]->isNull()) {
+ auto label = node[1]->getIString();
+ assert(labelToValue.count(label));
+ auto& capturers =
+ node[0] == BREAK ? breakCapturers : continueCapturers;
+ assert(!capturers.empty());
+ if (capturers.back() == labelToValue[label]) {
+ // Success, the break/continue goes exactly where we would if we
+ // didn't have the label!
+ node[1]->setNull();
+ }
}
}
}
- }
- });
+ });
}
-static void emitWasm(Module& wasm, Output& output, Wasm2JSBuilder::Flags flags, PassOptions options, Name name) {
+static void emitWasm(Module& wasm,
+ Output& output,
+ Wasm2JSBuilder::Flags flags,
+ PassOptions options,
+ Name name) {
if (options.optimizeLevel > 0) {
optimizeWasm(wasm, options);
}
@@ -264,7 +278,9 @@ public:
SExpressionWasmBuilder& sexpBuilder,
Output& out,
Wasm2JSBuilder::Flags flags,
- PassOptions options) : root(root), sexpBuilder(sexpBuilder), out(out), flags(flags), options(options) {}
+ PassOptions options)
+ : root(root), sexpBuilder(sexpBuilder), out(out), flags(flags),
+ options(options) {}
void emit();
@@ -310,11 +326,9 @@ Ref AssertionEmitter::emitAssertReturnFunc(Builder& wasmBuilder,
Expression* actual = sexpBuilder.parseExpression(e[1]);
Expression* body = nullptr;
if (e.size() == 2) {
- if (actual->type == none) {
- body = wasmBuilder.blockify(
- actual,
- wasmBuilder.makeConst(Literal(uint32_t(1)))
- );
+ if (actual->type == none) {
+ body = wasmBuilder.blockify(actual,
+ wasmBuilder.makeConst(Literal(uint32_t(1))));
} else {
body = actual;
}
@@ -330,9 +344,10 @@ Ref AssertionEmitter::emitAssertReturnFunc(Builder& wasmBuilder,
case i64:
body = wasmBuilder.makeCall(
"i64Equal",
- {actual, wasmBuilder.makeCall(WASM_FETCH_HIGH_BITS, {}, i32), expected},
- i32
- );
+ {actual,
+ wasmBuilder.makeCall(WASM_FETCH_HIGH_BITS, {}, i32),
+ expected},
+ i32);
break;
case f32: {
@@ -353,14 +368,11 @@ Ref AssertionEmitter::emitAssertReturnFunc(Builder& wasmBuilder,
assert(false && "Unexpected number of parameters in assert_return");
}
std::unique_ptr<Function> testFunc(
- wasmBuilder.makeFunction(
- testFuncName,
- std::vector<NameType>{},
- body->type,
- std::vector<NameType>{},
- body
- )
- );
+ wasmBuilder.makeFunction(testFuncName,
+ std::vector<NameType>{},
+ body->type,
+ std::vector<NameType>{},
+ body));
Ref jsFunc = processFunction(testFunc.get());
fixCalls(jsFunc, asmModule);
emitFunction(jsFunc);
@@ -374,14 +386,11 @@ Ref AssertionEmitter::emitAssertReturnNanFunc(Builder& wasmBuilder,
Expression* actual = sexpBuilder.parseExpression(e[1]);
Expression* body = wasmBuilder.makeCall("isNaN", {actual}, i32);
std::unique_ptr<Function> testFunc(
- wasmBuilder.makeFunction(
- testFuncName,
- std::vector<NameType>{},
- body->type,
- std::vector<NameType>{},
- body
- )
- );
+ wasmBuilder.makeFunction(testFuncName,
+ std::vector<NameType>{},
+ body->type,
+ std::vector<NameType>{},
+ body));
Ref jsFunc = processFunction(testFunc.get());
fixCalls(jsFunc, asmModule);
emitFunction(jsFunc);
@@ -399,8 +408,7 @@ Ref AssertionEmitter::emitAssertTrapFunc(Builder& wasmBuilder,
std::vector<NameType>{},
expr->type,
std::vector<NameType>{},
- expr)
- );
+ expr));
IString expectedErr = e[2]->str();
Ref innerFunc = processFunction(exprFunc.get());
fixCalls(innerFunc, asmModule);
@@ -411,33 +419,25 @@ Ref AssertionEmitter::emitAssertTrapFunc(Builder& wasmBuilder,
Ref catchBlock = ValueBuilder::makeBlock();
ValueBuilder::appendToBlock(
catchBlock,
- ValueBuilder::makeReturn(
- ValueBuilder::makeCall(
- ValueBuilder::makeDot(
- ValueBuilder::makeName(IString("e")),
- ValueBuilder::makeName(IString("message")),
- ValueBuilder::makeName(IString("includes"))
- ),
- ValueBuilder::makeString(expectedErr)
- )
- )
- );
+ ValueBuilder::makeReturn(ValueBuilder::makeCall(
+ ValueBuilder::makeDot(ValueBuilder::makeName(IString("e")),
+ ValueBuilder::makeName(IString("message")),
+ ValueBuilder::makeName(IString("includes"))),
+ ValueBuilder::makeString(expectedErr))));
outerFunc[3]->push_back(ValueBuilder::makeTry(
- tryBlock,
- ValueBuilder::makeName((IString("e"))),
- catchBlock));
+ tryBlock, ValueBuilder::makeName((IString("e"))), catchBlock));
outerFunc[3]->push_back(ValueBuilder::makeReturn(ValueBuilder::makeInt(0)));
emitFunction(outerFunc);
return outerFunc;
}
bool AssertionEmitter::isAssertHandled(Element& e) {
- return e.isList() && e.size() >= 2 && e[0]->isStr()
- && (e[0]->str() == Name("assert_return") ||
+ return e.isList() && e.size() >= 2 && e[0]->isStr() &&
+ (e[0]->str() == Name("assert_return") ||
e[0]->str() == Name("assert_return_nan") ||
- (flags.pedantic && e[0]->str() == Name("assert_trap")))
- && e[1]->isList() && e[1]->size() >= 2 && (*e[1])[0]->isStr()
- && (*e[1])[0]->str() == Name("invoke");
+ (flags.pedantic && e[0]->str() == Name("assert_trap"))) &&
+ e[1]->isList() && e[1]->size() >= 2 && (*e[1])[0]->isStr() &&
+ (*e[1])[0]->str() == Name("invoke");
}
void AssertionEmitter::fixCalls(Ref asmjs, Name asmModule) {
@@ -446,7 +446,8 @@ void AssertionEmitter::fixCalls(Ref asmjs, Name asmModule) {
for (Ref& r : arr) {
fixCalls(r, asmModule);
}
- if (arr.size() > 0 && arr[0]->isString() && arr[0]->getIString() == cashew::CALL) {
+ if (arr.size() > 0 && arr[0]->isString() &&
+ arr[0]->getIString() == cashew::CALL) {
assert(arr.size() >= 2);
if (arr[1]->getIString() == "f32Equal" ||
arr[1]->getIString() == "f64Equal" ||
@@ -457,7 +458,7 @@ void AssertionEmitter::fixCalls(Ref asmjs, Name asmModule) {
arr[1]->setString("Math.fround");
} else {
Ref fixed = ValueBuilder::makeDot(ValueBuilder::makeName(asmModule),
- arr[1]->getIString());
+ arr[1]->getIString());
arr[1]->setArray(fixed->getArray());
}
}
@@ -522,7 +523,8 @@ void AssertionEmitter::emit() {
Name asmModule = std::string("ret") + ASM_FUNC.str;
for (size_t i = 0; i < root.size(); ++i) {
Element& e = *root[i];
- if (e.isList() && e.size() >= 1 && e[0]->isStr() && e[0]->str() == Name("module")) {
+ if (e.isList() && e.size() >= 1 && e[0]->isStr() &&
+ e[0]->str() == Name("module")) {
std::stringstream funcNameS;
funcNameS << ASM_FUNC.c_str() << i;
std::stringstream moduleNameS;
@@ -555,10 +557,7 @@ void AssertionEmitter::emit() {
emitAssertTrapFunc(wasmBuilder, e, testFuncName, asmModule);
}
- out << "if (!"
- << testFuncName.str
- << "()) throw 'assertion failed: "
- << e
+ out << "if (!" << testFuncName.str << "()) throw 'assertion failed: " << e
<< "';\n";
}
}
@@ -567,38 +566,48 @@ void AssertionEmitter::emit() {
// Main
-int main(int argc, const char *argv[]) {
+int main(int argc, const char* argv[]) {
Wasm2JSBuilder::Flags flags;
- OptimizationOptions options("wasm2js", "Transform .wasm/.wast files to asm.js");
+ OptimizationOptions options("wasm2js",
+ "Transform .wasm/.wast files to asm.js");
options
- .add("--output", "-o", "Output file (stdout if not specified)",
- Options::Arguments::One,
- [](Options* o, const std::string& argument) {
- o->extra["output"] = argument;
- Colors::disable();
- })
- .add("--allow-asserts", "", "Allow compilation of .wast testing asserts",
- Options::Arguments::Zero,
- [&](Options* o, const std::string& argument) {
- flags.allowAsserts = true;
- o->extra["asserts"] = "1";
- })
- .add("--pedantic", "", "Emulate WebAssembly trapping behavior",
- Options::Arguments::Zero,
- [&](Options* o, const std::string& argument) {
- flags.pedantic = true;
- })
- .add("--emscripten", "", "Emulate the glue in emscripten-compatible form (and not ES6 module form)",
- Options::Arguments::Zero,
- [&](Options* o, const std::string& argument) {
- flags.emscripten = true;
- })
- .add_positional("INFILE", Options::Arguments::One,
- [](Options *o, const std::string& argument) {
- o->extra["infile"] = argument;
- });
+ .add("--output",
+ "-o",
+ "Output file (stdout if not specified)",
+ Options::Arguments::One,
+ [](Options* o, const std::string& argument) {
+ o->extra["output"] = argument;
+ Colors::disable();
+ })
+ .add("--allow-asserts",
+ "",
+ "Allow compilation of .wast testing asserts",
+ Options::Arguments::Zero,
+ [&](Options* o, const std::string& argument) {
+ flags.allowAsserts = true;
+ o->extra["asserts"] = "1";
+ })
+ .add(
+ "--pedantic",
+ "",
+ "Emulate WebAssembly trapping behavior",
+ Options::Arguments::Zero,
+ [&](Options* o, const std::string& argument) { flags.pedantic = true; })
+ .add(
+ "--emscripten",
+ "",
+ "Emulate the glue in emscripten-compatible form (and not ES6 module "
+ "form)",
+ Options::Arguments::Zero,
+ [&](Options* o, const std::string& argument) { flags.emscripten = true; })
+ .add_positional("INFILE",
+ Options::Arguments::One,
+ [](Options* o, const std::string& argument) {
+ o->extra["infile"] = argument;
+ });
options.parse(argc, argv);
- if (options.debug) flags.debug = true;
+ if (options.debug)
+ flags.debug = true;
Element* root = nullptr;
Module wasm;
@@ -606,11 +615,11 @@ int main(int argc, const char *argv[]) {
std::unique_ptr<SExpressionParser> sexprParser;
std::unique_ptr<SExpressionWasmBuilder> sexprBuilder;
- auto &input = options.extra["infile"];
+ auto& input = options.extra["infile"];
std::string suffix(".wasm");
bool binaryInput =
- input.size() >= suffix.size() &&
- input.compare(input.size() - suffix.size(), suffix.size(), suffix) == 0;
+ input.size() >= suffix.size() &&
+ input.compare(input.size() - suffix.size(), suffix.size(), suffix) == 0;
try {
// If the input filename ends in `.wasm`, then parse it in binary form,
@@ -627,20 +636,25 @@ int main(int argc, const char *argv[]) {
reader.read(input, wasm, "");
options.applyFeatures(wasm);
} else {
- auto input(
- read_file<std::vector<char>>(options.extra["infile"], Flags::Text, options.debug ? Flags::Debug : Flags::Release));
- if (options.debug) std::cerr << "s-parsing..." << std::endl;
+ auto input(read_file<std::vector<char>>(options.extra["infile"],
+ Flags::Text,
+ options.debug ? Flags::Debug
+ : Flags::Release));
+ if (options.debug)
+ std::cerr << "s-parsing..." << std::endl;
sexprParser = make_unique<SExpressionParser>(input.data());
root = sexprParser->root;
- if (options.debug) std::cerr << "w-parsing..." << std::endl;
+ if (options.debug)
+ std::cerr << "w-parsing..." << std::endl;
sexprBuilder = make_unique<SExpressionWasmBuilder>(wasm, *(*root)[0]);
}
} catch (ParseException& p) {
p.dump(std::cerr);
Fatal() << "error in parsing input";
} catch (std::bad_alloc&) {
- Fatal() << "error in building module, std::bad_alloc (possibly invalid request for silly amounts of memory)";
+ Fatal() << "error in building module, std::bad_alloc (possibly invalid "
+ "request for silly amounts of memory)";
}
if (options.passOptions.validate) {
@@ -650,13 +664,18 @@ int main(int argc, const char *argv[]) {
}
}
- if (options.debug) std::cerr << "j-printing..." << std::endl;
- Output output(options.extra["output"], Flags::Text, options.debug ? Flags::Debug : Flags::Release);
+ if (options.debug)
+ std::cerr << "j-printing..." << std::endl;
+ Output output(options.extra["output"],
+ Flags::Text,
+ options.debug ? Flags::Debug : Flags::Release);
if (!binaryInput && options.extra["asserts"] == "1") {
- AssertionEmitter(*root, *sexprBuilder, output, flags, options.passOptions).emit();
+ AssertionEmitter(*root, *sexprBuilder, output, flags, options.passOptions)
+ .emit();
} else {
emitWasm(wasm, output, flags, options.passOptions, "asmFunc");
}
- if (options.debug) std::cerr << "done." << std::endl;
+ if (options.debug)
+ std::cerr << "done." << std::endl;
}
diff --git a/src/wasm-binary.h b/src/wasm-binary.h
index 1f6222cba..aa13685e1 100644
--- a/src/wasm-binary.h
+++ b/src/wasm-binary.h
@@ -25,14 +25,14 @@
#include <ostream>
#include <type_traits>
-#include "wasm.h"
-#include "wasm-traversal.h"
-#include "asmjs/shared-constants.h"
#include "asm_v_wasm.h"
+#include "asmjs/shared-constants.h"
+#include "ir/import-utils.h"
#include "parsing.h"
#include "wasm-builder.h"
+#include "wasm-traversal.h"
#include "wasm-validator.h"
-#include "ir/import-utils.h"
+#include "wasm.h"
namespace wasm {
@@ -49,8 +49,7 @@ enum WebLimitations {
MaxFunctionLocals = 50 * 1000
};
-template<typename T, typename MiniT>
-struct LEB {
+template<typename T, typename MiniT> struct LEB {
static_assert(sizeof(MiniT) == 1, "MiniT must be a byte");
T value;
@@ -59,8 +58,12 @@ struct LEB {
LEB(T value) : value(value) {}
bool hasMore(T temp, MiniT byte) {
- // for signed, we must ensure the last bit has the right sign, as it will zero extend
- return std::is_signed<T>::value ? (temp != 0 && temp != T(-1)) || (value >= 0 && (byte & 64)) || (value < 0 && !(byte & 64)) : (temp != 0);
+ // for signed, we must ensure the last bit has the right sign, as it will
+ // zero extend
+ return std::is_signed<T>::value
+ ? (temp != 0 && temp != T(-1)) || (value >= 0 && (byte & 64)) ||
+ (value < 0 && !(byte & 64))
+ : (temp != 0);
}
void write(std::vector<uint8_t>* out) {
@@ -106,8 +109,8 @@ struct LEB {
T payload = byte & 127;
typedef typename std::make_unsigned<T>::type mask_type;
auto shift_mask = 0 == shift
- ? ~mask_type(0)
- : ((mask_type(1) << (sizeof(T) * 8 - shift)) - 1u);
+ ? ~mask_type(0)
+ : ((mask_type(1) << (sizeof(T) * 8 - shift)) - 1u);
T significant_payload = payload & shift_mask;
if (significant_payload != payload) {
if (!(std::is_signed<T>::value && last)) {
@@ -115,7 +118,8 @@ struct LEB {
}
}
value |= significant_payload << shift;
- if (last) break;
+ if (last)
+ break;
shift += 7;
if (size_t(shift) >= sizeof(T) * 8) {
throw ParseException("LEB overflow");
@@ -130,7 +134,8 @@ struct LEB {
value <<= sext_bits;
value >>= sext_bits;
if (value >= 0) {
- throw ParseException(" LEBsign-extend should produce a negative value");
+ throw ParseException(
+ " LEBsign-extend should produce a negative value");
}
}
}
@@ -155,33 +160,48 @@ public:
BufferWithRandomAccess(bool debug = false) : debug(debug) {}
BufferWithRandomAccess& operator<<(int8_t x) {
- if (debug) std::cerr << "writeInt8: " << (int)(uint8_t)x << " (at " << size() << ")" << std::endl;
+ if (debug)
+ std::cerr << "writeInt8: " << (int)(uint8_t)x << " (at " << size() << ")"
+ << std::endl;
push_back(x);
return *this;
}
BufferWithRandomAccess& operator<<(int16_t x) {
- if (debug) std::cerr << "writeInt16: " << x << " (at " << size() << ")" << std::endl;
+ if (debug)
+ std::cerr << "writeInt16: " << x << " (at " << size() << ")" << std::endl;
push_back(x & 0xff);
push_back(x >> 8);
return *this;
}
BufferWithRandomAccess& operator<<(int32_t x) {
- if (debug) std::cerr << "writeInt32: " << x << " (at " << size() << ")" << std::endl;
- push_back(x & 0xff); x >>= 8;
- push_back(x & 0xff); x >>= 8;
- push_back(x & 0xff); x >>= 8;
+ if (debug)
+ std::cerr << "writeInt32: " << x << " (at " << size() << ")" << std::endl;
+ push_back(x & 0xff);
+ x >>= 8;
+ push_back(x & 0xff);
+ x >>= 8;
+ push_back(x & 0xff);
+ x >>= 8;
push_back(x & 0xff);
return *this;
}
BufferWithRandomAccess& operator<<(int64_t x) {
- if (debug) std::cerr << "writeInt64: " << x << " (at " << size() << ")" << std::endl;
- push_back(x & 0xff); x >>= 8;
- push_back(x & 0xff); x >>= 8;
- push_back(x & 0xff); x >>= 8;
- push_back(x & 0xff); x >>= 8;
- push_back(x & 0xff); x >>= 8;
- push_back(x & 0xff); x >>= 8;
- push_back(x & 0xff); x >>= 8;
+ if (debug)
+ std::cerr << "writeInt64: " << x << " (at " << size() << ")" << std::endl;
+ push_back(x & 0xff);
+ x >>= 8;
+ push_back(x & 0xff);
+ x >>= 8;
+ push_back(x & 0xff);
+ x >>= 8;
+ push_back(x & 0xff);
+ x >>= 8;
+ push_back(x & 0xff);
+ x >>= 8;
+ push_back(x & 0xff);
+ x >>= 8;
+ push_back(x & 0xff);
+ x >>= 8;
push_back(x & 0xff);
return *this;
}
@@ -189,7 +209,8 @@ public:
size_t before = -1;
if (debug) {
before = size();
- std::cerr << "writeU32LEB: " << x.value << " (at " << before << ")" << std::endl;
+ std::cerr << "writeU32LEB: " << x.value << " (at " << before << ")"
+ << std::endl;
}
x.write(this);
if (debug) {
@@ -203,7 +224,8 @@ public:
size_t before = -1;
if (debug) {
before = size();
- std::cerr << "writeU64LEB: " << x.value << " (at " << before << ")" << std::endl;
+ std::cerr << "writeU64LEB: " << x.value << " (at " << before << ")"
+ << std::endl;
}
x.write(this);
if (debug) {
@@ -217,7 +239,8 @@ public:
size_t before = -1;
if (debug) {
before = size();
- std::cerr << "writeS32LEB: " << x.value << " (at " << before << ")" << std::endl;
+ std::cerr << "writeS32LEB: " << x.value << " (at " << before << ")"
+ << std::endl;
}
x.write(this);
if (debug) {
@@ -231,7 +254,8 @@ public:
size_t before = -1;
if (debug) {
before = size();
- std::cerr << "writeS64LEB: " << x.value << " (at " << before << ")" << std::endl;
+ std::cerr << "writeS64LEB: " << x.value << " (at " << before << ")"
+ << std::endl;
}
x.write(this);
if (debug) {
@@ -242,57 +266,63 @@ public:
return *this;
}
- BufferWithRandomAccess& operator<<(uint8_t x) {
- return *this << (int8_t)x;
- }
- BufferWithRandomAccess& operator<<(uint16_t x) {
- return *this << (int16_t)x;
- }
- BufferWithRandomAccess& operator<<(uint32_t x) {
- return *this << (int32_t)x;
- }
- BufferWithRandomAccess& operator<<(uint64_t x) {
- return *this << (int64_t)x;
- }
+ BufferWithRandomAccess& operator<<(uint8_t x) { return *this << (int8_t)x; }
+ BufferWithRandomAccess& operator<<(uint16_t x) { return *this << (int16_t)x; }
+ BufferWithRandomAccess& operator<<(uint32_t x) { return *this << (int32_t)x; }
+ BufferWithRandomAccess& operator<<(uint64_t x) { return *this << (int64_t)x; }
BufferWithRandomAccess& operator<<(float x) {
- if (debug) std::cerr << "writeFloat32: " << x << " (at " << size() << ")" << std::endl;
+ if (debug)
+ std::cerr << "writeFloat32: " << x << " (at " << size() << ")"
+ << std::endl;
return *this << Literal(x).reinterpreti32();
}
BufferWithRandomAccess& operator<<(double x) {
- if (debug) std::cerr << "writeFloat64: " << x << " (at " << size() << ")" << std::endl;
+ if (debug)
+ std::cerr << "writeFloat64: " << x << " (at " << size() << ")"
+ << std::endl;
return *this << Literal(x).reinterpreti64();
}
void writeAt(size_t i, uint16_t x) {
- if (debug) std::cerr << "backpatchInt16: " << x << " (at " << i << ")" << std::endl;
+ if (debug)
+ std::cerr << "backpatchInt16: " << x << " (at " << i << ")" << std::endl;
(*this)[i] = x & 0xff;
- (*this)[i+1] = x >> 8;
+ (*this)[i + 1] = x >> 8;
}
void writeAt(size_t i, uint32_t x) {
- if (debug) std::cerr << "backpatchInt32: " << x << " (at " << i << ")" << std::endl;
- (*this)[i] = x & 0xff; x >>= 8;
- (*this)[i+1] = x & 0xff; x >>= 8;
- (*this)[i+2] = x & 0xff; x >>= 8;
- (*this)[i+3] = x & 0xff;
+ if (debug)
+ std::cerr << "backpatchInt32: " << x << " (at " << i << ")" << std::endl;
+ (*this)[i] = x & 0xff;
+ x >>= 8;
+ (*this)[i + 1] = x & 0xff;
+ x >>= 8;
+ (*this)[i + 2] = x & 0xff;
+ x >>= 8;
+ (*this)[i + 3] = x & 0xff;
}
// writes out an LEB to an arbitrary location. this writes the LEB as a full
// 5 bytes, the fixed amount that can easily be set aside ahead of time
void writeAtFullFixedSize(size_t i, U32LEB x) {
- if (debug) std::cerr << "backpatchU32LEB: " << x.value << " (at " << i << ")" << std::endl;
- x.writeAt(this, i, MaxLEB32Bytes); // fill all 5 bytes, we have to do this when backpatching
+ if (debug)
+ std::cerr << "backpatchU32LEB: " << x.value << " (at " << i << ")"
+ << std::endl;
+ // fill all 5 bytes, we have to do this when backpatching
+ x.writeAt(this, i, MaxLEB32Bytes);
}
// writes out an LEB of normal size
// returns how many bytes were written
size_t writeAt(size_t i, U32LEB x) {
- if (debug) std::cerr << "writeAtU32LEB: " << x.value << " (at " << i << ")" << std::endl;
+ if (debug)
+ std::cerr << "writeAtU32LEB: " << x.value << " (at " << i << ")"
+ << std::endl;
return x.writeAt(this, i);
}
- template<typename T>
- void writeTo(T& o) {
- for (auto c : *this) o << c;
+ template<typename T> void writeTo(T& o) {
+ for (auto c : *this)
+ o << c;
}
std::vector<char> getAsChars() {
@@ -305,10 +335,7 @@ public:
namespace BinaryConsts {
-enum Meta {
- Magic = 0x6d736100,
- Version = 0x01
-};
+enum Meta { Magic = 0x6d736100, Version = 0x01 };
enum Section {
User = 0,
@@ -333,10 +360,10 @@ enum SegmentFlag {
enum EncodedType {
// value_type
- i32 = -0x1, // 0x7f
- i64 = -0x2, // 0x7e
- f32 = -0x3, // 0x7d
- f64 = -0x4, // 0x7c
+ i32 = -0x1, // 0x7f
+ i64 = -0x2, // 0x7e
+ f32 = -0x3, // 0x7d
+ f64 = -0x4, // 0x7c
v128 = -0x5, // 0x7b
// elem_type
AnyFunc = -0x10, // 0x70
@@ -394,7 +421,6 @@ enum ASTNodes {
GetGlobal = 0x23,
SetGlobal = 0x24,
-
I32LoadMem = 0x28,
I64LoadMem = 0x29,
F32LoadMem = 0x2a,
@@ -809,15 +835,12 @@ enum BulkMemoryOpcodes {
};
enum MemoryAccess {
- Offset = 0x10, // bit 4
- Alignment = 0x80, // bit 7
+ Offset = 0x10, // bit 4
+ Alignment = 0x80, // bit 7
NaturalAlignment = 0
};
-enum MemoryFlags {
- HasMaximum = 1 << 0,
- IsShared = 1 << 1
-};
+enum MemoryFlags { HasMaximum = 1 << 0, IsShared = 1 << 1 };
enum FeaturePrefix {
FeatureUsed = '+',
@@ -827,18 +850,30 @@ enum FeaturePrefix {
} // namespace BinaryConsts
-
inline S32LEB binaryType(Type type) {
int ret = 0;
switch (type) {
// None only used for block signatures. TODO: Separate out?
- case none: ret = BinaryConsts::EncodedType::Empty; break;
- case i32: ret = BinaryConsts::EncodedType::i32; break;
- case i64: ret = BinaryConsts::EncodedType::i64; break;
- case f32: ret = BinaryConsts::EncodedType::f32; break;
- case f64: ret = BinaryConsts::EncodedType::f64; break;
- case v128: ret = BinaryConsts::EncodedType::v128; break;
- case unreachable: WASM_UNREACHABLE();
+ case none:
+ ret = BinaryConsts::EncodedType::Empty;
+ break;
+ case i32:
+ ret = BinaryConsts::EncodedType::i32;
+ break;
+ case i64:
+ ret = BinaryConsts::EncodedType::i64;
+ break;
+ case f32:
+ ret = BinaryConsts::EncodedType::f32;
+ break;
+ case f64:
+ ret = BinaryConsts::EncodedType::f64;
+ break;
+ case v128:
+ ret = BinaryConsts::EncodedType::v128;
+ break;
+ case unreachable:
+ WASM_UNREACHABLE();
}
return S32LEB(ret);
}
@@ -847,10 +882,8 @@ inline S32LEB binaryType(Type type) {
class WasmBinaryWriter {
public:
- WasmBinaryWriter(Module* input,
- BufferWithRandomAccess& o,
- bool debug = false) :
- wasm(input), o(o), debug(debug) {
+ WasmBinaryWriter(Module* input, BufferWithRandomAccess& o, bool debug = false)
+ : wasm(input), o(o), debug(debug) {
prepare();
}
@@ -859,8 +892,9 @@ public:
struct Entry {
Name name;
size_t offset; // where the entry starts
- size_t size; // the size of the entry
- Entry(Name name, size_t offset, size_t size) : name(name), offset(offset), size(size) {}
+ size_t size; // the size of the entry
+ Entry(Name name, size_t offset, size_t size)
+ : name(name), offset(offset), size(size) {}
};
std::vector<Entry> functionBodies;
} tableOfContents;
@@ -875,9 +909,11 @@ public:
void write();
void writeHeader();
int32_t writeU32LEBPlaceholder();
- void writeResizableLimits(Address initial, Address maximum, bool hasMaximum, bool shared);
- template<typename T>
- int32_t startSection(T code);
+ void writeResizableLimits(Address initial,
+ Address maximum,
+ bool hasMaximum,
+ bool shared);
+ template<typename T> int32_t startSection(T code);
void finishSection(int32_t start);
int32_t startSubsection(BinaryConsts::UserSections::Subsection code);
void finishSubsection(int32_t start);
@@ -895,8 +931,10 @@ public:
void writeDataCount();
void writeDataSegments();
- std::unordered_map<Name, Index> mappedFunctions; // name of the Function => index. first imports, then internals
- std::unordered_map<Name, uint32_t> mappedGlobals; // name of the Global => index. first imported globals, then internal globals
+ // name of the Function => index. first imports, then internals
+ std::unordered_map<Name, Index> mappedFunctions;
+ // name of the Global => index. first imported globals, then internal globals
+ std::unordered_map<Name, uint32_t> mappedGlobals;
uint32_t getFunctionIndex(Name name);
uint32_t getGlobalIndex(Name name);
@@ -925,13 +963,14 @@ public:
const char* data;
size_t size;
size_t pointerLocation;
- Buffer(const char* data, size_t size, size_t pointerLocation) : data(data), size(size), pointerLocation(pointerLocation) {}
+ Buffer(const char* data, size_t size, size_t pointerLocation)
+ : data(data), size(size), pointerLocation(pointerLocation) {}
};
std::vector<Buffer> buffersToWrite;
void emitBuffer(const char* data, size_t size);
- void emitString(const char *str);
+ void emitString(const char* str);
void finishUp();
Module* getModule() { return wasm; }
@@ -948,9 +987,10 @@ private:
MixedArena allocator;
- // storage of source map locations until the section is placed at its final location
- // (shrinking LEBs may cause changes there)
- std::vector<std::pair<size_t, const Function::DebugLocation*>> sourceMapLocations;
+ // storage of source map locations until the section is placed at its final
+ // location (shrinking LEBs may cause changes there)
+ std::vector<std::pair<size_t, const Function::DebugLocation*>>
+ sourceMapLocations;
size_t sourceMapLocationsSizeAtSectionStart;
Function::DebugLocation lastDebugLocation;
@@ -975,13 +1015,8 @@ class WasmBinaryBuilder {
public:
WasmBinaryBuilder(Module& wasm, const std::vector<char>& input, bool debug)
- : wasm(wasm),
- allocator(wasm.allocator),
- input(input),
- debug(debug),
- sourceMap(nullptr),
- nextDebugLocation(0, { 0, 0, 0 }),
- debugLocation() {}
+ : wasm(wasm), allocator(wasm.allocator), input(input), debug(debug),
+ sourceMap(nullptr), nextDebugLocation(0, {0, 0, 0}), debugLocation() {}
void read();
void readUserSection(size_t payloadLen);
@@ -993,7 +1028,8 @@ public:
uint32_t getInt32();
uint64_t getInt64();
uint8_t getLaneIndex(size_t lanes);
- // it is unsafe to return a float directly, due to ABI issues with the signalling bit
+ // it is unsafe to return a float directly, due to ABI issues with the
+ // signalling bit
Literal getFloat32Literal();
Literal getFloat64Literal();
Literal getVec128Literal();
@@ -1016,7 +1052,10 @@ public:
// gets a name in the combined function import+defined function space
Name getFunctionIndexName(Index i);
- void getResizableLimits(Address& initial, Address& max, bool& shared, Address defaultIfNoMax);
+ void getResizableLimits(Address& initial,
+ Address& max,
+ bool& shared,
+ Address defaultIfNoMax);
void readImports();
std::vector<FunctionType*> functionTypes; // types of defined functions
@@ -1026,12 +1065,20 @@ public:
Name getNextLabel();
- // We read functions before we know their names, so we need to backpatch the names later
- std::vector<Function*> functions; // we store functions here before wasm.addFunction after we know their names
- std::vector<Function*> functionImports; // we store function imports here before wasm.addFunctionImport after we know their names
- std::map<Index, std::vector<Call*>> functionCalls; // at index i we have all calls to the function i
+ // We read functions before we know their names, so we need to backpatch the
+ // names later
+
+ // we store functions here before wasm.addFunction after we know their names
+ std::vector<Function*> functions;
+ // we store function imports here before wasm.addFunctionImport after we know
+ // their names
+ std::vector<Function*> functionImports;
+ // at index i we have all calls to the function i
+ std::map<Index, std::vector<Call*>> functionCalls;
Function* currFunction = nullptr;
- Index endOfFunction = -1; // before we see a function (like global init expressions), there is no end of function to check
+ // before we see a function (like global init expressions), there is no end of
+ // function to check
+ Index endOfFunction = -1;
// Throws a parsing error if we are not in a function context
void requireFunctionContext(const char* error);
@@ -1051,22 +1098,24 @@ public:
BreakTarget(Name name, int arity) : name(name), arity(arity) {}
};
std::vector<BreakTarget> breakStack;
- // the names that breaks target. this lets us know if a block has breaks to it or not.
+ // the names that breaks target. this lets us know if a block has breaks to it
+ // or not.
std::unordered_set<Name> breakTargetNames;
std::vector<Expression*> expressionStack;
- // set when we know code is unreachable in the sense of the wasm spec: we are in a block
- // and after an unreachable element.
- // this helps parse stacky wasm code, which can be unsuitable for our IR when unreachable.
+ // set when we know code is unreachable in the sense of the wasm spec: we are
+ // in a block and after an unreachable element. this helps parse stacky wasm
+ // code, which can be unsuitable for our IR when unreachable.
bool unreachableInTheWasmSense;
- // set when the current code being processed will not be emitted in the output, which is the
- // case when it is literally unreachable, for example,
+ // set when the current code being processed will not be emitted in the
+ // output, which is the case when it is literally unreachable, for example,
// (block $a
// (unreachable)
// (block $b
- // ;; code here is reachable in the wasm sense, even though $b as a whole is not
+ // ;; code here is reachable in the wasm sense, even though $b as a whole
+ // ;; is not
// (unreachable)
// ;; code here is unreachable in the wasm sense
// )
@@ -1075,14 +1124,16 @@ public:
BinaryConsts::ASTNodes lastSeparator = BinaryConsts::End;
- // process a block-type scope, until an end or else marker, or the end of the function
+ // process a block-type scope, until an end or else marker, or the end of the
+ // function
void processExpressions();
void skipUnreachableCode();
Expression* popExpression();
Expression* popNonVoidExpression();
- std::map<Index, Name> mappedGlobals; // index of the Global => name. first imported globals, then internal globals
+ // index of the Global => name. first imported globals, then internal globals
+ std::map<Index, Name> mappedGlobals;
Name getGlobalName(Index index);
void validateBinary(); // validations that cannot be performed on the Module
@@ -1102,9 +1153,7 @@ public:
void readFeatures(size_t);
// Debug information reading helpers
- void setDebugLocations(std::istream* sourceMap_) {
- sourceMap = sourceMap_;
- }
+ void setDebugLocations(std::istream* sourceMap_) { sourceMap = sourceMap_; }
std::unordered_map<std::string, Index> debugInfoFileIndices;
void readNextDebugLocation();
void readSourceMapHeader();
@@ -1122,13 +1171,13 @@ public:
void visitIf(If* curr);
void visitLoop(Loop* curr);
BreakTarget getBreakTarget(int32_t offset);
- void visitBreak(Break *curr, uint8_t code);
+ void visitBreak(Break* curr, uint8_t code);
void visitSwitch(Switch* curr);
void visitCall(Call* curr);
void visitCallIndirect(CallIndirect* curr);
void visitGetLocal(GetLocal* curr);
- void visitSetLocal(SetLocal *curr, uint8_t code);
+ void visitSetLocal(SetLocal* curr, uint8_t code);
void visitGetGlobal(GetGlobal* curr);
void visitSetGlobal(SetGlobal* curr);
void readMemoryAccess(Address& alignment, Address& offset);
diff --git a/src/wasm-builder.h b/src/wasm-builder.h
index 0bbc8eebc..8e7cc9908 100644
--- a/src/wasm-builder.h
+++ b/src/wasm-builder.h
@@ -17,8 +17,8 @@
#ifndef wasm_wasm_builder_h
#define wasm_wasm_builder_h
-#include "wasm.h"
#include "ir/manipulation.h"
+#include "wasm.h"
namespace wasm {
@@ -90,9 +90,7 @@ public:
// IR nodes
- Nop* makeNop() {
- return allocator.alloc<Nop>();
- }
+ Nop* makeNop() { return allocator.alloc<Nop>(); }
Block* makeBlock(Expression* first = nullptr) {
auto* ret = allocator.alloc<Block>();
if (first) {
@@ -139,53 +137,75 @@ public:
ret->finalize(type);
return ret;
}
- If* makeIf(Expression* condition, Expression* ifTrue, Expression* ifFalse = nullptr) {
+ If* makeIf(Expression* condition,
+ Expression* ifTrue,
+ Expression* ifFalse = nullptr) {
auto* ret = allocator.alloc<If>();
- ret->condition = condition; ret->ifTrue = ifTrue; ret->ifFalse = ifFalse;
+ ret->condition = condition;
+ ret->ifTrue = ifTrue;
+ ret->ifFalse = ifFalse;
ret->finalize();
return ret;
}
- If* makeIf(Expression* condition, Expression* ifTrue, Expression* ifFalse, Type type) {
+ If* makeIf(Expression* condition,
+ Expression* ifTrue,
+ Expression* ifFalse,
+ Type type) {
auto* ret = allocator.alloc<If>();
- ret->condition = condition; ret->ifTrue = ifTrue; ret->ifFalse = ifFalse;
+ ret->condition = condition;
+ ret->ifTrue = ifTrue;
+ ret->ifFalse = ifFalse;
ret->finalize(type);
return ret;
}
Loop* makeLoop(Name name, Expression* body) {
auto* ret = allocator.alloc<Loop>();
- ret->name = name; ret->body = body;
+ ret->name = name;
+ ret->body = body;
ret->finalize();
return ret;
}
- Break* makeBreak(Name name, Expression* value = nullptr, Expression* condition = nullptr) {
+ Break* makeBreak(Name name,
+ Expression* value = nullptr,
+ Expression* condition = nullptr) {
auto* ret = allocator.alloc<Break>();
- ret->name = name; ret->value = value; ret->condition = condition;
+ ret->name = name;
+ ret->value = value;
+ ret->condition = condition;
ret->finalize();
return ret;
}
template<typename T>
- Switch* makeSwitch(T& list, Name default_, Expression* condition, Expression* value = nullptr) {
+ Switch* makeSwitch(T& list,
+ Name default_,
+ Expression* condition,
+ Expression* value = nullptr) {
auto* ret = allocator.alloc<Switch>();
ret->targets.set(list);
- ret->default_ = default_; ret->value = value; ret->condition = condition;
+ ret->default_ = default_;
+ ret->value = value;
+ ret->condition = condition;
return ret;
}
Call* makeCall(Name target, const std::vector<Expression*>& args, Type type) {
auto* call = allocator.alloc<Call>();
- call->type = type; // not all functions may exist yet, so type must be provided
+ // not all functions may exist yet, so type must be provided
+ call->type = type;
call->target = target;
call->operands.set(args);
return call;
}
- template<typename T>
- Call* makeCall(Name target, const T& args, Type type) {
+ template<typename T> Call* makeCall(Name target, const T& args, Type type) {
auto* call = allocator.alloc<Call>();
- call->type = type; // not all functions may exist yet, so type must be provided
+ // not all functions may exist yet, so type must be provided
+ call->type = type;
call->target = target;
call->operands.set(args);
return call;
}
- CallIndirect* makeCallIndirect(FunctionType* type, Expression* target, const std::vector<Expression*>& args) {
+ CallIndirect* makeCallIndirect(FunctionType* type,
+ Expression* target,
+ const std::vector<Expression*>& args) {
auto* call = allocator.alloc<CallIndirect>();
call->fullType = type->name;
call->type = type->result;
@@ -193,7 +213,10 @@ public:
call->operands.set(args);
return call;
}
- CallIndirect* makeCallIndirect(Name fullType, Expression* target, const std::vector<Expression*>& args, Type type) {
+ CallIndirect* makeCallIndirect(Name fullType,
+ Expression* target,
+ const std::vector<Expression*>& args,
+ Type type) {
auto* call = allocator.alloc<CallIndirect>();
call->fullType = fullType;
call->type = type;
@@ -235,19 +258,33 @@ public:
ret->finalize();
return ret;
}
- Load* makeLoad(unsigned bytes, bool signed_, uint32_t offset, unsigned align, Expression *ptr, Type type) {
+ Load* makeLoad(unsigned bytes,
+ bool signed_,
+ uint32_t offset,
+ unsigned align,
+ Expression* ptr,
+ Type type) {
auto* ret = allocator.alloc<Load>();
ret->isAtomic = false;
- ret->bytes = bytes; ret->signed_ = signed_; ret->offset = offset; ret->align = align; ret->ptr = ptr;
+ ret->bytes = bytes;
+ ret->signed_ = signed_;
+ ret->offset = offset;
+ ret->align = align;
+ ret->ptr = ptr;
ret->type = type;
return ret;
}
- Load* makeAtomicLoad(unsigned bytes, uint32_t offset, Expression* ptr, Type type) {
+ Load*
+ makeAtomicLoad(unsigned bytes, uint32_t offset, Expression* ptr, Type type) {
Load* load = makeLoad(bytes, false, offset, bytes, ptr, type);
load->isAtomic = true;
return load;
}
- AtomicWait* makeAtomicWait(Expression* ptr, Expression* expected, Expression* timeout, Type expectedType, Address offset) {
+ AtomicWait* makeAtomicWait(Expression* ptr,
+ Expression* expected,
+ Expression* timeout,
+ Type expectedType,
+ Address offset) {
auto* wait = allocator.alloc<AtomicWait>();
wait->offset = offset;
wait->ptr = ptr;
@@ -257,7 +294,8 @@ public:
wait->finalize();
return wait;
}
- AtomicNotify* makeAtomicNotify(Expression* ptr, Expression* notifyCount, Address offset) {
+ AtomicNotify*
+ makeAtomicNotify(Expression* ptr, Expression* notifyCount, Address offset) {
auto* notify = allocator.alloc<AtomicNotify>();
notify->offset = offset;
notify->ptr = ptr;
@@ -265,21 +303,39 @@ public:
notify->finalize();
return notify;
}
- Store* makeStore(unsigned bytes, uint32_t offset, unsigned align, Expression *ptr, Expression *value, Type type) {
+ Store* makeStore(unsigned bytes,
+ uint32_t offset,
+ unsigned align,
+ Expression* ptr,
+ Expression* value,
+ Type type) {
auto* ret = allocator.alloc<Store>();
ret->isAtomic = false;
- ret->bytes = bytes; ret->offset = offset; ret->align = align; ret->ptr = ptr; ret->value = value; ret->valueType = type;
+ ret->bytes = bytes;
+ ret->offset = offset;
+ ret->align = align;
+ ret->ptr = ptr;
+ ret->value = value;
+ ret->valueType = type;
ret->finalize();
assert(isConcreteType(ret->value->type) ? ret->value->type == type : true);
return ret;
}
- Store* makeAtomicStore(unsigned bytes, uint32_t offset, Expression* ptr, Expression* value, Type type) {
+ Store* makeAtomicStore(unsigned bytes,
+ uint32_t offset,
+ Expression* ptr,
+ Expression* value,
+ Type type) {
Store* store = makeStore(bytes, offset, bytes, ptr, value, type);
store->isAtomic = true;
return store;
}
- AtomicRMW* makeAtomicRMW(AtomicRMWOp op, unsigned bytes, uint32_t offset,
- Expression* ptr, Expression* value, Type type) {
+ AtomicRMW* makeAtomicRMW(AtomicRMWOp op,
+ unsigned bytes,
+ uint32_t offset,
+ Expression* ptr,
+ Expression* value,
+ Type type) {
auto* ret = allocator.alloc<AtomicRMW>();
ret->op = op;
ret->bytes = bytes;
@@ -290,9 +346,12 @@ public:
ret->finalize();
return ret;
}
- AtomicCmpxchg* makeAtomicCmpxchg(unsigned bytes, uint32_t offset,
- Expression* ptr, Expression* expected,
- Expression* replacement, Type type) {
+ AtomicCmpxchg* makeAtomicCmpxchg(unsigned bytes,
+ uint32_t offset,
+ Expression* ptr,
+ Expression* expected,
+ Expression* replacement,
+ Type type) {
auto* ret = allocator.alloc<AtomicCmpxchg>();
ret->bytes = bytes;
ret->offset = offset;
@@ -303,7 +362,8 @@ public:
ret->finalize();
return ret;
}
- SIMDExtract* makeSIMDExtract(SIMDExtractOp op, Expression* vec, uint8_t index) {
+ SIMDExtract*
+ makeSIMDExtract(SIMDExtractOp op, Expression* vec, uint8_t index) {
auto* ret = allocator.alloc<SIMDExtract>();
ret->op = op;
ret->vec = vec;
@@ -311,7 +371,10 @@ public:
ret->finalize();
return ret;
}
- SIMDReplace* makeSIMDReplace(SIMDReplaceOp op, Expression* vec, uint8_t index, Expression* value) {
+ SIMDReplace* makeSIMDReplace(SIMDReplaceOp op,
+ Expression* vec,
+ uint8_t index,
+ Expression* value) {
auto* ret = allocator.alloc<SIMDReplace>();
ret->op = op;
ret->vec = vec;
@@ -320,7 +383,9 @@ public:
ret->finalize();
return ret;
}
- SIMDShuffle* makeSIMDShuffle(Expression* left, Expression* right, const std::array<uint8_t, 16>& mask) {
+ SIMDShuffle* makeSIMDShuffle(Expression* left,
+ Expression* right,
+ const std::array<uint8_t, 16>& mask) {
auto* ret = allocator.alloc<SIMDShuffle>();
ret->left = left;
ret->right = right;
@@ -328,7 +393,8 @@ public:
ret->finalize();
return ret;
}
- SIMDBitselect* makeSIMDBitselect(Expression* left, Expression* right, Expression* cond) {
+ SIMDBitselect*
+ makeSIMDBitselect(Expression* left, Expression* right, Expression* cond) {
auto* ret = allocator.alloc<SIMDBitselect>();
ret->left = left;
ret->right = right;
@@ -344,7 +410,10 @@ public:
ret->finalize();
return ret;
}
- MemoryInit* makeMemoryInit(uint32_t segment, Expression* dest, Expression* offset, Expression* size) {
+ MemoryInit* makeMemoryInit(uint32_t segment,
+ Expression* dest,
+ Expression* offset,
+ Expression* size) {
auto* ret = allocator.alloc<MemoryInit>();
ret->segment = segment;
ret->dest = dest;
@@ -359,7 +428,8 @@ public:
ret->finalize();
return ret;
}
- MemoryCopy* makeMemoryCopy(Expression* dest, Expression* source, Expression* size) {
+ MemoryCopy*
+ makeMemoryCopy(Expression* dest, Expression* source, Expression* size) {
auto* ret = allocator.alloc<MemoryCopy>();
ret->dest = dest;
ret->source = source;
@@ -367,7 +437,8 @@ public:
ret->finalize();
return ret;
}
- MemoryFill* makeMemoryFill(Expression* dest, Expression* value, Expression* size) {
+ MemoryFill*
+ makeMemoryFill(Expression* dest, Expression* value, Expression* size) {
auto* ret = allocator.alloc<MemoryFill>();
ret->dest = dest;
ret->value = value;
@@ -382,30 +453,37 @@ public:
ret->type = value.type;
return ret;
}
- Unary* makeUnary(UnaryOp op, Expression *value) {
+ Unary* makeUnary(UnaryOp op, Expression* value) {
auto* ret = allocator.alloc<Unary>();
- ret->op = op; ret->value = value;
+ ret->op = op;
+ ret->value = value;
ret->finalize();
return ret;
}
- Binary* makeBinary(BinaryOp op, Expression *left, Expression *right) {
+ Binary* makeBinary(BinaryOp op, Expression* left, Expression* right) {
auto* ret = allocator.alloc<Binary>();
- ret->op = op; ret->left = left; ret->right = right;
+ ret->op = op;
+ ret->left = left;
+ ret->right = right;
ret->finalize();
return ret;
}
- Select* makeSelect(Expression* condition, Expression *ifTrue, Expression *ifFalse) {
+ Select*
+ makeSelect(Expression* condition, Expression* ifTrue, Expression* ifFalse) {
auto* ret = allocator.alloc<Select>();
- ret->condition = condition; ret->ifTrue = ifTrue; ret->ifFalse = ifFalse;
+ ret->condition = condition;
+ ret->ifTrue = ifTrue;
+ ret->ifFalse = ifFalse;
ret->finalize();
return ret;
}
- Return* makeReturn(Expression *value = nullptr) {
+ Return* makeReturn(Expression* value = nullptr) {
auto* ret = allocator.alloc<Return>();
ret->value = value;
return ret;
}
- Host* makeHost(HostOp op, Name nameOperand, std::vector<Expression*>&& operands) {
+ Host*
+ makeHost(HostOp op, Name nameOperand, std::vector<Expression*>&& operands) {
auto* ret = allocator.alloc<Host>();
ret->op = op;
ret->nameOperand = nameOperand;
@@ -413,13 +491,11 @@ public:
ret->finalize();
return ret;
}
- Unreachable* makeUnreachable() {
- return allocator.alloc<Unreachable>();
- }
+ Unreachable* makeUnreachable() { return allocator.alloc<Unreachable>(); }
// Additional helpers
- Drop* makeDrop(Expression *value) {
+ Drop* makeDrop(Expression* value) {
auto* ret = allocator.alloc<Drop>();
ret->value = value;
ret->finalize();
@@ -467,11 +543,14 @@ public:
clearLocalNames(func);
}
- // ensure a node is a block, if it isn't already, and optionally append to the block
+ // ensure a node is a block, if it isn't already, and optionally append to the
+ // block
Block* blockify(Expression* any, Expression* append = nullptr) {
Block* block = nullptr;
- if (any) block = any->dynCast<Block>();
- if (!block) block = makeBlock(any);
+ if (any)
+ block = any->dynCast<Block>();
+ if (!block)
+ block = makeBlock(any);
if (append) {
block->list.push_back(append);
block->finalize();
@@ -479,17 +558,21 @@ public:
return block;
}
- template<typename ...Ts>
+ template<typename... Ts>
Block* blockify(Expression* any, Expression* append, Ts... args) {
return blockify(blockify(any, append), args...);
}
- // ensure a node is a block, if it isn't already, and optionally append to the block
- // this variant sets a name for the block, so it will not reuse a block already named
- Block* blockifyWithName(Expression* any, Name name, Expression* append = nullptr) {
+ // ensure a node is a block, if it isn't already, and optionally append to the
+ // block this variant sets a name for the block, so it will not reuse a block
+ // already named
+ Block*
+ blockifyWithName(Expression* any, Name name, Expression* append = nullptr) {
Block* block = nullptr;
- if (any) block = any->dynCast<Block>();
- if (!block || block->name.is()) block = makeBlock(any);
+ if (any)
+ block = any->dynCast<Block>();
+ if (!block || block->name.is())
+ block = makeBlock(any);
block->name = name;
if (append) {
block->list.push_back(append);
@@ -498,8 +581,8 @@ public:
return block;
}
- // a helper for the common pattern of a sequence of two expressions. Similar to
- // blockify, but does *not* reuse a block if the first is one.
+ // a helper for the common pattern of a sequence of two expressions. Similar
+ // to blockify, but does *not* reuse a block if the first is one.
Block* makeSequence(Expression* left, Expression* right) {
auto* block = makeBlock(left);
block->list.push_back(right);
@@ -508,7 +591,8 @@ public:
}
// Grab a slice out of a block, replacing it with nops, and returning
- // either another block with the contents (if more than 1) or a single expression
+ // either another block with the contents (if more than 1) or a single
+ // expression
Expression* stealSlice(Block* input, Index from, Index to) {
Expression* ret;
if (to == from + 1) {
@@ -535,7 +619,8 @@ public:
// Drop an expression if it has a concrete type
Expression* dropIfConcretelyTyped(Expression* curr) {
- if (!isConcreteType(curr->type)) return curr;
+ if (!isConcreteType(curr->type))
+ return curr;
return makeDrop(curr);
}
@@ -547,35 +632,42 @@ public:
// returns a replacement with the precise same type, and with
// minimal contents. as a replacement, this may reuse the
// input node
- template<typename T>
- Expression* replaceWithIdenticalType(T* curr) {
+ template<typename T> Expression* replaceWithIdenticalType(T* curr) {
Literal value;
// TODO: reuse node conditionally when possible for literals
switch (curr->type) {
- case i32: value = Literal(int32_t(0)); break;
- case i64: value = Literal(int64_t(0)); break;
- case f32: value = Literal(float(0)); break;
- case f64: value = Literal(double(0)); break;
+ case i32:
+ value = Literal(int32_t(0));
+ break;
+ case i64:
+ value = Literal(int64_t(0));
+ break;
+ case f32:
+ value = Literal(float(0));
+ break;
+ case f64:
+ value = Literal(double(0));
+ break;
case v128: {
std::array<uint8_t, 16> bytes;
bytes.fill(0);
value = Literal(bytes.data());
break;
}
- case none: return ExpressionManipulator::nop(curr);
- case unreachable: return ExpressionManipulator::convert<T, Unreachable>(curr);
+ case none:
+ return ExpressionManipulator::nop(curr);
+ case unreachable:
+ return ExpressionManipulator::convert<T, Unreachable>(curr);
}
return makeConst(value);
}
// Module-level helpers
- enum Mutability {
- Mutable,
- Immutable
- };
+ enum Mutability { Mutable, Immutable };
- static Global* makeGlobal(Name name, Type type, Expression* init, Mutability mutable_) {
+ static Global*
+ makeGlobal(Name name, Type type, Expression* init, Mutability mutable_) {
auto* glob = new Global;
glob->name = name;
glob->type = type;
diff --git a/src/wasm-emscripten.h b/src/wasm-emscripten.h
index 7d86031c7..686269a1c 100644
--- a/src/wasm-emscripten.h
+++ b/src/wasm-emscripten.h
@@ -17,10 +17,9 @@
#ifndef wasm_wasm_emscripten_h
#define wasm_wasm_emscripten_h
-#include "wasm.h"
-#include "wasm-builder.h"
#include "support/file.h"
-
+#include "wasm-builder.h"
+#include "wasm.h"
namespace wasm {
@@ -29,10 +28,8 @@ namespace wasm {
class EmscriptenGlueGenerator {
public:
EmscriptenGlueGenerator(Module& wasm, Address stackPointerOffset = Address(0))
- : wasm(wasm),
- builder(wasm),
- stackPointerOffset(stackPointerOffset),
- useStackPointerGlobal(stackPointerOffset == 0) { }
+ : wasm(wasm), builder(wasm), stackPointerOffset(stackPointerOffset),
+ useStackPointerGlobal(stackPointerOffset == 0) {}
void generateRuntimeFunctions();
Function* generateMemoryGrowthFunction();
@@ -48,15 +45,16 @@ public:
// and restore functions.
void replaceStackPointerGlobal();
- std::string generateEmscriptenMetadata(
- Address staticBump, std::vector<Name> const& initializerFunctions);
-
+ std::string
+ generateEmscriptenMetadata(Address staticBump,
+ std::vector<Name> const& initializerFunctions);
void fixInvokeFunctionNames();
// Emits the data segments to a file. The file contains data from address base
- // onwards (we must pass in base, as we can't tell it from the wasm - the first
- // segment may start after a run of zeros, but we need those zeros in the file).
+ // onwards (we must pass in base, as we can't tell it from the wasm - the
+ // first segment may start after a run of zeros, but we need those zeros in
+ // the file).
void separateDataSegments(Output* outfile, Address base);
private:
diff --git a/src/wasm-features.h b/src/wasm-features.h
index 6ef704f82..d31715f18 100644
--- a/src/wasm-features.h
+++ b/src/wasm-features.h
@@ -36,13 +36,20 @@ struct FeatureSet {
static std::string toString(Feature f) {
switch (f) {
- case Atomics: return "threads";
- case MutableGlobals: return "mutable-globals";
- case TruncSat: return "nontrapping-float-to-int";
- case SIMD: return "simd";
- case BulkMemory: return "bulk-memory";
- case SignExt: return "sign-ext";
- default: WASM_UNREACHABLE();
+ case Atomics:
+ return "threads";
+ case MutableGlobals:
+ return "mutable-globals";
+ case TruncSat:
+ return "nontrapping-float-to-int";
+ case SIMD:
+ return "simd";
+ case BulkMemory:
+ return "bulk-memory";
+ case SignExt:
+ return "sign-ext";
+ default:
+ WASM_UNREACHABLE();
}
}
@@ -60,7 +67,9 @@ struct FeatureSet {
bool hasAll() const { return features & All; }
void makeMVP() { features = MVP; }
- void set(Feature f, bool v = true) { features = v ? (features | f) : (features & ~f); }
+ void set(Feature f, bool v = true) {
+ features = v ? (features | f) : (features & ~f);
+ }
void setAtomics(bool v = true) { set(Atomics, v); }
void setMutableGlobals(bool v = true) { set(MutableGlobals, v); }
void setTruncSat(bool v = true) { set(TruncSat, v); }
@@ -74,14 +83,19 @@ struct FeatureSet {
features = features & ~other.features & All;
}
- template<typename F>
- void iterFeatures(F f) {
- if (hasAtomics()) f(Atomics);
- if (hasBulkMemory()) f(BulkMemory);
- if (hasMutableGlobals()) f(MutableGlobals);
- if (hasTruncSat()) f(TruncSat);
- if (hasSignExt()) f(SignExt);
- if (hasSIMD()) f(SIMD);
+ template<typename F> void iterFeatures(F f) {
+ if (hasAtomics())
+ f(Atomics);
+ if (hasBulkMemory())
+ f(BulkMemory);
+ if (hasMutableGlobals())
+ f(MutableGlobals);
+ if (hasTruncSat())
+ f(TruncSat);
+ if (hasSignExt())
+ f(SignExt);
+ if (hasSIMD())
+ f(SIMD);
}
bool operator<=(const FeatureSet& other) const {
@@ -92,9 +106,7 @@ struct FeatureSet {
return *this <= other && other <= *this;
}
- bool operator!=(const FeatureSet& other) const {
- return !(*this == other);
- }
+ bool operator!=(const FeatureSet& other) const { return !(*this == other); }
FeatureSet& operator|=(const FeatureSet& other) {
features |= other.features;
diff --git a/src/wasm-interpreter.h b/src/wasm-interpreter.h
index 23121a849..dd6e2b073 100644
--- a/src/wasm-interpreter.h
+++ b/src/wasm-interpreter.h
@@ -27,17 +27,16 @@
#include <limits.h>
#include <sstream>
+#include "ir/module-utils.h"
#include "support/bits.h"
#include "support/safe_integer.h"
-#include "wasm.h"
#include "wasm-traversal.h"
-#include "ir/module-utils.h"
+#include "wasm.h"
#ifdef WASM_INTERPRETER_DEBUG
#include "wasm-printing.h"
#endif
-
namespace wasm {
using namespace cashew;
@@ -46,11 +45,10 @@ using namespace cashew;
extern Name WASM, RETURN_FLOW;
-enum {
- maxCallDepth = 250
-};
+enum { maxCallDepth = 250 };
-// Stuff that flows around during executing expressions: a literal, or a change in control flow.
+// Stuff that flows around during executing expressions: a literal, or a change
+// in control flow.
class Flow {
public:
Flow() = default;
@@ -69,7 +67,8 @@ public:
}
friend std::ostream& operator<<(std::ostream& o, Flow& flow) {
- o << "(flow " << (flow.breakTo.is() ? flow.breakTo.str : "-") << " : " << flow.value << ')';
+ o << "(flow " << (flow.breakTo.is() ? flow.breakTo.str : "-") << " : "
+ << flow.value << ')';
return o;
}
};
@@ -91,21 +90,33 @@ public:
static void print();
};
-#define NOTE_ENTER(x) Indenter _int_blah(x); { \
- Indenter::print(); \
- std::cout << "visit " << x << " : " << curr << "\n"; }
-#define NOTE_ENTER_(x) Indenter _int_blah(x); { \
- Indenter::print(); \
- std::cout << "visit " << x << "\n"; }
-#define NOTE_NAME(p0) { \
- Indenter::print(); \
- std::cout << "name " << '(' << Name(p0) << ")\n"; }
-#define NOTE_EVAL1(p0) { \
- Indenter::print(); \
- std::cout << "eval " #p0 " (" << p0 << ")\n"; }
-#define NOTE_EVAL2(p0, p1) { \
- Indenter::print(); \
- std::cout << "eval " #p0 " (" << p0 << "), " #p1 " (" << p1 << ")\n"; }
+#define NOTE_ENTER(x) \
+ Indenter _int_blah(x); \
+ { \
+ Indenter::print(); \
+ std::cout << "visit " << x << " : " << curr << "\n"; \
+ }
+#define NOTE_ENTER_(x) \
+ Indenter _int_blah(x); \
+ { \
+ Indenter::print(); \
+ std::cout << "visit " << x << "\n"; \
+ }
+#define NOTE_NAME(p0) \
+ { \
+ Indenter::print(); \
+ std::cout << "name " << '(' << Name(p0) << ")\n"; \
+ }
+#define NOTE_EVAL1(p0) \
+ { \
+ Indenter::print(); \
+ std::cout << "eval " #p0 " (" << p0 << ")\n"; \
+ }
+#define NOTE_EVAL2(p0, p1) \
+ { \
+ Indenter::print(); \
+ std::cout << "eval " #p0 " (" << p0 << "), " #p1 " (" << p1 << ")\n"; \
+ }
#else // WASM_INTERPRETER_DEBUG
#define NOTE_ENTER(x)
#define NOTE_ENTER_(x)
@@ -118,12 +129,15 @@ public:
template<typename SubType>
class ExpressionRunner : public OverriddenVisitor<SubType, Flow> {
public:
- Flow visit(Expression *curr) {
+ Flow visit(Expression* curr) {
auto ret = OverriddenVisitor<SubType, Flow>::visit(curr);
- if (!ret.breaking() && (isConcreteType(curr->type) || isConcreteType(ret.value.type))) {
+ if (!ret.breaking() &&
+ (isConcreteType(curr->type) || isConcreteType(ret.value.type))) {
#if 1 // def WASM_INTERPRETER_DEBUG
if (ret.value.type != curr->type) {
- std::cerr << "expected " << printType(curr->type) << ", seeing " << printType(ret.value.type) << " from\n" << curr << '\n';
+ std::cerr << "expected " << printType(curr->type) << ", seeing "
+ << printType(ret.value.type) << " from\n"
+ << curr << '\n';
}
#endif
assert(ret.value.type == curr->type);
@@ -131,9 +145,10 @@ public:
return ret;
}
- Flow visitBlock(Block *curr) {
+ Flow visitBlock(Block* curr) {
NOTE_ENTER("Block");
- // special-case Block, because Block nesting (in their first element) can be incredibly deep
+ // special-case Block, because Block nesting (in their first element) can be
+ // incredibly deep
std::vector<Block*> stack;
stack.push_back(curr);
while (curr->list.size() > 0 && curr->list[0]->is<Block>()) {
@@ -164,58 +179,68 @@ public:
}
return flow;
}
- Flow visitIf(If *curr) {
+ Flow visitIf(If* curr) {
NOTE_ENTER("If");
Flow flow = visit(curr->condition);
- if (flow.breaking()) return flow;
+ if (flow.breaking())
+ return flow;
NOTE_EVAL1(flow.value);
if (flow.value.geti32()) {
Flow flow = visit(curr->ifTrue);
- if (!flow.breaking() && !curr->ifFalse) flow.value = Literal(); // if_else returns a value, but if does not
+ if (!flow.breaking() && !curr->ifFalse)
+ flow.value = Literal(); // if_else returns a value, but if does not
return flow;
}
- if (curr->ifFalse) return visit(curr->ifFalse);
+ if (curr->ifFalse)
+ return visit(curr->ifFalse);
return Flow();
}
- Flow visitLoop(Loop *curr) {
+ Flow visitLoop(Loop* curr) {
NOTE_ENTER("Loop");
while (1) {
Flow flow = visit(curr->body);
if (flow.breaking()) {
- if (flow.breakTo == curr->name) continue; // lol
+ if (flow.breakTo == curr->name)
+ continue; // lol
}
- return flow; // loop does not loop automatically, only continue achieves that
+ // loop does not loop automatically, only continue achieves that
+ return flow;
}
}
- Flow visitBreak(Break *curr) {
+ Flow visitBreak(Break* curr) {
NOTE_ENTER("Break");
bool condition = true;
Flow flow;
if (curr->value) {
flow = visit(curr->value);
- if (flow.breaking()) return flow;
+ if (flow.breaking())
+ return flow;
}
if (curr->condition) {
Flow conditionFlow = visit(curr->condition);
- if (conditionFlow.breaking()) return conditionFlow;
+ if (conditionFlow.breaking())
+ return conditionFlow;
condition = conditionFlow.value.getInteger() != 0;
- if (!condition) return flow;
+ if (!condition)
+ return flow;
}
flow.breakTo = curr->name;
return flow;
}
- Flow visitSwitch(Switch *curr) {
+ Flow visitSwitch(Switch* curr) {
NOTE_ENTER("Switch");
Flow flow;
Literal value;
if (curr->value) {
flow = visit(curr->value);
- if (flow.breaking()) return flow;
+ if (flow.breaking())
+ return flow;
value = flow.value;
NOTE_EVAL1(value);
}
flow = visit(curr->condition);
- if (flow.breaking()) return flow;
+ if (flow.breaking())
+ return flow;
int64_t index = flow.value.getInteger();
Name target = curr->default_;
if (index >= 0 && (size_t)index < curr->targets.size()) {
@@ -226,7 +251,7 @@ public:
return flow;
}
- Flow visitConst(Const *curr) {
+ Flow visitConst(Const* curr) {
NOTE_ENTER("Const");
NOTE_EVAL1(curr->value);
return Flow(curr->value); // heh
@@ -235,429 +260,662 @@ public:
// Unary and Binary nodes, the core math computations. We mostly just
// delegate to the Literal::* methods, except we handle traps here.
- Flow visitUnary(Unary *curr) {
+ Flow visitUnary(Unary* curr) {
NOTE_ENTER("Unary");
Flow flow = visit(curr->value);
- if (flow.breaking()) return flow;
+ if (flow.breaking())
+ return flow;
Literal value = flow.value;
NOTE_EVAL1(value);
switch (curr->op) {
case ClzInt32:
- case ClzInt64: return value.countLeadingZeroes();
+ case ClzInt64:
+ return value.countLeadingZeroes();
case CtzInt32:
- case CtzInt64: return value.countTrailingZeroes();
+ case CtzInt64:
+ return value.countTrailingZeroes();
case PopcntInt32:
- case PopcntInt64: return value.popCount();
+ case PopcntInt64:
+ return value.popCount();
case EqZInt32:
- case EqZInt64: return value.eqz();
- case ReinterpretInt32: return value.castToF32();
- case ReinterpretInt64: return value.castToF64();
- case ExtendSInt32: return value.extendToSI64();
- case ExtendUInt32: return value.extendToUI64();
- case WrapInt64: return value.wrapToI32();
+ case EqZInt64:
+ return value.eqz();
+ case ReinterpretInt32:
+ return value.castToF32();
+ case ReinterpretInt64:
+ return value.castToF64();
+ case ExtendSInt32:
+ return value.extendToSI64();
+ case ExtendUInt32:
+ return value.extendToUI64();
+ case WrapInt64:
+ return value.wrapToI32();
case ConvertUInt32ToFloat32:
- case ConvertUInt64ToFloat32: return value.convertUIToF32();
+ case ConvertUInt64ToFloat32:
+ return value.convertUIToF32();
case ConvertUInt32ToFloat64:
- case ConvertUInt64ToFloat64: return value.convertUIToF64();
+ case ConvertUInt64ToFloat64:
+ return value.convertUIToF64();
case ConvertSInt32ToFloat32:
- case ConvertSInt64ToFloat32: return value.convertSIToF32();
+ case ConvertSInt64ToFloat32:
+ return value.convertSIToF32();
case ConvertSInt32ToFloat64:
- case ConvertSInt64ToFloat64: return value.convertSIToF64();
+ case ConvertSInt64ToFloat64:
+ return value.convertSIToF64();
case ExtendS8Int32:
- case ExtendS8Int64: return value.extendS8();
+ case ExtendS8Int64:
+ return value.extendS8();
case ExtendS16Int32:
- case ExtendS16Int64: return value.extendS16();
- case ExtendS32Int64: return value.extendS32();
+ case ExtendS16Int64:
+ return value.extendS16();
+ case ExtendS32Int64:
+ return value.extendS32();
case NegFloat32:
- case NegFloat64: return value.neg();
+ case NegFloat64:
+ return value.neg();
case AbsFloat32:
- case AbsFloat64: return value.abs();
+ case AbsFloat64:
+ return value.abs();
case CeilFloat32:
- case CeilFloat64: return value.ceil();
+ case CeilFloat64:
+ return value.ceil();
case FloorFloat32:
- case FloorFloat64: return value.floor();
+ case FloorFloat64:
+ return value.floor();
case TruncFloat32:
- case TruncFloat64: return value.trunc();
+ case TruncFloat64:
+ return value.trunc();
case NearestFloat32:
- case NearestFloat64: return value.nearbyint();
+ case NearestFloat64:
+ return value.nearbyint();
case SqrtFloat32:
- case SqrtFloat64: return value.sqrt();
+ case SqrtFloat64:
+ return value.sqrt();
case TruncSFloat32ToInt32:
case TruncSFloat64ToInt32:
case TruncSFloat32ToInt64:
- case TruncSFloat64ToInt64: return truncSFloat(curr, value);
+ case TruncSFloat64ToInt64:
+ return truncSFloat(curr, value);
case TruncUFloat32ToInt32:
case TruncUFloat64ToInt32:
case TruncUFloat32ToInt64:
- case TruncUFloat64ToInt64: return truncUFloat(curr, value);
+ case TruncUFloat64ToInt64:
+ return truncUFloat(curr, value);
case TruncSatSFloat32ToInt32:
- case TruncSatSFloat64ToInt32: return value.truncSatToSI32();
+ case TruncSatSFloat64ToInt32:
+ return value.truncSatToSI32();
case TruncSatSFloat32ToInt64:
- case TruncSatSFloat64ToInt64: return value.truncSatToSI64();
+ case TruncSatSFloat64ToInt64:
+ return value.truncSatToSI64();
case TruncSatUFloat32ToInt32:
- case TruncSatUFloat64ToInt32: return value.truncSatToUI32();
+ case TruncSatUFloat64ToInt32:
+ return value.truncSatToUI32();
case TruncSatUFloat32ToInt64:
- case TruncSatUFloat64ToInt64: return value.truncSatToUI64();
- case ReinterpretFloat32: return value.castToI32();
- case PromoteFloat32: return value.extendToF64();
- case ReinterpretFloat64: return value.castToI64();
- case DemoteFloat64: return value.demote();
- case SplatVecI8x16: return value.splatI8x16();
- case SplatVecI16x8: return value.splatI16x8();
- case SplatVecI32x4: return value.splatI32x4();
- case SplatVecI64x2: return value.splatI64x2();
- case SplatVecF32x4: return value.splatF32x4();
- case SplatVecF64x2: return value.splatF64x2();
- case NotVec128: return value.notV128();
- case NegVecI8x16: return value.negI8x16();
- case AnyTrueVecI8x16: return value.anyTrueI8x16();
- case AllTrueVecI8x16: return value.allTrueI8x16();
- case NegVecI16x8: return value.negI16x8();
- case AnyTrueVecI16x8: return value.anyTrueI16x8();
- case AllTrueVecI16x8: return value.allTrueI16x8();
- case NegVecI32x4: return value.negI32x4();
- case AnyTrueVecI32x4: return value.anyTrueI32x4();
- case AllTrueVecI32x4: return value.allTrueI32x4();
- case NegVecI64x2: return value.negI64x2();
- case AnyTrueVecI64x2: return value.anyTrueI64x2();
- case AllTrueVecI64x2: return value.allTrueI64x2();
- case AbsVecF32x4: return value.absF32x4();
- case NegVecF32x4: return value.negF32x4();
- case SqrtVecF32x4: return value.sqrtF32x4();
- case AbsVecF64x2: return value.absF64x2();
- case NegVecF64x2: return value.negF64x2();
- case SqrtVecF64x2: return value.sqrtF64x2();
- case TruncSatSVecF32x4ToVecI32x4: return value.truncSatToSI32x4();
- case TruncSatUVecF32x4ToVecI32x4: return value.truncSatToUI32x4();
- case TruncSatSVecF64x2ToVecI64x2: return value.truncSatToSI64x2();
- case TruncSatUVecF64x2ToVecI64x2: return value.truncSatToUI64x2();
- case ConvertSVecI32x4ToVecF32x4: return value.convertSToF32x4();
- case ConvertUVecI32x4ToVecF32x4: return value.convertUToF32x4();
- case ConvertSVecI64x2ToVecF64x2: return value.convertSToF64x2();
- case ConvertUVecI64x2ToVecF64x2: return value.convertUToF64x2();
- case InvalidUnary: WASM_UNREACHABLE();
+ case TruncSatUFloat64ToInt64:
+ return value.truncSatToUI64();
+ case ReinterpretFloat32:
+ return value.castToI32();
+ case PromoteFloat32:
+ return value.extendToF64();
+ case ReinterpretFloat64:
+ return value.castToI64();
+ case DemoteFloat64:
+ return value.demote();
+ case SplatVecI8x16:
+ return value.splatI8x16();
+ case SplatVecI16x8:
+ return value.splatI16x8();
+ case SplatVecI32x4:
+ return value.splatI32x4();
+ case SplatVecI64x2:
+ return value.splatI64x2();
+ case SplatVecF32x4:
+ return value.splatF32x4();
+ case SplatVecF64x2:
+ return value.splatF64x2();
+ case NotVec128:
+ return value.notV128();
+ case NegVecI8x16:
+ return value.negI8x16();
+ case AnyTrueVecI8x16:
+ return value.anyTrueI8x16();
+ case AllTrueVecI8x16:
+ return value.allTrueI8x16();
+ case NegVecI16x8:
+ return value.negI16x8();
+ case AnyTrueVecI16x8:
+ return value.anyTrueI16x8();
+ case AllTrueVecI16x8:
+ return value.allTrueI16x8();
+ case NegVecI32x4:
+ return value.negI32x4();
+ case AnyTrueVecI32x4:
+ return value.anyTrueI32x4();
+ case AllTrueVecI32x4:
+ return value.allTrueI32x4();
+ case NegVecI64x2:
+ return value.negI64x2();
+ case AnyTrueVecI64x2:
+ return value.anyTrueI64x2();
+ case AllTrueVecI64x2:
+ return value.allTrueI64x2();
+ case AbsVecF32x4:
+ return value.absF32x4();
+ case NegVecF32x4:
+ return value.negF32x4();
+ case SqrtVecF32x4:
+ return value.sqrtF32x4();
+ case AbsVecF64x2:
+ return value.absF64x2();
+ case NegVecF64x2:
+ return value.negF64x2();
+ case SqrtVecF64x2:
+ return value.sqrtF64x2();
+ case TruncSatSVecF32x4ToVecI32x4:
+ return value.truncSatToSI32x4();
+ case TruncSatUVecF32x4ToVecI32x4:
+ return value.truncSatToUI32x4();
+ case TruncSatSVecF64x2ToVecI64x2:
+ return value.truncSatToSI64x2();
+ case TruncSatUVecF64x2ToVecI64x2:
+ return value.truncSatToUI64x2();
+ case ConvertSVecI32x4ToVecF32x4:
+ return value.convertSToF32x4();
+ case ConvertUVecI32x4ToVecF32x4:
+ return value.convertUToF32x4();
+ case ConvertSVecI64x2ToVecF64x2:
+ return value.convertSToF64x2();
+ case ConvertUVecI64x2ToVecF64x2:
+ return value.convertUToF64x2();
+ case InvalidUnary:
+ WASM_UNREACHABLE();
}
WASM_UNREACHABLE();
}
- Flow visitBinary(Binary *curr) {
+ Flow visitBinary(Binary* curr) {
NOTE_ENTER("Binary");
Flow flow = visit(curr->left);
- if (flow.breaking()) return flow;
+ if (flow.breaking())
+ return flow;
Literal left = flow.value;
flow = visit(curr->right);
- if (flow.breaking()) return flow;
+ if (flow.breaking())
+ return flow;
Literal right = flow.value;
NOTE_EVAL2(left, right);
- assert(isConcreteType(curr->left->type) ? left.type == curr->left->type : true);
- assert(isConcreteType(curr->right->type) ? right.type == curr->right->type : true);
+ assert(isConcreteType(curr->left->type) ? left.type == curr->left->type
+ : true);
+ assert(isConcreteType(curr->right->type) ? right.type == curr->right->type
+ : true);
switch (curr->op) {
case AddInt32:
case AddInt64:
case AddFloat32:
- case AddFloat64: return left.add(right);
+ case AddFloat64:
+ return left.add(right);
case SubInt32:
case SubInt64:
case SubFloat32:
- case SubFloat64: return left.sub(right);
+ case SubFloat64:
+ return left.sub(right);
case MulInt32:
case MulInt64:
case MulFloat32:
- case MulFloat64: return left.mul(right);
+ case MulFloat64:
+ return left.mul(right);
case DivSInt32: {
- if (right.getInteger() == 0) trap("i32.div_s by 0");
- if (left.getInteger() == std::numeric_limits<int32_t>::min() && right.getInteger() == -1) trap("i32.div_s overflow"); // signed division overflow
+ if (right.getInteger() == 0)
+ trap("i32.div_s by 0");
+ if (left.getInteger() == std::numeric_limits<int32_t>::min() &&
+ right.getInteger() == -1)
+ trap("i32.div_s overflow"); // signed division overflow
return left.divS(right);
}
case DivUInt32: {
- if (right.getInteger() == 0) trap("i32.div_u by 0");
+ if (right.getInteger() == 0)
+ trap("i32.div_u by 0");
return left.divU(right);
}
case RemSInt32: {
- if (right.getInteger() == 0) trap("i32.rem_s by 0");
- if (left.getInteger() == std::numeric_limits<int32_t>::min() && right.getInteger() == -1) return Literal(int32_t(0));
+ if (right.getInteger() == 0)
+ trap("i32.rem_s by 0");
+ if (left.getInteger() == std::numeric_limits<int32_t>::min() &&
+ right.getInteger() == -1)
+ return Literal(int32_t(0));
return left.remS(right);
}
case RemUInt32: {
- if (right.getInteger() == 0) trap("i32.rem_u by 0");
+ if (right.getInteger() == 0)
+ trap("i32.rem_u by 0");
return left.remU(right);
}
case DivSInt64: {
- if (right.getInteger() == 0) trap("i64.div_s by 0");
- if (left.getInteger() == LLONG_MIN && right.getInteger() == -1LL) trap("i64.div_s overflow"); // signed division overflow
+ if (right.getInteger() == 0)
+ trap("i64.div_s by 0");
+ if (left.getInteger() == LLONG_MIN && right.getInteger() == -1LL)
+ trap("i64.div_s overflow"); // signed division overflow
return left.divS(right);
}
case DivUInt64: {
- if (right.getInteger() == 0) trap("i64.div_u by 0");
+ if (right.getInteger() == 0)
+ trap("i64.div_u by 0");
return left.divU(right);
}
case RemSInt64: {
- if (right.getInteger() == 0) trap("i64.rem_s by 0");
- if (left.getInteger() == LLONG_MIN && right.getInteger() == -1LL) return Literal(int64_t(0));
+ if (right.getInteger() == 0)
+ trap("i64.rem_s by 0");
+ if (left.getInteger() == LLONG_MIN && right.getInteger() == -1LL)
+ return Literal(int64_t(0));
return left.remS(right);
}
case RemUInt64: {
- if (right.getInteger() == 0) trap("i64.rem_u by 0");
+ if (right.getInteger() == 0)
+ trap("i64.rem_u by 0");
return left.remU(right);
}
case DivFloat32:
- case DivFloat64: return left.div(right);
+ case DivFloat64:
+ return left.div(right);
case AndInt32:
- case AndInt64: return left.and_(right);
+ case AndInt64:
+ return left.and_(right);
case OrInt32:
- case OrInt64: return left.or_(right);
+ case OrInt64:
+ return left.or_(right);
case XorInt32:
- case XorInt64: return left.xor_(right);
+ case XorInt64:
+ return left.xor_(right);
case ShlInt32:
- case ShlInt64: return left.shl(right);
+ case ShlInt64:
+ return left.shl(right);
case ShrUInt32:
- case ShrUInt64: return left.shrU(right);
+ case ShrUInt64:
+ return left.shrU(right);
case ShrSInt32:
- case ShrSInt64: return left.shrS(right);
+ case ShrSInt64:
+ return left.shrS(right);
case RotLInt32:
- case RotLInt64: return left.rotL(right);
+ case RotLInt64:
+ return left.rotL(right);
case RotRInt32:
- case RotRInt64: return left.rotR(right);
+ case RotRInt64:
+ return left.rotR(right);
case EqInt32:
case EqInt64:
case EqFloat32:
- case EqFloat64: return left.eq(right);
+ case EqFloat64:
+ return left.eq(right);
case NeInt32:
case NeInt64:
case NeFloat32:
- case NeFloat64: return left.ne(right);
+ case NeFloat64:
+ return left.ne(right);
case LtSInt32:
- case LtSInt64: return left.ltS(right);
+ case LtSInt64:
+ return left.ltS(right);
case LtUInt32:
- case LtUInt64: return left.ltU(right);
+ case LtUInt64:
+ return left.ltU(right);
case LeSInt32:
- case LeSInt64: return left.leS(right);
+ case LeSInt64:
+ return left.leS(right);
case LeUInt32:
- case LeUInt64: return left.leU(right);
+ case LeUInt64:
+ return left.leU(right);
case GtSInt32:
- case GtSInt64: return left.gtS(right);
+ case GtSInt64:
+ return left.gtS(right);
case GtUInt32:
- case GtUInt64: return left.gtU(right);
+ case GtUInt64:
+ return left.gtU(right);
case GeSInt32:
- case GeSInt64: return left.geS(right);
+ case GeSInt64:
+ return left.geS(right);
case GeUInt32:
- case GeUInt64: return left.geU(right);
+ case GeUInt64:
+ return left.geU(right);
case LtFloat32:
- case LtFloat64: return left.lt(right);
+ case LtFloat64:
+ return left.lt(right);
case LeFloat32:
- case LeFloat64: return left.le(right);
+ case LeFloat64:
+ return left.le(right);
case GtFloat32:
- case GtFloat64: return left.gt(right);
+ case GtFloat64:
+ return left.gt(right);
case GeFloat32:
- case GeFloat64: return left.ge(right);
+ case GeFloat64:
+ return left.ge(right);
case CopySignFloat32:
- case CopySignFloat64: return left.copysign(right);
+ case CopySignFloat64:
+ return left.copysign(right);
case MinFloat32:
- case MinFloat64: return left.min(right);
+ case MinFloat64:
+ return left.min(right);
case MaxFloat32:
- case MaxFloat64: return left.max(right);
-
- case EqVecI8x16: return left.eqI8x16(right);
- case NeVecI8x16: return left.neI8x16(right);
- case LtSVecI8x16: return left.ltSI8x16(right);
- case LtUVecI8x16: return left.ltUI8x16(right);
- case GtSVecI8x16: return left.gtSI8x16(right);
- case GtUVecI8x16: return left.gtUI8x16(right);
- case LeSVecI8x16: return left.leSI8x16(right);
- case LeUVecI8x16: return left.leUI8x16(right);
- case GeSVecI8x16: return left.geSI8x16(right);
- case GeUVecI8x16: return left.geUI8x16(right);
- case EqVecI16x8: return left.eqI16x8(right);
- case NeVecI16x8: return left.neI16x8(right);
- case LtSVecI16x8: return left.ltSI16x8(right);
- case LtUVecI16x8: return left.ltUI16x8(right);
- case GtSVecI16x8: return left.gtSI16x8(right);
- case GtUVecI16x8: return left.gtUI16x8(right);
- case LeSVecI16x8: return left.leSI16x8(right);
- case LeUVecI16x8: return left.leUI16x8(right);
- case GeSVecI16x8: return left.geSI16x8(right);
- case GeUVecI16x8: return left.geUI16x8(right);
- case EqVecI32x4: return left.eqI32x4(right);
- case NeVecI32x4: return left.neI32x4(right);
- case LtSVecI32x4: return left.ltSI32x4(right);
- case LtUVecI32x4: return left.ltUI32x4(right);
- case GtSVecI32x4: return left.gtSI32x4(right);
- case GtUVecI32x4: return left.gtUI32x4(right);
- case LeSVecI32x4: return left.leSI32x4(right);
- case LeUVecI32x4: return left.leUI32x4(right);
- case GeSVecI32x4: return left.geSI32x4(right);
- case GeUVecI32x4: return left.geUI32x4(right);
- case EqVecF32x4: return left.eqF32x4(right);
- case NeVecF32x4: return left.neF32x4(right);
- case LtVecF32x4: return left.ltF32x4(right);
- case GtVecF32x4: return left.gtF32x4(right);
- case LeVecF32x4: return left.leF32x4(right);
- case GeVecF32x4: return left.geF32x4(right);
- case EqVecF64x2: return left.eqF64x2(right);
- case NeVecF64x2: return left.neF64x2(right);
- case LtVecF64x2: return left.ltF64x2(right);
- case GtVecF64x2: return left.gtF64x2(right);
- case LeVecF64x2: return left.leF64x2(right);
- case GeVecF64x2: return left.geF64x2(right);
-
- case AndVec128: return left.andV128(right);
- case OrVec128: return left.orV128(right);
- case XorVec128: return left.xorV128(right);
-
- case AddVecI8x16: return left.addI8x16(right);
- case AddSatSVecI8x16: return left.addSaturateSI8x16(right);
- case AddSatUVecI8x16: return left.addSaturateUI8x16(right);
- case SubVecI8x16: return left.subI8x16(right);
- case SubSatSVecI8x16: return left.subSaturateSI8x16(right);
- case SubSatUVecI8x16: return left.subSaturateUI8x16(right);
- case MulVecI8x16: return left.mulI8x16(right);
- case AddVecI16x8: return left.addI16x8(right);
- case AddSatSVecI16x8: return left.addSaturateSI16x8(right);
- case AddSatUVecI16x8: return left.addSaturateUI16x8(right);
- case SubVecI16x8: return left.subI16x8(right);
- case SubSatSVecI16x8: return left.subSaturateSI16x8(right);
- case SubSatUVecI16x8: return left.subSaturateUI16x8(right);
- case MulVecI16x8: return left.mulI16x8(right);
- case AddVecI32x4: return left.addI32x4(right);
- case SubVecI32x4: return left.subI32x4(right);
- case MulVecI32x4: return left.mulI32x4(right);
- case AddVecI64x2: return left.addI64x2(right);
- case SubVecI64x2: return left.subI64x2(right);
-
- case AddVecF32x4: return left.addF32x4(right);
- case SubVecF32x4: return left.subF32x4(right);
- case MulVecF32x4: return left.mulF32x4(right);
- case DivVecF32x4: return left.divF32x4(right);
- case MinVecF32x4: return left.minF32x4(right);
- case MaxVecF32x4: return left.maxF32x4(right);
- case AddVecF64x2: return left.addF64x2(right);
- case SubVecF64x2: return left.subF64x2(right);
- case MulVecF64x2: return left.mulF64x2(right);
- case DivVecF64x2: return left.divF64x2(right);
- case MinVecF64x2: return left.minF64x2(right);
- case MaxVecF64x2: return left.maxF64x2(right);
-
- case InvalidBinary: WASM_UNREACHABLE();
+ case MaxFloat64:
+ return left.max(right);
+
+ case EqVecI8x16:
+ return left.eqI8x16(right);
+ case NeVecI8x16:
+ return left.neI8x16(right);
+ case LtSVecI8x16:
+ return left.ltSI8x16(right);
+ case LtUVecI8x16:
+ return left.ltUI8x16(right);
+ case GtSVecI8x16:
+ return left.gtSI8x16(right);
+ case GtUVecI8x16:
+ return left.gtUI8x16(right);
+ case LeSVecI8x16:
+ return left.leSI8x16(right);
+ case LeUVecI8x16:
+ return left.leUI8x16(right);
+ case GeSVecI8x16:
+ return left.geSI8x16(right);
+ case GeUVecI8x16:
+ return left.geUI8x16(right);
+ case EqVecI16x8:
+ return left.eqI16x8(right);
+ case NeVecI16x8:
+ return left.neI16x8(right);
+ case LtSVecI16x8:
+ return left.ltSI16x8(right);
+ case LtUVecI16x8:
+ return left.ltUI16x8(right);
+ case GtSVecI16x8:
+ return left.gtSI16x8(right);
+ case GtUVecI16x8:
+ return left.gtUI16x8(right);
+ case LeSVecI16x8:
+ return left.leSI16x8(right);
+ case LeUVecI16x8:
+ return left.leUI16x8(right);
+ case GeSVecI16x8:
+ return left.geSI16x8(right);
+ case GeUVecI16x8:
+ return left.geUI16x8(right);
+ case EqVecI32x4:
+ return left.eqI32x4(right);
+ case NeVecI32x4:
+ return left.neI32x4(right);
+ case LtSVecI32x4:
+ return left.ltSI32x4(right);
+ case LtUVecI32x4:
+ return left.ltUI32x4(right);
+ case GtSVecI32x4:
+ return left.gtSI32x4(right);
+ case GtUVecI32x4:
+ return left.gtUI32x4(right);
+ case LeSVecI32x4:
+ return left.leSI32x4(right);
+ case LeUVecI32x4:
+ return left.leUI32x4(right);
+ case GeSVecI32x4:
+ return left.geSI32x4(right);
+ case GeUVecI32x4:
+ return left.geUI32x4(right);
+ case EqVecF32x4:
+ return left.eqF32x4(right);
+ case NeVecF32x4:
+ return left.neF32x4(right);
+ case LtVecF32x4:
+ return left.ltF32x4(right);
+ case GtVecF32x4:
+ return left.gtF32x4(right);
+ case LeVecF32x4:
+ return left.leF32x4(right);
+ case GeVecF32x4:
+ return left.geF32x4(right);
+ case EqVecF64x2:
+ return left.eqF64x2(right);
+ case NeVecF64x2:
+ return left.neF64x2(right);
+ case LtVecF64x2:
+ return left.ltF64x2(right);
+ case GtVecF64x2:
+ return left.gtF64x2(right);
+ case LeVecF64x2:
+ return left.leF64x2(right);
+ case GeVecF64x2:
+ return left.geF64x2(right);
+
+ case AndVec128:
+ return left.andV128(right);
+ case OrVec128:
+ return left.orV128(right);
+ case XorVec128:
+ return left.xorV128(right);
+
+ case AddVecI8x16:
+ return left.addI8x16(right);
+ case AddSatSVecI8x16:
+ return left.addSaturateSI8x16(right);
+ case AddSatUVecI8x16:
+ return left.addSaturateUI8x16(right);
+ case SubVecI8x16:
+ return left.subI8x16(right);
+ case SubSatSVecI8x16:
+ return left.subSaturateSI8x16(right);
+ case SubSatUVecI8x16:
+ return left.subSaturateUI8x16(right);
+ case MulVecI8x16:
+ return left.mulI8x16(right);
+ case AddVecI16x8:
+ return left.addI16x8(right);
+ case AddSatSVecI16x8:
+ return left.addSaturateSI16x8(right);
+ case AddSatUVecI16x8:
+ return left.addSaturateUI16x8(right);
+ case SubVecI16x8:
+ return left.subI16x8(right);
+ case SubSatSVecI16x8:
+ return left.subSaturateSI16x8(right);
+ case SubSatUVecI16x8:
+ return left.subSaturateUI16x8(right);
+ case MulVecI16x8:
+ return left.mulI16x8(right);
+ case AddVecI32x4:
+ return left.addI32x4(right);
+ case SubVecI32x4:
+ return left.subI32x4(right);
+ case MulVecI32x4:
+ return left.mulI32x4(right);
+ case AddVecI64x2:
+ return left.addI64x2(right);
+ case SubVecI64x2:
+ return left.subI64x2(right);
+
+ case AddVecF32x4:
+ return left.addF32x4(right);
+ case SubVecF32x4:
+ return left.subF32x4(right);
+ case MulVecF32x4:
+ return left.mulF32x4(right);
+ case DivVecF32x4:
+ return left.divF32x4(right);
+ case MinVecF32x4:
+ return left.minF32x4(right);
+ case MaxVecF32x4:
+ return left.maxF32x4(right);
+ case AddVecF64x2:
+ return left.addF64x2(right);
+ case SubVecF64x2:
+ return left.subF64x2(right);
+ case MulVecF64x2:
+ return left.mulF64x2(right);
+ case DivVecF64x2:
+ return left.divF64x2(right);
+ case MinVecF64x2:
+ return left.minF64x2(right);
+ case MaxVecF64x2:
+ return left.maxF64x2(right);
+
+ case InvalidBinary:
+ WASM_UNREACHABLE();
}
WASM_UNREACHABLE();
}
- Flow visitSIMDExtract(SIMDExtract *curr) {
+ Flow visitSIMDExtract(SIMDExtract* curr) {
NOTE_ENTER("SIMDExtract");
Flow flow = this->visit(curr->vec);
- if (flow.breaking()) return flow;
+ if (flow.breaking())
+ return flow;
Literal vec = flow.value;
switch (curr->op) {
- case ExtractLaneSVecI8x16: return vec.extractLaneSI8x16(curr->index);
- case ExtractLaneUVecI8x16: return vec.extractLaneUI8x16(curr->index);
- case ExtractLaneSVecI16x8: return vec.extractLaneSI16x8(curr->index);
- case ExtractLaneUVecI16x8: return vec.extractLaneUI16x8(curr->index);
- case ExtractLaneVecI32x4: return vec.extractLaneI32x4(curr->index);
- case ExtractLaneVecI64x2: return vec.extractLaneI64x2(curr->index);
- case ExtractLaneVecF32x4: return vec.extractLaneF32x4(curr->index);
- case ExtractLaneVecF64x2: return vec.extractLaneF64x2(curr->index);
+ case ExtractLaneSVecI8x16:
+ return vec.extractLaneSI8x16(curr->index);
+ case ExtractLaneUVecI8x16:
+ return vec.extractLaneUI8x16(curr->index);
+ case ExtractLaneSVecI16x8:
+ return vec.extractLaneSI16x8(curr->index);
+ case ExtractLaneUVecI16x8:
+ return vec.extractLaneUI16x8(curr->index);
+ case ExtractLaneVecI32x4:
+ return vec.extractLaneI32x4(curr->index);
+ case ExtractLaneVecI64x2:
+ return vec.extractLaneI64x2(curr->index);
+ case ExtractLaneVecF32x4:
+ return vec.extractLaneF32x4(curr->index);
+ case ExtractLaneVecF64x2:
+ return vec.extractLaneF64x2(curr->index);
}
WASM_UNREACHABLE();
}
- Flow visitSIMDReplace(SIMDReplace *curr) {
+ Flow visitSIMDReplace(SIMDReplace* curr) {
NOTE_ENTER("SIMDReplace");
Flow flow = this->visit(curr->vec);
- if (flow.breaking()) return flow;
+ if (flow.breaking())
+ return flow;
Literal vec = flow.value;
flow = this->visit(curr->value);
- if (flow.breaking()) return flow;
+ if (flow.breaking())
+ return flow;
Literal value = flow.value;
switch (curr->op) {
- case ReplaceLaneVecI8x16: return vec.replaceLaneI8x16(value, curr->index);
- case ReplaceLaneVecI16x8: return vec.replaceLaneI16x8(value, curr->index);
- case ReplaceLaneVecI32x4: return vec.replaceLaneI32x4(value, curr->index);
- case ReplaceLaneVecI64x2: return vec.replaceLaneI64x2(value, curr->index);
- case ReplaceLaneVecF32x4: return vec.replaceLaneF32x4(value, curr->index);
- case ReplaceLaneVecF64x2: return vec.replaceLaneF64x2(value, curr->index);
+ case ReplaceLaneVecI8x16:
+ return vec.replaceLaneI8x16(value, curr->index);
+ case ReplaceLaneVecI16x8:
+ return vec.replaceLaneI16x8(value, curr->index);
+ case ReplaceLaneVecI32x4:
+ return vec.replaceLaneI32x4(value, curr->index);
+ case ReplaceLaneVecI64x2:
+ return vec.replaceLaneI64x2(value, curr->index);
+ case ReplaceLaneVecF32x4:
+ return vec.replaceLaneF32x4(value, curr->index);
+ case ReplaceLaneVecF64x2:
+ return vec.replaceLaneF64x2(value, curr->index);
}
WASM_UNREACHABLE();
}
- Flow visitSIMDShuffle(SIMDShuffle *curr) {
+ Flow visitSIMDShuffle(SIMDShuffle* curr) {
NOTE_ENTER("SIMDShuffle");
Flow flow = this->visit(curr->left);
- if (flow.breaking()) return flow;
+ if (flow.breaking())
+ return flow;
Literal left = flow.value;
flow = this->visit(curr->right);
- if (flow.breaking()) return flow;
+ if (flow.breaking())
+ return flow;
Literal right = flow.value;
return left.shuffleV8x16(right, curr->mask);
}
- Flow visitSIMDBitselect(SIMDBitselect *curr) {
+ Flow visitSIMDBitselect(SIMDBitselect* curr) {
NOTE_ENTER("SIMDBitselect");
Flow flow = this->visit(curr->left);
- if (flow.breaking()) return flow;
+ if (flow.breaking())
+ return flow;
Literal left = flow.value;
flow = this->visit(curr->right);
- if (flow.breaking()) return flow;
+ if (flow.breaking())
+ return flow;
Literal right = flow.value;
flow = this->visit(curr->cond);
- if (flow.breaking()) return flow;
+ if (flow.breaking())
+ return flow;
Literal cond = flow.value;
return cond.bitselectV128(left, right);
}
- Flow visitSIMDShift(SIMDShift *curr) {
+ Flow visitSIMDShift(SIMDShift* curr) {
NOTE_ENTER("SIMDShift");
Flow flow = this->visit(curr->vec);
- if (flow.breaking()) return flow;
+ if (flow.breaking())
+ return flow;
Literal vec = flow.value;
flow = this->visit(curr->shift);
- if (flow.breaking()) return flow;
+ if (flow.breaking())
+ return flow;
Literal shift = flow.value;
switch (curr->op) {
- case ShlVecI8x16: return vec.shlI8x16(shift);
- case ShrSVecI8x16: return vec.shrSI8x16(shift);
- case ShrUVecI8x16: return vec.shrUI8x16(shift);
- case ShlVecI16x8: return vec.shlI16x8(shift);
- case ShrSVecI16x8: return vec.shrSI16x8(shift);
- case ShrUVecI16x8: return vec.shrUI16x8(shift);
- case ShlVecI32x4: return vec.shlI32x4(shift);
- case ShrSVecI32x4: return vec.shrSI32x4(shift);
- case ShrUVecI32x4: return vec.shrUI32x4(shift);
- case ShlVecI64x2: return vec.shlI64x2(shift);
- case ShrSVecI64x2: return vec.shrSI64x2(shift);
- case ShrUVecI64x2: return vec.shrUI64x2(shift);
+ case ShlVecI8x16:
+ return vec.shlI8x16(shift);
+ case ShrSVecI8x16:
+ return vec.shrSI8x16(shift);
+ case ShrUVecI8x16:
+ return vec.shrUI8x16(shift);
+ case ShlVecI16x8:
+ return vec.shlI16x8(shift);
+ case ShrSVecI16x8:
+ return vec.shrSI16x8(shift);
+ case ShrUVecI16x8:
+ return vec.shrUI16x8(shift);
+ case ShlVecI32x4:
+ return vec.shlI32x4(shift);
+ case ShrSVecI32x4:
+ return vec.shrSI32x4(shift);
+ case ShrUVecI32x4:
+ return vec.shrUI32x4(shift);
+ case ShlVecI64x2:
+ return vec.shlI64x2(shift);
+ case ShrSVecI64x2:
+ return vec.shrSI64x2(shift);
+ case ShrUVecI64x2:
+ return vec.shrUI64x2(shift);
}
WASM_UNREACHABLE();
}
- Flow visitSelect(Select *curr) {
+ Flow visitSelect(Select* curr) {
NOTE_ENTER("Select");
Flow ifTrue = visit(curr->ifTrue);
- if (ifTrue.breaking()) return ifTrue;
+ if (ifTrue.breaking())
+ return ifTrue;
Flow ifFalse = visit(curr->ifFalse);
- if (ifFalse.breaking()) return ifFalse;
+ if (ifFalse.breaking())
+ return ifFalse;
Flow condition = visit(curr->condition);
- if (condition.breaking()) return condition;
+ if (condition.breaking())
+ return condition;
NOTE_EVAL1(condition.value);
return condition.value.geti32() ? ifTrue : ifFalse; // ;-)
}
- Flow visitDrop(Drop *curr) {
+ Flow visitDrop(Drop* curr) {
NOTE_ENTER("Drop");
Flow value = visit(curr->value);
- if (value.breaking()) return value;
+ if (value.breaking())
+ return value;
return Flow();
}
- Flow visitReturn(Return *curr) {
+ Flow visitReturn(Return* curr) {
NOTE_ENTER("Return");
Flow flow;
if (curr->value) {
flow = visit(curr->value);
- if (flow.breaking()) return flow;
+ if (flow.breaking())
+ return flow;
NOTE_EVAL1(flow.value);
}
flow.breakTo = RETURN_FLOW;
return flow;
}
- Flow visitNop(Nop *curr) {
+ Flow visitNop(Nop* curr) {
NOTE_ENTER("Nop");
return Flow();
}
- Flow visitUnreachable(Unreachable *curr) {
+ Flow visitUnreachable(Unreachable* curr) {
NOTE_ENTER("Unreachable");
trap("unreachable");
WASM_UNREACHABLE();
@@ -665,19 +923,24 @@ public:
Literal truncSFloat(Unary* curr, Literal value) {
double val = value.getFloat();
- if (std::isnan(val)) trap("truncSFloat of nan");
+ if (std::isnan(val))
+ trap("truncSFloat of nan");
if (curr->type == i32) {
if (value.type == f32) {
- if (!isInRangeI32TruncS(value.reinterpreti32())) trap("i32.truncSFloat overflow");
+ if (!isInRangeI32TruncS(value.reinterpreti32()))
+ trap("i32.truncSFloat overflow");
} else {
- if (!isInRangeI32TruncS(value.reinterpreti64())) trap("i32.truncSFloat overflow");
+ if (!isInRangeI32TruncS(value.reinterpreti64()))
+ trap("i32.truncSFloat overflow");
}
return Literal(int32_t(val));
} else {
if (value.type == f32) {
- if (!isInRangeI64TruncS(value.reinterpreti32())) trap("i64.truncSFloat overflow");
+ if (!isInRangeI64TruncS(value.reinterpreti32()))
+ trap("i64.truncSFloat overflow");
} else {
- if (!isInRangeI64TruncS(value.reinterpreti64())) trap("i64.truncSFloat overflow");
+ if (!isInRangeI64TruncS(value.reinterpreti64()))
+ trap("i64.truncSFloat overflow");
}
return Literal(int64_t(val));
}
@@ -685,19 +948,24 @@ public:
Literal truncUFloat(Unary* curr, Literal value) {
double val = value.getFloat();
- if (std::isnan(val)) trap("truncUFloat of nan");
+ if (std::isnan(val))
+ trap("truncUFloat of nan");
if (curr->type == i32) {
if (value.type == f32) {
- if (!isInRangeI32TruncU(value.reinterpreti32())) trap("i32.truncUFloat overflow");
+ if (!isInRangeI32TruncU(value.reinterpreti32()))
+ trap("i32.truncUFloat overflow");
} else {
- if (!isInRangeI32TruncU(value.reinterpreti64())) trap("i32.truncUFloat overflow");
+ if (!isInRangeI32TruncU(value.reinterpreti64()))
+ trap("i32.truncUFloat overflow");
}
return Literal(uint32_t(val));
} else {
if (value.type == f32) {
- if (!isInRangeI64TruncU(value.reinterpreti32())) trap("i64.truncUFloat overflow");
+ if (!isInRangeI64TruncU(value.reinterpreti32()))
+ trap("i64.truncUFloat overflow");
} else {
- if (!isInRangeI64TruncU(value.reinterpreti64())) trap("i64.truncUFloat overflow");
+ if (!isInRangeI64TruncU(value.reinterpreti64()))
+ trap("i64.truncUFloat overflow");
}
return Literal(uint64_t(val));
}
@@ -708,37 +976,36 @@ public:
Flow visitGetLocal(GetLocal*) { WASM_UNREACHABLE(); }
Flow visitSetLocal(SetLocal*) { WASM_UNREACHABLE(); }
Flow visitSetGlobal(SetGlobal*) { WASM_UNREACHABLE(); }
- Flow visitLoad(Load *curr) { WASM_UNREACHABLE(); }
- Flow visitStore(Store *curr) { WASM_UNREACHABLE(); }
- Flow visitHost(Host *curr) { WASM_UNREACHABLE(); }
- Flow visitMemoryInit(MemoryInit *curr) { WASM_UNREACHABLE(); }
- Flow visitDataDrop(DataDrop *curr) { WASM_UNREACHABLE(); }
- Flow visitMemoryCopy(MemoryCopy *curr) { WASM_UNREACHABLE(); }
- Flow visitMemoryFill(MemoryFill *curr) { WASM_UNREACHABLE(); }
+ Flow visitLoad(Load* curr) { WASM_UNREACHABLE(); }
+ Flow visitStore(Store* curr) { WASM_UNREACHABLE(); }
+ Flow visitHost(Host* curr) { WASM_UNREACHABLE(); }
+ Flow visitMemoryInit(MemoryInit* curr) { WASM_UNREACHABLE(); }
+ Flow visitDataDrop(DataDrop* curr) { WASM_UNREACHABLE(); }
+ Flow visitMemoryCopy(MemoryCopy* curr) { WASM_UNREACHABLE(); }
+ Flow visitMemoryFill(MemoryFill* curr) { WASM_UNREACHABLE(); }
Flow visitAtomicRMW(AtomicRMW*) { WASM_UNREACHABLE(); }
Flow visitAtomicCmpxchg(AtomicCmpxchg*) { WASM_UNREACHABLE(); }
Flow visitAtomicWait(AtomicWait*) { WASM_UNREACHABLE(); }
Flow visitAtomicNotify(AtomicNotify*) { WASM_UNREACHABLE(); }
- virtual void trap(const char* why) {
- WASM_UNREACHABLE();
- }
+ virtual void trap(const char* why) { WASM_UNREACHABLE(); }
};
// Execute an constant expression in a global init or memory offset.
template<typename GlobalManager>
-class ConstantExpressionRunner : public ExpressionRunner<ConstantExpressionRunner<GlobalManager>> {
+class ConstantExpressionRunner
+ : public ExpressionRunner<ConstantExpressionRunner<GlobalManager>> {
GlobalManager& globals;
+
public:
ConstantExpressionRunner(GlobalManager& globals) : globals(globals) {}
- Flow visitGetGlobal(GetGlobal *curr) {
- return Flow(globals[curr->name]);
- }
+ Flow visitGetGlobal(GetGlobal* curr) { return Flow(globals[curr->name]); }
};
//
-// An instance of a WebAssembly module, which can execute it via AST interpretation.
+// An instance of a WebAssembly module, which can execute it via AST
+// interpretation.
//
// To embed this interpreter, you need to provide an ExternalInterface instance
// (see below) which provides the embedding-specific details, that is, how to
@@ -747,8 +1014,7 @@ public:
// To call into the interpreter, use callExport.
//
-template<typename GlobalManager, typename SubType>
-class ModuleInstanceBase {
+template<typename GlobalManager, typename SubType> class ModuleInstanceBase {
public:
//
// You need to implement one of these to create a concrete interpreter. The
@@ -759,7 +1025,10 @@ public:
virtual void init(Module& wasm, SubType& instance) {}
virtual void importGlobals(GlobalManager& globals, Module& wasm) = 0;
virtual Literal callImport(Function* import, LiteralList& arguments) = 0;
- virtual Literal callTable(Index index, LiteralList& arguments, Type result, SubType& instance) = 0;
+ virtual Literal callTable(Index index,
+ LiteralList& arguments,
+ Type result,
+ SubType& instance) = 0;
virtual void growMemory(Address oldSize, Address newSize) = 0;
virtual void trap(const char* why) = 0;
@@ -769,28 +1038,46 @@ public:
switch (load->type) {
case i32: {
switch (load->bytes) {
- case 1: return load->signed_ ? Literal((int32_t)load8s(addr)) : Literal((int32_t)load8u(addr));
- case 2: return load->signed_ ? Literal((int32_t)load16s(addr)) : Literal((int32_t)load16u(addr));
- case 4: return Literal((int32_t)load32s(addr));
- default: WASM_UNREACHABLE();
+ case 1:
+ return load->signed_ ? Literal((int32_t)load8s(addr))
+ : Literal((int32_t)load8u(addr));
+ case 2:
+ return load->signed_ ? Literal((int32_t)load16s(addr))
+ : Literal((int32_t)load16u(addr));
+ case 4:
+ return Literal((int32_t)load32s(addr));
+ default:
+ WASM_UNREACHABLE();
}
break;
}
case i64: {
switch (load->bytes) {
- case 1: return load->signed_ ? Literal((int64_t)load8s(addr)) : Literal((int64_t)load8u(addr));
- case 2: return load->signed_ ? Literal((int64_t)load16s(addr)) : Literal((int64_t)load16u(addr));
- case 4: return load->signed_ ? Literal((int64_t)load32s(addr)) : Literal((int64_t)load32u(addr));
- case 8: return Literal((int64_t)load64s(addr));
- default: WASM_UNREACHABLE();
+ case 1:
+ return load->signed_ ? Literal((int64_t)load8s(addr))
+ : Literal((int64_t)load8u(addr));
+ case 2:
+ return load->signed_ ? Literal((int64_t)load16s(addr))
+ : Literal((int64_t)load16u(addr));
+ case 4:
+ return load->signed_ ? Literal((int64_t)load32s(addr))
+ : Literal((int64_t)load32u(addr));
+ case 8:
+ return Literal((int64_t)load64s(addr));
+ default:
+ WASM_UNREACHABLE();
}
break;
}
- case f32: return Literal(load32u(addr)).castToF32();
- case f64: return Literal(load64u(addr)).castToF64();
- case v128: return Literal(load128(addr).data());
+ case f32:
+ return Literal(load32u(addr)).castToF32();
+ case f64:
+ return Literal(load64u(addr)).castToF64();
+ case v128:
+ return Literal(load128(addr).data());
case none:
- case unreachable: WASM_UNREACHABLE();
+ case unreachable:
+ WASM_UNREACHABLE();
}
WASM_UNREACHABLE();
}
@@ -798,29 +1085,52 @@ public:
switch (store->valueType) {
case i32: {
switch (store->bytes) {
- case 1: store8(addr, value.geti32()); break;
- case 2: store16(addr, value.geti32()); break;
- case 4: store32(addr, value.geti32()); break;
- default: WASM_UNREACHABLE();
+ case 1:
+ store8(addr, value.geti32());
+ break;
+ case 2:
+ store16(addr, value.geti32());
+ break;
+ case 4:
+ store32(addr, value.geti32());
+ break;
+ default:
+ WASM_UNREACHABLE();
}
break;
}
case i64: {
switch (store->bytes) {
- case 1: store8(addr, value.geti64()); break;
- case 2: store16(addr, value.geti64()); break;
- case 4: store32(addr, value.geti64()); break;
- case 8: store64(addr, value.geti64()); break;
- default: WASM_UNREACHABLE();
+ case 1:
+ store8(addr, value.geti64());
+ break;
+ case 2:
+ store16(addr, value.geti64());
+ break;
+ case 4:
+ store32(addr, value.geti64());
+ break;
+ case 8:
+ store64(addr, value.geti64());
+ break;
+ default:
+ WASM_UNREACHABLE();
}
break;
}
// write floats carefully, ensuring all bits reach memory
- case f32: store32(addr, value.reinterpreti32()); break;
- case f64: store64(addr, value.reinterpreti64()); break;
- case v128: store128(addr, value.getv128()); break;
+ case f32:
+ store32(addr, value.reinterpreti32());
+ break;
+ case f64:
+ store64(addr, value.reinterpreti64());
+ break;
+ case v128:
+ store128(addr, value.getv128());
+ break;
case none:
- case unreachable: WASM_UNREACHABLE();
+ case unreachable:
+ WASM_UNREACHABLE();
}
}
@@ -832,34 +1142,39 @@ public:
virtual uint32_t load32u(Address addr) { WASM_UNREACHABLE(); }
virtual int64_t load64s(Address addr) { WASM_UNREACHABLE(); }
virtual uint64_t load64u(Address addr) { WASM_UNREACHABLE(); }
- virtual std::array<uint8_t, 16> load128(Address addr) { WASM_UNREACHABLE(); }
+ virtual std::array<uint8_t, 16> load128(Address addr) {
+ WASM_UNREACHABLE();
+ }
virtual void store8(Address addr, int8_t value) { WASM_UNREACHABLE(); }
virtual void store16(Address addr, int16_t value) { WASM_UNREACHABLE(); }
virtual void store32(Address addr, int32_t value) { WASM_UNREACHABLE(); }
virtual void store64(Address addr, int64_t value) { WASM_UNREACHABLE(); }
- virtual void store128(Address addr, const std::array<uint8_t, 16>&) { WASM_UNREACHABLE(); }
+ virtual void store128(Address addr, const std::array<uint8_t, 16>&) {
+ WASM_UNREACHABLE();
+ }
virtual void tableStore(Address addr, Name entry) { WASM_UNREACHABLE(); }
};
- SubType* self() {
- return static_cast<SubType*>(this);
- }
+ SubType* self() { return static_cast<SubType*>(this); }
Module& wasm;
// Values of globals
GlobalManager globals;
- ModuleInstanceBase(Module& wasm, ExternalInterface* externalInterface) : wasm(wasm), externalInterface(externalInterface) {
+ ModuleInstanceBase(Module& wasm, ExternalInterface* externalInterface)
+ : wasm(wasm), externalInterface(externalInterface) {
// import globals from the outside
externalInterface->importGlobals(globals, wasm);
// prepare memory
memorySize = wasm.memory.initial;
// generate internal (non-imported) globals
ModuleUtils::iterDefinedGlobals(wasm, [&](Global* global) {
- globals[global->name] = ConstantExpressionRunner<GlobalManager>(globals).visit(global->init).value;
+ globals[global->name] = ConstantExpressionRunner<GlobalManager>(globals)
+ .visit(global->init)
+ .value;
});
// initialize the rest of the external interface
@@ -877,22 +1192,23 @@ public:
// call an exported function
Literal callExport(Name name, const LiteralList& arguments) {
- Export *export_ = wasm.getExportOrNull(name);
- if (!export_) externalInterface->trap("callExport not found");
+ Export* export_ = wasm.getExportOrNull(name);
+ if (!export_)
+ externalInterface->trap("callExport not found");
return callFunction(export_->value, arguments);
}
- Literal callExport(Name name) {
- return callExport(name, LiteralList());
- }
+ Literal callExport(Name name) { return callExport(name, LiteralList()); }
// get an exported global
Literal getExport(Name name) {
- Export *export_ = wasm.getExportOrNull(name);
- if (!export_) externalInterface->trap("getExport external not found");
+ Export* export_ = wasm.getExportOrNull(name);
+ if (!export_)
+ externalInterface->trap("getExport external not found");
Name internalName = export_->value;
auto iter = globals.find(internalName);
- if (iter == globals.end()) externalInterface->trap("getExport internal not found");
+ if (iter == globals.end())
+ externalInterface->trap("getExport internal not found");
return iter->second;
}
@@ -917,7 +1233,10 @@ private:
void initializeTableContents() {
for (auto& segment : wasm.table.segments) {
- Address offset = (uint32_t)ConstantExpressionRunner<GlobalManager>(globals).visit(segment.offset).value.geti32();
+ Address offset =
+ (uint32_t)ConstantExpressionRunner<GlobalManager>(globals)
+ .visit(segment.offset)
+ .value.geti32();
if (offset + segment.data.size() > wasm.table.initial) {
externalInterface->trap("invalid offset when initializing table");
}
@@ -965,12 +1284,12 @@ private:
}
class FunctionScope {
- public:
+ public:
std::vector<Literal> locals;
Function* function;
FunctionScope(Function* function, const LiteralList& arguments)
- : function(function) {
+ : function(function) {
if (function->params.size() != arguments.size()) {
std::cerr << "Function `" << function->name << "` expects "
<< function->params.size() << " parameters, got "
@@ -983,9 +1302,9 @@ private:
assert(function->isParam(i));
if (function->params[i] != arguments[i].type) {
std::cerr << "Function `" << function->name << "` expects type "
- << printType(function->params[i])
- << " for parameter " << i << ", got "
- << printType(arguments[i].type) << "." << std::endl;
+ << printType(function->params[i]) << " for parameter "
+ << i << ", got " << printType(arguments[i].type) << "."
+ << std::endl;
WASM_UNREACHABLE();
}
locals[i] = arguments[i];
@@ -997,32 +1316,38 @@ private:
}
};
- // Executes expressions with concrete runtime info, the function and module at runtime
- class RuntimeExpressionRunner : public ExpressionRunner<RuntimeExpressionRunner> {
+ // Executes expressions with concrete runtime info, the function and module at
+ // runtime
+ class RuntimeExpressionRunner
+ : public ExpressionRunner<RuntimeExpressionRunner> {
ModuleInstanceBase& instance;
FunctionScope& scope;
- public:
- RuntimeExpressionRunner(ModuleInstanceBase& instance, FunctionScope& scope) : instance(instance), scope(scope) {}
+ public:
+ RuntimeExpressionRunner(ModuleInstanceBase& instance, FunctionScope& scope)
+ : instance(instance), scope(scope) {}
- Flow generateArguments(const ExpressionList& operands, LiteralList& arguments) {
+ Flow generateArguments(const ExpressionList& operands,
+ LiteralList& arguments) {
NOTE_ENTER_("generateArguments");
arguments.reserve(operands.size());
for (auto expression : operands) {
Flow flow = this->visit(expression);
- if (flow.breaking()) return flow;
+ if (flow.breaking())
+ return flow;
NOTE_EVAL1(flow.value);
arguments.push_back(flow.value);
}
return Flow();
}
- Flow visitCall(Call *curr) {
+ Flow visitCall(Call* curr) {
NOTE_ENTER("Call");
NOTE_NAME(curr->target);
LiteralList arguments;
Flow flow = generateArguments(curr->operands, arguments);
- if (flow.breaking()) return flow;
+ if (flow.breaking())
+ return flow;
auto* func = instance.wasm.getFunction(curr->target);
Flow ret;
if (func->imported()) {
@@ -1035,29 +1360,33 @@ private:
#endif
return ret;
}
- Flow visitCallIndirect(CallIndirect *curr) {
+ Flow visitCallIndirect(CallIndirect* curr) {
NOTE_ENTER("CallIndirect");
LiteralList arguments;
Flow flow = generateArguments(curr->operands, arguments);
- if (flow.breaking()) return flow;
+ if (flow.breaking())
+ return flow;
Flow target = this->visit(curr->target);
- if (target.breaking()) return target;
+ if (target.breaking())
+ return target;
Index index = target.value.geti32();
- return instance.externalInterface->callTable(index, arguments, curr->type, *instance.self());
+ return instance.externalInterface->callTable(
+ index, arguments, curr->type, *instance.self());
}
- Flow visitGetLocal(GetLocal *curr) {
+ Flow visitGetLocal(GetLocal* curr) {
NOTE_ENTER("GetLocal");
auto index = curr->index;
NOTE_EVAL1(index);
NOTE_EVAL1(scope.locals[index]);
return scope.locals[index];
}
- Flow visitSetLocal(SetLocal *curr) {
+ Flow visitSetLocal(SetLocal* curr) {
NOTE_ENTER("SetLocal");
auto index = curr->index;
Flow flow = this->visit(curr->value);
- if (flow.breaking()) return flow;
+ if (flow.breaking())
+ return flow;
NOTE_EVAL1(index);
NOTE_EVAL1(flow.value);
assert(curr->isTee() ? flow.value.type == curr->type : true);
@@ -1065,7 +1394,7 @@ private:
return curr->isTee() ? flow : Flow();
}
- Flow visitGetGlobal(GetGlobal *curr) {
+ Flow visitGetGlobal(GetGlobal* curr) {
NOTE_ENTER("GetGlobal");
auto name = curr->name;
NOTE_EVAL1(name);
@@ -1073,21 +1402,23 @@ private:
NOTE_EVAL1(instance.globals[name]);
return instance.globals[name];
}
- Flow visitSetGlobal(SetGlobal *curr) {
+ Flow visitSetGlobal(SetGlobal* curr) {
NOTE_ENTER("SetGlobal");
auto name = curr->name;
Flow flow = this->visit(curr->value);
- if (flow.breaking()) return flow;
+ if (flow.breaking())
+ return flow;
NOTE_EVAL1(name);
NOTE_EVAL1(flow.value);
instance.globals[name] = flow.value;
return Flow();
}
- Flow visitLoad(Load *curr) {
+ Flow visitLoad(Load* curr) {
NOTE_ENTER("Load");
Flow flow = this->visit(curr->ptr);
- if (flow.breaking()) return flow;
+ if (flow.breaking())
+ return flow;
NOTE_EVAL1(flow);
auto addr = instance.getFinalAddress(curr, flow.value);
auto ret = instance.externalInterface->load(curr, addr);
@@ -1095,12 +1426,14 @@ private:
NOTE_EVAL1(ret);
return ret;
}
- Flow visitStore(Store *curr) {
+ Flow visitStore(Store* curr) {
NOTE_ENTER("Store");
Flow ptr = this->visit(curr->ptr);
- if (ptr.breaking()) return ptr;
+ if (ptr.breaking())
+ return ptr;
Flow value = this->visit(curr->value);
- if (value.breaking()) return value;
+ if (value.breaking())
+ return value;
auto addr = instance.getFinalAddress(curr, ptr.value);
NOTE_EVAL1(addr);
NOTE_EVAL1(value);
@@ -1108,12 +1441,14 @@ private:
return Flow();
}
- Flow visitAtomicRMW(AtomicRMW *curr) {
+ Flow visitAtomicRMW(AtomicRMW* curr) {
NOTE_ENTER("AtomicRMW");
Flow ptr = this->visit(curr->ptr);
- if (ptr.breaking()) return ptr;
+ if (ptr.breaking())
+ return ptr;
auto value = this->visit(curr->value);
- if (value.breaking()) return value;
+ if (value.breaking())
+ return value;
NOTE_EVAL1(ptr);
auto addr = instance.getFinalAddress(curr, ptr.value);
NOTE_EVAL1(addr);
@@ -1122,25 +1457,40 @@ private:
NOTE_EVAL1(loaded);
auto computed = value.value;
switch (curr->op) {
- case Add: computed = computed.add(value.value); break;
- case Sub: computed = computed.sub(value.value); break;
- case And: computed = computed.and_(value.value); break;
- case Or: computed = computed.or_(value.value); break;
- case Xor: computed = computed.xor_(value.value); break;
- case Xchg: computed = value.value; break;
+ case Add:
+ computed = computed.add(value.value);
+ break;
+ case Sub:
+ computed = computed.sub(value.value);
+ break;
+ case And:
+ computed = computed.and_(value.value);
+ break;
+ case Or:
+ computed = computed.or_(value.value);
+ break;
+ case Xor:
+ computed = computed.xor_(value.value);
+ break;
+ case Xchg:
+ computed = value.value;
+ break;
}
instance.doAtomicStore(addr, curr->bytes, computed);
return loaded;
}
- Flow visitAtomicCmpxchg(AtomicCmpxchg *curr) {
+ Flow visitAtomicCmpxchg(AtomicCmpxchg* curr) {
NOTE_ENTER("AtomicCmpxchg");
Flow ptr = this->visit(curr->ptr);
- if (ptr.breaking()) return ptr;
+ if (ptr.breaking())
+ return ptr;
NOTE_EVAL1(ptr);
auto expected = this->visit(curr->expected);
- if (expected.breaking()) return expected;
+ if (expected.breaking())
+ return expected;
auto replacement = this->visit(curr->replacement);
- if (replacement.breaking()) return replacement;
+ if (replacement.breaking())
+ return replacement;
auto addr = instance.getFinalAddress(curr, ptr.value);
NOTE_EVAL1(addr);
NOTE_EVAL1(expected);
@@ -1152,17 +1502,20 @@ private:
}
return loaded;
}
- Flow visitAtomicWait(AtomicWait *curr) {
+ Flow visitAtomicWait(AtomicWait* curr) {
NOTE_ENTER("AtomicWait");
Flow ptr = this->visit(curr->ptr);
- if (ptr.breaking()) return ptr;
+ if (ptr.breaking())
+ return ptr;
NOTE_EVAL1(ptr);
auto expected = this->visit(curr->expected);
NOTE_EVAL1(expected);
- if (expected.breaking()) return expected;
+ if (expected.breaking())
+ return expected;
auto timeout = this->visit(curr->timeout);
NOTE_EVAL1(timeout);
- if (timeout.breaking()) return timeout;
+ if (timeout.breaking())
+ return timeout;
auto bytes = getTypeSize(curr->expectedType);
auto addr = instance.getFinalAddress(ptr.value, bytes);
auto loaded = instance.doAtomicLoad(addr, bytes, curr->expectedType);
@@ -1174,46 +1527,58 @@ private:
// for now, just assume we are woken up
return Literal(int32_t(0)); // woken up
}
- Flow visitAtomicNotify(AtomicNotify *curr) {
+ Flow visitAtomicNotify(AtomicNotify* curr) {
NOTE_ENTER("AtomicNotify");
Flow ptr = this->visit(curr->ptr);
- if (ptr.breaking()) return ptr;
+ if (ptr.breaking())
+ return ptr;
NOTE_EVAL1(ptr);
auto count = this->visit(curr->notifyCount);
NOTE_EVAL1(count);
- if (count.breaking()) return count;
+ if (count.breaking())
+ return count;
// TODO: add threads support!
return Literal(int32_t(0)); // none woken up
}
- Flow visitHost(Host *curr) {
+ Flow visitHost(Host* curr) {
NOTE_ENTER("Host");
switch (curr->op) {
- case CurrentMemory: return Literal(int32_t(instance.memorySize));
- case GrowMemory: {
- auto fail = Literal(int32_t(-1));
- Flow flow = this->visit(curr->operands[0]);
- if (flow.breaking()) return flow;
- int32_t ret = instance.memorySize;
- uint32_t delta = flow.value.geti32();
- if (delta > uint32_t(-1) /Memory::kPageSize) return fail;
- if (instance.memorySize >= uint32_t(-1) - delta) return fail;
- uint32_t newSize = instance.memorySize + delta;
- if (newSize > instance.wasm.memory.max) return fail;
- instance.externalInterface->growMemory(instance.memorySize * Memory::kPageSize, newSize * Memory::kPageSize);
- instance.memorySize = newSize;
- return Literal(int32_t(ret));
- }
+ case CurrentMemory:
+ return Literal(int32_t(instance.memorySize));
+ case GrowMemory: {
+ auto fail = Literal(int32_t(-1));
+ Flow flow = this->visit(curr->operands[0]);
+ if (flow.breaking())
+ return flow;
+ int32_t ret = instance.memorySize;
+ uint32_t delta = flow.value.geti32();
+ if (delta > uint32_t(-1) / Memory::kPageSize)
+ return fail;
+ if (instance.memorySize >= uint32_t(-1) - delta)
+ return fail;
+ uint32_t newSize = instance.memorySize + delta;
+ if (newSize > instance.wasm.memory.max)
+ return fail;
+ instance.externalInterface->growMemory(instance.memorySize *
+ Memory::kPageSize,
+ newSize * Memory::kPageSize);
+ instance.memorySize = newSize;
+ return Literal(int32_t(ret));
+ }
}
WASM_UNREACHABLE();
}
- Flow visitMemoryInit(MemoryInit *curr) {
+ Flow visitMemoryInit(MemoryInit* curr) {
NOTE_ENTER("MemoryInit");
Flow dest = this->visit(curr->dest);
- if (dest.breaking()) return dest;
+ if (dest.breaking())
+ return dest;
Flow offset = this->visit(curr->offset);
- if (offset.breaking()) return offset;
+ if (offset.breaking())
+ return offset;
Flow size = this->visit(curr->size);
- if (size.breaking()) return size;
+ if (size.breaking())
+ return size;
NOTE_EVAL1(dest);
NOTE_EVAL1(offset);
NOTE_EVAL1(size);
@@ -1239,14 +1604,12 @@ private:
trap("out of bounds segment access in memory.init");
}
Literal addr(uint32_t(destVal + i));
- instance.externalInterface->store8(
- instance.getFinalAddress(addr, 1),
- segment.data[offsetVal + i]
- );
+ instance.externalInterface->store8(instance.getFinalAddress(addr, 1),
+ segment.data[offsetVal + i]);
}
return {};
}
- Flow visitDataDrop(DataDrop *curr) {
+ Flow visitDataDrop(DataDrop* curr) {
NOTE_ENTER("DataDrop");
if (instance.droppedSegments.count(curr->segment)) {
trap("data.drop of dropped segment");
@@ -1254,14 +1617,17 @@ private:
instance.droppedSegments.insert(curr->segment);
return {};
}
- Flow visitMemoryCopy(MemoryCopy *curr) {
+ Flow visitMemoryCopy(MemoryCopy* curr) {
NOTE_ENTER("MemoryCopy");
Flow dest = this->visit(curr->dest);
- if (dest.breaking()) return dest;
+ if (dest.breaking())
+ return dest;
Flow source = this->visit(curr->source);
- if (source.breaking()) return source;
+ if (source.breaking())
+ return source;
Flow size = this->visit(curr->size);
- if (size.breaking()) return size;
+ if (size.breaking())
+ return size;
NOTE_EVAL1(dest);
NOTE_EVAL1(source);
NOTE_EVAL1(size);
@@ -1293,14 +1659,17 @@ private:
}
return {};
}
- Flow visitMemoryFill(MemoryFill *curr) {
+ Flow visitMemoryFill(MemoryFill* curr) {
NOTE_ENTER("MemoryFill");
Flow dest = this->visit(curr->dest);
- if (dest.breaking()) return dest;
+ if (dest.breaking())
+ return dest;
Flow value = this->visit(curr->value);
- if (value.breaking()) return value;
+ if (value.breaking())
+ return value;
Flow size = this->visit(curr->size);
- if (size.breaking()) return size;
+ if (size.breaking())
+ return size;
NOTE_EVAL1(dest);
NOTE_EVAL1(value);
NOTE_EVAL1(size);
@@ -1325,40 +1694,45 @@ private:
public:
// Call a function, starting an invocation.
Literal callFunction(Name name, const LiteralList& arguments) {
- // if the last call ended in a jump up the stack, it might have left stuff for us to clean up here
+ // if the last call ended in a jump up the stack, it might have left stuff
+ // for us to clean up here
callDepth = 0;
functionStack.clear();
return callFunctionInternal(name, arguments);
}
- // Internal function call. Must be public so that callTable implementations can use it (refactor?)
+ // Internal function call. Must be public so that callTable implementations
+ // can use it (refactor?)
Literal callFunctionInternal(Name name, const LiteralList& arguments) {
- if (callDepth > maxCallDepth) externalInterface->trap("stack limit");
+ if (callDepth > maxCallDepth)
+ externalInterface->trap("stack limit");
auto previousCallDepth = callDepth;
callDepth++;
auto previousFunctionStackSize = functionStack.size();
functionStack.push_back(name);
- Function *function = wasm.getFunction(name);
+ Function* function = wasm.getFunction(name);
assert(function);
FunctionScope scope(function, arguments);
#ifdef WASM_INTERPRETER_DEBUG
- std::cout << "entering " << function->name
- << "\n with arguments:\n";
+ std::cout << "entering " << function->name << "\n with arguments:\n";
for (unsigned i = 0; i < arguments.size(); ++i) {
std::cout << " $" << i << ": " << arguments[i] << '\n';
}
#endif
Flow flow = RuntimeExpressionRunner(*this, scope).visit(function->body);
- assert(!flow.breaking() || flow.breakTo == RETURN_FLOW); // cannot still be breaking, it means we missed our stop
+ // cannot still be breaking, it means we missed our stop
+ assert(!flow.breaking() || flow.breakTo == RETURN_FLOW);
Literal ret = flow.value;
if (function->result != ret.type) {
- std::cerr << "calling " << function->name << " resulted in " << ret << " but the function type is " << function->result << '\n';
+ std::cerr << "calling " << function->name << " resulted in " << ret
+ << " but the function type is " << function->result << '\n';
WASM_UNREACHABLE();
}
- callDepth = previousCallDepth; // may decrease more than one, if we jumped up the stack
+ // may decrease more than one, if we jumped up the stack
+ callDepth = previousCallDepth;
// if we jumped up the stack, we also need to pop higher frames
while (functionStack.size() > previousFunctionStackSize) {
functionStack.pop_back();
@@ -1370,7 +1744,6 @@ public:
}
protected:
-
Address memorySize; // in pages
void trapIfGt(uint64_t lhs, uint64_t rhs, const char* msg) {
@@ -1381,8 +1754,7 @@ protected:
}
}
- template<class LS>
- Address getFinalAddress(LS* curr, Literal ptr) {
+ template<class LS> Address getFinalAddress(LS* curr, Literal ptr) {
Address memorySizeBytes = memorySize * Memory::kPageSize;
uint64_t addr = ptr.type == i32 ? ptr.geti32() : ptr.geti64();
trapIfGt(curr->offset, memorySizeBytes, "offset > memory");
@@ -1442,9 +1814,11 @@ protected:
// The default ModuleInstance uses a trivial global manager
using TrivialGlobalManager = std::map<Name, Literal>;
-class ModuleInstance : public ModuleInstanceBase<TrivialGlobalManager, ModuleInstance> {
+class ModuleInstance
+ : public ModuleInstanceBase<TrivialGlobalManager, ModuleInstance> {
public:
- ModuleInstance(Module& wasm, ExternalInterface* externalInterface) : ModuleInstanceBase(wasm, externalInterface) {}
+ ModuleInstance(Module& wasm, ExternalInterface* externalInterface)
+ : ModuleInstanceBase(wasm, externalInterface) {}
};
} // namespace wasm
diff --git a/src/wasm-io.h b/src/wasm-io.h
index 6d8dcc6e5..9c772f115 100644
--- a/src/wasm-io.h
+++ b/src/wasm-io.h
@@ -21,9 +21,9 @@
#ifndef wasm_wasm_io_h
#define wasm_wasm_io_h
-#include "wasm.h"
#include "parsing.h"
#include "support/file.h"
+#include "wasm.h"
namespace wasm {
@@ -40,12 +40,13 @@ public:
// read text
void readText(std::string filename, Module& wasm);
// read binary
- void readBinary(std::string filename, Module& wasm,
- std::string sourceMapFilename="");
+ void readBinary(std::string filename,
+ Module& wasm,
+ std::string sourceMapFilename = "");
// read text or binary, checking the contents for what it is. If `filename` is
// empty, read from stdin.
- void read(std::string filename, Module& wasm,
- std::string sourceMapFilename="");
+ void
+ read(std::string filename, Module& wasm, std::string sourceMapFilename = "");
// check whether a file is a wasm binary
bool isBinaryFile(std::string filename);
@@ -64,8 +65,12 @@ public:
void setBinary(bool binary_) { binary = binary_; }
void setDebugInfo(bool debugInfo_) { debugInfo = debugInfo_; }
void setSymbolMap(std::string symbolMap_) { symbolMap = symbolMap_; }
- void setSourceMapFilename(std::string sourceMapFilename_) { sourceMapFilename = sourceMapFilename_; }
- void setSourceMapUrl(std::string sourceMapUrl_) { sourceMapUrl = sourceMapUrl_; }
+ void setSourceMapFilename(std::string sourceMapFilename_) {
+ sourceMapFilename = sourceMapFilename_;
+ }
+ void setSourceMapUrl(std::string sourceMapUrl_) {
+ sourceMapUrl = sourceMapUrl_;
+ }
// write text
void writeText(Module& wasm, Output& output);
@@ -80,6 +85,6 @@ public:
void write(Module& wasm, std::string filename);
};
-}
+} // namespace wasm
#endif // wasm_wasm_io_h
diff --git a/src/wasm-module-building.h b/src/wasm-module-building.h
index d1f8f5504..6f9a58eeb 100644
--- a/src/wasm-module-building.h
+++ b/src/wasm-module-building.h
@@ -17,14 +17,20 @@
#ifndef wasm_wasm_module_building_h
#define wasm_wasm_module_building_h
-#include <wasm.h>
#include <support/threads.h>
+#include <wasm.h>
namespace wasm {
#ifdef BINARYEN_THREAD_DEBUG
static std::mutex debug;
-#define DEBUG_THREAD(x) { std::lock_guard<std::mutex> lock(debug); std::cerr << "[OptimizingIncrementalModuleBuilder Threading (thread: " << std::this_thread::get_id() << ")] " << x; std::cerr << '\n'; }
+#define DEBUG_THREAD(x) \
+ { \
+ std::lock_guard<std::mutex> lock(debug); \
+ std::cerr << "[OptimizingIncrementalModuleBuilder Threading (thread: " \
+ << std::this_thread::get_id() << ")] " << x; \
+ std::cerr << '\n'; \
+ }
#else
#define DEBUG_THREAD(x)
#endif
@@ -81,13 +87,14 @@ class OptimizingIncrementalModuleBuilder {
Module* wasm;
uint32_t numFunctions;
PassOptions passOptions;
- std::function<void (PassRunner&)> addPrePasses;
+ std::function<void(PassRunner&)> addPrePasses;
Function* endMarker;
std::atomic<Function*>* list;
uint32_t nextFunction; // only used on main thread
uint32_t numWorkers;
std::vector<std::unique_ptr<std::thread>> threads;
- std::atomic<uint32_t> liveWorkers, activeWorkers, availableFuncs, finishedFuncs;
+ std::atomic<uint32_t> liveWorkers, activeWorkers, availableFuncs,
+ finishedFuncs;
std::mutex mutex;
std::condition_variable condition;
bool finishing;
@@ -95,16 +102,20 @@ class OptimizingIncrementalModuleBuilder {
bool validateGlobally;
public:
- // numFunctions must be equal to the number of functions allocated, or higher. Knowing
- // this bounds helps avoid locking.
- OptimizingIncrementalModuleBuilder(Module* wasm, Index numFunctions, PassOptions passOptions,
- std::function<void (PassRunner&)> addPrePasses,
- bool debug, bool validateGlobally)
- : wasm(wasm), numFunctions(numFunctions), passOptions(passOptions),
- addPrePasses(addPrePasses),
- endMarker(nullptr), list(nullptr), nextFunction(0),
- numWorkers(0), liveWorkers(0), activeWorkers(0), availableFuncs(0), finishedFuncs(0),
- finishing(false), debug(debug), validateGlobally(validateGlobally) {
+ // numFunctions must be equal to the number of functions allocated, or higher.
+ // Knowing this bounds helps avoid locking.
+ OptimizingIncrementalModuleBuilder(
+ Module* wasm,
+ Index numFunctions,
+ PassOptions passOptions,
+ std::function<void(PassRunner&)> addPrePasses,
+ bool debug,
+ bool validateGlobally)
+ : wasm(wasm), numFunctions(numFunctions), passOptions(passOptions),
+ addPrePasses(addPrePasses), endMarker(nullptr), list(nullptr),
+ nextFunction(0), numWorkers(0), liveWorkers(0), activeWorkers(0),
+ availableFuncs(0), finishedFuncs(0), finishing(false), debug(debug),
+ validateGlobally(validateGlobally) {
if (!useWorkers()) {
// if we shouldn't use threads, don't
@@ -112,7 +123,8 @@ public:
}
// Before parallelism, create all passes on the main thread here, to ensure
- // prepareToRun() is called for each pass before we start to optimize functions.
+ // prepareToRun() is called for each pass before we start to optimize
+ // functions.
{
PassRunner passRunner(wasm, passOptions);
addPrePasses(passRunner);
@@ -132,7 +144,9 @@ public:
// worth it to use threads
liveWorkers.store(0);
activeWorkers.store(0);
- for (uint32_t i = 0; i < numWorkers; i++) { // TODO: one less, and add it at the very end, to not compete with main thread?
+ // TODO: one less, and add it at the very end, to not compete with main
+ // thread?
+ for (uint32_t i = 0; i < numWorkers; i++) {
createWorker();
}
waitUntilAllReady();
@@ -148,13 +162,15 @@ public:
}
bool useWorkers() {
- return numFunctions > 0 && !debug && ThreadPool::getNumCores() > 1 && !PassRunner::getPassDebug();
+ return numFunctions > 0 && !debug && ThreadPool::getNumCores() > 1 &&
+ !PassRunner::getPassDebug();
}
// Add a function to the module, and to be optimized
void addFunction(Function* func) {
wasm->addFunction(func);
- if (!useWorkers()) return; // we optimize at the end in that case
+ if (!useWorkers())
+ return; // we optimize at the end in that case
queueFunction(func);
// notify workers if needed
auto notify = availableFuncs.load();
@@ -183,7 +199,8 @@ public:
notifyAllWorkers();
waitUntilAllFinished();
}
- // TODO: clear side thread allocators from module allocator, as these threads were transient
+ // TODO: clear side thread allocators from module allocator, as these
+ // threads were transient
}
private:
@@ -208,7 +225,8 @@ private:
DEBUG_THREAD("wait until all workers are ready");
std::unique_lock<std::mutex> lock(mutex);
if (liveWorkers.load() < numWorkers) {
- condition.wait(lock, [this]() { return liveWorkers.load() == numWorkers; });
+ condition.wait(lock,
+ [this]() { return liveWorkers.load() == numWorkers; });
}
}
@@ -222,13 +240,15 @@ private:
}
}
DEBUG_THREAD("joining");
- for (auto& thread : threads) thread->join();
+ for (auto& thread : threads)
+ thread->join();
DEBUG_THREAD("joined");
}
void queueFunction(Function* func) {
DEBUG_THREAD("queue function");
- assert(nextFunction < numFunctions); // TODO: if we are given more than we expected, use a slower work queue?
+ // TODO: if we are given more than we expected, use a slower work queue?
+ assert(nextFunction < numFunctions);
list[nextFunction++].store(func);
availableFuncs++;
}
@@ -264,7 +284,8 @@ private:
self->activeWorkers--;
{
std::unique_lock<std::mutex> lock(self->mutex);
- if (!self->finishing) { // while waiting for the lock, things may have ended
+ // while waiting for the lock, things may have ended
+ if (!self->finishing) {
self->condition.wait(lock);
}
}
diff --git a/src/wasm-printing.h b/src/wasm-printing.h
index d3327aa4c..712dd3c1f 100644
--- a/src/wasm-printing.h
+++ b/src/wasm-printing.h
@@ -19,8 +19,8 @@
#include <ostream>
-#include "wasm.h"
#include "pass.h"
+#include "wasm.h"
namespace wasm {
@@ -29,11 +29,16 @@ struct WasmPrinter {
static std::ostream& printModule(Module* module);
- static std::ostream& printExpression(Expression* expression, std::ostream& o, bool minify = false, bool full = false);
+ static std::ostream& printExpression(Expression* expression,
+ std::ostream& o,
+ bool minify = false,
+ bool full = false);
- static std::ostream& printStackInst(StackInst* inst, std::ostream& o, Function* func=nullptr);
+ static std::ostream&
+ printStackInst(StackInst* inst, std::ostream& o, Function* func = nullptr);
- static std::ostream& printStackIR(StackIR* ir, std::ostream& o, Function* func=nullptr);
+ static std::ostream&
+ printStackIR(StackIR* ir, std::ostream& o, Function* func = nullptr);
};
} // namespace wasm
diff --git a/src/wasm-s-parser.h b/src/wasm-s-parser.h
index 295e6b6c9..004fd9840 100644
--- a/src/wasm-s-parser.h
+++ b/src/wasm-s-parser.h
@@ -22,20 +22,21 @@
#ifndef wasm_wasm_s_parser_h
#define wasm_wasm_s_parser_h
-#include "wasm.h"
#include "mixed_arena.h"
#include "parsing.h" // for UniqueNameMapper. TODO: move dependency to cpp file?
+#include "wasm.h"
namespace wasm {
-class SourceLocation
-{
+class SourceLocation {
public:
cashew::IString filename;
uint32_t line;
uint32_t column;
- SourceLocation(cashew::IString filename_, uint32_t line_, uint32_t column_ = 0)
- : filename(filename_), line(line_), column(column_) {}
+ SourceLocation(cashew::IString filename_,
+ uint32_t line_,
+ uint32_t column_ = 0)
+ : filename(filename_), line(line_), column(column_) {}
};
//
@@ -59,7 +60,7 @@ public:
bool quoted() const { return isStr() && quoted_; }
size_t line = -1;
- size_t col = -1;
+ size_t col = -1;
// original locations at the start/end of the S-Expression list
SourceLocation* startLoc = nullptr;
SourceLocation* endLoc = nullptr;
@@ -67,9 +68,7 @@ public:
// list methods
List& list();
Element* operator[](unsigned i);
- size_t size() {
- return list().size();
- }
+ size_t size() { return list().size(); }
// string methods
cashew::IString str() const;
@@ -116,15 +115,19 @@ class SExpressionWasmBuilder {
std::vector<Name> globalNames;
int functionCounter;
int globalCounter = 0;
- std::map<Name, Type> functionTypes; // we need to know function return types before we parse their contents
+ // we need to know function return types before we parse their contents
+ std::map<Name, Type> functionTypes;
std::unordered_map<cashew::IString, Index> debugInfoFileIndices;
public:
// Assumes control of and modifies the input.
- SExpressionWasmBuilder(Module& wasm, Element& module, Name* moduleName = nullptr);
+ SExpressionWasmBuilder(Module& wasm,
+ Element& module,
+ Name* moduleName = nullptr);
private:
- // pre-parse types and function definitions, so we know function return types before parsing their contents
+ // pre-parse types and function definitions, so we know function return types
+ // before parsing their contents
void preParseFunctionType(Element& s);
bool isImport(Element& curr);
void preParseImports(Element& curr);
@@ -142,30 +145,27 @@ private:
Name getFunctionName(Element& s);
Name getFunctionTypeName(Element& s);
Name getGlobalName(Element& s);
- void parseStart(Element& s) { wasm.addStart(getFunctionName(*s[1]));}
+ void parseStart(Element& s) { wasm.addStart(getFunctionName(*s[1])); }
// returns the next index in s
size_t parseFunctionNames(Element& s, Name& name, Name& exportName);
void parseFunction(Element& s, bool preParseImport = false);
- Type stringToType(cashew::IString str, bool allowError=false, bool prefix=false) {
+ Type stringToType(cashew::IString str,
+ bool allowError = false,
+ bool prefix = false) {
return stringToType(str.str, allowError, prefix);
}
- Type stringToType(const char* str, bool allowError=false, bool prefix=false);
+ Type
+ stringToType(const char* str, bool allowError = false, bool prefix = false);
Type stringToLaneType(const char* str);
- bool isType(cashew::IString str) {
- return stringToType(str, true) != none;
- }
+ bool isType(cashew::IString str) { return stringToType(str, true) != none; }
public:
- Expression* parseExpression(Element* s) {
- return parseExpression(*s);
- }
+ Expression* parseExpression(Element* s) { return parseExpression(*s); }
Expression* parseExpression(Element& s);
- MixedArena& getAllocator() {
- return allocator;
- }
+ MixedArena& getAllocator() { return allocator; }
private:
Expression* makeExpression(Element& s);
@@ -188,8 +188,10 @@ private:
Expression* makeLoad(Element& s, Type type, bool isAtomic);
Expression* makeStore(Element& s, Type type, bool isAtomic);
Expression* makeAtomicRMWOrCmpxchg(Element& s, Type type);
- Expression* makeAtomicRMW(Element& s, Type type, uint8_t bytes, const char* extra);
- Expression* makeAtomicCmpxchg(Element& s, Type type, uint8_t bytes, const char* extra);
+ Expression*
+ makeAtomicRMW(Element& s, Type type, uint8_t bytes, const char* extra);
+ Expression*
+ makeAtomicCmpxchg(Element& s, Type type, uint8_t bytes, const char* extra);
Expression* makeAtomicWait(Element& s, Type type);
Expression* makeAtomicNotify(Element& s);
Expression* makeSIMDExtract(Element& s, SIMDExtractOp op, size_t lanes);
diff --git a/src/wasm-stack.h b/src/wasm-stack.h
index afef2632b..124b70926 100644
--- a/src/wasm-stack.h
+++ b/src/wasm-stack.h
@@ -17,11 +17,11 @@
#ifndef wasm_stack_h
#define wasm_stack_h
-#include "wasm.h"
-#include "wasm-binary.h"
-#include "wasm-traversal.h"
#include "ir/branch-utils.h"
#include "pass.h"
+#include "wasm-binary.h"
+#include "wasm-traversal.h"
+#include "wasm.h"
namespace wasm {
@@ -40,8 +40,8 @@ namespace wasm {
// IR (so that we have just a single IR).
// A StackIR instance (see wasm.h) contains a linear sequence of
-// stack instructions. This representation is very simple: just a single vector of
-// all instructions, in order.
+// stack instructions. This representation is very simple: just a single vector
+// of all instructions, in order.
// * nullptr is allowed in the vector, representing something to skip.
// This is useful as a common thing optimizations do is remove instructions,
// so this way we can do so without compacting the vector all the time.
@@ -66,12 +66,14 @@ public:
Expression* origin; // the expression this originates from
- Type type; // the type - usually identical to the origin type, but
- // e.g. wasm has no unreachable blocks, they must be none
+ // the type - usually identical to the origin type, but e.g. wasm has no
+ // unreachable blocks, they must be none
+ Type type;
};
//
-// StackWriter: Writes out binary format stack machine code for a Binaryen IR expression
+// StackWriter: Writes out binary format stack machine code for a Binaryen IR
+// expression
//
// A stack writer has one of three modes:
// * Binaryen2Binary: directly writes the expression to wasm binary
@@ -89,23 +91,27 @@ public:
// downside.
//
-enum class StackWriterMode {
- Binaryen2Binary, Binaryen2Stack, Stack2Binary
-};
+enum class StackWriterMode { Binaryen2Binary, Binaryen2Stack, Stack2Binary };
template<StackWriterMode Mode, typename Parent>
class StackWriter : public Visitor<StackWriter<Mode, Parent>> {
public:
- StackWriter(Parent& parent, BufferWithRandomAccess& o, bool sourceMap=false, bool debug=false)
- : parent(parent), o(o), sourceMap(sourceMap), debug(debug), allocator(parent.getModule()->allocator) {}
+ StackWriter(Parent& parent,
+ BufferWithRandomAccess& o,
+ bool sourceMap = false,
+ bool debug = false)
+ : parent(parent), o(o), sourceMap(sourceMap), debug(debug),
+ allocator(parent.getModule()->allocator) {}
StackIR stackIR; // filled in Binaryen2Stack, read in Stack2Binary
- std::map<Type, size_t> numLocalsByType; // type => number of locals of that type in the compact form
+ // type => number of locals of that type in the compact form
+ std::map<Type, size_t> numLocalsByType;
// visits a node, emitting the proper code for it
void visit(Expression* curr);
- // emits a node, but if it is a block with no name, emit a list of its contents
+ // emits a node, but if it is a block with no name, emit a list of its
+ // contents
void visitPossibleBlockContents(Expression* curr);
// visits a child node. (in some modes we may not want to visit children,
// that logic is handled here)
@@ -162,9 +168,7 @@ public:
// non-control flow expressions.
bool justAddToStack(Expression* curr);
- void setFunction(Function* funcInit) {
- func = funcInit;
- }
+ void setFunction(Function* funcInit) { func = funcInit; }
void mapLocalsAndEmitHeader();
@@ -178,7 +182,8 @@ protected:
Function* func;
- std::map<Index, size_t> mappedLocals; // local index => index in compact form of [all int32s][all int64s]etc
+ // local index => index in compact form of [all int32s][all int64s]etc
+ std::map<Index, size_t> mappedLocals;
std::vector<Name> breakStack;
@@ -195,20 +200,31 @@ protected:
// Write out a single expression, such as an offset for a global segment.
template<typename Parent>
-class ExpressionStackWriter : StackWriter<StackWriterMode::Binaryen2Binary, Parent> {
+class ExpressionStackWriter
+ : StackWriter<StackWriterMode::Binaryen2Binary, Parent> {
public:
- ExpressionStackWriter(Expression* curr, Parent& parent, BufferWithRandomAccess& o, bool debug=false) :
- StackWriter<StackWriterMode::Binaryen2Binary, Parent>(parent, o, /* sourceMap= */ false, debug) {
+ ExpressionStackWriter(Expression* curr,
+ Parent& parent,
+ BufferWithRandomAccess& o,
+ bool debug = false)
+ : StackWriter<StackWriterMode::Binaryen2Binary, Parent>(
+ parent, o, /* sourceMap= */ false, debug) {
this->visit(curr);
}
};
// Write out a function body, including the local header info.
template<typename Parent>
-class FunctionStackWriter : StackWriter<StackWriterMode::Binaryen2Binary, Parent> {
+class FunctionStackWriter
+ : StackWriter<StackWriterMode::Binaryen2Binary, Parent> {
public:
- FunctionStackWriter(Function* funcInit, Parent& parent, BufferWithRandomAccess& o, bool sourceMap=false, bool debug=false) :
- StackWriter<StackWriterMode::Binaryen2Binary, Parent>(parent, o, sourceMap, debug) {
+ FunctionStackWriter(Function* funcInit,
+ Parent& parent,
+ BufferWithRandomAccess& o,
+ bool sourceMap = false,
+ bool debug = false)
+ : StackWriter<StackWriterMode::Binaryen2Binary, Parent>(
+ parent, o, sourceMap, debug) {
this->setFunction(funcInit);
this->mapLocalsAndEmitHeader();
this->visitPossibleBlockContents(this->func->body);
@@ -218,14 +234,20 @@ public:
// Use Stack IR to write the function body
template<typename Parent>
-class StackIRFunctionStackWriter : StackWriter<StackWriterMode::Stack2Binary, Parent> {
+class StackIRFunctionStackWriter
+ : StackWriter<StackWriterMode::Stack2Binary, Parent> {
public:
- StackIRFunctionStackWriter(Function* funcInit, Parent& parent, BufferWithRandomAccess& o, bool debug=false) :
- StackWriter<StackWriterMode::Stack2Binary, Parent>(parent, o, false, debug) {
+ StackIRFunctionStackWriter(Function* funcInit,
+ Parent& parent,
+ BufferWithRandomAccess& o,
+ bool debug = false)
+ : StackWriter<StackWriterMode::Stack2Binary, Parent>(
+ parent, o, false, debug) {
this->setFunction(funcInit);
this->mapLocalsAndEmitHeader();
for (auto* inst : *funcInit->stackIR) {
- if (!inst) continue; // a nullptr is just something we can skip
+ if (!inst)
+ continue; // a nullptr is just something we can skip
switch (inst->op) {
case StackInst::Basic:
case StackInst::BlockBegin:
@@ -250,7 +272,8 @@ public:
this->visitLoopEnd(inst->origin->template cast<Loop>());
break;
}
- default: WASM_UNREACHABLE();
+ default:
+ WASM_UNREACHABLE();
}
}
this->finishFunctionBody();
@@ -280,7 +303,8 @@ void StackWriter<Mode, Parent>::mapLocalsAndEmitHeader() {
for (Index i = func->getVarIndexBase(); i < func->getNumLocals(); i++) {
size_t index = func->getVarIndexBase();
Type type = func->getLocalType(i);
- currLocalsByType[type]++; // increment now for simplicity, must decrement it in returns
+ // increment now for simplicity, must decrement it in returns
+ currLocalsByType[type]++;
if (type == i32) {
mappedLocals[i] = index + currLocalsByType[i32] - 1;
continue;
@@ -308,18 +332,19 @@ void StackWriter<Mode, Parent>::mapLocalsAndEmitHeader() {
WASM_UNREACHABLE();
}
// Emit them.
- o << U32LEB(
- (numLocalsByType[i32] ? 1 : 0) +
- (numLocalsByType[i64] ? 1 : 0) +
- (numLocalsByType[f32] ? 1 : 0) +
- (numLocalsByType[f64] ? 1 : 0) +
- (numLocalsByType[v128] ? 1 : 0)
- );
- if (numLocalsByType[i32]) o << U32LEB(numLocalsByType[i32]) << binaryType(i32);
- if (numLocalsByType[i64]) o << U32LEB(numLocalsByType[i64]) << binaryType(i64);
- if (numLocalsByType[f32]) o << U32LEB(numLocalsByType[f32]) << binaryType(f32);
- if (numLocalsByType[f64]) o << U32LEB(numLocalsByType[f64]) << binaryType(f64);
- if (numLocalsByType[v128]) o << U32LEB(numLocalsByType[v128]) << binaryType(v128);
+ o << U32LEB((numLocalsByType[i32] ? 1 : 0) + (numLocalsByType[i64] ? 1 : 0) +
+ (numLocalsByType[f32] ? 1 : 0) + (numLocalsByType[f64] ? 1 : 0) +
+ (numLocalsByType[v128] ? 1 : 0));
+ if (numLocalsByType[i32])
+ o << U32LEB(numLocalsByType[i32]) << binaryType(i32);
+ if (numLocalsByType[i64])
+ o << U32LEB(numLocalsByType[i64]) << binaryType(i64);
+ if (numLocalsByType[f32])
+ o << U32LEB(numLocalsByType[f32]) << binaryType(f32);
+ if (numLocalsByType[f64])
+ o << U32LEB(numLocalsByType[f64]) << binaryType(f64);
+ if (numLocalsByType[v128])
+ o << U32LEB(numLocalsByType[v128]) << binaryType(v128);
}
template<StackWriterMode Mode, typename Parent>
@@ -366,7 +391,8 @@ void StackWriter<Mode, Parent>::visitBlock(Block* curr) {
o << int8_t(BinaryConsts::Block);
o << binaryType(curr->type != unreachable ? curr->type : none);
}
- breakStack.push_back(curr->name); // TODO: we don't need to do this in Binaryen2Stack
+ // TODO: we don't need to do this in Binaryen2Stack
+ breakStack.push_back(curr->name);
};
auto visitChildren = [this](Block* curr, Index from) {
auto& list = curr->list;
@@ -390,8 +416,7 @@ void StackWriter<Mode, Parent>::visitBlock(Block* curr) {
if (!curr->list.empty() && curr->list[0]->is<Block>()) {
std::vector<Block*> parents;
Block* child;
- while (!curr->list.empty() &&
- (child = curr->list[0]->dynCast<Block>())) {
+ while (!curr->list.empty() && (child = curr->list[0]->dynCast<Block>())) {
parents.push_back(curr);
tilChildren(curr);
curr = child;
@@ -420,10 +445,10 @@ void StackWriter<Mode, Parent>::visitBlock(Block* curr) {
template<StackWriterMode Mode, typename Parent>
void StackWriter<Mode, Parent>::visitBlockEnd(Block* curr) {
if (curr->type == unreachable) {
- // an unreachable block is one that cannot be exited. We cannot encode this directly
- // in wasm, where blocks must be none,i32,i64,f32,f64. Since the block cannot be
- // exited, we can emit an unreachable at the end, and that will always be valid,
- // and then the block is ok as a none
+ // an unreachable block is one that cannot be exited. We cannot encode this
+ // directly in wasm, where blocks must be none,i32,i64,f32,f64. Since the
+ // block cannot be exited, we can emit an unreachable at the end, and that
+ // will always be valid, and then the block is ok as a none
emitExtraUnreachable();
}
if (Mode == StackWriterMode::Binaryen2Stack) {
@@ -434,7 +459,8 @@ void StackWriter<Mode, Parent>::visitBlockEnd(Block* curr) {
assert(!breakStack.empty());
breakStack.pop_back();
if (curr->type == unreachable) {
- // and emit an unreachable *outside* the block too, so later things can pop anything
+ // and emit an unreachable *outside* the block too, so later things can pop
+ // anything
emitExtraUnreachable();
}
}
@@ -455,10 +481,12 @@ void StackWriter<Mode, Parent>::visitIf(If* curr) {
o << int8_t(BinaryConsts::If);
o << binaryType(curr->type != unreachable ? curr->type : none);
}
- breakStack.push_back(IMPOSSIBLE_CONTINUE); // the binary format requires this; we have a block if we need one
- // TODO: optimize this in Stack IR (if child is a block, we
- // may break to this instead)
- visitPossibleBlockContents(curr->ifTrue); // TODO: emit block contents directly, if possible
+ // the binary format requires this; we have a block if we need one
+ // TODO: optimize this in Stack IR (if child is a block, we may break to this
+ // instead)
+ breakStack.push_back(IMPOSSIBLE_CONTINUE);
+ // TODO: emit block contents directly, if possible
+ visitPossibleBlockContents(curr->ifTrue);
if (Mode == StackWriterMode::Stack2Binary) {
return;
}
@@ -491,10 +519,11 @@ void StackWriter<Mode, Parent>::visitIfEnd(If* curr) {
o << int8_t(BinaryConsts::End);
}
if (curr->type == unreachable) {
- // we already handled the case of the condition being unreachable. otherwise,
- // we may still be unreachable, if we are an if-else with both sides unreachable.
- // wasm does not allow this to be emitted directly, so we must do something more. we could do
- // better, but for now we emit an extra unreachable instruction after the if, so it is not consumed itself,
+ // we already handled the case of the condition being unreachable.
+ // otherwise, we may still be unreachable, if we are an if-else with both
+ // sides unreachable. wasm does not allow this to be emitted directly, so we
+ // must do something more. we could do better, but for now we emit an extra
+ // unreachable instruction after the if, so it is not consumed itself,
assert(curr->ifFalse);
emitExtraUnreachable();
}
@@ -541,7 +570,8 @@ void StackWriter<Mode, Parent>::visitBreak(Break* curr) {
if (curr->value) {
visitChild(curr->value);
}
- if (curr->condition) visitChild(curr->condition);
+ if (curr->condition)
+ visitChild(curr->condition);
if (!justAddToStack(curr)) {
o << int8_t(curr->condition ? BinaryConsts::BrIf : BinaryConsts::Br)
<< U32LEB(getBreakIndex(curr->name));
@@ -571,7 +601,8 @@ void StackWriter<Mode, Parent>::visitSwitch(Switch* curr) {
emitExtraUnreachable();
return;
}
- if (justAddToStack(curr)) return;
+ if (justAddToStack(curr))
+ return;
o << int8_t(BinaryConsts::TableSwitch) << U32LEB(curr->targets.size());
for (auto target : curr->targets) {
o << U32LEB(getBreakIndex(target));
@@ -585,9 +616,11 @@ void StackWriter<Mode, Parent>::visitCall(Call* curr) {
visitChild(operand);
}
if (!justAddToStack(curr)) {
- o << int8_t(BinaryConsts::CallFunction) << U32LEB(parent.getFunctionIndex(curr->target));
+ o << int8_t(BinaryConsts::CallFunction)
+ << U32LEB(parent.getFunctionIndex(curr->target));
}
- if (curr->type == unreachable) { // TODO FIXME: this and similar can be removed
+ // TODO FIXME: this and similar can be removed
+ if (curr->type == unreachable) {
emitExtraUnreachable();
}
}
@@ -610,7 +643,8 @@ void StackWriter<Mode, Parent>::visitCallIndirect(CallIndirect* curr) {
template<StackWriterMode Mode, typename Parent>
void StackWriter<Mode, Parent>::visitGetLocal(GetLocal* curr) {
- if (justAddToStack(curr)) return;
+ if (justAddToStack(curr))
+ return;
o << int8_t(BinaryConsts::GetLocal) << U32LEB(mappedLocals[curr->index]);
}
@@ -618,7 +652,8 @@ template<StackWriterMode Mode, typename Parent>
void StackWriter<Mode, Parent>::visitSetLocal(SetLocal* curr) {
visitChild(curr->value);
if (!justAddToStack(curr)) {
- o << int8_t(curr->isTee() ? BinaryConsts::TeeLocal : BinaryConsts::SetLocal) << U32LEB(mappedLocals[curr->index]);
+ o << int8_t(curr->isTee() ? BinaryConsts::TeeLocal : BinaryConsts::SetLocal)
+ << U32LEB(mappedLocals[curr->index]);
}
if (curr->type == unreachable) {
emitExtraUnreachable();
@@ -627,15 +662,19 @@ void StackWriter<Mode, Parent>::visitSetLocal(SetLocal* curr) {
template<StackWriterMode Mode, typename Parent>
void StackWriter<Mode, Parent>::visitGetGlobal(GetGlobal* curr) {
- if (justAddToStack(curr)) return;
- o << int8_t(BinaryConsts::GetGlobal) << U32LEB(parent.getGlobalIndex(curr->name));
+ if (justAddToStack(curr))
+ return;
+ o << int8_t(BinaryConsts::GetGlobal)
+ << U32LEB(parent.getGlobalIndex(curr->name));
}
template<StackWriterMode Mode, typename Parent>
void StackWriter<Mode, Parent>::visitSetGlobal(SetGlobal* curr) {
visitChild(curr->value);
- if (justAddToStack(curr)) return;
- o << int8_t(BinaryConsts::SetGlobal) << U32LEB(parent.getGlobalIndex(curr->name));
+ if (justAddToStack(curr))
+ return;
+ o << int8_t(BinaryConsts::SetGlobal)
+ << U32LEB(parent.getGlobalIndex(curr->name));
}
template<StackWriterMode Mode, typename Parent>
@@ -646,58 +685,108 @@ void StackWriter<Mode, Parent>::visitLoad(Load* curr) {
emitExtraUnreachable();
return;
}
- if (justAddToStack(curr)) return;
+ if (justAddToStack(curr))
+ return;
if (!curr->isAtomic) {
switch (curr->type) {
case i32: {
switch (curr->bytes) {
- case 1: o << int8_t(curr->signed_ ? BinaryConsts::I32LoadMem8S : BinaryConsts::I32LoadMem8U); break;
- case 2: o << int8_t(curr->signed_ ? BinaryConsts::I32LoadMem16S : BinaryConsts::I32LoadMem16U); break;
- case 4: o << int8_t(BinaryConsts::I32LoadMem); break;
- default: abort();
+ case 1:
+ o << int8_t(curr->signed_ ? BinaryConsts::I32LoadMem8S
+ : BinaryConsts::I32LoadMem8U);
+ break;
+ case 2:
+ o << int8_t(curr->signed_ ? BinaryConsts::I32LoadMem16S
+ : BinaryConsts::I32LoadMem16U);
+ break;
+ case 4:
+ o << int8_t(BinaryConsts::I32LoadMem);
+ break;
+ default:
+ abort();
}
break;
}
case i64: {
switch (curr->bytes) {
- case 1: o << int8_t(curr->signed_ ? BinaryConsts::I64LoadMem8S : BinaryConsts::I64LoadMem8U); break;
- case 2: o << int8_t(curr->signed_ ? BinaryConsts::I64LoadMem16S : BinaryConsts::I64LoadMem16U); break;
- case 4: o << int8_t(curr->signed_ ? BinaryConsts::I64LoadMem32S : BinaryConsts::I64LoadMem32U); break;
- case 8: o << int8_t(BinaryConsts::I64LoadMem); break;
- default: abort();
+ case 1:
+ o << int8_t(curr->signed_ ? BinaryConsts::I64LoadMem8S
+ : BinaryConsts::I64LoadMem8U);
+ break;
+ case 2:
+ o << int8_t(curr->signed_ ? BinaryConsts::I64LoadMem16S
+ : BinaryConsts::I64LoadMem16U);
+ break;
+ case 4:
+ o << int8_t(curr->signed_ ? BinaryConsts::I64LoadMem32S
+ : BinaryConsts::I64LoadMem32U);
+ break;
+ case 8:
+ o << int8_t(BinaryConsts::I64LoadMem);
+ break;
+ default:
+ abort();
}
break;
}
- case f32: o << int8_t(BinaryConsts::F32LoadMem); break;
- case f64: o << int8_t(BinaryConsts::F64LoadMem); break;
- case v128: o << int8_t(BinaryConsts::SIMDPrefix) << U32LEB(BinaryConsts::V128Load); break;
- case unreachable: return; // the pointer is unreachable, so we are never reached; just don't emit a load
- case none: WASM_UNREACHABLE();
+ case f32:
+ o << int8_t(BinaryConsts::F32LoadMem);
+ break;
+ case f64:
+ o << int8_t(BinaryConsts::F64LoadMem);
+ break;
+ case v128:
+ o << int8_t(BinaryConsts::SIMDPrefix) << U32LEB(BinaryConsts::V128Load);
+ break;
+ case unreachable:
+ // the pointer is unreachable, so we are never reached; just don't emit
+ // a load
+ return;
+ case none:
+ WASM_UNREACHABLE();
}
} else {
o << int8_t(BinaryConsts::AtomicPrefix);
switch (curr->type) {
case i32: {
switch (curr->bytes) {
- case 1: o << int8_t(BinaryConsts::I32AtomicLoad8U); break;
- case 2: o << int8_t(BinaryConsts::I32AtomicLoad16U); break;
- case 4: o << int8_t(BinaryConsts::I32AtomicLoad); break;
- default: WASM_UNREACHABLE();
+ case 1:
+ o << int8_t(BinaryConsts::I32AtomicLoad8U);
+ break;
+ case 2:
+ o << int8_t(BinaryConsts::I32AtomicLoad16U);
+ break;
+ case 4:
+ o << int8_t(BinaryConsts::I32AtomicLoad);
+ break;
+ default:
+ WASM_UNREACHABLE();
}
break;
}
case i64: {
switch (curr->bytes) {
- case 1: o << int8_t(BinaryConsts::I64AtomicLoad8U); break;
- case 2: o << int8_t(BinaryConsts::I64AtomicLoad16U); break;
- case 4: o << int8_t(BinaryConsts::I64AtomicLoad32U); break;
- case 8: o << int8_t(BinaryConsts::I64AtomicLoad); break;
- default: WASM_UNREACHABLE();
+ case 1:
+ o << int8_t(BinaryConsts::I64AtomicLoad8U);
+ break;
+ case 2:
+ o << int8_t(BinaryConsts::I64AtomicLoad16U);
+ break;
+ case 4:
+ o << int8_t(BinaryConsts::I64AtomicLoad32U);
+ break;
+ case 8:
+ o << int8_t(BinaryConsts::I64AtomicLoad);
+ break;
+ default:
+ WASM_UNREACHABLE();
}
break;
}
- case unreachable: return;
- default: WASM_UNREACHABLE();
+ case unreachable:
+ return;
+ default:
+ WASM_UNREACHABLE();
}
}
emitMemoryAccess(curr->align, curr->bytes, curr->offset);
@@ -712,57 +801,99 @@ void StackWriter<Mode, Parent>::visitStore(Store* curr) {
emitExtraUnreachable();
return;
}
- if (justAddToStack(curr)) return;
+ if (justAddToStack(curr))
+ return;
if (!curr->isAtomic) {
switch (curr->valueType) {
case i32: {
switch (curr->bytes) {
- case 1: o << int8_t(BinaryConsts::I32StoreMem8); break;
- case 2: o << int8_t(BinaryConsts::I32StoreMem16); break;
- case 4: o << int8_t(BinaryConsts::I32StoreMem); break;
- default: abort();
+ case 1:
+ o << int8_t(BinaryConsts::I32StoreMem8);
+ break;
+ case 2:
+ o << int8_t(BinaryConsts::I32StoreMem16);
+ break;
+ case 4:
+ o << int8_t(BinaryConsts::I32StoreMem);
+ break;
+ default:
+ abort();
}
break;
}
case i64: {
switch (curr->bytes) {
- case 1: o << int8_t(BinaryConsts::I64StoreMem8); break;
- case 2: o << int8_t(BinaryConsts::I64StoreMem16); break;
- case 4: o << int8_t(BinaryConsts::I64StoreMem32); break;
- case 8: o << int8_t(BinaryConsts::I64StoreMem); break;
- default: abort();
+ case 1:
+ o << int8_t(BinaryConsts::I64StoreMem8);
+ break;
+ case 2:
+ o << int8_t(BinaryConsts::I64StoreMem16);
+ break;
+ case 4:
+ o << int8_t(BinaryConsts::I64StoreMem32);
+ break;
+ case 8:
+ o << int8_t(BinaryConsts::I64StoreMem);
+ break;
+ default:
+ abort();
}
break;
}
- case f32: o << int8_t(BinaryConsts::F32StoreMem); break;
- case f64: o << int8_t(BinaryConsts::F64StoreMem); break;
- case v128: o << int8_t(BinaryConsts::SIMDPrefix) << U32LEB(BinaryConsts::V128Store); break;
+ case f32:
+ o << int8_t(BinaryConsts::F32StoreMem);
+ break;
+ case f64:
+ o << int8_t(BinaryConsts::F64StoreMem);
+ break;
+ case v128:
+ o << int8_t(BinaryConsts::SIMDPrefix)
+ << U32LEB(BinaryConsts::V128Store);
+ break;
case none:
- case unreachable: WASM_UNREACHABLE();
+ case unreachable:
+ WASM_UNREACHABLE();
}
} else {
o << int8_t(BinaryConsts::AtomicPrefix);
switch (curr->valueType) {
case i32: {
switch (curr->bytes) {
- case 1: o << int8_t(BinaryConsts::I32AtomicStore8); break;
- case 2: o << int8_t(BinaryConsts::I32AtomicStore16); break;
- case 4: o << int8_t(BinaryConsts::I32AtomicStore); break;
- default: WASM_UNREACHABLE();
+ case 1:
+ o << int8_t(BinaryConsts::I32AtomicStore8);
+ break;
+ case 2:
+ o << int8_t(BinaryConsts::I32AtomicStore16);
+ break;
+ case 4:
+ o << int8_t(BinaryConsts::I32AtomicStore);
+ break;
+ default:
+ WASM_UNREACHABLE();
}
break;
}
case i64: {
switch (curr->bytes) {
- case 1: o << int8_t(BinaryConsts::I64AtomicStore8); break;
- case 2: o << int8_t(BinaryConsts::I64AtomicStore16); break;
- case 4: o << int8_t(BinaryConsts::I64AtomicStore32); break;
- case 8: o << int8_t(BinaryConsts::I64AtomicStore); break;
- default: WASM_UNREACHABLE();
+ case 1:
+ o << int8_t(BinaryConsts::I64AtomicStore8);
+ break;
+ case 2:
+ o << int8_t(BinaryConsts::I64AtomicStore16);
+ break;
+ case 4:
+ o << int8_t(BinaryConsts::I64AtomicStore32);
+ break;
+ case 8:
+ o << int8_t(BinaryConsts::I64AtomicStore);
+ break;
+ default:
+ WASM_UNREACHABLE();
}
break;
}
- default: WASM_UNREACHABLE();
+ default:
+ WASM_UNREACHABLE();
}
}
emitMemoryAccess(curr->align, curr->bytes, curr->offset);
@@ -772,50 +903,71 @@ template<StackWriterMode Mode, typename Parent>
void StackWriter<Mode, Parent>::visitAtomicRMW(AtomicRMW* curr) {
visitChild(curr->ptr);
// stop if the rest isn't reachable anyhow
- if (curr->ptr->type == unreachable) return;
+ if (curr->ptr->type == unreachable)
+ return;
visitChild(curr->value);
- if (curr->value->type == unreachable) return;
+ if (curr->value->type == unreachable)
+ return;
if (curr->type == unreachable) {
// don't even emit it; we don't know the right type
emitExtraUnreachable();
return;
}
- if (justAddToStack(curr)) return;
+ if (justAddToStack(curr))
+ return;
o << int8_t(BinaryConsts::AtomicPrefix);
-#define CASE_FOR_OP(Op) \
- case Op: \
- switch (curr->type) { \
- case i32: \
- switch (curr->bytes) { \
- case 1: o << int8_t(BinaryConsts::I32AtomicRMW##Op##8U); break; \
- case 2: o << int8_t(BinaryConsts::I32AtomicRMW##Op##16U); break; \
- case 4: o << int8_t(BinaryConsts::I32AtomicRMW##Op); break; \
- default: WASM_UNREACHABLE(); \
- } \
- break; \
- case i64: \
- switch (curr->bytes) { \
- case 1: o << int8_t(BinaryConsts::I64AtomicRMW##Op##8U); break; \
- case 2: o << int8_t(BinaryConsts::I64AtomicRMW##Op##16U); break; \
- case 4: o << int8_t(BinaryConsts::I64AtomicRMW##Op##32U); break; \
- case 8: o << int8_t(BinaryConsts::I64AtomicRMW##Op); break; \
- default: WASM_UNREACHABLE(); \
- } \
- break; \
- default: WASM_UNREACHABLE(); \
- } \
+#define CASE_FOR_OP(Op) \
+ case Op: \
+ switch (curr->type) { \
+ case i32: \
+ switch (curr->bytes) { \
+ case 1: \
+ o << int8_t(BinaryConsts::I32AtomicRMW##Op##8U); \
+ break; \
+ case 2: \
+ o << int8_t(BinaryConsts::I32AtomicRMW##Op##16U); \
+ break; \
+ case 4: \
+ o << int8_t(BinaryConsts::I32AtomicRMW##Op); \
+ break; \
+ default: \
+ WASM_UNREACHABLE(); \
+ } \
+ break; \
+ case i64: \
+ switch (curr->bytes) { \
+ case 1: \
+ o << int8_t(BinaryConsts::I64AtomicRMW##Op##8U); \
+ break; \
+ case 2: \
+ o << int8_t(BinaryConsts::I64AtomicRMW##Op##16U); \
+ break; \
+ case 4: \
+ o << int8_t(BinaryConsts::I64AtomicRMW##Op##32U); \
+ break; \
+ case 8: \
+ o << int8_t(BinaryConsts::I64AtomicRMW##Op); \
+ break; \
+ default: \
+ WASM_UNREACHABLE(); \
+ } \
+ break; \
+ default: \
+ WASM_UNREACHABLE(); \
+ } \
break
- switch(curr->op) {
+ switch (curr->op) {
CASE_FOR_OP(Add);
CASE_FOR_OP(Sub);
CASE_FOR_OP(And);
CASE_FOR_OP(Or);
CASE_FOR_OP(Xor);
CASE_FOR_OP(Xchg);
- default: WASM_UNREACHABLE();
+ default:
+ WASM_UNREACHABLE();
}
#undef CASE_FOR_OP
@@ -826,38 +978,59 @@ template<StackWriterMode Mode, typename Parent>
void StackWriter<Mode, Parent>::visitAtomicCmpxchg(AtomicCmpxchg* curr) {
visitChild(curr->ptr);
// stop if the rest isn't reachable anyhow
- if (curr->ptr->type == unreachable) return;
+ if (curr->ptr->type == unreachable)
+ return;
visitChild(curr->expected);
- if (curr->expected->type == unreachable) return;
+ if (curr->expected->type == unreachable)
+ return;
visitChild(curr->replacement);
- if (curr->replacement->type == unreachable) return;
+ if (curr->replacement->type == unreachable)
+ return;
if (curr->type == unreachable) {
// don't even emit it; we don't know the right type
emitExtraUnreachable();
return;
}
- if (justAddToStack(curr)) return;
+ if (justAddToStack(curr))
+ return;
o << int8_t(BinaryConsts::AtomicPrefix);
switch (curr->type) {
case i32:
switch (curr->bytes) {
- case 1: o << int8_t(BinaryConsts::I32AtomicCmpxchg8U); break;
- case 2: o << int8_t(BinaryConsts::I32AtomicCmpxchg16U); break;
- case 4: o << int8_t(BinaryConsts::I32AtomicCmpxchg); break;
- default: WASM_UNREACHABLE();
+ case 1:
+ o << int8_t(BinaryConsts::I32AtomicCmpxchg8U);
+ break;
+ case 2:
+ o << int8_t(BinaryConsts::I32AtomicCmpxchg16U);
+ break;
+ case 4:
+ o << int8_t(BinaryConsts::I32AtomicCmpxchg);
+ break;
+ default:
+ WASM_UNREACHABLE();
}
break;
case i64:
switch (curr->bytes) {
- case 1: o << int8_t(BinaryConsts::I64AtomicCmpxchg8U); break;
- case 2: o << int8_t(BinaryConsts::I64AtomicCmpxchg16U); break;
- case 4: o << int8_t(BinaryConsts::I64AtomicCmpxchg32U); break;
- case 8: o << int8_t(BinaryConsts::I64AtomicCmpxchg); break;
- default: WASM_UNREACHABLE();
+ case 1:
+ o << int8_t(BinaryConsts::I64AtomicCmpxchg8U);
+ break;
+ case 2:
+ o << int8_t(BinaryConsts::I64AtomicCmpxchg16U);
+ break;
+ case 4:
+ o << int8_t(BinaryConsts::I64AtomicCmpxchg32U);
+ break;
+ case 8:
+ o << int8_t(BinaryConsts::I64AtomicCmpxchg);
+ break;
+ default:
+ WASM_UNREACHABLE();
}
break;
- default: WASM_UNREACHABLE();
+ default:
+ WASM_UNREACHABLE();
}
emitMemoryAccess(curr->bytes, curr->bytes, curr->offset);
}
@@ -866,12 +1039,16 @@ template<StackWriterMode Mode, typename Parent>
void StackWriter<Mode, Parent>::visitAtomicWait(AtomicWait* curr) {
visitChild(curr->ptr);
// stop if the rest isn't reachable anyhow
- if (curr->ptr->type == unreachable) return;
+ if (curr->ptr->type == unreachable)
+ return;
visitChild(curr->expected);
- if (curr->expected->type == unreachable) return;
+ if (curr->expected->type == unreachable)
+ return;
visitChild(curr->timeout);
- if (curr->timeout->type == unreachable) return;
- if (justAddToStack(curr)) return;
+ if (curr->timeout->type == unreachable)
+ return;
+ if (justAddToStack(curr))
+ return;
o << int8_t(BinaryConsts::AtomicPrefix);
switch (curr->expectedType) {
@@ -885,7 +1062,8 @@ void StackWriter<Mode, Parent>::visitAtomicWait(AtomicWait* curr) {
emitMemoryAccess(8, 8, 0);
break;
}
- default: WASM_UNREACHABLE();
+ default:
+ WASM_UNREACHABLE();
}
}
@@ -893,10 +1071,13 @@ template<StackWriterMode Mode, typename Parent>
void StackWriter<Mode, Parent>::visitAtomicNotify(AtomicNotify* curr) {
visitChild(curr->ptr);
// stop if the rest isn't reachable anyhow
- if (curr->ptr->type == unreachable) return;
+ if (curr->ptr->type == unreachable)
+ return;
visitChild(curr->notifyCount);
- if (curr->notifyCount->type == unreachable) return;
- if (justAddToStack(curr)) return;
+ if (curr->notifyCount->type == unreachable)
+ return;
+ if (justAddToStack(curr))
+ return;
o << int8_t(BinaryConsts::AtomicPrefix) << int8_t(BinaryConsts::AtomicNotify);
emitMemoryAccess(4, 4, 0);
@@ -905,17 +1086,34 @@ void StackWriter<Mode, Parent>::visitAtomicNotify(AtomicNotify* curr) {
template<StackWriterMode Mode, typename Parent>
void StackWriter<Mode, Parent>::visitSIMDExtract(SIMDExtract* curr) {
visitChild(curr->vec);
- if (justAddToStack(curr)) return;
+ if (justAddToStack(curr))
+ return;
o << int8_t(BinaryConsts::SIMDPrefix);
switch (curr->op) {
- case ExtractLaneSVecI8x16: o << U32LEB(BinaryConsts::I8x16ExtractLaneS); break;
- case ExtractLaneUVecI8x16: o << U32LEB(BinaryConsts::I8x16ExtractLaneU); break;
- case ExtractLaneSVecI16x8: o << U32LEB(BinaryConsts::I16x8ExtractLaneS); break;
- case ExtractLaneUVecI16x8: o << U32LEB(BinaryConsts::I16x8ExtractLaneU); break;
- case ExtractLaneVecI32x4: o << U32LEB(BinaryConsts::I32x4ExtractLane); break;
- case ExtractLaneVecI64x2: o << U32LEB(BinaryConsts::I64x2ExtractLane); break;
- case ExtractLaneVecF32x4: o << U32LEB(BinaryConsts::F32x4ExtractLane); break;
- case ExtractLaneVecF64x2: o << U32LEB(BinaryConsts::F64x2ExtractLane); break;
+ case ExtractLaneSVecI8x16:
+ o << U32LEB(BinaryConsts::I8x16ExtractLaneS);
+ break;
+ case ExtractLaneUVecI8x16:
+ o << U32LEB(BinaryConsts::I8x16ExtractLaneU);
+ break;
+ case ExtractLaneSVecI16x8:
+ o << U32LEB(BinaryConsts::I16x8ExtractLaneS);
+ break;
+ case ExtractLaneUVecI16x8:
+ o << U32LEB(BinaryConsts::I16x8ExtractLaneU);
+ break;
+ case ExtractLaneVecI32x4:
+ o << U32LEB(BinaryConsts::I32x4ExtractLane);
+ break;
+ case ExtractLaneVecI64x2:
+ o << U32LEB(BinaryConsts::I64x2ExtractLane);
+ break;
+ case ExtractLaneVecF32x4:
+ o << U32LEB(BinaryConsts::F32x4ExtractLane);
+ break;
+ case ExtractLaneVecF64x2:
+ o << U32LEB(BinaryConsts::F64x2ExtractLane);
+ break;
}
o << uint8_t(curr->index);
}
@@ -924,15 +1122,28 @@ template<StackWriterMode Mode, typename Parent>
void StackWriter<Mode, Parent>::visitSIMDReplace(SIMDReplace* curr) {
visitChild(curr->vec);
visitChild(curr->value);
- if (justAddToStack(curr)) return;
+ if (justAddToStack(curr))
+ return;
o << int8_t(BinaryConsts::SIMDPrefix);
switch (curr->op) {
- case ReplaceLaneVecI8x16: o << U32LEB(BinaryConsts::I8x16ReplaceLane); break;
- case ReplaceLaneVecI16x8: o << U32LEB(BinaryConsts::I16x8ReplaceLane); break;
- case ReplaceLaneVecI32x4: o << U32LEB(BinaryConsts::I32x4ReplaceLane); break;
- case ReplaceLaneVecI64x2: o << U32LEB(BinaryConsts::I64x2ReplaceLane); break;
- case ReplaceLaneVecF32x4: o << U32LEB(BinaryConsts::F32x4ReplaceLane); break;
- case ReplaceLaneVecF64x2: o << U32LEB(BinaryConsts::F64x2ReplaceLane); break;
+ case ReplaceLaneVecI8x16:
+ o << U32LEB(BinaryConsts::I8x16ReplaceLane);
+ break;
+ case ReplaceLaneVecI16x8:
+ o << U32LEB(BinaryConsts::I16x8ReplaceLane);
+ break;
+ case ReplaceLaneVecI32x4:
+ o << U32LEB(BinaryConsts::I32x4ReplaceLane);
+ break;
+ case ReplaceLaneVecI64x2:
+ o << U32LEB(BinaryConsts::I64x2ReplaceLane);
+ break;
+ case ReplaceLaneVecF32x4:
+ o << U32LEB(BinaryConsts::F32x4ReplaceLane);
+ break;
+ case ReplaceLaneVecF64x2:
+ o << U32LEB(BinaryConsts::F64x2ReplaceLane);
+ break;
}
assert(curr->index < 16);
o << uint8_t(curr->index);
@@ -942,7 +1153,8 @@ template<StackWriterMode Mode, typename Parent>
void StackWriter<Mode, Parent>::visitSIMDShuffle(SIMDShuffle* curr) {
visitChild(curr->left);
visitChild(curr->right);
- if (justAddToStack(curr)) return;
+ if (justAddToStack(curr))
+ return;
o << int8_t(BinaryConsts::SIMDPrefix) << U32LEB(BinaryConsts::V8x16Shuffle);
for (uint8_t m : curr->mask) {
o << m;
@@ -954,7 +1166,8 @@ void StackWriter<Mode, Parent>::visitSIMDBitselect(SIMDBitselect* curr) {
visitChild(curr->left);
visitChild(curr->right);
visitChild(curr->cond);
- if (justAddToStack(curr)) return;
+ if (justAddToStack(curr))
+ return;
o << int8_t(BinaryConsts::SIMDPrefix) << U32LEB(BinaryConsts::V128Bitselect);
}
@@ -962,21 +1175,46 @@ template<StackWriterMode Mode, typename Parent>
void StackWriter<Mode, Parent>::visitSIMDShift(SIMDShift* curr) {
visitChild(curr->vec);
visitChild(curr->shift);
- if (justAddToStack(curr)) return;
+ if (justAddToStack(curr))
+ return;
o << int8_t(BinaryConsts::SIMDPrefix);
switch (curr->op) {
- case ShlVecI8x16: o << U32LEB(BinaryConsts::I8x16Shl); break;
- case ShrSVecI8x16: o << U32LEB(BinaryConsts::I8x16ShrS); break;
- case ShrUVecI8x16: o << U32LEB(BinaryConsts::I8x16ShrU); break;
- case ShlVecI16x8: o << U32LEB(BinaryConsts::I16x8Shl); break;
- case ShrSVecI16x8: o << U32LEB(BinaryConsts::I16x8ShrS); break;
- case ShrUVecI16x8: o << U32LEB(BinaryConsts::I16x8ShrU); break;
- case ShlVecI32x4: o << U32LEB(BinaryConsts::I32x4Shl); break;
- case ShrSVecI32x4: o << U32LEB(BinaryConsts::I32x4ShrS); break;
- case ShrUVecI32x4: o << U32LEB(BinaryConsts::I32x4ShrU); break;
- case ShlVecI64x2: o << U32LEB(BinaryConsts::I64x2Shl); break;
- case ShrSVecI64x2: o << U32LEB(BinaryConsts::I64x2ShrS); break;
- case ShrUVecI64x2: o << U32LEB(BinaryConsts::I64x2ShrU); break;
+ case ShlVecI8x16:
+ o << U32LEB(BinaryConsts::I8x16Shl);
+ break;
+ case ShrSVecI8x16:
+ o << U32LEB(BinaryConsts::I8x16ShrS);
+ break;
+ case ShrUVecI8x16:
+ o << U32LEB(BinaryConsts::I8x16ShrU);
+ break;
+ case ShlVecI16x8:
+ o << U32LEB(BinaryConsts::I16x8Shl);
+ break;
+ case ShrSVecI16x8:
+ o << U32LEB(BinaryConsts::I16x8ShrS);
+ break;
+ case ShrUVecI16x8:
+ o << U32LEB(BinaryConsts::I16x8ShrU);
+ break;
+ case ShlVecI32x4:
+ o << U32LEB(BinaryConsts::I32x4Shl);
+ break;
+ case ShrSVecI32x4:
+ o << U32LEB(BinaryConsts::I32x4ShrS);
+ break;
+ case ShrUVecI32x4:
+ o << U32LEB(BinaryConsts::I32x4ShrU);
+ break;
+ case ShlVecI64x2:
+ o << U32LEB(BinaryConsts::I64x2Shl);
+ break;
+ case ShrSVecI64x2:
+ o << U32LEB(BinaryConsts::I64x2ShrS);
+ break;
+ case ShrUVecI64x2:
+ o << U32LEB(BinaryConsts::I64x2ShrU);
+ break;
}
}
@@ -985,7 +1223,8 @@ void StackWriter<Mode, Parent>::visitMemoryInit(MemoryInit* curr) {
visitChild(curr->dest);
visitChild(curr->offset);
visitChild(curr->size);
- if (justAddToStack(curr)) return;
+ if (justAddToStack(curr))
+ return;
o << int8_t(BinaryConsts::MiscPrefix);
o << U32LEB(BinaryConsts::MemoryInit);
o << U32LEB(curr->segment) << int8_t(0);
@@ -993,7 +1232,8 @@ void StackWriter<Mode, Parent>::visitMemoryInit(MemoryInit* curr) {
template<StackWriterMode Mode, typename Parent>
void StackWriter<Mode, Parent>::visitDataDrop(DataDrop* curr) {
- if (justAddToStack(curr)) return;
+ if (justAddToStack(curr))
+ return;
o << int8_t(BinaryConsts::MiscPrefix);
o << U32LEB(BinaryConsts::DataDrop);
o << U32LEB(curr->segment);
@@ -1004,7 +1244,8 @@ void StackWriter<Mode, Parent>::visitMemoryCopy(MemoryCopy* curr) {
visitChild(curr->dest);
visitChild(curr->source);
visitChild(curr->size);
- if (justAddToStack(curr)) return;
+ if (justAddToStack(curr))
+ return;
o << int8_t(BinaryConsts::MiscPrefix);
o << U32LEB(BinaryConsts::MemoryCopy);
o << int8_t(0) << int8_t(0);
@@ -1015,7 +1256,8 @@ void StackWriter<Mode, Parent>::visitMemoryFill(MemoryFill* curr) {
visitChild(curr->dest);
visitChild(curr->value);
visitChild(curr->size);
- if (justAddToStack(curr)) return;
+ if (justAddToStack(curr))
+ return;
o << int8_t(BinaryConsts::MiscPrefix);
o << U32LEB(BinaryConsts::MemoryFill);
o << int8_t(0);
@@ -1023,7 +1265,8 @@ void StackWriter<Mode, Parent>::visitMemoryFill(MemoryFill* curr) {
template<StackWriterMode Mode, typename Parent>
void StackWriter<Mode, Parent>::visitConst(Const* curr) {
- if (justAddToStack(curr)) return;
+ if (justAddToStack(curr))
+ return;
switch (curr->type) {
case i32: {
o << int8_t(BinaryConsts::I32Const) << S32LEB(curr->value.geti32());
@@ -1062,102 +1305,314 @@ void StackWriter<Mode, Parent>::visitUnary(Unary* curr) {
emitExtraUnreachable();
return;
}
- if (justAddToStack(curr)) return;
+ if (justAddToStack(curr))
+ return;
switch (curr->op) {
- case ClzInt32: o << int8_t(BinaryConsts::I32Clz); break;
- case CtzInt32: o << int8_t(BinaryConsts::I32Ctz); break;
- case PopcntInt32: o << int8_t(BinaryConsts::I32Popcnt); break;
- case EqZInt32: o << int8_t(BinaryConsts::I32EqZ); break;
- case ClzInt64: o << int8_t(BinaryConsts::I64Clz); break;
- case CtzInt64: o << int8_t(BinaryConsts::I64Ctz); break;
- case PopcntInt64: o << int8_t(BinaryConsts::I64Popcnt); break;
- case EqZInt64: o << int8_t(BinaryConsts::I64EqZ); break;
- case NegFloat32: o << int8_t(BinaryConsts::F32Neg); break;
- case AbsFloat32: o << int8_t(BinaryConsts::F32Abs); break;
- case CeilFloat32: o << int8_t(BinaryConsts::F32Ceil); break;
- case FloorFloat32: o << int8_t(BinaryConsts::F32Floor); break;
- case TruncFloat32: o << int8_t(BinaryConsts::F32Trunc); break;
- case NearestFloat32: o << int8_t(BinaryConsts::F32NearestInt); break;
- case SqrtFloat32: o << int8_t(BinaryConsts::F32Sqrt); break;
- case NegFloat64: o << int8_t(BinaryConsts::F64Neg); break;
- case AbsFloat64: o << int8_t(BinaryConsts::F64Abs); break;
- case CeilFloat64: o << int8_t(BinaryConsts::F64Ceil); break;
- case FloorFloat64: o << int8_t(BinaryConsts::F64Floor); break;
- case TruncFloat64: o << int8_t(BinaryConsts::F64Trunc); break;
- case NearestFloat64: o << int8_t(BinaryConsts::F64NearestInt); break;
- case SqrtFloat64: o << int8_t(BinaryConsts::F64Sqrt); break;
- case ExtendSInt32: o << int8_t(BinaryConsts::I64STruncI32); break;
- case ExtendUInt32: o << int8_t(BinaryConsts::I64UTruncI32); break;
- case WrapInt64: o << int8_t(BinaryConsts::I32ConvertI64); break;
- case TruncUFloat32ToInt32: o << int8_t(BinaryConsts::I32UTruncF32); break;
- case TruncUFloat32ToInt64: o << int8_t(BinaryConsts::I64UTruncF32); break;
- case TruncSFloat32ToInt32: o << int8_t(BinaryConsts::I32STruncF32); break;
- case TruncSFloat32ToInt64: o << int8_t(BinaryConsts::I64STruncF32); break;
- case TruncUFloat64ToInt32: o << int8_t(BinaryConsts::I32UTruncF64); break;
- case TruncUFloat64ToInt64: o << int8_t(BinaryConsts::I64UTruncF64); break;
- case TruncSFloat64ToInt32: o << int8_t(BinaryConsts::I32STruncF64); break;
- case TruncSFloat64ToInt64: o << int8_t(BinaryConsts::I64STruncF64); break;
- case ConvertUInt32ToFloat32: o << int8_t(BinaryConsts::F32UConvertI32); break;
- case ConvertUInt32ToFloat64: o << int8_t(BinaryConsts::F64UConvertI32); break;
- case ConvertSInt32ToFloat32: o << int8_t(BinaryConsts::F32SConvertI32); break;
- case ConvertSInt32ToFloat64: o << int8_t(BinaryConsts::F64SConvertI32); break;
- case ConvertUInt64ToFloat32: o << int8_t(BinaryConsts::F32UConvertI64); break;
- case ConvertUInt64ToFloat64: o << int8_t(BinaryConsts::F64UConvertI64); break;
- case ConvertSInt64ToFloat32: o << int8_t(BinaryConsts::F32SConvertI64); break;
- case ConvertSInt64ToFloat64: o << int8_t(BinaryConsts::F64SConvertI64); break;
- case DemoteFloat64: o << int8_t(BinaryConsts::F32ConvertF64); break;
- case PromoteFloat32: o << int8_t(BinaryConsts::F64ConvertF32); break;
- case ReinterpretFloat32: o << int8_t(BinaryConsts::I32ReinterpretF32); break;
- case ReinterpretFloat64: o << int8_t(BinaryConsts::I64ReinterpretF64); break;
- case ReinterpretInt32: o << int8_t(BinaryConsts::F32ReinterpretI32); break;
- case ReinterpretInt64: o << int8_t(BinaryConsts::F64ReinterpretI64); break;
- case ExtendS8Int32: o << int8_t(BinaryConsts::I32ExtendS8); break;
- case ExtendS16Int32: o << int8_t(BinaryConsts::I32ExtendS16); break;
- case ExtendS8Int64: o << int8_t(BinaryConsts::I64ExtendS8); break;
- case ExtendS16Int64: o << int8_t(BinaryConsts::I64ExtendS16); break;
- case ExtendS32Int64: o << int8_t(BinaryConsts::I64ExtendS32); break;
- case TruncSatSFloat32ToInt32: o << int8_t(BinaryConsts::MiscPrefix) << U32LEB(BinaryConsts::I32STruncSatF32); break;
- case TruncSatUFloat32ToInt32: o << int8_t(BinaryConsts::MiscPrefix) << U32LEB(BinaryConsts::I32UTruncSatF32); break;
- case TruncSatSFloat64ToInt32: o << int8_t(BinaryConsts::MiscPrefix) << U32LEB(BinaryConsts::I32STruncSatF64); break;
- case TruncSatUFloat64ToInt32: o << int8_t(BinaryConsts::MiscPrefix) << U32LEB(BinaryConsts::I32UTruncSatF64); break;
- case TruncSatSFloat32ToInt64: o << int8_t(BinaryConsts::MiscPrefix) << U32LEB(BinaryConsts::I64STruncSatF32); break;
- case TruncSatUFloat32ToInt64: o << int8_t(BinaryConsts::MiscPrefix) << U32LEB(BinaryConsts::I64UTruncSatF32); break;
- case TruncSatSFloat64ToInt64: o << int8_t(BinaryConsts::MiscPrefix) << U32LEB(BinaryConsts::I64STruncSatF64); break;
- case TruncSatUFloat64ToInt64: o << int8_t(BinaryConsts::MiscPrefix) << U32LEB(BinaryConsts::I64UTruncSatF64); break;
- case SplatVecI8x16: o << int8_t(BinaryConsts::SIMDPrefix) << U32LEB(BinaryConsts::I8x16Splat); break;
- case SplatVecI16x8: o << int8_t(BinaryConsts::SIMDPrefix) << U32LEB(BinaryConsts::I16x8Splat); break;
- case SplatVecI32x4: o << int8_t(BinaryConsts::SIMDPrefix) << U32LEB(BinaryConsts::I32x4Splat); break;
- case SplatVecI64x2: o << int8_t(BinaryConsts::SIMDPrefix) << U32LEB(BinaryConsts::I64x2Splat); break;
- case SplatVecF32x4: o << int8_t(BinaryConsts::SIMDPrefix) << U32LEB(BinaryConsts::F32x4Splat); break;
- case SplatVecF64x2: o << int8_t(BinaryConsts::SIMDPrefix) << U32LEB(BinaryConsts::F64x2Splat); break;
- case NotVec128: o << int8_t(BinaryConsts::SIMDPrefix) << U32LEB(BinaryConsts::V128Not); break;
- case NegVecI8x16: o << int8_t(BinaryConsts::SIMDPrefix) << U32LEB(BinaryConsts::I8x16Neg); break;
- case AnyTrueVecI8x16: o << int8_t(BinaryConsts::SIMDPrefix) << U32LEB(BinaryConsts::I8x16AnyTrue); break;
- case AllTrueVecI8x16: o << int8_t(BinaryConsts::SIMDPrefix) << U32LEB(BinaryConsts::I8x16AllTrue); break;
- case NegVecI16x8: o << int8_t(BinaryConsts::SIMDPrefix) << U32LEB(BinaryConsts::I16x8Neg); break;
- case AnyTrueVecI16x8: o << int8_t(BinaryConsts::SIMDPrefix) << U32LEB(BinaryConsts::I16x8AnyTrue); break;
- case AllTrueVecI16x8: o << int8_t(BinaryConsts::SIMDPrefix) << U32LEB(BinaryConsts::I16x8AllTrue); break;
- case NegVecI32x4: o << int8_t(BinaryConsts::SIMDPrefix) << U32LEB(BinaryConsts::I32x4Neg); break;
- case AnyTrueVecI32x4: o << int8_t(BinaryConsts::SIMDPrefix) << U32LEB(BinaryConsts::I32x4AnyTrue); break;
- case AllTrueVecI32x4: o << int8_t(BinaryConsts::SIMDPrefix) << U32LEB(BinaryConsts::I32x4AllTrue); break;
- case NegVecI64x2: o << int8_t(BinaryConsts::SIMDPrefix) << U32LEB(BinaryConsts::I64x2Neg); break;
- case AnyTrueVecI64x2: o << int8_t(BinaryConsts::SIMDPrefix) << U32LEB(BinaryConsts::I64x2AnyTrue); break;
- case AllTrueVecI64x2: o << int8_t(BinaryConsts::SIMDPrefix) << U32LEB(BinaryConsts::I64x2AllTrue); break;
- case AbsVecF32x4: o << int8_t(BinaryConsts::SIMDPrefix) << U32LEB(BinaryConsts::F32x4Abs); break;
- case NegVecF32x4: o << int8_t(BinaryConsts::SIMDPrefix) << U32LEB(BinaryConsts::F32x4Neg); break;
- case SqrtVecF32x4: o << int8_t(BinaryConsts::SIMDPrefix) << U32LEB(BinaryConsts::F32x4Sqrt); break;
- case AbsVecF64x2: o << int8_t(BinaryConsts::SIMDPrefix) << U32LEB(BinaryConsts::F64x2Abs); break;
- case NegVecF64x2: o << int8_t(BinaryConsts::SIMDPrefix) << U32LEB(BinaryConsts::F64x2Neg); break;
- case SqrtVecF64x2: o << int8_t(BinaryConsts::SIMDPrefix) << U32LEB(BinaryConsts::F64x2Sqrt); break;
- case TruncSatSVecF32x4ToVecI32x4: o << int8_t(BinaryConsts::SIMDPrefix) << U32LEB(BinaryConsts::I32x4TruncSatSF32x4); break;
- case TruncSatUVecF32x4ToVecI32x4: o << int8_t(BinaryConsts::SIMDPrefix) << U32LEB(BinaryConsts::I32x4TruncSatUF32x4); break;
- case TruncSatSVecF64x2ToVecI64x2: o << int8_t(BinaryConsts::SIMDPrefix) << U32LEB(BinaryConsts::I64x2TruncSatSF64x2); break;
- case TruncSatUVecF64x2ToVecI64x2: o << int8_t(BinaryConsts::SIMDPrefix) << U32LEB(BinaryConsts::I64x2TruncSatUF64x2); break;
- case ConvertSVecI32x4ToVecF32x4: o << int8_t(BinaryConsts::SIMDPrefix) << U32LEB(BinaryConsts::F32x4ConvertSI32x4); break;
- case ConvertUVecI32x4ToVecF32x4: o << int8_t(BinaryConsts::SIMDPrefix) << U32LEB(BinaryConsts::F32x4ConvertUI32x4); break;
- case ConvertSVecI64x2ToVecF64x2: o << int8_t(BinaryConsts::SIMDPrefix) << U32LEB(BinaryConsts::F64x2ConvertSI64x2); break;
- case ConvertUVecI64x2ToVecF64x2: o << int8_t(BinaryConsts::SIMDPrefix) << U32LEB(BinaryConsts::F64x2ConvertUI64x2); break;
- case InvalidUnary: WASM_UNREACHABLE();
+ case ClzInt32:
+ o << int8_t(BinaryConsts::I32Clz);
+ break;
+ case CtzInt32:
+ o << int8_t(BinaryConsts::I32Ctz);
+ break;
+ case PopcntInt32:
+ o << int8_t(BinaryConsts::I32Popcnt);
+ break;
+ case EqZInt32:
+ o << int8_t(BinaryConsts::I32EqZ);
+ break;
+ case ClzInt64:
+ o << int8_t(BinaryConsts::I64Clz);
+ break;
+ case CtzInt64:
+ o << int8_t(BinaryConsts::I64Ctz);
+ break;
+ case PopcntInt64:
+ o << int8_t(BinaryConsts::I64Popcnt);
+ break;
+ case EqZInt64:
+ o << int8_t(BinaryConsts::I64EqZ);
+ break;
+ case NegFloat32:
+ o << int8_t(BinaryConsts::F32Neg);
+ break;
+ case AbsFloat32:
+ o << int8_t(BinaryConsts::F32Abs);
+ break;
+ case CeilFloat32:
+ o << int8_t(BinaryConsts::F32Ceil);
+ break;
+ case FloorFloat32:
+ o << int8_t(BinaryConsts::F32Floor);
+ break;
+ case TruncFloat32:
+ o << int8_t(BinaryConsts::F32Trunc);
+ break;
+ case NearestFloat32:
+ o << int8_t(BinaryConsts::F32NearestInt);
+ break;
+ case SqrtFloat32:
+ o << int8_t(BinaryConsts::F32Sqrt);
+ break;
+ case NegFloat64:
+ o << int8_t(BinaryConsts::F64Neg);
+ break;
+ case AbsFloat64:
+ o << int8_t(BinaryConsts::F64Abs);
+ break;
+ case CeilFloat64:
+ o << int8_t(BinaryConsts::F64Ceil);
+ break;
+ case FloorFloat64:
+ o << int8_t(BinaryConsts::F64Floor);
+ break;
+ case TruncFloat64:
+ o << int8_t(BinaryConsts::F64Trunc);
+ break;
+ case NearestFloat64:
+ o << int8_t(BinaryConsts::F64NearestInt);
+ break;
+ case SqrtFloat64:
+ o << int8_t(BinaryConsts::F64Sqrt);
+ break;
+ case ExtendSInt32:
+ o << int8_t(BinaryConsts::I64STruncI32);
+ break;
+ case ExtendUInt32:
+ o << int8_t(BinaryConsts::I64UTruncI32);
+ break;
+ case WrapInt64:
+ o << int8_t(BinaryConsts::I32ConvertI64);
+ break;
+ case TruncUFloat32ToInt32:
+ o << int8_t(BinaryConsts::I32UTruncF32);
+ break;
+ case TruncUFloat32ToInt64:
+ o << int8_t(BinaryConsts::I64UTruncF32);
+ break;
+ case TruncSFloat32ToInt32:
+ o << int8_t(BinaryConsts::I32STruncF32);
+ break;
+ case TruncSFloat32ToInt64:
+ o << int8_t(BinaryConsts::I64STruncF32);
+ break;
+ case TruncUFloat64ToInt32:
+ o << int8_t(BinaryConsts::I32UTruncF64);
+ break;
+ case TruncUFloat64ToInt64:
+ o << int8_t(BinaryConsts::I64UTruncF64);
+ break;
+ case TruncSFloat64ToInt32:
+ o << int8_t(BinaryConsts::I32STruncF64);
+ break;
+ case TruncSFloat64ToInt64:
+ o << int8_t(BinaryConsts::I64STruncF64);
+ break;
+ case ConvertUInt32ToFloat32:
+ o << int8_t(BinaryConsts::F32UConvertI32);
+ break;
+ case ConvertUInt32ToFloat64:
+ o << int8_t(BinaryConsts::F64UConvertI32);
+ break;
+ case ConvertSInt32ToFloat32:
+ o << int8_t(BinaryConsts::F32SConvertI32);
+ break;
+ case ConvertSInt32ToFloat64:
+ o << int8_t(BinaryConsts::F64SConvertI32);
+ break;
+ case ConvertUInt64ToFloat32:
+ o << int8_t(BinaryConsts::F32UConvertI64);
+ break;
+ case ConvertUInt64ToFloat64:
+ o << int8_t(BinaryConsts::F64UConvertI64);
+ break;
+ case ConvertSInt64ToFloat32:
+ o << int8_t(BinaryConsts::F32SConvertI64);
+ break;
+ case ConvertSInt64ToFloat64:
+ o << int8_t(BinaryConsts::F64SConvertI64);
+ break;
+ case DemoteFloat64:
+ o << int8_t(BinaryConsts::F32ConvertF64);
+ break;
+ case PromoteFloat32:
+ o << int8_t(BinaryConsts::F64ConvertF32);
+ break;
+ case ReinterpretFloat32:
+ o << int8_t(BinaryConsts::I32ReinterpretF32);
+ break;
+ case ReinterpretFloat64:
+ o << int8_t(BinaryConsts::I64ReinterpretF64);
+ break;
+ case ReinterpretInt32:
+ o << int8_t(BinaryConsts::F32ReinterpretI32);
+ break;
+ case ReinterpretInt64:
+ o << int8_t(BinaryConsts::F64ReinterpretI64);
+ break;
+ case ExtendS8Int32:
+ o << int8_t(BinaryConsts::I32ExtendS8);
+ break;
+ case ExtendS16Int32:
+ o << int8_t(BinaryConsts::I32ExtendS16);
+ break;
+ case ExtendS8Int64:
+ o << int8_t(BinaryConsts::I64ExtendS8);
+ break;
+ case ExtendS16Int64:
+ o << int8_t(BinaryConsts::I64ExtendS16);
+ break;
+ case ExtendS32Int64:
+ o << int8_t(BinaryConsts::I64ExtendS32);
+ break;
+ case TruncSatSFloat32ToInt32:
+ o << int8_t(BinaryConsts::MiscPrefix)
+ << U32LEB(BinaryConsts::I32STruncSatF32);
+ break;
+ case TruncSatUFloat32ToInt32:
+ o << int8_t(BinaryConsts::MiscPrefix)
+ << U32LEB(BinaryConsts::I32UTruncSatF32);
+ break;
+ case TruncSatSFloat64ToInt32:
+ o << int8_t(BinaryConsts::MiscPrefix)
+ << U32LEB(BinaryConsts::I32STruncSatF64);
+ break;
+ case TruncSatUFloat64ToInt32:
+ o << int8_t(BinaryConsts::MiscPrefix)
+ << U32LEB(BinaryConsts::I32UTruncSatF64);
+ break;
+ case TruncSatSFloat32ToInt64:
+ o << int8_t(BinaryConsts::MiscPrefix)
+ << U32LEB(BinaryConsts::I64STruncSatF32);
+ break;
+ case TruncSatUFloat32ToInt64:
+ o << int8_t(BinaryConsts::MiscPrefix)
+ << U32LEB(BinaryConsts::I64UTruncSatF32);
+ break;
+ case TruncSatSFloat64ToInt64:
+ o << int8_t(BinaryConsts::MiscPrefix)
+ << U32LEB(BinaryConsts::I64STruncSatF64);
+ break;
+ case TruncSatUFloat64ToInt64:
+ o << int8_t(BinaryConsts::MiscPrefix)
+ << U32LEB(BinaryConsts::I64UTruncSatF64);
+ break;
+ case SplatVecI8x16:
+ o << int8_t(BinaryConsts::SIMDPrefix) << U32LEB(BinaryConsts::I8x16Splat);
+ break;
+ case SplatVecI16x8:
+ o << int8_t(BinaryConsts::SIMDPrefix) << U32LEB(BinaryConsts::I16x8Splat);
+ break;
+ case SplatVecI32x4:
+ o << int8_t(BinaryConsts::SIMDPrefix) << U32LEB(BinaryConsts::I32x4Splat);
+ break;
+ case SplatVecI64x2:
+ o << int8_t(BinaryConsts::SIMDPrefix) << U32LEB(BinaryConsts::I64x2Splat);
+ break;
+ case SplatVecF32x4:
+ o << int8_t(BinaryConsts::SIMDPrefix) << U32LEB(BinaryConsts::F32x4Splat);
+ break;
+ case SplatVecF64x2:
+ o << int8_t(BinaryConsts::SIMDPrefix) << U32LEB(BinaryConsts::F64x2Splat);
+ break;
+ case NotVec128:
+ o << int8_t(BinaryConsts::SIMDPrefix) << U32LEB(BinaryConsts::V128Not);
+ break;
+ case NegVecI8x16:
+ o << int8_t(BinaryConsts::SIMDPrefix) << U32LEB(BinaryConsts::I8x16Neg);
+ break;
+ case AnyTrueVecI8x16:
+ o << int8_t(BinaryConsts::SIMDPrefix)
+ << U32LEB(BinaryConsts::I8x16AnyTrue);
+ break;
+ case AllTrueVecI8x16:
+ o << int8_t(BinaryConsts::SIMDPrefix)
+ << U32LEB(BinaryConsts::I8x16AllTrue);
+ break;
+ case NegVecI16x8:
+ o << int8_t(BinaryConsts::SIMDPrefix) << U32LEB(BinaryConsts::I16x8Neg);
+ break;
+ case AnyTrueVecI16x8:
+ o << int8_t(BinaryConsts::SIMDPrefix)
+ << U32LEB(BinaryConsts::I16x8AnyTrue);
+ break;
+ case AllTrueVecI16x8:
+ o << int8_t(BinaryConsts::SIMDPrefix)
+ << U32LEB(BinaryConsts::I16x8AllTrue);
+ break;
+ case NegVecI32x4:
+ o << int8_t(BinaryConsts::SIMDPrefix) << U32LEB(BinaryConsts::I32x4Neg);
+ break;
+ case AnyTrueVecI32x4:
+ o << int8_t(BinaryConsts::SIMDPrefix)
+ << U32LEB(BinaryConsts::I32x4AnyTrue);
+ break;
+ case AllTrueVecI32x4:
+ o << int8_t(BinaryConsts::SIMDPrefix)
+ << U32LEB(BinaryConsts::I32x4AllTrue);
+ break;
+ case NegVecI64x2:
+ o << int8_t(BinaryConsts::SIMDPrefix) << U32LEB(BinaryConsts::I64x2Neg);
+ break;
+ case AnyTrueVecI64x2:
+ o << int8_t(BinaryConsts::SIMDPrefix)
+ << U32LEB(BinaryConsts::I64x2AnyTrue);
+ break;
+ case AllTrueVecI64x2:
+ o << int8_t(BinaryConsts::SIMDPrefix)
+ << U32LEB(BinaryConsts::I64x2AllTrue);
+ break;
+ case AbsVecF32x4:
+ o << int8_t(BinaryConsts::SIMDPrefix) << U32LEB(BinaryConsts::F32x4Abs);
+ break;
+ case NegVecF32x4:
+ o << int8_t(BinaryConsts::SIMDPrefix) << U32LEB(BinaryConsts::F32x4Neg);
+ break;
+ case SqrtVecF32x4:
+ o << int8_t(BinaryConsts::SIMDPrefix) << U32LEB(BinaryConsts::F32x4Sqrt);
+ break;
+ case AbsVecF64x2:
+ o << int8_t(BinaryConsts::SIMDPrefix) << U32LEB(BinaryConsts::F64x2Abs);
+ break;
+ case NegVecF64x2:
+ o << int8_t(BinaryConsts::SIMDPrefix) << U32LEB(BinaryConsts::F64x2Neg);
+ break;
+ case SqrtVecF64x2:
+ o << int8_t(BinaryConsts::SIMDPrefix) << U32LEB(BinaryConsts::F64x2Sqrt);
+ break;
+ case TruncSatSVecF32x4ToVecI32x4:
+ o << int8_t(BinaryConsts::SIMDPrefix)
+ << U32LEB(BinaryConsts::I32x4TruncSatSF32x4);
+ break;
+ case TruncSatUVecF32x4ToVecI32x4:
+ o << int8_t(BinaryConsts::SIMDPrefix)
+ << U32LEB(BinaryConsts::I32x4TruncSatUF32x4);
+ break;
+ case TruncSatSVecF64x2ToVecI64x2:
+ o << int8_t(BinaryConsts::SIMDPrefix)
+ << U32LEB(BinaryConsts::I64x2TruncSatSF64x2);
+ break;
+ case TruncSatUVecF64x2ToVecI64x2:
+ o << int8_t(BinaryConsts::SIMDPrefix)
+ << U32LEB(BinaryConsts::I64x2TruncSatUF64x2);
+ break;
+ case ConvertSVecI32x4ToVecF32x4:
+ o << int8_t(BinaryConsts::SIMDPrefix)
+ << U32LEB(BinaryConsts::F32x4ConvertSI32x4);
+ break;
+ case ConvertUVecI32x4ToVecF32x4:
+ o << int8_t(BinaryConsts::SIMDPrefix)
+ << U32LEB(BinaryConsts::F32x4ConvertUI32x4);
+ break;
+ case ConvertSVecI64x2ToVecF64x2:
+ o << int8_t(BinaryConsts::SIMDPrefix)
+ << U32LEB(BinaryConsts::F64x2ConvertSI64x2);
+ break;
+ case ConvertUVecI64x2ToVecF64x2:
+ o << int8_t(BinaryConsts::SIMDPrefix)
+ << U32LEB(BinaryConsts::F64x2ConvertUI64x2);
+ break;
+ case InvalidUnary:
+ WASM_UNREACHABLE();
}
}
@@ -1169,167 +1624,481 @@ void StackWriter<Mode, Parent>::visitBinary(Binary* curr) {
emitExtraUnreachable();
return;
}
- if (justAddToStack(curr)) return;
+ if (justAddToStack(curr))
+ return;
switch (curr->op) {
- case AddInt32: o << int8_t(BinaryConsts::I32Add); break;
- case SubInt32: o << int8_t(BinaryConsts::I32Sub); break;
- case MulInt32: o << int8_t(BinaryConsts::I32Mul); break;
- case DivSInt32: o << int8_t(BinaryConsts::I32DivS); break;
- case DivUInt32: o << int8_t(BinaryConsts::I32DivU); break;
- case RemSInt32: o << int8_t(BinaryConsts::I32RemS); break;
- case RemUInt32: o << int8_t(BinaryConsts::I32RemU); break;
- case AndInt32: o << int8_t(BinaryConsts::I32And); break;
- case OrInt32: o << int8_t(BinaryConsts::I32Or); break;
- case XorInt32: o << int8_t(BinaryConsts::I32Xor); break;
- case ShlInt32: o << int8_t(BinaryConsts::I32Shl); break;
- case ShrUInt32: o << int8_t(BinaryConsts::I32ShrU); break;
- case ShrSInt32: o << int8_t(BinaryConsts::I32ShrS); break;
- case RotLInt32: o << int8_t(BinaryConsts::I32RotL); break;
- case RotRInt32: o << int8_t(BinaryConsts::I32RotR); break;
- case EqInt32: o << int8_t(BinaryConsts::I32Eq); break;
- case NeInt32: o << int8_t(BinaryConsts::I32Ne); break;
- case LtSInt32: o << int8_t(BinaryConsts::I32LtS); break;
- case LtUInt32: o << int8_t(BinaryConsts::I32LtU); break;
- case LeSInt32: o << int8_t(BinaryConsts::I32LeS); break;
- case LeUInt32: o << int8_t(BinaryConsts::I32LeU); break;
- case GtSInt32: o << int8_t(BinaryConsts::I32GtS); break;
- case GtUInt32: o << int8_t(BinaryConsts::I32GtU); break;
- case GeSInt32: o << int8_t(BinaryConsts::I32GeS); break;
- case GeUInt32: o << int8_t(BinaryConsts::I32GeU); break;
-
- case AddInt64: o << int8_t(BinaryConsts::I64Add); break;
- case SubInt64: o << int8_t(BinaryConsts::I64Sub); break;
- case MulInt64: o << int8_t(BinaryConsts::I64Mul); break;
- case DivSInt64: o << int8_t(BinaryConsts::I64DivS); break;
- case DivUInt64: o << int8_t(BinaryConsts::I64DivU); break;
- case RemSInt64: o << int8_t(BinaryConsts::I64RemS); break;
- case RemUInt64: o << int8_t(BinaryConsts::I64RemU); break;
- case AndInt64: o << int8_t(BinaryConsts::I64And); break;
- case OrInt64: o << int8_t(BinaryConsts::I64Or); break;
- case XorInt64: o << int8_t(BinaryConsts::I64Xor); break;
- case ShlInt64: o << int8_t(BinaryConsts::I64Shl); break;
- case ShrUInt64: o << int8_t(BinaryConsts::I64ShrU); break;
- case ShrSInt64: o << int8_t(BinaryConsts::I64ShrS); break;
- case RotLInt64: o << int8_t(BinaryConsts::I64RotL); break;
- case RotRInt64: o << int8_t(BinaryConsts::I64RotR); break;
- case EqInt64: o << int8_t(BinaryConsts::I64Eq); break;
- case NeInt64: o << int8_t(BinaryConsts::I64Ne); break;
- case LtSInt64: o << int8_t(BinaryConsts::I64LtS); break;
- case LtUInt64: o << int8_t(BinaryConsts::I64LtU); break;
- case LeSInt64: o << int8_t(BinaryConsts::I64LeS); break;
- case LeUInt64: o << int8_t(BinaryConsts::I64LeU); break;
- case GtSInt64: o << int8_t(BinaryConsts::I64GtS); break;
- case GtUInt64: o << int8_t(BinaryConsts::I64GtU); break;
- case GeSInt64: o << int8_t(BinaryConsts::I64GeS); break;
- case GeUInt64: o << int8_t(BinaryConsts::I64GeU); break;
-
- case AddFloat32: o << int8_t(BinaryConsts::F32Add); break;
- case SubFloat32: o << int8_t(BinaryConsts::F32Sub); break;
- case MulFloat32: o << int8_t(BinaryConsts::F32Mul); break;
- case DivFloat32: o << int8_t(BinaryConsts::F32Div); break;
- case CopySignFloat32: o << int8_t(BinaryConsts::F32CopySign);break;
- case MinFloat32: o << int8_t(BinaryConsts::F32Min); break;
- case MaxFloat32: o << int8_t(BinaryConsts::F32Max); break;
- case EqFloat32: o << int8_t(BinaryConsts::F32Eq); break;
- case NeFloat32: o << int8_t(BinaryConsts::F32Ne); break;
- case LtFloat32: o << int8_t(BinaryConsts::F32Lt); break;
- case LeFloat32: o << int8_t(BinaryConsts::F32Le); break;
- case GtFloat32: o << int8_t(BinaryConsts::F32Gt); break;
- case GeFloat32: o << int8_t(BinaryConsts::F32Ge); break;
-
- case AddFloat64: o << int8_t(BinaryConsts::F64Add); break;
- case SubFloat64: o << int8_t(BinaryConsts::F64Sub); break;
- case MulFloat64: o << int8_t(BinaryConsts::F64Mul); break;
- case DivFloat64: o << int8_t(BinaryConsts::F64Div); break;
- case CopySignFloat64: o << int8_t(BinaryConsts::F64CopySign);break;
- case MinFloat64: o << int8_t(BinaryConsts::F64Min); break;
- case MaxFloat64: o << int8_t(BinaryConsts::F64Max); break;
- case EqFloat64: o << int8_t(BinaryConsts::F64Eq); break;
- case NeFloat64: o << int8_t(BinaryConsts::F64Ne); break;
- case LtFloat64: o << int8_t(BinaryConsts::F64Lt); break;
- case LeFloat64: o << int8_t(BinaryConsts::F64Le); break;
- case GtFloat64: o << int8_t(BinaryConsts::F64Gt); break;
- case GeFloat64: o << int8_t(BinaryConsts::F64Ge); break;
-
- case EqVecI8x16: o << int8_t(BinaryConsts::SIMDPrefix) << U32LEB(BinaryConsts::I8x16Eq); break;
- case NeVecI8x16: o << int8_t(BinaryConsts::SIMDPrefix) << U32LEB(BinaryConsts::I8x16Ne); break;
- case LtSVecI8x16: o << int8_t(BinaryConsts::SIMDPrefix) << U32LEB(BinaryConsts::I8x16LtS); break;
- case LtUVecI8x16: o << int8_t(BinaryConsts::SIMDPrefix) << U32LEB(BinaryConsts::I8x16LtU); break;
- case GtSVecI8x16: o << int8_t(BinaryConsts::SIMDPrefix) << U32LEB(BinaryConsts::I8x16GtS); break;
- case GtUVecI8x16: o << int8_t(BinaryConsts::SIMDPrefix) << U32LEB(BinaryConsts::I8x16GtU); break;
- case LeSVecI8x16: o << int8_t(BinaryConsts::SIMDPrefix) << U32LEB(BinaryConsts::I8x16LeS); break;
- case LeUVecI8x16: o << int8_t(BinaryConsts::SIMDPrefix) << U32LEB(BinaryConsts::I8x16LeU); break;
- case GeSVecI8x16: o << int8_t(BinaryConsts::SIMDPrefix) << U32LEB(BinaryConsts::I8x16GeS); break;
- case GeUVecI8x16: o << int8_t(BinaryConsts::SIMDPrefix) << U32LEB(BinaryConsts::I8x16GeU); break;
- case EqVecI16x8: o << int8_t(BinaryConsts::SIMDPrefix) << U32LEB(BinaryConsts::I16x8Eq); break;
- case NeVecI16x8: o << int8_t(BinaryConsts::SIMDPrefix) << U32LEB(BinaryConsts::I16x8Ne); break;
- case LtSVecI16x8: o << int8_t(BinaryConsts::SIMDPrefix) << U32LEB(BinaryConsts::I16x8LtS); break;
- case LtUVecI16x8: o << int8_t(BinaryConsts::SIMDPrefix) << U32LEB(BinaryConsts::I16x8LtU); break;
- case GtSVecI16x8: o << int8_t(BinaryConsts::SIMDPrefix) << U32LEB(BinaryConsts::I16x8GtS); break;
- case GtUVecI16x8: o << int8_t(BinaryConsts::SIMDPrefix) << U32LEB(BinaryConsts::I16x8GtU); break;
- case LeSVecI16x8: o << int8_t(BinaryConsts::SIMDPrefix) << U32LEB(BinaryConsts::I16x8LeS); break;
- case LeUVecI16x8: o << int8_t(BinaryConsts::SIMDPrefix) << U32LEB(BinaryConsts::I16x8LeU); break;
- case GeSVecI16x8: o << int8_t(BinaryConsts::SIMDPrefix) << U32LEB(BinaryConsts::I16x8GeS); break;
- case GeUVecI16x8: o << int8_t(BinaryConsts::SIMDPrefix) << U32LEB(BinaryConsts::I16x8GeU); break;
- case EqVecI32x4: o << int8_t(BinaryConsts::SIMDPrefix) << U32LEB(BinaryConsts::I32x4Eq); break;
- case NeVecI32x4: o << int8_t(BinaryConsts::SIMDPrefix) << U32LEB(BinaryConsts::I32x4Ne); break;
- case LtSVecI32x4: o << int8_t(BinaryConsts::SIMDPrefix) << U32LEB(BinaryConsts::I32x4LtS); break;
- case LtUVecI32x4: o << int8_t(BinaryConsts::SIMDPrefix) << U32LEB(BinaryConsts::I32x4LtU); break;
- case GtSVecI32x4: o << int8_t(BinaryConsts::SIMDPrefix) << U32LEB(BinaryConsts::I32x4GtS); break;
- case GtUVecI32x4: o << int8_t(BinaryConsts::SIMDPrefix) << U32LEB(BinaryConsts::I32x4GtU); break;
- case LeSVecI32x4: o << int8_t(BinaryConsts::SIMDPrefix) << U32LEB(BinaryConsts::I32x4LeS); break;
- case LeUVecI32x4: o << int8_t(BinaryConsts::SIMDPrefix) << U32LEB(BinaryConsts::I32x4LeU); break;
- case GeSVecI32x4: o << int8_t(BinaryConsts::SIMDPrefix) << U32LEB(BinaryConsts::I32x4GeS); break;
- case GeUVecI32x4: o << int8_t(BinaryConsts::SIMDPrefix) << U32LEB(BinaryConsts::I32x4GeU); break;
- case EqVecF32x4: o << int8_t(BinaryConsts::SIMDPrefix) << U32LEB(BinaryConsts::F32x4Eq); break;
- case NeVecF32x4: o << int8_t(BinaryConsts::SIMDPrefix) << U32LEB(BinaryConsts::F32x4Ne); break;
- case LtVecF32x4: o << int8_t(BinaryConsts::SIMDPrefix) << U32LEB(BinaryConsts::F32x4Lt); break;
- case GtVecF32x4: o << int8_t(BinaryConsts::SIMDPrefix) << U32LEB(BinaryConsts::F32x4Gt); break;
- case LeVecF32x4: o << int8_t(BinaryConsts::SIMDPrefix) << U32LEB(BinaryConsts::F32x4Le); break;
- case GeVecF32x4: o << int8_t(BinaryConsts::SIMDPrefix) << U32LEB(BinaryConsts::F32x4Ge); break;
- case EqVecF64x2: o << int8_t(BinaryConsts::SIMDPrefix) << U32LEB(BinaryConsts::F64x2Eq); break;
- case NeVecF64x2: o << int8_t(BinaryConsts::SIMDPrefix) << U32LEB(BinaryConsts::F64x2Ne); break;
- case LtVecF64x2: o << int8_t(BinaryConsts::SIMDPrefix) << U32LEB(BinaryConsts::F64x2Lt); break;
- case GtVecF64x2: o << int8_t(BinaryConsts::SIMDPrefix) << U32LEB(BinaryConsts::F64x2Gt); break;
- case LeVecF64x2: o << int8_t(BinaryConsts::SIMDPrefix) << U32LEB(BinaryConsts::F64x2Le); break;
- case GeVecF64x2: o << int8_t(BinaryConsts::SIMDPrefix) << U32LEB(BinaryConsts::F64x2Ge); break;
- case AndVec128: o << int8_t(BinaryConsts::SIMDPrefix) << U32LEB(BinaryConsts::V128And); break;
- case OrVec128: o << int8_t(BinaryConsts::SIMDPrefix) << U32LEB(BinaryConsts::V128Or); break;
- case XorVec128: o << int8_t(BinaryConsts::SIMDPrefix) << U32LEB(BinaryConsts::V128Xor); break;
-
- case AddVecI8x16: o << int8_t(BinaryConsts::SIMDPrefix) << U32LEB(BinaryConsts::I8x16Add); break;
- case AddSatSVecI8x16: o << int8_t(BinaryConsts::SIMDPrefix) << U32LEB(BinaryConsts::I8x16AddSatS); break;
- case AddSatUVecI8x16: o << int8_t(BinaryConsts::SIMDPrefix) << U32LEB(BinaryConsts::I8x16AddSatU); break;
- case SubVecI8x16: o << int8_t(BinaryConsts::SIMDPrefix) << U32LEB(BinaryConsts::I8x16Sub); break;
- case SubSatSVecI8x16: o << int8_t(BinaryConsts::SIMDPrefix) << U32LEB(BinaryConsts::I8x16SubSatS); break;
- case SubSatUVecI8x16: o << int8_t(BinaryConsts::SIMDPrefix) << U32LEB(BinaryConsts::I8x16SubSatU); break;
- case MulVecI8x16: o << int8_t(BinaryConsts::SIMDPrefix) << U32LEB(BinaryConsts::I8x16Mul); break;
- case AddVecI16x8: o << int8_t(BinaryConsts::SIMDPrefix) << U32LEB(BinaryConsts::I16x8Add); break;
- case AddSatSVecI16x8: o << int8_t(BinaryConsts::SIMDPrefix) << U32LEB(BinaryConsts::I16x8AddSatS); break;
- case AddSatUVecI16x8: o << int8_t(BinaryConsts::SIMDPrefix) << U32LEB(BinaryConsts::I16x8AddSatU); break;
- case SubVecI16x8: o << int8_t(BinaryConsts::SIMDPrefix) << U32LEB(BinaryConsts::I16x8Sub); break;
- case SubSatSVecI16x8: o << int8_t(BinaryConsts::SIMDPrefix) << U32LEB(BinaryConsts::I16x8SubSatS); break;
- case SubSatUVecI16x8: o << int8_t(BinaryConsts::SIMDPrefix) << U32LEB(BinaryConsts::I16x8SubSatU); break;
- case MulVecI16x8: o << int8_t(BinaryConsts::SIMDPrefix) << U32LEB(BinaryConsts::I16x8Mul); break;
- case AddVecI32x4: o << int8_t(BinaryConsts::SIMDPrefix) << U32LEB(BinaryConsts::I32x4Add); break;
- case SubVecI32x4: o << int8_t(BinaryConsts::SIMDPrefix) << U32LEB(BinaryConsts::I32x4Sub); break;
- case MulVecI32x4: o << int8_t(BinaryConsts::SIMDPrefix) << U32LEB(BinaryConsts::I32x4Mul); break;
- case AddVecI64x2: o << int8_t(BinaryConsts::SIMDPrefix) << U32LEB(BinaryConsts::I64x2Add); break;
- case SubVecI64x2: o << int8_t(BinaryConsts::SIMDPrefix) << U32LEB(BinaryConsts::I64x2Sub); break;
-
- case AddVecF32x4: o << int8_t(BinaryConsts::SIMDPrefix) << U32LEB(BinaryConsts::F32x4Add); break;
- case SubVecF32x4: o << int8_t(BinaryConsts::SIMDPrefix) << U32LEB(BinaryConsts::F32x4Sub); break;
- case MulVecF32x4: o << int8_t(BinaryConsts::SIMDPrefix) << U32LEB(BinaryConsts::F32x4Mul); break;
- case DivVecF32x4: o << int8_t(BinaryConsts::SIMDPrefix) << U32LEB(BinaryConsts::F32x4Div); break;
- case MinVecF32x4: o << int8_t(BinaryConsts::SIMDPrefix) << U32LEB(BinaryConsts::F32x4Min); break;
- case MaxVecF32x4: o << int8_t(BinaryConsts::SIMDPrefix) << U32LEB(BinaryConsts::F32x4Max); break;
- case AddVecF64x2: o << int8_t(BinaryConsts::SIMDPrefix) << U32LEB(BinaryConsts::F64x2Add); break;
- case SubVecF64x2: o << int8_t(BinaryConsts::SIMDPrefix) << U32LEB(BinaryConsts::F64x2Sub); break;
- case MulVecF64x2: o << int8_t(BinaryConsts::SIMDPrefix) << U32LEB(BinaryConsts::F64x2Mul); break;
- case DivVecF64x2: o << int8_t(BinaryConsts::SIMDPrefix) << U32LEB(BinaryConsts::F64x2Div); break;
- case MinVecF64x2: o << int8_t(BinaryConsts::SIMDPrefix) << U32LEB(BinaryConsts::F64x2Min); break;
- case MaxVecF64x2: o << int8_t(BinaryConsts::SIMDPrefix) << U32LEB(BinaryConsts::F64x2Max); break;
- case InvalidBinary: WASM_UNREACHABLE();
+ case AddInt32:
+ o << int8_t(BinaryConsts::I32Add);
+ break;
+ case SubInt32:
+ o << int8_t(BinaryConsts::I32Sub);
+ break;
+ case MulInt32:
+ o << int8_t(BinaryConsts::I32Mul);
+ break;
+ case DivSInt32:
+ o << int8_t(BinaryConsts::I32DivS);
+ break;
+ case DivUInt32:
+ o << int8_t(BinaryConsts::I32DivU);
+ break;
+ case RemSInt32:
+ o << int8_t(BinaryConsts::I32RemS);
+ break;
+ case RemUInt32:
+ o << int8_t(BinaryConsts::I32RemU);
+ break;
+ case AndInt32:
+ o << int8_t(BinaryConsts::I32And);
+ break;
+ case OrInt32:
+ o << int8_t(BinaryConsts::I32Or);
+ break;
+ case XorInt32:
+ o << int8_t(BinaryConsts::I32Xor);
+ break;
+ case ShlInt32:
+ o << int8_t(BinaryConsts::I32Shl);
+ break;
+ case ShrUInt32:
+ o << int8_t(BinaryConsts::I32ShrU);
+ break;
+ case ShrSInt32:
+ o << int8_t(BinaryConsts::I32ShrS);
+ break;
+ case RotLInt32:
+ o << int8_t(BinaryConsts::I32RotL);
+ break;
+ case RotRInt32:
+ o << int8_t(BinaryConsts::I32RotR);
+ break;
+ case EqInt32:
+ o << int8_t(BinaryConsts::I32Eq);
+ break;
+ case NeInt32:
+ o << int8_t(BinaryConsts::I32Ne);
+ break;
+ case LtSInt32:
+ o << int8_t(BinaryConsts::I32LtS);
+ break;
+ case LtUInt32:
+ o << int8_t(BinaryConsts::I32LtU);
+ break;
+ case LeSInt32:
+ o << int8_t(BinaryConsts::I32LeS);
+ break;
+ case LeUInt32:
+ o << int8_t(BinaryConsts::I32LeU);
+ break;
+ case GtSInt32:
+ o << int8_t(BinaryConsts::I32GtS);
+ break;
+ case GtUInt32:
+ o << int8_t(BinaryConsts::I32GtU);
+ break;
+ case GeSInt32:
+ o << int8_t(BinaryConsts::I32GeS);
+ break;
+ case GeUInt32:
+ o << int8_t(BinaryConsts::I32GeU);
+ break;
+
+ case AddInt64:
+ o << int8_t(BinaryConsts::I64Add);
+ break;
+ case SubInt64:
+ o << int8_t(BinaryConsts::I64Sub);
+ break;
+ case MulInt64:
+ o << int8_t(BinaryConsts::I64Mul);
+ break;
+ case DivSInt64:
+ o << int8_t(BinaryConsts::I64DivS);
+ break;
+ case DivUInt64:
+ o << int8_t(BinaryConsts::I64DivU);
+ break;
+ case RemSInt64:
+ o << int8_t(BinaryConsts::I64RemS);
+ break;
+ case RemUInt64:
+ o << int8_t(BinaryConsts::I64RemU);
+ break;
+ case AndInt64:
+ o << int8_t(BinaryConsts::I64And);
+ break;
+ case OrInt64:
+ o << int8_t(BinaryConsts::I64Or);
+ break;
+ case XorInt64:
+ o << int8_t(BinaryConsts::I64Xor);
+ break;
+ case ShlInt64:
+ o << int8_t(BinaryConsts::I64Shl);
+ break;
+ case ShrUInt64:
+ o << int8_t(BinaryConsts::I64ShrU);
+ break;
+ case ShrSInt64:
+ o << int8_t(BinaryConsts::I64ShrS);
+ break;
+ case RotLInt64:
+ o << int8_t(BinaryConsts::I64RotL);
+ break;
+ case RotRInt64:
+ o << int8_t(BinaryConsts::I64RotR);
+ break;
+ case EqInt64:
+ o << int8_t(BinaryConsts::I64Eq);
+ break;
+ case NeInt64:
+ o << int8_t(BinaryConsts::I64Ne);
+ break;
+ case LtSInt64:
+ o << int8_t(BinaryConsts::I64LtS);
+ break;
+ case LtUInt64:
+ o << int8_t(BinaryConsts::I64LtU);
+ break;
+ case LeSInt64:
+ o << int8_t(BinaryConsts::I64LeS);
+ break;
+ case LeUInt64:
+ o << int8_t(BinaryConsts::I64LeU);
+ break;
+ case GtSInt64:
+ o << int8_t(BinaryConsts::I64GtS);
+ break;
+ case GtUInt64:
+ o << int8_t(BinaryConsts::I64GtU);
+ break;
+ case GeSInt64:
+ o << int8_t(BinaryConsts::I64GeS);
+ break;
+ case GeUInt64:
+ o << int8_t(BinaryConsts::I64GeU);
+ break;
+
+ case AddFloat32:
+ o << int8_t(BinaryConsts::F32Add);
+ break;
+ case SubFloat32:
+ o << int8_t(BinaryConsts::F32Sub);
+ break;
+ case MulFloat32:
+ o << int8_t(BinaryConsts::F32Mul);
+ break;
+ case DivFloat32:
+ o << int8_t(BinaryConsts::F32Div);
+ break;
+ case CopySignFloat32:
+ o << int8_t(BinaryConsts::F32CopySign);
+ break;
+ case MinFloat32:
+ o << int8_t(BinaryConsts::F32Min);
+ break;
+ case MaxFloat32:
+ o << int8_t(BinaryConsts::F32Max);
+ break;
+ case EqFloat32:
+ o << int8_t(BinaryConsts::F32Eq);
+ break;
+ case NeFloat32:
+ o << int8_t(BinaryConsts::F32Ne);
+ break;
+ case LtFloat32:
+ o << int8_t(BinaryConsts::F32Lt);
+ break;
+ case LeFloat32:
+ o << int8_t(BinaryConsts::F32Le);
+ break;
+ case GtFloat32:
+ o << int8_t(BinaryConsts::F32Gt);
+ break;
+ case GeFloat32:
+ o << int8_t(BinaryConsts::F32Ge);
+ break;
+
+ case AddFloat64:
+ o << int8_t(BinaryConsts::F64Add);
+ break;
+ case SubFloat64:
+ o << int8_t(BinaryConsts::F64Sub);
+ break;
+ case MulFloat64:
+ o << int8_t(BinaryConsts::F64Mul);
+ break;
+ case DivFloat64:
+ o << int8_t(BinaryConsts::F64Div);
+ break;
+ case CopySignFloat64:
+ o << int8_t(BinaryConsts::F64CopySign);
+ break;
+ case MinFloat64:
+ o << int8_t(BinaryConsts::F64Min);
+ break;
+ case MaxFloat64:
+ o << int8_t(BinaryConsts::F64Max);
+ break;
+ case EqFloat64:
+ o << int8_t(BinaryConsts::F64Eq);
+ break;
+ case NeFloat64:
+ o << int8_t(BinaryConsts::F64Ne);
+ break;
+ case LtFloat64:
+ o << int8_t(BinaryConsts::F64Lt);
+ break;
+ case LeFloat64:
+ o << int8_t(BinaryConsts::F64Le);
+ break;
+ case GtFloat64:
+ o << int8_t(BinaryConsts::F64Gt);
+ break;
+ case GeFloat64:
+ o << int8_t(BinaryConsts::F64Ge);
+ break;
+
+ case EqVecI8x16:
+ o << int8_t(BinaryConsts::SIMDPrefix) << U32LEB(BinaryConsts::I8x16Eq);
+ break;
+ case NeVecI8x16:
+ o << int8_t(BinaryConsts::SIMDPrefix) << U32LEB(BinaryConsts::I8x16Ne);
+ break;
+ case LtSVecI8x16:
+ o << int8_t(BinaryConsts::SIMDPrefix) << U32LEB(BinaryConsts::I8x16LtS);
+ break;
+ case LtUVecI8x16:
+ o << int8_t(BinaryConsts::SIMDPrefix) << U32LEB(BinaryConsts::I8x16LtU);
+ break;
+ case GtSVecI8x16:
+ o << int8_t(BinaryConsts::SIMDPrefix) << U32LEB(BinaryConsts::I8x16GtS);
+ break;
+ case GtUVecI8x16:
+ o << int8_t(BinaryConsts::SIMDPrefix) << U32LEB(BinaryConsts::I8x16GtU);
+ break;
+ case LeSVecI8x16:
+ o << int8_t(BinaryConsts::SIMDPrefix) << U32LEB(BinaryConsts::I8x16LeS);
+ break;
+ case LeUVecI8x16:
+ o << int8_t(BinaryConsts::SIMDPrefix) << U32LEB(BinaryConsts::I8x16LeU);
+ break;
+ case GeSVecI8x16:
+ o << int8_t(BinaryConsts::SIMDPrefix) << U32LEB(BinaryConsts::I8x16GeS);
+ break;
+ case GeUVecI8x16:
+ o << int8_t(BinaryConsts::SIMDPrefix) << U32LEB(BinaryConsts::I8x16GeU);
+ break;
+ case EqVecI16x8:
+ o << int8_t(BinaryConsts::SIMDPrefix) << U32LEB(BinaryConsts::I16x8Eq);
+ break;
+ case NeVecI16x8:
+ o << int8_t(BinaryConsts::SIMDPrefix) << U32LEB(BinaryConsts::I16x8Ne);
+ break;
+ case LtSVecI16x8:
+ o << int8_t(BinaryConsts::SIMDPrefix) << U32LEB(BinaryConsts::I16x8LtS);
+ break;
+ case LtUVecI16x8:
+ o << int8_t(BinaryConsts::SIMDPrefix) << U32LEB(BinaryConsts::I16x8LtU);
+ break;
+ case GtSVecI16x8:
+ o << int8_t(BinaryConsts::SIMDPrefix) << U32LEB(BinaryConsts::I16x8GtS);
+ break;
+ case GtUVecI16x8:
+ o << int8_t(BinaryConsts::SIMDPrefix) << U32LEB(BinaryConsts::I16x8GtU);
+ break;
+ case LeSVecI16x8:
+ o << int8_t(BinaryConsts::SIMDPrefix) << U32LEB(BinaryConsts::I16x8LeS);
+ break;
+ case LeUVecI16x8:
+ o << int8_t(BinaryConsts::SIMDPrefix) << U32LEB(BinaryConsts::I16x8LeU);
+ break;
+ case GeSVecI16x8:
+ o << int8_t(BinaryConsts::SIMDPrefix) << U32LEB(BinaryConsts::I16x8GeS);
+ break;
+ case GeUVecI16x8:
+ o << int8_t(BinaryConsts::SIMDPrefix) << U32LEB(BinaryConsts::I16x8GeU);
+ break;
+ case EqVecI32x4:
+ o << int8_t(BinaryConsts::SIMDPrefix) << U32LEB(BinaryConsts::I32x4Eq);
+ break;
+ case NeVecI32x4:
+ o << int8_t(BinaryConsts::SIMDPrefix) << U32LEB(BinaryConsts::I32x4Ne);
+ break;
+ case LtSVecI32x4:
+ o << int8_t(BinaryConsts::SIMDPrefix) << U32LEB(BinaryConsts::I32x4LtS);
+ break;
+ case LtUVecI32x4:
+ o << int8_t(BinaryConsts::SIMDPrefix) << U32LEB(BinaryConsts::I32x4LtU);
+ break;
+ case GtSVecI32x4:
+ o << int8_t(BinaryConsts::SIMDPrefix) << U32LEB(BinaryConsts::I32x4GtS);
+ break;
+ case GtUVecI32x4:
+ o << int8_t(BinaryConsts::SIMDPrefix) << U32LEB(BinaryConsts::I32x4GtU);
+ break;
+ case LeSVecI32x4:
+ o << int8_t(BinaryConsts::SIMDPrefix) << U32LEB(BinaryConsts::I32x4LeS);
+ break;
+ case LeUVecI32x4:
+ o << int8_t(BinaryConsts::SIMDPrefix) << U32LEB(BinaryConsts::I32x4LeU);
+ break;
+ case GeSVecI32x4:
+ o << int8_t(BinaryConsts::SIMDPrefix) << U32LEB(BinaryConsts::I32x4GeS);
+ break;
+ case GeUVecI32x4:
+ o << int8_t(BinaryConsts::SIMDPrefix) << U32LEB(BinaryConsts::I32x4GeU);
+ break;
+ case EqVecF32x4:
+ o << int8_t(BinaryConsts::SIMDPrefix) << U32LEB(BinaryConsts::F32x4Eq);
+ break;
+ case NeVecF32x4:
+ o << int8_t(BinaryConsts::SIMDPrefix) << U32LEB(BinaryConsts::F32x4Ne);
+ break;
+ case LtVecF32x4:
+ o << int8_t(BinaryConsts::SIMDPrefix) << U32LEB(BinaryConsts::F32x4Lt);
+ break;
+ case GtVecF32x4:
+ o << int8_t(BinaryConsts::SIMDPrefix) << U32LEB(BinaryConsts::F32x4Gt);
+ break;
+ case LeVecF32x4:
+ o << int8_t(BinaryConsts::SIMDPrefix) << U32LEB(BinaryConsts::F32x4Le);
+ break;
+ case GeVecF32x4:
+ o << int8_t(BinaryConsts::SIMDPrefix) << U32LEB(BinaryConsts::F32x4Ge);
+ break;
+ case EqVecF64x2:
+ o << int8_t(BinaryConsts::SIMDPrefix) << U32LEB(BinaryConsts::F64x2Eq);
+ break;
+ case NeVecF64x2:
+ o << int8_t(BinaryConsts::SIMDPrefix) << U32LEB(BinaryConsts::F64x2Ne);
+ break;
+ case LtVecF64x2:
+ o << int8_t(BinaryConsts::SIMDPrefix) << U32LEB(BinaryConsts::F64x2Lt);
+ break;
+ case GtVecF64x2:
+ o << int8_t(BinaryConsts::SIMDPrefix) << U32LEB(BinaryConsts::F64x2Gt);
+ break;
+ case LeVecF64x2:
+ o << int8_t(BinaryConsts::SIMDPrefix) << U32LEB(BinaryConsts::F64x2Le);
+ break;
+ case GeVecF64x2:
+ o << int8_t(BinaryConsts::SIMDPrefix) << U32LEB(BinaryConsts::F64x2Ge);
+ break;
+ case AndVec128:
+ o << int8_t(BinaryConsts::SIMDPrefix) << U32LEB(BinaryConsts::V128And);
+ break;
+ case OrVec128:
+ o << int8_t(BinaryConsts::SIMDPrefix) << U32LEB(BinaryConsts::V128Or);
+ break;
+ case XorVec128:
+ o << int8_t(BinaryConsts::SIMDPrefix) << U32LEB(BinaryConsts::V128Xor);
+ break;
+
+ case AddVecI8x16:
+ o << int8_t(BinaryConsts::SIMDPrefix) << U32LEB(BinaryConsts::I8x16Add);
+ break;
+ case AddSatSVecI8x16:
+ o << int8_t(BinaryConsts::SIMDPrefix)
+ << U32LEB(BinaryConsts::I8x16AddSatS);
+ break;
+ case AddSatUVecI8x16:
+ o << int8_t(BinaryConsts::SIMDPrefix)
+ << U32LEB(BinaryConsts::I8x16AddSatU);
+ break;
+ case SubVecI8x16:
+ o << int8_t(BinaryConsts::SIMDPrefix) << U32LEB(BinaryConsts::I8x16Sub);
+ break;
+ case SubSatSVecI8x16:
+ o << int8_t(BinaryConsts::SIMDPrefix)
+ << U32LEB(BinaryConsts::I8x16SubSatS);
+ break;
+ case SubSatUVecI8x16:
+ o << int8_t(BinaryConsts::SIMDPrefix)
+ << U32LEB(BinaryConsts::I8x16SubSatU);
+ break;
+ case MulVecI8x16:
+ o << int8_t(BinaryConsts::SIMDPrefix) << U32LEB(BinaryConsts::I8x16Mul);
+ break;
+ case AddVecI16x8:
+ o << int8_t(BinaryConsts::SIMDPrefix) << U32LEB(BinaryConsts::I16x8Add);
+ break;
+ case AddSatSVecI16x8:
+ o << int8_t(BinaryConsts::SIMDPrefix)
+ << U32LEB(BinaryConsts::I16x8AddSatS);
+ break;
+ case AddSatUVecI16x8:
+ o << int8_t(BinaryConsts::SIMDPrefix)
+ << U32LEB(BinaryConsts::I16x8AddSatU);
+ break;
+ case SubVecI16x8:
+ o << int8_t(BinaryConsts::SIMDPrefix) << U32LEB(BinaryConsts::I16x8Sub);
+ break;
+ case SubSatSVecI16x8:
+ o << int8_t(BinaryConsts::SIMDPrefix)
+ << U32LEB(BinaryConsts::I16x8SubSatS);
+ break;
+ case SubSatUVecI16x8:
+ o << int8_t(BinaryConsts::SIMDPrefix)
+ << U32LEB(BinaryConsts::I16x8SubSatU);
+ break;
+ case MulVecI16x8:
+ o << int8_t(BinaryConsts::SIMDPrefix) << U32LEB(BinaryConsts::I16x8Mul);
+ break;
+ case AddVecI32x4:
+ o << int8_t(BinaryConsts::SIMDPrefix) << U32LEB(BinaryConsts::I32x4Add);
+ break;
+ case SubVecI32x4:
+ o << int8_t(BinaryConsts::SIMDPrefix) << U32LEB(BinaryConsts::I32x4Sub);
+ break;
+ case MulVecI32x4:
+ o << int8_t(BinaryConsts::SIMDPrefix) << U32LEB(BinaryConsts::I32x4Mul);
+ break;
+ case AddVecI64x2:
+ o << int8_t(BinaryConsts::SIMDPrefix) << U32LEB(BinaryConsts::I64x2Add);
+ break;
+ case SubVecI64x2:
+ o << int8_t(BinaryConsts::SIMDPrefix) << U32LEB(BinaryConsts::I64x2Sub);
+ break;
+
+ case AddVecF32x4:
+ o << int8_t(BinaryConsts::SIMDPrefix) << U32LEB(BinaryConsts::F32x4Add);
+ break;
+ case SubVecF32x4:
+ o << int8_t(BinaryConsts::SIMDPrefix) << U32LEB(BinaryConsts::F32x4Sub);
+ break;
+ case MulVecF32x4:
+ o << int8_t(BinaryConsts::SIMDPrefix) << U32LEB(BinaryConsts::F32x4Mul);
+ break;
+ case DivVecF32x4:
+ o << int8_t(BinaryConsts::SIMDPrefix) << U32LEB(BinaryConsts::F32x4Div);
+ break;
+ case MinVecF32x4:
+ o << int8_t(BinaryConsts::SIMDPrefix) << U32LEB(BinaryConsts::F32x4Min);
+ break;
+ case MaxVecF32x4:
+ o << int8_t(BinaryConsts::SIMDPrefix) << U32LEB(BinaryConsts::F32x4Max);
+ break;
+ case AddVecF64x2:
+ o << int8_t(BinaryConsts::SIMDPrefix) << U32LEB(BinaryConsts::F64x2Add);
+ break;
+ case SubVecF64x2:
+ o << int8_t(BinaryConsts::SIMDPrefix) << U32LEB(BinaryConsts::F64x2Sub);
+ break;
+ case MulVecF64x2:
+ o << int8_t(BinaryConsts::SIMDPrefix) << U32LEB(BinaryConsts::F64x2Mul);
+ break;
+ case DivVecF64x2:
+ o << int8_t(BinaryConsts::SIMDPrefix) << U32LEB(BinaryConsts::F64x2Div);
+ break;
+ case MinVecF64x2:
+ o << int8_t(BinaryConsts::SIMDPrefix) << U32LEB(BinaryConsts::F64x2Min);
+ break;
+ case MaxVecF64x2:
+ o << int8_t(BinaryConsts::SIMDPrefix) << U32LEB(BinaryConsts::F64x2Max);
+ break;
+ case InvalidBinary:
+ WASM_UNREACHABLE();
}
}
@@ -1342,7 +2111,8 @@ void StackWriter<Mode, Parent>::visitSelect(Select* curr) {
emitExtraUnreachable();
return;
}
- if (justAddToStack(curr)) return;
+ if (justAddToStack(curr))
+ return;
o << int8_t(BinaryConsts::Select);
}
@@ -1351,7 +2121,8 @@ void StackWriter<Mode, Parent>::visitReturn(Return* curr) {
if (curr->value) {
visitChild(curr->value);
}
- if (justAddToStack(curr)) return;
+ if (justAddToStack(curr))
+ return;
o << int8_t(BinaryConsts::Return);
}
@@ -1367,7 +2138,8 @@ void StackWriter<Mode, Parent>::visitHost(Host* curr) {
break;
}
}
- if (justAddToStack(curr)) return;
+ if (justAddToStack(curr))
+ return;
switch (curr->op) {
case CurrentMemory: {
o << int8_t(BinaryConsts::CurrentMemory);
@@ -1383,20 +2155,23 @@ void StackWriter<Mode, Parent>::visitHost(Host* curr) {
template<StackWriterMode Mode, typename Parent>
void StackWriter<Mode, Parent>::visitNop(Nop* curr) {
- if (justAddToStack(curr)) return;
+ if (justAddToStack(curr))
+ return;
o << int8_t(BinaryConsts::Nop);
}
template<StackWriterMode Mode, typename Parent>
void StackWriter<Mode, Parent>::visitUnreachable(Unreachable* curr) {
- if (justAddToStack(curr)) return;
+ if (justAddToStack(curr))
+ return;
o << int8_t(BinaryConsts::Unreachable);
}
template<StackWriterMode Mode, typename Parent>
void StackWriter<Mode, Parent>::visitDrop(Drop* curr) {
visitChild(curr->value);
- if (justAddToStack(curr)) return;
+ if (justAddToStack(curr))
+ return;
o << int8_t(BinaryConsts::Drop);
}
@@ -1411,7 +2186,9 @@ int32_t StackWriter<Mode, Parent>::getBreakIndex(Name name) { // -1 if not found
}
template<StackWriterMode Mode, typename Parent>
-void StackWriter<Mode, Parent>::emitMemoryAccess(size_t alignment, size_t bytes, uint32_t offset) {
+void StackWriter<Mode, Parent>::emitMemoryAccess(size_t alignment,
+ size_t bytes,
+ uint32_t offset) {
o << U32LEB(Log2(alignment ? alignment : bytes));
o << U32LEB(offset);
}
@@ -1443,18 +2220,19 @@ void StackWriter<Mode, Parent>::finishFunctionBody() {
}
template<StackWriterMode Mode, typename Parent>
-StackInst* StackWriter<Mode, Parent>::makeStackInst(StackInst::Op op, Expression* origin) {
+StackInst* StackWriter<Mode, Parent>::makeStackInst(StackInst::Op op,
+ Expression* origin) {
auto* ret = allocator.alloc<StackInst>();
ret->op = op;
ret->origin = origin;
auto stackType = origin->type;
if (origin->is<Block>() || origin->is<Loop>() || origin->is<If>()) {
if (stackType == unreachable) {
- // There are no unreachable blocks, loops, or ifs. we emit extra unreachables
- // to fix that up, so that they are valid as having none type.
+ // There are no unreachable blocks, loops, or ifs. we emit extra
+ // unreachables to fix that up, so that they are valid as having none
+ // type.
stackType = none;
- } else if (op != StackInst::BlockEnd &&
- op != StackInst::IfEnd &&
+ } else if (op != StackInst::BlockEnd && op != StackInst::IfEnd &&
op != StackInst::LoopEnd) {
// If a concrete type is returned, we mark the end of the construct has
// having that type (as it is pushed to the value stack at that point),
diff --git a/src/wasm-traversal.h b/src/wasm-traversal.h
index 38fcdb990..2b495e025 100644
--- a/src/wasm-traversal.h
+++ b/src/wasm-traversal.h
@@ -27,16 +27,15 @@
#ifndef wasm_wasm_traversal_h
#define wasm_wasm_traversal_h
-#include "wasm.h"
#include "support/small_vector.h"
#include "support/threads.h"
+#include "wasm.h"
namespace wasm {
// A generic visitor, defaulting to doing nothing on each visit
-template<typename SubType, typename ReturnType = void>
-struct Visitor {
+template<typename SubType, typename ReturnType = void> struct Visitor {
// Expression visitors
ReturnType visitBlock(Block* curr) { return ReturnType(); }
ReturnType visitIf(If* curr) { return ReturnType(); }
@@ -85,51 +84,87 @@ struct Visitor {
ReturnType visit(Expression* curr) {
assert(curr);
- #define DELEGATE(CLASS_TO_VISIT) \
- return static_cast<SubType*>(this)-> \
- visit##CLASS_TO_VISIT(static_cast<CLASS_TO_VISIT*>(curr))
+#define DELEGATE(CLASS_TO_VISIT) \
+ return static_cast<SubType*>(this)->visit##CLASS_TO_VISIT( \
+ static_cast<CLASS_TO_VISIT*>(curr))
switch (curr->_id) {
- case Expression::Id::BlockId: DELEGATE(Block);
- case Expression::Id::IfId: DELEGATE(If);
- case Expression::Id::LoopId: DELEGATE(Loop);
- case Expression::Id::BreakId: DELEGATE(Break);
- case Expression::Id::SwitchId: DELEGATE(Switch);
- case Expression::Id::CallId: DELEGATE(Call);
- case Expression::Id::CallIndirectId: DELEGATE(CallIndirect);
- case Expression::Id::GetLocalId: DELEGATE(GetLocal);
- case Expression::Id::SetLocalId: DELEGATE(SetLocal);
- case Expression::Id::GetGlobalId: DELEGATE(GetGlobal);
- case Expression::Id::SetGlobalId: DELEGATE(SetGlobal);
- case Expression::Id::LoadId: DELEGATE(Load);
- case Expression::Id::StoreId: DELEGATE(Store);
- case Expression::Id::AtomicRMWId: DELEGATE(AtomicRMW);
- case Expression::Id::AtomicCmpxchgId: DELEGATE(AtomicCmpxchg);
- case Expression::Id::AtomicWaitId: DELEGATE(AtomicWait);
- case Expression::Id::AtomicNotifyId: DELEGATE(AtomicNotify);
- case Expression::Id::SIMDExtractId: DELEGATE(SIMDExtract);
- case Expression::Id::SIMDReplaceId: DELEGATE(SIMDReplace);
- case Expression::Id::SIMDShuffleId: DELEGATE(SIMDShuffle);
- case Expression::Id::SIMDBitselectId: DELEGATE(SIMDBitselect);
- case Expression::Id::SIMDShiftId: DELEGATE(SIMDShift);
- case Expression::Id::MemoryInitId: DELEGATE(MemoryInit);
- case Expression::Id::DataDropId: DELEGATE(DataDrop);
- case Expression::Id::MemoryCopyId: DELEGATE(MemoryCopy);
- case Expression::Id::MemoryFillId: DELEGATE(MemoryFill);
- case Expression::Id::ConstId: DELEGATE(Const);
- case Expression::Id::UnaryId: DELEGATE(Unary);
- case Expression::Id::BinaryId: DELEGATE(Binary);
- case Expression::Id::SelectId: DELEGATE(Select);
- case Expression::Id::DropId: DELEGATE(Drop);
- case Expression::Id::ReturnId: DELEGATE(Return);
- case Expression::Id::HostId: DELEGATE(Host);
- case Expression::Id::NopId: DELEGATE(Nop);
- case Expression::Id::UnreachableId: DELEGATE(Unreachable);
+ case Expression::Id::BlockId:
+ DELEGATE(Block);
+ case Expression::Id::IfId:
+ DELEGATE(If);
+ case Expression::Id::LoopId:
+ DELEGATE(Loop);
+ case Expression::Id::BreakId:
+ DELEGATE(Break);
+ case Expression::Id::SwitchId:
+ DELEGATE(Switch);
+ case Expression::Id::CallId:
+ DELEGATE(Call);
+ case Expression::Id::CallIndirectId:
+ DELEGATE(CallIndirect);
+ case Expression::Id::GetLocalId:
+ DELEGATE(GetLocal);
+ case Expression::Id::SetLocalId:
+ DELEGATE(SetLocal);
+ case Expression::Id::GetGlobalId:
+ DELEGATE(GetGlobal);
+ case Expression::Id::SetGlobalId:
+ DELEGATE(SetGlobal);
+ case Expression::Id::LoadId:
+ DELEGATE(Load);
+ case Expression::Id::StoreId:
+ DELEGATE(Store);
+ case Expression::Id::AtomicRMWId:
+ DELEGATE(AtomicRMW);
+ case Expression::Id::AtomicCmpxchgId:
+ DELEGATE(AtomicCmpxchg);
+ case Expression::Id::AtomicWaitId:
+ DELEGATE(AtomicWait);
+ case Expression::Id::AtomicNotifyId:
+ DELEGATE(AtomicNotify);
+ case Expression::Id::SIMDExtractId:
+ DELEGATE(SIMDExtract);
+ case Expression::Id::SIMDReplaceId:
+ DELEGATE(SIMDReplace);
+ case Expression::Id::SIMDShuffleId:
+ DELEGATE(SIMDShuffle);
+ case Expression::Id::SIMDBitselectId:
+ DELEGATE(SIMDBitselect);
+ case Expression::Id::SIMDShiftId:
+ DELEGATE(SIMDShift);
+ case Expression::Id::MemoryInitId:
+ DELEGATE(MemoryInit);
+ case Expression::Id::DataDropId:
+ DELEGATE(DataDrop);
+ case Expression::Id::MemoryCopyId:
+ DELEGATE(MemoryCopy);
+ case Expression::Id::MemoryFillId:
+ DELEGATE(MemoryFill);
+ case Expression::Id::ConstId:
+ DELEGATE(Const);
+ case Expression::Id::UnaryId:
+ DELEGATE(Unary);
+ case Expression::Id::BinaryId:
+ DELEGATE(Binary);
+ case Expression::Id::SelectId:
+ DELEGATE(Select);
+ case Expression::Id::DropId:
+ DELEGATE(Drop);
+ case Expression::Id::ReturnId:
+ DELEGATE(Return);
+ case Expression::Id::HostId:
+ DELEGATE(Host);
+ case Expression::Id::NopId:
+ DELEGATE(Nop);
+ case Expression::Id::UnreachableId:
+ DELEGATE(Unreachable);
case Expression::Id::InvalidId:
- default: WASM_UNREACHABLE();
+ default:
+ WASM_UNREACHABLE();
}
- #undef DELEGATE
+#undef DELEGATE
}
};
@@ -137,12 +172,15 @@ struct Visitor {
template<typename SubType, typename ReturnType = void>
struct OverriddenVisitor {
- // Expression visitors, which must be overridden
- #define UNIMPLEMENTED(CLASS_TO_VISIT) \
- ReturnType visit##CLASS_TO_VISIT(CLASS_TO_VISIT* curr) { \
- static_assert(&SubType::visit##CLASS_TO_VISIT != &OverriddenVisitor<SubType, ReturnType>::visit##CLASS_TO_VISIT, "Derived class must implement visit" #CLASS_TO_VISIT); \
- WASM_UNREACHABLE(); \
- }
+// Expression visitors, which must be overridden
+#define UNIMPLEMENTED(CLASS_TO_VISIT) \
+ ReturnType visit##CLASS_TO_VISIT(CLASS_TO_VISIT* curr) { \
+ static_assert( \
+ &SubType::visit##CLASS_TO_VISIT != \
+ &OverriddenVisitor<SubType, ReturnType>::visit##CLASS_TO_VISIT, \
+ "Derived class must implement visit" #CLASS_TO_VISIT); \
+ WASM_UNREACHABLE(); \
+ }
UNIMPLEMENTED(Block);
UNIMPLEMENTED(If);
@@ -187,56 +225,92 @@ struct OverriddenVisitor {
UNIMPLEMENTED(Memory);
UNIMPLEMENTED(Module);
- #undef UNIMPLEMENTED
+#undef UNIMPLEMENTED
ReturnType visit(Expression* curr) {
assert(curr);
- #define DELEGATE(CLASS_TO_VISIT) \
- return static_cast<SubType*>(this)-> \
- visit##CLASS_TO_VISIT(static_cast<CLASS_TO_VISIT*>(curr))
+#define DELEGATE(CLASS_TO_VISIT) \
+ return static_cast<SubType*>(this)->visit##CLASS_TO_VISIT( \
+ static_cast<CLASS_TO_VISIT*>(curr))
switch (curr->_id) {
- case Expression::Id::BlockId: DELEGATE(Block);
- case Expression::Id::IfId: DELEGATE(If);
- case Expression::Id::LoopId: DELEGATE(Loop);
- case Expression::Id::BreakId: DELEGATE(Break);
- case Expression::Id::SwitchId: DELEGATE(Switch);
- case Expression::Id::CallId: DELEGATE(Call);
- case Expression::Id::CallIndirectId: DELEGATE(CallIndirect);
- case Expression::Id::GetLocalId: DELEGATE(GetLocal);
- case Expression::Id::SetLocalId: DELEGATE(SetLocal);
- case Expression::Id::GetGlobalId: DELEGATE(GetGlobal);
- case Expression::Id::SetGlobalId: DELEGATE(SetGlobal);
- case Expression::Id::LoadId: DELEGATE(Load);
- case Expression::Id::StoreId: DELEGATE(Store);
- case Expression::Id::AtomicRMWId: DELEGATE(AtomicRMW);
- case Expression::Id::AtomicCmpxchgId: DELEGATE(AtomicCmpxchg);
- case Expression::Id::AtomicWaitId: DELEGATE(AtomicWait);
- case Expression::Id::AtomicNotifyId: DELEGATE(AtomicNotify);
- case Expression::Id::SIMDExtractId: DELEGATE(SIMDExtract);
- case Expression::Id::SIMDReplaceId: DELEGATE(SIMDReplace);
- case Expression::Id::SIMDShuffleId: DELEGATE(SIMDShuffle);
- case Expression::Id::SIMDBitselectId: DELEGATE(SIMDBitselect);
- case Expression::Id::SIMDShiftId: DELEGATE(SIMDShift);
- case Expression::Id::MemoryInitId: DELEGATE(MemoryInit);
- case Expression::Id::DataDropId: DELEGATE(DataDrop);
- case Expression::Id::MemoryCopyId: DELEGATE(MemoryCopy);
- case Expression::Id::MemoryFillId: DELEGATE(MemoryFill);
- case Expression::Id::ConstId: DELEGATE(Const);
- case Expression::Id::UnaryId: DELEGATE(Unary);
- case Expression::Id::BinaryId: DELEGATE(Binary);
- case Expression::Id::SelectId: DELEGATE(Select);
- case Expression::Id::DropId: DELEGATE(Drop);
- case Expression::Id::ReturnId: DELEGATE(Return);
- case Expression::Id::HostId: DELEGATE(Host);
- case Expression::Id::NopId: DELEGATE(Nop);
- case Expression::Id::UnreachableId: DELEGATE(Unreachable);
+ case Expression::Id::BlockId:
+ DELEGATE(Block);
+ case Expression::Id::IfId:
+ DELEGATE(If);
+ case Expression::Id::LoopId:
+ DELEGATE(Loop);
+ case Expression::Id::BreakId:
+ DELEGATE(Break);
+ case Expression::Id::SwitchId:
+ DELEGATE(Switch);
+ case Expression::Id::CallId:
+ DELEGATE(Call);
+ case Expression::Id::CallIndirectId:
+ DELEGATE(CallIndirect);
+ case Expression::Id::GetLocalId:
+ DELEGATE(GetLocal);
+ case Expression::Id::SetLocalId:
+ DELEGATE(SetLocal);
+ case Expression::Id::GetGlobalId:
+ DELEGATE(GetGlobal);
+ case Expression::Id::SetGlobalId:
+ DELEGATE(SetGlobal);
+ case Expression::Id::LoadId:
+ DELEGATE(Load);
+ case Expression::Id::StoreId:
+ DELEGATE(Store);
+ case Expression::Id::AtomicRMWId:
+ DELEGATE(AtomicRMW);
+ case Expression::Id::AtomicCmpxchgId:
+ DELEGATE(AtomicCmpxchg);
+ case Expression::Id::AtomicWaitId:
+ DELEGATE(AtomicWait);
+ case Expression::Id::AtomicNotifyId:
+ DELEGATE(AtomicNotify);
+ case Expression::Id::SIMDExtractId:
+ DELEGATE(SIMDExtract);
+ case Expression::Id::SIMDReplaceId:
+ DELEGATE(SIMDReplace);
+ case Expression::Id::SIMDShuffleId:
+ DELEGATE(SIMDShuffle);
+ case Expression::Id::SIMDBitselectId:
+ DELEGATE(SIMDBitselect);
+ case Expression::Id::SIMDShiftId:
+ DELEGATE(SIMDShift);
+ case Expression::Id::MemoryInitId:
+ DELEGATE(MemoryInit);
+ case Expression::Id::DataDropId:
+ DELEGATE(DataDrop);
+ case Expression::Id::MemoryCopyId:
+ DELEGATE(MemoryCopy);
+ case Expression::Id::MemoryFillId:
+ DELEGATE(MemoryFill);
+ case Expression::Id::ConstId:
+ DELEGATE(Const);
+ case Expression::Id::UnaryId:
+ DELEGATE(Unary);
+ case Expression::Id::BinaryId:
+ DELEGATE(Binary);
+ case Expression::Id::SelectId:
+ DELEGATE(Select);
+ case Expression::Id::DropId:
+ DELEGATE(Drop);
+ case Expression::Id::ReturnId:
+ DELEGATE(Return);
+ case Expression::Id::HostId:
+ DELEGATE(Host);
+ case Expression::Id::NopId:
+ DELEGATE(Nop);
+ case Expression::Id::UnreachableId:
+ DELEGATE(Unreachable);
case Expression::Id::InvalidId:
- default: WASM_UNREACHABLE();
+ default:
+ WASM_UNREACHABLE();
}
- #undef DELEGATE
+#undef DELEGATE
}
};
@@ -249,41 +323,111 @@ struct UnifiedExpressionVisitor : public Visitor<SubType, ReturnType> {
ReturnType visitExpression(Expression* curr) { return ReturnType(); }
// redirects
- ReturnType visitBlock(Block* curr) { return static_cast<SubType*>(this)->visitExpression(curr); }
- ReturnType visitIf(If* curr) { return static_cast<SubType*>(this)->visitExpression(curr); }
- ReturnType visitLoop(Loop* curr) { return static_cast<SubType*>(this)->visitExpression(curr); }
- ReturnType visitBreak(Break* curr) { return static_cast<SubType*>(this)->visitExpression(curr); }
- ReturnType visitSwitch(Switch* curr) { return static_cast<SubType*>(this)->visitExpression(curr); }
- ReturnType visitCall(Call* curr) { return static_cast<SubType*>(this)->visitExpression(curr); }
- ReturnType visitCallIndirect(CallIndirect* curr) { return static_cast<SubType*>(this)->visitExpression(curr); }
- ReturnType visitGetLocal(GetLocal* curr) { return static_cast<SubType*>(this)->visitExpression(curr); }
- ReturnType visitSetLocal(SetLocal* curr) { return static_cast<SubType*>(this)->visitExpression(curr); }
- ReturnType visitGetGlobal(GetGlobal* curr) { return static_cast<SubType*>(this)->visitExpression(curr); }
- ReturnType visitSetGlobal(SetGlobal* curr) { return static_cast<SubType*>(this)->visitExpression(curr); }
- ReturnType visitLoad(Load* curr) { return static_cast<SubType*>(this)->visitExpression(curr); }
- ReturnType visitStore(Store* curr) { return static_cast<SubType*>(this)->visitExpression(curr); }
- ReturnType visitAtomicRMW(AtomicRMW* curr) { return static_cast<SubType*>(this)->visitExpression(curr); }
- ReturnType visitAtomicCmpxchg(AtomicCmpxchg* curr) { return static_cast<SubType*>(this)->visitExpression(curr); }
- ReturnType visitAtomicWait(AtomicWait* curr) { return static_cast<SubType*>(this)->visitExpression(curr); }
- ReturnType visitAtomicNotify(AtomicNotify* curr) { return static_cast<SubType*>(this)->visitExpression(curr); }
- ReturnType visitSIMDExtract(SIMDExtract* curr) { return static_cast<SubType*>(this)->visitExpression(curr); }
- ReturnType visitSIMDReplace(SIMDReplace* curr) { return static_cast<SubType*>(this)->visitExpression(curr); }
- ReturnType visitSIMDShuffle(SIMDShuffle* curr) { return static_cast<SubType*>(this)->visitExpression(curr); }
- ReturnType visitSIMDBitselect(SIMDBitselect* curr) { return static_cast<SubType*>(this)->visitExpression(curr); }
- ReturnType visitSIMDShift(SIMDShift* curr) { return static_cast<SubType*>(this)->visitExpression(curr); }
- ReturnType visitMemoryInit(MemoryInit* curr) { return static_cast<SubType*>(this)->visitExpression(curr); }
- ReturnType visitDataDrop(DataDrop* curr) { return static_cast<SubType*>(this)->visitExpression(curr); }
- ReturnType visitMemoryCopy(MemoryCopy* curr) { return static_cast<SubType*>(this)->visitExpression(curr); }
- ReturnType visitMemoryFill(MemoryFill* curr) { return static_cast<SubType*>(this)->visitExpression(curr); }
- ReturnType visitConst(Const* curr) { return static_cast<SubType*>(this)->visitExpression(curr); }
- ReturnType visitUnary(Unary* curr) { return static_cast<SubType*>(this)->visitExpression(curr); }
- ReturnType visitBinary(Binary* curr) { return static_cast<SubType*>(this)->visitExpression(curr); }
- ReturnType visitSelect(Select* curr) { return static_cast<SubType*>(this)->visitExpression(curr); }
- ReturnType visitDrop(Drop* curr) { return static_cast<SubType*>(this)->visitExpression(curr); }
- ReturnType visitReturn(Return* curr) { return static_cast<SubType*>(this)->visitExpression(curr); }
- ReturnType visitHost(Host* curr) { return static_cast<SubType*>(this)->visitExpression(curr); }
- ReturnType visitNop(Nop* curr) { return static_cast<SubType*>(this)->visitExpression(curr); }
- ReturnType visitUnreachable(Unreachable* curr) { return static_cast<SubType*>(this)->visitExpression(curr); }
+ ReturnType visitBlock(Block* curr) {
+ return static_cast<SubType*>(this)->visitExpression(curr);
+ }
+ ReturnType visitIf(If* curr) {
+ return static_cast<SubType*>(this)->visitExpression(curr);
+ }
+ ReturnType visitLoop(Loop* curr) {
+ return static_cast<SubType*>(this)->visitExpression(curr);
+ }
+ ReturnType visitBreak(Break* curr) {
+ return static_cast<SubType*>(this)->visitExpression(curr);
+ }
+ ReturnType visitSwitch(Switch* curr) {
+ return static_cast<SubType*>(this)->visitExpression(curr);
+ }
+ ReturnType visitCall(Call* curr) {
+ return static_cast<SubType*>(this)->visitExpression(curr);
+ }
+ ReturnType visitCallIndirect(CallIndirect* curr) {
+ return static_cast<SubType*>(this)->visitExpression(curr);
+ }
+ ReturnType visitGetLocal(GetLocal* curr) {
+ return static_cast<SubType*>(this)->visitExpression(curr);
+ }
+ ReturnType visitSetLocal(SetLocal* curr) {
+ return static_cast<SubType*>(this)->visitExpression(curr);
+ }
+ ReturnType visitGetGlobal(GetGlobal* curr) {
+ return static_cast<SubType*>(this)->visitExpression(curr);
+ }
+ ReturnType visitSetGlobal(SetGlobal* curr) {
+ return static_cast<SubType*>(this)->visitExpression(curr);
+ }
+ ReturnType visitLoad(Load* curr) {
+ return static_cast<SubType*>(this)->visitExpression(curr);
+ }
+ ReturnType visitStore(Store* curr) {
+ return static_cast<SubType*>(this)->visitExpression(curr);
+ }
+ ReturnType visitAtomicRMW(AtomicRMW* curr) {
+ return static_cast<SubType*>(this)->visitExpression(curr);
+ }
+ ReturnType visitAtomicCmpxchg(AtomicCmpxchg* curr) {
+ return static_cast<SubType*>(this)->visitExpression(curr);
+ }
+ ReturnType visitAtomicWait(AtomicWait* curr) {
+ return static_cast<SubType*>(this)->visitExpression(curr);
+ }
+ ReturnType visitAtomicNotify(AtomicNotify* curr) {
+ return static_cast<SubType*>(this)->visitExpression(curr);
+ }
+ ReturnType visitSIMDExtract(SIMDExtract* curr) {
+ return static_cast<SubType*>(this)->visitExpression(curr);
+ }
+ ReturnType visitSIMDReplace(SIMDReplace* curr) {
+ return static_cast<SubType*>(this)->visitExpression(curr);
+ }
+ ReturnType visitSIMDShuffle(SIMDShuffle* curr) {
+ return static_cast<SubType*>(this)->visitExpression(curr);
+ }
+ ReturnType visitSIMDBitselect(SIMDBitselect* curr) {
+ return static_cast<SubType*>(this)->visitExpression(curr);
+ }
+ ReturnType visitSIMDShift(SIMDShift* curr) {
+ return static_cast<SubType*>(this)->visitExpression(curr);
+ }
+ ReturnType visitMemoryInit(MemoryInit* curr) {
+ return static_cast<SubType*>(this)->visitExpression(curr);
+ }
+ ReturnType visitDataDrop(DataDrop* curr) {
+ return static_cast<SubType*>(this)->visitExpression(curr);
+ }
+ ReturnType visitMemoryCopy(MemoryCopy* curr) {
+ return static_cast<SubType*>(this)->visitExpression(curr);
+ }
+ ReturnType visitMemoryFill(MemoryFill* curr) {
+ return static_cast<SubType*>(this)->visitExpression(curr);
+ }
+ ReturnType visitConst(Const* curr) {
+ return static_cast<SubType*>(this)->visitExpression(curr);
+ }
+ ReturnType visitUnary(Unary* curr) {
+ return static_cast<SubType*>(this)->visitExpression(curr);
+ }
+ ReturnType visitBinary(Binary* curr) {
+ return static_cast<SubType*>(this)->visitExpression(curr);
+ }
+ ReturnType visitSelect(Select* curr) {
+ return static_cast<SubType*>(this)->visitExpression(curr);
+ }
+ ReturnType visitDrop(Drop* curr) {
+ return static_cast<SubType*>(this)->visitExpression(curr);
+ }
+ ReturnType visitReturn(Return* curr) {
+ return static_cast<SubType*>(this)->visitExpression(curr);
+ }
+ ReturnType visitHost(Host* curr) {
+ return static_cast<SubType*>(this)->visitExpression(curr);
+ }
+ ReturnType visitNop(Nop* curr) {
+ return static_cast<SubType*>(this)->visitExpression(curr);
+ }
+ ReturnType visitUnreachable(Unreachable* curr) {
+ return static_cast<SubType*>(this)->visitExpression(curr);
+ }
};
//
@@ -318,23 +462,15 @@ struct Walker : public VisitorType {
return *replacep = expression;
}
- Expression* getCurrent() {
- return *replacep;
- }
+ Expression* getCurrent() { return *replacep; }
- Expression** getCurrentPointer() {
- return replacep;
- }
+ Expression** getCurrentPointer() { return replacep; }
// Get the current module
- Module* getModule() {
- return currModule;
- }
+ Module* getModule() { return currModule; }
// Get the current function
- Function* getFunction() {
- return currFunction;
- }
+ Function* getFunction() { return currFunction; }
// Walk starting
@@ -360,9 +496,7 @@ struct Walker : public VisitorType {
}
// override this to provide custom functionality
- void doWalkFunction(Function* func) {
- walk(func->body);
- }
+ void doWalkFunction(Function* func) { walk(func->body); }
void walkTable(Table* table) {
for (auto& segment : table->segments) {
@@ -459,55 +593,122 @@ struct Walker : public VisitorType {
// task hooks to call visitors
- static void doVisitBlock(SubType* self, Expression** currp) { self->visitBlock((*currp)->cast<Block>()); }
- static void doVisitIf(SubType* self, Expression** currp) { self->visitIf((*currp)->cast<If>()); }
- static void doVisitLoop(SubType* self, Expression** currp) { self->visitLoop((*currp)->cast<Loop>()); }
- static void doVisitBreak(SubType* self, Expression** currp) { self->visitBreak((*currp)->cast<Break>()); }
- static void doVisitSwitch(SubType* self, Expression** currp) { self->visitSwitch((*currp)->cast<Switch>()); }
- static void doVisitCall(SubType* self, Expression** currp) { self->visitCall((*currp)->cast<Call>()); }
- static void doVisitCallIndirect(SubType* self, Expression** currp) { self->visitCallIndirect((*currp)->cast<CallIndirect>()); }
- static void doVisitGetLocal(SubType* self, Expression** currp) { self->visitGetLocal((*currp)->cast<GetLocal>()); }
- static void doVisitSetLocal(SubType* self, Expression** currp) { self->visitSetLocal((*currp)->cast<SetLocal>()); }
- static void doVisitGetGlobal(SubType* self, Expression** currp) { self->visitGetGlobal((*currp)->cast<GetGlobal>()); }
- static void doVisitSetGlobal(SubType* self, Expression** currp) { self->visitSetGlobal((*currp)->cast<SetGlobal>()); }
- static void doVisitLoad(SubType* self, Expression** currp) { self->visitLoad((*currp)->cast<Load>()); }
- static void doVisitStore(SubType* self, Expression** currp) { self->visitStore((*currp)->cast<Store>()); }
- static void doVisitAtomicRMW(SubType* self, Expression** currp) { self->visitAtomicRMW((*currp)->cast<AtomicRMW>()); }
- static void doVisitAtomicCmpxchg(SubType* self, Expression** currp){ self->visitAtomicCmpxchg((*currp)->cast<AtomicCmpxchg>()); }
- static void doVisitAtomicWait(SubType* self, Expression** currp) { self->visitAtomicWait((*currp)->cast<AtomicWait>()); }
- static void doVisitAtomicNotify(SubType* self, Expression** currp) { self->visitAtomicNotify((*currp)->cast<AtomicNotify>()); }
- static void doVisitSIMDExtract(SubType* self, Expression** currp) { self->visitSIMDExtract((*currp)->cast<SIMDExtract>()); }
- static void doVisitSIMDReplace(SubType* self, Expression** currp) { self->visitSIMDReplace((*currp)->cast<SIMDReplace>()); }
- static void doVisitSIMDShuffle(SubType* self, Expression** currp) { self->visitSIMDShuffle((*currp)->cast<SIMDShuffle>()); }
- static void doVisitSIMDBitselect(SubType* self, Expression** currp) { self->visitSIMDBitselect((*currp)->cast<SIMDBitselect>()); }
- static void doVisitSIMDShift(SubType* self, Expression** currp) { self->visitSIMDShift((*currp)->cast<SIMDShift>()); }
- static void doVisitMemoryInit(SubType* self, Expression** currp) { self->visitMemoryInit((*currp)->cast<MemoryInit>()); }
- static void doVisitDataDrop(SubType* self, Expression** currp) { self->visitDataDrop((*currp)->cast<DataDrop>()); }
- static void doVisitMemoryCopy(SubType* self, Expression** currp) { self->visitMemoryCopy((*currp)->cast<MemoryCopy>()); }
- static void doVisitMemoryFill(SubType* self, Expression** currp) { self->visitMemoryFill((*currp)->cast<MemoryFill>()); }
- static void doVisitConst(SubType* self, Expression** currp) { self->visitConst((*currp)->cast<Const>()); }
- static void doVisitUnary(SubType* self, Expression** currp) { self->visitUnary((*currp)->cast<Unary>()); }
- static void doVisitBinary(SubType* self, Expression** currp) { self->visitBinary((*currp)->cast<Binary>()); }
- static void doVisitSelect(SubType* self, Expression** currp) { self->visitSelect((*currp)->cast<Select>()); }
- static void doVisitDrop(SubType* self, Expression** currp) { self->visitDrop((*currp)->cast<Drop>()); }
- static void doVisitReturn(SubType* self, Expression** currp) { self->visitReturn((*currp)->cast<Return>()); }
- static void doVisitHost(SubType* self, Expression** currp) { self->visitHost((*currp)->cast<Host>()); }
- static void doVisitNop(SubType* self, Expression** currp) { self->visitNop((*currp)->cast<Nop>()); }
- static void doVisitUnreachable(SubType* self, Expression** currp) { self->visitUnreachable((*currp)->cast<Unreachable>()); }
-
- void setModule(Module* module) {
- currModule = module;
- }
-
- void setFunction(Function* func) {
- currFunction = func;
+ static void doVisitBlock(SubType* self, Expression** currp) {
+ self->visitBlock((*currp)->cast<Block>());
+ }
+ static void doVisitIf(SubType* self, Expression** currp) {
+ self->visitIf((*currp)->cast<If>());
+ }
+ static void doVisitLoop(SubType* self, Expression** currp) {
+ self->visitLoop((*currp)->cast<Loop>());
+ }
+ static void doVisitBreak(SubType* self, Expression** currp) {
+ self->visitBreak((*currp)->cast<Break>());
+ }
+ static void doVisitSwitch(SubType* self, Expression** currp) {
+ self->visitSwitch((*currp)->cast<Switch>());
+ }
+ static void doVisitCall(SubType* self, Expression** currp) {
+ self->visitCall((*currp)->cast<Call>());
+ }
+ static void doVisitCallIndirect(SubType* self, Expression** currp) {
+ self->visitCallIndirect((*currp)->cast<CallIndirect>());
+ }
+ static void doVisitGetLocal(SubType* self, Expression** currp) {
+ self->visitGetLocal((*currp)->cast<GetLocal>());
+ }
+ static void doVisitSetLocal(SubType* self, Expression** currp) {
+ self->visitSetLocal((*currp)->cast<SetLocal>());
+ }
+ static void doVisitGetGlobal(SubType* self, Expression** currp) {
+ self->visitGetGlobal((*currp)->cast<GetGlobal>());
+ }
+ static void doVisitSetGlobal(SubType* self, Expression** currp) {
+ self->visitSetGlobal((*currp)->cast<SetGlobal>());
+ }
+ static void doVisitLoad(SubType* self, Expression** currp) {
+ self->visitLoad((*currp)->cast<Load>());
+ }
+ static void doVisitStore(SubType* self, Expression** currp) {
+ self->visitStore((*currp)->cast<Store>());
+ }
+ static void doVisitAtomicRMW(SubType* self, Expression** currp) {
+ self->visitAtomicRMW((*currp)->cast<AtomicRMW>());
+ }
+ static void doVisitAtomicCmpxchg(SubType* self, Expression** currp) {
+ self->visitAtomicCmpxchg((*currp)->cast<AtomicCmpxchg>());
+ }
+ static void doVisitAtomicWait(SubType* self, Expression** currp) {
+ self->visitAtomicWait((*currp)->cast<AtomicWait>());
+ }
+ static void doVisitAtomicNotify(SubType* self, Expression** currp) {
+ self->visitAtomicNotify((*currp)->cast<AtomicNotify>());
+ }
+ static void doVisitSIMDExtract(SubType* self, Expression** currp) {
+ self->visitSIMDExtract((*currp)->cast<SIMDExtract>());
+ }
+ static void doVisitSIMDReplace(SubType* self, Expression** currp) {
+ self->visitSIMDReplace((*currp)->cast<SIMDReplace>());
+ }
+ static void doVisitSIMDShuffle(SubType* self, Expression** currp) {
+ self->visitSIMDShuffle((*currp)->cast<SIMDShuffle>());
+ }
+ static void doVisitSIMDBitselect(SubType* self, Expression** currp) {
+ self->visitSIMDBitselect((*currp)->cast<SIMDBitselect>());
+ }
+ static void doVisitSIMDShift(SubType* self, Expression** currp) {
+ self->visitSIMDShift((*currp)->cast<SIMDShift>());
+ }
+ static void doVisitMemoryInit(SubType* self, Expression** currp) {
+ self->visitMemoryInit((*currp)->cast<MemoryInit>());
+ }
+ static void doVisitDataDrop(SubType* self, Expression** currp) {
+ self->visitDataDrop((*currp)->cast<DataDrop>());
}
+ static void doVisitMemoryCopy(SubType* self, Expression** currp) {
+ self->visitMemoryCopy((*currp)->cast<MemoryCopy>());
+ }
+ static void doVisitMemoryFill(SubType* self, Expression** currp) {
+ self->visitMemoryFill((*currp)->cast<MemoryFill>());
+ }
+ static void doVisitConst(SubType* self, Expression** currp) {
+ self->visitConst((*currp)->cast<Const>());
+ }
+ static void doVisitUnary(SubType* self, Expression** currp) {
+ self->visitUnary((*currp)->cast<Unary>());
+ }
+ static void doVisitBinary(SubType* self, Expression** currp) {
+ self->visitBinary((*currp)->cast<Binary>());
+ }
+ static void doVisitSelect(SubType* self, Expression** currp) {
+ self->visitSelect((*currp)->cast<Select>());
+ }
+ static void doVisitDrop(SubType* self, Expression** currp) {
+ self->visitDrop((*currp)->cast<Drop>());
+ }
+ static void doVisitReturn(SubType* self, Expression** currp) {
+ self->visitReturn((*currp)->cast<Return>());
+ }
+ static void doVisitHost(SubType* self, Expression** currp) {
+ self->visitHost((*currp)->cast<Host>());
+ }
+ static void doVisitNop(SubType* self, Expression** currp) {
+ self->visitNop((*currp)->cast<Nop>());
+ }
+ static void doVisitUnreachable(SubType* self, Expression** currp) {
+ self->visitUnreachable((*currp)->cast<Unreachable>());
+ }
+
+ void setModule(Module* module) { currModule = module; }
+
+ void setFunction(Function* func) { currFunction = func; }
private:
- Expression** replacep = nullptr; // the address of the current node, used to replace it
- SmallVector<Task, 10> stack; // stack of tasks
+ Expression** replacep =
+ nullptr; // the address of the current node, used to replace it
+ SmallVector<Task, 10> stack; // stack of tasks
Function* currFunction = nullptr; // current function being processed
- Module* currModule = nullptr; // current module being processed
+ Module* currModule = nullptr; // current module being processed
};
// Walks in post-order, i.e., children first. When there isn't an obvious
@@ -520,7 +721,8 @@ struct PostWalker : public Walker<SubType, VisitorType> {
Expression* curr = *currp;
switch (curr->_id) {
- case Expression::Id::InvalidId: abort();
+ case Expression::Id::InvalidId:
+ abort();
case Expression::Id::BlockId: {
self->pushTask(SubType::doVisitBlock, currp);
auto& list = curr->cast<Block>()->list;
@@ -571,7 +773,8 @@ struct PostWalker : public Walker<SubType, VisitorType> {
break;
}
case Expression::Id::GetLocalId: {
- self->pushTask(SubType::doVisitGetLocal, currp); // TODO: optimize leaves with a direct call?
+ // TODO: optimize leaves with a direct call?
+ self->pushTask(SubType::doVisitGetLocal, currp);
break;
}
case Expression::Id::SetLocalId: {
@@ -607,7 +810,8 @@ struct PostWalker : public Walker<SubType, VisitorType> {
}
case Expression::Id::AtomicCmpxchgId: {
self->pushTask(SubType::doVisitAtomicCmpxchg, currp);
- self->pushTask(SubType::scan, &curr->cast<AtomicCmpxchg>()->replacement);
+ self->pushTask(SubType::scan,
+ &curr->cast<AtomicCmpxchg>()->replacement);
self->pushTask(SubType::scan, &curr->cast<AtomicCmpxchg>()->expected);
self->pushTask(SubType::scan, &curr->cast<AtomicCmpxchg>()->ptr);
break;
@@ -661,25 +865,25 @@ struct PostWalker : public Walker<SubType, VisitorType> {
self->pushTask(SubType::scan, &curr->cast<MemoryInit>()->offset);
self->pushTask(SubType::scan, &curr->cast<MemoryInit>()->dest);
break;
- }
+ }
case Expression::Id::DataDropId: {
self->pushTask(SubType::doVisitDataDrop, currp);
break;
- }
+ }
case Expression::Id::MemoryCopyId: {
self->pushTask(SubType::doVisitMemoryCopy, currp);
self->pushTask(SubType::scan, &curr->cast<MemoryCopy>()->size);
self->pushTask(SubType::scan, &curr->cast<MemoryCopy>()->source);
self->pushTask(SubType::scan, &curr->cast<MemoryCopy>()->dest);
break;
- }
+ }
case Expression::Id::MemoryFillId: {
self->pushTask(SubType::doVisitMemoryFill, currp);
self->pushTask(SubType::scan, &curr->cast<MemoryFill>()->size);
self->pushTask(SubType::scan, &curr->cast<MemoryFill>()->value);
self->pushTask(SubType::scan, &curr->cast<MemoryFill>()->dest);
break;
- }
+ }
case Expression::Id::ConstId: {
self->pushTask(SubType::doVisitConst, currp);
break;
@@ -728,7 +932,8 @@ struct PostWalker : public Walker<SubType, VisitorType> {
self->pushTask(SubType::doVisitUnreachable, currp);
break;
}
- case Expression::Id::NumExpressionIds: WASM_UNREACHABLE();
+ case Expression::Id::NumExpressionIds:
+ WASM_UNREACHABLE();
}
}
};
@@ -752,14 +957,17 @@ struct ControlFlowWalker : public PostWalker<SubType, VisitorType> {
while (1) {
auto* curr = controlFlowStack[i];
if (Block* block = curr->template dynCast<Block>()) {
- if (name == block->name) return curr;
+ if (name == block->name)
+ return curr;
} else if (Loop* loop = curr->template dynCast<Loop>()) {
- if (name == loop->name) return curr;
+ if (name == loop->name)
+ return curr;
} else {
// an if, ignorable
assert(curr->template is<If>());
}
- if (i == 0) return nullptr;
+ if (i == 0)
+ return nullptr;
i--;
}
}
@@ -769,7 +977,8 @@ struct ControlFlowWalker : public PostWalker<SubType, VisitorType> {
}
static void doPostVisitControlFlow(SubType* self, Expression** currp) {
- // note that we might be popping something else, as we may have been replaced
+ // note that we might be popping something else, as we may have been
+ // replaced
self->controlFlowStack.pop_back();
}
@@ -815,19 +1024,23 @@ struct ExpressionStackWalker : public PostWalker<SubType, VisitorType> {
while (1) {
auto* curr = expressionStack[i];
if (Block* block = curr->template dynCast<Block>()) {
- if (name == block->name) return curr;
+ if (name == block->name)
+ return curr;
} else if (Loop* loop = curr->template dynCast<Loop>()) {
- if (name == loop->name) return curr;
+ if (name == loop->name)
+ return curr;
} else {
WASM_UNREACHABLE();
}
- if (i == 0) return nullptr;
+ if (i == 0)
+ return nullptr;
i--;
}
}
Expression* getParent() {
- if (expressionStack.size() == 1) return nullptr;
+ if (expressionStack.size() == 1)
+ return nullptr;
assert(expressionStack.size() >= 2);
return expressionStack[expressionStack.size() - 2];
}
@@ -882,7 +1095,8 @@ struct LinearExecutionWalker : public PostWalker<SubType, VisitorType> {
Expression* curr = *currp;
switch (curr->_id) {
- case Expression::Id::InvalidId: abort();
+ case Expression::Id::InvalidId:
+ abort();
case Expression::Id::BlockId: {
self->pushTask(SubType::doVisitBlock, currp);
if (curr->cast<Block>()->name.is()) {
diff --git a/src/wasm-validator.h b/src/wasm-validator.h
index 9f9cddb02..496109a4c 100644
--- a/src/wasm-validator.h
+++ b/src/wasm-validator.h
@@ -43,8 +43,8 @@
#include <sstream>
#include <unordered_set>
-#include "wasm.h"
#include "wasm-printing.h"
+#include "wasm.h"
namespace wasm {
diff --git a/src/wasm.h b/src/wasm.h
index 83809243c..a6b6b83d1 100644
--- a/src/wasm.h
+++ b/src/wasm.h
@@ -34,8 +34,8 @@
#include "literal.h"
#include "mixed_arena.h"
#include "support/name.h"
-#include "wasm-type.h"
#include "wasm-features.h"
+#include "wasm-type.h"
namespace wasm {
@@ -56,114 +56,375 @@ struct Address {
return *this;
}
operator address_t() const { return addr; }
- Address& operator++() { ++addr; return *this; }
+ Address& operator++() {
+ ++addr;
+ return *this;
+ }
};
// Operators
enum UnaryOp {
- ClzInt32, ClzInt64, CtzInt32, CtzInt64, PopcntInt32, PopcntInt64, // int
- NegFloat32, NegFloat64, AbsFloat32, AbsFloat64, CeilFloat32, CeilFloat64, FloorFloat32, FloorFloat64, TruncFloat32, TruncFloat64, NearestFloat32, NearestFloat64, SqrtFloat32, SqrtFloat64, // float
+ // int
+ ClzInt32,
+ ClzInt64,
+ CtzInt32,
+ CtzInt64,
+ PopcntInt32,
+ PopcntInt64,
+
+ // float
+ NegFloat32,
+ NegFloat64,
+ AbsFloat32,
+ AbsFloat64,
+ CeilFloat32,
+ CeilFloat64,
+ FloorFloat32,
+ FloorFloat64,
+ TruncFloat32,
+ TruncFloat64,
+ NearestFloat32,
+ NearestFloat64,
+ SqrtFloat32,
+ SqrtFloat64,
+
// relational
- EqZInt32, EqZInt64,
+ EqZInt32,
+ EqZInt64,
+
// conversions
- ExtendSInt32, ExtendUInt32, // extend i32 to i64
- WrapInt64, // i64 to i32
- TruncSFloat32ToInt32, TruncSFloat32ToInt64, TruncUFloat32ToInt32, TruncUFloat32ToInt64, TruncSFloat64ToInt32, TruncSFloat64ToInt64, TruncUFloat64ToInt32, TruncUFloat64ToInt64, // float to int
- ReinterpretFloat32, ReinterpretFloat64, // reintepret bits to int
- ConvertSInt32ToFloat32, ConvertSInt32ToFloat64, ConvertUInt32ToFloat32, ConvertUInt32ToFloat64, ConvertSInt64ToFloat32, ConvertSInt64ToFloat64, ConvertUInt64ToFloat32, ConvertUInt64ToFloat64, // int to float
- PromoteFloat32, // f32 to f64
- DemoteFloat64, // f64 to f32
- ReinterpretInt32, ReinterpretInt64, // reinterpret bits to float
+ // extend i32 to i64
+ ExtendSInt32,
+ ExtendUInt32,
+ // i64 to i32
+ WrapInt64,
+ // float to int
+ TruncSFloat32ToInt32,
+ TruncSFloat32ToInt64,
+ TruncUFloat32ToInt32,
+ TruncUFloat32ToInt64,
+ TruncSFloat64ToInt32,
+ TruncSFloat64ToInt64,
+ TruncUFloat64ToInt32,
+ TruncUFloat64ToInt64,
+ // reintepret bits to int
+ ReinterpretFloat32,
+ ReinterpretFloat64,
+ // int to float
+ ConvertSInt32ToFloat32,
+ ConvertSInt32ToFloat64,
+ ConvertUInt32ToFloat32,
+ ConvertUInt32ToFloat64,
+ ConvertSInt64ToFloat32,
+ ConvertSInt64ToFloat64,
+ ConvertUInt64ToFloat32,
+ ConvertUInt64ToFloat64,
+ // f32 to f64
+ PromoteFloat32,
+ // f64 to f32
+ DemoteFloat64,
+ // reinterpret bits to float
+ ReinterpretInt32,
+ ReinterpretInt64,
+
// Extend signed subword-sized integer. This differs from e.g. ExtendSInt32
// because the input integer is in an i64 value insetad of an i32 value.
- ExtendS8Int32, ExtendS16Int32, ExtendS8Int64, ExtendS16Int64, ExtendS32Int64,
+ ExtendS8Int32,
+ ExtendS16Int32,
+ ExtendS8Int64,
+ ExtendS16Int64,
+ ExtendS32Int64,
+
// Saturating float-to-int
- TruncSatSFloat32ToInt32, TruncSatUFloat32ToInt32, TruncSatSFloat64ToInt32, TruncSatUFloat64ToInt32,
- TruncSatSFloat32ToInt64, TruncSatUFloat32ToInt64, TruncSatSFloat64ToInt64, TruncSatUFloat64ToInt64,
+ TruncSatSFloat32ToInt32,
+ TruncSatUFloat32ToInt32,
+ TruncSatSFloat64ToInt32,
+ TruncSatUFloat64ToInt32,
+ TruncSatSFloat32ToInt64,
+ TruncSatUFloat32ToInt64,
+ TruncSatSFloat64ToInt64,
+ TruncSatUFloat64ToInt64,
+
// SIMD splats
- SplatVecI8x16, SplatVecI16x8, SplatVecI32x4, SplatVecI64x2, SplatVecF32x4, SplatVecF64x2,
+ SplatVecI8x16,
+ SplatVecI16x8,
+ SplatVecI32x4,
+ SplatVecI64x2,
+ SplatVecF32x4,
+ SplatVecF64x2,
+
// SIMD arithmetic
NotVec128,
- NegVecI8x16, AnyTrueVecI8x16, AllTrueVecI8x16, NegVecI16x8, AnyTrueVecI16x8, AllTrueVecI16x8,
- NegVecI32x4, AnyTrueVecI32x4, AllTrueVecI32x4, NegVecI64x2, AnyTrueVecI64x2, AllTrueVecI64x2,
- AbsVecF32x4, NegVecF32x4, SqrtVecF32x4, AbsVecF64x2, NegVecF64x2, SqrtVecF64x2,
- TruncSatSVecF32x4ToVecI32x4, TruncSatUVecF32x4ToVecI32x4, TruncSatSVecF64x2ToVecI64x2, TruncSatUVecF64x2ToVecI64x2,
- ConvertSVecI32x4ToVecF32x4, ConvertUVecI32x4ToVecF32x4, ConvertSVecI64x2ToVecF64x2, ConvertUVecI64x2ToVecF64x2,
+ NegVecI8x16,
+ AnyTrueVecI8x16,
+ AllTrueVecI8x16,
+ NegVecI16x8,
+ AnyTrueVecI16x8,
+ AllTrueVecI16x8,
+ NegVecI32x4,
+ AnyTrueVecI32x4,
+ AllTrueVecI32x4,
+ NegVecI64x2,
+ AnyTrueVecI64x2,
+ AllTrueVecI64x2,
+ AbsVecF32x4,
+ NegVecF32x4,
+ SqrtVecF32x4,
+ AbsVecF64x2,
+ NegVecF64x2,
+ SqrtVecF64x2,
+ TruncSatSVecF32x4ToVecI32x4,
+ TruncSatUVecF32x4ToVecI32x4,
+ TruncSatSVecF64x2ToVecI64x2,
+ TruncSatUVecF64x2ToVecI64x2,
+ ConvertSVecI32x4ToVecF32x4,
+ ConvertUVecI32x4ToVecF32x4,
+ ConvertSVecI64x2ToVecF64x2,
+ ConvertUVecI64x2ToVecF64x2,
InvalidUnary
};
enum BinaryOp {
- AddInt32, SubInt32, MulInt32, // int or float
- DivSInt32, DivUInt32, RemSInt32, RemUInt32, AndInt32, OrInt32, XorInt32, ShlInt32, ShrUInt32, ShrSInt32, RotLInt32, RotRInt32, // int
+ // int or float
+ AddInt32,
+ SubInt32,
+ MulInt32,
+
+ // int
+ DivSInt32,
+ DivUInt32,
+ RemSInt32,
+ RemUInt32,
+ AndInt32,
+ OrInt32,
+ XorInt32,
+ ShlInt32,
+ ShrUInt32,
+ ShrSInt32,
+ RotLInt32,
+ RotRInt32,
+
// relational ops
- EqInt32, NeInt32, // int or float
- LtSInt32, LtUInt32, LeSInt32, LeUInt32, GtSInt32, GtUInt32, GeSInt32, GeUInt32, // int
+ // int or float
+ EqInt32,
+ NeInt32,
+ // int
+ LtSInt32,
+ LtUInt32,
+ LeSInt32,
+ LeUInt32,
+ GtSInt32,
+ GtUInt32,
+ GeSInt32,
+ GeUInt32,
+
+ // int or float
+ AddInt64,
+ SubInt64,
+ MulInt64,
+
+ // int
+ DivSInt64,
+ DivUInt64,
+ RemSInt64,
+ RemUInt64,
+ AndInt64,
+ OrInt64,
+ XorInt64,
+ ShlInt64,
+ ShrUInt64,
+ ShrSInt64,
+ RotLInt64,
+ RotRInt64,
- AddInt64, SubInt64, MulInt64, // int or float
- DivSInt64, DivUInt64, RemSInt64, RemUInt64, AndInt64, OrInt64, XorInt64, ShlInt64, ShrUInt64, ShrSInt64, RotLInt64, RotRInt64, // int
// relational ops
- EqInt64, NeInt64, // int or float
- LtSInt64, LtUInt64, LeSInt64, LeUInt64, GtSInt64, GtUInt64, GeSInt64, GeUInt64, // int
+ // int or float
+ EqInt64,
+ NeInt64,
+ // int
+ LtSInt64,
+ LtUInt64,
+ LeSInt64,
+ LeUInt64,
+ GtSInt64,
+ GtUInt64,
+ GeSInt64,
+ GeUInt64,
+
+ // int or float
+ AddFloat32,
+ SubFloat32,
+ MulFloat32,
+
+ // float
+ DivFloat32,
+ CopySignFloat32,
+ MinFloat32,
+ MaxFloat32,
- AddFloat32, SubFloat32, MulFloat32, // int or float
- DivFloat32, CopySignFloat32, MinFloat32, MaxFloat32, // float
// relational ops
- EqFloat32, NeFloat32, // int or float
- LtFloat32, LeFloat32, GtFloat32, GeFloat32, // float
+ // int or float
+ EqFloat32,
+ NeFloat32,
+ // float
+ LtFloat32,
+ LeFloat32,
+ GtFloat32,
+ GeFloat32,
+
+ // int or float
+ AddFloat64,
+ SubFloat64,
+ MulFloat64,
+
+ // float
+ DivFloat64,
+ CopySignFloat64,
+ MinFloat64,
+ MaxFloat64,
- AddFloat64, SubFloat64, MulFloat64, // int or float
- DivFloat64, CopySignFloat64, MinFloat64, MaxFloat64, // float
// relational ops
- EqFloat64, NeFloat64, // int or float
- LtFloat64, LeFloat64, GtFloat64, GeFloat64, // float
+ // int or float
+ EqFloat64,
+ NeFloat64,
+ // float
+ LtFloat64,
+ LeFloat64,
+ GtFloat64,
+ GeFloat64,
+
// SIMD relational ops (return vectors)
- EqVecI8x16, NeVecI8x16, LtSVecI8x16, LtUVecI8x16, GtSVecI8x16, GtUVecI8x16, LeSVecI8x16, LeUVecI8x16, GeSVecI8x16, GeUVecI8x16,
- EqVecI16x8, NeVecI16x8, LtSVecI16x8, LtUVecI16x8, GtSVecI16x8, GtUVecI16x8, LeSVecI16x8, LeUVecI16x8, GeSVecI16x8, GeUVecI16x8,
- EqVecI32x4, NeVecI32x4, LtSVecI32x4, LtUVecI32x4, GtSVecI32x4, GtUVecI32x4, LeSVecI32x4, LeUVecI32x4, GeSVecI32x4, GeUVecI32x4,
- EqVecF32x4, NeVecF32x4, LtVecF32x4, GtVecF32x4, LeVecF32x4, GeVecF32x4,
- EqVecF64x2, NeVecF64x2, LtVecF64x2, GtVecF64x2, LeVecF64x2, GeVecF64x2,
+ EqVecI8x16,
+ NeVecI8x16,
+ LtSVecI8x16,
+ LtUVecI8x16,
+ GtSVecI8x16,
+ GtUVecI8x16,
+ LeSVecI8x16,
+ LeUVecI8x16,
+ GeSVecI8x16,
+ GeUVecI8x16,
+ EqVecI16x8,
+ NeVecI16x8,
+ LtSVecI16x8,
+ LtUVecI16x8,
+ GtSVecI16x8,
+ GtUVecI16x8,
+ LeSVecI16x8,
+ LeUVecI16x8,
+ GeSVecI16x8,
+ GeUVecI16x8,
+ EqVecI32x4,
+ NeVecI32x4,
+ LtSVecI32x4,
+ LtUVecI32x4,
+ GtSVecI32x4,
+ GtUVecI32x4,
+ LeSVecI32x4,
+ LeUVecI32x4,
+ GeSVecI32x4,
+ GeUVecI32x4,
+ EqVecF32x4,
+ NeVecF32x4,
+ LtVecF32x4,
+ GtVecF32x4,
+ LeVecF32x4,
+ GeVecF32x4,
+ EqVecF64x2,
+ NeVecF64x2,
+ LtVecF64x2,
+ GtVecF64x2,
+ LeVecF64x2,
+ GeVecF64x2,
+
// SIMD arithmetic
- AndVec128, OrVec128, XorVec128,
- AddVecI8x16, AddSatSVecI8x16, AddSatUVecI8x16, SubVecI8x16, SubSatSVecI8x16, SubSatUVecI8x16, MulVecI8x16,
- AddVecI16x8, AddSatSVecI16x8, AddSatUVecI16x8, SubVecI16x8, SubSatSVecI16x8, SubSatUVecI16x8, MulVecI16x8,
- AddVecI32x4, SubVecI32x4, MulVecI32x4, AddVecI64x2, SubVecI64x2,
- AddVecF32x4, SubVecF32x4, MulVecF32x4, DivVecF32x4, MinVecF32x4, MaxVecF32x4,
- AddVecF64x2, SubVecF64x2, MulVecF64x2, DivVecF64x2, MinVecF64x2, MaxVecF64x2,
+ AndVec128,
+ OrVec128,
+ XorVec128,
+ AddVecI8x16,
+ AddSatSVecI8x16,
+ AddSatUVecI8x16,
+ SubVecI8x16,
+ SubSatSVecI8x16,
+ SubSatUVecI8x16,
+ MulVecI8x16,
+ AddVecI16x8,
+ AddSatSVecI16x8,
+ AddSatUVecI16x8,
+ SubVecI16x8,
+ SubSatSVecI16x8,
+ SubSatUVecI16x8,
+ MulVecI16x8,
+ AddVecI32x4,
+ SubVecI32x4,
+ MulVecI32x4,
+ AddVecI64x2,
+ SubVecI64x2,
+ AddVecF32x4,
+ SubVecF32x4,
+ MulVecF32x4,
+ DivVecF32x4,
+ MinVecF32x4,
+ MaxVecF32x4,
+ AddVecF64x2,
+ SubVecF64x2,
+ MulVecF64x2,
+ DivVecF64x2,
+ MinVecF64x2,
+ MaxVecF64x2,
InvalidBinary
};
-enum HostOp {
- CurrentMemory, GrowMemory
-};
+enum HostOp { CurrentMemory, GrowMemory };
-enum AtomicRMWOp {
- Add, Sub, And, Or, Xor, Xchg
-};
+enum AtomicRMWOp { Add, Sub, And, Or, Xor, Xchg };
enum SIMDExtractOp {
- ExtractLaneSVecI8x16, ExtractLaneUVecI8x16, ExtractLaneSVecI16x8, ExtractLaneUVecI16x8,
- ExtractLaneVecI32x4, ExtractLaneVecI64x2, ExtractLaneVecF32x4, ExtractLaneVecF64x2
+ ExtractLaneSVecI8x16,
+ ExtractLaneUVecI8x16,
+ ExtractLaneSVecI16x8,
+ ExtractLaneUVecI16x8,
+ ExtractLaneVecI32x4,
+ ExtractLaneVecI64x2,
+ ExtractLaneVecF32x4,
+ ExtractLaneVecF64x2
};
enum SIMDReplaceOp {
- ReplaceLaneVecI8x16, ReplaceLaneVecI16x8, ReplaceLaneVecI32x4, ReplaceLaneVecI64x2, ReplaceLaneVecF32x4, ReplaceLaneVecF64x2
+ ReplaceLaneVecI8x16,
+ ReplaceLaneVecI16x8,
+ ReplaceLaneVecI32x4,
+ ReplaceLaneVecI64x2,
+ ReplaceLaneVecF32x4,
+ ReplaceLaneVecF64x2
};
enum SIMDShiftOp {
- ShlVecI8x16, ShrSVecI8x16, ShrUVecI8x16, ShlVecI16x8, ShrSVecI16x8, ShrUVecI16x8,
- ShlVecI32x4, ShrSVecI32x4, ShrUVecI32x4, ShlVecI64x2, ShrSVecI64x2, ShrUVecI64x2
+ ShlVecI8x16,
+ ShrSVecI8x16,
+ ShrUVecI8x16,
+ ShlVecI16x8,
+ ShrSVecI16x8,
+ ShrUVecI16x8,
+ ShlVecI32x4,
+ ShrSVecI32x4,
+ ShrUVecI32x4,
+ ShlVecI64x2,
+ ShrSVecI64x2,
+ ShrUVecI64x2
};
//
// Expressions
//
-// Note that little is provided in terms of constructors for these. The rationale
-// is that writing new Something(a, b, c, d, e) is not the clearest, and it would
-// be better to write new Something(name=a, leftOperand=b... etc., but C++
-// lacks named operands, so in asm2wasm etc. you will see things like
+// Note that little is provided in terms of constructors for these. The
+// rationale is that writing new Something(a, b, c, d, e) is not the clearest,
+// and it would be better to write new Something(name=a, leftOperand=b...
+// etc., but C++ lacks named operands, so in asm2wasm etc. you will see things
+// like
// auto x = new Something();
// x->name = a;
// x->leftOperand = b;
@@ -227,29 +488,22 @@ public:
void finalize() {}
- template<class T>
- bool is() const {
- return int(_id) == int(T::SpecificId);
- }
+ template<class T> bool is() const { return int(_id) == int(T::SpecificId); }
- template<class T>
- T* dynCast() {
+ template<class T> T* dynCast() {
return int(_id) == int(T::SpecificId) ? (T*)this : nullptr;
}
- template <class T>
- const T* dynCast() const {
+ template<class T> const T* dynCast() const {
return int(_id) == int(T::SpecificId) ? (const T*)this : nullptr;
}
- template<class T>
- T* cast() {
+ template<class T> T* cast() {
assert(int(_id) == int(T::SpecificId));
return (T*)this;
}
- template<class T>
- const T* cast() const {
+ template<class T> const T* cast() const {
assert(int(_id) == int(T::SpecificId));
return (const T*)this;
}
@@ -259,8 +513,7 @@ const char* getExpressionName(Expression* curr);
typedef ArenaVector<Expression*> ExpressionList;
-template<Expression::Id SID>
-class SpecificExpression : public Expression {
+template<Expression::Id SID> class SpecificExpression : public Expression {
public:
enum {
SpecificId = SID // compile-time access to the type for the class
@@ -282,19 +535,20 @@ public:
Name name;
ExpressionList list;
- // set the type purely based on its contents. this scans the block, so it is not fast.
+ // set the type purely based on its contents. this scans the block, so it is
+ // not fast.
void finalize();
// set the type given you know its type, which is the case when parsing
- // s-expression or binary, as explicit types are given. the only additional work
- // this does is to set the type to unreachable in the cases that is needed
- // (which may require scanning the block)
+ // s-expression or binary, as explicit types are given. the only additional
+ // work this does is to set the type to unreachable in the cases that is
+ // needed (which may require scanning the block)
void finalize(Type type_);
- // set the type given you know its type, and you know if there is a break to this
- // block. this avoids the need to scan the contents of the block in the case that
- // it might be unreachable, so it is recommended if you already know the type
- // and breakability anyhow.
+ // set the type given you know its type, and you know if there is a break to
+ // this block. this avoids the need to scan the contents of the block in the
+ // case that it might be unreachable, so it is recommended if you already know
+ // the type and breakability anyhow.
void finalize(Type type_, bool hasBreak);
};
@@ -308,8 +562,9 @@ public:
Expression* ifFalse;
// set the type given you know its type, which is the case when parsing
- // s-expression or binary, as explicit types are given. the only additional work
- // this does is to set the type to unreachable in the cases that is needed.
+ // s-expression or binary, as explicit types are given. the only additional
+ // work this does is to set the type to unreachable in the cases that is
+ // needed.
void finalize(Type type_);
// set the type purely based on its contents.
@@ -325,8 +580,9 @@ public:
Expression* body;
// set the type given you know its type, which is the case when parsing
- // s-expression or binary, as explicit types are given. the only additional work
- // this does is to set the type to unreachable in the cases that is needed.
+ // s-expression or binary, as explicit types are given. the only additional
+ // work this does is to set the type to unreachable in the cases that is
+ // needed.
void finalize(Type type_);
// set the type purely based on its contents.
@@ -336,9 +592,7 @@ public:
class Break : public SpecificExpression<Expression::BreakId> {
public:
Break() : value(nullptr), condition(nullptr) {}
- Break(MixedArena& allocator) : Break() {
- type = unreachable;
- }
+ Break(MixedArena& allocator) : Break() { type = unreachable; }
Name name;
Expression* value;
@@ -349,9 +603,7 @@ public:
class Switch : public SpecificExpression<Expression::SwitchId> {
public:
- Switch(MixedArena& allocator) : targets(allocator) {
- type = unreachable;
- }
+ Switch(MixedArena& allocator) : targets(allocator) { type = unreachable; }
ArenaVector<Name> targets;
Name default_;
@@ -471,7 +723,7 @@ public:
};
class AtomicRMW : public SpecificExpression<Expression::AtomicRMWId> {
- public:
+public:
AtomicRMW() = default;
AtomicRMW(MixedArena& allocator) : AtomicRMW() {}
@@ -485,7 +737,7 @@ class AtomicRMW : public SpecificExpression<Expression::AtomicRMWId> {
};
class AtomicCmpxchg : public SpecificExpression<Expression::AtomicCmpxchgId> {
- public:
+public:
AtomicCmpxchg() = default;
AtomicCmpxchg(MixedArena& allocator) : AtomicCmpxchg() {}
@@ -499,7 +751,7 @@ class AtomicCmpxchg : public SpecificExpression<Expression::AtomicCmpxchgId> {
};
class AtomicWait : public SpecificExpression<Expression::AtomicWaitId> {
- public:
+public:
AtomicWait() = default;
AtomicWait(MixedArena& allocator) : AtomicWait() {}
@@ -513,7 +765,7 @@ class AtomicWait : public SpecificExpression<Expression::AtomicWaitId> {
};
class AtomicNotify : public SpecificExpression<Expression::AtomicNotifyId> {
- public:
+public:
AtomicNotify() = default;
AtomicNotify(MixedArena& allocator) : AtomicNotify() {}
@@ -525,7 +777,7 @@ class AtomicNotify : public SpecificExpression<Expression::AtomicNotifyId> {
};
class SIMDExtract : public SpecificExpression<Expression::SIMDExtractId> {
- public:
+public:
SIMDExtract() = default;
SIMDExtract(MixedArena& allocator) : SIMDExtract() {}
@@ -537,7 +789,7 @@ class SIMDExtract : public SpecificExpression<Expression::SIMDExtractId> {
};
class SIMDReplace : public SpecificExpression<Expression::SIMDReplaceId> {
- public:
+public:
SIMDReplace() = default;
SIMDReplace(MixedArena& allocator) : SIMDReplace() {}
@@ -550,7 +802,7 @@ class SIMDReplace : public SpecificExpression<Expression::SIMDReplaceId> {
};
class SIMDShuffle : public SpecificExpression<Expression::SIMDShuffleId> {
- public:
+public:
SIMDShuffle() = default;
SIMDShuffle(MixedArena& allocator) : SIMDShuffle() {}
@@ -562,7 +814,7 @@ class SIMDShuffle : public SpecificExpression<Expression::SIMDShuffleId> {
};
class SIMDBitselect : public SpecificExpression<Expression::SIMDBitselectId> {
- public:
+public:
SIMDBitselect() = default;
SIMDBitselect(MixedArena& allocator) : SIMDBitselect() {}
@@ -574,7 +826,7 @@ class SIMDBitselect : public SpecificExpression<Expression::SIMDBitselectId> {
};
class SIMDShift : public SpecificExpression<Expression::SIMDShiftId> {
- public:
+public:
SIMDShift() = default;
SIMDShift(MixedArena& allocator) : SIMDShift() {}
@@ -586,7 +838,7 @@ class SIMDShift : public SpecificExpression<Expression::SIMDShiftId> {
};
class MemoryInit : public SpecificExpression<Expression::MemoryInitId> {
- public:
+public:
MemoryInit() = default;
MemoryInit(MixedArena& allocator) : MemoryInit() {}
@@ -599,7 +851,7 @@ class MemoryInit : public SpecificExpression<Expression::MemoryInitId> {
};
class DataDrop : public SpecificExpression<Expression::DataDropId> {
- public:
+public:
DataDrop() = default;
DataDrop(MixedArena& allocator) : DataDrop() {}
@@ -609,7 +861,7 @@ class DataDrop : public SpecificExpression<Expression::DataDropId> {
};
class MemoryCopy : public SpecificExpression<Expression::MemoryCopyId> {
- public:
+public:
MemoryCopy() = default;
MemoryCopy(MixedArena& allocator) : MemoryCopy() {}
@@ -621,7 +873,7 @@ class MemoryCopy : public SpecificExpression<Expression::MemoryCopyId> {
};
class MemoryFill : public SpecificExpression<Expression::MemoryFillId> {
- public:
+public:
MemoryFill() = default;
MemoryFill(MixedArena& allocator) : MemoryFill() {}
@@ -698,9 +950,7 @@ public:
class Return : public SpecificExpression<Expression::ReturnId> {
public:
- Return() {
- type = unreachable;
- }
+ Return() { type = unreachable; }
Return(MixedArena& allocator) : Return() {}
Expression* value = nullptr;
@@ -719,9 +969,7 @@ public:
class Unreachable : public SpecificExpression<Expression::UnreachableId> {
public:
- Unreachable() {
- type = unreachable;
- }
+ Unreachable() { type = unreachable; }
Unreachable(MixedArena& allocator) : Unreachable() {}
};
@@ -731,9 +979,7 @@ struct Importable {
// If these are set, then this is an import, as module.base
Name module, base;
- bool imported() {
- return module.is();
- }
+ bool imported() { return module.is(); }
};
// Forward declarations of Stack IR, as functions can contain it, see
@@ -749,7 +995,7 @@ public:
Type result = none;
std::vector<Type> params; // function locals are
std::vector<Type> vars; // params plus vars
- Name type; // if null, it is implicit in params and result
+ Name type; // if null, it is implicit in params and result
// The body of the function
Expression* body = nullptr;
@@ -770,11 +1016,19 @@ public:
struct DebugLocation {
uint32_t fileIndex, lineNumber, columnNumber;
- bool operator==(const DebugLocation& other) const { return fileIndex == other.fileIndex && lineNumber == other.lineNumber && columnNumber == other.columnNumber; }
- bool operator!=(const DebugLocation& other) const { return !(*this == other); }
+ bool operator==(const DebugLocation& other) const {
+ return fileIndex == other.fileIndex && lineNumber == other.lineNumber &&
+ columnNumber == other.columnNumber;
+ }
+ bool operator!=(const DebugLocation& other) const {
+ return !(*this == other);
+ }
bool operator<(const DebugLocation& other) const {
- return fileIndex != other.fileIndex ? fileIndex < other.fileIndex :
- lineNumber != other.lineNumber ? lineNumber < other.lineNumber : columnNumber < other.columnNumber;
+ return fileIndex != other.fileIndex
+ ? fileIndex < other.fileIndex
+ : lineNumber != other.lineNumber
+ ? lineNumber < other.lineNumber
+ : columnNumber < other.columnNumber;
}
};
std::unordered_map<Expression*, DebugLocation> debugLocations;
@@ -813,7 +1067,9 @@ enum class ExternalKind {
class Export {
public:
- Name name; // exported name - note that this is the key, as the internal name is non-unique (can have multiple exports for an internal, also over kinds)
+ // exported name - note that this is the key, as the internal name is
+ // non-unique (can have multiple exports for an internal, also over kinds)
+ Name name;
Name value; // internal name
ExternalKind kind;
};
@@ -835,17 +1091,16 @@ public:
}
};
- // Currently the wasm object always 'has' one Table. It 'exists' if it has been defined or imported.
- // The table can exist but be empty and have no defined initial or max size.
+ // Currently the wasm object always 'has' one Table. It 'exists' if it has
+ // been defined or imported. The table can exist but be empty and have no
+ // defined initial or max size.
bool exists = false;
Name name;
Address initial = 0;
Address max = kMaxSize;
std::vector<Segment> segments;
- Table() {
- name = Name::fromInt(0);
- }
+ Table() { name = Name::fromInt(0); }
bool hasMax() { return max != kUnlimitedSize; }
};
@@ -854,7 +1109,8 @@ public:
static const Address::address_t kPageSize = 64 * 1024;
static const Address::address_t kUnlimitedSize = Address::address_t(-1);
// In wasm32, the maximum memory size is limited by a 32-bit pointer: 4GB
- static const Address::address_t kMaxSize = (uint64_t(4) * 1024 * 1024 * 1024) / kPageSize;
+ static const Address::address_t kMaxSize =
+ (uint64_t(4) * 1024 * 1024 * 1024) / kPageSize;
static const Address::address_t kPageMask = ~(kPageSize - 1);
struct Segment {
@@ -863,7 +1119,8 @@ public:
std::vector<char> data; // TODO: optimize
Segment() = default;
Segment(Expression* offset) : offset(offset) {}
- Segment(Expression* offset, const char* init, Address size) : offset(offset) {
+ Segment(Expression* offset, const char* init, Address size)
+ : offset(offset) {
data.resize(size);
std::copy_n(init, size, data.begin());
}
@@ -871,7 +1128,7 @@ public:
data.swap(init);
}
Segment(bool isPassive, Expression* offset, const char* init, Address size)
- : isPassive(isPassive), offset(offset) {
+ : isPassive(isPassive), offset(offset) {
data.resize(size);
std::copy_n(init, size, data.begin());
}
@@ -886,9 +1143,7 @@ public:
// See comment in Table.
bool shared = false;
- Memory() {
- name = Name::fromInt(0);
- }
+ Memory() { name = Name::fromInt(0); }
bool hasMax() { return max != kUnlimitedSize; }
};
@@ -910,7 +1165,8 @@ public:
class Module {
public:
- // wasm contents (generally you shouldn't access these from outside, except maybe for iterating; use add*() and the get() functions)
+ // wasm contents (generally you shouldn't access these from outside, except
+ // maybe for iterating; use add*() and the get() functions)
std::vector<std::unique_ptr<FunctionType>> functionTypes;
std::vector<std::unique_ptr<Export>> exports;
std::vector<std::unique_ptr<Function>> functions;
@@ -933,9 +1189,11 @@ public:
MixedArena allocator;
private:
- // TODO: add a build option where Names are just indices, and then these methods are not needed
+ // TODO: add a build option where Names are just indices, and then these
+ // methods are not needed
std::map<Name, FunctionType*> functionTypesMap;
- std::map<Name, Export*> exportsMap; // exports map is by the *exported* name, which is unique
+ // exports map is by the *exported* name, which is unique
+ std::map<Name, Export*> exportsMap;
std::map<Name, Function*> functionsMap;
std::map<Name, Global*> globalsMap;
@@ -978,6 +1236,6 @@ template<> struct hash<wasm::Address> {
return std::hash<wasm::Address::address_t>()(a.addr);
}
};
-}
+} // namespace std
#endif // wasm_wasm_h
diff --git a/src/wasm/literal.cpp b/src/wasm/literal.cpp
index b374566d1..be92ae03d 100644
--- a/src/wasm/literal.cpp
+++ b/src/wasm/literal.cpp
@@ -20,16 +20,14 @@
#include <cmath>
#include "emscripten-optimizer/simple_ast.h"
+#include "ir/bits.h"
#include "pretty_printing.h"
#include "support/bits.h"
#include "support/utilities.h"
-#include "ir/bits.h"
-
namespace wasm {
-template<int N>
-using LaneArray = std::array<Literal, N>;
+template<int N> using LaneArray = std::array<Literal, N>;
Literal::Literal(const uint8_t init[16]) : type(Type::v128) {
memcpy(&v128, init, 16);
@@ -45,7 +43,8 @@ static void extractBytes(uint8_t (&dest)[16], const LaneArray<Lanes>& lanes) {
LaneT lane;
memcpy(&lane, bits, sizeof(lane));
for (size_t offset = 0; offset < lane_width; ++offset) {
- bytes.at(lane_index * lane_width + offset) = uint8_t(lane >> (8 * offset));
+ bytes.at(lane_index * lane_width + offset) =
+ uint8_t(lane >> (8 * offset));
}
}
memcpy(&dest, bytes.data(), sizeof(bytes));
@@ -104,17 +103,23 @@ Literal Literal::castToI64() {
int64_t Literal::getInteger() const {
switch (type) {
- case Type::i32: return i32;
- case Type::i64: return i64;
- default: abort();
+ case Type::i32:
+ return i32;
+ case Type::i64:
+ return i64;
+ default:
+ abort();
}
}
double Literal::getFloat() const {
switch (type) {
- case Type::f32: return getf32();
- case Type::f64: return getf64();
- default: abort();
+ case Type::f32:
+ return getf32();
+ case Type::f64:
+ return getf64();
+ default:
+ abort();
}
}
@@ -122,18 +127,27 @@ void Literal::getBits(uint8_t (&buf)[16]) const {
memset(buf, 0, 16);
switch (type) {
case Type::i32:
- case Type::f32: memcpy(buf, &i32, sizeof(i32)); break;
+ case Type::f32:
+ memcpy(buf, &i32, sizeof(i32));
+ break;
case Type::i64:
- case Type::f64: memcpy(buf, &i64, sizeof(i64)); break;
- case Type::v128: memcpy(buf, &v128, sizeof(v128)); break;
+ case Type::f64:
+ memcpy(buf, &i64, sizeof(i64));
+ break;
+ case Type::v128:
+ memcpy(buf, &v128, sizeof(v128));
+ break;
case Type::none:
- case Type::unreachable: WASM_UNREACHABLE();
+ case Type::unreachable:
+ WASM_UNREACHABLE();
}
}
bool Literal::operator==(const Literal& other) const {
- if (type != other.type) return false;
- if (type == none) return true;
+ if (type != other.type)
+ return false;
+ if (type == none)
+ return true;
uint8_t bits[16], other_bits[16];
getBits(bits);
other.getBits(other_bits);
@@ -181,7 +195,7 @@ double Literal::setQuietNaN(double f) {
return bit_cast<double>(0x0008000000000000ull | bit_cast<uint64_t>(f));
}
-void Literal::printFloat(std::ostream &o, float f) {
+void Literal::printFloat(std::ostream& o, float f) {
if (std::isnan(f)) {
const char* sign = std::signbit(f) ? "-" : "";
o << sign << "nan";
@@ -224,13 +238,10 @@ void Literal::printDouble(std::ostream& o, double d) {
void Literal::printVec128(std::ostream& o, const std::array<uint8_t, 16>& v) {
o << std::hex;
for (auto i = 0; i < 16; i += 4) {
- if (i) o << " ";
- o << "0x" << std::setfill('0') << std::setw(8) << uint32_t(
- v[i ] |
- (v[i + 1] << 8) |
- (v[i + 2] << 16) |
- (v[i + 3] << 24)
- );
+ if (i)
+ o << " ";
+ o << "0x" << std::setfill('0') << std::setw(8)
+ << uint32_t(v[i] | (v[i + 1] << 8) | (v[i + 2] << 16) | (v[i + 3] << 24));
}
o << std::dec;
}
@@ -238,33 +249,53 @@ void Literal::printVec128(std::ostream& o, const std::array<uint8_t, 16>& v) {
std::ostream& operator<<(std::ostream& o, Literal literal) {
prepareMinorColor(o) << printType(literal.type) << ".const ";
switch (literal.type) {
- case Type::none: o << "?"; break;
- case Type::i32: o << literal.i32; break;
- case Type::i64: o << literal.i64; break;
- case Type::f32: literal.printFloat(o, literal.getf32()); break;
- case Type::f64: literal.printDouble(o, literal.getf64()); break;
- case Type::v128: o << "i32x4 "; literal.printVec128(o, literal.getv128()); break;
- case Type::unreachable: WASM_UNREACHABLE();
+ case Type::none:
+ o << "?";
+ break;
+ case Type::i32:
+ o << literal.i32;
+ break;
+ case Type::i64:
+ o << literal.i64;
+ break;
+ case Type::f32:
+ literal.printFloat(o, literal.getf32());
+ break;
+ case Type::f64:
+ literal.printDouble(o, literal.getf64());
+ break;
+ case Type::v128:
+ o << "i32x4 ";
+ literal.printVec128(o, literal.getv128());
+ break;
+ case Type::unreachable:
+ WASM_UNREACHABLE();
}
restoreNormalColor(o);
return o;
}
Literal Literal::countLeadingZeroes() const {
- if (type == Type::i32) return Literal((int32_t)CountLeadingZeroes(i32));
- if (type == Type::i64) return Literal((int64_t)CountLeadingZeroes(i64));
+ if (type == Type::i32)
+ return Literal((int32_t)CountLeadingZeroes(i32));
+ if (type == Type::i64)
+ return Literal((int64_t)CountLeadingZeroes(i64));
WASM_UNREACHABLE();
}
Literal Literal::countTrailingZeroes() const {
- if (type == Type::i32) return Literal((int32_t)CountTrailingZeroes(i32));
- if (type == Type::i64) return Literal((int64_t)CountTrailingZeroes(i64));
+ if (type == Type::i32)
+ return Literal((int32_t)CountTrailingZeroes(i32));
+ if (type == Type::i64)
+ return Literal((int64_t)CountTrailingZeroes(i64));
WASM_UNREACHABLE();
}
Literal Literal::popCount() const {
- if (type == Type::i32) return Literal((int32_t)PopCount(i32));
- if (type == Type::i64) return Literal((int64_t)PopCount(i64));
+ if (type == Type::i32)
+ return Literal((int32_t)PopCount(i32));
+ if (type == Type::i64)
+ return Literal((int64_t)PopCount(i64));
WASM_UNREACHABLE();
}
@@ -284,19 +315,24 @@ Literal Literal::extendToF64() const {
}
Literal Literal::extendS8() const {
- if (type == Type::i32) return Literal(int32_t(int8_t(geti32() & 0xFF)));
- if (type == Type::i64) return Literal(int64_t(int8_t(geti64() & 0xFF)));
+ if (type == Type::i32)
+ return Literal(int32_t(int8_t(geti32() & 0xFF)));
+ if (type == Type::i64)
+ return Literal(int64_t(int8_t(geti64() & 0xFF)));
WASM_UNREACHABLE();
}
Literal Literal::extendS16() const {
- if (type == Type::i32) return Literal(int32_t(int16_t(geti32() & 0xFFFF)));
- if (type == Type::i64) return Literal(int64_t(int16_t(geti64() & 0xFFFF)));
+ if (type == Type::i32)
+ return Literal(int32_t(int16_t(geti32() & 0xFFFF)));
+ if (type == Type::i64)
+ return Literal(int64_t(int16_t(geti64() & 0xFFFF)));
WASM_UNREACHABLE();
}
Literal Literal::extendS32() const {
- if (type == Type::i64) return Literal(int64_t(int32_t(geti64() & 0xFFFFFFFF)));
+ if (type == Type::i64)
+ return Literal(int64_t(int32_t(geti64() & 0xFFFFFFFF)));
WASM_UNREACHABLE();
}
@@ -306,33 +342,38 @@ Literal Literal::wrapToI32() const {
}
Literal Literal::convertSIToF32() const {
- if (type == Type::i32) return Literal(float(i32));
- if (type == Type::i64) return Literal(float(i64));
+ if (type == Type::i32)
+ return Literal(float(i32));
+ if (type == Type::i64)
+ return Literal(float(i64));
WASM_UNREACHABLE();
}
Literal Literal::convertUIToF32() const {
- if (type == Type::i32) return Literal(float(uint32_t(i32)));
- if (type == Type::i64) return Literal(float(uint64_t(i64)));
+ if (type == Type::i32)
+ return Literal(float(uint32_t(i32)));
+ if (type == Type::i64)
+ return Literal(float(uint64_t(i64)));
WASM_UNREACHABLE();
}
Literal Literal::convertSIToF64() const {
- if (type == Type::i32) return Literal(double(i32));
- if (type == Type::i64) return Literal(double(i64));
+ if (type == Type::i32)
+ return Literal(double(i32));
+ if (type == Type::i64)
+ return Literal(double(i64));
WASM_UNREACHABLE();
}
Literal Literal::convertUIToF64() const {
- if (type == Type::i32) return Literal(double(uint32_t(i32)));
- if (type == Type::i64) return Literal(double(uint64_t(i64)));
+ if (type == Type::i32)
+ return Literal(double(uint32_t(i32)));
+ if (type == Type::i64)
+ return Literal(double(uint64_t(i64)));
WASM_UNREACHABLE();
}
-template<typename F>
-struct AsInt {
- using type = void;
-};
+template<typename F> struct AsInt { using type = void; };
template<> struct AsInt<float> { using type = int32_t; };
template<> struct AsInt<double> { using type = int64_t; };
@@ -354,13 +395,11 @@ static Literal saturating_trunc(typename AsInt<F>::type val) {
Literal Literal::truncSatToSI32() const {
if (type == Type::f32) {
return saturating_trunc<float, int32_t, isInRangeI32TruncS>(
- Literal(*this).castToI32().geti32()
- );
+ Literal(*this).castToI32().geti32());
}
if (type == Type::f64) {
return saturating_trunc<double, int32_t, isInRangeI32TruncS>(
- Literal(*this).castToI64().geti64()
- );
+ Literal(*this).castToI64().geti64());
}
WASM_UNREACHABLE();
}
@@ -368,13 +407,11 @@ Literal Literal::truncSatToSI32() const {
Literal Literal::truncSatToSI64() const {
if (type == Type::f32) {
return saturating_trunc<float, int64_t, isInRangeI64TruncS>(
- Literal(*this).castToI32().geti32()
- );
+ Literal(*this).castToI32().geti32());
}
if (type == Type::f64) {
return saturating_trunc<double, int64_t, isInRangeI64TruncS>(
- Literal(*this).castToI64().geti64()
- );
+ Literal(*this).castToI64().geti64());
}
WASM_UNREACHABLE();
}
@@ -382,13 +419,11 @@ Literal Literal::truncSatToSI64() const {
Literal Literal::truncSatToUI32() const {
if (type == Type::f32) {
return saturating_trunc<float, uint32_t, isInRangeI32TruncU>(
- Literal(*this).castToI32().geti32()
- );
+ Literal(*this).castToI32().geti32());
}
if (type == Type::f64) {
return saturating_trunc<double, uint32_t, isInRangeI32TruncU>(
- Literal(*this).castToI64().geti64()
- );
+ Literal(*this).castToI64().geti64());
}
WASM_UNREACHABLE();
}
@@ -396,180 +431,223 @@ Literal Literal::truncSatToUI32() const {
Literal Literal::truncSatToUI64() const {
if (type == Type::f32) {
return saturating_trunc<float, uint64_t, isInRangeI64TruncU>(
- Literal(*this).castToI32().geti32()
- );
+ Literal(*this).castToI32().geti32());
}
if (type == Type::f64) {
return saturating_trunc<double, uint64_t, isInRangeI64TruncU>(
- Literal(*this).castToI64().geti64()
- );
+ Literal(*this).castToI64().geti64());
}
WASM_UNREACHABLE();
}
Literal Literal::eqz() const {
switch (type) {
- case Type::i32: return eq(Literal(int32_t(0)));
- case Type::i64: return eq(Literal(int64_t(0)));
- case Type::f32: return eq(Literal(float(0)));
- case Type::f64: return eq(Literal(double(0)));
+ case Type::i32:
+ return eq(Literal(int32_t(0)));
+ case Type::i64:
+ return eq(Literal(int64_t(0)));
+ case Type::f32:
+ return eq(Literal(float(0)));
+ case Type::f64:
+ return eq(Literal(double(0)));
case Type::v128:
case Type::none:
- case Type::unreachable: WASM_UNREACHABLE();
+ case Type::unreachable:
+ WASM_UNREACHABLE();
}
WASM_UNREACHABLE();
}
Literal Literal::neg() const {
switch (type) {
- case Type::i32: return Literal(-uint32_t(i32));
- case Type::i64: return Literal(-uint64_t(i64));
- case Type::f32: return Literal(i32 ^ 0x80000000).castToF32();
- case Type::f64: return Literal(int64_t(i64 ^ 0x8000000000000000ULL)).castToF64();
+ case Type::i32:
+ return Literal(-uint32_t(i32));
+ case Type::i64:
+ return Literal(-uint64_t(i64));
+ case Type::f32:
+ return Literal(i32 ^ 0x80000000).castToF32();
+ case Type::f64:
+ return Literal(int64_t(i64 ^ 0x8000000000000000ULL)).castToF64();
case Type::v128:
case Type::none:
- case Type::unreachable: WASM_UNREACHABLE();
+ case Type::unreachable:
+ WASM_UNREACHABLE();
}
WASM_UNREACHABLE();
}
Literal Literal::abs() const {
switch (type) {
- case Type::i32: return Literal(i32 & 0x7fffffff);
- case Type::i64: return Literal(int64_t(i64 & 0x7fffffffffffffffULL));
- case Type::f32: return Literal(i32 & 0x7fffffff).castToF32();
- case Type::f64: return Literal(int64_t(i64 & 0x7fffffffffffffffULL)).castToF64();
+ case Type::i32:
+ return Literal(i32 & 0x7fffffff);
+ case Type::i64:
+ return Literal(int64_t(i64 & 0x7fffffffffffffffULL));
+ case Type::f32:
+ return Literal(i32 & 0x7fffffff).castToF32();
+ case Type::f64:
+ return Literal(int64_t(i64 & 0x7fffffffffffffffULL)).castToF64();
case Type::v128:
case Type::none:
- case Type::unreachable: WASM_UNREACHABLE();
+ case Type::unreachable:
+ WASM_UNREACHABLE();
}
WASM_UNREACHABLE();
}
Literal Literal::ceil() const {
switch (type) {
- case Type::f32: return Literal(std::ceil(getf32()));
- case Type::f64: return Literal(std::ceil(getf64()));
- default: WASM_UNREACHABLE();
+ case Type::f32:
+ return Literal(std::ceil(getf32()));
+ case Type::f64:
+ return Literal(std::ceil(getf64()));
+ default:
+ WASM_UNREACHABLE();
}
}
Literal Literal::floor() const {
switch (type) {
- case Type::f32: return Literal(std::floor(getf32()));
- case Type::f64: return Literal(std::floor(getf64()));
- default: WASM_UNREACHABLE();
+ case Type::f32:
+ return Literal(std::floor(getf32()));
+ case Type::f64:
+ return Literal(std::floor(getf64()));
+ default:
+ WASM_UNREACHABLE();
}
}
Literal Literal::trunc() const {
switch (type) {
- case Type::f32: return Literal(std::trunc(getf32()));
- case Type::f64: return Literal(std::trunc(getf64()));
- default: WASM_UNREACHABLE();
+ case Type::f32:
+ return Literal(std::trunc(getf32()));
+ case Type::f64:
+ return Literal(std::trunc(getf64()));
+ default:
+ WASM_UNREACHABLE();
}
}
Literal Literal::nearbyint() const {
switch (type) {
- case Type::f32: return Literal(std::nearbyint(getf32()));
- case Type::f64: return Literal(std::nearbyint(getf64()));
- default: WASM_UNREACHABLE();
+ case Type::f32:
+ return Literal(std::nearbyint(getf32()));
+ case Type::f64:
+ return Literal(std::nearbyint(getf64()));
+ default:
+ WASM_UNREACHABLE();
}
}
Literal Literal::sqrt() const {
switch (type) {
- case Type::f32: return Literal(std::sqrt(getf32()));
- case Type::f64: return Literal(std::sqrt(getf64()));
- default: WASM_UNREACHABLE();
+ case Type::f32:
+ return Literal(std::sqrt(getf32()));
+ case Type::f64:
+ return Literal(std::sqrt(getf64()));
+ default:
+ WASM_UNREACHABLE();
}
}
Literal Literal::demote() const {
auto f64 = getf64();
- if (std::isnan(f64)) return Literal(float(f64));
- if (std::isinf(f64)) return Literal(float(f64));
+ if (std::isnan(f64))
+ return Literal(float(f64));
+ if (std::isinf(f64))
+ return Literal(float(f64));
// when close to the limit, but still truncatable to a valid value, do that
- // see https://github.com/WebAssembly/sexpr-wasm-prototype/blob/2d375e8d502327e814d62a08f22da9d9b6b675dc/src/wasm-interpreter.c#L247
+ // see
+ // https://github.com/WebAssembly/sexpr-wasm-prototype/blob/2d375e8d502327e814d62a08f22da9d9b6b675dc/src/wasm-interpreter.c#L247
uint64_t bits = reinterpreti64();
- if (bits > 0x47efffffe0000000ULL && bits < 0x47effffff0000000ULL) return Literal(std::numeric_limits<float>::max());
- if (bits > 0xc7efffffe0000000ULL && bits < 0xc7effffff0000000ULL) return Literal(-std::numeric_limits<float>::max());
+ if (bits > 0x47efffffe0000000ULL && bits < 0x47effffff0000000ULL)
+ return Literal(std::numeric_limits<float>::max());
+ if (bits > 0xc7efffffe0000000ULL && bits < 0xc7effffff0000000ULL)
+ return Literal(-std::numeric_limits<float>::max());
// when we must convert to infinity, do that
- if (f64 < -std::numeric_limits<float>::max()) return Literal(-std::numeric_limits<float>::infinity());
- if (f64 > std::numeric_limits<float>::max()) return Literal(std::numeric_limits<float>::infinity());
+ if (f64 < -std::numeric_limits<float>::max())
+ return Literal(-std::numeric_limits<float>::infinity());
+ if (f64 > std::numeric_limits<float>::max())
+ return Literal(std::numeric_limits<float>::infinity());
return Literal(float(getf64()));
}
Literal Literal::add(const Literal& other) const {
switch (type) {
- case Type::i32: return Literal(uint32_t(i32) + uint32_t(other.i32));
- case Type::i64: return Literal(uint64_t(i64) + uint64_t(other.i64));
- case Type::f32: return Literal(getf32() + other.getf32());
- case Type::f64: return Literal(getf64() + other.getf64());
+ case Type::i32:
+ return Literal(uint32_t(i32) + uint32_t(other.i32));
+ case Type::i64:
+ return Literal(uint64_t(i64) + uint64_t(other.i64));
+ case Type::f32:
+ return Literal(getf32() + other.getf32());
+ case Type::f64:
+ return Literal(getf64() + other.getf64());
case Type::v128:
case Type::none:
- case Type::unreachable: WASM_UNREACHABLE();
+ case Type::unreachable:
+ WASM_UNREACHABLE();
}
WASM_UNREACHABLE();
}
Literal Literal::sub(const Literal& other) const {
switch (type) {
- case Type::i32: return Literal(uint32_t(i32) - uint32_t(other.i32));
- case Type::i64: return Literal(uint64_t(i64) - uint64_t(other.i64));
- case Type::f32: return Literal(getf32() - other.getf32());
- case Type::f64: return Literal(getf64() - other.getf64());
+ case Type::i32:
+ return Literal(uint32_t(i32) - uint32_t(other.i32));
+ case Type::i64:
+ return Literal(uint64_t(i64) - uint64_t(other.i64));
+ case Type::f32:
+ return Literal(getf32() - other.getf32());
+ case Type::f64:
+ return Literal(getf64() - other.getf64());
case Type::v128:
case Type::none:
- case Type::unreachable: WASM_UNREACHABLE();
+ case Type::unreachable:
+ WASM_UNREACHABLE();
}
WASM_UNREACHABLE();
}
-template<typename T>
-static T add_sat_s(T a, T b) {
- static_assert(std::is_signed<T>::value, "Trying to instantiate add_sat_s with unsigned type");
+template<typename T> static T add_sat_s(T a, T b) {
+ static_assert(std::is_signed<T>::value,
+ "Trying to instantiate add_sat_s with unsigned type");
using UT = typename std::make_unsigned<T>::type;
UT ua = static_cast<UT>(a);
UT ub = static_cast<UT>(b);
UT ures = ua + ub;
// overflow if sign of result is different from sign of a and b
if (static_cast<T>((ures ^ ua) & (ures ^ ub)) < 0) {
- return (a < 0)
- ? std::numeric_limits<T>::min()
- : std::numeric_limits<T>::max();
+ return (a < 0) ? std::numeric_limits<T>::min()
+ : std::numeric_limits<T>::max();
}
return static_cast<T>(ures);
}
-template<typename T>
-static T sub_sat_s(T a, T b) {
- static_assert(std::is_signed<T>::value, "Trying to instantiate sub_sat_s with unsigned type");
+template<typename T> static T sub_sat_s(T a, T b) {
+ static_assert(std::is_signed<T>::value,
+ "Trying to instantiate sub_sat_s with unsigned type");
using UT = typename std::make_unsigned<T>::type;
UT ua = static_cast<UT>(a);
UT ub = static_cast<UT>(b);
UT ures = ua - ub;
// overflow if a and b have different signs and result and a differ in sign
if (static_cast<T>((ua ^ ub) & (ures ^ ua)) < 0) {
- return (a < 0)
- ? std::numeric_limits<T>::min()
- : std::numeric_limits<T>::max();
+ return (a < 0) ? std::numeric_limits<T>::min()
+ : std::numeric_limits<T>::max();
}
return static_cast<T>(ures);
}
-template<typename T>
-static T add_sat_u(T a, T b) {
- static_assert(std::is_unsigned<T>::value, "Trying to instantiate add_sat_u with signed type");
+template<typename T> static T add_sat_u(T a, T b) {
+ static_assert(std::is_unsigned<T>::value,
+ "Trying to instantiate add_sat_u with signed type");
T res = a + b;
// overflow if result is less than arguments
return (res < a) ? std::numeric_limits<T>::max() : res;
}
-template<typename T>
-static T sub_sat_u(T a, T b) {
- static_assert(std::is_unsigned<T>::value, "Trying to instantiate sub_sat_u with signed type");
+template<typename T> static T sub_sat_u(T a, T b) {
+ static_assert(std::is_unsigned<T>::value,
+ "Trying to instantiate sub_sat_u with signed type");
T res = a - b;
// overflow if result is greater than a
return (res > a) ? 0 : res;
@@ -602,13 +680,18 @@ Literal Literal::subSatUI16(const Literal& other) const {
Literal Literal::mul(const Literal& other) const {
switch (type) {
- case Type::i32: return Literal(uint32_t(i32) * uint32_t(other.i32));
- case Type::i64: return Literal(uint64_t(i64) * uint64_t(other.i64));
- case Type::f32: return Literal(getf32() * other.getf32());
- case Type::f64: return Literal(getf64() * other.getf64());
+ case Type::i32:
+ return Literal(uint32_t(i32) * uint32_t(other.i32));
+ case Type::i64:
+ return Literal(uint64_t(i64) * uint64_t(other.i64));
+ case Type::f32:
+ return Literal(getf32() * other.getf32());
+ case Type::f64:
+ return Literal(getf64() * other.getf64());
case Type::v128:
case Type::none:
- case Type::unreachable: WASM_UNREACHABLE();
+ case Type::unreachable:
+ WASM_UNREACHABLE();
}
WASM_UNREACHABLE();
}
@@ -620,19 +703,27 @@ Literal Literal::div(const Literal& other) const {
float sign = std::signbit(lhs) == std::signbit(rhs) ? 0.f : -0.f;
switch (std::fpclassify(rhs)) {
case FP_ZERO:
- switch (std::fpclassify(lhs)) {
- case FP_NAN: return Literal(setQuietNaN(lhs));
- case FP_ZERO: return Literal(std::copysign(std::numeric_limits<float>::quiet_NaN(), sign));
- case FP_NORMAL: // fallthrough
- case FP_SUBNORMAL: // fallthrough
- case FP_INFINITE: return Literal(std::copysign(std::numeric_limits<float>::infinity(), sign));
- default: WASM_UNREACHABLE();
- }
- case FP_NAN: // fallthrough
+ switch (std::fpclassify(lhs)) {
+ case FP_NAN:
+ return Literal(setQuietNaN(lhs));
+ case FP_ZERO:
+ return Literal(
+ std::copysign(std::numeric_limits<float>::quiet_NaN(), sign));
+ case FP_NORMAL: // fallthrough
+ case FP_SUBNORMAL: // fallthrough
+ case FP_INFINITE:
+ return Literal(
+ std::copysign(std::numeric_limits<float>::infinity(), sign));
+ default:
+ WASM_UNREACHABLE();
+ }
+ case FP_NAN: // fallthrough
case FP_INFINITE: // fallthrough
- case FP_NORMAL: // fallthrough
- case FP_SUBNORMAL: return Literal(lhs / rhs);
- default: WASM_UNREACHABLE();
+ case FP_NORMAL: // fallthrough
+ case FP_SUBNORMAL:
+ return Literal(lhs / rhs);
+ default:
+ WASM_UNREACHABLE();
}
}
case Type::f64: {
@@ -640,240 +731,335 @@ Literal Literal::div(const Literal& other) const {
double sign = std::signbit(lhs) == std::signbit(rhs) ? 0. : -0.;
switch (std::fpclassify(rhs)) {
case FP_ZERO:
- switch (std::fpclassify(lhs)) {
- case FP_NAN: return Literal(setQuietNaN(lhs));
- case FP_ZERO: return Literal(std::copysign(std::numeric_limits<double>::quiet_NaN(), sign));
- case FP_NORMAL: // fallthrough
- case FP_SUBNORMAL: // fallthrough
- case FP_INFINITE: return Literal(std::copysign(std::numeric_limits<double>::infinity(), sign));
- default: WASM_UNREACHABLE();
- }
- case FP_NAN: // fallthrough
+ switch (std::fpclassify(lhs)) {
+ case FP_NAN:
+ return Literal(setQuietNaN(lhs));
+ case FP_ZERO:
+ return Literal(
+ std::copysign(std::numeric_limits<double>::quiet_NaN(), sign));
+ case FP_NORMAL: // fallthrough
+ case FP_SUBNORMAL: // fallthrough
+ case FP_INFINITE:
+ return Literal(
+ std::copysign(std::numeric_limits<double>::infinity(), sign));
+ default:
+ WASM_UNREACHABLE();
+ }
+ case FP_NAN: // fallthrough
case FP_INFINITE: // fallthrough
- case FP_NORMAL: // fallthrough
- case FP_SUBNORMAL: return Literal(lhs / rhs);
- default: WASM_UNREACHABLE();
+ case FP_NORMAL: // fallthrough
+ case FP_SUBNORMAL:
+ return Literal(lhs / rhs);
+ default:
+ WASM_UNREACHABLE();
}
}
- default: WASM_UNREACHABLE();
+ default:
+ WASM_UNREACHABLE();
}
}
Literal Literal::divS(const Literal& other) const {
switch (type) {
- case Type::i32: return Literal(i32 / other.i32);
- case Type::i64: return Literal(i64 / other.i64);
- default: WASM_UNREACHABLE();
+ case Type::i32:
+ return Literal(i32 / other.i32);
+ case Type::i64:
+ return Literal(i64 / other.i64);
+ default:
+ WASM_UNREACHABLE();
}
}
Literal Literal::divU(const Literal& other) const {
switch (type) {
- case Type::i32: return Literal(uint32_t(i32) / uint32_t(other.i32));
- case Type::i64: return Literal(uint64_t(i64) / uint64_t(other.i64));
- default: WASM_UNREACHABLE();
+ case Type::i32:
+ return Literal(uint32_t(i32) / uint32_t(other.i32));
+ case Type::i64:
+ return Literal(uint64_t(i64) / uint64_t(other.i64));
+ default:
+ WASM_UNREACHABLE();
}
}
Literal Literal::remS(const Literal& other) const {
switch (type) {
- case Type::i32: return Literal(i32 % other.i32);
- case Type::i64: return Literal(i64 % other.i64);
- default: WASM_UNREACHABLE();
+ case Type::i32:
+ return Literal(i32 % other.i32);
+ case Type::i64:
+ return Literal(i64 % other.i64);
+ default:
+ WASM_UNREACHABLE();
}
}
Literal Literal::remU(const Literal& other) const {
switch (type) {
- case Type::i32: return Literal(uint32_t(i32) % uint32_t(other.i32));
- case Type::i64: return Literal(uint64_t(i64) % uint64_t(other.i64));
- default: WASM_UNREACHABLE();
+ case Type::i32:
+ return Literal(uint32_t(i32) % uint32_t(other.i32));
+ case Type::i64:
+ return Literal(uint64_t(i64) % uint64_t(other.i64));
+ default:
+ WASM_UNREACHABLE();
}
}
Literal Literal::and_(const Literal& other) const {
switch (type) {
- case Type::i32: return Literal(i32 & other.i32);
- case Type::i64: return Literal(i64 & other.i64);
- default: WASM_UNREACHABLE();
+ case Type::i32:
+ return Literal(i32 & other.i32);
+ case Type::i64:
+ return Literal(i64 & other.i64);
+ default:
+ WASM_UNREACHABLE();
}
}
Literal Literal::or_(const Literal& other) const {
switch (type) {
- case Type::i32: return Literal(i32 | other.i32);
- case Type::i64: return Literal(i64 | other.i64);
- default: WASM_UNREACHABLE();
+ case Type::i32:
+ return Literal(i32 | other.i32);
+ case Type::i64:
+ return Literal(i64 | other.i64);
+ default:
+ WASM_UNREACHABLE();
}
}
Literal Literal::xor_(const Literal& other) const {
switch (type) {
- case Type::i32: return Literal(i32 ^ other.i32);
- case Type::i64: return Literal(i64 ^ other.i64);
- default: WASM_UNREACHABLE();
+ case Type::i32:
+ return Literal(i32 ^ other.i32);
+ case Type::i64:
+ return Literal(i64 ^ other.i64);
+ default:
+ WASM_UNREACHABLE();
}
}
Literal Literal::shl(const Literal& other) const {
switch (type) {
- case Type::i32: return Literal(uint32_t(i32) << Bits::getEffectiveShifts(other.i32, Type::i32));
- case Type::i64: return Literal(uint64_t(i64) << Bits::getEffectiveShifts(other.i64, Type::i64));
- default: WASM_UNREACHABLE();
+ case Type::i32:
+ return Literal(uint32_t(i32)
+ << Bits::getEffectiveShifts(other.i32, Type::i32));
+ case Type::i64:
+ return Literal(uint64_t(i64)
+ << Bits::getEffectiveShifts(other.i64, Type::i64));
+ default:
+ WASM_UNREACHABLE();
}
}
Literal Literal::shrS(const Literal& other) const {
switch (type) {
- case Type::i32: return Literal(i32 >> Bits::getEffectiveShifts(other.i32, Type::i32));
- case Type::i64: return Literal(i64 >> Bits::getEffectiveShifts(other.i64, Type::i64));
- default: WASM_UNREACHABLE();
+ case Type::i32:
+ return Literal(i32 >> Bits::getEffectiveShifts(other.i32, Type::i32));
+ case Type::i64:
+ return Literal(i64 >> Bits::getEffectiveShifts(other.i64, Type::i64));
+ default:
+ WASM_UNREACHABLE();
}
}
Literal Literal::shrU(const Literal& other) const {
switch (type) {
- case Type::i32: return Literal(uint32_t(i32) >> Bits::getEffectiveShifts(other.i32, Type::i32));
- case Type::i64: return Literal(uint64_t(i64) >> Bits::getEffectiveShifts(other.i64, Type::i64));
- default: WASM_UNREACHABLE();
+ case Type::i32:
+ return Literal(uint32_t(i32) >>
+ Bits::getEffectiveShifts(other.i32, Type::i32));
+ case Type::i64:
+ return Literal(uint64_t(i64) >>
+ Bits::getEffectiveShifts(other.i64, Type::i64));
+ default:
+ WASM_UNREACHABLE();
}
}
Literal Literal::rotL(const Literal& other) const {
switch (type) {
- case Type::i32: return Literal(RotateLeft(uint32_t(i32), uint32_t(other.i32)));
- case Type::i64: return Literal(RotateLeft(uint64_t(i64), uint64_t(other.i64)));
- default: WASM_UNREACHABLE();
+ case Type::i32:
+ return Literal(RotateLeft(uint32_t(i32), uint32_t(other.i32)));
+ case Type::i64:
+ return Literal(RotateLeft(uint64_t(i64), uint64_t(other.i64)));
+ default:
+ WASM_UNREACHABLE();
}
}
Literal Literal::rotR(const Literal& other) const {
switch (type) {
- case Type::i32: return Literal(RotateRight(uint32_t(i32), uint32_t(other.i32)));
- case Type::i64: return Literal(RotateRight(uint64_t(i64), uint64_t(other.i64)));
- default: WASM_UNREACHABLE();
+ case Type::i32:
+ return Literal(RotateRight(uint32_t(i32), uint32_t(other.i32)));
+ case Type::i64:
+ return Literal(RotateRight(uint64_t(i64), uint64_t(other.i64)));
+ default:
+ WASM_UNREACHABLE();
}
}
Literal Literal::eq(const Literal& other) const {
switch (type) {
- case Type::i32: return Literal(i32 == other.i32);
- case Type::i64: return Literal(i64 == other.i64);
- case Type::f32: return Literal(getf32() == other.getf32());
- case Type::f64: return Literal(getf64() == other.getf64());
+ case Type::i32:
+ return Literal(i32 == other.i32);
+ case Type::i64:
+ return Literal(i64 == other.i64);
+ case Type::f32:
+ return Literal(getf32() == other.getf32());
+ case Type::f64:
+ return Literal(getf64() == other.getf64());
case Type::v128:
case Type::none:
- case Type::unreachable: WASM_UNREACHABLE();
+ case Type::unreachable:
+ WASM_UNREACHABLE();
}
WASM_UNREACHABLE();
}
Literal Literal::ne(const Literal& other) const {
switch (type) {
- case Type::i32: return Literal(i32 != other.i32);
- case Type::i64: return Literal(i64 != other.i64);
- case Type::f32: return Literal(getf32() != other.getf32());
- case Type::f64: return Literal(getf64() != other.getf64());
+ case Type::i32:
+ return Literal(i32 != other.i32);
+ case Type::i64:
+ return Literal(i64 != other.i64);
+ case Type::f32:
+ return Literal(getf32() != other.getf32());
+ case Type::f64:
+ return Literal(getf64() != other.getf64());
case Type::v128:
case Type::none:
- case Type::unreachable: WASM_UNREACHABLE();
+ case Type::unreachable:
+ WASM_UNREACHABLE();
}
WASM_UNREACHABLE();
}
Literal Literal::ltS(const Literal& other) const {
switch (type) {
- case Type::i32: return Literal(i32 < other.i32);
- case Type::i64: return Literal(i64 < other.i64);
- default: WASM_UNREACHABLE();
+ case Type::i32:
+ return Literal(i32 < other.i32);
+ case Type::i64:
+ return Literal(i64 < other.i64);
+ default:
+ WASM_UNREACHABLE();
}
}
Literal Literal::ltU(const Literal& other) const {
switch (type) {
- case Type::i32: return Literal(uint32_t(i32) < uint32_t(other.i32));
- case Type::i64: return Literal(uint64_t(i64) < uint64_t(other.i64));
- default: WASM_UNREACHABLE();
+ case Type::i32:
+ return Literal(uint32_t(i32) < uint32_t(other.i32));
+ case Type::i64:
+ return Literal(uint64_t(i64) < uint64_t(other.i64));
+ default:
+ WASM_UNREACHABLE();
}
}
Literal Literal::lt(const Literal& other) const {
switch (type) {
- case Type::f32: return Literal(getf32() < other.getf32());
- case Type::f64: return Literal(getf64() < other.getf64());
- default: WASM_UNREACHABLE();
+ case Type::f32:
+ return Literal(getf32() < other.getf32());
+ case Type::f64:
+ return Literal(getf64() < other.getf64());
+ default:
+ WASM_UNREACHABLE();
}
}
Literal Literal::leS(const Literal& other) const {
switch (type) {
- case Type::i32: return Literal(i32 <= other.i32);
- case Type::i64: return Literal(i64 <= other.i64);
- default: WASM_UNREACHABLE();
+ case Type::i32:
+ return Literal(i32 <= other.i32);
+ case Type::i64:
+ return Literal(i64 <= other.i64);
+ default:
+ WASM_UNREACHABLE();
}
}
Literal Literal::leU(const Literal& other) const {
switch (type) {
- case Type::i32: return Literal(uint32_t(i32) <= uint32_t(other.i32));
- case Type::i64: return Literal(uint64_t(i64) <= uint64_t(other.i64));
- default: WASM_UNREACHABLE();
+ case Type::i32:
+ return Literal(uint32_t(i32) <= uint32_t(other.i32));
+ case Type::i64:
+ return Literal(uint64_t(i64) <= uint64_t(other.i64));
+ default:
+ WASM_UNREACHABLE();
}
}
Literal Literal::le(const Literal& other) const {
switch (type) {
- case Type::f32: return Literal(getf32() <= other.getf32());
- case Type::f64: return Literal(getf64() <= other.getf64());
- default: WASM_UNREACHABLE();
+ case Type::f32:
+ return Literal(getf32() <= other.getf32());
+ case Type::f64:
+ return Literal(getf64() <= other.getf64());
+ default:
+ WASM_UNREACHABLE();
}
}
Literal Literal::gtS(const Literal& other) const {
switch (type) {
- case Type::i32: return Literal(i32 > other.i32);
- case Type::i64: return Literal(i64 > other.i64);
- default: WASM_UNREACHABLE();
+ case Type::i32:
+ return Literal(i32 > other.i32);
+ case Type::i64:
+ return Literal(i64 > other.i64);
+ default:
+ WASM_UNREACHABLE();
}
}
Literal Literal::gtU(const Literal& other) const {
switch (type) {
- case Type::i32: return Literal(uint32_t(i32) > uint32_t(other.i32));
- case Type::i64: return Literal(uint64_t(i64) > uint64_t(other.i64));
- default: WASM_UNREACHABLE();
+ case Type::i32:
+ return Literal(uint32_t(i32) > uint32_t(other.i32));
+ case Type::i64:
+ return Literal(uint64_t(i64) > uint64_t(other.i64));
+ default:
+ WASM_UNREACHABLE();
}
}
Literal Literal::gt(const Literal& other) const {
switch (type) {
- case Type::f32: return Literal(getf32() > other.getf32());
- case Type::f64: return Literal(getf64() > other.getf64());
- default: WASM_UNREACHABLE();
+ case Type::f32:
+ return Literal(getf32() > other.getf32());
+ case Type::f64:
+ return Literal(getf64() > other.getf64());
+ default:
+ WASM_UNREACHABLE();
}
}
Literal Literal::geS(const Literal& other) const {
switch (type) {
- case Type::i32: return Literal(i32 >= other.i32);
- case Type::i64: return Literal(i64 >= other.i64);
- default: WASM_UNREACHABLE();
+ case Type::i32:
+ return Literal(i32 >= other.i32);
+ case Type::i64:
+ return Literal(i64 >= other.i64);
+ default:
+ WASM_UNREACHABLE();
}
}
Literal Literal::geU(const Literal& other) const {
switch (type) {
- case Type::i32: return Literal(uint32_t(i32) >= uint32_t(other.i32));
- case Type::i64: return Literal(uint64_t(i64) >= uint64_t(other.i64));
- default: WASM_UNREACHABLE();
+ case Type::i32:
+ return Literal(uint32_t(i32) >= uint32_t(other.i32));
+ case Type::i64:
+ return Literal(uint64_t(i64) >= uint64_t(other.i64));
+ default:
+ WASM_UNREACHABLE();
}
}
Literal Literal::ge(const Literal& other) const {
switch (type) {
- case Type::f32: return Literal(getf32() >= other.getf32());
- case Type::f64: return Literal(getf64() >= other.getf64());
- default: WASM_UNREACHABLE();
+ case Type::f32:
+ return Literal(getf32() >= other.getf32());
+ case Type::f64:
+ return Literal(getf64() >= other.getf64());
+ default:
+ WASM_UNREACHABLE();
}
}
@@ -881,23 +1067,36 @@ Literal Literal::min(const Literal& other) const {
switch (type) {
case Type::f32: {
auto l = getf32(), r = other.getf32();
- if (l == r && l == 0) return Literal(std::signbit(l) ? l : r);
+ if (l == r && l == 0)
+ return Literal(std::signbit(l) ? l : r);
auto result = std::min(l, r);
bool lnan = std::isnan(l), rnan = std::isnan(r);
- if (!std::isnan(result) && !lnan && !rnan) return Literal(result);
- if (!lnan && !rnan) return Literal((int32_t)0x7fc00000).castToF32();
- return Literal(lnan ? l : r).castToI32().or_(Literal(0xc00000)).castToF32();
+ if (!std::isnan(result) && !lnan && !rnan)
+ return Literal(result);
+ if (!lnan && !rnan)
+ return Literal((int32_t)0x7fc00000).castToF32();
+ return Literal(lnan ? l : r)
+ .castToI32()
+ .or_(Literal(0xc00000))
+ .castToF32();
}
case Type::f64: {
auto l = getf64(), r = other.getf64();
- if (l == r && l == 0) return Literal(std::signbit(l) ? l : r);
+ if (l == r && l == 0)
+ return Literal(std::signbit(l) ? l : r);
auto result = std::min(l, r);
bool lnan = std::isnan(l), rnan = std::isnan(r);
- if (!std::isnan(result) && !lnan && !rnan) return Literal(result);
- if (!lnan && !rnan) return Literal((int64_t)0x7ff8000000000000LL).castToF64();
- return Literal(lnan ? l : r).castToI64().or_(Literal(int64_t(0x8000000000000LL))).castToF64();
+ if (!std::isnan(result) && !lnan && !rnan)
+ return Literal(result);
+ if (!lnan && !rnan)
+ return Literal((int64_t)0x7ff8000000000000LL).castToF64();
+ return Literal(lnan ? l : r)
+ .castToI64()
+ .or_(Literal(int64_t(0x8000000000000LL)))
+ .castToF64();
}
- default: WASM_UNREACHABLE();
+ default:
+ WASM_UNREACHABLE();
}
}
@@ -905,32 +1104,52 @@ Literal Literal::max(const Literal& other) const {
switch (type) {
case Type::f32: {
auto l = getf32(), r = other.getf32();
- if (l == r && l == 0) return Literal(std::signbit(l) ? r : l);
+ if (l == r && l == 0)
+ return Literal(std::signbit(l) ? r : l);
auto result = std::max(l, r);
bool lnan = std::isnan(l), rnan = std::isnan(r);
- if (!std::isnan(result) && !lnan && !rnan) return Literal(result);
- if (!lnan && !rnan) return Literal((int32_t)0x7fc00000).castToF32();
- return Literal(lnan ? l : r).castToI32().or_(Literal(0xc00000)).castToF32();
+ if (!std::isnan(result) && !lnan && !rnan)
+ return Literal(result);
+ if (!lnan && !rnan)
+ return Literal((int32_t)0x7fc00000).castToF32();
+ return Literal(lnan ? l : r)
+ .castToI32()
+ .or_(Literal(0xc00000))
+ .castToF32();
}
case Type::f64: {
auto l = getf64(), r = other.getf64();
- if (l == r && l == 0) return Literal(std::signbit(l) ? r : l);
+ if (l == r && l == 0)
+ return Literal(std::signbit(l) ? r : l);
auto result = std::max(l, r);
bool lnan = std::isnan(l), rnan = std::isnan(r);
- if (!std::isnan(result) && !lnan && !rnan) return Literal(result);
- if (!lnan && !rnan) return Literal((int64_t)0x7ff8000000000000LL).castToF64();
- return Literal(lnan ? l : r).castToI64().or_(Literal(int64_t(0x8000000000000LL))).castToF64();
+ if (!std::isnan(result) && !lnan && !rnan)
+ return Literal(result);
+ if (!lnan && !rnan)
+ return Literal((int64_t)0x7ff8000000000000LL).castToF64();
+ return Literal(lnan ? l : r)
+ .castToI64()
+ .or_(Literal(int64_t(0x8000000000000LL)))
+ .castToF64();
}
- default: WASM_UNREACHABLE();
+ default:
+ WASM_UNREACHABLE();
}
}
Literal Literal::copysign(const Literal& other) const {
// operate on bits directly, to avoid signalling bit being set on a float
switch (type) {
- case Type::f32: return Literal((i32 & 0x7fffffff) | (other.i32 & 0x80000000)).castToF32(); break;
- case Type::f64: return Literal((i64 & 0x7fffffffffffffffUL) | (other.i64 & 0x8000000000000000UL)).castToF64(); break;
- default: WASM_UNREACHABLE();
+ case Type::f32:
+ return Literal((i32 & 0x7fffffff) | (other.i32 & 0x80000000)).castToF32();
+ break;
+ case Type::f64:
+ return Literal((i64 & 0x7fffffffffffffffUL) |
+ (other.i64 & 0x8000000000000000UL))
+ .castToF64();
+ break;
+ default:
+ WASM_UNREACHABLE();
}
}
@@ -943,7 +1162,8 @@ static LaneArray<Lanes> getLanes(const Literal& val) {
for (size_t lane_index = 0; lane_index < Lanes; ++lane_index) {
LaneT lane(0);
for (size_t offset = 0; offset < lane_width; ++offset) {
- lane |= LaneT(bytes.at(lane_index * lane_width + offset)) << LaneT(8 * offset);
+ lane |= LaneT(bytes.at(lane_index * lane_width + offset))
+ << LaneT(8 * offset);
}
lanes.at(lane_index) = Literal(lane);
}
@@ -983,7 +1203,8 @@ LaneArray<2> Literal::getLanesF64x2() const {
return lanes;
}
-Literal Literal::shuffleV8x16(const Literal& other, const std::array<uint8_t, 16>& mask) const {
+Literal Literal::shuffleV8x16(const Literal& other,
+ const std::array<uint8_t, 16>& mask) const {
assert(type == Type::v128);
uint8_t bytes[16];
for (size_t i = 0; i < mask.size(); ++i) {
@@ -992,8 +1213,7 @@ Literal Literal::shuffleV8x16(const Literal& other, const std::array<uint8_t, 16
return Literal(bytes);
}
-template<Type Ty, int Lanes>
-static Literal splat(const Literal& val) {
+template<Type Ty, int Lanes> static Literal splat(const Literal& val) {
assert(val.type == Ty);
LaneArray<Lanes> lanes;
lanes.fill(val);
@@ -1007,17 +1227,34 @@ Literal Literal::splatI64x2() const { return splat<Type::i64, 2>(*this); }
Literal Literal::splatF32x4() const { return splat<Type::f32, 4>(*this); }
Literal Literal::splatF64x2() const { return splat<Type::f64, 2>(*this); }
-Literal Literal::extractLaneSI8x16(uint8_t index) const { return getLanesSI8x16().at(index); }
-Literal Literal::extractLaneUI8x16(uint8_t index) const { return getLanesUI8x16().at(index); }
-Literal Literal::extractLaneSI16x8(uint8_t index) const { return getLanesSI16x8().at(index); }
-Literal Literal::extractLaneUI16x8(uint8_t index) const { return getLanesUI16x8().at(index); }
-Literal Literal::extractLaneI32x4(uint8_t index) const { return getLanesI32x4().at(index); }
-Literal Literal::extractLaneI64x2(uint8_t index) const { return getLanesI64x2().at(index); }
-Literal Literal::extractLaneF32x4(uint8_t index) const { return getLanesF32x4().at(index); }
-Literal Literal::extractLaneF64x2(uint8_t index) const { return getLanesF64x2().at(index); }
+Literal Literal::extractLaneSI8x16(uint8_t index) const {
+ return getLanesSI8x16().at(index);
+}
+Literal Literal::extractLaneUI8x16(uint8_t index) const {
+ return getLanesUI8x16().at(index);
+}
+Literal Literal::extractLaneSI16x8(uint8_t index) const {
+ return getLanesSI16x8().at(index);
+}
+Literal Literal::extractLaneUI16x8(uint8_t index) const {
+ return getLanesUI16x8().at(index);
+}
+Literal Literal::extractLaneI32x4(uint8_t index) const {
+ return getLanesI32x4().at(index);
+}
+Literal Literal::extractLaneI64x2(uint8_t index) const {
+ return getLanesI64x2().at(index);
+}
+Literal Literal::extractLaneF32x4(uint8_t index) const {
+ return getLanesF32x4().at(index);
+}
+Literal Literal::extractLaneF64x2(uint8_t index) const {
+ return getLanesF64x2().at(index);
+}
template<int Lanes, LaneArray<Lanes> (Literal::*IntoLanes)() const>
-static Literal replace(const Literal& val, const Literal& other, uint8_t index) {
+static Literal
+replace(const Literal& val, const Literal& other, uint8_t index) {
LaneArray<Lanes> lanes = (val.*IntoLanes)();
lanes.at(index) = other;
auto ret = Literal(lanes);
@@ -1043,7 +1280,8 @@ Literal Literal::replaceLaneF64x2(const Literal& other, uint8_t index) const {
return replace<2, &Literal::getLanesF64x2>(*this, other, index);
}
-template<int Lanes, LaneArray<Lanes> (Literal::*IntoLanes)() const,
+template<int Lanes,
+ LaneArray<Lanes> (Literal::*IntoLanes)() const,
Literal (Literal::*UnaryOp)(void) const>
static Literal unary(const Literal& val) {
LaneArray<Lanes> lanes = (val.*IntoLanes)();
@@ -1160,14 +1398,16 @@ Literal Literal::allTrueI64x2() const {
return all_true<2, &Literal::getLanesI64x2>(*this);
}
-template<int Lanes, LaneArray<Lanes> (Literal::*IntoLanes)() const,
+template<int Lanes,
+ LaneArray<Lanes> (Literal::*IntoLanes)() const,
Literal (Literal::*ShiftOp)(const Literal&) const>
static Literal shift(const Literal& vec, const Literal& shift) {
assert(shift.type == Type::i32);
size_t lane_bits = 128 / Lanes;
LaneArray<Lanes> lanes = (vec.*IntoLanes)();
for (size_t i = 0; i < Lanes; ++i) {
- lanes[i] = (lanes[i].*ShiftOp)(Literal(int32_t(shift.geti32() % lane_bits)));
+ lanes[i] =
+ (lanes[i].*ShiftOp)(Literal(int32_t(shift.geti32() % lane_bits)));
}
return Literal(lanes);
}
@@ -1209,7 +1449,8 @@ Literal Literal::shrUI64x2(const Literal& other) const {
return shift<2, &Literal::getLanesI64x2, &Literal::shrU>(*this, other);
}
-template<int Lanes, LaneArray<Lanes> (Literal::*IntoLanes)() const,
+template<int Lanes,
+ LaneArray<Lanes> (Literal::*IntoLanes)() const,
Literal (Literal::*CompareOp)(const Literal&) const,
typename LaneT = int32_t>
static Literal compare(const Literal& val, const Literal& other) {
@@ -1217,8 +1458,8 @@ static Literal compare(const Literal& val, const Literal& other) {
LaneArray<Lanes> other_lanes = (other.*IntoLanes)();
for (size_t i = 0; i < Lanes; ++i) {
lanes[i] = (lanes[i].*CompareOp)(other_lanes[i]) == Literal(int32_t(1))
- ? Literal(LaneT(-1))
- : Literal(LaneT(0));
+ ? Literal(LaneT(-1))
+ : Literal(LaneT(0));
}
return Literal(lanes);
}
@@ -1235,7 +1476,7 @@ Literal Literal::ltSI8x16(const Literal& other) const {
Literal Literal::ltUI8x16(const Literal& other) const {
return compare<16, &Literal::getLanesUI8x16, &Literal::ltU>(*this, other);
}
-Literal Literal::gtSI8x16(const Literal& other) const {
+Literal Literal::gtSI8x16(const Literal& other) const {
return compare<16, &Literal::getLanesSI8x16, &Literal::gtS>(*this, other);
}
Literal Literal::gtUI8x16(const Literal& other) const {
@@ -1332,26 +1573,33 @@ Literal Literal::geF32x4(const Literal& other) const {
return compare<4, &Literal::getLanesF32x4, &Literal::ge>(*this, other);
}
Literal Literal::eqF64x2(const Literal& other) const {
- return compare<2, &Literal::getLanesF64x2, &Literal::eq, int64_t>(*this, other);
+ return compare<2, &Literal::getLanesF64x2, &Literal::eq, int64_t>(*this,
+ other);
}
Literal Literal::neF64x2(const Literal& other) const {
- return compare<2, &Literal::getLanesF64x2, &Literal::ne, int64_t>(*this, other);
+ return compare<2, &Literal::getLanesF64x2, &Literal::ne, int64_t>(*this,
+ other);
}
Literal Literal::ltF64x2(const Literal& other) const {
- return compare<2, &Literal::getLanesF64x2, &Literal::lt, int64_t>(*this, other);
+ return compare<2, &Literal::getLanesF64x2, &Literal::lt, int64_t>(*this,
+ other);
}
Literal Literal::gtF64x2(const Literal& other) const {
- return compare<2, &Literal::getLanesF64x2, &Literal::gt, int64_t>(*this, other);
+ return compare<2, &Literal::getLanesF64x2, &Literal::gt, int64_t>(*this,
+ other);
}
Literal Literal::leF64x2(const Literal& other) const {
- return compare<2, &Literal::getLanesF64x2, &Literal::le, int64_t>(*this, other);
+ return compare<2, &Literal::getLanesF64x2, &Literal::le, int64_t>(*this,
+ other);
}
Literal Literal::geF64x2(const Literal& other) const {
- return compare<2, &Literal::getLanesF64x2, &Literal::ge, int64_t>(*this, other);
+ return compare<2, &Literal::getLanesF64x2, &Literal::ge, int64_t>(*this,
+ other);
}
-template<int Lanes, LaneArray<Lanes> (Literal::*IntoLanes)() const,
- Literal (Literal::*BinaryOp)(const Literal&) const>
+template<int Lanes,
+ LaneArray<Lanes> (Literal::*IntoLanes)() const,
+ Literal (Literal::*BinaryOp)(const Literal&) const>
static Literal binary(const Literal& val, const Literal& other) {
LaneArray<Lanes> lanes = (val.*IntoLanes)();
LaneArray<Lanes> other_lanes = (other.*IntoLanes)();
@@ -1374,19 +1622,23 @@ Literal Literal::addI8x16(const Literal& other) const {
return binary<16, &Literal::getLanesUI8x16, &Literal::add>(*this, other);
}
Literal Literal::addSaturateSI8x16(const Literal& other) const {
- return binary<16, &Literal::getLanesUI8x16, &Literal::addSatSI8>(*this, other);
+ return binary<16, &Literal::getLanesUI8x16, &Literal::addSatSI8>(*this,
+ other);
}
Literal Literal::addSaturateUI8x16(const Literal& other) const {
- return binary<16, &Literal::getLanesSI8x16, &Literal::addSatUI8>(*this, other);
+ return binary<16, &Literal::getLanesSI8x16, &Literal::addSatUI8>(*this,
+ other);
}
Literal Literal::subI8x16(const Literal& other) const {
return binary<16, &Literal::getLanesUI8x16, &Literal::sub>(*this, other);
}
Literal Literal::subSaturateSI8x16(const Literal& other) const {
- return binary<16, &Literal::getLanesUI8x16, &Literal::subSatSI8>(*this, other);
+ return binary<16, &Literal::getLanesUI8x16, &Literal::subSatSI8>(*this,
+ other);
}
Literal Literal::subSaturateUI8x16(const Literal& other) const {
- return binary<16, &Literal::getLanesSI8x16, &Literal::subSatUI8>(*this, other);
+ return binary<16, &Literal::getLanesSI8x16, &Literal::subSatUI8>(*this,
+ other);
}
Literal Literal::mulI8x16(const Literal& other) const {
return binary<16, &Literal::getLanesUI8x16, &Literal::mul>(*this, other);
@@ -1395,19 +1647,23 @@ Literal Literal::addI16x8(const Literal& other) const {
return binary<8, &Literal::getLanesUI16x8, &Literal::add>(*this, other);
}
Literal Literal::addSaturateSI16x8(const Literal& other) const {
- return binary<8, &Literal::getLanesUI16x8, &Literal::addSatSI16>(*this, other);
+ return binary<8, &Literal::getLanesUI16x8, &Literal::addSatSI16>(*this,
+ other);
}
Literal Literal::addSaturateUI16x8(const Literal& other) const {
- return binary<8, &Literal::getLanesSI16x8, &Literal::addSatUI16>(*this, other);
+ return binary<8, &Literal::getLanesSI16x8, &Literal::addSatUI16>(*this,
+ other);
}
Literal Literal::subI16x8(const Literal& other) const {
return binary<8, &Literal::getLanesUI16x8, &Literal::sub>(*this, other);
}
Literal Literal::subSaturateSI16x8(const Literal& other) const {
- return binary<8, &Literal::getLanesUI16x8, &Literal::subSatSI16>(*this, other);
+ return binary<8, &Literal::getLanesUI16x8, &Literal::subSatSI16>(*this,
+ other);
}
Literal Literal::subSaturateUI16x8(const Literal& other) const {
- return binary<8, &Literal::getLanesSI16x8, &Literal::subSatUI16>(*this, other);
+ return binary<8, &Literal::getLanesSI16x8, &Literal::subSatUI16>(*this,
+ other);
}
Literal Literal::mulI16x8(const Literal& other) const {
return binary<8, &Literal::getLanesUI16x8, &Literal::mul>(*this, other);
@@ -1464,7 +1720,8 @@ Literal Literal::maxF64x2(const Literal& other) const {
return binary<2, &Literal::getLanesF64x2, &Literal::max>(*this, other);
}
-Literal Literal::bitselectV128(const Literal& left, const Literal& right) const {
+Literal Literal::bitselectV128(const Literal& left,
+ const Literal& right) const {
return andV128(left).orV128(notV128().andV128(right));
}
diff --git a/src/wasm/wasm-binary.cpp b/src/wasm/wasm-binary.cpp
index b8c3f1049..6369a79fa 100644
--- a/src/wasm/wasm-binary.cpp
+++ b/src/wasm/wasm-binary.cpp
@@ -17,10 +17,10 @@
#include <algorithm>
#include <fstream>
-#include "wasm-binary.h"
-#include "wasm-stack.h"
#include "ir/module-utils.h"
#include "support/bits.h"
+#include "wasm-binary.h"
+#include "wasm-stack.h"
namespace wasm {
@@ -30,7 +30,9 @@ void WasmBinaryWriter::prepare() {
if (func->type.isNull()) {
func->type = ensureFunctionType(getSig(func.get()), wasm)->name;
}
- // TODO: depending on upstream flux https://github.com/WebAssembly/spec/pull/301 might want this: assert(!func->type.isNull());
+ // TODO: depending on upstream flux
+ // https://github.com/WebAssembly/spec/pull/301 might want this:
+ // assert(!func->type.isNull());
}
ModuleUtils::BinaryIndexes indexes(*wasm);
mappedFunctions = std::move(indexes.functionIndexes);
@@ -61,9 +63,12 @@ void WasmBinaryWriter::write() {
writeDataCount();
writeFunctions();
writeDataSegments();
- if (debugInfo) writeNames();
- if (sourceMap && !sourceMapUrl.empty()) writeSourceMapUrl();
- if (symbolMap.size() > 0) writeSymbolMap();
+ if (debugInfo)
+ writeNames();
+ if (sourceMap && !sourceMapUrl.empty())
+ writeSourceMapUrl();
+ if (symbolMap.size() > 0)
+ writeSymbolMap();
if (sourceMap) {
writeSourceMapEpilog();
@@ -76,7 +81,8 @@ void WasmBinaryWriter::write() {
}
void WasmBinaryWriter::writeHeader() {
- if (debug) std::cerr << "== writeHeader" << std::endl;
+ if (debug)
+ std::cerr << "== writeHeader" << std::endl;
o << int32_t(BinaryConsts::Magic); // magic number \0asm
o << int32_t(BinaryConsts::Version);
}
@@ -88,11 +94,12 @@ int32_t WasmBinaryWriter::writeU32LEBPlaceholder() {
return ret;
}
-void WasmBinaryWriter::writeResizableLimits(Address initial, Address maximum,
- bool hasMaximum, bool shared) {
- uint32_t flags =
- (hasMaximum ? (uint32_t) BinaryConsts::HasMaximum : 0U) |
- (shared ? (uint32_t) BinaryConsts::IsShared : 0U);
+void WasmBinaryWriter::writeResizableLimits(Address initial,
+ Address maximum,
+ bool hasMaximum,
+ bool shared) {
+ uint32_t flags = (hasMaximum ? (uint32_t)BinaryConsts::HasMaximum : 0U) |
+ (shared ? (uint32_t)BinaryConsts::IsShared : 0U);
o << U32LEB(flags);
o << U32LEB(initial);
if (hasMaximum) {
@@ -100,63 +107,76 @@ void WasmBinaryWriter::writeResizableLimits(Address initial, Address maximum,
}
}
-template<typename T>
-int32_t WasmBinaryWriter::startSection(T code) {
+template<typename T> int32_t WasmBinaryWriter::startSection(T code) {
o << U32LEB(code);
- if (sourceMap) sourceMapLocationsSizeAtSectionStart = sourceMapLocations.size();
+ if (sourceMap)
+ sourceMapLocationsSizeAtSectionStart = sourceMapLocations.size();
return writeU32LEBPlaceholder(); // section size to be filled in later
}
void WasmBinaryWriter::finishSection(int32_t start) {
- int32_t size = o.size() - start - MaxLEB32Bytes; // section size does not include the reserved bytes of the size field itself
+ // section size does not include the reserved bytes of the size field itself
+ int32_t size = o.size() - start - MaxLEB32Bytes;
auto sizeFieldSize = o.writeAt(start, U32LEB(size));
if (sizeFieldSize != MaxLEB32Bytes) {
// we can save some room, nice
assert(sizeFieldSize < MaxLEB32Bytes);
- std::move(&o[start] + MaxLEB32Bytes, &o[start] + MaxLEB32Bytes + size, &o[start] + sizeFieldSize);
+ std::move(&o[start] + MaxLEB32Bytes,
+ &o[start] + MaxLEB32Bytes + size,
+ &o[start] + sizeFieldSize);
auto adjustment = MaxLEB32Bytes - sizeFieldSize;
o.resize(o.size() - adjustment);
if (sourceMap) {
- for (auto i = sourceMapLocationsSizeAtSectionStart; i < sourceMapLocations.size(); ++i) {
+ for (auto i = sourceMapLocationsSizeAtSectionStart;
+ i < sourceMapLocations.size();
+ ++i) {
sourceMapLocations[i].first -= adjustment;
}
}
}
}
-int32_t WasmBinaryWriter::startSubsection(BinaryConsts::UserSections::Subsection code) {
+int32_t
+WasmBinaryWriter::startSubsection(BinaryConsts::UserSections::Subsection code) {
return startSection(code);
}
-void WasmBinaryWriter::finishSubsection(int32_t start) {
- finishSection(start);
-}
+void WasmBinaryWriter::finishSubsection(int32_t start) { finishSection(start); }
void WasmBinaryWriter::writeStart() {
- if (!wasm->start.is()) return;
- if (debug) std::cerr << "== writeStart" << std::endl;
+ if (!wasm->start.is())
+ return;
+ if (debug)
+ std::cerr << "== writeStart" << std::endl;
auto start = startSection(BinaryConsts::Section::Start);
o << U32LEB(getFunctionIndex(wasm->start.str));
finishSection(start);
}
void WasmBinaryWriter::writeMemory() {
- if (!wasm->memory.exists || wasm->memory.imported()) return;
- if (debug) std::cerr << "== writeMemory" << std::endl;
+ if (!wasm->memory.exists || wasm->memory.imported())
+ return;
+ if (debug)
+ std::cerr << "== writeMemory" << std::endl;
auto start = startSection(BinaryConsts::Section::Memory);
o << U32LEB(1); // Define 1 memory
- writeResizableLimits(wasm->memory.initial, wasm->memory.max,
- wasm->memory.hasMax(), wasm->memory.shared);
+ writeResizableLimits(wasm->memory.initial,
+ wasm->memory.max,
+ wasm->memory.hasMax(),
+ wasm->memory.shared);
finishSection(start);
}
void WasmBinaryWriter::writeTypes() {
- if (wasm->functionTypes.size() == 0) return;
- if (debug) std::cerr << "== writeTypes" << std::endl;
+ if (wasm->functionTypes.size() == 0)
+ return;
+ if (debug)
+ std::cerr << "== writeTypes" << std::endl;
auto start = startSection(BinaryConsts::Section::Type);
o << U32LEB(wasm->functionTypes.size());
for (auto& type : wasm->functionTypes) {
- if (debug) std::cerr << "write one" << std::endl;
+ if (debug)
+ std::cerr << "write one" << std::endl;
o << S32LEB(BinaryConsts::EncodedType::Func);
o << U32LEB(type->params.size());
for (auto param : type->params) {
@@ -175,15 +195,18 @@ void WasmBinaryWriter::writeTypes() {
int32_t WasmBinaryWriter::getFunctionTypeIndex(Name type) {
// TODO: optimize
for (size_t i = 0; i < wasm->functionTypes.size(); i++) {
- if (wasm->functionTypes[i]->name == type) return i;
+ if (wasm->functionTypes[i]->name == type)
+ return i;
}
abort();
}
void WasmBinaryWriter::writeImports() {
auto num = importInfo->getNumImports();
- if (num == 0) return;
- if (debug) std::cerr << "== writeImports" << std::endl;
+ if (num == 0)
+ return;
+ if (debug)
+ std::cerr << "== writeImports" << std::endl;
auto start = startSection(BinaryConsts::Section::Import);
o << U32LEB(num);
auto writeImportHeader = [&](Importable* import) {
@@ -191,42 +214,54 @@ void WasmBinaryWriter::writeImports() {
writeInlineString(import->base.str);
};
ModuleUtils::iterImportedFunctions(*wasm, [&](Function* func) {
- if (debug) std::cerr << "write one function" << std::endl;
+ if (debug)
+ std::cerr << "write one function" << std::endl;
writeImportHeader(func);
o << U32LEB(int32_t(ExternalKind::Function));
o << U32LEB(getFunctionTypeIndex(func->type));
});
ModuleUtils::iterImportedGlobals(*wasm, [&](Global* global) {
- if (debug) std::cerr << "write one global" << std::endl;
+ if (debug)
+ std::cerr << "write one global" << std::endl;
writeImportHeader(global);
o << U32LEB(int32_t(ExternalKind::Global));
o << binaryType(global->type);
o << U32LEB(global->mutable_);
});
if (wasm->memory.imported()) {
- if (debug) std::cerr << "write one memory" << std::endl;
+ if (debug)
+ std::cerr << "write one memory" << std::endl;
writeImportHeader(&wasm->memory);
o << U32LEB(int32_t(ExternalKind::Memory));
- writeResizableLimits(wasm->memory.initial, wasm->memory.max,
- wasm->memory.hasMax(), wasm->memory.shared);
+ writeResizableLimits(wasm->memory.initial,
+ wasm->memory.max,
+ wasm->memory.hasMax(),
+ wasm->memory.shared);
}
if (wasm->table.imported()) {
- if (debug) std::cerr << "write one table" << std::endl;
+ if (debug)
+ std::cerr << "write one table" << std::endl;
writeImportHeader(&wasm->table);
o << U32LEB(int32_t(ExternalKind::Table));
o << S32LEB(BinaryConsts::EncodedType::AnyFunc);
- writeResizableLimits(wasm->table.initial, wasm->table.max, wasm->table.hasMax(), /*shared=*/false);
+ writeResizableLimits(wasm->table.initial,
+ wasm->table.max,
+ wasm->table.hasMax(),
+ /*shared=*/false);
}
finishSection(start);
}
void WasmBinaryWriter::writeFunctionSignatures() {
- if (importInfo->getNumDefinedFunctions() == 0) return;
- if (debug) std::cerr << "== writeFunctionSignatures" << std::endl;
+ if (importInfo->getNumDefinedFunctions() == 0)
+ return;
+ if (debug)
+ std::cerr << "== writeFunctionSignatures" << std::endl;
auto start = startSection(BinaryConsts::Section::Function);
o << U32LEB(importInfo->getNumDefinedFunctions());
ModuleUtils::iterDefinedFunctions(*wasm, [&](Function* func) {
- if (debug) std::cerr << "write one" << std::endl;
+ if (debug)
+ std::cerr << "write one" << std::endl;
o << U32LEB(getFunctionTypeIndex(func->type));
});
finishSection(start);
@@ -237,27 +272,35 @@ void WasmBinaryWriter::writeExpression(Expression* curr) {
}
void WasmBinaryWriter::writeFunctions() {
- if (importInfo->getNumDefinedFunctions() == 0) return;
- if (debug) std::cerr << "== writeFunctions" << std::endl;
+ if (importInfo->getNumDefinedFunctions() == 0)
+ return;
+ if (debug)
+ std::cerr << "== writeFunctions" << std::endl;
auto start = startSection(BinaryConsts::Section::Code);
o << U32LEB(importInfo->getNumDefinedFunctions());
ModuleUtils::iterDefinedFunctions(*wasm, [&](Function* func) {
size_t sourceMapLocationsSizeAtFunctionStart = sourceMapLocations.size();
- if (debug) std::cerr << "write one at" << o.size() << std::endl;
+ if (debug)
+ std::cerr << "write one at" << o.size() << std::endl;
size_t sizePos = writeU32LEBPlaceholder();
size_t start = o.size();
- if (debug) std::cerr << "writing" << func->name << std::endl;
+ if (debug)
+ std::cerr << "writing" << func->name << std::endl;
// Emit Stack IR if present, and if we can
if (func->stackIR && !sourceMap) {
- if (debug) std::cerr << "write Stack IR" << std::endl;
+ if (debug)
+ std::cerr << "write Stack IR" << std::endl;
StackIRFunctionStackWriter<WasmBinaryWriter>(func, *this, o, debug);
} else {
- if (debug) std::cerr << "write Binaryen IR" << std::endl;
+ if (debug)
+ std::cerr << "write Binaryen IR" << std::endl;
FunctionStackWriter<WasmBinaryWriter>(func, *this, o, sourceMap, debug);
}
size_t size = o.size() - start;
assert(size <= std::numeric_limits<uint32_t>::max());
- if (debug) std::cerr << "body size: " << size << ", writing at " << sizePos << ", next starts at " << o.size() << std::endl;
+ if (debug)
+ std::cerr << "body size: " << size << ", writing at " << sizePos
+ << ", next starts at " << o.size() << std::endl;
auto sizeFieldSize = o.writeAt(sizePos, U32LEB(size));
if (sizeFieldSize != MaxLEB32Bytes) {
// we can save some room, nice
@@ -266,24 +309,30 @@ void WasmBinaryWriter::writeFunctions() {
auto adjustment = MaxLEB32Bytes - sizeFieldSize;
o.resize(o.size() - adjustment);
if (sourceMap) {
- for (auto i = sourceMapLocationsSizeAtFunctionStart; i < sourceMapLocations.size(); ++i) {
+ for (auto i = sourceMapLocationsSizeAtFunctionStart;
+ i < sourceMapLocations.size();
+ ++i) {
sourceMapLocations[i].first -= adjustment;
}
}
}
- tableOfContents.functionBodies.emplace_back(func->name, sizePos + sizeFieldSize, size);
+ tableOfContents.functionBodies.emplace_back(
+ func->name, sizePos + sizeFieldSize, size);
});
finishSection(start);
}
void WasmBinaryWriter::writeGlobals() {
- if (importInfo->getNumDefinedGlobals() == 0) return;
- if (debug) std::cerr << "== writeglobals" << std::endl;
+ if (importInfo->getNumDefinedGlobals() == 0)
+ return;
+ if (debug)
+ std::cerr << "== writeglobals" << std::endl;
auto start = startSection(BinaryConsts::Section::Global);
auto num = importInfo->getNumDefinedGlobals();
o << U32LEB(num);
ModuleUtils::iterDefinedGlobals(*wasm, [&](Global* global) {
- if (debug) std::cerr << "write one" << std::endl;
+ if (debug)
+ std::cerr << "write one" << std::endl;
o << binaryType(global->type);
o << U32LEB(global->mutable_);
writeExpression(global->init);
@@ -293,22 +342,33 @@ void WasmBinaryWriter::writeGlobals() {
}
void WasmBinaryWriter::writeExports() {
- if (wasm->exports.size() == 0) return;
- if (debug) std::cerr << "== writeexports" << std::endl;
+ if (wasm->exports.size() == 0)
+ return;
+ if (debug)
+ std::cerr << "== writeexports" << std::endl;
auto start = startSection(BinaryConsts::Section::Export);
o << U32LEB(wasm->exports.size());
for (auto& curr : wasm->exports) {
- if (debug) std::cerr << "write one" << std::endl;
+ if (debug)
+ std::cerr << "write one" << std::endl;
writeInlineString(curr->name.str);
o << U32LEB(int32_t(curr->kind));
switch (curr->kind) {
- case ExternalKind::Function: o << U32LEB(getFunctionIndex(curr->value)); break;
- case ExternalKind::Table: o << U32LEB(0); break;
- case ExternalKind::Memory: o << U32LEB(0); break;
- case ExternalKind::Global: o << U32LEB(getGlobalIndex(curr->value)); break;
- default: WASM_UNREACHABLE();
+ case ExternalKind::Function:
+ o << U32LEB(getFunctionIndex(curr->value));
+ break;
+ case ExternalKind::Table:
+ o << U32LEB(0);
+ break;
+ case ExternalKind::Memory:
+ o << U32LEB(0);
+ break;
+ case ExternalKind::Global:
+ o << U32LEB(getGlobalIndex(curr->value));
+ break;
+ default:
+ WASM_UNREACHABLE();
}
-
}
finishSection(start);
}
@@ -323,7 +383,8 @@ void WasmBinaryWriter::writeDataCount() {
}
void WasmBinaryWriter::writeDataSegments() {
- if (wasm->memory.segments.size() == 0) return;
+ if (wasm->memory.segments.size() == 0)
+ return;
if (wasm->memory.segments.size() > WebLimitations::MaxDataSegments) {
std::cerr << "Some VMs may not accept this binary because it has a large "
<< "number of data segments. Run the limit-segments pass to "
@@ -357,12 +418,17 @@ uint32_t WasmBinaryWriter::getGlobalIndex(Name name) {
}
void WasmBinaryWriter::writeFunctionTableDeclaration() {
- if (!wasm->table.exists || wasm->table.imported()) return;
- if (debug) std::cerr << "== writeFunctionTableDeclaration" << std::endl;
+ if (!wasm->table.exists || wasm->table.imported())
+ return;
+ if (debug)
+ std::cerr << "== writeFunctionTableDeclaration" << std::endl;
auto start = startSection(BinaryConsts::Section::Table);
o << U32LEB(1); // Declare 1 table.
o << S32LEB(BinaryConsts::EncodedType::AnyFunc);
- writeResizableLimits(wasm->table.initial, wasm->table.max, wasm->table.hasMax(), /*shared=*/false);
+ writeResizableLimits(wasm->table.initial,
+ wasm->table.max,
+ wasm->table.hasMax(),
+ /*shared=*/false);
finishSection(start);
}
@@ -370,12 +436,14 @@ void WasmBinaryWriter::writeTableElements() {
if (!wasm->table.exists || wasm->table.segments.size() == 0) {
return;
}
- if (debug) std::cerr << "== writeTableElements" << std::endl;
+ if (debug)
+ std::cerr << "== writeTableElements" << std::endl;
auto start = startSection(BinaryConsts::Section::Element);
o << U32LEB(wasm->table.segments.size());
for (auto& segment : wasm->table.segments) {
- o << U32LEB(0); // Table index; 0 in the MVP (and binaryen IR only has 1 table)
+ // Table index; 0 in the MVP (and binaryen IR only has 1 table)
+ o << U32LEB(0);
writeExpression(segment.offset);
o << int8_t(BinaryConsts::End);
o << U32LEB(segment.data.size());
@@ -392,11 +460,14 @@ void WasmBinaryWriter::writeNames() {
hasContents = true;
getFunctionIndex(wasm->functions[0]->name); // generate mappedFunctions
}
- if (!hasContents) return;
- if (debug) std::cerr << "== writeNames" << std::endl;
+ if (!hasContents)
+ return;
+ if (debug)
+ std::cerr << "== writeNames" << std::endl;
auto start = startSection(BinaryConsts::Section::User);
writeInlineString(BinaryConsts::UserSections::Name);
- auto substart = startSubsection(BinaryConsts::UserSections::Subsection::NameFunction);
+ auto substart =
+ startSubsection(BinaryConsts::UserSections::Subsection::NameFunction);
o << U32LEB(mappedFunctions.size());
Index emitted = 0;
auto add = [&](Function* curr) {
@@ -413,7 +484,8 @@ void WasmBinaryWriter::writeNames() {
}
void WasmBinaryWriter::writeSourceMapUrl() {
- if (debug) std::cerr << "== writeSourceMapUrl" << std::endl;
+ if (debug)
+ std::cerr << "== writeSourceMapUrl" << std::endl;
auto start = startSection(BinaryConsts::Section::User);
writeInlineString(BinaryConsts::UserSections::SourceMapUrl);
writeInlineString(sourceMapUrl.c_str());
@@ -431,13 +503,14 @@ void WasmBinaryWriter::writeSymbolMap() {
}
void WasmBinaryWriter::initializeDebugInfo() {
- lastDebugLocation = { 0, /* lineNumber = */ 1, 0 };
+ lastDebugLocation = {0, /* lineNumber = */ 1, 0};
}
void WasmBinaryWriter::writeSourceMapProlog() {
*sourceMap << "{\"version\":3,\"sources\":[";
for (size_t i = 0; i < wasm->debugInfoFileNames.size(); i++) {
- if (i > 0) *sourceMap << ",";
+ if (i > 0)
+ *sourceMap << ",";
// TODO respect JSON string encoding, e.g. quotes and control chars.
*sourceMap << "\"" << wasm->debugInfoFileNames[i] << "\"";
}
@@ -456,15 +529,17 @@ static void writeBase64VLQ(std::ostream& out, int32_t n) {
}
// more VLG digit will follow -- add continuation bit (0x20),
// base64 codes 'g'..'z', '0'..'9', '+', '/'
- out << char(digit < 20 ? 'g' + digit : digit < 30 ? '0' + digit - 20 : digit == 30 ? '+' : '/');
+ out << char(digit < 20
+ ? 'g' + digit
+ : digit < 30 ? '0' + digit - 20 : digit == 30 ? '+' : '/');
}
}
void WasmBinaryWriter::writeSourceMapEpilog() {
// write source map entries
size_t lastOffset = 0;
- Function::DebugLocation lastLoc = { 0, /* lineNumber = */ 1, 0 };
- for (const auto &offsetAndlocPair : sourceMapLocations) {
+ Function::DebugLocation lastLoc = {0, /* lineNumber = */ 1, 0};
+ for (const auto& offsetAndlocPair : sourceMapLocations) {
if (lastOffset > 0) {
*sourceMap << ",";
}
@@ -473,7 +548,8 @@ void WasmBinaryWriter::writeSourceMapEpilog() {
writeBase64VLQ(*sourceMap, int32_t(offset - lastOffset));
writeBase64VLQ(*sourceMap, int32_t(loc.fileIndex - lastLoc.fileIndex));
writeBase64VLQ(*sourceMap, int32_t(loc.lineNumber - lastLoc.lineNumber));
- writeBase64VLQ(*sourceMap, int32_t(loc.columnNumber - lastLoc.columnNumber));
+ writeBase64VLQ(*sourceMap,
+ int32_t(loc.columnNumber - lastLoc.columnNumber));
lastLoc = loc;
lastOffset = offset;
}
@@ -516,20 +592,26 @@ void WasmBinaryWriter::writeFeaturesSection() {
// FeatureSet::toString()
auto toString = [](FeatureSet::Feature f) {
switch (f) {
- case FeatureSet::Atomics: return "atomics";
- case FeatureSet::MutableGlobals: return "mutable-globals";
- case FeatureSet::TruncSat: return "nontrapping-fptoint";
- case FeatureSet::SIMD: return "simd128";
- case FeatureSet::BulkMemory: return "bulk-memory";
- case FeatureSet::SignExt: return "sign-ext";
- default: WASM_UNREACHABLE();
+ case FeatureSet::Atomics:
+ return "atomics";
+ case FeatureSet::MutableGlobals:
+ return "mutable-globals";
+ case FeatureSet::TruncSat:
+ return "nontrapping-fptoint";
+ case FeatureSet::SIMD:
+ return "simd128";
+ case FeatureSet::BulkMemory:
+ return "bulk-memory";
+ case FeatureSet::SignExt:
+ return "sign-ext";
+ default:
+ WASM_UNREACHABLE();
}
};
std::vector<const char*> features;
- wasm->features.iterFeatures([&](FeatureSet::Feature f) {
- features.push_back(toString(f));
- });
+ wasm->features.iterFeatures(
+ [&](FeatureSet::Feature f) { features.push_back(toString(f)); });
auto start = startSection(BinaryConsts::User);
writeInlineString(BinaryConsts::UserSections::TargetFeatures);
@@ -541,7 +623,6 @@ void WasmBinaryWriter::writeFeaturesSection() {
finishSection(start);
}
-
void WasmBinaryWriter::writeDebugLocation(const Function::DebugLocation& loc) {
if (loc == lastDebugLocation) {
return;
@@ -568,7 +649,8 @@ void WasmBinaryWriter::writeInlineString(const char* name) {
}
static bool isHexDigit(char ch) {
- return (ch >= '0' && ch <= '9') || (ch >= 'a' && ch <= 'f') || (ch >= 'A' && ch <= 'F');
+ return (ch >= '0' && ch <= '9') || (ch >= 'a' && ch <= 'f') ||
+ (ch >= 'A' && ch <= 'F');
}
static int decodeHexNibble(char ch) {
@@ -586,11 +668,13 @@ void WasmBinaryWriter::writeEscapedName(const char* name) {
for (int32_t i = 0; i < size;) {
char ch = name[i++];
// support only `\xx` escapes; ignore invalid or unsupported escapes
- if (ch != '\\' || i + 1 >= size || !isHexDigit(name[i]) || !isHexDigit(name[i + 1])) {
+ if (ch != '\\' || i + 1 >= size || !isHexDigit(name[i]) ||
+ !isHexDigit(name[i + 1])) {
unescaped.push_back(ch);
continue;
}
- unescaped.push_back(char((decodeHexNibble(name[i]) << 4) | decodeHexNibble(name[i + 1])));
+ unescaped.push_back(
+ char((decodeHexNibble(name[i]) << 4) | decodeHexNibble(name[i + 1])));
i += 2;
}
writeInlineString(unescaped.c_str());
@@ -606,19 +690,25 @@ void WasmBinaryWriter::writeInlineBuffer(const char* data, size_t size) {
void WasmBinaryWriter::emitBuffer(const char* data, size_t size) {
assert(size > 0);
buffersToWrite.emplace_back(data, size, o.size());
- o << uint32_t(0); // placeholder, we'll fill in the pointer to the buffer later when we have it
+ // placeholder, we'll fill in the pointer to the buffer later when we have it
+ o << uint32_t(0);
}
-void WasmBinaryWriter::emitString(const char *str) {
- if (debug) std::cerr << "emitString " << str << std::endl;
+void WasmBinaryWriter::emitString(const char* str) {
+ if (debug)
+ std::cerr << "emitString " << str << std::endl;
emitBuffer(str, strlen(str) + 1);
}
void WasmBinaryWriter::finishUp() {
- if (debug) std::cerr << "finishUp" << std::endl;
+ if (debug)
+ std::cerr << "finishUp" << std::endl;
// finish buffers
for (const auto& buffer : buffersToWrite) {
- if (debug) std::cerr << "writing buffer" << (int)buffer.data[0] << "," << (int)buffer.data[1] << " at " << o.size() << " and pointer is at " << buffer.pointerLocation << std::endl;
+ if (debug)
+ std::cerr << "writing buffer" << (int)buffer.data[0] << ","
+ << (int)buffer.data[1] << " at " << o.size()
+ << " and pointer is at " << buffer.pointerLocation << std::endl;
o.writeAt(buffer.pointerLocation, (uint32_t)o.size());
for (size_t i = 0; i < buffer.size; i++) {
o << (uint8_t)buffer.data[i];
@@ -637,42 +727,71 @@ void WasmBinaryBuilder::read() {
while (more()) {
uint32_t sectionCode = getU32LEB();
uint32_t payloadLen = getU32LEB();
- if (pos + payloadLen > input.size()) throwError("Section extends beyond end of input");
+ if (pos + payloadLen > input.size())
+ throwError("Section extends beyond end of input");
auto oldPos = pos;
- // note the section in the list of seen sections, as almost no sections can appear more than once,
- // and verify those that shouldn't do not.
- if (sectionCode != BinaryConsts::Section::User && sectionCode != BinaryConsts::Section::Code) {
+ // note the section in the list of seen sections, as almost no sections can
+ // appear more than once, and verify those that shouldn't do not.
+ if (sectionCode != BinaryConsts::Section::User &&
+ sectionCode != BinaryConsts::Section::Code) {
if (!seenSections.insert(BinaryConsts::Section(sectionCode)).second) {
- throwError("section seen more than once: " + std::to_string(sectionCode));
+ throwError("section seen more than once: " +
+ std::to_string(sectionCode));
}
}
switch (sectionCode) {
- case BinaryConsts::Section::Start: readStart(); break;
- case BinaryConsts::Section::Memory: readMemory(); break;
- case BinaryConsts::Section::Type: readSignatures(); break;
- case BinaryConsts::Section::Import: readImports(); break;
- case BinaryConsts::Section::Function: readFunctionSignatures(); break;
- case BinaryConsts::Section::Code: readFunctions(); break;
- case BinaryConsts::Section::Export: readExports(); break;
- case BinaryConsts::Section::Element: readTableElements(); break;
+ case BinaryConsts::Section::Start:
+ readStart();
+ break;
+ case BinaryConsts::Section::Memory:
+ readMemory();
+ break;
+ case BinaryConsts::Section::Type:
+ readSignatures();
+ break;
+ case BinaryConsts::Section::Import:
+ readImports();
+ break;
+ case BinaryConsts::Section::Function:
+ readFunctionSignatures();
+ break;
+ case BinaryConsts::Section::Code:
+ readFunctions();
+ break;
+ case BinaryConsts::Section::Export:
+ readExports();
+ break;
+ case BinaryConsts::Section::Element:
+ readTableElements();
+ break;
case BinaryConsts::Section::Global: {
readGlobals();
- // imports can read global imports, so we run getGlobalName and create the mapping
- // but after we read globals, we need to add the internal globals too, so do that here
+ // imports can read global imports, so we run getGlobalName and create
+ // the mapping but after we read globals, we need to add the internal
+ // globals too, so do that here
mappedGlobals.clear(); // wipe the mapping
- getGlobalName(-1); // force rebuild
+ getGlobalName(-1); // force rebuild
break;
}
- case BinaryConsts::Section::Data: readDataSegments(); break;
- case BinaryConsts::Section::DataCount: readDataCount(); break;
- case BinaryConsts::Section::Table: readFunctionTableDeclaration(); break;
+ case BinaryConsts::Section::Data:
+ readDataSegments();
+ break;
+ case BinaryConsts::Section::DataCount:
+ readDataCount();
+ break;
+ case BinaryConsts::Section::Table:
+ readFunctionTableDeclaration();
+ break;
default: {
readUserSection(payloadLen);
if (pos > oldPos + payloadLen) {
- throwError("bad user section size, started at " + std::to_string(oldPos) + " plus payload " + std::to_string(payloadLen) + " not being equal to new position " + std::to_string(pos));
+ throwError("bad user section size, started at " +
+ std::to_string(oldPos) + " plus payload " +
+ std::to_string(payloadLen) +
+ " not being equal to new position " + std::to_string(pos));
}
pos = oldPos + payloadLen;
}
@@ -680,7 +799,9 @@ void WasmBinaryBuilder::read() {
// make sure we advanced exactly past this section
if (pos != oldPos + payloadLen) {
- throwError("bad section size, started at " + std::to_string(oldPos) + " plus payload " + std::to_string(payloadLen) + " not being equal to new position " + std::to_string(pos));
+ throwError("bad section size, started at " + std::to_string(oldPos) +
+ " plus payload " + std::to_string(payloadLen) +
+ " not being equal to new position " + std::to_string(pos));
}
}
@@ -703,7 +824,9 @@ void WasmBinaryBuilder::readUserSection(size_t payloadLen) {
} else {
// an unfamiliar custom section
if (sectionName.equals(BinaryConsts::UserSections::Linking)) {
- std::cerr << "warning: linking section is present, so this is not a standard wasm file - binaryen cannot handle this properly!\n";
+ std::cerr
+ << "warning: linking section is present, so this is not a standard "
+ "wasm file - binaryen cannot handle this properly!\n";
}
wasm.userSections.resize(wasm.userSections.size() + 1);
auto& section = wasm.userSections.back();
@@ -717,107 +840,129 @@ void WasmBinaryBuilder::readUserSection(size_t payloadLen) {
}
uint8_t WasmBinaryBuilder::getInt8() {
- if (!more()) throwError("unexpected end of input");
- if (debug) std::cerr << "getInt8: " << (int)(uint8_t)input[pos] << " (at " << pos << ")" << std::endl;
+ if (!more())
+ throwError("unexpected end of input");
+ if (debug)
+ std::cerr << "getInt8: " << (int)(uint8_t)input[pos] << " (at " << pos
+ << ")" << std::endl;
return input[pos++];
}
uint16_t WasmBinaryBuilder::getInt16() {
- if (debug) std::cerr << "<==" << std::endl;
+ if (debug)
+ std::cerr << "<==" << std::endl;
auto ret = uint16_t(getInt8());
ret |= uint16_t(getInt8()) << 8;
- if (debug) std::cerr << "getInt16: " << ret << "/0x" << std::hex << ret << std::dec << " ==>" << std::endl;
+ if (debug)
+ std::cerr << "getInt16: " << ret << "/0x" << std::hex << ret << std::dec
+ << " ==>" << std::endl;
return ret;
}
uint32_t WasmBinaryBuilder::getInt32() {
- if (debug) std::cerr << "<==" << std::endl;
+ if (debug)
+ std::cerr << "<==" << std::endl;
auto ret = uint32_t(getInt16());
ret |= uint32_t(getInt16()) << 16;
- if (debug) std::cerr << "getInt32: " << ret << "/0x" << std::hex << ret << std::dec <<" ==>" << std::endl;
+ if (debug)
+ std::cerr << "getInt32: " << ret << "/0x" << std::hex << ret << std::dec
+ << " ==>" << std::endl;
return ret;
}
uint64_t WasmBinaryBuilder::getInt64() {
- if (debug) std::cerr << "<==" << std::endl;
+ if (debug)
+ std::cerr << "<==" << std::endl;
auto ret = uint64_t(getInt32());
ret |= uint64_t(getInt32()) << 32;
- if (debug) std::cerr << "getInt64: " << ret << "/0x" << std::hex << ret << std::dec << " ==>" << std::endl;
+ if (debug)
+ std::cerr << "getInt64: " << ret << "/0x" << std::hex << ret << std::dec
+ << " ==>" << std::endl;
return ret;
}
uint8_t WasmBinaryBuilder::getLaneIndex(size_t lanes) {
- if (debug) std::cerr << "<==" << std::endl;
+ if (debug)
+ std::cerr << "<==" << std::endl;
auto ret = getInt8();
- if (ret >= lanes) throwError("Illegal lane index");
- if (debug) std::cerr << "getLaneIndex(" << lanes << "): " << ret << " ==>" << std::endl;
+ if (ret >= lanes)
+ throwError("Illegal lane index");
+ if (debug)
+ std::cerr << "getLaneIndex(" << lanes << "): " << ret << " ==>"
+ << std::endl;
return ret;
}
Literal WasmBinaryBuilder::getFloat32Literal() {
- if (debug) std::cerr << "<==" << std::endl;
+ if (debug)
+ std::cerr << "<==" << std::endl;
auto ret = Literal(getInt32());
ret = ret.castToF32();
- if (debug) std::cerr << "getFloat32: " << ret << " ==>" << std::endl;
+ if (debug)
+ std::cerr << "getFloat32: " << ret << " ==>" << std::endl;
return ret;
}
Literal WasmBinaryBuilder::getFloat64Literal() {
- if (debug) std::cerr << "<==" << std::endl;
+ if (debug)
+ std::cerr << "<==" << std::endl;
auto ret = Literal(getInt64());
ret = ret.castToF64();
- if (debug) std::cerr << "getFloat64: " << ret << " ==>" << std::endl;
+ if (debug)
+ std::cerr << "getFloat64: " << ret << " ==>" << std::endl;
return ret;
}
Literal WasmBinaryBuilder::getVec128Literal() {
- if (debug) std::cerr << "<==" << std::endl;
+ if (debug)
+ std::cerr << "<==" << std::endl;
std::array<uint8_t, 16> bytes;
for (auto i = 0; i < 16; ++i) {
bytes[i] = getInt8();
}
auto ret = Literal(bytes.data());
- if (debug) std::cerr << "getVec128: " << ret << " ==>" << std::endl;
+ if (debug)
+ std::cerr << "getVec128: " << ret << " ==>" << std::endl;
return ret;
}
uint32_t WasmBinaryBuilder::getU32LEB() {
- if (debug) std::cerr << "<==" << std::endl;
+ if (debug)
+ std::cerr << "<==" << std::endl;
U32LEB ret;
- ret.read([&]() {
- return getInt8();
- });
- if (debug) std::cerr << "getU32LEB: " << ret.value << " ==>" << std::endl;
+ ret.read([&]() { return getInt8(); });
+ if (debug)
+ std::cerr << "getU32LEB: " << ret.value << " ==>" << std::endl;
return ret.value;
}
uint64_t WasmBinaryBuilder::getU64LEB() {
- if (debug) std::cerr << "<==" << std::endl;
+ if (debug)
+ std::cerr << "<==" << std::endl;
U64LEB ret;
- ret.read([&]() {
- return getInt8();
- });
- if (debug) std::cerr << "getU64LEB: " << ret.value << " ==>" << std::endl;
+ ret.read([&]() { return getInt8(); });
+ if (debug)
+ std::cerr << "getU64LEB: " << ret.value << " ==>" << std::endl;
return ret.value;
}
int32_t WasmBinaryBuilder::getS32LEB() {
- if (debug) std::cerr << "<==" << std::endl;
+ if (debug)
+ std::cerr << "<==" << std::endl;
S32LEB ret;
- ret.read([&]() {
- return (int8_t)getInt8();
- });
- if (debug) std::cerr << "getS32LEB: " << ret.value << " ==>" << std::endl;
+ ret.read([&]() { return (int8_t)getInt8(); });
+ if (debug)
+ std::cerr << "getS32LEB: " << ret.value << " ==>" << std::endl;
return ret.value;
}
int64_t WasmBinaryBuilder::getS64LEB() {
- if (debug) std::cerr << "<==" << std::endl;
+ if (debug)
+ std::cerr << "<==" << std::endl;
S64LEB ret;
- ret.read([&]() {
- return (int8_t)getInt8();
- });
- if (debug) std::cerr << "getS64LEB: " << ret.value << " ==>" << std::endl;
+ ret.read([&]() { return (int8_t)getInt8(); });
+ if (debug)
+ std::cerr << "getS64LEB: " << ret.value << " ==>" << std::endl;
return ret.value;
}
@@ -825,15 +970,19 @@ Type WasmBinaryBuilder::getType() {
int type = getS32LEB();
switch (type) {
// None only used for block signatures. TODO: Separate out?
- case BinaryConsts::EncodedType::Empty: return none;
- case BinaryConsts::EncodedType::i32: return i32;
- case BinaryConsts::EncodedType::i64: return i64;
- case BinaryConsts::EncodedType::f32: return f32;
- case BinaryConsts::EncodedType::f64: return f64;
- case BinaryConsts::EncodedType::v128: return v128;
- default: {
- throwError("invalid wasm type: " + std::to_string(type));
- }
+ case BinaryConsts::EncodedType::Empty:
+ return none;
+ case BinaryConsts::EncodedType::i32:
+ return i32;
+ case BinaryConsts::EncodedType::i64:
+ return i64;
+ case BinaryConsts::EncodedType::f32:
+ return f32;
+ case BinaryConsts::EncodedType::f64:
+ return f64;
+ case BinaryConsts::EncodedType::v128:
+ return v128;
+ default: { throwError("invalid wasm type: " + std::to_string(type)); }
}
WASM_UNREACHABLE();
}
@@ -847,61 +996,74 @@ Type WasmBinaryBuilder::getConcreteType() {
}
Name WasmBinaryBuilder::getInlineString() {
- if (debug) std::cerr << "<==" << std::endl;
+ if (debug)
+ std::cerr << "<==" << std::endl;
auto len = getU32LEB();
std::string str;
for (size_t i = 0; i < len; i++) {
auto curr = char(getInt8());
if (curr == 0) {
- throwError("inline string contains NULL (0). that is technically valid in wasm, but you shouldn't do it, and it's not supported in binaryen");
+ throwError(
+ "inline string contains NULL (0). that is technically valid in wasm, "
+ "but you shouldn't do it, and it's not supported in binaryen");
}
str = str + curr;
}
- if (debug) std::cerr << "getInlineString: " << str << " ==>" << std::endl;
+ if (debug)
+ std::cerr << "getInlineString: " << str << " ==>" << std::endl;
return Name(str);
}
void WasmBinaryBuilder::verifyInt8(int8_t x) {
int8_t y = getInt8();
- if (x != y) throwError("surprising value");
+ if (x != y)
+ throwError("surprising value");
}
void WasmBinaryBuilder::verifyInt16(int16_t x) {
int16_t y = getInt16();
- if (x != y) throwError("surprising value");
+ if (x != y)
+ throwError("surprising value");
}
void WasmBinaryBuilder::verifyInt32(int32_t x) {
int32_t y = getInt32();
- if (x != y) throwError("surprising value");
+ if (x != y)
+ throwError("surprising value");
}
void WasmBinaryBuilder::verifyInt64(int64_t x) {
int64_t y = getInt64();
- if (x != y) throwError("surprising value");
+ if (x != y)
+ throwError("surprising value");
}
void WasmBinaryBuilder::ungetInt8() {
assert(pos > 0);
- if (debug) std::cerr << "ungetInt8 (at " << pos << ")" << std::endl;
+ if (debug)
+ std::cerr << "ungetInt8 (at " << pos << ")" << std::endl;
pos--;
}
void WasmBinaryBuilder::readHeader() {
- if (debug) std::cerr << "== readHeader" << std::endl;
+ if (debug)
+ std::cerr << "== readHeader" << std::endl;
verifyInt32(BinaryConsts::Magic);
verifyInt32(BinaryConsts::Version);
}
void WasmBinaryBuilder::readStart() {
- if (debug) std::cerr << "== readStart" << std::endl;
+ if (debug)
+ std::cerr << "== readStart" << std::endl;
startIndex = getU32LEB();
}
void WasmBinaryBuilder::readMemory() {
- if (debug) std::cerr << "== readMemory" << std::endl;
+ if (debug)
+ std::cerr << "== readMemory" << std::endl;
auto numMemories = getU32LEB();
- if (!numMemories) return;
+ if (!numMemories)
+ return;
if (numMemories != 1) {
throwError("Must be exactly 1 memory");
}
@@ -909,22 +1071,29 @@ void WasmBinaryBuilder::readMemory() {
throwError("Memory cannot be both imported and defined");
}
wasm.memory.exists = true;
- getResizableLimits(wasm.memory.initial, wasm.memory.max, wasm.memory.shared, Memory::kUnlimitedSize);
+ getResizableLimits(wasm.memory.initial,
+ wasm.memory.max,
+ wasm.memory.shared,
+ Memory::kUnlimitedSize);
}
void WasmBinaryBuilder::readSignatures() {
- if (debug) std::cerr << "== readSignatures" << std::endl;
+ if (debug)
+ std::cerr << "== readSignatures" << std::endl;
size_t numTypes = getU32LEB();
- if (debug) std::cerr << "num: " << numTypes << std::endl;
+ if (debug)
+ std::cerr << "num: " << numTypes << std::endl;
for (size_t i = 0; i < numTypes; i++) {
- if (debug) std::cerr << "read one" << std::endl;
+ if (debug)
+ std::cerr << "read one" << std::endl;
auto curr = make_unique<FunctionType>();
auto form = getS32LEB();
if (form != BinaryConsts::EncodedType::Func) {
throwError("bad signature form " + std::to_string(form));
}
size_t numParams = getU32LEB();
- if (debug) std::cerr << "num params: " << numParams << std::endl;
+ if (debug)
+ std::cerr << "num params: " << numParams << std::endl;
for (size_t j = 0; j < numParams; j++) {
curr->params.push_back(getConcreteType());
}
@@ -949,36 +1118,46 @@ Name WasmBinaryBuilder::getFunctionIndexName(Index i) {
return wasm.functions[i]->name;
}
-void WasmBinaryBuilder::getResizableLimits(Address& initial, Address& max, bool &shared, Address defaultIfNoMax) {
+void WasmBinaryBuilder::getResizableLimits(Address& initial,
+ Address& max,
+ bool& shared,
+ Address defaultIfNoMax) {
auto flags = getU32LEB();
initial = getU32LEB();
bool hasMax = (flags & BinaryConsts::HasMaximum) != 0;
bool isShared = (flags & BinaryConsts::IsShared) != 0;
- if (isShared && !hasMax) throwError("shared memory must have max size");
+ if (isShared && !hasMax)
+ throwError("shared memory must have max size");
shared = isShared;
- if (hasMax) max = getU32LEB();
- else max = defaultIfNoMax;
+ if (hasMax)
+ max = getU32LEB();
+ else
+ max = defaultIfNoMax;
}
void WasmBinaryBuilder::readImports() {
- if (debug) std::cerr << "== readImports" << std::endl;
+ if (debug)
+ std::cerr << "== readImports" << std::endl;
size_t num = getU32LEB();
- if (debug) std::cerr << "num: " << num << std::endl;
+ if (debug)
+ std::cerr << "num: " << num << std::endl;
Builder builder(wasm);
for (size_t i = 0; i < num; i++) {
- if (debug) std::cerr << "read one" << std::endl;
+ if (debug)
+ std::cerr << "read one" << std::endl;
auto module = getInlineString();
auto base = getInlineString();
auto kind = (ExternalKind)getU32LEB();
- // We set a unique prefix for the name based on the kind. This ensures no collisions
- // between them, which can't occur here (due to the index i) but could occur later
- // due to the names section.
+ // We set a unique prefix for the name based on the kind. This ensures no
+ // collisions between them, which can't occur here (due to the index i) but
+ // could occur later due to the names section.
switch (kind) {
case ExternalKind::Function: {
auto name = Name(std::string("fimport$") + std::to_string(i));
auto index = getU32LEB();
if (index >= wasm.functionTypes.size()) {
- throwError("invalid function index " + std::to_string(index) + " / " + std::to_string(wasm.functionTypes.size()));
+ throwError("invalid function index " + std::to_string(index) + " / " +
+ std::to_string(wasm.functionTypes.size()));
}
auto* functionType = wasm.functionTypes[index].get();
auto params = functionType->params;
@@ -997,11 +1176,14 @@ void WasmBinaryBuilder::readImports() {
wasm.table.name = Name(std::string("timport$") + std::to_string(i));
auto elementType = getS32LEB();
WASM_UNUSED(elementType);
- if (elementType != BinaryConsts::EncodedType::AnyFunc) throwError("Imported table type is not AnyFunc");
+ if (elementType != BinaryConsts::EncodedType::AnyFunc)
+ throwError("Imported table type is not AnyFunc");
wasm.table.exists = true;
bool is_shared;
- getResizableLimits(wasm.table.initial, wasm.table.max, is_shared, Table::kUnlimitedSize);
- if (is_shared) throwError("Tables may not be shared");
+ getResizableLimits(
+ wasm.table.initial, wasm.table.max, is_shared, Table::kUnlimitedSize);
+ if (is_shared)
+ throwError("Tables may not be shared");
break;
}
case ExternalKind::Memory: {
@@ -1009,22 +1191,27 @@ void WasmBinaryBuilder::readImports() {
wasm.memory.base = base;
wasm.memory.name = Name(std::to_string(i));
wasm.memory.exists = true;
- getResizableLimits(wasm.memory.initial, wasm.memory.max, wasm.memory.shared, Memory::kUnlimitedSize);
+ getResizableLimits(wasm.memory.initial,
+ wasm.memory.max,
+ wasm.memory.shared,
+ Memory::kUnlimitedSize);
break;
}
case ExternalKind::Global: {
auto name = Name(std::string("gimport$") + std::to_string(i));
auto type = getConcreteType();
auto mutable_ = getU32LEB();
- auto* curr = builder.makeGlobal(name, type, nullptr, mutable_ ? Builder::Mutable : Builder::Immutable);
+ auto* curr =
+ builder.makeGlobal(name,
+ type,
+ nullptr,
+ mutable_ ? Builder::Mutable : Builder::Immutable);
curr->module = module;
curr->base = base;
wasm.addGlobal(curr);
break;
}
- default: {
- throwError("bad import kind");
- }
+ default: { throwError("bad import kind"); }
}
}
}
@@ -1041,11 +1228,14 @@ void WasmBinaryBuilder::requireFunctionContext(const char* error) {
}
void WasmBinaryBuilder::readFunctionSignatures() {
- if (debug) std::cerr << "== readFunctionSignatures" << std::endl;
+ if (debug)
+ std::cerr << "== readFunctionSignatures" << std::endl;
size_t num = getU32LEB();
- if (debug) std::cerr << "num: " << num << std::endl;
+ if (debug)
+ std::cerr << "num: " << num << std::endl;
for (size_t i = 0; i < num; i++) {
- if (debug) std::cerr << "read one" << std::endl;
+ if (debug)
+ std::cerr << "read one" << std::endl;
auto index = getU32LEB();
if (index >= wasm.functionTypes.size()) {
throwError("invalid function type index for function");
@@ -1055,27 +1245,30 @@ void WasmBinaryBuilder::readFunctionSignatures() {
}
void WasmBinaryBuilder::readFunctions() {
- if (debug) std::cerr << "== readFunctions" << std::endl;
+ if (debug)
+ std::cerr << "== readFunctions" << std::endl;
size_t total = getU32LEB();
if (total != functionTypes.size()) {
throwError("invalid function section size, must equal types");
}
for (size_t i = 0; i < total; i++) {
- if (debug) std::cerr << "read one at " << pos << std::endl;
+ if (debug)
+ std::cerr << "read one at " << pos << std::endl;
size_t size = getU32LEB();
if (size == 0) {
throwError("empty function size");
}
endOfFunction = pos + size;
- Function *func = new Function;
+ Function* func = new Function;
func->name = Name::fromInt(i);
currFunction = func;
readNextDebugLocation();
auto type = functionTypes[i];
- if (debug) std::cerr << "reading " << i << std::endl;
+ if (debug)
+ std::cerr << "reading " << i << std::endl;
func->type = type->name;
func->result = type->result;
for (size_t j = 0; j < type->params.size(); j++) {
@@ -1093,7 +1286,8 @@ void WasmBinaryBuilder::readFunctions() {
std::swap(func->prologLocation, debugLocation);
{
// process the function body
- if (debug) std::cerr << "processing function: " << i << std::endl;
+ if (debug)
+ std::cerr << "processing function: " << i << std::endl;
nextLabel = 0;
debugLocation.clear();
willBeIgnored = false;
@@ -1118,16 +1312,20 @@ void WasmBinaryBuilder::readFunctions() {
debugLocation.clear();
functions.push_back(func);
}
- if (debug) std::cerr << " end function bodies" << std::endl;
+ if (debug)
+ std::cerr << " end function bodies" << std::endl;
}
void WasmBinaryBuilder::readExports() {
- if (debug) std::cerr << "== readExports" << std::endl;
+ if (debug)
+ std::cerr << "== readExports" << std::endl;
size_t num = getU32LEB();
- if (debug) std::cerr << "num: " << num << std::endl;
+ if (debug)
+ std::cerr << "num: " << num << std::endl;
std::set<Name> names;
for (size_t i = 0; i < num; i++) {
- if (debug) std::cerr << "read one" << std::endl;
+ if (debug)
+ std::cerr << "read one" << std::endl;
auto curr = new Export;
curr->name = getInlineString();
if (names.count(curr->name) > 0) {
@@ -1154,11 +1352,12 @@ static int32_t readBase64VLQ(std::istream& in) {
value |= digit << shift;
break;
}
- if (!(ch >= 'g' && ch <= 'z') && !(ch >= '0' && ch <= '9') &&
- ch != '+' && ch != '/') {
+ if (!(ch >= 'g' && ch <= 'z') && !(ch >= '0' && ch <= '9') && ch != '+' &&
+ ch != '/') {
throw MapParseException("invalid VLQ digit");
}
- uint32_t digit = ch > '9' ? ch - 'g' : (ch >= '0' ? ch - '0' + 20 : (ch == '+' ? 30 : 31));
+ uint32_t digit =
+ ch > '9' ? ch - 'g' : (ch >= '0' ? ch - '0' + 20 : (ch == '+' ? 30 : 31));
value |= digit << shift;
shift += 5;
}
@@ -1166,7 +1365,8 @@ static int32_t readBase64VLQ(std::istream& in) {
}
void WasmBinaryBuilder::readSourceMapHeader() {
- if (!sourceMap) return;
+ if (!sourceMap)
+ return;
auto skipWhitespace = [&]() {
while (sourceMap->peek() == ' ' || sourceMap->peek() == '\n')
@@ -1174,7 +1374,8 @@ void WasmBinaryBuilder::readSourceMapHeader() {
};
auto maybeReadChar = [&](char expected) {
- if (sourceMap->peek() != expected) return false;
+ if (sourceMap->peek() != expected)
+ return false;
sourceMap->get();
return true;
};
@@ -1193,7 +1394,8 @@ void WasmBinaryBuilder::readSourceMapHeader() {
size_t pos;
while (1) {
int ch = sourceMap->get();
- if (ch == EOF) return false;
+ if (ch == EOF)
+ return false;
if (ch == '\"') {
if (matching) {
// we matched a terminating quote.
@@ -1226,7 +1428,8 @@ void WasmBinaryBuilder::readSourceMapHeader() {
if (ch == EOF) {
throw MapParseException("unexpected EOF in the middle of string");
}
- if (ch == '\"') break;
+ if (ch == '\"')
+ break;
vec.push_back(ch);
}
}
@@ -1263,13 +1466,15 @@ void WasmBinaryBuilder::readSourceMapHeader() {
// read first debug location
uint32_t position = readBase64VLQ(*sourceMap);
uint32_t fileIndex = readBase64VLQ(*sourceMap);
- uint32_t lineNumber = readBase64VLQ(*sourceMap) + 1; // adjust zero-based line number
+ uint32_t lineNumber =
+ readBase64VLQ(*sourceMap) + 1; // adjust zero-based line number
uint32_t columnNumber = readBase64VLQ(*sourceMap);
- nextDebugLocation = { position, { fileIndex, lineNumber, columnNumber } };
+ nextDebugLocation = {position, {fileIndex, lineNumber, columnNumber}};
}
void WasmBinaryBuilder::readNextDebugLocation() {
- if (!sourceMap) return;
+ if (!sourceMap)
+ return;
while (nextDebugLocation.first && nextDebugLocation.first <= pos) {
if (nextDebugLocation.first < pos) {
@@ -1299,9 +1504,10 @@ void WasmBinaryBuilder::readNextDebugLocation() {
int32_t lineNumberDelta = readBase64VLQ(*sourceMap);
uint32_t lineNumber = nextDebugLocation.second.lineNumber + lineNumberDelta;
int32_t columnNumberDelta = readBase64VLQ(*sourceMap);
- uint32_t columnNumber = nextDebugLocation.second.columnNumber + columnNumberDelta;
+ uint32_t columnNumber =
+ nextDebugLocation.second.columnNumber + columnNumberDelta;
- nextDebugLocation = { position, { fileIndex, lineNumber, columnNumber } };
+ nextDebugLocation = {position, {fileIndex, lineNumber, columnNumber}};
}
}
@@ -1317,33 +1523,38 @@ Expression* WasmBinaryBuilder::readExpression() {
}
void WasmBinaryBuilder::readGlobals() {
- if (debug) std::cerr << "== readGlobals" << std::endl;
+ if (debug)
+ std::cerr << "== readGlobals" << std::endl;
size_t num = getU32LEB();
- if (debug) std::cerr << "num: " << num << std::endl;
+ if (debug)
+ std::cerr << "num: " << num << std::endl;
for (size_t i = 0; i < num; i++) {
- if (debug) std::cerr << "read one" << std::endl;
+ if (debug)
+ std::cerr << "read one" << std::endl;
auto type = getConcreteType();
auto mutable_ = getU32LEB();
- if (mutable_ & ~1) throwError("Global mutability must be 0 or 1");
+ if (mutable_ & ~1)
+ throwError("Global mutability must be 0 or 1");
auto* init = readExpression();
- wasm.addGlobal(Builder::makeGlobal(
- "global$" + std::to_string(i),
- type,
- init,
- mutable_ ? Builder::Mutable : Builder::Immutable
- ));
+ wasm.addGlobal(
+ Builder::makeGlobal("global$" + std::to_string(i),
+ type,
+ init,
+ mutable_ ? Builder::Mutable : Builder::Immutable));
}
}
void WasmBinaryBuilder::processExpressions() {
- if (debug) std::cerr << "== processExpressions" << std::endl;
+ if (debug)
+ std::cerr << "== processExpressions" << std::endl;
unreachableInTheWasmSense = false;
while (1) {
Expression* curr;
auto ret = readExpression(curr);
if (!curr) {
lastSeparator = ret;
- if (debug) std::cerr << "== processExpressions finished" << std::endl;
+ if (debug)
+ std::cerr << "== processExpressions finished" << std::endl;
return;
}
expressionStack.push_back(curr);
@@ -1351,15 +1562,18 @@ void WasmBinaryBuilder::processExpressions() {
// once we see something unreachable, we don't want to add anything else
// to the stack, as it could be stacky code that is non-representable in
// our AST. but we do need to skip it
- // if there is nothing else here, just stop. otherwise, go into unreachable
- // mode. peek to see what to do
+ // if there is nothing else here, just stop. otherwise, go into
+ // unreachable mode. peek to see what to do
if (pos == endOfFunction) {
throwError("Reached function end without seeing End opcode");
}
- if (!more()) throwError("unexpected end of input");
+ if (!more())
+ throwError("unexpected end of input");
auto peek = input[pos];
if (peek == BinaryConsts::End || peek == BinaryConsts::Else) {
- if (debug) std::cerr << "== processExpressions finished with unreachable" << std::endl;
+ if (debug)
+ std::cerr << "== processExpressions finished with unreachable"
+ << std::endl;
readNextDebugLocation();
lastSeparator = BinaryConsts::ASTNodes(peek);
pos++;
@@ -1373,10 +1587,11 @@ void WasmBinaryBuilder::processExpressions() {
}
void WasmBinaryBuilder::skipUnreachableCode() {
- if (debug) std::cerr << "== skipUnreachableCode" << std::endl;
- // preserve the stack, and restore it. it contains the instruction that made us
- // unreachable, and we can ignore anything after it. things after it may pop,
- // we want to undo that
+ if (debug)
+ std::cerr << "== skipUnreachableCode" << std::endl;
+ // preserve the stack, and restore it. it contains the instruction that made
+ // us unreachable, and we can ignore anything after it. things after it may
+ // pop, we want to undo that
auto savedStack = expressionStack;
// note we are entering unreachable code, and note what the state as before so
// we can restore it
@@ -1387,12 +1602,14 @@ void WasmBinaryBuilder::skipUnreachableCode() {
// result in uneachables being returned
expressionStack.clear();
while (1) {
- // set the unreachableInTheWasmSense flag each time, as sub-blocks may set and unset it
+ // set the unreachableInTheWasmSense flag each time, as sub-blocks may set
+ // and unset it
unreachableInTheWasmSense = true;
Expression* curr;
auto ret = readExpression(curr);
if (!curr) {
- if (debug) std::cerr << "== skipUnreachableCode finished" << std::endl;
+ if (debug)
+ std::cerr << "== skipUnreachableCode finished" << std::endl;
lastSeparator = ret;
unreachableInTheWasmSense = false;
willBeIgnored = before;
@@ -1404,15 +1621,20 @@ void WasmBinaryBuilder::skipUnreachableCode() {
}
Expression* WasmBinaryBuilder::popExpression() {
- if (debug) std::cerr << "== popExpression" << std::endl;
+ if (debug)
+ std::cerr << "== popExpression" << std::endl;
if (expressionStack.empty()) {
if (unreachableInTheWasmSense) {
// in unreachable code, trying to pop past the polymorphic stack
// area results in receiving unreachables
- if (debug) std::cerr << "== popping unreachable from polymorphic stack" << std::endl;
+ if (debug)
+ std::cerr << "== popping unreachable from polymorphic stack"
+ << std::endl;
return allocator.alloc<Unreachable>();
}
- throwError("attempted pop from empty stack / beyond block start boundary at " + std::to_string(pos));
+ throwError(
+ "attempted pop from empty stack / beyond block start boundary at " +
+ std::to_string(pos));
}
// the stack is not empty, and we would not be going out of the current block
auto ret = expressionStack.back();
@@ -1422,7 +1644,8 @@ Expression* WasmBinaryBuilder::popExpression() {
Expression* WasmBinaryBuilder::popNonVoidExpression() {
auto* ret = popExpression();
- if (ret->type != none) return ret;
+ if (ret->type != none)
+ return ret;
// we found a void, so this is stacky code that we must handle carefully
Builder builder(wasm);
// add elements until we find a non-void
@@ -1431,7 +1654,8 @@ Expression* WasmBinaryBuilder::popNonVoidExpression() {
while (1) {
auto* curr = popExpression();
expressions.push_back(curr);
- if (curr->type != none) break;
+ if (curr->type != none)
+ break;
}
auto* block = builder.makeBlock();
while (!expressions.empty()) {
@@ -1462,7 +1686,8 @@ Name WasmBinaryBuilder::getGlobalName(Index index) {
ModuleUtils::iterImportedGlobals(wasm, add);
ModuleUtils::iterDefinedGlobals(wasm, add);
}
- if (index == Index(-1)) return Name("null"); // just a force-rebuild
+ if (index == Index(-1))
+ return Name("null"); // just a force-rebuild
if (mappedGlobals.count(index) == 0) {
throwError("bad global index");
}
@@ -1493,10 +1718,17 @@ void WasmBinaryBuilder::processFunctions() {
curr->value = getFunctionIndexName(index);
break;
}
- case ExternalKind::Table: curr->value = Name::fromInt(0); break;
- case ExternalKind::Memory: curr->value = Name::fromInt(0); break;
- case ExternalKind::Global: curr->value = getGlobalName(index); break;
- default: throwError("bad export kind");
+ case ExternalKind::Table:
+ curr->value = Name::fromInt(0);
+ break;
+ case ExternalKind::Memory:
+ curr->value = Name::fromInt(0);
+ break;
+ case ExternalKind::Global:
+ curr->value = getGlobalName(index);
+ break;
+ default:
+ throwError("bad export kind");
}
wasm.addExport(curr);
}
@@ -1523,13 +1755,15 @@ void WasmBinaryBuilder::processFunctions() {
}
void WasmBinaryBuilder::readDataCount() {
- if (debug) std::cerr << "== readDataCount" << std::endl;
+ if (debug)
+ std::cerr << "== readDataCount" << std::endl;
hasDataCount = true;
dataCount = getU32LEB();
}
void WasmBinaryBuilder::readDataSegments() {
- if (debug) std::cerr << "== readDataSegments" << std::endl;
+ if (debug)
+ std::cerr << "== readDataSegments" << std::endl;
auto num = getU32LEB();
for (size_t i = 0; i < num; i++) {
Memory::Segment curr;
@@ -1558,25 +1792,34 @@ void WasmBinaryBuilder::readDataSegments() {
}
void WasmBinaryBuilder::readFunctionTableDeclaration() {
- if (debug) std::cerr << "== readFunctionTableDeclaration" << std::endl;
+ if (debug)
+ std::cerr << "== readFunctionTableDeclaration" << std::endl;
auto numTables = getU32LEB();
- if (numTables != 1) throwError("Only 1 table definition allowed in MVP");
- if (wasm.table.exists) throwError("Table cannot be both imported and defined");
+ if (numTables != 1)
+ throwError("Only 1 table definition allowed in MVP");
+ if (wasm.table.exists)
+ throwError("Table cannot be both imported and defined");
wasm.table.exists = true;
auto elemType = getS32LEB();
- if (elemType != BinaryConsts::EncodedType::AnyFunc) throwError("ElementType must be AnyFunc in MVP");
+ if (elemType != BinaryConsts::EncodedType::AnyFunc)
+ throwError("ElementType must be AnyFunc in MVP");
bool is_shared;
- getResizableLimits(wasm.table.initial, wasm.table.max, is_shared, Table::kUnlimitedSize);
- if (is_shared) throwError("Tables may not be shared");
+ getResizableLimits(
+ wasm.table.initial, wasm.table.max, is_shared, Table::kUnlimitedSize);
+ if (is_shared)
+ throwError("Tables may not be shared");
}
void WasmBinaryBuilder::readTableElements() {
- if (debug) std::cerr << "== readTableElements" << std::endl;
+ if (debug)
+ std::cerr << "== readTableElements" << std::endl;
auto numSegments = getU32LEB();
- if (numSegments >= Table::kMaxSize) throwError("Too many segments");
+ if (numSegments >= Table::kMaxSize)
+ throwError("Too many segments");
for (size_t i = 0; i < numSegments; i++) {
auto tableIndex = getU32LEB();
- if (tableIndex != 0) throwError("Table elements must refer to table 0 in MVP");
+ if (tableIndex != 0)
+ throwError("Table elements must refer to table 0 in MVP");
wasm.table.segments.emplace_back(readExpression());
auto& indexSegment = functionTable[i];
@@ -1588,20 +1831,21 @@ void WasmBinaryBuilder::readTableElements() {
}
static bool isIdChar(char ch) {
- return (ch >= '0' && ch <= '9') || (ch >= 'A' && ch <= 'Z') || (ch >= 'a' && ch <= 'z') ||
- ch == '!' || ch == '#' || ch == '$' || ch == '%' || ch == '&' || ch == '\'' || ch == '*' ||
- ch == '+' || ch == '-' || ch == '.' || ch == '/' || ch == ':' || ch == '<' || ch == '=' ||
- ch == '>' || ch == '?' || ch == '@' || ch == '^' || ch == '_' || ch == '`' || ch == '|' ||
- ch == '~';
+ return (ch >= '0' && ch <= '9') || (ch >= 'A' && ch <= 'Z') ||
+ (ch >= 'a' && ch <= 'z') || ch == '!' || ch == '#' || ch == '$' ||
+ ch == '%' || ch == '&' || ch == '\'' || ch == '*' || ch == '+' ||
+ ch == '-' || ch == '.' || ch == '/' || ch == ':' || ch == '<' ||
+ ch == '=' || ch == '>' || ch == '?' || ch == '@' || ch == '^' ||
+ ch == '_' || ch == '`' || ch == '|' || ch == '~';
}
static char formatNibble(int nibble) {
return nibble < 10 ? '0' + nibble : 'a' - 10 + nibble;
}
-static void escapeName(Name &name) {
+static void escapeName(Name& name) {
bool allIdChars = true;
- for (const char *p = name.str; allIdChars && *p; p++) {
+ for (const char* p = name.str; allIdChars && *p; p++) {
allIdChars = isIdChar(*p);
}
if (allIdChars) {
@@ -1609,7 +1853,7 @@ static void escapeName(Name &name) {
}
// encode name, if at least one non-idchar (per WebAssembly spec) was found
std::string escaped;
- for (const char *p = name.str; *p; p++) {
+ for (const char* p = name.str; *p; p++) {
char ch = *p;
if (isIdChar(ch)) {
escaped.push_back(ch);
@@ -1624,7 +1868,8 @@ static void escapeName(Name &name) {
}
void WasmBinaryBuilder::readNames(size_t payloadLen) {
- if (debug) std::cerr << "== readNames" << std::endl;
+ if (debug)
+ std::cerr << "== readNames" << std::endl;
auto sectionPos = pos;
while (pos < sectionPos + payloadLen) {
auto nameType = getU32LEB();
@@ -1713,79 +1958,146 @@ BinaryConsts::ASTNodes WasmBinaryBuilder::readExpression(Expression*& curr) {
if (pos == endOfFunction) {
throwError("Reached function end without seeing End opcode");
}
- if (debug) std::cerr << "zz recurse into " << ++depth << " at " << pos << std::endl;
+ if (debug)
+ std::cerr << "zz recurse into " << ++depth << " at " << pos << std::endl;
readNextDebugLocation();
std::set<Function::DebugLocation> currDebugLocation;
if (debugLocation.size()) {
currDebugLocation.insert(*debugLocation.begin());
}
uint8_t code = getInt8();
- if (debug) std::cerr << "readExpression seeing " << (int)code << std::endl;
+ if (debug)
+ std::cerr << "readExpression seeing " << (int)code << std::endl;
switch (code) {
- case BinaryConsts::Block: visitBlock((curr = allocator.alloc<Block>())->cast<Block>()); break;
- case BinaryConsts::If: visitIf((curr = allocator.alloc<If>())->cast<If>()); break;
- case BinaryConsts::Loop: visitLoop((curr = allocator.alloc<Loop>())->cast<Loop>()); break;
+ case BinaryConsts::Block:
+ visitBlock((curr = allocator.alloc<Block>())->cast<Block>());
+ break;
+ case BinaryConsts::If:
+ visitIf((curr = allocator.alloc<If>())->cast<If>());
+ break;
+ case BinaryConsts::Loop:
+ visitLoop((curr = allocator.alloc<Loop>())->cast<Loop>());
+ break;
case BinaryConsts::Br:
- case BinaryConsts::BrIf: visitBreak((curr = allocator.alloc<Break>())->cast<Break>(), code); break; // code distinguishes br from br_if
- case BinaryConsts::TableSwitch: visitSwitch((curr = allocator.alloc<Switch>())->cast<Switch>()); break;
- case BinaryConsts::CallFunction: visitCall((curr = allocator.alloc<Call>())->cast<Call>()); break;
- case BinaryConsts::CallIndirect: visitCallIndirect((curr = allocator.alloc<CallIndirect>())->cast<CallIndirect>()); break;
- case BinaryConsts::GetLocal: visitGetLocal((curr = allocator.alloc<GetLocal>())->cast<GetLocal>()); break;
+ case BinaryConsts::BrIf:
+ visitBreak((curr = allocator.alloc<Break>())->cast<Break>(), code);
+ break; // code distinguishes br from br_if
+ case BinaryConsts::TableSwitch:
+ visitSwitch((curr = allocator.alloc<Switch>())->cast<Switch>());
+ break;
+ case BinaryConsts::CallFunction:
+ visitCall((curr = allocator.alloc<Call>())->cast<Call>());
+ break;
+ case BinaryConsts::CallIndirect:
+ visitCallIndirect(
+ (curr = allocator.alloc<CallIndirect>())->cast<CallIndirect>());
+ break;
+ case BinaryConsts::GetLocal:
+ visitGetLocal((curr = allocator.alloc<GetLocal>())->cast<GetLocal>());
+ break;
case BinaryConsts::TeeLocal:
- case BinaryConsts::SetLocal: visitSetLocal((curr = allocator.alloc<SetLocal>())->cast<SetLocal>(), code); break;
- case BinaryConsts::GetGlobal: visitGetGlobal((curr = allocator.alloc<GetGlobal>())->cast<GetGlobal>()); break;
- case BinaryConsts::SetGlobal: visitSetGlobal((curr = allocator.alloc<SetGlobal>())->cast<SetGlobal>()); break;
- case BinaryConsts::Select: visitSelect((curr = allocator.alloc<Select>())->cast<Select>()); break;
- case BinaryConsts::Return: visitReturn((curr = allocator.alloc<Return>())->cast<Return>()); break;
- case BinaryConsts::Nop: visitNop((curr = allocator.alloc<Nop>())->cast<Nop>()); break;
- case BinaryConsts::Unreachable: visitUnreachable((curr = allocator.alloc<Unreachable>())->cast<Unreachable>()); break;
- case BinaryConsts::Drop: visitDrop((curr = allocator.alloc<Drop>())->cast<Drop>()); break;
+ case BinaryConsts::SetLocal:
+ visitSetLocal((curr = allocator.alloc<SetLocal>())->cast<SetLocal>(),
+ code);
+ break;
+ case BinaryConsts::GetGlobal:
+ visitGetGlobal((curr = allocator.alloc<GetGlobal>())->cast<GetGlobal>());
+ break;
+ case BinaryConsts::SetGlobal:
+ visitSetGlobal((curr = allocator.alloc<SetGlobal>())->cast<SetGlobal>());
+ break;
+ case BinaryConsts::Select:
+ visitSelect((curr = allocator.alloc<Select>())->cast<Select>());
+ break;
+ case BinaryConsts::Return:
+ visitReturn((curr = allocator.alloc<Return>())->cast<Return>());
+ break;
+ case BinaryConsts::Nop:
+ visitNop((curr = allocator.alloc<Nop>())->cast<Nop>());
+ break;
+ case BinaryConsts::Unreachable:
+ visitUnreachable(
+ (curr = allocator.alloc<Unreachable>())->cast<Unreachable>());
+ break;
+ case BinaryConsts::Drop:
+ visitDrop((curr = allocator.alloc<Drop>())->cast<Drop>());
+ break;
case BinaryConsts::End:
- case BinaryConsts::Else: curr = nullptr; break;
+ case BinaryConsts::Else:
+ curr = nullptr;
+ break;
case BinaryConsts::AtomicPrefix: {
code = static_cast<uint8_t>(getU32LEB());
- if (maybeVisitLoad(curr, code, /*isAtomic=*/true)) break;
- if (maybeVisitStore(curr, code, /*isAtomic=*/true)) break;
- if (maybeVisitAtomicRMW(curr, code)) break;
- if (maybeVisitAtomicCmpxchg(curr, code)) break;
- if (maybeVisitAtomicWait(curr, code)) break;
- if (maybeVisitAtomicNotify(curr, code)) break;
+ if (maybeVisitLoad(curr, code, /*isAtomic=*/true))
+ break;
+ if (maybeVisitStore(curr, code, /*isAtomic=*/true))
+ break;
+ if (maybeVisitAtomicRMW(curr, code))
+ break;
+ if (maybeVisitAtomicCmpxchg(curr, code))
+ break;
+ if (maybeVisitAtomicWait(curr, code))
+ break;
+ if (maybeVisitAtomicNotify(curr, code))
+ break;
throwError("invalid code after atomic prefix: " + std::to_string(code));
break;
}
case BinaryConsts::MiscPrefix: {
auto opcode = getU32LEB();
- if (maybeVisitTruncSat(curr, opcode)) break;
- if (maybeVisitMemoryInit(curr, opcode)) break;
- if (maybeVisitDataDrop(curr, opcode)) break;
- if (maybeVisitMemoryCopy(curr, opcode)) break;
- if (maybeVisitMemoryFill(curr, opcode)) break;
- throwError("invalid code after nontrapping float-to-int prefix: " + std::to_string(opcode));
+ if (maybeVisitTruncSat(curr, opcode))
+ break;
+ if (maybeVisitMemoryInit(curr, opcode))
+ break;
+ if (maybeVisitDataDrop(curr, opcode))
+ break;
+ if (maybeVisitMemoryCopy(curr, opcode))
+ break;
+ if (maybeVisitMemoryFill(curr, opcode))
+ break;
+ throwError("invalid code after nontrapping float-to-int prefix: " +
+ std::to_string(opcode));
break;
}
case BinaryConsts::SIMDPrefix: {
auto opcode = getU32LEB();
- if (maybeVisitSIMDBinary(curr, opcode)) break;
- if (maybeVisitSIMDUnary(curr, opcode)) break;
- if (maybeVisitSIMDConst(curr, opcode)) break;
- if (maybeVisitSIMDLoad(curr, opcode)) break;
- if (maybeVisitSIMDStore(curr, opcode)) break;
- if (maybeVisitSIMDExtract(curr, opcode)) break;
- if (maybeVisitSIMDReplace(curr, opcode)) break;
- if (maybeVisitSIMDShuffle(curr, opcode)) break;
- if (maybeVisitSIMDBitselect(curr, opcode)) break;
- if (maybeVisitSIMDShift(curr, opcode)) break;
+ if (maybeVisitSIMDBinary(curr, opcode))
+ break;
+ if (maybeVisitSIMDUnary(curr, opcode))
+ break;
+ if (maybeVisitSIMDConst(curr, opcode))
+ break;
+ if (maybeVisitSIMDLoad(curr, opcode))
+ break;
+ if (maybeVisitSIMDStore(curr, opcode))
+ break;
+ if (maybeVisitSIMDExtract(curr, opcode))
+ break;
+ if (maybeVisitSIMDReplace(curr, opcode))
+ break;
+ if (maybeVisitSIMDShuffle(curr, opcode))
+ break;
+ if (maybeVisitSIMDBitselect(curr, opcode))
+ break;
+ if (maybeVisitSIMDShift(curr, opcode))
+ break;
throwError("invalid code after SIMD prefix: " + std::to_string(opcode));
break;
}
default: {
// otherwise, the code is a subcode TODO: optimize
- if (maybeVisitBinary(curr, code)) break;
- if (maybeVisitUnary(curr, code)) break;
- if (maybeVisitConst(curr, code)) break;
- if (maybeVisitLoad(curr, code, /*isAtomic=*/false)) break;
- if (maybeVisitStore(curr, code, /*isAtomic=*/false)) break;
- if (maybeVisitHost(curr, code)) break;
+ if (maybeVisitBinary(curr, code))
+ break;
+ if (maybeVisitUnary(curr, code))
+ break;
+ if (maybeVisitConst(curr, code))
+ break;
+ if (maybeVisitLoad(curr, code, /*isAtomic=*/false))
+ break;
+ if (maybeVisitStore(curr, code, /*isAtomic=*/false))
+ break;
+ if (maybeVisitHost(curr, code))
+ break;
throwError("bad node code " + std::to_string(code));
break;
}
@@ -1793,26 +2105,31 @@ BinaryConsts::ASTNodes WasmBinaryBuilder::readExpression(Expression*& curr) {
if (curr && currDebugLocation.size()) {
currFunction->debugLocations[curr] = *currDebugLocation.begin();
}
- if (debug) std::cerr << "zz recurse from " << depth-- << " at " << pos << std::endl;
+ if (debug)
+ std::cerr << "zz recurse from " << depth-- << " at " << pos << std::endl;
return BinaryConsts::ASTNodes(code);
}
-void WasmBinaryBuilder::pushBlockElements(Block* curr, size_t start, size_t end) {
+void WasmBinaryBuilder::pushBlockElements(Block* curr,
+ size_t start,
+ size_t end) {
assert(start <= expressionStack.size());
assert(start <= end);
assert(end <= expressionStack.size());
- // the first dropped element may be consumed by code later - it was on the stack first,
- // and is the only thing left on the stack. there must be just one thing on the stack
- // since we are at the end of a block context. note that we may need to drop more than
- // one thing, since a bunch of concrete values may be all "consumed" by an unreachable
- // (in which case, the first value can't be consumed anyhow, so it doesn't matter)
+ // the first dropped element may be consumed by code later - it was on the
+ // stack first, and is the only thing left on the stack. there must be just
+ // one thing on the stack since we are at the end of a block context. note
+ // that we may need to drop more than one thing, since a bunch of concrete
+ // values may be all "consumed" by an unreachable (in which case, the first
+ // value can't be consumed anyhow, so it doesn't matter)
const Index NONE = -1;
Index consumable = NONE;
for (size_t i = start; i < end; i++) {
auto* item = expressionStack[i];
curr->list.push_back(item);
if (i < end - 1) {
- // stacky&unreachable code may introduce elements that need to be dropped in non-final positions
+ // stacky&unreachable code may introduce elements that need to be dropped
+ // in non-final positions
if (isConcreteType(item->type)) {
curr->list.back() = Builder(wasm).makeDrop(item);
if (consumable == NONE) {
@@ -1825,7 +2142,8 @@ void WasmBinaryBuilder::pushBlockElements(Block* curr, size_t start, size_t end)
expressionStack.resize(start);
// if we have a consumable item and need it, use it
if (consumable != NONE && curr->list.back()->type == none) {
- requireFunctionContext("need an extra var in a non-function context, invalid wasm");
+ requireFunctionContext(
+ "need an extra var in a non-function context, invalid wasm");
Builder builder(wasm);
auto* item = curr->list[consumable]->cast<Drop>()->value;
auto temp = builder.addVar(currFunction, item->type);
@@ -1835,9 +2153,10 @@ void WasmBinaryBuilder::pushBlockElements(Block* curr, size_t start, size_t end)
}
void WasmBinaryBuilder::visitBlock(Block* curr) {
- if (debug) std::cerr << "zz node: Block" << std::endl;
- // special-case Block and de-recurse nested blocks in their first position, as that is
- // a common pattern that can be very highly nested.
+ if (debug)
+ std::cerr << "zz node: Block" << std::endl;
+ // special-case Block and de-recurse nested blocks in their first position, as
+ // that is a common pattern that can be very highly nested.
std::vector<Block*> stack;
while (1) {
curr->type = getType();
@@ -1862,7 +2181,8 @@ void WasmBinaryBuilder::visitBlock(Block* curr) {
while (stack.size() > 0) {
curr = stack.back();
stack.pop_back();
- size_t start = expressionStack.size(); // everything after this, that is left when we see the marker, is ours
+ // everything after this, that is left when we see the marker, is ours
+ size_t start = expressionStack.size();
if (last) {
// the previous block is our first-position element
expressionStack.push_back(last);
@@ -1874,7 +2194,9 @@ void WasmBinaryBuilder::visitBlock(Block* curr) {
throwError("block cannot pop from outside");
}
pushBlockElements(curr, start, end);
- curr->finalize(curr->type, breakTargetNames.find(curr->name) != breakTargetNames.end() /* hasBreak */);
+ curr->finalize(curr->type,
+ breakTargetNames.find(curr->name) !=
+ breakTargetNames.end() /* hasBreak */);
breakStack.pop_back();
breakTargetNames.erase(curr->name);
}
@@ -1906,7 +2228,8 @@ Expression* WasmBinaryBuilder::getBlockOrSingleton(Type type) {
}
void WasmBinaryBuilder::visitIf(If* curr) {
- if (debug) std::cerr << "zz node: If" << std::endl;
+ if (debug)
+ std::cerr << "zz node: If" << std::endl;
curr->type = getType();
curr->condition = popNonVoidExpression();
curr->ifTrue = getBlockOrSingleton(curr->type);
@@ -1920,7 +2243,8 @@ void WasmBinaryBuilder::visitIf(If* curr) {
}
void WasmBinaryBuilder::visitLoop(Loop* curr) {
- if (debug) std::cerr << "zz node: Loop" << std::endl;
+ if (debug)
+ std::cerr << "zz node: Loop" << std::endl;
curr->type = getType();
curr->name = getNextLabel();
breakStack.push_back({curr->name, 0});
@@ -1948,8 +2272,10 @@ void WasmBinaryBuilder::visitLoop(Loop* curr) {
curr->finalize(curr->type);
}
-WasmBinaryBuilder::BreakTarget WasmBinaryBuilder::getBreakTarget(int32_t offset) {
- if (debug) std::cerr << "getBreakTarget " << offset << std::endl;
+WasmBinaryBuilder::BreakTarget
+WasmBinaryBuilder::getBreakTarget(int32_t offset) {
+ if (debug)
+ std::cerr << "getBreakTarget " << offset << std::endl;
if (breakStack.size() < 1 + size_t(offset)) {
throwError("bad breakindex (low)");
}
@@ -1957,42 +2283,52 @@ WasmBinaryBuilder::BreakTarget WasmBinaryBuilder::getBreakTarget(int32_t offset)
if (index >= breakStack.size()) {
throwError("bad breakindex (high)");
}
- if (debug) std::cerr << "breaktarget "<< breakStack[index].name << " arity " << breakStack[index].arity << std::endl;
+ if (debug)
+ std::cerr << "breaktarget " << breakStack[index].name << " arity "
+ << breakStack[index].arity << std::endl;
auto& ret = breakStack[index];
- // if the break is in literally unreachable code, then we will not emit it anyhow,
- // so do not note that the target has breaks to it
+ // if the break is in literally unreachable code, then we will not emit it
+ // anyhow, so do not note that the target has breaks to it
if (!willBeIgnored) {
breakTargetNames.insert(ret.name);
}
return ret;
}
-void WasmBinaryBuilder::visitBreak(Break *curr, uint8_t code) {
- if (debug) std::cerr << "zz node: Break, code "<< int32_t(code) << std::endl;
+void WasmBinaryBuilder::visitBreak(Break* curr, uint8_t code) {
+ if (debug)
+ std::cerr << "zz node: Break, code " << int32_t(code) << std::endl;
BreakTarget target = getBreakTarget(getU32LEB());
curr->name = target.name;
- if (code == BinaryConsts::BrIf) curr->condition = popNonVoidExpression();
- if (target.arity) curr->value = popNonVoidExpression();
+ if (code == BinaryConsts::BrIf)
+ curr->condition = popNonVoidExpression();
+ if (target.arity)
+ curr->value = popNonVoidExpression();
curr->finalize();
}
void WasmBinaryBuilder::visitSwitch(Switch* curr) {
- if (debug) std::cerr << "zz node: Switch" << std::endl;
+ if (debug)
+ std::cerr << "zz node: Switch" << std::endl;
curr->condition = popNonVoidExpression();
auto numTargets = getU32LEB();
- if (debug) std::cerr << "targets: "<< numTargets<<std::endl;
+ if (debug)
+ std::cerr << "targets: " << numTargets << std::endl;
for (size_t i = 0; i < numTargets; i++) {
curr->targets.push_back(getBreakTarget(getU32LEB()).name);
}
auto defaultTarget = getBreakTarget(getU32LEB());
curr->default_ = defaultTarget.name;
- if (debug) std::cerr << "default: "<< curr->default_<<std::endl;
- if (defaultTarget.arity) curr->value = popNonVoidExpression();
+ if (debug)
+ std::cerr << "default: " << curr->default_ << std::endl;
+ if (defaultTarget.arity)
+ curr->value = popNonVoidExpression();
curr->finalize();
}
void WasmBinaryBuilder::visitCall(Call* curr) {
- if (debug) std::cerr << "zz node: Call" << std::endl;
+ if (debug)
+ std::cerr << "zz node: Call" << std::endl;
auto index = getU32LEB();
FunctionType* type;
if (index < functionImports.size()) {
@@ -2017,14 +2353,16 @@ void WasmBinaryBuilder::visitCall(Call* curr) {
}
void WasmBinaryBuilder::visitCallIndirect(CallIndirect* curr) {
- if (debug) std::cerr << "zz node: CallIndirect" << std::endl;
+ if (debug)
+ std::cerr << "zz node: CallIndirect" << std::endl;
auto index = getU32LEB();
if (index >= wasm.functionTypes.size()) {
throwError("bad call_indirect function index");
}
auto* fullType = wasm.functionTypes[index].get();
auto reserved = getU32LEB();
- if (reserved != 0) throwError("Invalid flags field in call_indirect");
+ if (reserved != 0)
+ throwError("Invalid flags field in call_indirect");
curr->fullType = fullType->name;
auto num = fullType->params.size();
curr->operands.resize(num);
@@ -2037,7 +2375,8 @@ void WasmBinaryBuilder::visitCallIndirect(CallIndirect* curr) {
}
void WasmBinaryBuilder::visitGetLocal(GetLocal* curr) {
- if (debug) std::cerr << "zz node: GetLocal " << pos << std::endl;
+ if (debug)
+ std::cerr << "zz node: GetLocal " << pos << std::endl;
requireFunctionContext("local.get");
curr->index = getU32LEB();
if (curr->index >= currFunction->getNumLocals()) {
@@ -2047,8 +2386,9 @@ void WasmBinaryBuilder::visitGetLocal(GetLocal* curr) {
curr->finalize();
}
-void WasmBinaryBuilder::visitSetLocal(SetLocal *curr, uint8_t code) {
- if (debug) std::cerr << "zz node: Set|TeeLocal" << std::endl;
+void WasmBinaryBuilder::visitSetLocal(SetLocal* curr, uint8_t code) {
+ if (debug)
+ std::cerr << "zz node: Set|TeeLocal" << std::endl;
requireFunctionContext("local.set outside of function");
curr->index = getU32LEB();
if (curr->index >= currFunction->getNumLocals()) {
@@ -2061,14 +2401,16 @@ void WasmBinaryBuilder::visitSetLocal(SetLocal *curr, uint8_t code) {
}
void WasmBinaryBuilder::visitGetGlobal(GetGlobal* curr) {
- if (debug) std::cerr << "zz node: GetGlobal " << pos << std::endl;
+ if (debug)
+ std::cerr << "zz node: GetGlobal " << pos << std::endl;
auto index = getU32LEB();
curr->name = getGlobalName(index);
curr->type = wasm.getGlobal(curr->name)->type;
}
void WasmBinaryBuilder::visitSetGlobal(SetGlobal* curr) {
- if (debug) std::cerr << "zz node: SetGlobal" << std::endl;
+ if (debug)
+ std::cerr << "zz node: SetGlobal" << std::endl;
auto index = getU32LEB();
curr->name = getGlobalName(index);
curr->value = popNonVoidExpression();
@@ -2077,45 +2419,146 @@ void WasmBinaryBuilder::visitSetGlobal(SetGlobal* curr) {
void WasmBinaryBuilder::readMemoryAccess(Address& alignment, Address& offset) {
auto rawAlignment = getU32LEB();
- if (rawAlignment > 4) throwError("Alignment must be of a reasonable size");
+ if (rawAlignment > 4)
+ throwError("Alignment must be of a reasonable size");
alignment = Pow2(rawAlignment);
offset = getU32LEB();
}
-bool WasmBinaryBuilder::maybeVisitLoad(Expression*& out, uint8_t code, bool isAtomic) {
+bool WasmBinaryBuilder::maybeVisitLoad(Expression*& out,
+ uint8_t code,
+ bool isAtomic) {
Load* curr;
if (!isAtomic) {
switch (code) {
- case BinaryConsts::I32LoadMem8S: curr = allocator.alloc<Load>(); curr->bytes = 1; curr->type = i32; curr->signed_ = true; break;
- case BinaryConsts::I32LoadMem8U: curr = allocator.alloc<Load>(); curr->bytes = 1; curr->type = i32; curr->signed_ = false; break;
- case BinaryConsts::I32LoadMem16S: curr = allocator.alloc<Load>(); curr->bytes = 2; curr->type = i32; curr->signed_ = true; break;
- case BinaryConsts::I32LoadMem16U: curr = allocator.alloc<Load>(); curr->bytes = 2; curr->type = i32; curr->signed_ = false; break;
- case BinaryConsts::I32LoadMem: curr = allocator.alloc<Load>(); curr->bytes = 4; curr->type = i32; break;
- case BinaryConsts::I64LoadMem8S: curr = allocator.alloc<Load>(); curr->bytes = 1; curr->type = i64; curr->signed_ = true; break;
- case BinaryConsts::I64LoadMem8U: curr = allocator.alloc<Load>(); curr->bytes = 1; curr->type = i64; curr->signed_ = false; break;
- case BinaryConsts::I64LoadMem16S: curr = allocator.alloc<Load>(); curr->bytes = 2; curr->type = i64; curr->signed_ = true; break;
- case BinaryConsts::I64LoadMem16U: curr = allocator.alloc<Load>(); curr->bytes = 2; curr->type = i64; curr->signed_ = false; break;
- case BinaryConsts::I64LoadMem32S: curr = allocator.alloc<Load>(); curr->bytes = 4; curr->type = i64; curr->signed_ = true; break;
- case BinaryConsts::I64LoadMem32U: curr = allocator.alloc<Load>(); curr->bytes = 4; curr->type = i64; curr->signed_ = false; break;
- case BinaryConsts::I64LoadMem: curr = allocator.alloc<Load>(); curr->bytes = 8; curr->type = i64; break;
- case BinaryConsts::F32LoadMem: curr = allocator.alloc<Load>(); curr->bytes = 4; curr->type = f32; break;
- case BinaryConsts::F64LoadMem: curr = allocator.alloc<Load>(); curr->bytes = 8; curr->type = f64; break;
- default: return false;
- }
- if (debug) std::cerr << "zz node: Load" << std::endl;
+ case BinaryConsts::I32LoadMem8S:
+ curr = allocator.alloc<Load>();
+ curr->bytes = 1;
+ curr->type = i32;
+ curr->signed_ = true;
+ break;
+ case BinaryConsts::I32LoadMem8U:
+ curr = allocator.alloc<Load>();
+ curr->bytes = 1;
+ curr->type = i32;
+ curr->signed_ = false;
+ break;
+ case BinaryConsts::I32LoadMem16S:
+ curr = allocator.alloc<Load>();
+ curr->bytes = 2;
+ curr->type = i32;
+ curr->signed_ = true;
+ break;
+ case BinaryConsts::I32LoadMem16U:
+ curr = allocator.alloc<Load>();
+ curr->bytes = 2;
+ curr->type = i32;
+ curr->signed_ = false;
+ break;
+ case BinaryConsts::I32LoadMem:
+ curr = allocator.alloc<Load>();
+ curr->bytes = 4;
+ curr->type = i32;
+ break;
+ case BinaryConsts::I64LoadMem8S:
+ curr = allocator.alloc<Load>();
+ curr->bytes = 1;
+ curr->type = i64;
+ curr->signed_ = true;
+ break;
+ case BinaryConsts::I64LoadMem8U:
+ curr = allocator.alloc<Load>();
+ curr->bytes = 1;
+ curr->type = i64;
+ curr->signed_ = false;
+ break;
+ case BinaryConsts::I64LoadMem16S:
+ curr = allocator.alloc<Load>();
+ curr->bytes = 2;
+ curr->type = i64;
+ curr->signed_ = true;
+ break;
+ case BinaryConsts::I64LoadMem16U:
+ curr = allocator.alloc<Load>();
+ curr->bytes = 2;
+ curr->type = i64;
+ curr->signed_ = false;
+ break;
+ case BinaryConsts::I64LoadMem32S:
+ curr = allocator.alloc<Load>();
+ curr->bytes = 4;
+ curr->type = i64;
+ curr->signed_ = true;
+ break;
+ case BinaryConsts::I64LoadMem32U:
+ curr = allocator.alloc<Load>();
+ curr->bytes = 4;
+ curr->type = i64;
+ curr->signed_ = false;
+ break;
+ case BinaryConsts::I64LoadMem:
+ curr = allocator.alloc<Load>();
+ curr->bytes = 8;
+ curr->type = i64;
+ break;
+ case BinaryConsts::F32LoadMem:
+ curr = allocator.alloc<Load>();
+ curr->bytes = 4;
+ curr->type = f32;
+ break;
+ case BinaryConsts::F64LoadMem:
+ curr = allocator.alloc<Load>();
+ curr->bytes = 8;
+ curr->type = f64;
+ break;
+ default:
+ return false;
+ }
+ if (debug)
+ std::cerr << "zz node: Load" << std::endl;
} else {
switch (code) {
- case BinaryConsts::I32AtomicLoad8U: curr = allocator.alloc<Load>(); curr->bytes = 1; curr->type = i32; break;
- case BinaryConsts::I32AtomicLoad16U: curr = allocator.alloc<Load>(); curr->bytes = 2; curr->type = i32; break;
- case BinaryConsts::I32AtomicLoad: curr = allocator.alloc<Load>(); curr->bytes = 4; curr->type = i32; break;
- case BinaryConsts::I64AtomicLoad8U: curr = allocator.alloc<Load>(); curr->bytes = 1; curr->type = i64; break;
- case BinaryConsts::I64AtomicLoad16U: curr = allocator.alloc<Load>(); curr->bytes = 2; curr->type = i64; break;
- case BinaryConsts::I64AtomicLoad32U: curr = allocator.alloc<Load>(); curr->bytes = 4; curr->type = i64; break;
- case BinaryConsts::I64AtomicLoad: curr = allocator.alloc<Load>(); curr->bytes = 8; curr->type = i64; break;
- default: return false;
+ case BinaryConsts::I32AtomicLoad8U:
+ curr = allocator.alloc<Load>();
+ curr->bytes = 1;
+ curr->type = i32;
+ break;
+ case BinaryConsts::I32AtomicLoad16U:
+ curr = allocator.alloc<Load>();
+ curr->bytes = 2;
+ curr->type = i32;
+ break;
+ case BinaryConsts::I32AtomicLoad:
+ curr = allocator.alloc<Load>();
+ curr->bytes = 4;
+ curr->type = i32;
+ break;
+ case BinaryConsts::I64AtomicLoad8U:
+ curr = allocator.alloc<Load>();
+ curr->bytes = 1;
+ curr->type = i64;
+ break;
+ case BinaryConsts::I64AtomicLoad16U:
+ curr = allocator.alloc<Load>();
+ curr->bytes = 2;
+ curr->type = i64;
+ break;
+ case BinaryConsts::I64AtomicLoad32U:
+ curr = allocator.alloc<Load>();
+ curr->bytes = 4;
+ curr->type = i64;
+ break;
+ case BinaryConsts::I64AtomicLoad:
+ curr = allocator.alloc<Load>();
+ curr->bytes = 8;
+ curr->type = i64;
+ break;
+ default:
+ return false;
}
curr->signed_ = false;
- if (debug) std::cerr << "zz node: AtomicLoad" << std::endl;
+ if (debug)
+ std::cerr << "zz node: AtomicLoad" << std::endl;
}
curr->isAtomic = isAtomic;
@@ -2126,36 +2569,105 @@ bool WasmBinaryBuilder::maybeVisitLoad(Expression*& out, uint8_t code, bool isAt
return true;
}
-bool WasmBinaryBuilder::maybeVisitStore(Expression*& out, uint8_t code, bool isAtomic) {
+bool WasmBinaryBuilder::maybeVisitStore(Expression*& out,
+ uint8_t code,
+ bool isAtomic) {
Store* curr;
if (!isAtomic) {
switch (code) {
- case BinaryConsts::I32StoreMem8: curr = allocator.alloc<Store>(); curr->bytes = 1; curr->valueType = i32; break;
- case BinaryConsts::I32StoreMem16: curr = allocator.alloc<Store>(); curr->bytes = 2; curr->valueType = i32; break;
- case BinaryConsts::I32StoreMem: curr = allocator.alloc<Store>(); curr->bytes = 4; curr->valueType = i32; break;
- case BinaryConsts::I64StoreMem8: curr = allocator.alloc<Store>(); curr->bytes = 1; curr->valueType = i64; break;
- case BinaryConsts::I64StoreMem16: curr = allocator.alloc<Store>(); curr->bytes = 2; curr->valueType = i64; break;
- case BinaryConsts::I64StoreMem32: curr = allocator.alloc<Store>(); curr->bytes = 4; curr->valueType = i64; break;
- case BinaryConsts::I64StoreMem: curr = allocator.alloc<Store>(); curr->bytes = 8; curr->valueType = i64; break;
- case BinaryConsts::F32StoreMem: curr = allocator.alloc<Store>(); curr->bytes = 4; curr->valueType = f32; break;
- case BinaryConsts::F64StoreMem: curr = allocator.alloc<Store>(); curr->bytes = 8; curr->valueType = f64; break;
- default: return false;
+ case BinaryConsts::I32StoreMem8:
+ curr = allocator.alloc<Store>();
+ curr->bytes = 1;
+ curr->valueType = i32;
+ break;
+ case BinaryConsts::I32StoreMem16:
+ curr = allocator.alloc<Store>();
+ curr->bytes = 2;
+ curr->valueType = i32;
+ break;
+ case BinaryConsts::I32StoreMem:
+ curr = allocator.alloc<Store>();
+ curr->bytes = 4;
+ curr->valueType = i32;
+ break;
+ case BinaryConsts::I64StoreMem8:
+ curr = allocator.alloc<Store>();
+ curr->bytes = 1;
+ curr->valueType = i64;
+ break;
+ case BinaryConsts::I64StoreMem16:
+ curr = allocator.alloc<Store>();
+ curr->bytes = 2;
+ curr->valueType = i64;
+ break;
+ case BinaryConsts::I64StoreMem32:
+ curr = allocator.alloc<Store>();
+ curr->bytes = 4;
+ curr->valueType = i64;
+ break;
+ case BinaryConsts::I64StoreMem:
+ curr = allocator.alloc<Store>();
+ curr->bytes = 8;
+ curr->valueType = i64;
+ break;
+ case BinaryConsts::F32StoreMem:
+ curr = allocator.alloc<Store>();
+ curr->bytes = 4;
+ curr->valueType = f32;
+ break;
+ case BinaryConsts::F64StoreMem:
+ curr = allocator.alloc<Store>();
+ curr->bytes = 8;
+ curr->valueType = f64;
+ break;
+ default:
+ return false;
}
} else {
switch (code) {
- case BinaryConsts::I32AtomicStore8: curr = allocator.alloc<Store>(); curr->bytes = 1; curr->valueType = i32; break;
- case BinaryConsts::I32AtomicStore16: curr = allocator.alloc<Store>(); curr->bytes = 2; curr->valueType = i32; break;
- case BinaryConsts::I32AtomicStore: curr = allocator.alloc<Store>(); curr->bytes = 4; curr->valueType = i32; break;
- case BinaryConsts::I64AtomicStore8: curr = allocator.alloc<Store>(); curr->bytes = 1; curr->valueType = i64; break;
- case BinaryConsts::I64AtomicStore16: curr = allocator.alloc<Store>(); curr->bytes = 2; curr->valueType = i64; break;
- case BinaryConsts::I64AtomicStore32: curr = allocator.alloc<Store>(); curr->bytes = 4; curr->valueType = i64; break;
- case BinaryConsts::I64AtomicStore: curr = allocator.alloc<Store>(); curr->bytes = 8; curr->valueType = i64; break;
- default: return false;
+ case BinaryConsts::I32AtomicStore8:
+ curr = allocator.alloc<Store>();
+ curr->bytes = 1;
+ curr->valueType = i32;
+ break;
+ case BinaryConsts::I32AtomicStore16:
+ curr = allocator.alloc<Store>();
+ curr->bytes = 2;
+ curr->valueType = i32;
+ break;
+ case BinaryConsts::I32AtomicStore:
+ curr = allocator.alloc<Store>();
+ curr->bytes = 4;
+ curr->valueType = i32;
+ break;
+ case BinaryConsts::I64AtomicStore8:
+ curr = allocator.alloc<Store>();
+ curr->bytes = 1;
+ curr->valueType = i64;
+ break;
+ case BinaryConsts::I64AtomicStore16:
+ curr = allocator.alloc<Store>();
+ curr->bytes = 2;
+ curr->valueType = i64;
+ break;
+ case BinaryConsts::I64AtomicStore32:
+ curr = allocator.alloc<Store>();
+ curr->bytes = 4;
+ curr->valueType = i64;
+ break;
+ case BinaryConsts::I64AtomicStore:
+ curr = allocator.alloc<Store>();
+ curr->bytes = 8;
+ curr->valueType = i64;
+ break;
+ default:
+ return false;
}
}
curr->isAtomic = isAtomic;
- if (debug) std::cerr << "zz node: Store" << std::endl;
+ if (debug)
+ std::cerr << "zz node: Store" << std::endl;
readMemoryAccess(curr->align, curr->offset);
curr->value = popNonVoidExpression();
curr->ptr = popNonVoidExpression();
@@ -2165,41 +2677,60 @@ bool WasmBinaryBuilder::maybeVisitStore(Expression*& out, uint8_t code, bool isA
}
bool WasmBinaryBuilder::maybeVisitAtomicRMW(Expression*& out, uint8_t code) {
- if (code < BinaryConsts::AtomicRMWOps_Begin || code > BinaryConsts::AtomicRMWOps_End) return false;
+ if (code < BinaryConsts::AtomicRMWOps_Begin ||
+ code > BinaryConsts::AtomicRMWOps_End)
+ return false;
auto* curr = allocator.alloc<AtomicRMW>();
// Set curr to the given opcode, type and size.
-#define SET(opcode, optype, size) \
- curr->op = opcode; \
- curr->type = optype; \
+#define SET(opcode, optype, size) \
+ curr->op = opcode; \
+ curr->type = optype; \
curr->bytes = size
// Handle the cases for all the valid types for a particular opcode
-#define SET_FOR_OP(Op) \
- case BinaryConsts::I32AtomicRMW##Op: SET(Op, i32, 4); break; \
- case BinaryConsts::I32AtomicRMW##Op##8U: SET(Op, i32, 1); break; \
- case BinaryConsts::I32AtomicRMW##Op##16U: SET(Op, i32, 2); break; \
- case BinaryConsts::I64AtomicRMW##Op: SET(Op, i64, 8); break; \
- case BinaryConsts::I64AtomicRMW##Op##8U: SET(Op, i64, 1); break; \
- case BinaryConsts::I64AtomicRMW##Op##16U: SET(Op, i64, 2); break; \
- case BinaryConsts::I64AtomicRMW##Op##32U: SET(Op, i64, 4); break;
-
- switch(code) {
+#define SET_FOR_OP(Op) \
+ case BinaryConsts::I32AtomicRMW##Op: \
+ SET(Op, i32, 4); \
+ break; \
+ case BinaryConsts::I32AtomicRMW##Op##8U: \
+ SET(Op, i32, 1); \
+ break; \
+ case BinaryConsts::I32AtomicRMW##Op##16U: \
+ SET(Op, i32, 2); \
+ break; \
+ case BinaryConsts::I64AtomicRMW##Op: \
+ SET(Op, i64, 8); \
+ break; \
+ case BinaryConsts::I64AtomicRMW##Op##8U: \
+ SET(Op, i64, 1); \
+ break; \
+ case BinaryConsts::I64AtomicRMW##Op##16U: \
+ SET(Op, i64, 2); \
+ break; \
+ case BinaryConsts::I64AtomicRMW##Op##32U: \
+ SET(Op, i64, 4); \
+ break;
+
+ switch (code) {
SET_FOR_OP(Add);
SET_FOR_OP(Sub);
SET_FOR_OP(And);
SET_FOR_OP(Or);
SET_FOR_OP(Xor);
SET_FOR_OP(Xchg);
- default: WASM_UNREACHABLE();
+ default:
+ WASM_UNREACHABLE();
}
#undef SET_FOR_OP
#undef SET
- if (debug) std::cerr << "zz node: AtomicRMW" << std::endl;
+ if (debug)
+ std::cerr << "zz node: AtomicRMW" << std::endl;
Address readAlign;
readMemoryAccess(readAlign, curr->offset);
- if (readAlign != curr->bytes) throwError("Align of AtomicRMW must match size");
+ if (readAlign != curr->bytes)
+ throwError("Align of AtomicRMW must match size");
curr->value = popNonVoidExpression();
curr->ptr = popNonVoidExpression();
curr->finalize();
@@ -2207,30 +2738,50 @@ bool WasmBinaryBuilder::maybeVisitAtomicRMW(Expression*& out, uint8_t code) {
return true;
}
-bool WasmBinaryBuilder::maybeVisitAtomicCmpxchg(Expression*& out, uint8_t code) {
- if (code < BinaryConsts::AtomicCmpxchgOps_Begin || code > BinaryConsts::AtomicCmpxchgOps_End) return false;
+bool WasmBinaryBuilder::maybeVisitAtomicCmpxchg(Expression*& out,
+ uint8_t code) {
+ if (code < BinaryConsts::AtomicCmpxchgOps_Begin ||
+ code > BinaryConsts::AtomicCmpxchgOps_End)
+ return false;
auto* curr = allocator.alloc<AtomicCmpxchg>();
// Set curr to the given type and size.
-#define SET(optype, size) \
- curr->type = optype; \
+#define SET(optype, size) \
+ curr->type = optype; \
curr->bytes = size
switch (code) {
- case BinaryConsts::I32AtomicCmpxchg: SET(i32, 4); break;
- case BinaryConsts::I64AtomicCmpxchg: SET(i64, 8); break;
- case BinaryConsts::I32AtomicCmpxchg8U: SET(i32, 1); break;
- case BinaryConsts::I32AtomicCmpxchg16U: SET(i32, 2); break;
- case BinaryConsts::I64AtomicCmpxchg8U: SET(i64, 1); break;
- case BinaryConsts::I64AtomicCmpxchg16U: SET(i64, 2); break;
- case BinaryConsts::I64AtomicCmpxchg32U: SET(i64, 4); break;
- default: WASM_UNREACHABLE();
+ case BinaryConsts::I32AtomicCmpxchg:
+ SET(i32, 4);
+ break;
+ case BinaryConsts::I64AtomicCmpxchg:
+ SET(i64, 8);
+ break;
+ case BinaryConsts::I32AtomicCmpxchg8U:
+ SET(i32, 1);
+ break;
+ case BinaryConsts::I32AtomicCmpxchg16U:
+ SET(i32, 2);
+ break;
+ case BinaryConsts::I64AtomicCmpxchg8U:
+ SET(i64, 1);
+ break;
+ case BinaryConsts::I64AtomicCmpxchg16U:
+ SET(i64, 2);
+ break;
+ case BinaryConsts::I64AtomicCmpxchg32U:
+ SET(i64, 4);
+ break;
+ default:
+ WASM_UNREACHABLE();
}
- if (debug) std::cerr << "zz node: AtomicCmpxchg" << std::endl;
+ if (debug)
+ std::cerr << "zz node: AtomicCmpxchg" << std::endl;
Address readAlign;
readMemoryAccess(readAlign, curr->offset);
- if (readAlign != curr->bytes) throwError("Align of AtomicCpxchg must match size");
+ if (readAlign != curr->bytes)
+ throwError("Align of AtomicCpxchg must match size");
curr->replacement = popNonVoidExpression();
curr->expected = popNonVoidExpression();
curr->ptr = popNonVoidExpression();
@@ -2240,38 +2791,49 @@ bool WasmBinaryBuilder::maybeVisitAtomicCmpxchg(Expression*& out, uint8_t code)
}
bool WasmBinaryBuilder::maybeVisitAtomicWait(Expression*& out, uint8_t code) {
- if (code < BinaryConsts::I32AtomicWait || code > BinaryConsts::I64AtomicWait) return false;
+ if (code < BinaryConsts::I32AtomicWait || code > BinaryConsts::I64AtomicWait)
+ return false;
auto* curr = allocator.alloc<AtomicWait>();
switch (code) {
- case BinaryConsts::I32AtomicWait: curr->expectedType = i32; break;
- case BinaryConsts::I64AtomicWait: curr->expectedType = i64; break;
- default: WASM_UNREACHABLE();
+ case BinaryConsts::I32AtomicWait:
+ curr->expectedType = i32;
+ break;
+ case BinaryConsts::I64AtomicWait:
+ curr->expectedType = i64;
+ break;
+ default:
+ WASM_UNREACHABLE();
}
curr->type = i32;
- if (debug) std::cerr << "zz node: AtomicWait" << std::endl;
+ if (debug)
+ std::cerr << "zz node: AtomicWait" << std::endl;
curr->timeout = popNonVoidExpression();
curr->expected = popNonVoidExpression();
curr->ptr = popNonVoidExpression();
Address readAlign;
readMemoryAccess(readAlign, curr->offset);
- if (readAlign != getTypeSize(curr->expectedType)) throwError("Align of AtomicWait must match size");
+ if (readAlign != getTypeSize(curr->expectedType))
+ throwError("Align of AtomicWait must match size");
curr->finalize();
out = curr;
return true;
}
bool WasmBinaryBuilder::maybeVisitAtomicNotify(Expression*& out, uint8_t code) {
- if (code != BinaryConsts::AtomicNotify) return false;
+ if (code != BinaryConsts::AtomicNotify)
+ return false;
auto* curr = allocator.alloc<AtomicNotify>();
- if (debug) std::cerr << "zz node: AtomicNotify" << std::endl;
+ if (debug)
+ std::cerr << "zz node: AtomicNotify" << std::endl;
curr->type = i32;
curr->notifyCount = popNonVoidExpression();
curr->ptr = popNonVoidExpression();
Address readAlign;
readMemoryAccess(readAlign, curr->offset);
- if (readAlign != getTypeSize(curr->type)) throwError("Align of AtomicNotify must match size");
+ if (readAlign != getTypeSize(curr->type))
+ throwError("Align of AtomicNotify must match size");
curr->finalize();
out = curr;
return true;
@@ -2279,13 +2841,27 @@ bool WasmBinaryBuilder::maybeVisitAtomicNotify(Expression*& out, uint8_t code) {
bool WasmBinaryBuilder::maybeVisitConst(Expression*& out, uint8_t code) {
Const* curr;
- if (debug) std::cerr << "zz node: Const, code " << code << std::endl;
+ if (debug)
+ std::cerr << "zz node: Const, code " << code << std::endl;
switch (code) {
- case BinaryConsts::I32Const: curr = allocator.alloc<Const>(); curr->value = Literal(getS32LEB()); break;
- case BinaryConsts::I64Const: curr = allocator.alloc<Const>(); curr->value = Literal(getS64LEB()); break;
- case BinaryConsts::F32Const: curr = allocator.alloc<Const>(); curr->value = getFloat32Literal(); break;
- case BinaryConsts::F64Const: curr = allocator.alloc<Const>(); curr->value = getFloat64Literal(); break;
- default: return false;
+ case BinaryConsts::I32Const:
+ curr = allocator.alloc<Const>();
+ curr->value = Literal(getS32LEB());
+ break;
+ case BinaryConsts::I64Const:
+ curr = allocator.alloc<Const>();
+ curr->value = Literal(getS64LEB());
+ break;
+ case BinaryConsts::F32Const:
+ curr = allocator.alloc<Const>();
+ curr->value = getFloat32Literal();
+ break;
+ case BinaryConsts::F64Const:
+ curr = allocator.alloc<Const>();
+ curr->value = getFloat64Literal();
+ break;
+ default:
+ return false;
}
curr->type = curr->value.type;
out = curr;
@@ -2296,67 +2872,225 @@ bool WasmBinaryBuilder::maybeVisitConst(Expression*& out, uint8_t code) {
bool WasmBinaryBuilder::maybeVisitUnary(Expression*& out, uint8_t code) {
Unary* curr;
switch (code) {
- case BinaryConsts::I32Clz: curr = allocator.alloc<Unary>(); curr->op = ClzInt32; break;
- case BinaryConsts::I64Clz: curr = allocator.alloc<Unary>(); curr->op = ClzInt64; break;
- case BinaryConsts::I32Ctz: curr = allocator.alloc<Unary>(); curr->op = CtzInt32; break;
- case BinaryConsts::I64Ctz: curr = allocator.alloc<Unary>(); curr->op = CtzInt64; break;
- case BinaryConsts::I32Popcnt: curr = allocator.alloc<Unary>(); curr->op = PopcntInt32; break;
- case BinaryConsts::I64Popcnt: curr = allocator.alloc<Unary>(); curr->op = PopcntInt64; break;
- case BinaryConsts::I32EqZ: curr = allocator.alloc<Unary>(); curr->op = EqZInt32; break;
- case BinaryConsts::I64EqZ: curr = allocator.alloc<Unary>(); curr->op = EqZInt64; break;
- case BinaryConsts::F32Neg: curr = allocator.alloc<Unary>(); curr->op = NegFloat32; break;
- case BinaryConsts::F64Neg: curr = allocator.alloc<Unary>(); curr->op = NegFloat64; break;
- case BinaryConsts::F32Abs: curr = allocator.alloc<Unary>(); curr->op = AbsFloat32; break;
- case BinaryConsts::F64Abs: curr = allocator.alloc<Unary>(); curr->op = AbsFloat64; break;
- case BinaryConsts::F32Ceil: curr = allocator.alloc<Unary>(); curr->op = CeilFloat32; break;
- case BinaryConsts::F64Ceil: curr = allocator.alloc<Unary>(); curr->op = CeilFloat64; break;
- case BinaryConsts::F32Floor: curr = allocator.alloc<Unary>(); curr->op = FloorFloat32; break;
- case BinaryConsts::F64Floor: curr = allocator.alloc<Unary>(); curr->op = FloorFloat64; break;
- case BinaryConsts::F32NearestInt: curr = allocator.alloc<Unary>(); curr->op = NearestFloat32; break;
- case BinaryConsts::F64NearestInt: curr = allocator.alloc<Unary>(); curr->op = NearestFloat64; break;
- case BinaryConsts::F32Sqrt: curr = allocator.alloc<Unary>(); curr->op = SqrtFloat32; break;
- case BinaryConsts::F64Sqrt: curr = allocator.alloc<Unary>(); curr->op = SqrtFloat64; break;
- case BinaryConsts::F32UConvertI32: curr = allocator.alloc<Unary>(); curr->op = ConvertUInt32ToFloat32; break;
- case BinaryConsts::F64UConvertI32: curr = allocator.alloc<Unary>(); curr->op = ConvertUInt32ToFloat64; break;
- case BinaryConsts::F32SConvertI32: curr = allocator.alloc<Unary>(); curr->op = ConvertSInt32ToFloat32; break;
- case BinaryConsts::F64SConvertI32: curr = allocator.alloc<Unary>(); curr->op = ConvertSInt32ToFloat64; break;
- case BinaryConsts::F32UConvertI64: curr = allocator.alloc<Unary>(); curr->op = ConvertUInt64ToFloat32; break;
- case BinaryConsts::F64UConvertI64: curr = allocator.alloc<Unary>(); curr->op = ConvertUInt64ToFloat64; break;
- case BinaryConsts::F32SConvertI64: curr = allocator.alloc<Unary>(); curr->op = ConvertSInt64ToFloat32; break;
- case BinaryConsts::F64SConvertI64: curr = allocator.alloc<Unary>(); curr->op = ConvertSInt64ToFloat64; break;
-
- case BinaryConsts::I64STruncI32: curr = allocator.alloc<Unary>(); curr->op = ExtendSInt32; break;
- case BinaryConsts::I64UTruncI32: curr = allocator.alloc<Unary>(); curr->op = ExtendUInt32; break;
- case BinaryConsts::I32ConvertI64: curr = allocator.alloc<Unary>(); curr->op = WrapInt64; break;
-
- case BinaryConsts::I32UTruncF32: curr = allocator.alloc<Unary>(); curr->op = TruncUFloat32ToInt32; break;
- case BinaryConsts::I32UTruncF64: curr = allocator.alloc<Unary>(); curr->op = TruncUFloat64ToInt32; break;
- case BinaryConsts::I32STruncF32: curr = allocator.alloc<Unary>(); curr->op = TruncSFloat32ToInt32; break;
- case BinaryConsts::I32STruncF64: curr = allocator.alloc<Unary>(); curr->op = TruncSFloat64ToInt32; break;
- case BinaryConsts::I64UTruncF32: curr = allocator.alloc<Unary>(); curr->op = TruncUFloat32ToInt64; break;
- case BinaryConsts::I64UTruncF64: curr = allocator.alloc<Unary>(); curr->op = TruncUFloat64ToInt64; break;
- case BinaryConsts::I64STruncF32: curr = allocator.alloc<Unary>(); curr->op = TruncSFloat32ToInt64; break;
- case BinaryConsts::I64STruncF64: curr = allocator.alloc<Unary>(); curr->op = TruncSFloat64ToInt64; break;
-
- case BinaryConsts::F32Trunc: curr = allocator.alloc<Unary>(); curr->op = TruncFloat32; break;
- case BinaryConsts::F64Trunc: curr = allocator.alloc<Unary>(); curr->op = TruncFloat64; break;
-
- case BinaryConsts::F32ConvertF64: curr = allocator.alloc<Unary>(); curr->op = DemoteFloat64; break;
- case BinaryConsts::F64ConvertF32: curr = allocator.alloc<Unary>(); curr->op = PromoteFloat32; break;
- case BinaryConsts::I32ReinterpretF32: curr = allocator.alloc<Unary>(); curr->op = ReinterpretFloat32; break;
- case BinaryConsts::I64ReinterpretF64: curr = allocator.alloc<Unary>(); curr->op = ReinterpretFloat64; break;
- case BinaryConsts::F32ReinterpretI32: curr = allocator.alloc<Unary>(); curr->op = ReinterpretInt32; break;
- case BinaryConsts::F64ReinterpretI64: curr = allocator.alloc<Unary>(); curr->op = ReinterpretInt64; break;
-
- case BinaryConsts::I32ExtendS8: curr = allocator.alloc<Unary>(); curr->op = ExtendS8Int32; break;
- case BinaryConsts::I32ExtendS16: curr = allocator.alloc<Unary>(); curr->op = ExtendS16Int32; break;
- case BinaryConsts::I64ExtendS8: curr = allocator.alloc<Unary>(); curr->op = ExtendS8Int64; break;
- case BinaryConsts::I64ExtendS16: curr = allocator.alloc<Unary>(); curr->op = ExtendS16Int64; break;
- case BinaryConsts::I64ExtendS32: curr = allocator.alloc<Unary>(); curr->op = ExtendS32Int64; break;
-
- default: return false;
- }
- if (debug) std::cerr << "zz node: Unary" << std::endl;
+ case BinaryConsts::I32Clz:
+ curr = allocator.alloc<Unary>();
+ curr->op = ClzInt32;
+ break;
+ case BinaryConsts::I64Clz:
+ curr = allocator.alloc<Unary>();
+ curr->op = ClzInt64;
+ break;
+ case BinaryConsts::I32Ctz:
+ curr = allocator.alloc<Unary>();
+ curr->op = CtzInt32;
+ break;
+ case BinaryConsts::I64Ctz:
+ curr = allocator.alloc<Unary>();
+ curr->op = CtzInt64;
+ break;
+ case BinaryConsts::I32Popcnt:
+ curr = allocator.alloc<Unary>();
+ curr->op = PopcntInt32;
+ break;
+ case BinaryConsts::I64Popcnt:
+ curr = allocator.alloc<Unary>();
+ curr->op = PopcntInt64;
+ break;
+ case BinaryConsts::I32EqZ:
+ curr = allocator.alloc<Unary>();
+ curr->op = EqZInt32;
+ break;
+ case BinaryConsts::I64EqZ:
+ curr = allocator.alloc<Unary>();
+ curr->op = EqZInt64;
+ break;
+ case BinaryConsts::F32Neg:
+ curr = allocator.alloc<Unary>();
+ curr->op = NegFloat32;
+ break;
+ case BinaryConsts::F64Neg:
+ curr = allocator.alloc<Unary>();
+ curr->op = NegFloat64;
+ break;
+ case BinaryConsts::F32Abs:
+ curr = allocator.alloc<Unary>();
+ curr->op = AbsFloat32;
+ break;
+ case BinaryConsts::F64Abs:
+ curr = allocator.alloc<Unary>();
+ curr->op = AbsFloat64;
+ break;
+ case BinaryConsts::F32Ceil:
+ curr = allocator.alloc<Unary>();
+ curr->op = CeilFloat32;
+ break;
+ case BinaryConsts::F64Ceil:
+ curr = allocator.alloc<Unary>();
+ curr->op = CeilFloat64;
+ break;
+ case BinaryConsts::F32Floor:
+ curr = allocator.alloc<Unary>();
+ curr->op = FloorFloat32;
+ break;
+ case BinaryConsts::F64Floor:
+ curr = allocator.alloc<Unary>();
+ curr->op = FloorFloat64;
+ break;
+ case BinaryConsts::F32NearestInt:
+ curr = allocator.alloc<Unary>();
+ curr->op = NearestFloat32;
+ break;
+ case BinaryConsts::F64NearestInt:
+ curr = allocator.alloc<Unary>();
+ curr->op = NearestFloat64;
+ break;
+ case BinaryConsts::F32Sqrt:
+ curr = allocator.alloc<Unary>();
+ curr->op = SqrtFloat32;
+ break;
+ case BinaryConsts::F64Sqrt:
+ curr = allocator.alloc<Unary>();
+ curr->op = SqrtFloat64;
+ break;
+ case BinaryConsts::F32UConvertI32:
+ curr = allocator.alloc<Unary>();
+ curr->op = ConvertUInt32ToFloat32;
+ break;
+ case BinaryConsts::F64UConvertI32:
+ curr = allocator.alloc<Unary>();
+ curr->op = ConvertUInt32ToFloat64;
+ break;
+ case BinaryConsts::F32SConvertI32:
+ curr = allocator.alloc<Unary>();
+ curr->op = ConvertSInt32ToFloat32;
+ break;
+ case BinaryConsts::F64SConvertI32:
+ curr = allocator.alloc<Unary>();
+ curr->op = ConvertSInt32ToFloat64;
+ break;
+ case BinaryConsts::F32UConvertI64:
+ curr = allocator.alloc<Unary>();
+ curr->op = ConvertUInt64ToFloat32;
+ break;
+ case BinaryConsts::F64UConvertI64:
+ curr = allocator.alloc<Unary>();
+ curr->op = ConvertUInt64ToFloat64;
+ break;
+ case BinaryConsts::F32SConvertI64:
+ curr = allocator.alloc<Unary>();
+ curr->op = ConvertSInt64ToFloat32;
+ break;
+ case BinaryConsts::F64SConvertI64:
+ curr = allocator.alloc<Unary>();
+ curr->op = ConvertSInt64ToFloat64;
+ break;
+
+ case BinaryConsts::I64STruncI32:
+ curr = allocator.alloc<Unary>();
+ curr->op = ExtendSInt32;
+ break;
+ case BinaryConsts::I64UTruncI32:
+ curr = allocator.alloc<Unary>();
+ curr->op = ExtendUInt32;
+ break;
+ case BinaryConsts::I32ConvertI64:
+ curr = allocator.alloc<Unary>();
+ curr->op = WrapInt64;
+ break;
+
+ case BinaryConsts::I32UTruncF32:
+ curr = allocator.alloc<Unary>();
+ curr->op = TruncUFloat32ToInt32;
+ break;
+ case BinaryConsts::I32UTruncF64:
+ curr = allocator.alloc<Unary>();
+ curr->op = TruncUFloat64ToInt32;
+ break;
+ case BinaryConsts::I32STruncF32:
+ curr = allocator.alloc<Unary>();
+ curr->op = TruncSFloat32ToInt32;
+ break;
+ case BinaryConsts::I32STruncF64:
+ curr = allocator.alloc<Unary>();
+ curr->op = TruncSFloat64ToInt32;
+ break;
+ case BinaryConsts::I64UTruncF32:
+ curr = allocator.alloc<Unary>();
+ curr->op = TruncUFloat32ToInt64;
+ break;
+ case BinaryConsts::I64UTruncF64:
+ curr = allocator.alloc<Unary>();
+ curr->op = TruncUFloat64ToInt64;
+ break;
+ case BinaryConsts::I64STruncF32:
+ curr = allocator.alloc<Unary>();
+ curr->op = TruncSFloat32ToInt64;
+ break;
+ case BinaryConsts::I64STruncF64:
+ curr = allocator.alloc<Unary>();
+ curr->op = TruncSFloat64ToInt64;
+ break;
+
+ case BinaryConsts::F32Trunc:
+ curr = allocator.alloc<Unary>();
+ curr->op = TruncFloat32;
+ break;
+ case BinaryConsts::F64Trunc:
+ curr = allocator.alloc<Unary>();
+ curr->op = TruncFloat64;
+ break;
+
+ case BinaryConsts::F32ConvertF64:
+ curr = allocator.alloc<Unary>();
+ curr->op = DemoteFloat64;
+ break;
+ case BinaryConsts::F64ConvertF32:
+ curr = allocator.alloc<Unary>();
+ curr->op = PromoteFloat32;
+ break;
+ case BinaryConsts::I32ReinterpretF32:
+ curr = allocator.alloc<Unary>();
+ curr->op = ReinterpretFloat32;
+ break;
+ case BinaryConsts::I64ReinterpretF64:
+ curr = allocator.alloc<Unary>();
+ curr->op = ReinterpretFloat64;
+ break;
+ case BinaryConsts::F32ReinterpretI32:
+ curr = allocator.alloc<Unary>();
+ curr->op = ReinterpretInt32;
+ break;
+ case BinaryConsts::F64ReinterpretI64:
+ curr = allocator.alloc<Unary>();
+ curr->op = ReinterpretInt64;
+ break;
+
+ case BinaryConsts::I32ExtendS8:
+ curr = allocator.alloc<Unary>();
+ curr->op = ExtendS8Int32;
+ break;
+ case BinaryConsts::I32ExtendS16:
+ curr = allocator.alloc<Unary>();
+ curr->op = ExtendS16Int32;
+ break;
+ case BinaryConsts::I64ExtendS8:
+ curr = allocator.alloc<Unary>();
+ curr->op = ExtendS8Int64;
+ break;
+ case BinaryConsts::I64ExtendS16:
+ curr = allocator.alloc<Unary>();
+ curr->op = ExtendS16Int64;
+ break;
+ case BinaryConsts::I64ExtendS32:
+ curr = allocator.alloc<Unary>();
+ curr->op = ExtendS32Int64;
+ break;
+
+ default:
+ return false;
+ }
+ if (debug)
+ std::cerr << "zz node: Unary" << std::endl;
curr->value = popNonVoidExpression();
curr->finalize();
out = curr;
@@ -2366,17 +3100,43 @@ bool WasmBinaryBuilder::maybeVisitUnary(Expression*& out, uint8_t code) {
bool WasmBinaryBuilder::maybeVisitTruncSat(Expression*& out, uint32_t code) {
Unary* curr;
switch (code) {
- case BinaryConsts::I32STruncSatF32: curr = allocator.alloc<Unary>(); curr->op = TruncSatSFloat32ToInt32; break;
- case BinaryConsts::I32UTruncSatF32: curr = allocator.alloc<Unary>(); curr->op = TruncSatUFloat32ToInt32; break;
- case BinaryConsts::I32STruncSatF64: curr = allocator.alloc<Unary>(); curr->op = TruncSatSFloat64ToInt32; break;
- case BinaryConsts::I32UTruncSatF64: curr = allocator.alloc<Unary>(); curr->op = TruncSatUFloat64ToInt32; break;
- case BinaryConsts::I64STruncSatF32: curr = allocator.alloc<Unary>(); curr->op = TruncSatSFloat32ToInt64; break;
- case BinaryConsts::I64UTruncSatF32: curr = allocator.alloc<Unary>(); curr->op = TruncSatUFloat32ToInt64; break;
- case BinaryConsts::I64STruncSatF64: curr = allocator.alloc<Unary>(); curr->op = TruncSatSFloat64ToInt64; break;
- case BinaryConsts::I64UTruncSatF64: curr = allocator.alloc<Unary>(); curr->op = TruncSatUFloat64ToInt64; break;
- default: return false;
- }
- if (debug) std::cerr << "zz node: Unary (nontrapping float-to-int)" << std::endl;
+ case BinaryConsts::I32STruncSatF32:
+ curr = allocator.alloc<Unary>();
+ curr->op = TruncSatSFloat32ToInt32;
+ break;
+ case BinaryConsts::I32UTruncSatF32:
+ curr = allocator.alloc<Unary>();
+ curr->op = TruncSatUFloat32ToInt32;
+ break;
+ case BinaryConsts::I32STruncSatF64:
+ curr = allocator.alloc<Unary>();
+ curr->op = TruncSatSFloat64ToInt32;
+ break;
+ case BinaryConsts::I32UTruncSatF64:
+ curr = allocator.alloc<Unary>();
+ curr->op = TruncSatUFloat64ToInt32;
+ break;
+ case BinaryConsts::I64STruncSatF32:
+ curr = allocator.alloc<Unary>();
+ curr->op = TruncSatSFloat32ToInt64;
+ break;
+ case BinaryConsts::I64UTruncSatF32:
+ curr = allocator.alloc<Unary>();
+ curr->op = TruncSatUFloat32ToInt64;
+ break;
+ case BinaryConsts::I64STruncSatF64:
+ curr = allocator.alloc<Unary>();
+ curr->op = TruncSatSFloat64ToInt64;
+ break;
+ case BinaryConsts::I64UTruncSatF64:
+ curr = allocator.alloc<Unary>();
+ curr->op = TruncSatUFloat64ToInt64;
+ break;
+ default:
+ return false;
+ }
+ if (debug)
+ std::cerr << "zz node: Unary (nontrapping float-to-int)" << std::endl;
curr->value = popNonVoidExpression();
curr->finalize();
out = curr;
@@ -2445,18 +3205,33 @@ bool WasmBinaryBuilder::maybeVisitMemoryFill(Expression*& out, uint32_t code) {
bool WasmBinaryBuilder::maybeVisitBinary(Expression*& out, uint8_t code) {
Binary* curr;
-#define INT_TYPED_CODE(code) { \
- case BinaryConsts::I32##code: curr = allocator.alloc<Binary>(); curr->op = code##Int32; break; \
- case BinaryConsts::I64##code: curr = allocator.alloc<Binary>(); curr->op = code##Int64; break; \
- }
-#define FLOAT_TYPED_CODE(code) { \
- case BinaryConsts::F32##code: curr = allocator.alloc<Binary>(); curr->op = code##Float32; break; \
- case BinaryConsts::F64##code: curr = allocator.alloc<Binary>(); curr->op = code##Float64; break; \
+#define INT_TYPED_CODE(code) \
+ { \
+ case BinaryConsts::I32##code: \
+ curr = allocator.alloc<Binary>(); \
+ curr->op = code##Int32; \
+ break; \
+ case BinaryConsts::I64##code: \
+ curr = allocator.alloc<Binary>(); \
+ curr->op = code##Int64; \
+ break; \
+ }
+#define FLOAT_TYPED_CODE(code) \
+ { \
+ case BinaryConsts::F32##code: \
+ curr = allocator.alloc<Binary>(); \
+ curr->op = code##Float32; \
+ break; \
+ case BinaryConsts::F64##code: \
+ curr = allocator.alloc<Binary>(); \
+ curr->op = code##Float64; \
+ break; \
+ }
+#define TYPED_CODE(code) \
+ { \
+ INT_TYPED_CODE(code) \
+ FLOAT_TYPED_CODE(code) \
}
-#define TYPED_CODE(code) { \
- INT_TYPED_CODE(code) \
- FLOAT_TYPED_CODE(code) \
- }
switch (code) {
TYPED_CODE(Add);
@@ -2492,9 +3267,11 @@ bool WasmBinaryBuilder::maybeVisitBinary(Expression*& out, uint8_t code) {
FLOAT_TYPED_CODE(Le);
FLOAT_TYPED_CODE(Gt);
FLOAT_TYPED_CODE(Ge);
- default: return false;
+ default:
+ return false;
}
- if (debug) std::cerr << "zz node: Binary" << std::endl;
+ if (debug)
+ std::cerr << "zz node: Binary" << std::endl;
curr->right = popNonVoidExpression();
curr->left = popNonVoidExpression();
curr->finalize();
@@ -2508,85 +3285,315 @@ bool WasmBinaryBuilder::maybeVisitBinary(Expression*& out, uint8_t code) {
bool WasmBinaryBuilder::maybeVisitSIMDBinary(Expression*& out, uint32_t code) {
Binary* curr;
switch (code) {
- case BinaryConsts::I8x16Eq: curr = allocator.alloc<Binary>(); curr->op = EqVecI8x16; break;
- case BinaryConsts::I8x16Ne: curr = allocator.alloc<Binary>(); curr->op = NeVecI8x16; break;
- case BinaryConsts::I8x16LtS: curr = allocator.alloc<Binary>(); curr->op = LtSVecI8x16; break;
- case BinaryConsts::I8x16LtU: curr = allocator.alloc<Binary>(); curr->op = LtUVecI8x16; break;
- case BinaryConsts::I8x16GtS: curr = allocator.alloc<Binary>(); curr->op = GtSVecI8x16; break;
- case BinaryConsts::I8x16GtU: curr = allocator.alloc<Binary>(); curr->op = GtUVecI8x16; break;
- case BinaryConsts::I8x16LeS: curr = allocator.alloc<Binary>(); curr->op = LeSVecI8x16; break;
- case BinaryConsts::I8x16LeU: curr = allocator.alloc<Binary>(); curr->op = LeUVecI8x16; break;
- case BinaryConsts::I8x16GeS: curr = allocator.alloc<Binary>(); curr->op = GeSVecI8x16; break;
- case BinaryConsts::I8x16GeU: curr = allocator.alloc<Binary>(); curr->op = GeUVecI8x16; break;
- case BinaryConsts::I16x8Eq: curr = allocator.alloc<Binary>(); curr->op = EqVecI16x8; break;
- case BinaryConsts::I16x8Ne: curr = allocator.alloc<Binary>(); curr->op = NeVecI16x8; break;
- case BinaryConsts::I16x8LtS: curr = allocator.alloc<Binary>(); curr->op = LtSVecI16x8; break;
- case BinaryConsts::I16x8LtU: curr = allocator.alloc<Binary>(); curr->op = LtUVecI16x8; break;
- case BinaryConsts::I16x8GtS: curr = allocator.alloc<Binary>(); curr->op = GtSVecI16x8; break;
- case BinaryConsts::I16x8GtU: curr = allocator.alloc<Binary>(); curr->op = GtUVecI16x8; break;
- case BinaryConsts::I16x8LeS: curr = allocator.alloc<Binary>(); curr->op = LeSVecI16x8; break;
- case BinaryConsts::I16x8LeU: curr = allocator.alloc<Binary>(); curr->op = LeUVecI16x8; break;
- case BinaryConsts::I16x8GeS: curr = allocator.alloc<Binary>(); curr->op = GeSVecI16x8; break;
- case BinaryConsts::I16x8GeU: curr = allocator.alloc<Binary>(); curr->op = GeUVecI16x8; break;
- case BinaryConsts::I32x4Eq: curr = allocator.alloc<Binary>(); curr->op = EqVecI32x4; break;
- case BinaryConsts::I32x4Ne: curr = allocator.alloc<Binary>(); curr->op = NeVecI32x4; break;
- case BinaryConsts::I32x4LtS: curr = allocator.alloc<Binary>(); curr->op = LtSVecI32x4; break;
- case BinaryConsts::I32x4LtU: curr = allocator.alloc<Binary>(); curr->op = LtUVecI32x4; break;
- case BinaryConsts::I32x4GtS: curr = allocator.alloc<Binary>(); curr->op = GtSVecI32x4; break;
- case BinaryConsts::I32x4GtU: curr = allocator.alloc<Binary>(); curr->op = GtUVecI32x4; break;
- case BinaryConsts::I32x4LeS: curr = allocator.alloc<Binary>(); curr->op = LeSVecI32x4; break;
- case BinaryConsts::I32x4LeU: curr = allocator.alloc<Binary>(); curr->op = LeUVecI32x4; break;
- case BinaryConsts::I32x4GeS: curr = allocator.alloc<Binary>(); curr->op = GeSVecI32x4; break;
- case BinaryConsts::I32x4GeU: curr = allocator.alloc<Binary>(); curr->op = GeUVecI32x4; break;
- case BinaryConsts::F32x4Eq: curr = allocator.alloc<Binary>(); curr->op = EqVecF32x4; break;
- case BinaryConsts::F32x4Ne: curr = allocator.alloc<Binary>(); curr->op = NeVecF32x4; break;
- case BinaryConsts::F32x4Lt: curr = allocator.alloc<Binary>(); curr->op = LtVecF32x4; break;
- case BinaryConsts::F32x4Gt: curr = allocator.alloc<Binary>(); curr->op = GtVecF32x4; break;
- case BinaryConsts::F32x4Le: curr = allocator.alloc<Binary>(); curr->op = LeVecF32x4; break;
- case BinaryConsts::F32x4Ge: curr = allocator.alloc<Binary>(); curr->op = GeVecF32x4; break;
- case BinaryConsts::F64x2Eq: curr = allocator.alloc<Binary>(); curr->op = EqVecF64x2; break;
- case BinaryConsts::F64x2Ne: curr = allocator.alloc<Binary>(); curr->op = NeVecF64x2; break;
- case BinaryConsts::F64x2Lt: curr = allocator.alloc<Binary>(); curr->op = LtVecF64x2; break;
- case BinaryConsts::F64x2Gt: curr = allocator.alloc<Binary>(); curr->op = GtVecF64x2; break;
- case BinaryConsts::F64x2Le: curr = allocator.alloc<Binary>(); curr->op = LeVecF64x2; break;
- case BinaryConsts::F64x2Ge: curr = allocator.alloc<Binary>(); curr->op = GeVecF64x2; break;
- case BinaryConsts::V128And: curr = allocator.alloc<Binary>(); curr->op = AndVec128; break;
- case BinaryConsts::V128Or: curr = allocator.alloc<Binary>(); curr->op = OrVec128; break;
- case BinaryConsts::V128Xor: curr = allocator.alloc<Binary>(); curr->op = XorVec128; break;
- case BinaryConsts::I8x16Add: curr = allocator.alloc<Binary>(); curr->op = AddVecI8x16; break;
- case BinaryConsts::I8x16AddSatS: curr = allocator.alloc<Binary>(); curr->op = AddSatSVecI8x16; break;
- case BinaryConsts::I8x16AddSatU: curr = allocator.alloc<Binary>(); curr->op = AddSatUVecI8x16; break;
- case BinaryConsts::I8x16Sub: curr = allocator.alloc<Binary>(); curr->op = SubVecI8x16; break;
- case BinaryConsts::I8x16SubSatS: curr = allocator.alloc<Binary>(); curr->op = SubSatSVecI8x16; break;
- case BinaryConsts::I8x16SubSatU: curr = allocator.alloc<Binary>(); curr->op = SubSatUVecI8x16; break;
- case BinaryConsts::I8x16Mul: curr = allocator.alloc<Binary>(); curr->op = MulVecI8x16; break;
- case BinaryConsts::I16x8Add: curr = allocator.alloc<Binary>(); curr->op = AddVecI16x8; break;
- case BinaryConsts::I16x8AddSatS: curr = allocator.alloc<Binary>(); curr->op = AddSatSVecI16x8; break;
- case BinaryConsts::I16x8AddSatU: curr = allocator.alloc<Binary>(); curr->op = AddSatUVecI16x8; break;
- case BinaryConsts::I16x8Sub: curr = allocator.alloc<Binary>(); curr->op = SubVecI16x8; break;
- case BinaryConsts::I16x8SubSatS: curr = allocator.alloc<Binary>(); curr->op = SubSatSVecI16x8; break;
- case BinaryConsts::I16x8SubSatU: curr = allocator.alloc<Binary>(); curr->op = SubSatUVecI16x8; break;
- case BinaryConsts::I16x8Mul: curr = allocator.alloc<Binary>(); curr->op = MulVecI16x8; break;
- case BinaryConsts::I32x4Add: curr = allocator.alloc<Binary>(); curr->op = AddVecI32x4; break;
- case BinaryConsts::I32x4Sub: curr = allocator.alloc<Binary>(); curr->op = SubVecI32x4; break;
- case BinaryConsts::I32x4Mul: curr = allocator.alloc<Binary>(); curr->op = MulVecI32x4; break;
- case BinaryConsts::I64x2Add: curr = allocator.alloc<Binary>(); curr->op = AddVecI64x2; break;
- case BinaryConsts::I64x2Sub: curr = allocator.alloc<Binary>(); curr->op = SubVecI64x2; break;
- case BinaryConsts::F32x4Add: curr = allocator.alloc<Binary>(); curr->op = AddVecF32x4; break;
- case BinaryConsts::F32x4Sub: curr = allocator.alloc<Binary>(); curr->op = SubVecF32x4; break;
- case BinaryConsts::F32x4Mul: curr = allocator.alloc<Binary>(); curr->op = MulVecF32x4; break;
- case BinaryConsts::F32x4Div: curr = allocator.alloc<Binary>(); curr->op = DivVecF32x4; break;
- case BinaryConsts::F32x4Min: curr = allocator.alloc<Binary>(); curr->op = MinVecF32x4; break;
- case BinaryConsts::F32x4Max: curr = allocator.alloc<Binary>(); curr->op = MaxVecF32x4; break;
- case BinaryConsts::F64x2Add: curr = allocator.alloc<Binary>(); curr->op = AddVecF64x2; break;
- case BinaryConsts::F64x2Sub: curr = allocator.alloc<Binary>(); curr->op = SubVecF64x2; break;
- case BinaryConsts::F64x2Mul: curr = allocator.alloc<Binary>(); curr->op = MulVecF64x2; break;
- case BinaryConsts::F64x2Div: curr = allocator.alloc<Binary>(); curr->op = DivVecF64x2; break;
- case BinaryConsts::F64x2Min: curr = allocator.alloc<Binary>(); curr->op = MinVecF64x2; break;
- case BinaryConsts::F64x2Max: curr = allocator.alloc<Binary>(); curr->op = MaxVecF64x2; break;
- default: return false;
- }
- if (debug) std::cerr << "zz node: Binary" << std::endl;
+ case BinaryConsts::I8x16Eq:
+ curr = allocator.alloc<Binary>();
+ curr->op = EqVecI8x16;
+ break;
+ case BinaryConsts::I8x16Ne:
+ curr = allocator.alloc<Binary>();
+ curr->op = NeVecI8x16;
+ break;
+ case BinaryConsts::I8x16LtS:
+ curr = allocator.alloc<Binary>();
+ curr->op = LtSVecI8x16;
+ break;
+ case BinaryConsts::I8x16LtU:
+ curr = allocator.alloc<Binary>();
+ curr->op = LtUVecI8x16;
+ break;
+ case BinaryConsts::I8x16GtS:
+ curr = allocator.alloc<Binary>();
+ curr->op = GtSVecI8x16;
+ break;
+ case BinaryConsts::I8x16GtU:
+ curr = allocator.alloc<Binary>();
+ curr->op = GtUVecI8x16;
+ break;
+ case BinaryConsts::I8x16LeS:
+ curr = allocator.alloc<Binary>();
+ curr->op = LeSVecI8x16;
+ break;
+ case BinaryConsts::I8x16LeU:
+ curr = allocator.alloc<Binary>();
+ curr->op = LeUVecI8x16;
+ break;
+ case BinaryConsts::I8x16GeS:
+ curr = allocator.alloc<Binary>();
+ curr->op = GeSVecI8x16;
+ break;
+ case BinaryConsts::I8x16GeU:
+ curr = allocator.alloc<Binary>();
+ curr->op = GeUVecI8x16;
+ break;
+ case BinaryConsts::I16x8Eq:
+ curr = allocator.alloc<Binary>();
+ curr->op = EqVecI16x8;
+ break;
+ case BinaryConsts::I16x8Ne:
+ curr = allocator.alloc<Binary>();
+ curr->op = NeVecI16x8;
+ break;
+ case BinaryConsts::I16x8LtS:
+ curr = allocator.alloc<Binary>();
+ curr->op = LtSVecI16x8;
+ break;
+ case BinaryConsts::I16x8LtU:
+ curr = allocator.alloc<Binary>();
+ curr->op = LtUVecI16x8;
+ break;
+ case BinaryConsts::I16x8GtS:
+ curr = allocator.alloc<Binary>();
+ curr->op = GtSVecI16x8;
+ break;
+ case BinaryConsts::I16x8GtU:
+ curr = allocator.alloc<Binary>();
+ curr->op = GtUVecI16x8;
+ break;
+ case BinaryConsts::I16x8LeS:
+ curr = allocator.alloc<Binary>();
+ curr->op = LeSVecI16x8;
+ break;
+ case BinaryConsts::I16x8LeU:
+ curr = allocator.alloc<Binary>();
+ curr->op = LeUVecI16x8;
+ break;
+ case BinaryConsts::I16x8GeS:
+ curr = allocator.alloc<Binary>();
+ curr->op = GeSVecI16x8;
+ break;
+ case BinaryConsts::I16x8GeU:
+ curr = allocator.alloc<Binary>();
+ curr->op = GeUVecI16x8;
+ break;
+ case BinaryConsts::I32x4Eq:
+ curr = allocator.alloc<Binary>();
+ curr->op = EqVecI32x4;
+ break;
+ case BinaryConsts::I32x4Ne:
+ curr = allocator.alloc<Binary>();
+ curr->op = NeVecI32x4;
+ break;
+ case BinaryConsts::I32x4LtS:
+ curr = allocator.alloc<Binary>();
+ curr->op = LtSVecI32x4;
+ break;
+ case BinaryConsts::I32x4LtU:
+ curr = allocator.alloc<Binary>();
+ curr->op = LtUVecI32x4;
+ break;
+ case BinaryConsts::I32x4GtS:
+ curr = allocator.alloc<Binary>();
+ curr->op = GtSVecI32x4;
+ break;
+ case BinaryConsts::I32x4GtU:
+ curr = allocator.alloc<Binary>();
+ curr->op = GtUVecI32x4;
+ break;
+ case BinaryConsts::I32x4LeS:
+ curr = allocator.alloc<Binary>();
+ curr->op = LeSVecI32x4;
+ break;
+ case BinaryConsts::I32x4LeU:
+ curr = allocator.alloc<Binary>();
+ curr->op = LeUVecI32x4;
+ break;
+ case BinaryConsts::I32x4GeS:
+ curr = allocator.alloc<Binary>();
+ curr->op = GeSVecI32x4;
+ break;
+ case BinaryConsts::I32x4GeU:
+ curr = allocator.alloc<Binary>();
+ curr->op = GeUVecI32x4;
+ break;
+ case BinaryConsts::F32x4Eq:
+ curr = allocator.alloc<Binary>();
+ curr->op = EqVecF32x4;
+ break;
+ case BinaryConsts::F32x4Ne:
+ curr = allocator.alloc<Binary>();
+ curr->op = NeVecF32x4;
+ break;
+ case BinaryConsts::F32x4Lt:
+ curr = allocator.alloc<Binary>();
+ curr->op = LtVecF32x4;
+ break;
+ case BinaryConsts::F32x4Gt:
+ curr = allocator.alloc<Binary>();
+ curr->op = GtVecF32x4;
+ break;
+ case BinaryConsts::F32x4Le:
+ curr = allocator.alloc<Binary>();
+ curr->op = LeVecF32x4;
+ break;
+ case BinaryConsts::F32x4Ge:
+ curr = allocator.alloc<Binary>();
+ curr->op = GeVecF32x4;
+ break;
+ case BinaryConsts::F64x2Eq:
+ curr = allocator.alloc<Binary>();
+ curr->op = EqVecF64x2;
+ break;
+ case BinaryConsts::F64x2Ne:
+ curr = allocator.alloc<Binary>();
+ curr->op = NeVecF64x2;
+ break;
+ case BinaryConsts::F64x2Lt:
+ curr = allocator.alloc<Binary>();
+ curr->op = LtVecF64x2;
+ break;
+ case BinaryConsts::F64x2Gt:
+ curr = allocator.alloc<Binary>();
+ curr->op = GtVecF64x2;
+ break;
+ case BinaryConsts::F64x2Le:
+ curr = allocator.alloc<Binary>();
+ curr->op = LeVecF64x2;
+ break;
+ case BinaryConsts::F64x2Ge:
+ curr = allocator.alloc<Binary>();
+ curr->op = GeVecF64x2;
+ break;
+ case BinaryConsts::V128And:
+ curr = allocator.alloc<Binary>();
+ curr->op = AndVec128;
+ break;
+ case BinaryConsts::V128Or:
+ curr = allocator.alloc<Binary>();
+ curr->op = OrVec128;
+ break;
+ case BinaryConsts::V128Xor:
+ curr = allocator.alloc<Binary>();
+ curr->op = XorVec128;
+ break;
+ case BinaryConsts::I8x16Add:
+ curr = allocator.alloc<Binary>();
+ curr->op = AddVecI8x16;
+ break;
+ case BinaryConsts::I8x16AddSatS:
+ curr = allocator.alloc<Binary>();
+ curr->op = AddSatSVecI8x16;
+ break;
+ case BinaryConsts::I8x16AddSatU:
+ curr = allocator.alloc<Binary>();
+ curr->op = AddSatUVecI8x16;
+ break;
+ case BinaryConsts::I8x16Sub:
+ curr = allocator.alloc<Binary>();
+ curr->op = SubVecI8x16;
+ break;
+ case BinaryConsts::I8x16SubSatS:
+ curr = allocator.alloc<Binary>();
+ curr->op = SubSatSVecI8x16;
+ break;
+ case BinaryConsts::I8x16SubSatU:
+ curr = allocator.alloc<Binary>();
+ curr->op = SubSatUVecI8x16;
+ break;
+ case BinaryConsts::I8x16Mul:
+ curr = allocator.alloc<Binary>();
+ curr->op = MulVecI8x16;
+ break;
+ case BinaryConsts::I16x8Add:
+ curr = allocator.alloc<Binary>();
+ curr->op = AddVecI16x8;
+ break;
+ case BinaryConsts::I16x8AddSatS:
+ curr = allocator.alloc<Binary>();
+ curr->op = AddSatSVecI16x8;
+ break;
+ case BinaryConsts::I16x8AddSatU:
+ curr = allocator.alloc<Binary>();
+ curr->op = AddSatUVecI16x8;
+ break;
+ case BinaryConsts::I16x8Sub:
+ curr = allocator.alloc<Binary>();
+ curr->op = SubVecI16x8;
+ break;
+ case BinaryConsts::I16x8SubSatS:
+ curr = allocator.alloc<Binary>();
+ curr->op = SubSatSVecI16x8;
+ break;
+ case BinaryConsts::I16x8SubSatU:
+ curr = allocator.alloc<Binary>();
+ curr->op = SubSatUVecI16x8;
+ break;
+ case BinaryConsts::I16x8Mul:
+ curr = allocator.alloc<Binary>();
+ curr->op = MulVecI16x8;
+ break;
+ case BinaryConsts::I32x4Add:
+ curr = allocator.alloc<Binary>();
+ curr->op = AddVecI32x4;
+ break;
+ case BinaryConsts::I32x4Sub:
+ curr = allocator.alloc<Binary>();
+ curr->op = SubVecI32x4;
+ break;
+ case BinaryConsts::I32x4Mul:
+ curr = allocator.alloc<Binary>();
+ curr->op = MulVecI32x4;
+ break;
+ case BinaryConsts::I64x2Add:
+ curr = allocator.alloc<Binary>();
+ curr->op = AddVecI64x2;
+ break;
+ case BinaryConsts::I64x2Sub:
+ curr = allocator.alloc<Binary>();
+ curr->op = SubVecI64x2;
+ break;
+ case BinaryConsts::F32x4Add:
+ curr = allocator.alloc<Binary>();
+ curr->op = AddVecF32x4;
+ break;
+ case BinaryConsts::F32x4Sub:
+ curr = allocator.alloc<Binary>();
+ curr->op = SubVecF32x4;
+ break;
+ case BinaryConsts::F32x4Mul:
+ curr = allocator.alloc<Binary>();
+ curr->op = MulVecF32x4;
+ break;
+ case BinaryConsts::F32x4Div:
+ curr = allocator.alloc<Binary>();
+ curr->op = DivVecF32x4;
+ break;
+ case BinaryConsts::F32x4Min:
+ curr = allocator.alloc<Binary>();
+ curr->op = MinVecF32x4;
+ break;
+ case BinaryConsts::F32x4Max:
+ curr = allocator.alloc<Binary>();
+ curr->op = MaxVecF32x4;
+ break;
+ case BinaryConsts::F64x2Add:
+ curr = allocator.alloc<Binary>();
+ curr->op = AddVecF64x2;
+ break;
+ case BinaryConsts::F64x2Sub:
+ curr = allocator.alloc<Binary>();
+ curr->op = SubVecF64x2;
+ break;
+ case BinaryConsts::F64x2Mul:
+ curr = allocator.alloc<Binary>();
+ curr->op = MulVecF64x2;
+ break;
+ case BinaryConsts::F64x2Div:
+ curr = allocator.alloc<Binary>();
+ curr->op = DivVecF64x2;
+ break;
+ case BinaryConsts::F64x2Min:
+ curr = allocator.alloc<Binary>();
+ curr->op = MinVecF64x2;
+ break;
+ case BinaryConsts::F64x2Max:
+ curr = allocator.alloc<Binary>();
+ curr->op = MaxVecF64x2;
+ break;
+ default:
+ return false;
+ }
+ if (debug)
+ std::cerr << "zz node: Binary" << std::endl;
curr->right = popNonVoidExpression();
curr->left = popNonVoidExpression();
curr->finalize();
@@ -2596,40 +3603,140 @@ bool WasmBinaryBuilder::maybeVisitSIMDBinary(Expression*& out, uint32_t code) {
bool WasmBinaryBuilder::maybeVisitSIMDUnary(Expression*& out, uint32_t code) {
Unary* curr;
switch (code) {
- case BinaryConsts::I8x16Splat: curr = allocator.alloc<Unary>(); curr->op = SplatVecI8x16; break;
- case BinaryConsts::I16x8Splat: curr = allocator.alloc<Unary>(); curr->op = SplatVecI16x8; break;
- case BinaryConsts::I32x4Splat: curr = allocator.alloc<Unary>(); curr->op = SplatVecI32x4; break;
- case BinaryConsts::I64x2Splat: curr = allocator.alloc<Unary>(); curr->op = SplatVecI64x2; break;
- case BinaryConsts::F32x4Splat: curr = allocator.alloc<Unary>(); curr->op = SplatVecF32x4; break;
- case BinaryConsts::F64x2Splat: curr = allocator.alloc<Unary>(); curr->op = SplatVecF64x2; break;
- case BinaryConsts::V128Not: curr = allocator.alloc<Unary>(); curr->op = NotVec128; break;
- case BinaryConsts::I8x16Neg: curr = allocator.alloc<Unary>(); curr->op = NegVecI8x16; break;
- case BinaryConsts::I8x16AnyTrue: curr = allocator.alloc<Unary>(); curr->op = AnyTrueVecI8x16; break;
- case BinaryConsts::I8x16AllTrue: curr = allocator.alloc<Unary>(); curr->op = AllTrueVecI8x16; break;
- case BinaryConsts::I16x8Neg: curr = allocator.alloc<Unary>(); curr->op = NegVecI16x8; break;
- case BinaryConsts::I16x8AnyTrue: curr = allocator.alloc<Unary>(); curr->op = AnyTrueVecI16x8; break;
- case BinaryConsts::I16x8AllTrue: curr = allocator.alloc<Unary>(); curr->op = AllTrueVecI16x8; break;
- case BinaryConsts::I32x4Neg: curr = allocator.alloc<Unary>(); curr->op = NegVecI32x4; break;
- case BinaryConsts::I32x4AnyTrue: curr = allocator.alloc<Unary>(); curr->op = AnyTrueVecI32x4; break;
- case BinaryConsts::I32x4AllTrue: curr = allocator.alloc<Unary>(); curr->op = AllTrueVecI32x4; break;
- case BinaryConsts::I64x2Neg: curr = allocator.alloc<Unary>(); curr->op = NegVecI64x2; break;
- case BinaryConsts::I64x2AnyTrue: curr = allocator.alloc<Unary>(); curr->op = AnyTrueVecI64x2; break;
- case BinaryConsts::I64x2AllTrue: curr = allocator.alloc<Unary>(); curr->op = AllTrueVecI64x2; break;
- case BinaryConsts::F32x4Abs: curr = allocator.alloc<Unary>(); curr->op = AbsVecF32x4; break;
- case BinaryConsts::F32x4Neg: curr = allocator.alloc<Unary>(); curr->op = NegVecF32x4; break;
- case BinaryConsts::F32x4Sqrt: curr = allocator.alloc<Unary>(); curr->op = SqrtVecF32x4; break;
- case BinaryConsts::F64x2Abs: curr = allocator.alloc<Unary>(); curr->op = AbsVecF64x2; break;
- case BinaryConsts::F64x2Neg: curr = allocator.alloc<Unary>(); curr->op = NegVecF64x2; break;
- case BinaryConsts::F64x2Sqrt: curr = allocator.alloc<Unary>(); curr->op = SqrtVecF64x2; break;
- case BinaryConsts::I32x4TruncSatSF32x4: curr = allocator.alloc<Unary>(); curr->op = TruncSatSVecF32x4ToVecI32x4; break;
- case BinaryConsts::I32x4TruncSatUF32x4: curr = allocator.alloc<Unary>(); curr->op = TruncSatUVecF32x4ToVecI32x4; break;
- case BinaryConsts::I64x2TruncSatSF64x2: curr = allocator.alloc<Unary>(); curr->op = TruncSatSVecF64x2ToVecI64x2; break;
- case BinaryConsts::I64x2TruncSatUF64x2: curr = allocator.alloc<Unary>(); curr->op = TruncSatUVecF64x2ToVecI64x2; break;
- case BinaryConsts::F32x4ConvertSI32x4: curr = allocator.alloc<Unary>(); curr->op = ConvertSVecI32x4ToVecF32x4; break;
- case BinaryConsts::F32x4ConvertUI32x4: curr = allocator.alloc<Unary>(); curr->op = ConvertUVecI32x4ToVecF32x4; break;
- case BinaryConsts::F64x2ConvertSI64x2: curr = allocator.alloc<Unary>(); curr->op = ConvertSVecI64x2ToVecF64x2; break;
- case BinaryConsts::F64x2ConvertUI64x2: curr = allocator.alloc<Unary>(); curr->op = ConvertUVecI64x2ToVecF64x2; break;
- default: return false;
+ case BinaryConsts::I8x16Splat:
+ curr = allocator.alloc<Unary>();
+ curr->op = SplatVecI8x16;
+ break;
+ case BinaryConsts::I16x8Splat:
+ curr = allocator.alloc<Unary>();
+ curr->op = SplatVecI16x8;
+ break;
+ case BinaryConsts::I32x4Splat:
+ curr = allocator.alloc<Unary>();
+ curr->op = SplatVecI32x4;
+ break;
+ case BinaryConsts::I64x2Splat:
+ curr = allocator.alloc<Unary>();
+ curr->op = SplatVecI64x2;
+ break;
+ case BinaryConsts::F32x4Splat:
+ curr = allocator.alloc<Unary>();
+ curr->op = SplatVecF32x4;
+ break;
+ case BinaryConsts::F64x2Splat:
+ curr = allocator.alloc<Unary>();
+ curr->op = SplatVecF64x2;
+ break;
+ case BinaryConsts::V128Not:
+ curr = allocator.alloc<Unary>();
+ curr->op = NotVec128;
+ break;
+ case BinaryConsts::I8x16Neg:
+ curr = allocator.alloc<Unary>();
+ curr->op = NegVecI8x16;
+ break;
+ case BinaryConsts::I8x16AnyTrue:
+ curr = allocator.alloc<Unary>();
+ curr->op = AnyTrueVecI8x16;
+ break;
+ case BinaryConsts::I8x16AllTrue:
+ curr = allocator.alloc<Unary>();
+ curr->op = AllTrueVecI8x16;
+ break;
+ case BinaryConsts::I16x8Neg:
+ curr = allocator.alloc<Unary>();
+ curr->op = NegVecI16x8;
+ break;
+ case BinaryConsts::I16x8AnyTrue:
+ curr = allocator.alloc<Unary>();
+ curr->op = AnyTrueVecI16x8;
+ break;
+ case BinaryConsts::I16x8AllTrue:
+ curr = allocator.alloc<Unary>();
+ curr->op = AllTrueVecI16x8;
+ break;
+ case BinaryConsts::I32x4Neg:
+ curr = allocator.alloc<Unary>();
+ curr->op = NegVecI32x4;
+ break;
+ case BinaryConsts::I32x4AnyTrue:
+ curr = allocator.alloc<Unary>();
+ curr->op = AnyTrueVecI32x4;
+ break;
+ case BinaryConsts::I32x4AllTrue:
+ curr = allocator.alloc<Unary>();
+ curr->op = AllTrueVecI32x4;
+ break;
+ case BinaryConsts::I64x2Neg:
+ curr = allocator.alloc<Unary>();
+ curr->op = NegVecI64x2;
+ break;
+ case BinaryConsts::I64x2AnyTrue:
+ curr = allocator.alloc<Unary>();
+ curr->op = AnyTrueVecI64x2;
+ break;
+ case BinaryConsts::I64x2AllTrue:
+ curr = allocator.alloc<Unary>();
+ curr->op = AllTrueVecI64x2;
+ break;
+ case BinaryConsts::F32x4Abs:
+ curr = allocator.alloc<Unary>();
+ curr->op = AbsVecF32x4;
+ break;
+ case BinaryConsts::F32x4Neg:
+ curr = allocator.alloc<Unary>();
+ curr->op = NegVecF32x4;
+ break;
+ case BinaryConsts::F32x4Sqrt:
+ curr = allocator.alloc<Unary>();
+ curr->op = SqrtVecF32x4;
+ break;
+ case BinaryConsts::F64x2Abs:
+ curr = allocator.alloc<Unary>();
+ curr->op = AbsVecF64x2;
+ break;
+ case BinaryConsts::F64x2Neg:
+ curr = allocator.alloc<Unary>();
+ curr->op = NegVecF64x2;
+ break;
+ case BinaryConsts::F64x2Sqrt:
+ curr = allocator.alloc<Unary>();
+ curr->op = SqrtVecF64x2;
+ break;
+ case BinaryConsts::I32x4TruncSatSF32x4:
+ curr = allocator.alloc<Unary>();
+ curr->op = TruncSatSVecF32x4ToVecI32x4;
+ break;
+ case BinaryConsts::I32x4TruncSatUF32x4:
+ curr = allocator.alloc<Unary>();
+ curr->op = TruncSatUVecF32x4ToVecI32x4;
+ break;
+ case BinaryConsts::I64x2TruncSatSF64x2:
+ curr = allocator.alloc<Unary>();
+ curr->op = TruncSatSVecF64x2ToVecI64x2;
+ break;
+ case BinaryConsts::I64x2TruncSatUF64x2:
+ curr = allocator.alloc<Unary>();
+ curr->op = TruncSatUVecF64x2ToVecI64x2;
+ break;
+ case BinaryConsts::F32x4ConvertSI32x4:
+ curr = allocator.alloc<Unary>();
+ curr->op = ConvertSVecI32x4ToVecF32x4;
+ break;
+ case BinaryConsts::F32x4ConvertUI32x4:
+ curr = allocator.alloc<Unary>();
+ curr->op = ConvertUVecI32x4ToVecF32x4;
+ break;
+ case BinaryConsts::F64x2ConvertSI64x2:
+ curr = allocator.alloc<Unary>();
+ curr->op = ConvertSVecI64x2ToVecF64x2;
+ break;
+ case BinaryConsts::F64x2ConvertUI64x2:
+ curr = allocator.alloc<Unary>();
+ curr->op = ConvertUVecI64x2ToVecF64x2;
+ break;
+ default:
+ return false;
}
curr->value = popNonVoidExpression();
curr->finalize();
@@ -2682,15 +3789,48 @@ bool WasmBinaryBuilder::maybeVisitSIMDStore(Expression*& out, uint32_t code) {
bool WasmBinaryBuilder::maybeVisitSIMDExtract(Expression*& out, uint32_t code) {
SIMDExtract* curr;
switch (code) {
- case BinaryConsts::I8x16ExtractLaneS: curr = allocator.alloc<SIMDExtract>(); curr->op = ExtractLaneSVecI8x16; curr->index = getLaneIndex(16); break;
- case BinaryConsts::I8x16ExtractLaneU: curr = allocator.alloc<SIMDExtract>(); curr->op = ExtractLaneUVecI8x16; curr->index = getLaneIndex(16); break;
- case BinaryConsts::I16x8ExtractLaneS: curr = allocator.alloc<SIMDExtract>(); curr->op = ExtractLaneSVecI16x8; curr->index = getLaneIndex(8); break;
- case BinaryConsts::I16x8ExtractLaneU: curr = allocator.alloc<SIMDExtract>(); curr->op = ExtractLaneUVecI16x8; curr->index = getLaneIndex(8); break;
- case BinaryConsts::I32x4ExtractLane: curr = allocator.alloc<SIMDExtract>(); curr->op = ExtractLaneVecI32x4; curr->index = getLaneIndex(4); break;
- case BinaryConsts::I64x2ExtractLane: curr = allocator.alloc<SIMDExtract>(); curr->op = ExtractLaneVecI64x2; curr->index = getLaneIndex(2); break;
- case BinaryConsts::F32x4ExtractLane: curr = allocator.alloc<SIMDExtract>(); curr->op = ExtractLaneVecF32x4; curr->index = getLaneIndex(4); break;
- case BinaryConsts::F64x2ExtractLane: curr = allocator.alloc<SIMDExtract>(); curr->op = ExtractLaneVecF64x2; curr->index = getLaneIndex(2); break;
- default: return false;
+ case BinaryConsts::I8x16ExtractLaneS:
+ curr = allocator.alloc<SIMDExtract>();
+ curr->op = ExtractLaneSVecI8x16;
+ curr->index = getLaneIndex(16);
+ break;
+ case BinaryConsts::I8x16ExtractLaneU:
+ curr = allocator.alloc<SIMDExtract>();
+ curr->op = ExtractLaneUVecI8x16;
+ curr->index = getLaneIndex(16);
+ break;
+ case BinaryConsts::I16x8ExtractLaneS:
+ curr = allocator.alloc<SIMDExtract>();
+ curr->op = ExtractLaneSVecI16x8;
+ curr->index = getLaneIndex(8);
+ break;
+ case BinaryConsts::I16x8ExtractLaneU:
+ curr = allocator.alloc<SIMDExtract>();
+ curr->op = ExtractLaneUVecI16x8;
+ curr->index = getLaneIndex(8);
+ break;
+ case BinaryConsts::I32x4ExtractLane:
+ curr = allocator.alloc<SIMDExtract>();
+ curr->op = ExtractLaneVecI32x4;
+ curr->index = getLaneIndex(4);
+ break;
+ case BinaryConsts::I64x2ExtractLane:
+ curr = allocator.alloc<SIMDExtract>();
+ curr->op = ExtractLaneVecI64x2;
+ curr->index = getLaneIndex(2);
+ break;
+ case BinaryConsts::F32x4ExtractLane:
+ curr = allocator.alloc<SIMDExtract>();
+ curr->op = ExtractLaneVecF32x4;
+ curr->index = getLaneIndex(4);
+ break;
+ case BinaryConsts::F64x2ExtractLane:
+ curr = allocator.alloc<SIMDExtract>();
+ curr->op = ExtractLaneVecF64x2;
+ curr->index = getLaneIndex(2);
+ break;
+ default:
+ return false;
}
curr->vec = popNonVoidExpression();
curr->finalize();
@@ -2701,13 +3841,38 @@ bool WasmBinaryBuilder::maybeVisitSIMDExtract(Expression*& out, uint32_t code) {
bool WasmBinaryBuilder::maybeVisitSIMDReplace(Expression*& out, uint32_t code) {
SIMDReplace* curr;
switch (code) {
- case BinaryConsts::I8x16ReplaceLane: curr = allocator.alloc<SIMDReplace>(); curr->op = ReplaceLaneVecI8x16; curr->index = getLaneIndex(16); break;
- case BinaryConsts::I16x8ReplaceLane: curr = allocator.alloc<SIMDReplace>(); curr->op = ReplaceLaneVecI16x8; curr->index = getLaneIndex(8); break;
- case BinaryConsts::I32x4ReplaceLane: curr = allocator.alloc<SIMDReplace>(); curr->op = ReplaceLaneVecI32x4; curr->index = getLaneIndex(4); break;
- case BinaryConsts::I64x2ReplaceLane: curr = allocator.alloc<SIMDReplace>(); curr->op = ReplaceLaneVecI64x2; curr->index = getLaneIndex(2); break;
- case BinaryConsts::F32x4ReplaceLane: curr = allocator.alloc<SIMDReplace>(); curr->op = ReplaceLaneVecF32x4; curr->index = getLaneIndex(4); break;
- case BinaryConsts::F64x2ReplaceLane: curr = allocator.alloc<SIMDReplace>(); curr->op = ReplaceLaneVecF64x2; curr->index = getLaneIndex(2); break;
- default: return false;
+ case BinaryConsts::I8x16ReplaceLane:
+ curr = allocator.alloc<SIMDReplace>();
+ curr->op = ReplaceLaneVecI8x16;
+ curr->index = getLaneIndex(16);
+ break;
+ case BinaryConsts::I16x8ReplaceLane:
+ curr = allocator.alloc<SIMDReplace>();
+ curr->op = ReplaceLaneVecI16x8;
+ curr->index = getLaneIndex(8);
+ break;
+ case BinaryConsts::I32x4ReplaceLane:
+ curr = allocator.alloc<SIMDReplace>();
+ curr->op = ReplaceLaneVecI32x4;
+ curr->index = getLaneIndex(4);
+ break;
+ case BinaryConsts::I64x2ReplaceLane:
+ curr = allocator.alloc<SIMDReplace>();
+ curr->op = ReplaceLaneVecI64x2;
+ curr->index = getLaneIndex(2);
+ break;
+ case BinaryConsts::F32x4ReplaceLane:
+ curr = allocator.alloc<SIMDReplace>();
+ curr->op = ReplaceLaneVecF32x4;
+ curr->index = getLaneIndex(4);
+ break;
+ case BinaryConsts::F64x2ReplaceLane:
+ curr = allocator.alloc<SIMDReplace>();
+ curr->op = ReplaceLaneVecF64x2;
+ curr->index = getLaneIndex(2);
+ break;
+ default:
+ return false;
}
curr->value = popNonVoidExpression();
curr->vec = popNonVoidExpression();
@@ -2731,7 +3896,8 @@ bool WasmBinaryBuilder::maybeVisitSIMDShuffle(Expression*& out, uint32_t code) {
return true;
}
-bool WasmBinaryBuilder::maybeVisitSIMDBitselect(Expression*& out, uint32_t code) {
+bool WasmBinaryBuilder::maybeVisitSIMDBitselect(Expression*& out,
+ uint32_t code) {
if (code != BinaryConsts::V128Bitselect) {
return false;
}
@@ -2747,19 +3913,56 @@ bool WasmBinaryBuilder::maybeVisitSIMDBitselect(Expression*& out, uint32_t code)
bool WasmBinaryBuilder::maybeVisitSIMDShift(Expression*& out, uint32_t code) {
SIMDShift* curr;
switch (code) {
- case BinaryConsts::I8x16Shl: curr = allocator.alloc<SIMDShift>(); curr->op = ShlVecI8x16; break;
- case BinaryConsts::I8x16ShrS: curr = allocator.alloc<SIMDShift>(); curr->op = ShrSVecI8x16; break;
- case BinaryConsts::I8x16ShrU: curr = allocator.alloc<SIMDShift>(); curr->op = ShrUVecI8x16; break;
- case BinaryConsts::I16x8Shl: curr = allocator.alloc<SIMDShift>(); curr->op = ShlVecI16x8; break;
- case BinaryConsts::I16x8ShrS: curr = allocator.alloc<SIMDShift>(); curr->op = ShrSVecI16x8; break;
- case BinaryConsts::I16x8ShrU: curr = allocator.alloc<SIMDShift>(); curr->op = ShrUVecI16x8; break;
- case BinaryConsts::I32x4Shl: curr = allocator.alloc<SIMDShift>(); curr->op = ShlVecI32x4; break;
- case BinaryConsts::I32x4ShrS: curr = allocator.alloc<SIMDShift>(); curr->op = ShrSVecI32x4; break;
- case BinaryConsts::I32x4ShrU: curr = allocator.alloc<SIMDShift>(); curr->op = ShrUVecI32x4; break;
- case BinaryConsts::I64x2Shl: curr = allocator.alloc<SIMDShift>(); curr->op = ShlVecI64x2; break;
- case BinaryConsts::I64x2ShrS: curr = allocator.alloc<SIMDShift>(); curr->op = ShrSVecI64x2; break;
- case BinaryConsts::I64x2ShrU: curr = allocator.alloc<SIMDShift>(); curr->op = ShrUVecI64x2; break;
- default: return false;
+ case BinaryConsts::I8x16Shl:
+ curr = allocator.alloc<SIMDShift>();
+ curr->op = ShlVecI8x16;
+ break;
+ case BinaryConsts::I8x16ShrS:
+ curr = allocator.alloc<SIMDShift>();
+ curr->op = ShrSVecI8x16;
+ break;
+ case BinaryConsts::I8x16ShrU:
+ curr = allocator.alloc<SIMDShift>();
+ curr->op = ShrUVecI8x16;
+ break;
+ case BinaryConsts::I16x8Shl:
+ curr = allocator.alloc<SIMDShift>();
+ curr->op = ShlVecI16x8;
+ break;
+ case BinaryConsts::I16x8ShrS:
+ curr = allocator.alloc<SIMDShift>();
+ curr->op = ShrSVecI16x8;
+ break;
+ case BinaryConsts::I16x8ShrU:
+ curr = allocator.alloc<SIMDShift>();
+ curr->op = ShrUVecI16x8;
+ break;
+ case BinaryConsts::I32x4Shl:
+ curr = allocator.alloc<SIMDShift>();
+ curr->op = ShlVecI32x4;
+ break;
+ case BinaryConsts::I32x4ShrS:
+ curr = allocator.alloc<SIMDShift>();
+ curr->op = ShrSVecI32x4;
+ break;
+ case BinaryConsts::I32x4ShrU:
+ curr = allocator.alloc<SIMDShift>();
+ curr->op = ShrUVecI32x4;
+ break;
+ case BinaryConsts::I64x2Shl:
+ curr = allocator.alloc<SIMDShift>();
+ curr->op = ShlVecI64x2;
+ break;
+ case BinaryConsts::I64x2ShrS:
+ curr = allocator.alloc<SIMDShift>();
+ curr->op = ShrSVecI64x2;
+ break;
+ case BinaryConsts::I64x2ShrU:
+ curr = allocator.alloc<SIMDShift>();
+ curr->op = ShrUVecI64x2;
+ break;
+ default:
+ return false;
}
curr->shift = popNonVoidExpression();
curr->vec = popNonVoidExpression();
@@ -2769,7 +3972,8 @@ bool WasmBinaryBuilder::maybeVisitSIMDShift(Expression*& out, uint32_t code) {
}
void WasmBinaryBuilder::visitSelect(Select* curr) {
- if (debug) std::cerr << "zz node: Select" << std::endl;
+ if (debug)
+ std::cerr << "zz node: Select" << std::endl;
curr->condition = popNonVoidExpression();
curr->ifFalse = popNonVoidExpression();
curr->ifTrue = popNonVoidExpression();
@@ -2777,7 +3981,8 @@ void WasmBinaryBuilder::visitSelect(Select* curr) {
}
void WasmBinaryBuilder::visitReturn(Return* curr) {
- if (debug) std::cerr << "zz node: Return" << std::endl;
+ if (debug)
+ std::cerr << "zz node: Return" << std::endl;
requireFunctionContext("return");
if (currFunction->result != none) {
curr->value = popNonVoidExpression();
@@ -2800,26 +4005,32 @@ bool WasmBinaryBuilder::maybeVisitHost(Expression*& out, uint8_t code) {
curr->operands[0] = popNonVoidExpression();
break;
}
- default: return false;
+ default:
+ return false;
}
- if (debug) std::cerr << "zz node: Host" << std::endl;
+ if (debug)
+ std::cerr << "zz node: Host" << std::endl;
auto reserved = getU32LEB();
- if (reserved != 0) throwError("Invalid reserved field on grow_memory/current_memory");
+ if (reserved != 0)
+ throwError("Invalid reserved field on grow_memory/current_memory");
curr->finalize();
out = curr;
return true;
}
void WasmBinaryBuilder::visitNop(Nop* curr) {
- if (debug) std::cerr << "zz node: Nop" << std::endl;
+ if (debug)
+ std::cerr << "zz node: Nop" << std::endl;
}
void WasmBinaryBuilder::visitUnreachable(Unreachable* curr) {
- if (debug) std::cerr << "zz node: Unreachable" << std::endl;
+ if (debug)
+ std::cerr << "zz node: Unreachable" << std::endl;
}
void WasmBinaryBuilder::visitDrop(Drop* curr) {
- if (debug) std::cerr << "zz node: Drop" << std::endl;
+ if (debug)
+ std::cerr << "zz node: Drop" << std::endl;
curr->value = popNonVoidExpression();
curr->finalize();
}
diff --git a/src/wasm/wasm-emscripten.cpp b/src/wasm/wasm-emscripten.cpp
index a66c8d1ac..c1bb36338 100644
--- a/src/wasm/wasm-emscripten.cpp
+++ b/src/wasm/wasm-emscripten.cpp
@@ -20,25 +20,25 @@
#include "asm_v_wasm.h"
#include "asmjs/shared-constants.h"
+#include "ir/function-type-utils.h"
+#include "ir/import-utils.h"
+#include "ir/module-utils.h"
#include "shared-constants.h"
#include "wasm-builder.h"
#include "wasm-traversal.h"
#include "wasm.h"
-#include "ir/function-type-utils.h"
-#include "ir/import-utils.h"
-#include "ir/module-utils.h"
namespace wasm {
cashew::IString EMSCRIPTEN_ASM_CONST("emscripten_asm_const");
cashew::IString EM_JS_PREFIX("__em_js__");
-static Name STACK_SAVE("stackSave"),
- STACK_RESTORE("stackRestore"),
- STACK_ALLOC("stackAlloc"),
- STACK_INIT("stack$init"),
- POST_INSTANTIATE("__post_instantiate"),
- ASSIGN_GOT_ENTIRES("__assign_got_enties");
+static Name STACK_SAVE("stackSave");
+static Name STACK_RESTORE("stackRestore");
+static Name STACK_ALLOC("stackAlloc");
+static Name STACK_INIT("stack$init");
+static Name POST_INSTANTIATE("__post_instantiate");
+static Name ASSIGN_GOT_ENTIRES("__assign_got_enties");
void addExportedFunction(Module& wasm, Function* function) {
wasm.addFunction(function);
@@ -78,13 +78,12 @@ Global* EmscriptenGlueGenerator::getStackPointerGlobal() {
Expression* EmscriptenGlueGenerator::generateLoadStackPointer() {
if (!useStackPointerGlobal) {
return builder.makeLoad(
- /* bytes =*/ 4,
- /* signed =*/ false,
- /* offset =*/ stackPointerOffset,
- /* align =*/ 4,
- /* ptr =*/ builder.makeConst(Literal(0)),
- /* type =*/ i32
- );
+ /* bytes =*/4,
+ /* signed =*/false,
+ /* offset =*/stackPointerOffset,
+ /* align =*/4,
+ /* ptr =*/builder.makeConst(Literal(0)),
+ /* type =*/i32);
}
Global* stackPointer = getStackPointerGlobal();
if (!stackPointer)
@@ -92,16 +91,16 @@ Expression* EmscriptenGlueGenerator::generateLoadStackPointer() {
return builder.makeGetGlobal(stackPointer->name, i32);
}
-Expression* EmscriptenGlueGenerator::generateStoreStackPointer(Expression* value) {
+Expression*
+EmscriptenGlueGenerator::generateStoreStackPointer(Expression* value) {
if (!useStackPointerGlobal) {
return builder.makeStore(
- /* bytes =*/ 4,
- /* offset =*/ stackPointerOffset,
- /* align =*/ 4,
- /* ptr =*/ builder.makeConst(Literal(0)),
- /* value =*/ value,
- /* type =*/ i32
- );
+ /* bytes =*/4,
+ /* offset =*/stackPointerOffset,
+ /* align =*/4,
+ /* ptr =*/builder.makeConst(Literal(0)),
+ /* value =*/value,
+ /* type =*/i32);
}
Global* stackPointer = getStackPointerGlobal();
if (!stackPointer)
@@ -110,10 +109,9 @@ Expression* EmscriptenGlueGenerator::generateStoreStackPointer(Expression* value
}
void EmscriptenGlueGenerator::generateStackSaveFunction() {
- std::vector<NameType> params { };
- Function* function = builder.makeFunction(
- STACK_SAVE, std::move(params), i32, {}
- );
+ std::vector<NameType> params{};
+ Function* function =
+ builder.makeFunction(STACK_SAVE, std::move(params), i32, {});
function->body = generateLoadStackPointer();
@@ -121,10 +119,9 @@ void EmscriptenGlueGenerator::generateStackSaveFunction() {
}
void EmscriptenGlueGenerator::generateStackAllocFunction() {
- std::vector<NameType> params { { "0", i32 } };
- Function* function = builder.makeFunction(
- STACK_ALLOC, std::move(params), i32, { { "1", i32 } }
- );
+ std::vector<NameType> params{{"0", i32}};
+ Function* function =
+ builder.makeFunction(STACK_ALLOC, std::move(params), i32, {{"1", i32}});
Expression* loadStack = generateLoadStackPointer();
GetLocal* getSizeArg = builder.makeGetLocal(0, i32);
Binary* sub = builder.makeBinary(SubInt32, loadStack, getSizeArg);
@@ -146,10 +143,9 @@ void EmscriptenGlueGenerator::generateStackAllocFunction() {
}
void EmscriptenGlueGenerator::generateStackRestoreFunction() {
- std::vector<NameType> params { { "0", i32 } };
- Function* function = builder.makeFunction(
- STACK_RESTORE, std::move(params), none, {}
- );
+ std::vector<NameType> params{{"0", i32}};
+ Function* function =
+ builder.makeFunction(STACK_RESTORE, std::move(params), none, {});
GetLocal* getArg = builder.makeGetLocal(0, i32);
Expression* store = generateStoreStackPointer(getArg);
@@ -164,7 +160,8 @@ void EmscriptenGlueGenerator::generateRuntimeFunctions() {
generateStackRestoreFunction();
}
-static Function* ensureFunctionImport(Module* module, Name name, std::string sig) {
+static Function*
+ensureFunctionImport(Module* module, Name name, std::string sig) {
// Then see if its already imported
ImportInfo info(*module);
if (Function* f = info.getImportedFunction(ENV, name)) {
@@ -246,7 +243,9 @@ Function* EmscriptenGlueGenerator::generateAssignGOTEntriesFunction() {
}
}
- Name getter((std::string("fp$") + g->base.c_str() + std::string("$") + getSig(f)).c_str());
+ Name getter(
+ (std::string("fp$") + g->base.c_str() + std::string("$") + getSig(f))
+ .c_str());
ensureFunctionImport(&wasm, getter, "i");
Expression* call = builder.makeCall(getter, {}, i32);
SetGlobal* set_global = builder.makeSetGlobal(g->name, call);
@@ -299,15 +298,11 @@ void EmscriptenGlueGenerator::generatePostInstantiateFunction() {
Function* EmscriptenGlueGenerator::generateMemoryGrowthFunction() {
Name name(GROW_WASM_MEMORY);
- std::vector<NameType> params { { NEW_SIZE, i32 } };
- Function* growFunction = builder.makeFunction(
- name, std::move(params), i32, {}
- );
- growFunction->body = builder.makeHost(
- GrowMemory,
- Name(),
- { builder.makeGetLocal(0, i32) }
- );
+ std::vector<NameType> params{{NEW_SIZE, i32}};
+ Function* growFunction =
+ builder.makeFunction(name, std::move(params), i32, {});
+ growFunction->body =
+ builder.makeHost(GrowMemory, Name(), {builder.makeGetLocal(0, i32)});
addExportedFunction(wasm, growFunction);
@@ -327,7 +322,8 @@ inline void exportFunction(Module& wasm, Name name, bool must_export) {
assert(!must_export);
return;
}
- if (wasm.getExportOrNull(name)) return; // Already exported
+ if (wasm.getExportOrNull(name))
+ return; // Already exported
auto exp = new Export;
exp->name = exp->value = name;
exp->kind = ExternalKind::Function;
@@ -354,8 +350,10 @@ void EmscriptenGlueGenerator::generateDynCallThunks() {
std::vector<NameType> params;
params.emplace_back("fptr", i32); // function pointer param
int p = 0;
- for (const auto& ty : funcType->params) params.emplace_back(std::to_string(p++), ty);
- Function* f = builder.makeFunction(name, std::move(params), funcType->result, {});
+ for (const auto& ty : funcType->params)
+ params.emplace_back(std::to_string(p++), ty);
+ Function* f =
+ builder.makeFunction(name, std::move(params), funcType->result, {});
Expression* fptr = builder.makeGetLocal(0, i32);
std::vector<Expression*> args;
for (unsigned i = 0; i < funcType->params.size(); ++i) {
@@ -375,7 +373,8 @@ struct RemoveStackPointer : public PostWalker<RemoveStackPointer> {
void visitGetGlobal(GetGlobal* curr) {
if (getModule()->getGlobalOrNull(curr->name) == stackPointer) {
needStackSave = true;
- if (!builder) builder = make_unique<Builder>(*getModule());
+ if (!builder)
+ builder = make_unique<Builder>(*getModule());
replaceCurrent(builder->makeCall(STACK_SAVE, {}, i32));
}
}
@@ -383,7 +382,8 @@ struct RemoveStackPointer : public PostWalker<RemoveStackPointer> {
void visitSetGlobal(SetGlobal* curr) {
if (getModule()->getGlobalOrNull(curr->name) == stackPointer) {
needStackRestore = true;
- if (!builder) builder = make_unique<Builder>(*getModule());
+ if (!builder)
+ builder = make_unique<Builder>(*getModule());
replaceCurrent(builder->makeCall(STACK_RESTORE, {curr->value}, none));
}
}
@@ -431,7 +431,7 @@ std::vector<Address> getSegmentOffsets(Module& wasm) {
return segmentOffsets;
}
-std::string escape(const char *input) {
+std::string escape(const char* input) {
std::string code = input;
// replace newlines quotes with escaped newlines
size_t curr = 0;
@@ -442,11 +442,18 @@ std::string escape(const char *input) {
// replace double quotes with escaped single quotes
curr = 0;
while ((curr = code.find('"', curr)) != std::string::npos) {
- if (curr == 0 || code[curr-1] != '\\') {
- code = code.replace(curr, 1, "\\" "\"");
+ if (curr == 0 || code[curr - 1] != '\\') {
+ code = code.replace(curr,
+ 1,
+ "\\"
+ "\"");
curr += 2; // skip this one
- } else { // already escaped, escape the slash as well
- code = code.replace(curr, 1, "\\" "\\" "\"");
+ } else { // already escaped, escape the slash as well
+ code = code.replace(curr,
+ 1,
+ "\\"
+ "\\"
+ "\"");
curr += 3; // skip this one
}
}
@@ -486,11 +493,11 @@ struct AsmConstWalker : public LinearExecutionWalker<AsmConstWalker> {
std::map<std::string, std::set<std::string>> sigsForCode;
std::map<std::string, Address> ids;
std::set<std::string> allSigs;
- std::map<Index, SetLocal*> sets; // last sets in the current basic block, per index
+ // last sets in the current basic block, per index
+ std::map<Index, SetLocal*> sets;
AsmConstWalker(Module& _wasm)
- : wasm(_wasm),
- segmentOffsets(getSegmentOffsets(wasm)) { }
+ : wasm(_wasm), segmentOffsets(getSegmentOffsets(wasm)) {}
void noteNonLinear(Expression* curr);
@@ -516,9 +523,7 @@ void AsmConstWalker::noteNonLinear(Expression* curr) {
sets.clear();
}
-void AsmConstWalker::visitSetLocal(SetLocal* curr) {
- sets[curr->index] = curr;
-}
+void AsmConstWalker::visitSetLocal(SetLocal* curr) { sets[curr->index] = curr; }
void AsmConstWalker::visitCall(Call* curr) {
auto* import = wasm.getFunction(curr->target);
@@ -547,7 +552,7 @@ void AsmConstWalker::visitCall(Call* curr) {
} else {
if (!value) {
Fatal() << "Unexpected arg0 type (" << getExpressionName(arg)
- << ") in call to to: " << import->base;
+ << ") in call to to: " << import->base;
}
}
}
@@ -608,7 +613,8 @@ Literal AsmConstWalker::idLiteralForCode(std::string code) {
std::string AsmConstWalker::asmConstSig(std::string baseSig) {
std::string sig = "";
for (size_t i = 0; i < baseSig.size(); ++i) {
- // Omit the signature of the "code" parameter, taken as a string, as the first argument
+ // Omit the signature of the "code" parameter, taken as a string, as the
+ // first argument
if (i != 1) {
sig += baseSig[i];
}
@@ -663,8 +669,7 @@ struct EmJsWalker : public PostWalker<EmJsWalker> {
std::map<std::string, std::string> codeByName;
EmJsWalker(Module& _wasm)
- : wasm(_wasm),
- segmentOffsets(getSegmentOffsets(wasm)) { }
+ : wasm(_wasm), segmentOffsets(getSegmentOffsets(wasm)) {}
void visitFunction(Function* curr) {
if (curr->imported()) {
@@ -750,7 +755,8 @@ EmJsWalker fixEmJsFuncsAndReturnWalker(Module& wasm) {
// emscripten_longjmp here.
// 2. Converts invoke wrapper names.
// Refer to the comments in fixEmExceptionInvoke below.
-struct FixInvokeFunctionNamesWalker : public PostWalker<FixInvokeFunctionNamesWalker> {
+struct FixInvokeFunctionNamesWalker
+ : public PostWalker<FixInvokeFunctionNamesWalker> {
Module& wasm;
std::map<Name, Name> importRenames;
std::vector<Name> toRemove;
@@ -789,7 +795,7 @@ struct FixInvokeFunctionNamesWalker : public PostWalker<FixInvokeFunctionNamesWa
return Name("invoke_" + sigWoOrigFunc);
}
- static Name fixEmEHSjLjNames(const Name &name, const std::string& sig) {
+ static Name fixEmEHSjLjNames(const Name& name, const std::string& sig) {
if (name == "emscripten_longjmp_jmpbuf")
return "emscripten_longjmp";
return fixEmExceptionInvoke(name, sig);
@@ -830,20 +836,21 @@ void EmscriptenGlueGenerator::fixInvokeFunctionNames() {
walker.walkModule(&wasm);
}
-template<class C>
-void printSet(std::ostream& o, C& c) {
+template<class C> void printSet(std::ostream& o, C& c) {
o << "[";
bool first = true;
for (auto& item : c) {
- if (first) first = false;
- else o << ",";
+ if (first)
+ first = false;
+ else
+ o << ",";
o << '"' << item << '"';
}
o << "]";
}
std::string EmscriptenGlueGenerator::generateEmscriptenMetadata(
- Address staticBump, std::vector<Name> const& initializerFunctions) {
+ Address staticBump, std::vector<Name> const& initializerFunctions) {
bool commaFirst;
auto nextElement = [&commaFirst]() {
if (commaFirst) {
@@ -964,7 +971,8 @@ std::string EmscriptenGlueGenerator::generateEmscriptenMetadata(
assert(g->type == i32);
Const* init = g->init->cast<Const>();
uint32_t addr = init->value.geti32();
- meta << nextElement() << '"' << ex->name.str << "\" : \"" << addr << '"';
+ meta << nextElement() << '"' << ex->name.str << "\" : \"" << addr
+ << '"';
}
}
meta << "\n },\n";
@@ -993,7 +1001,8 @@ std::string EmscriptenGlueGenerator::generateEmscriptenMetadata(
return meta.str();
}
-void EmscriptenGlueGenerator::separateDataSegments(Output* outfile, Address base) {
+void EmscriptenGlueGenerator::separateDataSegments(Output* outfile,
+ Address base) {
size_t lastEnd = 0;
for (Memory::Segment& seg : wasm.memory.segments) {
assert(!seg.isPassive && "separating passive segments not implemented");
diff --git a/src/wasm/wasm-interpreter.cpp b/src/wasm/wasm-interpreter.cpp
index e7df785ac..ad4b565fe 100644
--- a/src/wasm/wasm-interpreter.cpp
+++ b/src/wasm/wasm-interpreter.cpp
@@ -5,9 +5,7 @@ namespace wasm {
#ifdef WASM_INTERPRETER_DEBUG
int Indenter::indentLevel = 0;
-Indenter::Indenter(const char* entry) : entryName(entry) {
- ++indentLevel;
-}
+Indenter::Indenter(const char* entry) : entryName(entry) { ++indentLevel; }
Indenter::~Indenter() {
print();
std::cout << "exit " << entryName << '\n';
diff --git a/src/wasm/wasm-io.cpp b/src/wasm/wasm-io.cpp
index 057798d2e..1bdb76d5f 100644
--- a/src/wasm/wasm-io.cpp
+++ b/src/wasm/wasm-io.cpp
@@ -25,8 +25,8 @@
//
#include "wasm-io.h"
-#include "wasm-s-parser.h"
#include "wasm-binary.h"
+#include "wasm-s-parser.h"
namespace wasm {
@@ -34,17 +34,20 @@ static void readTextData(std::string& input, Module& wasm) {
SExpressionParser parser(const_cast<char*>(input.c_str()));
Element& root = *parser.root;
SExpressionWasmBuilder builder(wasm, *root[0]);
-
}
void ModuleReader::readText(std::string filename, Module& wasm) {
- if (debug) std::cerr << "reading text from " << filename << "\n";
- auto input(read_file<std::string>(filename, Flags::Text, debug ? Flags::Debug : Flags::Release));
+ if (debug)
+ std::cerr << "reading text from " << filename << "\n";
+ auto input(read_file<std::string>(
+ filename, Flags::Text, debug ? Flags::Debug : Flags::Release));
readTextData(input, wasm);
}
-static void readBinaryData(std::vector<char>& input, Module& wasm,
- std::string sourceMapFilename, bool debug) {
+static void readBinaryData(std::vector<char>& input,
+ Module& wasm,
+ std::string sourceMapFilename,
+ bool debug) {
std::unique_ptr<std::ifstream> sourceMapStream;
WasmBinaryBuilder parser(wasm, input, debug);
if (sourceMapFilename.size()) {
@@ -58,10 +61,13 @@ static void readBinaryData(std::vector<char>& input, Module& wasm,
}
}
-void ModuleReader::readBinary(std::string filename, Module& wasm,
+void ModuleReader::readBinary(std::string filename,
+ Module& wasm,
std::string sourceMapFilename) {
- if (debug) std::cerr << "reading binary from " << filename << "\n";
- auto input(read_file<std::vector<char>>(filename, Flags::Binary, debug ? Flags::Debug : Flags::Release));
+ if (debug)
+ std::cerr << "reading binary from " << filename << "\n";
+ auto input(read_file<std::vector<char>>(
+ filename, Flags::Binary, debug ? Flags::Debug : Flags::Release));
readBinaryData(input, wasm, sourceMapFilename, debug);
}
@@ -69,13 +75,15 @@ bool ModuleReader::isBinaryFile(std::string filename) {
std::ifstream infile;
std::ios_base::openmode flags = std::ifstream::in | std::ifstream::binary;
infile.open(filename, flags);
- char buffer[4] = { 1, 2, 3, 4 };
+ char buffer[4] = {1, 2, 3, 4};
infile.read(buffer, 4);
infile.close();
- return buffer[0] == '\0' && buffer[1] == 'a' && buffer[2] == 's' && buffer[3] == 'm';
+ return buffer[0] == '\0' && buffer[1] == 'a' && buffer[2] == 's' &&
+ buffer[3] == 'm';
}
-void ModuleReader::read(std::string filename, Module& wasm,
+void ModuleReader::read(std::string filename,
+ Module& wasm,
std::string sourceMapFilename) {
// empty filename means read from stdin
if (!filename.size()) {
@@ -87,7 +95,8 @@ void ModuleReader::read(std::string filename, Module& wasm,
} else {
// default to text
if (sourceMapFilename.size()) {
- std::cerr << "Binaryen ModuleReader::read() - source map filename provided, but file appears to not be binary\n";
+ std::cerr << "Binaryen ModuleReader::read() - source map filename "
+ "provided, but file appears to not be binary\n";
}
readText(filename, wasm);
}
@@ -109,13 +118,13 @@ void ModuleReader::readStdin(Module& wasm, std::string sourceMapFilename) {
}
}
-
void ModuleWriter::writeText(Module& wasm, Output& output) {
WasmPrinter::printModule(&wasm, output.getStream());
}
void ModuleWriter::writeText(Module& wasm, std::string filename) {
- if (debug) std::cerr << "writing text to " << filename << "\n";
+ if (debug)
+ std::cerr << "writing text to " << filename << "\n";
Output output(filename, Flags::Text, debug ? Flags::Debug : Flags::Release);
writeText(wasm, output);
}
@@ -131,7 +140,8 @@ void ModuleWriter::writeBinary(Module& wasm, Output& output) {
sourceMapStream->open(sourceMapFilename);
writer.setSourceMap(sourceMapStream.get(), sourceMapUrl);
}
- if (symbolMap.size() > 0) writer.setSymbolMap(symbolMap);
+ if (symbolMap.size() > 0)
+ writer.setSymbolMap(symbolMap);
writer.write();
buffer.writeTo(output);
if (sourceMapStream) {
@@ -140,7 +150,8 @@ void ModuleWriter::writeBinary(Module& wasm, Output& output) {
}
void ModuleWriter::writeBinary(Module& wasm, std::string filename) {
- if (debug) std::cerr << "writing binary to " << filename << "\n";
+ if (debug)
+ std::cerr << "writing binary to " << filename << "\n";
Output output(filename, Flags::Binary, debug ? Flags::Debug : Flags::Release);
writeBinary(wasm, output);
}
@@ -161,4 +172,4 @@ void ModuleWriter::write(Module& wasm, std::string filename) {
}
}
-}
+} // namespace wasm
diff --git a/src/wasm/wasm-s-parser.cpp b/src/wasm/wasm-s-parser.cpp
index 3ba8e0622..bb498329f 100644
--- a/src/wasm/wasm-s-parser.cpp
+++ b/src/wasm/wasm-s-parser.cpp
@@ -16,8 +16,8 @@
#include "wasm-s-parser.h"
-#include <cmath>
#include <cctype>
+#include <cmath>
#include <limits>
#include "asm_v_wasm.h"
@@ -28,19 +28,24 @@
#include "wasm-binary.h"
#include "wasm-builder.h"
-#define abort_on(str) { throw ParseException(std::string("abort_on ") + str); }
-#define element_assert(condition) assert((condition) ? true : (std::cerr << "on: " << *this << '\n' && 0));
+#define abort_on(str) \
+ { throw ParseException(std::string("abort_on ") + str); }
+#define element_assert(condition) \
+ assert((condition) ? true : (std::cerr << "on: " << *this << '\n' && 0));
using cashew::IString;
namespace {
int unhex(char c) {
- if (c >= '0' && c <= '9') return c - '0';
- if (c >= 'a' && c <= 'f') return c - 'a' + 10;
- if (c >= 'A' && c <= 'F') return c - 'A' + 10;
+ if (c >= '0' && c <= '9')
+ return c - '0';
+ if (c >= 'a' && c <= 'f')
+ return c - 'a' + 10;
+ if (c >= 'A' && c <= 'F')
+ return c - 'A' + 10;
throw wasm::ParseException("invalid hexadecimal");
}
-}
+} // namespace
namespace wasm {
@@ -53,23 +58,28 @@ static Address getCheckedAddress(const Element* s, const char* errorText) {
}
Element::List& Element::list() {
- if (!isList()) throw ParseException("expected list", line, col);
+ if (!isList())
+ throw ParseException("expected list", line, col);
return list_;
}
Element* Element::operator[](unsigned i) {
- if (!isList()) throw ParseException("expected list", line, col);
- if (i >= list().size()) throw ParseException("expected more elements in list", line, col);
+ if (!isList())
+ throw ParseException("expected list", line, col);
+ if (i >= list().size())
+ throw ParseException("expected more elements in list", line, col);
return list()[i];
}
IString Element::str() const {
- if (!isStr()) throw ParseException("expected string", line, col);
+ if (!isStr())
+ throw ParseException("expected string", line, col);
return str_;
}
const char* Element::c_str() const {
- if (!isStr()) throw ParseException("expected string", line, col);
+ if (!isStr())
+ throw ParseException("expected string", line, col);
return str_.str;
}
@@ -81,7 +91,8 @@ Element* Element::setString(IString str__, bool dollared__, bool quoted__) {
return this;
}
-Element* Element::setMetadata(size_t line_, size_t col_, SourceLocation* startLoc_) {
+Element*
+Element::setMetadata(size_t line_, size_t col_, SourceLocation* startLoc_) {
line = line_;
col = col_;
startLoc = startLoc_;
@@ -91,7 +102,8 @@ Element* Element::setMetadata(size_t line_, size_t col_, SourceLocation* startLo
std::ostream& operator<<(std::ostream& o, Element& e) {
if (e.isList_) {
o << '(';
- for (auto item : e.list_) o << ' ' << *item;
+ for (auto item : e.list_)
+ o << ' ' << *item;
o << " )";
} else {
o << e.str_.str;
@@ -103,7 +115,6 @@ void Element::dump() {
std::cout << "dumping " << this << " : " << *this << ".\n";
}
-
SExpressionParser::SExpressionParser(char* input) : input(input) {
root = nullptr;
line = 1;
@@ -114,16 +125,18 @@ SExpressionParser::SExpressionParser(char* input) : input(input) {
}
Element* SExpressionParser::parse() {
- std::vector<Element *> stack;
+ std::vector<Element*> stack;
std::vector<SourceLocation*> stackLocs;
- Element *curr = allocator.alloc<Element>();
+ Element* curr = allocator.alloc<Element>();
while (1) {
skipWhitespace();
- if (input[0] == 0) break;
+ if (input[0] == 0)
+ break;
if (input[0] == '(') {
input++;
stack.push_back(curr);
- curr = allocator.alloc<Element>()->setMetadata(line, input - lineStart - 1, loc);
+ curr = allocator.alloc<Element>()->setMetadata(
+ line, input - lineStart - 1, loc);
stackLocs.push_back(loc);
assert(stack.size() == stackLocs.size());
} else if (input[0] == ')') {
@@ -143,31 +156,38 @@ Element* SExpressionParser::parse() {
curr->list().push_back(parseString());
}
}
- if (stack.size() != 0) throw ParseException("stack is not empty", curr->line, curr->col);
+ if (stack.size() != 0)
+ throw ParseException("stack is not empty", curr->line, curr->col);
return curr;
}
void SExpressionParser::parseDebugLocation() {
// Extracting debug location (if valid)
char* debugLoc = input + 3; // skipping ";;@"
- while (debugLoc[0] && debugLoc[0] == ' ') debugLoc++;
+ while (debugLoc[0] && debugLoc[0] == ' ')
+ debugLoc++;
char* debugLocEnd = debugLoc;
- while (debugLocEnd[0] && debugLocEnd[0] != '\n') debugLocEnd++;
+ while (debugLocEnd[0] && debugLocEnd[0] != '\n')
+ debugLocEnd++;
char* pos = debugLoc;
- while (pos < debugLocEnd && pos[0] != ':') pos++;
+ while (pos < debugLocEnd && pos[0] != ':')
+ pos++;
if (pos >= debugLocEnd) {
return; // no line number
}
std::string name(debugLoc, pos);
char* lineStart = ++pos;
- while (pos < debugLocEnd && pos[0] != ':') pos++;
+ while (pos < debugLocEnd && pos[0] != ':')
+ pos++;
std::string lineStr(lineStart, pos);
if (pos >= debugLocEnd) {
return; // no column number
}
std::string colStr(++pos, debugLocEnd);
- void* buf = allocator.allocSpace(sizeof(SourceLocation), alignof(SourceLocation));
- loc = new (buf) SourceLocation(IString(name.c_str(), false), atoi(lineStr.c_str()), atoi(colStr.c_str()));
+ void* buf =
+ allocator.allocSpace(sizeof(SourceLocation), alignof(SourceLocation));
+ loc = new (buf) SourceLocation(
+ IString(name.c_str(), false), atoi(lineStr.c_str()), atoi(colStr.c_str()));
}
void SExpressionParser::skipWhitespace() {
@@ -183,16 +203,19 @@ void SExpressionParser::skipWhitespace() {
if (input[2] == '@') {
parseDebugLocation();
}
- while (input[0] && input[0] != '\n') input++;
+ while (input[0] && input[0] != '\n')
+ input++;
line++;
- if (!input[0]) return;
+ if (!input[0])
+ return;
lineStart = ++input;
} else if (input[0] == '(' && input[1] == ';') {
// Skip nested block comments.
input += 2;
int depth = 1;
while (1) {
- if (!input[0]) return;
+ if (!input[0])
+ return;
if (input[0] == '(' && input[1] == ';') {
input += 2;
depth++;
@@ -222,17 +245,22 @@ Element* SExpressionParser::parseString() {
input++;
dollared = true;
}
- char *start = input;
+ char* start = input;
if (input[0] == '"') {
- // parse escaping \", but leave code escaped - we'll handle escaping in memory segments specifically
+ // parse escaping \", but leave code escaped - we'll handle escaping in
+ // memory segments specifically
input++;
std::string str;
while (1) {
- if (input[0] == 0) throw ParseException("unterminated string", line, start - lineStart);
- if (input[0] == '"') break;
+ if (input[0] == 0)
+ throw ParseException("unterminated string", line, start - lineStart);
+ if (input[0] == '"')
+ break;
if (input[0] == '\\') {
str += input[0];
- if (input[1] == 0) throw ParseException("unterminated string escape", line, start - lineStart);
+ if (input[1] == 0)
+ throw ParseException(
+ "unterminated string escape", line, start - lineStart);
str += input[1];
input += 2;
continue;
@@ -241,21 +269,34 @@ Element* SExpressionParser::parseString() {
input++;
}
input++;
- return allocator.alloc<Element>()->setString(IString(str.c_str(), false), dollared, true)->setMetadata(line, start - lineStart, loc);
+ return allocator.alloc<Element>()
+ ->setString(IString(str.c_str(), false), dollared, true)
+ ->setMetadata(line, start - lineStart, loc);
}
- while (input[0] && !isspace(input[0]) && input[0] != ')' && input[0] != '(' && input[0] != ';') input++;
- if (start == input) throw ParseException("expected string", line, input - lineStart);
+ while (input[0] && !isspace(input[0]) && input[0] != ')' && input[0] != '(' &&
+ input[0] != ';')
+ input++;
+ if (start == input)
+ throw ParseException("expected string", line, input - lineStart);
char temp = input[0];
input[0] = 0;
- auto ret = allocator.alloc<Element>()->setString(IString(start, false), dollared, false)->setMetadata(line, start - lineStart, loc);
+ auto ret = allocator.alloc<Element>()
+ ->setString(IString(start, false), dollared, false)
+ ->setMetadata(line, start - lineStart, loc);
input[0] = temp;
return ret;
}
-SExpressionWasmBuilder::SExpressionWasmBuilder(Module& wasm, Element& module, Name* moduleName) : wasm(wasm), allocator(wasm.allocator) {
- if (module.size() == 0) throw ParseException("empty toplevel, expected module");
- if (module[0]->str() != MODULE) throw ParseException("toplevel does not start with module");
- if (module.size() == 1) return;
+SExpressionWasmBuilder::SExpressionWasmBuilder(Module& wasm,
+ Element& module,
+ Name* moduleName)
+ : wasm(wasm), allocator(wasm.allocator) {
+ if (module.size() == 0)
+ throw ParseException("empty toplevel, expected module");
+ if (module[0]->str() != MODULE)
+ throw ParseException("toplevel does not start with module");
+ if (module.size() == 1)
+ return;
Index i = 1;
if (module[i]->dollared()) {
if (moduleName) {
@@ -286,7 +327,9 @@ SExpressionWasmBuilder::SExpressionWasmBuilder(Module& wasm, Element& module, Na
implementedFunctions++;
}
}
- functionCounter -= implementedFunctions; // we go through the functions again, now parsing them, and the counter begins from where imports ended
+ // we go through the functions again, now parsing them, and the counter begins
+ // from where imports ended
+ functionCounter -= implementedFunctions;
for (unsigned j = i; j < module.size(); j++) {
parseModuleElement(*module[j]);
}
@@ -295,36 +338,55 @@ SExpressionWasmBuilder::SExpressionWasmBuilder(Module& wasm, Element& module, Na
bool SExpressionWasmBuilder::isImport(Element& curr) {
for (Index i = 0; i < curr.size(); i++) {
auto& x = *curr[i];
- if (x.isList() && x.size() > 0 && x[0]->isStr() && x[0]->str() == IMPORT) return true;
+ if (x.isList() && x.size() > 0 && x[0]->isStr() && x[0]->str() == IMPORT)
+ return true;
}
return false;
}
void SExpressionWasmBuilder::preParseImports(Element& curr) {
IString id = curr[0]->str();
- if (id == IMPORT) parseImport(curr);
+ if (id == IMPORT)
+ parseImport(curr);
if (isImport(curr)) {
- if (id == FUNC) parseFunction(curr, true /* preParseImport */);
- else if (id == GLOBAL) parseGlobal(curr, true /* preParseImport */);
- else if (id == TABLE) parseTable(curr, true /* preParseImport */);
- else if (id == MEMORY) parseMemory(curr, true /* preParseImport */);
- else throw ParseException("fancy import we don't support yet", curr.line, curr.col);
+ if (id == FUNC)
+ parseFunction(curr, true /* preParseImport */);
+ else if (id == GLOBAL)
+ parseGlobal(curr, true /* preParseImport */);
+ else if (id == TABLE)
+ parseTable(curr, true /* preParseImport */);
+ else if (id == MEMORY)
+ parseMemory(curr, true /* preParseImport */);
+ else
+ throw ParseException(
+ "fancy import we don't support yet", curr.line, curr.col);
}
}
void SExpressionWasmBuilder::parseModuleElement(Element& curr) {
- if (isImport(curr)) return; // already done
+ if (isImport(curr))
+ return; // already done
IString id = curr[0]->str();
- if (id == START) return parseStart(curr);
- if (id == FUNC) return parseFunction(curr);
- if (id == MEMORY) return parseMemory(curr);
- if (id == DATA) return parseData(curr);
- if (id == EXPORT) return parseExport(curr);
- if (id == IMPORT) return; // already done
- if (id == GLOBAL) return parseGlobal(curr);
- if (id == TABLE) return parseTable(curr);
- if (id == ELEM) return parseElem(curr);
- if (id == TYPE) return; // already done
+ if (id == START)
+ return parseStart(curr);
+ if (id == FUNC)
+ return parseFunction(curr);
+ if (id == MEMORY)
+ return parseMemory(curr);
+ if (id == DATA)
+ return parseData(curr);
+ if (id == EXPORT)
+ return parseExport(curr);
+ if (id == IMPORT)
+ return; // already done
+ if (id == GLOBAL)
+ return parseGlobal(curr);
+ if (id == TABLE)
+ return parseTable(curr);
+ if (id == ELEM)
+ return parseElem(curr);
+ if (id == TYPE)
+ return; // already done
std::cerr << "bad module element " << id.str << '\n';
throw ParseException("unknown module element", curr.line, curr.col);
}
@@ -335,7 +397,8 @@ Name SExpressionWasmBuilder::getFunctionName(Element& s) {
} else {
// index
size_t offset = atoi(s.str().c_str());
- if (offset >= functionNames.size()) throw ParseException("unknown function in getFunctionName");
+ if (offset >= functionNames.size())
+ throw ParseException("unknown function in getFunctionName");
return functionNames[offset];
}
}
@@ -346,7 +409,8 @@ Name SExpressionWasmBuilder::getFunctionTypeName(Element& s) {
} else {
// index
size_t offset = atoi(s.str().c_str());
- if (offset >= functionTypeNames.size()) throw ParseException("unknown function type in getFunctionTypeName");
+ if (offset >= functionTypeNames.size())
+ throw ParseException("unknown function type in getFunctionTypeName");
return functionTypeNames[offset];
}
}
@@ -357,16 +421,18 @@ Name SExpressionWasmBuilder::getGlobalName(Element& s) {
} else {
// index
size_t offset = atoi(s.str().c_str());
- if (offset >= globalNames.size()) throw ParseException("unknown global in getGlobalName");
+ if (offset >= globalNames.size())
+ throw ParseException("unknown global in getGlobalName");
return globalNames[offset];
}
}
-
void SExpressionWasmBuilder::preParseFunctionType(Element& s) {
IString id = s[0]->str();
- if (id == TYPE) return parseType(s);
- if (id != FUNC) return;
+ if (id == TYPE)
+ return parseType(s);
+ if (id != FUNC)
+ return;
size_t i = 1;
Name name, exportName;
i = parseFunctionNames(s, name, exportName);
@@ -379,15 +445,17 @@ void SExpressionWasmBuilder::preParseFunctionType(Element& s) {
FunctionType* type = nullptr;
functionTypes[name] = none;
std::vector<Type> params;
- for (;i < s.size(); i++) {
+ for (; i < s.size(); i++) {
Element& curr = *s[i];
IString id = curr[0]->str();
if (id == RESULT) {
- if (curr.size() > 2) throw ParseException("invalid result arity", curr.line, curr.col);
+ if (curr.size() > 2)
+ throw ParseException("invalid result arity", curr.line, curr.col);
functionTypes[name] = stringToType(curr[1]->str());
} else if (id == TYPE) {
Name typeName = getFunctionTypeName(*curr[1]);
- if (!wasm.getFunctionTypeOrNull(typeName)) throw ParseException("unknown function type", curr.line, curr.col);
+ if (!wasm.getFunctionTypeOrNull(typeName))
+ throw ParseException("unknown function type", curr.line, curr.col);
type = wasm.getFunctionType(typeName);
functionTypes[name] = type->result;
} else if (id == PARAM && curr.size() > 1) {
@@ -403,8 +471,8 @@ void SExpressionWasmBuilder::preParseFunctionType(Element& s) {
}
}
if (!type) {
- // if no function type provided, generate one, but reuse a previous one with the
- // right structure if there is one.
+ // if no function type provided, generate one, but reuse a previous one with
+ // the right structure if there is one.
// see https://github.com/WebAssembly/spec/pull/301
bool need = true;
std::unique_ptr<FunctionType> functionType = make_unique<FunctionType>();
@@ -419,13 +487,16 @@ void SExpressionWasmBuilder::preParseFunctionType(Element& s) {
if (need) {
functionType->name = Name::fromInt(wasm.functionTypes.size());
functionTypeNames.push_back(functionType->name);
- if (wasm.getFunctionTypeOrNull(functionType->name)) throw ParseException("duplicate function type", s.line, s.col);
+ if (wasm.getFunctionTypeOrNull(functionType->name))
+ throw ParseException("duplicate function type", s.line, s.col);
wasm.addFunctionType(std::move(functionType));
}
}
}
-size_t SExpressionWasmBuilder::parseFunctionNames(Element& s, Name& name, Name& exportName) {
+size_t SExpressionWasmBuilder::parseFunctionNames(Element& s,
+ Name& name,
+ Name& exportName) {
size_t i = 1;
while (i < s.size() && i < 3 && s[i]->isStr()) {
if (s[i]->quoted()) {
@@ -476,27 +547,26 @@ void SExpressionWasmBuilder::parseFunction(Element& s, bool preParseImport) {
ex->name = exportName;
ex->value = name;
ex->kind = ExternalKind::Function;
- if (wasm.getExportOrNull(ex->name)) throw ParseException("duplicate export", s.line, s.col);
+ if (wasm.getExportOrNull(ex->name))
+ throw ParseException("duplicate export", s.line, s.col);
wasm.addExport(ex.release());
}
Expression* body = nullptr;
localIndex = 0;
otherIndex = 0;
brokeToAutoBlock = false;
- std::vector<NameType> typeParams; // we may have both params and a type. store the type info here
+ // we may have both params and a type. store the type info here
+ std::vector<NameType> typeParams;
std::vector<NameType> params;
std::vector<NameType> vars;
Type result = none;
Name type;
- Block* autoBlock = nullptr; // we may need to add a block for the very top level
+ // we may need to add a block for the very top level
+ Block* autoBlock = nullptr;
Name importModule, importBase;
auto makeFunction = [&]() {
currFunction = std::unique_ptr<Function>(Builder(wasm).makeFunction(
- name,
- std::move(params),
- result,
- std::move(vars)
- ));
+ name, std::move(params), result, std::move(vars)));
};
auto ensureAutoBlock = [&]() {
if (!autoBlock) {
@@ -505,7 +575,7 @@ void SExpressionWasmBuilder::parseFunction(Element& s, bool preParseImport) {
body = autoBlock;
}
};
- for (;i < s.size(); i++) {
+ for (; i < s.size(); i++) {
Element& curr = *s[i];
IString id = curr[0]->str();
if (id == PARAM || id == LOCAL) {
@@ -521,7 +591,7 @@ void SExpressionWasmBuilder::parseFunction(Element& s, bool preParseImport) {
name = Name::fromInt(localIndex);
} else {
name = curr[j]->str();
- type = stringToType(curr[j+1]->str());
+ type = stringToType(curr[j + 1]->str());
j++;
}
j++;
@@ -534,12 +604,14 @@ void SExpressionWasmBuilder::parseFunction(Element& s, bool preParseImport) {
currLocalTypes[name] = type;
}
} else if (id == RESULT) {
- if (curr.size() > 2) throw ParseException("invalid result arity", curr.line, curr.col);
+ if (curr.size() > 2)
+ throw ParseException("invalid result arity", curr.line, curr.col);
result = stringToType(curr[1]->str());
} else if (id == TYPE) {
Name name = getFunctionTypeName(*curr[1]);
type = name;
- if (!wasm.getFunctionTypeOrNull(name)) throw ParseException("unknown function type");
+ if (!wasm.getFunctionTypeOrNull(name))
+ throw ParseException("unknown function type");
FunctionType* type = wasm.getFunctionType(name);
result = type->result;
for (size_t j = 0; j < type->params.size(); j++) {
@@ -556,7 +628,8 @@ void SExpressionWasmBuilder::parseFunction(Element& s, bool preParseImport) {
if (typeParams.size() > 0 && params.size() == 0) {
params = typeParams;
}
- if (!currFunction) makeFunction();
+ if (!currFunction)
+ makeFunction();
Expression* ex = parseExpression(curr);
if (!body) {
body = ex;
@@ -569,19 +642,23 @@ void SExpressionWasmBuilder::parseFunction(Element& s, bool preParseImport) {
// see https://github.com/WebAssembly/spec/pull/301
if (type.isNull()) {
// if no function type name provided, then we generated one
- auto functionType = make_unique<FunctionType>(sigToFunctionType(getSigFromStructs(result, params)));
+ auto functionType = make_unique<FunctionType>(
+ sigToFunctionType(getSigFromStructs(result, params)));
for (auto& existing : wasm.functionTypes) {
if (existing->structuralComparison(*functionType)) {
type = existing->name;
break;
}
}
- if (!type.is()) throw ParseException("no function type [internal error?]", s.line, s.col);
+ if (!type.is())
+ throw ParseException("no function type [internal error?]", s.line, s.col);
}
if (importModule.is()) {
// this is an import, actually
- if (!importBase.size()) throw ParseException("module but no base for import");
- if (!preParseImport) throw ParseException("!preParseImport in func");
+ if (!importBase.size())
+ throw ParseException("module but no base for import");
+ if (!preParseImport)
+ throw ParseException("!preParseImport in func");
auto im = make_unique<Function>();
im->name = name;
im->module = importModule;
@@ -589,14 +666,17 @@ void SExpressionWasmBuilder::parseFunction(Element& s, bool preParseImport) {
im->type = type;
FunctionTypeUtils::fillFunction(im.get(), wasm.getFunctionType(type));
functionTypes[name] = im->result;
- if (wasm.getFunctionOrNull(im->name)) throw ParseException("duplicate import", s.line, s.col);
+ if (wasm.getFunctionOrNull(im->name))
+ throw ParseException("duplicate import", s.line, s.col);
wasm.addFunction(im.release());
- if (currFunction) throw ParseException("import module inside function dec");
+ if (currFunction)
+ throw ParseException("import module inside function dec");
currLocalTypes.clear();
nameMapper.clear();
return;
}
- if (preParseImport) throw ParseException("preParseImport in func");
+ if (preParseImport)
+ throw ParseException("preParseImport in func");
if (brokeToAutoBlock) {
ensureAutoBlock();
autoBlock->name = FAKE_RETURN;
@@ -608,7 +688,8 @@ void SExpressionWasmBuilder::parseFunction(Element& s, bool preParseImport) {
makeFunction();
body = allocator.alloc<Nop>();
}
- if (currFunction->result != result) throw ParseException("bad func declaration", s.line, s.col);
+ if (currFunction->result != result)
+ throw ParseException("bad func declaration", s.line, s.col);
currFunction->body = body;
currFunction->type = type;
if (s.startLoc) {
@@ -617,41 +698,57 @@ void SExpressionWasmBuilder::parseFunction(Element& s, bool preParseImport) {
if (s.endLoc) {
currFunction->epilogLocation.insert(getDebugLocation(*s.endLoc));
}
- if (wasm.getFunctionOrNull(currFunction->name)) throw ParseException("duplicate function", s.line, s.col);
+ if (wasm.getFunctionOrNull(currFunction->name))
+ throw ParseException("duplicate function", s.line, s.col);
wasm.addFunction(currFunction.release());
currLocalTypes.clear();
nameMapper.clear();
}
-Type SExpressionWasmBuilder::stringToType(const char* str, bool allowError, bool prefix) {
+Type SExpressionWasmBuilder::stringToType(const char* str,
+ bool allowError,
+ bool prefix) {
if (str[0] == 'i') {
- if (str[1] == '3' && str[2] == '2' && (prefix || str[3] == 0)) return i32;
- if (str[1] == '6' && str[2] == '4' && (prefix || str[3] == 0)) return i64;
+ if (str[1] == '3' && str[2] == '2' && (prefix || str[3] == 0))
+ return i32;
+ if (str[1] == '6' && str[2] == '4' && (prefix || str[3] == 0))
+ return i64;
}
if (str[0] == 'f') {
- if (str[1] == '3' && str[2] == '2' && (prefix || str[3] == 0)) return f32;
- if (str[1] == '6' && str[2] == '4' && (prefix || str[3] == 0)) return f64;
+ if (str[1] == '3' && str[2] == '2' && (prefix || str[3] == 0))
+ return f32;
+ if (str[1] == '6' && str[2] == '4' && (prefix || str[3] == 0))
+ return f64;
}
if (str[0] == 'v') {
- if (str[1] == '1' && str[2] == '2' && str[3] == '8' && (prefix || str[4] == 0)) {
+ if (str[1] == '1' && str[2] == '2' && str[3] == '8' &&
+ (prefix || str[4] == 0)) {
return v128;
}
}
- if (allowError) return none;
+ if (allowError)
+ return none;
throw ParseException("invalid wasm type");
}
Type SExpressionWasmBuilder::stringToLaneType(const char* str) {
- if (strcmp(str, "i8x16") == 0) return i32;
- if (strcmp(str, "i16x8") == 0) return i32;
- if (strcmp(str, "i32x4") == 0) return i32;
- if (strcmp(str, "i64x2") == 0) return i64;
- if (strcmp(str, "f32x4") == 0) return f32;
- if (strcmp(str, "f64x2") == 0) return f64;
+ if (strcmp(str, "i8x16") == 0)
+ return i32;
+ if (strcmp(str, "i16x8") == 0)
+ return i32;
+ if (strcmp(str, "i32x4") == 0)
+ return i32;
+ if (strcmp(str, "i64x2") == 0)
+ return i64;
+ if (strcmp(str, "f32x4") == 0)
+ return f32;
+ if (strcmp(str, "f64x2") == 0)
+ return f64;
return none;
}
-Function::DebugLocation SExpressionWasmBuilder::getDebugLocation(const SourceLocation& loc) {
+Function::DebugLocation
+SExpressionWasmBuilder::getDebugLocation(const SourceLocation& loc) {
IString file = loc.filename;
auto& debugInfoFileNames = wasm.debugInfoFileNames;
auto iter = debugInfoFileIndices.find(file);
@@ -672,7 +769,7 @@ Expression* SExpressionWasmBuilder::parseExpression(Element& s) {
return result;
}
-Expression* SExpressionWasmBuilder::makeExpression(Element& s) {
+Expression* SExpressionWasmBuilder::makeExpression(Element& s){
#define INSTRUCTION_PARSER
#include "gen-s-parser.inc"
}
@@ -681,9 +778,7 @@ Expression* SExpressionWasmBuilder::makeUnreachable() {
return allocator.alloc<Unreachable>();
}
-Expression* SExpressionWasmBuilder::makeNop() {
- return allocator.alloc<Nop>();
-}
+Expression* SExpressionWasmBuilder::makeNop() { return allocator.alloc<Nop>(); }
Expression* SExpressionWasmBuilder::makeBinary(Element& s, BinaryOp op) {
auto ret = allocator.alloc<Binary>();
@@ -694,7 +789,6 @@ Expression* SExpressionWasmBuilder::makeBinary(Element& s, BinaryOp op) {
return ret;
}
-
Expression* SExpressionWasmBuilder::makeUnary(Element& s, UnaryOp op) {
auto ret = allocator.alloc<Unary>();
ret->op = op;
@@ -737,15 +831,18 @@ Expression* SExpressionWasmBuilder::makeHost(Element& s, HostOp op) {
}
Index SExpressionWasmBuilder::getLocalIndex(Element& s) {
- if (!currFunction) throw ParseException("local access in non-function scope", s.line, s.col);
+ if (!currFunction)
+ throw ParseException("local access in non-function scope", s.line, s.col);
if (s.dollared()) {
auto ret = s.str();
- if (currFunction->localIndices.count(ret) == 0) throw ParseException("bad local name", s.line, s.col);
+ if (currFunction->localIndices.count(ret) == 0)
+ throw ParseException("bad local name", s.line, s.col);
return currFunction->getLocalIndex(ret);
}
// this is a numeric index
Index ret = atoi(s.c_str());
- if (ret >= currFunction->getNumLocals()) throw ParseException("bad local index", s.line, s.col);
+ if (ret >= currFunction->getNumLocals())
+ throw ParseException("bad local index", s.line, s.col);
return ret;
}
@@ -788,16 +885,19 @@ Expression* SExpressionWasmBuilder::makeGetGlobal(Element& s) {
Expression* SExpressionWasmBuilder::makeSetGlobal(Element& s) {
auto ret = allocator.alloc<SetGlobal>();
ret->name = getGlobalName(*s[1]);
- if (wasm.getGlobalOrNull(ret->name) && !wasm.getGlobalOrNull(ret->name)->mutable_) throw ParseException("global.set of immutable", s.line, s.col);
+ if (wasm.getGlobalOrNull(ret->name) &&
+ !wasm.getGlobalOrNull(ret->name)->mutable_)
+ throw ParseException("global.set of immutable", s.line, s.col);
ret->value = parseExpression(s[2]);
ret->finalize();
return ret;
}
-
Expression* SExpressionWasmBuilder::makeBlock(Element& s) {
- if (!currFunction) throw ParseException("block is unallowed outside of functions");
- // special-case Block, because Block nesting (in their first element) can be incredibly deep
+ if (!currFunction)
+ throw ParseException("block is unallowed outside of functions");
+ // special-case Block, because Block nesting (in their first element) can be
+ // incredibly deep
auto curr = allocator.alloc<Block>();
auto* sp = &s;
std::vector<std::pair<Element*, Block*>> stack;
@@ -808,7 +908,8 @@ Expression* SExpressionWasmBuilder::makeBlock(Element& s) {
Name sName;
if (i < s.size() && s[i]->isStr()) {
// could be a name or a type
- if (s[i]->dollared() || stringToType(s[i]->str(), true /* allowError */) == none) {
+ if (s[i]->dollared() ||
+ stringToType(s[i]->str(), true /* allowError */) == none) {
sName = s[i++]->str();
} else {
sName = "block";
@@ -819,7 +920,8 @@ Expression* SExpressionWasmBuilder::makeBlock(Element& s) {
curr->name = nameMapper.pushLabelName(sName);
// block signature
curr->type = parseOptionalResultType(s, i);
- if (i >= s.size()) break; // empty block
+ if (i >= s.size())
+ break; // empty block
auto& first = *s[i];
if (first[0]->str() == BLOCK) {
// recurse
@@ -860,7 +962,8 @@ Expression* SExpressionWasmBuilder::makeBlock(Element& s) {
return stack[0].second;
}
-// Similar to block, but the label is handled by the enclosing if (since there might not be a then or else, ick)
+// Similar to block, but the label is handled by the enclosing if (since there
+// might not be a then or else, ick)
Expression* SExpressionWasmBuilder::makeThenOrElse(Element& s) {
auto ret = allocator.alloc<Block>();
size_t i = 1;
@@ -878,7 +981,7 @@ template<int Lanes>
static Literal makeLanes(Element& s, MixedArena& allocator, Type lane_t) {
std::array<Literal, Lanes> lanes;
for (size_t i = 0; i < Lanes; ++i) {
- Expression* lane = parseConst(s[i+2]->str(), lane_t, allocator);
+ Expression* lane = parseConst(s[i + 2]->str(), lane_t, allocator);
if (lane) {
lanes[i] = lane->cast<Const>()->value;
} else {
@@ -891,7 +994,8 @@ static Literal makeLanes(Element& s, MixedArena& allocator, Type lane_t) {
Expression* SExpressionWasmBuilder::makeConst(Element& s, Type type) {
if (type != v128) {
auto ret = parseConst(s[1]->str(), type, allocator);
- if (!ret) throw ParseException("bad const");
+ if (!ret)
+ throw ParseException("bad const");
return ret;
}
@@ -927,7 +1031,8 @@ Expression* SExpressionWasmBuilder::makeConst(Element& s, Type type) {
ret->value = makeLanes<16>(s, allocator, lane_t);
break;
}
- default: throw ParseException("Unexpected number of lanes in v128 literal");
+ default:
+ throw ParseException("Unexpected number of lanes in v128 literal");
}
ret->finalize();
return ret;
@@ -939,11 +1044,14 @@ static uint8_t parseMemBytes(const char*& s, uint8_t fallback) {
ret = 1;
s++;
} else if (s[0] == '1') {
- if (s[1] != '6') throw ParseException("expected 16 for memop size");
+ if (s[1] != '6')
+ throw ParseException("expected 16 for memop size");
ret = 2;
s += 2;
} else if (s[0] == '3') {
- if (s[1] != '2') throw ParseException("expected 32 for memop size");;
+ if (s[1] != '2')
+ throw ParseException("expected 32 for memop size");
+ ;
ret = 4;
s += 2;
} else {
@@ -952,28 +1060,36 @@ static uint8_t parseMemBytes(const char*& s, uint8_t fallback) {
return ret;
}
-static size_t parseMemAttributes(Element& s, Address* offset, Address* align, Address fallback) {
+static size_t parseMemAttributes(Element& s,
+ Address* offset,
+ Address* align,
+ Address fallback) {
size_t i = 1;
*offset = 0;
*align = fallback;
while (!s[i]->isList()) {
- const char *str = s[i]->c_str();
- const char *eq = strchr(str, '=');
- if (!eq) throw ParseException("missing = in memory attribute");
+ const char* str = s[i]->c_str();
+ const char* eq = strchr(str, '=');
+ if (!eq)
+ throw ParseException("missing = in memory attribute");
eq++;
- if (*eq == 0) throw ParseException("missing value in memory attribute", s.line, s.col);
+ if (*eq == 0)
+ throw ParseException("missing value in memory attribute", s.line, s.col);
char* endptr;
uint64_t value = strtoll(eq, &endptr, 10);
if (*endptr != 0) {
throw ParseException("bad memory attribute immediate", s.line, s.col);
}
if (str[0] == 'a') {
- if (value > std::numeric_limits<uint32_t>::max()) throw ParseException("bad align", s.line, s.col);
+ if (value > std::numeric_limits<uint32_t>::max())
+ throw ParseException("bad align", s.line, s.col);
*align = value;
} else if (str[0] == 'o') {
- if (value > std::numeric_limits<uint32_t>::max()) throw ParseException("bad offset", s.line, s.col);
+ if (value > std::numeric_limits<uint32_t>::max())
+ throw ParseException("bad offset", s.line, s.col);
*offset = value;
- } else throw ParseException("bad memory attribute");
+ } else
+ throw ParseException("bad memory attribute");
i++;
}
return i;
@@ -983,14 +1099,18 @@ static const char* findMemExtra(const Element& s, size_t skip, bool isAtomic) {
auto* str = s.c_str();
auto size = strlen(str);
auto* ret = strchr(str, '.');
- if (!ret) throw ParseException("missing '.' in memory access", s.line, s.col);
+ if (!ret)
+ throw ParseException("missing '.' in memory access", s.line, s.col);
ret += skip;
- if (isAtomic) ret += 7; // after "type.atomic.load"
- if (ret > str + size) throw ParseException("memory access ends abruptly", s.line, s.col);
+ if (isAtomic)
+ ret += 7; // after "type.atomic.load"
+ if (ret > str + size)
+ throw ParseException("memory access ends abruptly", s.line, s.col);
return ret;
}
-Expression* SExpressionWasmBuilder::makeLoad(Element& s, Type type, bool isAtomic) {
+Expression*
+SExpressionWasmBuilder::makeLoad(Element& s, Type type, bool isAtomic) {
const char* extra = findMemExtra(*s[0], 5 /* after "type.load" */, isAtomic);
auto* ret = allocator.alloc<Load>();
ret->isAtomic = isAtomic;
@@ -1003,7 +1123,8 @@ Expression* SExpressionWasmBuilder::makeLoad(Element& s, Type type, bool isAtomi
return ret;
}
-Expression* SExpressionWasmBuilder::makeStore(Element& s, Type type, bool isAtomic) {
+Expression*
+SExpressionWasmBuilder::makeStore(Element& s, Type type, bool isAtomic) {
const char* extra = findMemExtra(*s[0], 6 /* after "type.store" */, isAtomic);
auto ret = allocator.alloc<Store>();
ret->isAtomic = isAtomic;
@@ -1011,51 +1132,70 @@ Expression* SExpressionWasmBuilder::makeStore(Element& s, Type type, bool isAtom
ret->bytes = parseMemBytes(extra, getTypeSize(type));
size_t i = parseMemAttributes(s, &ret->offset, &ret->align, ret->bytes);
ret->ptr = parseExpression(s[i]);
- ret->value = parseExpression(s[i+1]);
+ ret->value = parseExpression(s[i + 1]);
ret->finalize();
return ret;
}
-Expression* SExpressionWasmBuilder::makeAtomicRMWOrCmpxchg(Element& s, Type type) {
- const char* extra = findMemExtra(*s[0], 11 /* after "type.atomic.rmw" */, /* isAtomic = */ false);
+Expression* SExpressionWasmBuilder::makeAtomicRMWOrCmpxchg(Element& s,
+ Type type) {
+ const char* extra = findMemExtra(
+ *s[0], 11 /* after "type.atomic.rmw" */, /* isAtomic = */ false);
auto bytes = parseMemBytes(extra, getTypeSize(type));
extra = strchr(extra, '.'); // after the optional '_u' and before the opcode
- if (!extra) throw ParseException("malformed atomic rmw instruction");
+ if (!extra)
+ throw ParseException("malformed atomic rmw instruction");
extra++; // after the '.'
- if (!strncmp(extra, "cmpxchg", 7)) return makeAtomicCmpxchg(s, type, bytes, extra);
+ if (!strncmp(extra, "cmpxchg", 7))
+ return makeAtomicCmpxchg(s, type, bytes, extra);
return makeAtomicRMW(s, type, bytes, extra);
}
-Expression* SExpressionWasmBuilder::makeAtomicRMW(Element& s, Type type, uint8_t bytes, const char* extra) {
+Expression* SExpressionWasmBuilder::makeAtomicRMW(Element& s,
+ Type type,
+ uint8_t bytes,
+ const char* extra) {
auto ret = allocator.alloc<AtomicRMW>();
ret->type = type;
ret->bytes = bytes;
- if (!strncmp(extra, "add", 3)) ret->op = Add;
- else if (!strncmp(extra, "and", 3)) ret->op = And;
- else if (!strncmp(extra, "or", 2)) ret->op = Or;
- else if (!strncmp(extra, "sub", 3)) ret->op = Sub;
- else if (!strncmp(extra, "xor", 3)) ret->op = Xor;
- else if (!strncmp(extra, "xchg", 4)) ret->op = Xchg;
- else throw ParseException("bad atomic rmw operator");
+ if (!strncmp(extra, "add", 3))
+ ret->op = Add;
+ else if (!strncmp(extra, "and", 3))
+ ret->op = And;
+ else if (!strncmp(extra, "or", 2))
+ ret->op = Or;
+ else if (!strncmp(extra, "sub", 3))
+ ret->op = Sub;
+ else if (!strncmp(extra, "xor", 3))
+ ret->op = Xor;
+ else if (!strncmp(extra, "xchg", 4))
+ ret->op = Xchg;
+ else
+ throw ParseException("bad atomic rmw operator");
Address align;
size_t i = parseMemAttributes(s, &ret->offset, &align, ret->bytes);
- if (align != ret->bytes) throw ParseException("Align of Atomic RMW must match size");
+ if (align != ret->bytes)
+ throw ParseException("Align of Atomic RMW must match size");
ret->ptr = parseExpression(s[i]);
- ret->value = parseExpression(s[i+1]);
+ ret->value = parseExpression(s[i + 1]);
ret->finalize();
return ret;
}
-Expression* SExpressionWasmBuilder::makeAtomicCmpxchg(Element& s, Type type, uint8_t bytes, const char* extra) {
+Expression* SExpressionWasmBuilder::makeAtomicCmpxchg(Element& s,
+ Type type,
+ uint8_t bytes,
+ const char* extra) {
auto ret = allocator.alloc<AtomicCmpxchg>();
ret->type = type;
ret->bytes = bytes;
Address align;
size_t i = parseMemAttributes(s, &ret->offset, &align, ret->bytes);
- if (align != ret->bytes) throw ParseException("Align of Atomic Cmpxchg must match size");
+ if (align != ret->bytes)
+ throw ParseException("Align of Atomic Cmpxchg must match size");
ret->ptr = parseExpression(s[i]);
- ret->expected = parseExpression(s[i+1]);
- ret->replacement = parseExpression(s[i+2]);
+ ret->expected = parseExpression(s[i + 1]);
+ ret->replacement = parseExpression(s[i + 2]);
ret->finalize();
return ret;
}
@@ -1081,15 +1221,20 @@ Expression* SExpressionWasmBuilder::makeAtomicNotify(Element& s) {
}
static uint8_t parseLaneIndex(const Element* s, size_t lanes) {
- const char *str = s->c_str();
- char *end;
+ const char* str = s->c_str();
+ char* end;
auto n = static_cast<unsigned long long>(strtoll(str, &end, 10));
- if (end == str || *end != '\0') throw ParseException("Expected lane index");
- if (n > lanes) throw ParseException("lane index must be less than " + std::to_string(lanes));
+ if (end == str || *end != '\0')
+ throw ParseException("Expected lane index");
+ if (n > lanes)
+ throw ParseException("lane index must be less than " +
+ std::to_string(lanes));
return uint8_t(n);
}
-Expression* SExpressionWasmBuilder::makeSIMDExtract(Element& s, SIMDExtractOp op, size_t lanes) {
+Expression* SExpressionWasmBuilder::makeSIMDExtract(Element& s,
+ SIMDExtractOp op,
+ size_t lanes) {
auto ret = allocator.alloc<SIMDExtract>();
ret->op = op;
ret->index = parseLaneIndex(s[1], lanes);
@@ -1098,7 +1243,9 @@ Expression* SExpressionWasmBuilder::makeSIMDExtract(Element& s, SIMDExtractOp op
return ret;
}
-Expression* SExpressionWasmBuilder::makeSIMDReplace(Element& s, SIMDReplaceOp op, size_t lanes) {
+Expression* SExpressionWasmBuilder::makeSIMDReplace(Element& s,
+ SIMDReplaceOp op,
+ size_t lanes) {
auto ret = allocator.alloc<SIMDReplace>();
ret->op = op;
ret->index = parseLaneIndex(s[1], lanes);
@@ -1111,7 +1258,7 @@ Expression* SExpressionWasmBuilder::makeSIMDReplace(Element& s, SIMDReplaceOp op
Expression* SExpressionWasmBuilder::makeSIMDShuffle(Element& s) {
auto ret = allocator.alloc<SIMDShuffle>();
for (size_t i = 0; i < 16; ++i) {
- ret->mask[i] = parseLaneIndex(s[i+1], 32);
+ ret->mask[i] = parseLaneIndex(s[i + 1], 32);
}
ret->left = parseExpression(s[17]);
ret->right = parseExpression(s[18]);
@@ -1203,11 +1350,13 @@ Expression* SExpressionWasmBuilder::makeIf(Element& s) {
return ret;
}
-
-Expression* SExpressionWasmBuilder::makeMaybeBlock(Element& s, size_t i, Type type) {
+Expression*
+SExpressionWasmBuilder::makeMaybeBlock(Element& s, size_t i, Type type) {
Index stopAt = -1;
- if (s.size() == i) return allocator.alloc<Nop>();
- if (s.size() == i+1) return parseExpression(s[i]);
+ if (s.size() == i)
+ return allocator.alloc<Nop>();
+ if (s.size() == i + 1)
+ return parseExpression(s[i]);
auto ret = allocator.alloc<Block>();
for (; i < s.size() && i < stopAt; i++) {
ret->list.push_back(parseExpression(s[i]));
@@ -1265,7 +1414,8 @@ Expression* SExpressionWasmBuilder::makeCall(Element& s) {
}
Expression* SExpressionWasmBuilder::makeCallIndirect(Element& s) {
- if (!wasm.table.exists) throw ParseException("no table");
+ if (!wasm.table.exists)
+ throw ParseException("no table");
auto ret = allocator.alloc<CallIndirect>();
Index i = 1;
Element& typeElement = *s[i];
@@ -1273,7 +1423,8 @@ Expression* SExpressionWasmBuilder::makeCallIndirect(Element& s) {
// type name given
IString type = typeElement[1]->str();
auto* fullType = wasm.getFunctionTypeOrNull(type);
- if (!fullType) throw ParseException("invalid call_indirect type", s.line, s.col);
+ if (!fullType)
+ throw ParseException("invalid call_indirect type", s.line, s.col);
ret->fullType = fullType->name;
i++;
} else {
@@ -1314,9 +1465,11 @@ Name SExpressionWasmBuilder::getLabel(Element& s) {
} catch (std::out_of_range&) {
throw ParseException("out of range break offset");
}
- if (offset > nameMapper.labelStack.size()) throw ParseException("invalid label", s.line, s.col);
+ if (offset > nameMapper.labelStack.size())
+ throw ParseException("invalid label", s.line, s.col);
if (offset == nameMapper.labelStack.size()) {
- // a break to the function's scope. this means we need an automatic block, with a name
+ // a break to the function's scope. this means we need an automatic block,
+ // with a name
brokeToAutoBlock = true;
return FAKE_RETURN;
}
@@ -1329,7 +1482,8 @@ Expression* SExpressionWasmBuilder::makeBreak(Element& s) {
size_t i = 1;
ret->name = getLabel(*s[i]);
i++;
- if (i == s.size()) return ret;
+ if (i == s.size())
+ return ret;
if (s[0]->str() == BR_IF) {
if (i + 1 < s.size()) {
ret->value = parseExpression(s[i]);
@@ -1349,7 +1503,8 @@ Expression* SExpressionWasmBuilder::makeBreakTable(Element& s) {
while (!s[i]->isList()) {
ret->targets.push_back(getLabel(*s[i++]));
}
- if (ret->targets.size() == 0) throw ParseException("switch with no targets");
+ if (ret->targets.size() == 0)
+ throw ParseException("switch with no targets");
ret->default_ = ret->targets.back();
ret->targets.pop_back();
ret->condition = parseExpression(s[i++]);
@@ -1368,14 +1523,18 @@ Expression* SExpressionWasmBuilder::makeReturn(Element& s) {
return ret;
}
-// converts an s-expression string representing binary data into an output sequence of raw bytes
-// this appends to data, which may already contain content.
-void SExpressionWasmBuilder::stringToBinary(const char* input, size_t size, std::vector<char>& data) {
+// converts an s-expression string representing binary data into an output
+// sequence of raw bytes this appends to data, which may already contain
+// content.
+void SExpressionWasmBuilder::stringToBinary(const char* input,
+ size_t size,
+ std::vector<char>& data) {
auto originalSize = data.size();
data.resize(originalSize + size);
- char *write = data.data() + originalSize;
+ char* write = data.data() + originalSize;
while (1) {
- if (input[0] == 0) break;
+ if (input[0] == 0)
+ break;
if (input[0] == '\\') {
if (input[1] == '"') {
*write++ = '"';
@@ -1398,7 +1557,7 @@ void SExpressionWasmBuilder::stringToBinary(const char* input, size_t size, std:
input += 2;
continue;
} else {
- *write++ = (char)(unhex(input[1])*16 + unhex(input[2]));
+ *write++ = (char)(unhex(input[1]) * 16 + unhex(input[2]));
input += 3;
continue;
}
@@ -1419,13 +1578,15 @@ Index SExpressionWasmBuilder::parseMemoryLimits(Element& s, Index i) {
return i;
}
uint64_t max = atoll(s[i++]->c_str());
- if (max > Memory::kMaxSize) throw ParseException("total memory must be <= 4GB");
+ if (max > Memory::kMaxSize)
+ throw ParseException("total memory must be <= 4GB");
wasm.memory.max = max;
return i;
}
void SExpressionWasmBuilder::parseMemory(Element& s, bool preParseImport) {
- if (wasm.memory.exists) throw ParseException("too many memories");
+ if (wasm.memory.exists)
+ throw ParseException("too many memories");
wasm.memory.exists = true;
wasm.memory.shared = false;
Index i = 1;
@@ -1440,7 +1601,8 @@ void SExpressionWasmBuilder::parseMemory(Element& s, bool preParseImport) {
ex->name = inner[1]->str();
ex->value = wasm.memory.name;
ex->kind = ExternalKind::Memory;
- if (wasm.getExportOrNull(ex->name)) throw ParseException("duplicate export", s.line, s.col);
+ if (wasm.getExportOrNull(ex->name))
+ throw ParseException("duplicate export", s.line, s.col);
wasm.addExport(ex.release());
i++;
} else if (inner[0]->str() == IMPORT) {
@@ -1452,7 +1614,8 @@ void SExpressionWasmBuilder::parseMemory(Element& s, bool preParseImport) {
parseMemoryLimits(inner, 1);
i++;
} else {
- if (!(inner.size() > 0 ? inner[0]->str() != IMPORT : true)) throw ParseException("bad import ending");
+ if (!(inner.size() > 0 ? inner[0]->str() != IMPORT : true))
+ throw ParseException("bad import ending");
// (memory (data ..)) format
auto offset = allocator.alloc<Const>()->set(Literal(int32_t(0)));
parseInnerData(*s[i], 1, offset, false);
@@ -1460,7 +1623,8 @@ void SExpressionWasmBuilder::parseMemory(Element& s, bool preParseImport) {
return;
}
}
- if (!wasm.memory.shared) i = parseMemoryLimits(s, i);
+ if (!wasm.memory.shared)
+ i = parseMemoryLimits(s, i);
// Parse memory initializers.
while (i < s.size()) {
@@ -1472,7 +1636,7 @@ void SExpressionWasmBuilder::parseMemory(Element& s, bool preParseImport) {
} else {
offsetValue = getCheckedAddress(curr[j++], "excessive memory offset");
}
- const char *input = curr[j]->c_str();
+ const char* input = curr[j]->c_str();
auto* offset = allocator.alloc<Const>();
offset->type = i32;
offset->value = Literal(int32_t(offsetValue));
@@ -1488,7 +1652,8 @@ void SExpressionWasmBuilder::parseMemory(Element& s, bool preParseImport) {
}
void SExpressionWasmBuilder::parseData(Element& s) {
- if (!wasm.memory.exists) throw ParseException("data but no memory");
+ if (!wasm.memory.exists)
+ throw ParseException("data but no memory");
bool isPassive = false;
Expression* offset = nullptr;
Index i = 1;
@@ -1508,15 +1673,19 @@ void SExpressionWasmBuilder::parseData(Element& s) {
parseInnerData(s, s.size() - 1, offset, isPassive);
}
-void SExpressionWasmBuilder::parseInnerData(Element& s, Index i, Expression* offset, bool isPassive) {
+void SExpressionWasmBuilder::parseInnerData(Element& s,
+ Index i,
+ Expression* offset,
+ bool isPassive) {
std::vector<char> data;
while (i < s.size()) {
- const char *input = s[i++]->c_str();
+ const char* input = s[i++]->c_str();
if (auto size = strlen(input)) {
stringToBinary(input, size, data);
}
}
- wasm.memory.segments.emplace_back(isPassive, offset, data.data(), data.size());
+ wasm.memory.segments.emplace_back(
+ isPassive, offset, data.data(), data.size());
}
void SExpressionWasmBuilder::parseExport(Element& s) {
@@ -1533,14 +1702,17 @@ void SExpressionWasmBuilder::parseExport(Element& s) {
ex->kind = ExternalKind::Table;
} else if (inner[0]->str() == GLOBAL) {
ex->kind = ExternalKind::Global;
- if (wasm.getGlobalOrNull(ex->value) && wasm.getGlobal(ex->value)->mutable_) throw ParseException("cannot export a mutable global", s.line, s.col);
+ if (wasm.getGlobalOrNull(ex->value) &&
+ wasm.getGlobal(ex->value)->mutable_)
+ throw ParseException("cannot export a mutable global", s.line, s.col);
} else {
throw ParseException("invalid export");
}
} else if (!s[2]->dollared() && !std::isdigit(s[2]->str()[0])) {
ex->value = s[3]->str();
if (s[2]->str() == MEMORY) {
- if (!wasm.memory.exists) throw ParseException("memory exported but no memory");
+ if (!wasm.memory.exists)
+ throw ParseException("memory exported but no memory");
ex->kind = ExternalKind::Memory;
} else if (s[2]->str() == TABLE) {
ex->kind = ExternalKind::Table;
@@ -1554,24 +1726,28 @@ void SExpressionWasmBuilder::parseExport(Element& s) {
ex->value = s[2]->str();
ex->kind = ExternalKind::Function;
}
- if (wasm.getExportOrNull(ex->name)) throw ParseException("duplicate export", s.line, s.col);
+ if (wasm.getExportOrNull(ex->name))
+ throw ParseException("duplicate export", s.line, s.col);
wasm.addExport(ex.release());
}
void SExpressionWasmBuilder::parseImport(Element& s) {
size_t i = 1;
- bool newStyle = s.size() == 4 && s[3]->isList(); // (import "env" "STACKTOP" (global $stackTop i32))
+ // (import "env" "STACKTOP" (global $stackTop i32))
+ bool newStyle = s.size() == 4 && s[3]->isList();
auto kind = ExternalKind::Invalid;
if (newStyle) {
if ((*s[3])[0]->str() == FUNC) {
kind = ExternalKind::Function;
} else if ((*s[3])[0]->str() == MEMORY) {
kind = ExternalKind::Memory;
- if (wasm.memory.exists) throw ParseException("more than one memory");
+ if (wasm.memory.exists)
+ throw ParseException("more than one memory");
wasm.memory.exists = true;
} else if ((*s[3])[0]->str() == TABLE) {
kind = ExternalKind::Table;
- if (wasm.table.exists) throw ParseException("more than one table");
+ if (wasm.table.exists)
+ throw ParseException("more than one table");
wasm.table.exists = true;
} else if ((*s[3])[0]->str() == GLOBAL) {
kind = ExternalKind::Global;
@@ -1583,7 +1759,8 @@ void SExpressionWasmBuilder::parseImport(Element& s) {
Name name;
if (s.size() > 3 && s[3]->isStr()) {
name = s[i++]->str();
- } else if (newStyle && newStyleInner < s[3]->size() && (*s[3])[newStyleInner]->dollared()) {
+ } else if (newStyle && newStyleInner < s[3]->size() &&
+ (*s[3])[newStyleInner]->dollared()) {
name = (*s[3])[newStyleInner++]->str();
}
if (!name.is()) {
@@ -1616,9 +1793,11 @@ void SExpressionWasmBuilder::parseImport(Element& s) {
kind = ExternalKind::Function;
}
auto module = s[i++]->str();
- if (!s[i]->isStr()) throw ParseException("no name for import");
+ if (!s[i]->isStr())
+ throw ParseException("no name for import");
auto base = s[i++]->str();
- if (!module.size() || !base.size()) throw ParseException("imports must have module and base");
+ if (!module.size() || !base.size())
+ throw ParseException("imports must have module and base");
// parse internals
Element& inner = newStyle ? *s[3] : s;
Index j = newStyle ? newStyleInner : i;
@@ -1635,14 +1814,16 @@ void SExpressionWasmBuilder::parseImport(Element& s) {
type->result = stringToType(params[1]->str());
} else if (id == TYPE) {
IString name = params[1]->str();
- if (!wasm.getFunctionTypeOrNull(name)) throw ParseException("bad function type for import");
+ if (!wasm.getFunctionTypeOrNull(name))
+ throw ParseException("bad function type for import");
*type = *wasm.getFunctionType(name);
} else {
throw ParseException("bad import element");
}
- if (inner.size() > j+1) {
- Element& result = *inner[j+1];
- if (result[0]->str() != RESULT) throw ParseException("expected result");
+ if (inner.size() > j + 1) {
+ Element& result = *inner[j + 1];
+ if (result[0]->str() != RESULT)
+ throw ParseException("expected result");
type->result = stringToType(result[1]->str());
}
}
@@ -1662,7 +1843,8 @@ void SExpressionWasmBuilder::parseImport(Element& s) {
type = stringToType(inner[j]->str());
} else {
auto& inner2 = *inner[j];
- if (inner2[0]->str() != MUT) throw ParseException("expected mut");
+ if (inner2[0]->str() != MUT)
+ throw ParseException("expected mut");
type = stringToType(inner2[1]->str());
mutable_ = true;
}
@@ -1677,10 +1859,12 @@ void SExpressionWasmBuilder::parseImport(Element& s) {
wasm.table.module = module;
wasm.table.base = base;
if (j < inner.size() - 1) {
- wasm.table.initial = getCheckedAddress(inner[j++], "excessive table init size");
+ wasm.table.initial =
+ getCheckedAddress(inner[j++], "excessive table init size");
}
if (j < inner.size() - 1) {
- wasm.table.max = getCheckedAddress(inner[j++], "excessive table max size");
+ wasm.table.max =
+ getCheckedAddress(inner[j++], "excessive table max size");
} else {
wasm.table.max = Table::kUnlimitedSize;
}
@@ -1690,7 +1874,8 @@ void SExpressionWasmBuilder::parseImport(Element& s) {
wasm.memory.base = base;
if (inner[j]->isList()) {
auto& limits = *inner[j];
- if (!(limits[0]->isStr() && limits[0]->str() == "shared")) throw ParseException("bad memory limit declaration");
+ if (!(limits[0]->isStr() && limits[0]->str() == "shared"))
+ throw ParseException("bad memory limit declaration");
wasm.memory.shared = true;
parseMemoryLimits(limits, 1);
} else {
@@ -1720,7 +1905,8 @@ void SExpressionWasmBuilder::parseGlobal(Element& s, bool preParseImport) {
ex->name = inner[1]->str();
ex->value = global->name;
ex->kind = ExternalKind::Global;
- if (wasm.getExportOrNull(ex->name)) throw ParseException("duplicate export", s.line, s.col);
+ if (wasm.getExportOrNull(ex->name))
+ throw ParseException("duplicate export", s.line, s.col);
wasm.addExport(ex.release());
exported = true;
i++;
@@ -1736,25 +1922,30 @@ void SExpressionWasmBuilder::parseGlobal(Element& s, bool preParseImport) {
break;
}
}
- if (exported && mutable_) throw ParseException("cannot export a mutable global", s.line, s.col);
+ if (exported && mutable_)
+ throw ParseException("cannot export a mutable global", s.line, s.col);
if (type == none) {
type = stringToType(s[i++]->str());
}
if (importModule.is()) {
// this is an import, actually
- if (!importBase.size()) throw ParseException("module but no base for import");
- if (!preParseImport) throw ParseException("!preParseImport in global");
+ if (!importBase.size())
+ throw ParseException("module but no base for import");
+ if (!preParseImport)
+ throw ParseException("!preParseImport in global");
auto im = make_unique<Global>();
im->name = global->name;
im->module = importModule;
im->base = importBase;
im->type = type;
im->mutable_ = mutable_;
- if (wasm.getGlobalOrNull(im->name)) throw ParseException("duplicate import", s.line, s.col);
+ if (wasm.getGlobalOrNull(im->name))
+ throw ParseException("duplicate import", s.line, s.col);
wasm.addGlobal(im.release());
return;
}
- if (preParseImport) throw ParseException("preParseImport in global");
+ if (preParseImport)
+ throw ParseException("preParseImport in global");
global->type = type;
if (i < s.size()) {
global->init = parseExpression(s[i++]);
@@ -1762,21 +1953,25 @@ void SExpressionWasmBuilder::parseGlobal(Element& s, bool preParseImport) {
throw ParseException("global without init", s.line, s.col);
}
global->mutable_ = mutable_;
- if (i != s.size()) throw ParseException("extra import elements");
- if (wasm.getGlobalOrNull(global->name)) throw ParseException("duplicate import", s.line, s.col);
+ if (i != s.size())
+ throw ParseException("extra import elements");
+ if (wasm.getGlobalOrNull(global->name))
+ throw ParseException("duplicate import", s.line, s.col);
wasm.addGlobal(global.release());
}
-
void SExpressionWasmBuilder::parseTable(Element& s, bool preParseImport) {
- if (wasm.table.exists) throw ParseException("more than one table");
+ if (wasm.table.exists)
+ throw ParseException("more than one table");
wasm.table.exists = true;
Index i = 1;
- if (i == s.size()) return; // empty table in old notation
+ if (i == s.size())
+ return; // empty table in old notation
if (s[i]->dollared()) {
wasm.table.name = s[i++]->str();
}
- if (i == s.size()) return;
+ if (i == s.size())
+ return;
Name importModule, importBase;
if (s[i]->isList()) {
auto& inner = *s[i];
@@ -1785,11 +1980,13 @@ void SExpressionWasmBuilder::parseTable(Element& s, bool preParseImport) {
ex->name = inner[1]->str();
ex->value = wasm.table.name;
ex->kind = ExternalKind::Table;
- if (wasm.getExportOrNull(ex->name)) throw ParseException("duplicate export", s.line, s.col);
+ if (wasm.getExportOrNull(ex->name))
+ throw ParseException("duplicate export", s.line, s.col);
wasm.addExport(ex.release());
i++;
} else if (inner[0]->str() == IMPORT) {
- if (!preParseImport) throw ParseException("!preParseImport in table");
+ if (!preParseImport)
+ throw ParseException("!preParseImport in table");
wasm.table.module = inner[1]->str();
wasm.table.base = inner[2]->str();
i++;
@@ -1797,19 +1994,23 @@ void SExpressionWasmBuilder::parseTable(Element& s, bool preParseImport) {
throw ParseException("invalid table");
}
}
- if (i == s.size()) return;
+ if (i == s.size())
+ return;
if (!s[i]->dollared()) {
if (s[i]->str() == FUNCREF) {
// (table type (elem ..))
parseInnerElem(*s[i + 1]);
if (wasm.table.segments.size() > 0) {
- wasm.table.initial = wasm.table.max = wasm.table.segments[0].data.size();
+ wasm.table.initial = wasm.table.max =
+ wasm.table.segments[0].data.size();
} else {
wasm.table.initial = wasm.table.max = 0;
}
return;
}
- // first element isn't dollared, and isn't funcref. this could be old syntax for (table 0 1) which means function 0 and 1, or it could be (table initial max? type), look for type
+ // first element isn't dollared, and isn't funcref. this could be old syntax
+ // for (table 0 1) which means function 0 and 1, or it could be (table
+ // initial max? type), look for type
if (s[s.size() - 1]->str() == FUNCREF) {
// (table initial max? type)
if (i < s.size() - 1) {
@@ -1840,8 +2041,11 @@ void SExpressionWasmBuilder::parseElem(Element& s) {
parseInnerElem(s, i, offset);
}
-void SExpressionWasmBuilder::parseInnerElem(Element& s, Index i, Expression* offset) {
- if (!wasm.table.exists) throw ParseException("elem without table", s.line, s.col);
+void SExpressionWasmBuilder::parseInnerElem(Element& s,
+ Index i,
+ Expression* offset) {
+ if (!wasm.table.exists)
+ throw ParseException("elem without table", s.line, s.col);
if (!offset) {
offset = allocator.alloc<Const>()->set(Literal(int32_t(0)));
}
@@ -1867,7 +2071,8 @@ void SExpressionWasmBuilder::parseType(Element& s) {
type->params.push_back(stringToType(curr[j]->str()));
}
} else if (curr[0]->str() == RESULT) {
- if (curr.size() > 2) throw ParseException("invalid result arity", curr.line, curr.col);
+ if (curr.size() > 2)
+ throw ParseException("invalid result arity", curr.line, curr.col);
type->result = stringToType(curr[1]->str());
}
}
@@ -1875,7 +2080,8 @@ void SExpressionWasmBuilder::parseType(Element& s) {
type->name = Name::fromInt(wasm.functionTypes.size());
}
functionTypeNames.push_back(type->name);
- if (wasm.getFunctionTypeOrNull(type->name)) throw ParseException("duplicate function type", s.line, s.col);
+ if (wasm.getFunctionTypeOrNull(type->name))
+ throw ParseException("duplicate function type", s.line, s.col);
wasm.addFunctionType(std::move(type));
}
diff --git a/src/wasm/wasm-type.cpp b/src/wasm/wasm-type.cpp
index fc393ed98..78ad6f628 100644
--- a/src/wasm/wasm-type.cpp
+++ b/src/wasm/wasm-type.cpp
@@ -17,33 +17,46 @@
#include "wasm-type.h"
#include "wasm-features.h"
-#include <cstdlib>
#include "compiler-support.h"
+#include <cstdlib>
namespace wasm {
const char* printType(Type type) {
switch (type) {
- case Type::none: return "none";
- case Type::i32: return "i32";
- case Type::i64: return "i64";
- case Type::f32: return "f32";
- case Type::f64: return "f64";
- case Type::v128: return "v128";
- case Type::unreachable: return "unreachable";
+ case Type::none:
+ return "none";
+ case Type::i32:
+ return "i32";
+ case Type::i64:
+ return "i64";
+ case Type::f32:
+ return "f32";
+ case Type::f64:
+ return "f64";
+ case Type::v128:
+ return "v128";
+ case Type::unreachable:
+ return "unreachable";
}
WASM_UNREACHABLE();
}
unsigned getTypeSize(Type type) {
switch (type) {
- case Type::i32: return 4;
- case Type::i64: return 8;
- case Type::f32: return 4;
- case Type::f64: return 8;
- case Type::v128: return 16;
+ case Type::i32:
+ return 4;
+ case Type::i64:
+ return 8;
+ case Type::f32:
+ return 4;
+ case Type::f64:
+ return 8;
+ case Type::v128:
+ return 16;
case Type::none:
- case Type::unreachable: WASM_UNREACHABLE();
+ case Type::unreachable:
+ WASM_UNREACHABLE();
}
WASM_UNREACHABLE();
}
@@ -56,39 +69,41 @@ FeatureSet getFeatures(Type type) {
}
Type getType(unsigned size, bool float_) {
- if (size < 4) return Type::i32;
- if (size == 4) return float_ ? Type::f32 : Type::i32;
- if (size == 8) return float_ ? Type::f64 : Type::i64;
- if (size == 16) return Type::v128;
+ if (size < 4)
+ return Type::i32;
+ if (size == 4)
+ return float_ ? Type::f32 : Type::i32;
+ if (size == 8)
+ return float_ ? Type::f64 : Type::i64;
+ if (size == 16)
+ return Type::v128;
WASM_UNREACHABLE();
}
-Type getReachableType(Type a, Type b) {
- return a != unreachable ? a : b;
-}
+Type getReachableType(Type a, Type b) { return a != unreachable ? a : b; }
-bool isConcreteType(Type type) {
- return type != none && type != unreachable;
-}
+bool isConcreteType(Type type) { return type != none && type != unreachable; }
bool isIntegerType(Type type) {
switch (type) {
case i32:
- case i64: return true;
- default: return false;
+ case i64:
+ return true;
+ default:
+ return false;
}
}
bool isFloatType(Type type) {
switch (type) {
case f32:
- case f64: return true;
- default: return false;
+ case f64:
+ return true;
+ default:
+ return false;
}
}
-bool isVectorType(Type type) {
- return type == v128;
-}
+bool isVectorType(Type type) { return type == v128; }
} // namespace wasm
diff --git a/src/wasm/wasm-validator.cpp b/src/wasm/wasm-validator.cpp
index 1e94ead0a..ea8e92047 100644
--- a/src/wasm/wasm-validator.cpp
+++ b/src/wasm/wasm-validator.cpp
@@ -19,29 +19,30 @@
#include <sstream>
#include <unordered_set>
-#include "wasm.h"
-#include "wasm-printing.h"
-#include "wasm-validator.h"
-#include "ir/utils.h"
#include "ir/branch-utils.h"
#include "ir/features.h"
#include "ir/module-utils.h"
+#include "ir/utils.h"
#include "support/colors.h"
+#include "wasm-printing.h"
+#include "wasm-validator.h"
+#include "wasm.h"
namespace wasm {
// Print anything that can be streamed to an ostream
template<typename T,
- typename std::enable_if<
- !std::is_base_of<Expression, typename std::remove_pointer<T>::type>::value
- >::type* = nullptr>
+ typename std::enable_if<!std::is_base_of<
+ Expression,
+ typename std::remove_pointer<T>::type>::value>::type* = nullptr>
inline std::ostream& printModuleComponent(T curr, std::ostream& stream) {
stream << curr << std::endl;
return stream;
}
// Extra overload for Expressions, to print type info too
-inline std::ostream& printModuleComponent(Expression* curr, std::ostream& stream) {
+inline std::ostream& printModuleComponent(Expression* curr,
+ std::ostream& stream) {
WasmPrinter::printExpression(curr, stream, false, true) << std::endl;
return stream;
}
@@ -60,14 +61,13 @@ struct ValidationInfo {
std::mutex mutex;
std::unordered_map<Function*, std::unique_ptr<std::ostringstream>> outputs;
- ValidationInfo() {
- valid.store(true);
- }
+ ValidationInfo() { valid.store(true); }
std::ostringstream& getStream(Function* func) {
std::unique_lock<std::mutex> lock(mutex);
auto iter = outputs.find(func);
- if (iter != outputs.end()) return *(iter->second.get());
+ if (iter != outputs.end())
+ return *(iter->second.get());
auto& ret = outputs[func] = make_unique<std::ostringstream>();
return *ret.get();
}
@@ -78,7 +78,8 @@ struct ValidationInfo {
std::ostream& fail(S text, T curr, Function* func) {
valid.store(false);
auto& stream = getStream(func);
- if (quiet) return stream;
+ if (quiet)
+ return stream;
auto& ret = printFailureHeader(func);
ret << text << ", on \n";
return printModuleComponent(curr, ret);
@@ -86,7 +87,8 @@ struct ValidationInfo {
std::ostream& printFailureHeader(Function* func) {
auto& stream = getStream(func);
- if (quiet) return stream;
+ if (quiet)
+ return stream;
Colors::red(stream);
if (func) {
stream << "[wasm-validator error in function ";
@@ -104,7 +106,10 @@ struct ValidationInfo {
// checking utilities
template<typename T>
- bool shouldBeTrue(bool result, T curr, const char* text, Function* func = nullptr) {
+ bool shouldBeTrue(bool result,
+ T curr,
+ const char* text,
+ Function* func = nullptr) {
if (!result) {
fail("unexpected false: " + std::string(text), curr, func);
return false;
@@ -112,7 +117,10 @@ struct ValidationInfo {
return result;
}
template<typename T>
- bool shouldBeFalse(bool result, T curr, const char* text, Function* func = nullptr) {
+ bool shouldBeFalse(bool result,
+ T curr,
+ const char* text,
+ Function* func = nullptr) {
if (result) {
fail("unexpected true: " + std::string(text), curr, func);
return false;
@@ -121,7 +129,8 @@ struct ValidationInfo {
}
template<typename T, typename S>
- bool shouldBeEqual(S left, S right, T curr, const char* text, Function* func = nullptr) {
+ bool shouldBeEqual(
+ S left, S right, T curr, const char* text, Function* func = nullptr) {
if (left != right) {
std::ostringstream ss;
ss << left << " != " << right << ": " << text;
@@ -132,7 +141,8 @@ struct ValidationInfo {
}
template<typename T, typename S>
- bool shouldBeEqualOrFirstIsUnreachable(S left, S right, T curr, const char* text, Function* func = nullptr) {
+ bool shouldBeEqualOrFirstIsUnreachable(
+ S left, S right, T curr, const char* text, Function* func = nullptr) {
if (left != unreachable && left != right) {
std::ostringstream ss;
ss << left << " != " << right << ": " << text;
@@ -143,7 +153,8 @@ struct ValidationInfo {
}
template<typename T, typename S>
- bool shouldBeUnequal(S left, S right, T curr, const char* text, Function* func = nullptr) {
+ bool shouldBeUnequal(
+ S left, S right, T curr, const char* text, Function* func = nullptr) {
if (left == right) {
std::ostringstream ss;
ss << left << " == " << right << ": " << text;
@@ -153,17 +164,20 @@ struct ValidationInfo {
return true;
}
- void shouldBeIntOrUnreachable(Type ty, Expression* curr, const char* text, Function* func = nullptr) {
+ void shouldBeIntOrUnreachable(Type ty,
+ Expression* curr,
+ const char* text,
+ Function* func = nullptr) {
switch (ty) {
case i32:
case i64:
case unreachable: {
break;
}
- default: fail(text, curr, func);
+ default:
+ fail(text, curr, func);
}
}
-
};
struct FunctionValidator : public WalkerPass<PostWalker<FunctionValidator>> {
@@ -178,10 +192,7 @@ struct FunctionValidator : public WalkerPass<PostWalker<FunctionValidator>> {
FunctionValidator(ValidationInfo* info) : info(*info) {}
struct BreakInfo {
- enum {
- UnsetArity = Index(-1),
- PoisonArity = Index(-2)
- };
+ enum { UnsetArity = Index(-1), PoisonArity = Index(-2) };
Type type;
Index arity;
@@ -198,7 +209,9 @@ struct FunctionValidator : public WalkerPass<PostWalker<FunctionValidator>> {
Type returnType = unreachable; // type used in returns
- std::unordered_set<Name> labelNames; // Binaryen IR requires that label names must be unique - IR generators must ensure that
+ // Binaryen IR requires that label names must be unique - IR generators must
+ // ensure that
+ std::unordered_set<Name> labelNames;
void noteLabelName(Name name);
@@ -207,14 +220,16 @@ public:
static void visitPreBlock(FunctionValidator* self, Expression** currp) {
auto* curr = (*currp)->cast<Block>();
- if (curr->name.is()) self->breakInfos[curr->name];
+ if (curr->name.is())
+ self->breakInfos[curr->name];
}
void visitBlock(Block* curr);
static void visitPreLoop(FunctionValidator* self, Expression** currp) {
auto* curr = (*currp)->cast<Loop>();
- if (curr->name.is()) self->breakInfos[curr->name];
+ if (curr->name.is())
+ self->breakInfos[curr->name];
}
void visitLoop(Loop* curr);
@@ -225,8 +240,10 @@ public:
PostWalker<FunctionValidator>::scan(self, currp);
auto* curr = *currp;
- if (curr->is<Block>()) self->pushTask(visitPreBlock, currp);
- if (curr->is<Loop>()) self->pushTask(visitPreLoop, currp);
+ if (curr->is<Block>())
+ self->pushTask(visitPreBlock, currp);
+ if (curr->is<Loop>())
+ self->pushTask(visitPreLoop, currp);
}
void noteBreak(Name name, Expression* value, Expression* curr);
@@ -264,9 +281,7 @@ public:
// helpers
private:
- std::ostream& getStream() {
- return info.getStream(getFunction());
- }
+ std::ostream& getStream() { return info.getStream(getFunction()); }
template<typename T>
bool shouldBeTrue(bool result, T curr, const char* text) {
@@ -283,8 +298,10 @@ private:
}
template<typename T, typename S>
- bool shouldBeEqualOrFirstIsUnreachable(S left, S right, T curr, const char* text) {
- return info.shouldBeEqualOrFirstIsUnreachable(left, right, curr, text, getFunction());
+ bool
+ shouldBeEqualOrFirstIsUnreachable(S left, S right, T curr, const char* text) {
+ return info.shouldBeEqualOrFirstIsUnreachable(
+ left, right, curr, text, getFunction());
}
template<typename T, typename S>
@@ -296,16 +313,20 @@ private:
return info.shouldBeIntOrUnreachable(ty, curr, text, getFunction());
}
- void validateAlignment(size_t align, Type type, Index bytes, bool isAtomic,
- Expression* curr);
+ void validateAlignment(
+ size_t align, Type type, Index bytes, bool isAtomic, Expression* curr);
void validateMemBytes(uint8_t bytes, Type type, Expression* curr);
};
void FunctionValidator::noteLabelName(Name name) {
- if (!name.is()) return;
+ if (!name.is())
+ return;
bool inserted;
std::tie(std::ignore, inserted) = labelNames.insert(name);
- shouldBeTrue(inserted, name, "names in Binaryen IR must be unique - IR generators must ensure that");
+ shouldBeTrue(
+ inserted,
+ name,
+ "names in Binaryen IR must be unique - IR generators must ensure that");
}
void FunctionValidator::visitBlock(Block* curr) {
@@ -317,25 +338,46 @@ void FunctionValidator::visitBlock(Block* curr) {
auto& info = iter->second;
if (info.hasBeenSet()) {
if (isConcreteType(curr->type)) {
- shouldBeTrue(info.arity != 0, curr, "break arities must be > 0 if block has a value");
+ shouldBeTrue(info.arity != 0,
+ curr,
+ "break arities must be > 0 if block has a value");
} else {
- shouldBeTrue(info.arity == 0, curr, "break arities must be 0 if block has no value");
+ shouldBeTrue(info.arity == 0,
+ curr,
+ "break arities must be 0 if block has no value");
}
- // none or unreachable means a poison value that we should ignore - if consumed, it will error
+ // none or unreachable means a poison value that we should ignore - if
+ // consumed, it will error
if (isConcreteType(info.type) && isConcreteType(curr->type)) {
- shouldBeEqual(curr->type, info.type, curr, "block+breaks must have right type if breaks return a value");
+ shouldBeEqual(
+ curr->type,
+ info.type,
+ curr,
+ "block+breaks must have right type if breaks return a value");
}
- if (isConcreteType(curr->type) && info.arity && info.type != unreachable) {
- shouldBeEqual(curr->type, info.type, curr, "block+breaks must have right type if breaks have arity");
+ if (isConcreteType(curr->type) && info.arity &&
+ info.type != unreachable) {
+ shouldBeEqual(curr->type,
+ info.type,
+ curr,
+ "block+breaks must have right type if breaks have arity");
}
- shouldBeTrue(info.arity != BreakInfo::PoisonArity, curr, "break arities must match");
+ shouldBeTrue(
+ info.arity != BreakInfo::PoisonArity, curr, "break arities must match");
if (curr->list.size() > 0) {
auto last = curr->list.back()->type;
if (isConcreteType(last) && info.type != unreachable) {
- shouldBeEqual(last, info.type, curr, "block+breaks must have right type if block ends with a reachable value");
+ shouldBeEqual(last,
+ info.type,
+ curr,
+ "block+breaks must have right type if block ends with "
+ "a reachable value");
}
if (last == none) {
- shouldBeTrue(info.arity == Index(0), curr, "if block ends with a none, breaks cannot send a value of any type");
+ shouldBeTrue(info.arity == Index(0),
+ curr,
+ "if block ends with a none, breaks cannot send a value "
+ "of any type");
}
}
}
@@ -343,25 +385,44 @@ void FunctionValidator::visitBlock(Block* curr) {
}
if (curr->list.size() > 1) {
for (Index i = 0; i < curr->list.size() - 1; i++) {
- if (!shouldBeTrue(!isConcreteType(curr->list[i]->type), curr, "non-final block elements returning a value must be drop()ed (binaryen's autodrop option might help you)") && !info.quiet) {
- getStream() << "(on index " << i << ":\n" << curr->list[i] << "\n), type: " << curr->list[i]->type << "\n";
+ if (!shouldBeTrue(
+ !isConcreteType(curr->list[i]->type),
+ curr,
+ "non-final block elements returning a value must be drop()ed "
+ "(binaryen's autodrop option might help you)") &&
+ !info.quiet) {
+ getStream() << "(on index " << i << ":\n"
+ << curr->list[i] << "\n), type: " << curr->list[i]->type
+ << "\n";
}
}
}
if (curr->list.size() > 0) {
auto backType = curr->list.back()->type;
if (!isConcreteType(curr->type)) {
- shouldBeFalse(isConcreteType(backType), curr, "if block is not returning a value, final element should not flow out a value");
+ shouldBeFalse(isConcreteType(backType),
+ curr,
+ "if block is not returning a value, final element should "
+ "not flow out a value");
} else {
if (isConcreteType(backType)) {
- shouldBeEqual(curr->type, backType, curr, "block with value and last element with value must match types");
+ shouldBeEqual(
+ curr->type,
+ backType,
+ curr,
+ "block with value and last element with value must match types");
} else {
- shouldBeUnequal(backType, none, curr, "block with value must not have last element that is none");
+ shouldBeUnequal(
+ backType,
+ none,
+ curr,
+ "block with value must not have last element that is none");
}
}
}
if (isConcreteType(curr->type)) {
- shouldBeTrue(curr->list.size() > 0, curr, "block with a value must not be empty");
+ shouldBeTrue(
+ curr->list.size() > 0, curr, "block with a value must not be empty");
}
}
@@ -372,44 +433,84 @@ void FunctionValidator::visitLoop(Loop* curr) {
assert(iter != breakInfos.end()); // we set it ourselves
auto& info = iter->second;
if (info.hasBeenSet()) {
- shouldBeEqual(info.arity, Index(0), curr, "breaks to a loop cannot pass a value");
+ shouldBeEqual(
+ info.arity, Index(0), curr, "breaks to a loop cannot pass a value");
}
breakInfos.erase(iter);
}
if (curr->type == none) {
- shouldBeFalse(isConcreteType(curr->body->type), curr, "bad body for a loop that has no value");
+ shouldBeFalse(isConcreteType(curr->body->type),
+ curr,
+ "bad body for a loop that has no value");
}
}
void FunctionValidator::visitIf(If* curr) {
- shouldBeTrue(curr->condition->type == unreachable || curr->condition->type == i32, curr, "if condition must be valid");
+ shouldBeTrue(curr->condition->type == unreachable ||
+ curr->condition->type == i32,
+ curr,
+ "if condition must be valid");
if (!curr->ifFalse) {
- shouldBeFalse(isConcreteType(curr->ifTrue->type), curr, "if without else must not return a value in body");
+ shouldBeFalse(isConcreteType(curr->ifTrue->type),
+ curr,
+ "if without else must not return a value in body");
if (curr->condition->type != unreachable) {
- shouldBeEqual(curr->type, none, curr, "if without else and reachable condition must be none");
+ shouldBeEqual(curr->type,
+ none,
+ curr,
+ "if without else and reachable condition must be none");
}
} else {
if (curr->type != unreachable) {
- shouldBeEqualOrFirstIsUnreachable(curr->ifTrue->type, curr->type, curr, "returning if-else's true must have right type");
- shouldBeEqualOrFirstIsUnreachable(curr->ifFalse->type, curr->type, curr, "returning if-else's false must have right type");
+ shouldBeEqualOrFirstIsUnreachable(
+ curr->ifTrue->type,
+ curr->type,
+ curr,
+ "returning if-else's true must have right type");
+ shouldBeEqualOrFirstIsUnreachable(
+ curr->ifFalse->type,
+ curr->type,
+ curr,
+ "returning if-else's false must have right type");
} else {
if (curr->condition->type != unreachable) {
- shouldBeEqual(curr->ifTrue->type, unreachable, curr, "unreachable if-else must have unreachable true");
- shouldBeEqual(curr->ifFalse->type, unreachable, curr, "unreachable if-else must have unreachable false");
+ shouldBeEqual(curr->ifTrue->type,
+ unreachable,
+ curr,
+ "unreachable if-else must have unreachable true");
+ shouldBeEqual(curr->ifFalse->type,
+ unreachable,
+ curr,
+ "unreachable if-else must have unreachable false");
}
}
if (isConcreteType(curr->ifTrue->type)) {
- shouldBeEqual(curr->type, curr->ifTrue->type, curr, "if type must match concrete ifTrue");
- shouldBeEqualOrFirstIsUnreachable(curr->ifFalse->type, curr->ifTrue->type, curr, "other arm must match concrete ifTrue");
+ shouldBeEqual(curr->type,
+ curr->ifTrue->type,
+ curr,
+ "if type must match concrete ifTrue");
+ shouldBeEqualOrFirstIsUnreachable(curr->ifFalse->type,
+ curr->ifTrue->type,
+ curr,
+ "other arm must match concrete ifTrue");
}
if (isConcreteType(curr->ifFalse->type)) {
- shouldBeEqual(curr->type, curr->ifFalse->type, curr, "if type must match concrete ifFalse");
- shouldBeEqualOrFirstIsUnreachable(curr->ifTrue->type, curr->ifFalse->type, curr, "other arm must match concrete ifFalse");
+ shouldBeEqual(curr->type,
+ curr->ifFalse->type,
+ curr,
+ "if type must match concrete ifFalse");
+ shouldBeEqualOrFirstIsUnreachable(
+ curr->ifTrue->type,
+ curr->ifFalse->type,
+ curr,
+ "other arm must match concrete ifFalse");
}
}
}
-void FunctionValidator::noteBreak(Name name, Expression* value, Expression* curr) {
+void FunctionValidator::noteBreak(Name name,
+ Expression* value,
+ Expression* curr) {
Type valueType = none;
Index arity = 0;
if (value) {
@@ -418,7 +519,9 @@ void FunctionValidator::noteBreak(Name name, Expression* value, Expression* curr
arity = 1;
}
auto iter = breakInfos.find(name);
- if (!shouldBeTrue(iter != breakInfos.end(), curr, "all break targets must be valid")) return;
+ if (!shouldBeTrue(
+ iter != breakInfos.end(), curr, "all break targets must be valid"))
+ return;
auto& info = iter->second;
if (!info.hasBeenSet()) {
info = BreakInfo(valueType, arity);
@@ -438,7 +541,10 @@ void FunctionValidator::noteBreak(Name name, Expression* value, Expression* curr
void FunctionValidator::visitBreak(Break* curr) {
noteBreak(curr->name, curr->value, curr);
if (curr->condition) {
- shouldBeTrue(curr->condition->type == unreachable || curr->condition->type == i32, curr, "break condition must be i32");
+ shouldBeTrue(curr->condition->type == unreachable ||
+ curr->condition->type == i32,
+ curr,
+ "break condition must be i32");
}
}
@@ -447,260 +553,500 @@ void FunctionValidator::visitSwitch(Switch* curr) {
noteBreak(target, curr->value, curr);
}
noteBreak(curr->default_, curr->value, curr);
- shouldBeTrue(curr->condition->type == unreachable || curr->condition->type == i32, curr, "br_table condition must be i32");
+ shouldBeTrue(curr->condition->type == unreachable ||
+ curr->condition->type == i32,
+ curr,
+ "br_table condition must be i32");
}
void FunctionValidator::visitCall(Call* curr) {
- if (!info.validateGlobally) return;
+ if (!info.validateGlobally)
+ return;
auto* target = getModule()->getFunctionOrNull(curr->target);
- if (!shouldBeTrue(!!target, curr, "call target must exist")) return;
- if (!shouldBeTrue(curr->operands.size() == target->params.size(), curr, "call param number must match")) return;
+ if (!shouldBeTrue(!!target, curr, "call target must exist"))
+ return;
+ if (!shouldBeTrue(curr->operands.size() == target->params.size(),
+ curr,
+ "call param number must match"))
+ return;
for (size_t i = 0; i < curr->operands.size(); i++) {
- if (!shouldBeEqualOrFirstIsUnreachable(curr->operands[i]->type, target->params[i], curr, "call param types must match") && !info.quiet) {
+ if (!shouldBeEqualOrFirstIsUnreachable(curr->operands[i]->type,
+ target->params[i],
+ curr,
+ "call param types must match") &&
+ !info.quiet) {
getStream() << "(on argument " << i << ")\n";
}
}
}
void FunctionValidator::visitCallIndirect(CallIndirect* curr) {
- if (!info.validateGlobally) return;
+ if (!info.validateGlobally)
+ return;
auto* type = getModule()->getFunctionTypeOrNull(curr->fullType);
- if (!shouldBeTrue(!!type, curr, "call_indirect type must exist")) return;
- shouldBeEqualOrFirstIsUnreachable(curr->target->type, i32, curr, "indirect call target must be an i32");
- if (!shouldBeTrue(curr->operands.size() == type->params.size(), curr, "call param number must match")) return;
+ if (!shouldBeTrue(!!type, curr, "call_indirect type must exist"))
+ return;
+ shouldBeEqualOrFirstIsUnreachable(
+ curr->target->type, i32, curr, "indirect call target must be an i32");
+ if (!shouldBeTrue(curr->operands.size() == type->params.size(),
+ curr,
+ "call param number must match"))
+ return;
for (size_t i = 0; i < curr->operands.size(); i++) {
- if (!shouldBeEqualOrFirstIsUnreachable(curr->operands[i]->type, type->params[i], curr, "call param types must match") && !info.quiet) {
+ if (!shouldBeEqualOrFirstIsUnreachable(curr->operands[i]->type,
+ type->params[i],
+ curr,
+ "call param types must match") &&
+ !info.quiet) {
getStream() << "(on argument " << i << ")\n";
}
}
}
void FunctionValidator::visitConst(Const* curr) {
- shouldBeTrue(getFeatures(curr->type) <= getModule()->features, curr,
+ shouldBeTrue(getFeatures(curr->type) <= getModule()->features,
+ curr,
"all used features should be allowed");
}
void FunctionValidator::visitGetLocal(GetLocal* curr) {
- shouldBeTrue(curr->index < getFunction()->getNumLocals(), curr, "local.get index must be small enough");
- shouldBeTrue(isConcreteType(curr->type), curr, "local.get must have a valid type - check what you provided when you constructed the node");
- shouldBeTrue(curr->type == getFunction()->getLocalType(curr->index), curr, "local.get must have proper type");
+ shouldBeTrue(curr->index < getFunction()->getNumLocals(),
+ curr,
+ "local.get index must be small enough");
+ shouldBeTrue(isConcreteType(curr->type),
+ curr,
+ "local.get must have a valid type - check what you provided "
+ "when you constructed the node");
+ shouldBeTrue(curr->type == getFunction()->getLocalType(curr->index),
+ curr,
+ "local.get must have proper type");
}
void FunctionValidator::visitSetLocal(SetLocal* curr) {
- shouldBeTrue(curr->index < getFunction()->getNumLocals(), curr, "local.set index must be small enough");
+ shouldBeTrue(curr->index < getFunction()->getNumLocals(),
+ curr,
+ "local.set index must be small enough");
if (curr->value->type != unreachable) {
if (curr->type != none) { // tee is ok anyhow
- shouldBeEqualOrFirstIsUnreachable(curr->value->type, curr->type, curr, "local.set type must be correct");
+ shouldBeEqualOrFirstIsUnreachable(
+ curr->value->type, curr->type, curr, "local.set type must be correct");
}
- shouldBeEqual(getFunction()->getLocalType(curr->index), curr->value->type, curr, "local.set type must match function");
+ shouldBeEqual(getFunction()->getLocalType(curr->index),
+ curr->value->type,
+ curr,
+ "local.set type must match function");
}
}
void FunctionValidator::visitGetGlobal(GetGlobal* curr) {
- if (!info.validateGlobally) return;
- shouldBeTrue(getModule()->getGlobalOrNull(curr->name), curr, "global.get name must be valid");
+ if (!info.validateGlobally)
+ return;
+ shouldBeTrue(getModule()->getGlobalOrNull(curr->name),
+ curr,
+ "global.get name must be valid");
}
void FunctionValidator::visitSetGlobal(SetGlobal* curr) {
- if (!info.validateGlobally) return;
+ if (!info.validateGlobally)
+ return;
auto* global = getModule()->getGlobalOrNull(curr->name);
- if (shouldBeTrue(global, curr, "global.set name must be valid (and not an import; imports can't be modified)")) {
+ if (shouldBeTrue(global,
+ curr,
+ "global.set name must be valid (and not an import; imports "
+ "can't be modified)")) {
shouldBeTrue(global->mutable_, curr, "global.set global must be mutable");
- shouldBeEqualOrFirstIsUnreachable(curr->value->type, global->type, curr, "global.set value must have right type");
+ shouldBeEqualOrFirstIsUnreachable(curr->value->type,
+ global->type,
+ curr,
+ "global.set value must have right type");
}
}
void FunctionValidator::visitLoad(Load* curr) {
- shouldBeTrue(getModule()->memory.exists, curr, "Memory operations require a memory");
+ shouldBeTrue(
+ getModule()->memory.exists, curr, "Memory operations require a memory");
if (curr->isAtomic) {
- shouldBeTrue(getModule()->features.hasAtomics(), curr, "Atomic operation (atomics are disabled)");
- shouldBeTrue(curr->type == i32 || curr->type == i64 || curr->type == unreachable, curr, "Atomic load should be i32 or i64");
- }
- if (curr->type == v128) shouldBeTrue(getModule()->features.hasSIMD(), curr, "SIMD operation (SIMD is disabled)");
- shouldBeFalse(curr->isAtomic && !getModule()->memory.shared, curr, "Atomic operation with non-shared memory");
+ shouldBeTrue(getModule()->features.hasAtomics(),
+ curr,
+ "Atomic operation (atomics are disabled)");
+ shouldBeTrue(curr->type == i32 || curr->type == i64 ||
+ curr->type == unreachable,
+ curr,
+ "Atomic load should be i32 or i64");
+ }
+ if (curr->type == v128)
+ shouldBeTrue(getModule()->features.hasSIMD(),
+ curr,
+ "SIMD operation (SIMD is disabled)");
+ shouldBeFalse(curr->isAtomic && !getModule()->memory.shared,
+ curr,
+ "Atomic operation with non-shared memory");
validateMemBytes(curr->bytes, curr->type, curr);
validateAlignment(curr->align, curr->type, curr->bytes, curr->isAtomic, curr);
- shouldBeEqualOrFirstIsUnreachable(curr->ptr->type, i32, curr, "load pointer type must be i32");
+ shouldBeEqualOrFirstIsUnreachable(
+ curr->ptr->type, i32, curr, "load pointer type must be i32");
if (curr->isAtomic) {
shouldBeFalse(curr->signed_, curr, "atomic loads must be unsigned");
- shouldBeIntOrUnreachable(curr->type, curr, "atomic loads must be of integers");
+ shouldBeIntOrUnreachable(
+ curr->type, curr, "atomic loads must be of integers");
}
}
void FunctionValidator::visitStore(Store* curr) {
- shouldBeTrue(getModule()->memory.exists, curr, "Memory operations require a memory");
+ shouldBeTrue(
+ getModule()->memory.exists, curr, "Memory operations require a memory");
if (curr->isAtomic) {
- shouldBeTrue(getModule()->features.hasAtomics(), curr, "Atomic operation (atomics are disabled)");
- shouldBeTrue(curr->valueType == i32 || curr->valueType == i64 || curr->valueType == unreachable, curr, "Atomic store should be i32 or i64");
- }
- if (curr->valueType == v128) shouldBeTrue(getModule()->features.hasSIMD(), curr, "SIMD operation (SIMD is disabled)");
- shouldBeFalse(curr->isAtomic && !getModule()->memory.shared, curr, "Atomic operation with non-shared memory");
+ shouldBeTrue(getModule()->features.hasAtomics(),
+ curr,
+ "Atomic operation (atomics are disabled)");
+ shouldBeTrue(curr->valueType == i32 || curr->valueType == i64 ||
+ curr->valueType == unreachable,
+ curr,
+ "Atomic store should be i32 or i64");
+ }
+ if (curr->valueType == v128)
+ shouldBeTrue(getModule()->features.hasSIMD(),
+ curr,
+ "SIMD operation (SIMD is disabled)");
+ shouldBeFalse(curr->isAtomic && !getModule()->memory.shared,
+ curr,
+ "Atomic operation with non-shared memory");
validateMemBytes(curr->bytes, curr->valueType, curr);
- validateAlignment(curr->align, curr->valueType, curr->bytes, curr->isAtomic, curr);
- shouldBeEqualOrFirstIsUnreachable(curr->ptr->type, i32, curr, "store pointer type must be i32");
- shouldBeUnequal(curr->value->type, none, curr, "store value type must not be none");
- shouldBeEqualOrFirstIsUnreachable(curr->value->type, curr->valueType, curr, "store value type must match");
+ validateAlignment(
+ curr->align, curr->valueType, curr->bytes, curr->isAtomic, curr);
+ shouldBeEqualOrFirstIsUnreachable(
+ curr->ptr->type, i32, curr, "store pointer type must be i32");
+ shouldBeUnequal(
+ curr->value->type, none, curr, "store value type must not be none");
+ shouldBeEqualOrFirstIsUnreachable(
+ curr->value->type, curr->valueType, curr, "store value type must match");
if (curr->isAtomic) {
- shouldBeIntOrUnreachable(curr->valueType, curr, "atomic stores must be of integers");
+ shouldBeIntOrUnreachable(
+ curr->valueType, curr, "atomic stores must be of integers");
}
}
void FunctionValidator::visitAtomicRMW(AtomicRMW* curr) {
- shouldBeTrue(getModule()->memory.exists, curr, "Memory operations require a memory");
- shouldBeTrue(getModule()->features.hasAtomics(), curr, "Atomic operation (atomics are disabled)");
- shouldBeFalse(!getModule()->memory.shared, curr, "Atomic operation with non-shared memory");
+ shouldBeTrue(
+ getModule()->memory.exists, curr, "Memory operations require a memory");
+ shouldBeTrue(getModule()->features.hasAtomics(),
+ curr,
+ "Atomic operation (atomics are disabled)");
+ shouldBeFalse(!getModule()->memory.shared,
+ curr,
+ "Atomic operation with non-shared memory");
validateMemBytes(curr->bytes, curr->type, curr);
- shouldBeEqualOrFirstIsUnreachable(curr->ptr->type, i32, curr, "AtomicRMW pointer type must be i32");
- shouldBeEqualOrFirstIsUnreachable(curr->type, curr->value->type, curr, "AtomicRMW result type must match operand");
- shouldBeIntOrUnreachable(curr->type, curr, "Atomic operations are only valid on int types");
+ shouldBeEqualOrFirstIsUnreachable(
+ curr->ptr->type, i32, curr, "AtomicRMW pointer type must be i32");
+ shouldBeEqualOrFirstIsUnreachable(curr->type,
+ curr->value->type,
+ curr,
+ "AtomicRMW result type must match operand");
+ shouldBeIntOrUnreachable(
+ curr->type, curr, "Atomic operations are only valid on int types");
}
void FunctionValidator::visitAtomicCmpxchg(AtomicCmpxchg* curr) {
- shouldBeTrue(getModule()->memory.exists, curr, "Memory operations require a memory");
- shouldBeTrue(getModule()->features.hasAtomics(), curr, "Atomic operation (atomics are disabled)");
- shouldBeFalse(!getModule()->memory.shared, curr, "Atomic operation with non-shared memory");
+ shouldBeTrue(
+ getModule()->memory.exists, curr, "Memory operations require a memory");
+ shouldBeTrue(getModule()->features.hasAtomics(),
+ curr,
+ "Atomic operation (atomics are disabled)");
+ shouldBeFalse(!getModule()->memory.shared,
+ curr,
+ "Atomic operation with non-shared memory");
validateMemBytes(curr->bytes, curr->type, curr);
- shouldBeEqualOrFirstIsUnreachable(curr->ptr->type, i32, curr, "cmpxchg pointer type must be i32");
- if (curr->expected->type != unreachable && curr->replacement->type != unreachable) {
- shouldBeEqual(curr->expected->type, curr->replacement->type, curr, "cmpxchg operand types must match");
- }
- shouldBeEqualOrFirstIsUnreachable(curr->type, curr->expected->type, curr, "Cmpxchg result type must match expected");
- shouldBeEqualOrFirstIsUnreachable(curr->type, curr->replacement->type, curr, "Cmpxchg result type must match replacement");
- shouldBeIntOrUnreachable(curr->expected->type, curr, "Atomic operations are only valid on int types");
+ shouldBeEqualOrFirstIsUnreachable(
+ curr->ptr->type, i32, curr, "cmpxchg pointer type must be i32");
+ if (curr->expected->type != unreachable &&
+ curr->replacement->type != unreachable) {
+ shouldBeEqual(curr->expected->type,
+ curr->replacement->type,
+ curr,
+ "cmpxchg operand types must match");
+ }
+ shouldBeEqualOrFirstIsUnreachable(curr->type,
+ curr->expected->type,
+ curr,
+ "Cmpxchg result type must match expected");
+ shouldBeEqualOrFirstIsUnreachable(
+ curr->type,
+ curr->replacement->type,
+ curr,
+ "Cmpxchg result type must match replacement");
+ shouldBeIntOrUnreachable(curr->expected->type,
+ curr,
+ "Atomic operations are only valid on int types");
}
void FunctionValidator::visitAtomicWait(AtomicWait* curr) {
- shouldBeTrue(getModule()->memory.exists, curr, "Memory operations require a memory");
- shouldBeTrue(getModule()->features.hasAtomics(), curr, "Atomic operation (atomics are disabled)");
- shouldBeFalse(!getModule()->memory.shared, curr, "Atomic operation with non-shared memory");
- shouldBeEqualOrFirstIsUnreachable(curr->type, i32, curr, "AtomicWait must have type i32");
- shouldBeEqualOrFirstIsUnreachable(curr->ptr->type, i32, curr, "AtomicWait pointer type must be i32");
- shouldBeIntOrUnreachable(curr->expected->type, curr, "AtomicWait expected type must be int");
- shouldBeEqualOrFirstIsUnreachable(curr->expected->type, curr->expectedType, curr, "AtomicWait expected type must match operand");
- shouldBeEqualOrFirstIsUnreachable(curr->timeout->type, i64, curr, "AtomicWait timeout type must be i64");
+ shouldBeTrue(
+ getModule()->memory.exists, curr, "Memory operations require a memory");
+ shouldBeTrue(getModule()->features.hasAtomics(),
+ curr,
+ "Atomic operation (atomics are disabled)");
+ shouldBeFalse(!getModule()->memory.shared,
+ curr,
+ "Atomic operation with non-shared memory");
+ shouldBeEqualOrFirstIsUnreachable(
+ curr->type, i32, curr, "AtomicWait must have type i32");
+ shouldBeEqualOrFirstIsUnreachable(
+ curr->ptr->type, i32, curr, "AtomicWait pointer type must be i32");
+ shouldBeIntOrUnreachable(
+ curr->expected->type, curr, "AtomicWait expected type must be int");
+ shouldBeEqualOrFirstIsUnreachable(
+ curr->expected->type,
+ curr->expectedType,
+ curr,
+ "AtomicWait expected type must match operand");
+ shouldBeEqualOrFirstIsUnreachable(
+ curr->timeout->type, i64, curr, "AtomicWait timeout type must be i64");
}
void FunctionValidator::visitAtomicNotify(AtomicNotify* curr) {
- shouldBeTrue(getModule()->memory.exists, curr, "Memory operations require a memory");
- shouldBeTrue(getModule()->features.hasAtomics(), curr, "Atomic operation (atomics are disabled)");
- shouldBeFalse(!getModule()->memory.shared, curr, "Atomic operation with non-shared memory");
- shouldBeEqualOrFirstIsUnreachable(curr->type, i32, curr, "AtomicNotify must have type i32");
- shouldBeEqualOrFirstIsUnreachable(curr->ptr->type, i32, curr, "AtomicNotify pointer type must be i32");
- shouldBeEqualOrFirstIsUnreachable(curr->notifyCount->type, i32, curr, "AtomicNotify notifyCount type must be i32");
+ shouldBeTrue(
+ getModule()->memory.exists, curr, "Memory operations require a memory");
+ shouldBeTrue(getModule()->features.hasAtomics(),
+ curr,
+ "Atomic operation (atomics are disabled)");
+ shouldBeFalse(!getModule()->memory.shared,
+ curr,
+ "Atomic operation with non-shared memory");
+ shouldBeEqualOrFirstIsUnreachable(
+ curr->type, i32, curr, "AtomicNotify must have type i32");
+ shouldBeEqualOrFirstIsUnreachable(
+ curr->ptr->type, i32, curr, "AtomicNotify pointer type must be i32");
+ shouldBeEqualOrFirstIsUnreachable(
+ curr->notifyCount->type,
+ i32,
+ curr,
+ "AtomicNotify notifyCount type must be i32");
}
void FunctionValidator::visitSIMDExtract(SIMDExtract* curr) {
- shouldBeTrue(getModule()->features.hasSIMD(), curr, "SIMD operation (SIMD is disabled)");
- shouldBeEqualOrFirstIsUnreachable(curr->vec->type, v128, curr, "extract_lane must operate on a v128");
+ shouldBeTrue(
+ getModule()->features.hasSIMD(), curr, "SIMD operation (SIMD is disabled)");
+ shouldBeEqualOrFirstIsUnreachable(
+ curr->vec->type, v128, curr, "extract_lane must operate on a v128");
Type lane_t = none;
size_t lanes = 0;
switch (curr->op) {
case ExtractLaneSVecI8x16:
- case ExtractLaneUVecI8x16: lane_t = i32; lanes = 16; break;
+ case ExtractLaneUVecI8x16:
+ lane_t = i32;
+ lanes = 16;
+ break;
case ExtractLaneSVecI16x8:
- case ExtractLaneUVecI16x8: lane_t = i32; lanes = 8; break;
- case ExtractLaneVecI32x4: lane_t = i32; lanes = 4; break;
- case ExtractLaneVecI64x2: lane_t = i64; lanes = 2; break;
- case ExtractLaneVecF32x4: lane_t = f32; lanes = 4; break;
- case ExtractLaneVecF64x2: lane_t = f64; lanes = 2; break;
+ case ExtractLaneUVecI16x8:
+ lane_t = i32;
+ lanes = 8;
+ break;
+ case ExtractLaneVecI32x4:
+ lane_t = i32;
+ lanes = 4;
+ break;
+ case ExtractLaneVecI64x2:
+ lane_t = i64;
+ lanes = 2;
+ break;
+ case ExtractLaneVecF32x4:
+ lane_t = f32;
+ lanes = 4;
+ break;
+ case ExtractLaneVecF64x2:
+ lane_t = f64;
+ lanes = 2;
+ break;
}
- shouldBeEqualOrFirstIsUnreachable(curr->type, lane_t, curr, "extract_lane must have same type as vector lane");
+ shouldBeEqualOrFirstIsUnreachable(
+ curr->type,
+ lane_t,
+ curr,
+ "extract_lane must have same type as vector lane");
shouldBeTrue(curr->index < lanes, curr, "invalid lane index");
}
void FunctionValidator::visitSIMDReplace(SIMDReplace* curr) {
- shouldBeTrue(getModule()->features.hasSIMD(), curr, "SIMD operation (SIMD is disabled)");
- shouldBeEqualOrFirstIsUnreachable(curr->type, v128, curr, "replace_lane must have type v128");
- shouldBeEqualOrFirstIsUnreachable(curr->vec->type, v128, curr, "replace_lane must operate on a v128");
+ shouldBeTrue(
+ getModule()->features.hasSIMD(), curr, "SIMD operation (SIMD is disabled)");
+ shouldBeEqualOrFirstIsUnreachable(
+ curr->type, v128, curr, "replace_lane must have type v128");
+ shouldBeEqualOrFirstIsUnreachable(
+ curr->vec->type, v128, curr, "replace_lane must operate on a v128");
Type lane_t = none;
size_t lanes = 0;
switch (curr->op) {
- case ReplaceLaneVecI8x16: lane_t = i32; lanes = 16; break;
- case ReplaceLaneVecI16x8: lane_t = i32; lanes = 8; break;
- case ReplaceLaneVecI32x4: lane_t = i32; lanes = 4; break;
- case ReplaceLaneVecI64x2: lane_t = i64; lanes = 2; break;
- case ReplaceLaneVecF32x4: lane_t = f32; lanes = 4; break;
- case ReplaceLaneVecF64x2: lane_t = f64; lanes = 2; break;
- }
- shouldBeEqualOrFirstIsUnreachable(curr->value->type, lane_t, curr, "unexpected value type");
+ case ReplaceLaneVecI8x16:
+ lane_t = i32;
+ lanes = 16;
+ break;
+ case ReplaceLaneVecI16x8:
+ lane_t = i32;
+ lanes = 8;
+ break;
+ case ReplaceLaneVecI32x4:
+ lane_t = i32;
+ lanes = 4;
+ break;
+ case ReplaceLaneVecI64x2:
+ lane_t = i64;
+ lanes = 2;
+ break;
+ case ReplaceLaneVecF32x4:
+ lane_t = f32;
+ lanes = 4;
+ break;
+ case ReplaceLaneVecF64x2:
+ lane_t = f64;
+ lanes = 2;
+ break;
+ }
+ shouldBeEqualOrFirstIsUnreachable(
+ curr->value->type, lane_t, curr, "unexpected value type");
shouldBeTrue(curr->index < lanes, curr, "invalid lane index");
}
void FunctionValidator::visitSIMDShuffle(SIMDShuffle* curr) {
- shouldBeTrue(getModule()->features.hasSIMD(), curr, "SIMD operation (SIMD is disabled)");
- shouldBeEqualOrFirstIsUnreachable(curr->type, v128, curr, "v128.shuffle must have type v128");
- shouldBeEqualOrFirstIsUnreachable(curr->left->type, v128, curr, "expected operand of type v128");
- shouldBeEqualOrFirstIsUnreachable(curr->right->type, v128, curr, "expected operand of type v128");
+ shouldBeTrue(
+ getModule()->features.hasSIMD(), curr, "SIMD operation (SIMD is disabled)");
+ shouldBeEqualOrFirstIsUnreachable(
+ curr->type, v128, curr, "v128.shuffle must have type v128");
+ shouldBeEqualOrFirstIsUnreachable(
+ curr->left->type, v128, curr, "expected operand of type v128");
+ shouldBeEqualOrFirstIsUnreachable(
+ curr->right->type, v128, curr, "expected operand of type v128");
for (uint8_t index : curr->mask) {
shouldBeTrue(index < 32, curr, "Invalid lane index in mask");
}
}
void FunctionValidator::visitSIMDBitselect(SIMDBitselect* curr) {
- shouldBeTrue(getModule()->features.hasSIMD(), curr, "SIMD operation (SIMD is disabled)");
- shouldBeEqualOrFirstIsUnreachable(curr->type, v128, curr, "v128.bitselect must have type v128");
- shouldBeEqualOrFirstIsUnreachable(curr->left->type, v128, curr, "expected operand of type v128");
- shouldBeEqualOrFirstIsUnreachable(curr->right->type, v128, curr, "expected operand of type v128");
- shouldBeEqualOrFirstIsUnreachable(curr->cond->type, v128, curr, "expected operand of type v128");
+ shouldBeTrue(
+ getModule()->features.hasSIMD(), curr, "SIMD operation (SIMD is disabled)");
+ shouldBeEqualOrFirstIsUnreachable(
+ curr->type, v128, curr, "v128.bitselect must have type v128");
+ shouldBeEqualOrFirstIsUnreachable(
+ curr->left->type, v128, curr, "expected operand of type v128");
+ shouldBeEqualOrFirstIsUnreachable(
+ curr->right->type, v128, curr, "expected operand of type v128");
+ shouldBeEqualOrFirstIsUnreachable(
+ curr->cond->type, v128, curr, "expected operand of type v128");
}
void FunctionValidator::visitSIMDShift(SIMDShift* curr) {
- shouldBeTrue(getModule()->features.hasSIMD(), curr, "SIMD operation (SIMD is disabled)");
- shouldBeEqualOrFirstIsUnreachable(curr->type, v128, curr, "vector shift must have type v128");
- shouldBeEqualOrFirstIsUnreachable(curr->vec->type, v128, curr, "expected operand of type v128");
- shouldBeEqualOrFirstIsUnreachable(curr->shift->type, i32, curr, "expected shift amount to have type i32");
+ shouldBeTrue(
+ getModule()->features.hasSIMD(), curr, "SIMD operation (SIMD is disabled)");
+ shouldBeEqualOrFirstIsUnreachable(
+ curr->type, v128, curr, "vector shift must have type v128");
+ shouldBeEqualOrFirstIsUnreachable(
+ curr->vec->type, v128, curr, "expected operand of type v128");
+ shouldBeEqualOrFirstIsUnreachable(
+ curr->shift->type, i32, curr, "expected shift amount to have type i32");
}
void FunctionValidator::visitMemoryInit(MemoryInit* curr) {
- shouldBeTrue(getModule()->memory.exists, curr, "Memory operations require a memory");
- shouldBeTrue(getModule()->features.hasBulkMemory(), curr, "Bulk memory operation (bulk memory is disabled)");
- shouldBeEqualOrFirstIsUnreachable(curr->type, none, curr, "memory.init must have type none");
- shouldBeEqualOrFirstIsUnreachable(curr->dest->type, i32, curr, "memory.init dest must be an i32");
- shouldBeEqualOrFirstIsUnreachable(curr->offset->type, i32, curr, "memory.init offset must be an i32");
- shouldBeEqualOrFirstIsUnreachable(curr->size->type, i32, curr, "memory.init size must be an i32");
- shouldBeTrue(curr->segment < getModule()->memory.segments.size(), curr, "memory.init segment index out of bounds");
+ shouldBeTrue(
+ getModule()->memory.exists, curr, "Memory operations require a memory");
+ shouldBeTrue(getModule()->features.hasBulkMemory(),
+ curr,
+ "Bulk memory operation (bulk memory is disabled)");
+ shouldBeEqualOrFirstIsUnreachable(
+ curr->type, none, curr, "memory.init must have type none");
+ shouldBeEqualOrFirstIsUnreachable(
+ curr->dest->type, i32, curr, "memory.init dest must be an i32");
+ shouldBeEqualOrFirstIsUnreachable(
+ curr->offset->type, i32, curr, "memory.init offset must be an i32");
+ shouldBeEqualOrFirstIsUnreachable(
+ curr->size->type, i32, curr, "memory.init size must be an i32");
+ shouldBeTrue(curr->segment < getModule()->memory.segments.size(),
+ curr,
+ "memory.init segment index out of bounds");
}
void FunctionValidator::visitDataDrop(DataDrop* curr) {
- shouldBeTrue(getModule()->memory.exists, curr, "Memory operations require a memory");
- shouldBeTrue(getModule()->features.hasBulkMemory(), curr, "Bulk memory operation (bulk memory is disabled)");
- shouldBeEqualOrFirstIsUnreachable(curr->type, none, curr, "data.drop must have type none");
- shouldBeTrue(curr->segment < getModule()->memory.segments.size(), curr, "data.drop segment index out of bounds");
+ shouldBeTrue(
+ getModule()->memory.exists, curr, "Memory operations require a memory");
+ shouldBeTrue(getModule()->features.hasBulkMemory(),
+ curr,
+ "Bulk memory operation (bulk memory is disabled)");
+ shouldBeEqualOrFirstIsUnreachable(
+ curr->type, none, curr, "data.drop must have type none");
+ shouldBeTrue(curr->segment < getModule()->memory.segments.size(),
+ curr,
+ "data.drop segment index out of bounds");
}
void FunctionValidator::visitMemoryCopy(MemoryCopy* curr) {
- shouldBeTrue(getModule()->memory.exists, curr, "Memory operations require a memory");
- shouldBeTrue(getModule()->features.hasBulkMemory(), curr, "Bulk memory operation (bulk memory is disabled)");
- shouldBeEqualOrFirstIsUnreachable(curr->type, none, curr, "memory.copy must have type none");
- shouldBeEqualOrFirstIsUnreachable(curr->dest->type, i32, curr, "memory.copy dest must be an i32");
- shouldBeEqualOrFirstIsUnreachable(curr->source->type, i32, curr, "memory.copy source must be an i32");
- shouldBeEqualOrFirstIsUnreachable(curr->size->type, i32, curr, "memory.copy size must be an i32");
+ shouldBeTrue(
+ getModule()->memory.exists, curr, "Memory operations require a memory");
+ shouldBeTrue(getModule()->features.hasBulkMemory(),
+ curr,
+ "Bulk memory operation (bulk memory is disabled)");
+ shouldBeEqualOrFirstIsUnreachable(
+ curr->type, none, curr, "memory.copy must have type none");
+ shouldBeEqualOrFirstIsUnreachable(
+ curr->dest->type, i32, curr, "memory.copy dest must be an i32");
+ shouldBeEqualOrFirstIsUnreachable(
+ curr->source->type, i32, curr, "memory.copy source must be an i32");
+ shouldBeEqualOrFirstIsUnreachable(
+ curr->size->type, i32, curr, "memory.copy size must be an i32");
}
void FunctionValidator::visitMemoryFill(MemoryFill* curr) {
- shouldBeTrue(getModule()->memory.exists, curr, "Memory operations require a memory");
- shouldBeTrue(getModule()->features.hasBulkMemory(), curr, "Bulk memory operation (bulk memory is disabled)");
- shouldBeEqualOrFirstIsUnreachable(curr->type, none, curr, "memory.fill must have type none");
- shouldBeEqualOrFirstIsUnreachable(curr->dest->type, i32, curr, "memory.fill dest must be an i32");
- shouldBeEqualOrFirstIsUnreachable(curr->value->type, i32, curr, "memory.fill value must be an i32");
- shouldBeEqualOrFirstIsUnreachable(curr->size->type, i32, curr, "memory.fill size must be an i32");
+ shouldBeTrue(
+ getModule()->memory.exists, curr, "Memory operations require a memory");
+ shouldBeTrue(getModule()->features.hasBulkMemory(),
+ curr,
+ "Bulk memory operation (bulk memory is disabled)");
+ shouldBeEqualOrFirstIsUnreachable(
+ curr->type, none, curr, "memory.fill must have type none");
+ shouldBeEqualOrFirstIsUnreachable(
+ curr->dest->type, i32, curr, "memory.fill dest must be an i32");
+ shouldBeEqualOrFirstIsUnreachable(
+ curr->value->type, i32, curr, "memory.fill value must be an i32");
+ shouldBeEqualOrFirstIsUnreachable(
+ curr->size->type, i32, curr, "memory.fill size must be an i32");
}
-void FunctionValidator::validateMemBytes(uint8_t bytes, Type type, Expression* curr) {
+void FunctionValidator::validateMemBytes(uint8_t bytes,
+ Type type,
+ Expression* curr) {
switch (type) {
- case i32: shouldBeTrue(bytes == 1 || bytes == 2 || bytes == 4, curr, "expected i32 operation to touch 1, 2, or 4 bytes"); break;
- case i64: shouldBeTrue(bytes == 1 || bytes == 2 || bytes == 4 || bytes == 8, curr, "expected i64 operation to touch 1, 2, 4, or 8 bytes"); break;
- case f32: shouldBeEqual(bytes, uint8_t(4), curr, "expected f32 operation to touch 4 bytes"); break;
- case f64: shouldBeEqual(bytes, uint8_t(8), curr, "expected f64 operation to touch 8 bytes"); break;
- case v128: shouldBeEqual(bytes, uint8_t(16), curr, "expected v128 operation to touch 16 bytes"); break;
- case none: WASM_UNREACHABLE();
- case unreachable: break;
+ case i32:
+ shouldBeTrue(bytes == 1 || bytes == 2 || bytes == 4,
+ curr,
+ "expected i32 operation to touch 1, 2, or 4 bytes");
+ break;
+ case i64:
+ shouldBeTrue(bytes == 1 || bytes == 2 || bytes == 4 || bytes == 8,
+ curr,
+ "expected i64 operation to touch 1, 2, 4, or 8 bytes");
+ break;
+ case f32:
+ shouldBeEqual(
+ bytes, uint8_t(4), curr, "expected f32 operation to touch 4 bytes");
+ break;
+ case f64:
+ shouldBeEqual(
+ bytes, uint8_t(8), curr, "expected f64 operation to touch 8 bytes");
+ break;
+ case v128:
+ shouldBeEqual(
+ bytes, uint8_t(16), curr, "expected v128 operation to touch 16 bytes");
+ break;
+ case none:
+ WASM_UNREACHABLE();
+ case unreachable:
+ break;
}
}
void FunctionValidator::visitBinary(Binary* curr) {
if (curr->left->type != unreachable && curr->right->type != unreachable) {
- shouldBeEqual(curr->left->type, curr->right->type, curr, "binary child types must be equal");
+ shouldBeEqual(curr->left->type,
+ curr->right->type,
+ curr,
+ "binary child types must be equal");
}
switch (curr->op) {
case AddInt32:
@@ -866,30 +1212,41 @@ void FunctionValidator::visitBinary(Binary* curr) {
case MulVecF64x2:
case DivVecF64x2:
case MinVecF64x2:
- case MaxVecF64x2: {
- shouldBeEqualOrFirstIsUnreachable(curr->left->type, v128, curr, "v128 op");
- shouldBeEqualOrFirstIsUnreachable(curr->right->type, v128, curr, "v128 op");
+ case MaxVecF64x2: {
+ shouldBeEqualOrFirstIsUnreachable(
+ curr->left->type, v128, curr, "v128 op");
+ shouldBeEqualOrFirstIsUnreachable(
+ curr->right->type, v128, curr, "v128 op");
break;
}
- case InvalidBinary: WASM_UNREACHABLE();
+ case InvalidBinary:
+ WASM_UNREACHABLE();
}
- shouldBeTrue(Features::get(curr->op) <= getModule()->features, curr, "all used features should be allowed");
+ shouldBeTrue(Features::get(curr->op) <= getModule()->features,
+ curr,
+ "all used features should be allowed");
}
void FunctionValidator::visitUnary(Unary* curr) {
- shouldBeUnequal(curr->value->type, none, curr, "unaries must not receive a none as their input");
- if (curr->value->type == unreachable) return; // nothing to check
+ shouldBeUnequal(curr->value->type,
+ none,
+ curr,
+ "unaries must not receive a none as their input");
+ if (curr->value->type == unreachable)
+ return; // nothing to check
switch (curr->op) {
case ClzInt32:
case CtzInt32:
case PopcntInt32: {
- shouldBeEqual(curr->value->type, i32, curr, "i32 unary value type must be correct");
+ shouldBeEqual(
+ curr->value->type, i32, curr, "i32 unary value type must be correct");
break;
}
case ClzInt64:
case CtzInt64:
case PopcntInt64: {
- shouldBeEqual(curr->value->type, i64, curr, "i64 unary value type must be correct");
+ shouldBeEqual(
+ curr->value->type, i64, curr, "i64 unary value type must be correct");
break;
}
case NegFloat32:
@@ -899,7 +1256,8 @@ void FunctionValidator::visitUnary(Unary* curr) {
case TruncFloat32:
case NearestFloat32:
case SqrtFloat32: {
- shouldBeEqual(curr->value->type, f32, curr, "f32 unary value type must be correct");
+ shouldBeEqual(
+ curr->value->type, f32, curr, "f32 unary value type must be correct");
break;
}
case NegFloat64:
@@ -909,7 +1267,8 @@ void FunctionValidator::visitUnary(Unary* curr) {
case TruncFloat64:
case NearestFloat64:
case SqrtFloat64: {
- shouldBeEqual(curr->value->type, f64, curr, "f64 unary value type must be correct");
+ shouldBeEqual(
+ curr->value->type, f64, curr, "f64 unary value type must be correct");
break;
}
case EqZInt32: {
@@ -924,13 +1283,15 @@ void FunctionValidator::visitUnary(Unary* curr) {
case ExtendUInt32:
case ExtendS8Int32:
case ExtendS16Int32: {
- shouldBeEqual(curr->value->type, i32, curr, "extend type must be correct");
+ shouldBeEqual(
+ curr->value->type, i32, curr, "extend type must be correct");
break;
}
case ExtendS8Int64:
case ExtendS16Int64:
case ExtendS32Int64: {
- shouldBeEqual(curr->value->type, i64, curr, "extend type must be correct");
+ shouldBeEqual(
+ curr->value->type, i64, curr, "extend type must be correct");
break;
}
case WrapInt64: {
@@ -966,41 +1327,49 @@ void FunctionValidator::visitUnary(Unary* curr) {
break;
}
case ReinterpretFloat32: {
- shouldBeEqual(curr->value->type, f32, curr, "reinterpret/f32 type must be correct");
+ shouldBeEqual(
+ curr->value->type, f32, curr, "reinterpret/f32 type must be correct");
break;
}
case ReinterpretFloat64: {
- shouldBeEqual(curr->value->type, f64, curr, "reinterpret/f64 type must be correct");
+ shouldBeEqual(
+ curr->value->type, f64, curr, "reinterpret/f64 type must be correct");
break;
}
case ConvertUInt32ToFloat32:
case ConvertUInt32ToFloat64:
case ConvertSInt32ToFloat32:
case ConvertSInt32ToFloat64: {
- shouldBeEqual(curr->value->type, i32, curr, "convert type must be correct");
+ shouldBeEqual(
+ curr->value->type, i32, curr, "convert type must be correct");
break;
}
case ConvertUInt64ToFloat32:
case ConvertUInt64ToFloat64:
case ConvertSInt64ToFloat32:
case ConvertSInt64ToFloat64: {
- shouldBeEqual(curr->value->type, i64, curr, "convert type must be correct");
+ shouldBeEqual(
+ curr->value->type, i64, curr, "convert type must be correct");
break;
}
case PromoteFloat32: {
- shouldBeEqual(curr->value->type, f32, curr, "promote type must be correct");
+ shouldBeEqual(
+ curr->value->type, f32, curr, "promote type must be correct");
break;
}
case DemoteFloat64: {
- shouldBeEqual(curr->value->type, f64, curr, "demote type must be correct");
+ shouldBeEqual(
+ curr->value->type, f64, curr, "demote type must be correct");
break;
}
case ReinterpretInt32: {
- shouldBeEqual(curr->value->type, i32, curr, "reinterpret/i32 type must be correct");
+ shouldBeEqual(
+ curr->value->type, i32, curr, "reinterpret/i32 type must be correct");
break;
}
case ReinterpretInt64: {
- shouldBeEqual(curr->value->type, i64, curr, "reinterpret/i64 type must be correct");
+ shouldBeEqual(
+ curr->value->type, i64, curr, "reinterpret/i64 type must be correct");
break;
}
case SplatVecI8x16:
@@ -1051,25 +1420,39 @@ void FunctionValidator::visitUnary(Unary* curr) {
case AllTrueVecI32x4:
case AnyTrueVecI64x2:
case AllTrueVecI64x2:
- shouldBeEqual(curr->type, i32, curr, "expected boolean reduction to have i32 type");
+ shouldBeEqual(
+ curr->type, i32, curr, "expected boolean reduction to have i32 type");
shouldBeEqual(curr->value->type, v128, curr, "expected v128 operand");
break;
- case InvalidUnary: WASM_UNREACHABLE();
+ case InvalidUnary:
+ WASM_UNREACHABLE();
}
- shouldBeTrue(Features::get(curr->op) <= getModule()->features, curr, "all used features should be allowed");
+ shouldBeTrue(Features::get(curr->op) <= getModule()->features,
+ curr,
+ "all used features should be allowed");
}
void FunctionValidator::visitSelect(Select* curr) {
shouldBeUnequal(curr->ifTrue->type, none, curr, "select left must be valid");
- shouldBeUnequal(curr->ifFalse->type, none, curr, "select right must be valid");
- shouldBeTrue(curr->condition->type == unreachable || curr->condition->type == i32, curr, "select condition must be valid");
+ shouldBeUnequal(
+ curr->ifFalse->type, none, curr, "select right must be valid");
+ shouldBeTrue(curr->condition->type == unreachable ||
+ curr->condition->type == i32,
+ curr,
+ "select condition must be valid");
if (curr->ifTrue->type != unreachable && curr->ifFalse->type != unreachable) {
- shouldBeEqual(curr->ifTrue->type, curr->ifFalse->type, curr, "select sides must be equal");
+ shouldBeEqual(curr->ifTrue->type,
+ curr->ifFalse->type,
+ curr,
+ "select sides must be equal");
}
}
void FunctionValidator::visitDrop(Drop* curr) {
- shouldBeTrue(isConcreteType(curr->value->type) || curr->value->type == unreachable, curr, "can only drop a valid value");
+ shouldBeTrue(isConcreteType(curr->value->type) ||
+ curr->value->type == unreachable,
+ curr,
+ "can only drop a valid value");
}
void FunctionValidator::visitReturn(Return* curr) {
@@ -1077,7 +1460,8 @@ void FunctionValidator::visitReturn(Return* curr) {
if (returnType == unreachable) {
returnType = curr->value->type;
} else if (curr->value->type != unreachable) {
- shouldBeEqual(curr->value->type, returnType, curr, "function results must match");
+ shouldBeEqual(
+ curr->value->type, returnType, curr, "function results must match");
}
} else {
returnType = none;
@@ -1087,11 +1471,18 @@ void FunctionValidator::visitReturn(Return* curr) {
void FunctionValidator::visitHost(Host* curr) {
switch (curr->op) {
case GrowMemory: {
- shouldBeEqual(curr->operands.size(), size_t(1), curr, "grow_memory must have 1 operand");
- shouldBeEqualOrFirstIsUnreachable(curr->operands[0]->type, i32, curr, "grow_memory must have i32 operand");
+ shouldBeEqual(curr->operands.size(),
+ size_t(1),
+ curr,
+ "grow_memory must have 1 operand");
+ shouldBeEqualOrFirstIsUnreachable(curr->operands[0]->type,
+ i32,
+ curr,
+ "grow_memory must have i32 operand");
break;
}
- case CurrentMemory: break;
+ case CurrentMemory:
+ break;
}
}
@@ -1105,27 +1496,42 @@ void FunctionValidator::visitFunction(Function* curr) {
typeFeatures |= getFeatures(type);
shouldBeTrue(isConcreteType(type), curr, "vars must be concretely typed");
}
- shouldBeTrue(typeFeatures <= getModule()->features, curr,
+ shouldBeTrue(typeFeatures <= getModule()->features,
+ curr,
"all used types should be allowed");
// if function has no result, it is ignored
// if body is unreachable, it might be e.g. a return
if (curr->body->type != unreachable) {
- shouldBeEqual(curr->result, curr->body->type, curr->body, "function body type must match, if function returns");
+ shouldBeEqual(curr->result,
+ curr->body->type,
+ curr->body,
+ "function body type must match, if function returns");
}
if (returnType != unreachable) {
- shouldBeEqual(curr->result, returnType, curr->body, "function result must match, if function has returns");
+ shouldBeEqual(curr->result,
+ returnType,
+ curr->body,
+ "function result must match, if function has returns");
}
- shouldBeTrue(breakInfos.empty(), curr->body, "all named break targets must exist");
+ shouldBeTrue(
+ breakInfos.empty(), curr->body, "all named break targets must exist");
returnType = unreachable;
labelNames.clear();
- // if function has a named type, it must match up with the function's params and result
+ // if function has a named type, it must match up with the function's params
+ // and result
if (info.validateGlobally && curr->type.is()) {
auto* ft = getModule()->getFunctionType(curr->type);
- shouldBeTrue(ft->params == curr->params, curr->name, "function params must match its declared type");
- shouldBeTrue(ft->result == curr->result, curr->name, "function result must match its declared type");
+ shouldBeTrue(ft->params == curr->params,
+ curr->name,
+ "function params must match its declared type");
+ shouldBeTrue(ft->result == curr->result,
+ curr->name,
+ "function result must match its declared type");
}
if (curr->imported()) {
- shouldBeTrue(curr->type.is(), curr->name, "imported functions must have a function type");
+ shouldBeTrue(curr->type.is(),
+ curr->name,
+ "imported functions must have a function type");
}
// validate optional local names
std::set<Name> seen;
@@ -1136,9 +1542,11 @@ void FunctionValidator::visitFunction(Function* curr) {
}
static bool checkOffset(Expression* curr, Address add, Address max) {
- if (curr->is<GetGlobal>()) return true;
+ if (curr->is<GetGlobal>())
+ return true;
auto* c = curr->dynCast<Const>();
- if (!c) return false;
+ if (!c)
+ return false;
uint64_t raw = c->value.getInteger();
if (raw > std::numeric_limits<Address::address_t>::max()) {
return false;
@@ -1150,10 +1558,13 @@ static bool checkOffset(Expression* curr, Address add, Address max) {
return offset + add <= max;
}
-void FunctionValidator::validateAlignment(size_t align, Type type, Index bytes,
- bool isAtomic, Expression* curr) {
+void FunctionValidator::validateAlignment(
+ size_t align, Type type, Index bytes, bool isAtomic, Expression* curr) {
if (isAtomic) {
- shouldBeEqual(align, (size_t)bytes, curr, "atomic accesses must have natural alignment");
+ shouldBeEqual(align,
+ (size_t)bytes,
+ curr,
+ "atomic accesses must have natural alignment");
return;
}
switch (align) {
@@ -1161,8 +1572,9 @@ void FunctionValidator::validateAlignment(size_t align, Type type, Index bytes,
case 2:
case 4:
case 8:
- case 16: break;
- default:{
+ case 16:
+ break;
+ default: {
info.fail("bad alignment: " + std::to_string(align), curr, getFunction());
break;
}
@@ -1180,13 +1592,17 @@ void FunctionValidator::validateAlignment(size_t align, Type type, Index bytes,
break;
}
case v128:
- case unreachable: break;
- case none: WASM_UNREACHABLE();
+ case unreachable:
+ break;
+ case none:
+ WASM_UNREACHABLE();
}
}
static void validateBinaryenIR(Module& wasm, ValidationInfo& info) {
- struct BinaryenIRValidator : public PostWalker<BinaryenIRValidator, UnifiedExpressionVisitor<BinaryenIRValidator>> {
+ struct BinaryenIRValidator
+ : public PostWalker<BinaryenIRValidator,
+ UnifiedExpressionVisitor<BinaryenIRValidator>> {
ValidationInfo& info;
std::unordered_set<Expression*> seen;
@@ -1195,7 +1611,8 @@ static void validateBinaryenIR(Module& wasm, ValidationInfo& info) {
void visitExpression(Expression* curr) {
auto scope = getFunction() ? getFunction()->name : Name("(global scope)");
- // check if a node type is 'stale', i.e., we forgot to finalize() the node.
+ // check if a node type is 'stale', i.e., we forgot to finalize() the
+ // node.
auto oldType = curr->type;
ReFinalizeNode().visit(curr);
auto newType = curr->type;
@@ -1205,21 +1622,25 @@ static void validateBinaryenIR(Module& wasm, ValidationInfo& info) {
//
// (drop (block (result i32) (unreachable)))
//
- // The block has an added type, not derived from the ast itself, so it is
- // ok for it to be either i32 or unreachable.
+ // The block has an added type, not derived from the ast itself, so it
+ // is ok for it to be either i32 or unreachable.
if (!(isConcreteType(oldType) && newType == unreachable)) {
std::ostringstream ss;
- ss << "stale type found in " << scope << " on " << curr << "\n(marked as " << printType(oldType) << ", should be " << printType(newType) << ")\n";
+ ss << "stale type found in " << scope << " on " << curr
+ << "\n(marked as " << printType(oldType) << ", should be "
+ << printType(newType) << ")\n";
info.fail(ss.str(), curr, getFunction());
}
curr->type = oldType;
}
- // check if a node is a duplicate - expressions must not be seen more than once
+ // check if a node is a duplicate - expressions must not be seen more than
+ // once
bool inserted;
std::tie(std::ignore, inserted) = seen.insert(curr);
if (!inserted) {
std::ostringstream ss;
- ss << "expression seen more than once in the tree in " << scope << " on " << curr << '\n';
+ ss << "expression seen more than once in the tree in " << scope
+ << " on " << curr << '\n';
info.fail(ss.str(), curr, getFunction());
}
}
@@ -1234,15 +1655,22 @@ static void validateImports(Module& module, ValidationInfo& info) {
ModuleUtils::iterImportedFunctions(module, [&](Function* curr) {
if (info.validateWeb) {
auto* functionType = module.getFunctionType(curr->type);
- info.shouldBeUnequal(functionType->result, i64, curr->name, "Imported function must not have i64 return type");
+ info.shouldBeUnequal(functionType->result,
+ i64,
+ curr->name,
+ "Imported function must not have i64 return type");
for (Type param : functionType->params) {
- info.shouldBeUnequal(param, i64, curr->name, "Imported function must not have i64 parameters");
+ info.shouldBeUnequal(param,
+ i64,
+ curr->name,
+ "Imported function must not have i64 parameters");
}
}
});
if (!module.features.hasMutableGlobals()) {
ModuleUtils::iterImportedGlobals(module, [&](Global* curr) {
- info.shouldBeFalse(curr->mutable_, curr->name, "Imported global cannot be mutable");
+ info.shouldBeFalse(
+ curr->mutable_, curr->name, "Imported global cannot be mutable");
});
}
}
@@ -1252,14 +1680,23 @@ static void validateExports(Module& module, ValidationInfo& info) {
if (curr->kind == ExternalKind::Function) {
if (info.validateWeb) {
Function* f = module.getFunction(curr->value);
- info.shouldBeUnequal(f->result, i64, f->name, "Exported function must not have i64 return type");
+ info.shouldBeUnequal(f->result,
+ i64,
+ f->name,
+ "Exported function must not have i64 return type");
for (auto param : f->params) {
- info.shouldBeUnequal(param, i64, f->name, "Exported function must not have i64 parameters");
+ info.shouldBeUnequal(
+ param,
+ i64,
+ f->name,
+ "Exported function must not have i64 parameters");
}
}
- } else if (curr->kind == ExternalKind::Global && !module.features.hasMutableGlobals()) {
+ } else if (curr->kind == ExternalKind::Global &&
+ !module.features.hasMutableGlobals()) {
if (Global* g = module.getGlobalOrNull(curr->value)) {
- info.shouldBeFalse(g->mutable_, g->name, "Exported global cannot be mutable");
+ info.shouldBeFalse(
+ g->mutable_, g->name, "Exported global cannot be mutable");
}
}
}
@@ -1267,29 +1704,47 @@ static void validateExports(Module& module, ValidationInfo& info) {
for (auto& exp : module.exports) {
Name name = exp->value;
if (exp->kind == ExternalKind::Function) {
- info.shouldBeTrue(module.getFunctionOrNull(name), name, "module function exports must be found");
+ info.shouldBeTrue(module.getFunctionOrNull(name),
+ name,
+ "module function exports must be found");
} else if (exp->kind == ExternalKind::Global) {
- info.shouldBeTrue(module.getGlobalOrNull(name), name, "module global exports must be found");
+ info.shouldBeTrue(module.getGlobalOrNull(name),
+ name,
+ "module global exports must be found");
} else if (exp->kind == ExternalKind::Table) {
- info.shouldBeTrue(name == Name("0") || name == module.table.name, name, "module table exports must be found");
+ info.shouldBeTrue(name == Name("0") || name == module.table.name,
+ name,
+ "module table exports must be found");
} else if (exp->kind == ExternalKind::Memory) {
- info.shouldBeTrue(name == Name("0") || name == module.memory.name, name, "module memory exports must be found");
+ info.shouldBeTrue(name == Name("0") || name == module.memory.name,
+ name,
+ "module memory exports must be found");
} else {
WASM_UNREACHABLE();
}
Name exportName = exp->name;
- info.shouldBeFalse(exportNames.count(exportName) > 0, exportName, "module exports must be unique");
+ info.shouldBeFalse(exportNames.count(exportName) > 0,
+ exportName,
+ "module exports must be unique");
exportNames.insert(exportName);
}
}
static void validateGlobals(Module& module, ValidationInfo& info) {
ModuleUtils::iterDefinedGlobals(module, [&](Global* curr) {
- info.shouldBeTrue(getFeatures(curr->type) <= module.features, curr->name,
+ info.shouldBeTrue(getFeatures(curr->type) <= module.features,
+ curr->name,
"all used types should be allowed");
- info.shouldBeTrue(curr->init != nullptr, curr->name, "global init must be non-null");
- info.shouldBeTrue(curr->init->is<Const>() || curr->init->is<GetGlobal>(), curr->name, "global init must be valid");
- if (!info.shouldBeEqual(curr->type, curr->init->type, curr->init, "global init must have correct type") && !info.quiet) {
+ info.shouldBeTrue(
+ curr->init != nullptr, curr->name, "global init must be non-null");
+ info.shouldBeTrue(curr->init->is<Const>() || curr->init->is<GetGlobal>(),
+ curr->name,
+ "global init must be valid");
+ if (!info.shouldBeEqual(curr->type,
+ curr->init->type,
+ curr->init,
+ "global init must have correct type") &&
+ !info.quiet) {
info.getStream(nullptr) << "(on global " << curr->name << ")\n";
}
});
@@ -1297,30 +1752,57 @@ static void validateGlobals(Module& module, ValidationInfo& info) {
static void validateMemory(Module& module, ValidationInfo& info) {
auto& curr = module.memory;
- info.shouldBeFalse(curr.initial > curr.max, "memory", "memory max >= initial");
- info.shouldBeTrue(curr.initial <= Memory::kMaxSize, "memory", "initial memory must be <= 4GB");
- info.shouldBeTrue(!curr.hasMax() || curr.max <= Memory::kMaxSize, "memory", "max memory must be <= 4GB, or unlimited");
- info.shouldBeTrue(!curr.shared || curr.hasMax(), "memory", "shared memory must have max size");
- if (curr.shared) info.shouldBeTrue(module.features.hasAtomics(), "memory", "memory is shared, but atomics are disabled");
+ info.shouldBeFalse(
+ curr.initial > curr.max, "memory", "memory max >= initial");
+ info.shouldBeTrue(curr.initial <= Memory::kMaxSize,
+ "memory",
+ "initial memory must be <= 4GB");
+ info.shouldBeTrue(!curr.hasMax() || curr.max <= Memory::kMaxSize,
+ "memory",
+ "max memory must be <= 4GB, or unlimited");
+ info.shouldBeTrue(!curr.shared || curr.hasMax(),
+ "memory",
+ "shared memory must have max size");
+ if (curr.shared)
+ info.shouldBeTrue(module.features.hasAtomics(),
+ "memory",
+ "memory is shared, but atomics are disabled");
for (auto& segment : curr.segments) {
Index size = segment.data.size();
if (segment.isPassive) {
- info.shouldBeTrue(module.features.hasBulkMemory(), segment.offset, "nonzero segment flags (bulk memory is disabled)");
- info.shouldBeEqual(segment.offset, (Expression*)nullptr, segment.offset, "passive segment should not have an offset");
+ info.shouldBeTrue(module.features.hasBulkMemory(),
+ segment.offset,
+ "nonzero segment flags (bulk memory is disabled)");
+ info.shouldBeEqual(segment.offset,
+ (Expression*)nullptr,
+ segment.offset,
+ "passive segment should not have an offset");
} else {
- if (!info.shouldBeEqual(segment.offset->type, i32, segment.offset, "segment offset should be i32")) continue;
- info.shouldBeTrue(checkOffset(segment.offset, segment.data.size(), curr.initial * Memory::kPageSize), segment.offset, "segment offset should be reasonable");
+ if (!info.shouldBeEqual(segment.offset->type,
+ i32,
+ segment.offset,
+ "segment offset should be i32"))
+ continue;
+ info.shouldBeTrue(checkOffset(segment.offset,
+ segment.data.size(),
+ curr.initial * Memory::kPageSize),
+ segment.offset,
+ "segment offset should be reasonable");
if (segment.offset->is<Const>()) {
Index start = segment.offset->cast<Const>()->value.geti32();
Index end = start + size;
- info.shouldBeTrue(end <= curr.initial * Memory::kPageSize, segment.data.size(), "segment size should fit in memory (end)");
+ info.shouldBeTrue(end <= curr.initial * Memory::kPageSize,
+ segment.data.size(),
+ "segment size should fit in memory (end)");
}
}
// If the memory is imported we don't actually know its initial size.
// Specifically wasm dll's import a zero sized memory which is perfectly
// valid.
if (!curr.imported()) {
- info.shouldBeTrue(size <= curr.initial * Memory::kPageSize, segment.data.size(), "segment size should fit in memory (initial)");
+ info.shouldBeTrue(size <= curr.initial * Memory::kPageSize,
+ segment.data.size(),
+ "segment size should fit in memory (initial)");
}
}
}
@@ -1328,10 +1810,18 @@ static void validateMemory(Module& module, ValidationInfo& info) {
static void validateTable(Module& module, ValidationInfo& info) {
auto& curr = module.table;
for (auto& segment : curr.segments) {
- info.shouldBeEqual(segment.offset->type, i32, segment.offset, "segment offset should be i32");
- info.shouldBeTrue(checkOffset(segment.offset, segment.data.size(), module.table.initial * Table::kPageSize), segment.offset, "segment offset should be reasonable");
+ info.shouldBeEqual(segment.offset->type,
+ i32,
+ segment.offset,
+ "segment offset should be i32");
+ info.shouldBeTrue(checkOffset(segment.offset,
+ segment.data.size(),
+ module.table.initial * Table::kPageSize),
+ segment.offset,
+ "segment offset should be reasonable");
for (auto name : segment.data) {
- info.shouldBeTrue(module.getFunctionOrNull(name), name, "segment name should be valid");
+ info.shouldBeTrue(
+ module.getFunctionOrNull(name), name, "segment name should be valid");
}
}
}
@@ -1340,16 +1830,19 @@ static void validateModule(Module& module, ValidationInfo& info) {
// start
if (module.start.is()) {
auto func = module.getFunctionOrNull(module.start);
- if (info.shouldBeTrue(func != nullptr, module.start, "start must be found")) {
- info.shouldBeTrue(func->params.size() == 0, module.start, "start must have 0 params");
- info.shouldBeTrue(func->result == none, module.start, "start must not return a value");
+ if (info.shouldBeTrue(
+ func != nullptr, module.start, "start must be found")) {
+ info.shouldBeTrue(
+ func->params.size() == 0, module.start, "start must have 0 params");
+ info.shouldBeTrue(
+ func->result == none, module.start, "start must not return a value");
}
}
}
-// TODO: If we want the validator to be part of libwasm rather than libpasses, then
-// Using PassRunner::getPassDebug causes a circular dependence. We should fix that,
-// perhaps by moving some of the pass infrastructure into libsupport.
+// TODO: If we want the validator to be part of libwasm rather than libpasses,
+// then Using PassRunner::getPassDebug causes a circular dependence. We should
+// fix that, perhaps by moving some of the pass infrastructure into libsupport.
bool WasmValidator::validate(Module& module, Flags flags) {
ValidationInfo info;
info.validateWeb = (flags & Web) != 0;
diff --git a/src/wasm/wasm.cpp b/src/wasm/wasm.cpp
index 519814cb7..22cce6e80 100644
--- a/src/wasm/wasm.cpp
+++ b/src/wasm/wasm.cpp
@@ -15,15 +15,15 @@
*/
#include "wasm.h"
-#include "wasm-traversal.h"
#include "ir/branch-utils.h"
+#include "wasm-traversal.h"
namespace wasm {
// shared constants
-Name WASM("wasm"),
- RETURN_FLOW("*return:)*");
+Name WASM("wasm");
+Name RETURN_FLOW("*return:)*");
namespace BinaryConsts {
namespace UserSections {
@@ -39,90 +39,127 @@ const char* ExceptionHandlingFeature = "exception-handling";
const char* TruncSatFeature = "nontrapping-fptoint";
const char* SignExtFeature = "sign-ext";
const char* SIMD128Feature = "simd128";
-}
-}
-
-Name GROW_WASM_MEMORY("__growWasmMemory"),
- WASM_CALL_CTORS("__wasm_call_ctors"),
- MEMORY_BASE("__memory_base"),
- TABLE_BASE("__table_base"),
- GET_TEMP_RET0("getTempRet0"),
- SET_TEMP_RET0("setTempRet0"),
- NEW_SIZE("newSize"),
- MODULE("module"),
- START("start"),
- FUNC("func"),
- PARAM("param"),
- RESULT("result"),
- MEMORY("memory"),
- DATA("data"),
- PASSIVE("passive"),
- EXPORT("export"),
- IMPORT("import"),
- TABLE("table"),
- ELEM("elem"),
- LOCAL("local"),
- TYPE("type"),
- CALL("call"),
- CALL_INDIRECT("call_indirect"),
- BLOCK("block"),
- BR_IF("br_if"),
- THEN("then"),
- ELSE("else"),
- _NAN("NaN"),
- _INFINITY("Infinity"),
- NEG_INFINITY("-infinity"),
- NEG_NAN("-nan"),
- CASE("case"),
- BR("br"),
- FUNCREF("funcref"),
- FAKE_RETURN("fake_return_waka123"),
- MUT("mut"),
- SPECTEST("spectest"),
- PRINT("print"),
- EXIT("exit");
+} // namespace UserSections
+} // namespace BinaryConsts
+
+Name GROW_WASM_MEMORY("__growWasmMemory");
+Name WASM_CALL_CTORS("__wasm_call_ctors");
+Name MEMORY_BASE("__memory_base");
+Name TABLE_BASE("__table_base");
+Name GET_TEMP_RET0("getTempRet0");
+Name SET_TEMP_RET0("setTempRet0");
+Name NEW_SIZE("newSize");
+Name MODULE("module");
+Name START("start");
+Name FUNC("func");
+Name PARAM("param");
+Name RESULT("result");
+Name MEMORY("memory");
+Name DATA("data");
+Name PASSIVE("passive");
+Name EXPORT("export");
+Name IMPORT("import");
+Name TABLE("table");
+Name ELEM("elem");
+Name LOCAL("local");
+Name TYPE("type");
+Name CALL("call");
+Name CALL_INDIRECT("call_indirect");
+Name BLOCK("block");
+Name BR_IF("br_if");
+Name THEN("then");
+Name ELSE("else");
+Name _NAN("NaN");
+Name _INFINITY("Infinity");
+Name NEG_INFINITY("-infinity");
+Name NEG_NAN("-nan");
+Name CASE("case");
+Name BR("br");
+Name FUNCREF("funcref");
+Name FAKE_RETURN("fake_return_waka123");
+Name MUT("mut");
+Name SPECTEST("spectest");
+Name PRINT("print");
+Name EXIT("exit");
// Expressions
const char* getExpressionName(Expression* curr) {
switch (curr->_id) {
- case Expression::Id::InvalidId: WASM_UNREACHABLE();
- case Expression::Id::BlockId: return "block";
- case Expression::Id::IfId: return "if";
- case Expression::Id::LoopId: return "loop";
- case Expression::Id::BreakId: return "break";
- case Expression::Id::SwitchId: return "switch";
- case Expression::Id::CallId: return "call";
- case Expression::Id::CallIndirectId: return "call_indirect";
- case Expression::Id::GetLocalId: return "local.get";
- case Expression::Id::SetLocalId: return "local.set";
- case Expression::Id::GetGlobalId: return "global.get";
- case Expression::Id::SetGlobalId: return "global.set";
- case Expression::Id::LoadId: return "load";
- case Expression::Id::StoreId: return "store";
- case Expression::Id::ConstId: return "const";
- case Expression::Id::UnaryId: return "unary";
- case Expression::Id::BinaryId: return "binary";
- case Expression::Id::SelectId: return "select";
- case Expression::Id::DropId: return "drop";
- case Expression::Id::ReturnId: return "return";
- case Expression::Id::HostId: return "host";
- case Expression::Id::NopId: return "nop";
- case Expression::Id::UnreachableId: return "unreachable";
- case Expression::Id::AtomicCmpxchgId: return "atomic_cmpxchg";
- case Expression::Id::AtomicRMWId: return "atomic_rmw";
- case Expression::Id::AtomicWaitId: return "atomic_wait";
- case Expression::Id::AtomicNotifyId: return "atomic_notify";
- case Expression::Id::SIMDExtractId: return "simd_extract";
- case Expression::Id::SIMDReplaceId: return "simd_replace";
- case Expression::Id::SIMDShuffleId: return "simd_shuffle";
- case Expression::Id::SIMDBitselectId: return "simd_bitselect";
- case Expression::Id::SIMDShiftId: return "simd_shift";
- case Expression::Id::MemoryInitId: return "memory_init";
- case Expression::Id::DataDropId: return "data_drop";
- case Expression::Id::MemoryCopyId: return "memory_copy";
- case Expression::Id::MemoryFillId: return "memory_fill";
- case Expression::Id::NumExpressionIds: WASM_UNREACHABLE();
+ case Expression::Id::InvalidId:
+ WASM_UNREACHABLE();
+ case Expression::Id::BlockId:
+ return "block";
+ case Expression::Id::IfId:
+ return "if";
+ case Expression::Id::LoopId:
+ return "loop";
+ case Expression::Id::BreakId:
+ return "break";
+ case Expression::Id::SwitchId:
+ return "switch";
+ case Expression::Id::CallId:
+ return "call";
+ case Expression::Id::CallIndirectId:
+ return "call_indirect";
+ case Expression::Id::GetLocalId:
+ return "local.get";
+ case Expression::Id::SetLocalId:
+ return "local.set";
+ case Expression::Id::GetGlobalId:
+ return "global.get";
+ case Expression::Id::SetGlobalId:
+ return "global.set";
+ case Expression::Id::LoadId:
+ return "load";
+ case Expression::Id::StoreId:
+ return "store";
+ case Expression::Id::ConstId:
+ return "const";
+ case Expression::Id::UnaryId:
+ return "unary";
+ case Expression::Id::BinaryId:
+ return "binary";
+ case Expression::Id::SelectId:
+ return "select";
+ case Expression::Id::DropId:
+ return "drop";
+ case Expression::Id::ReturnId:
+ return "return";
+ case Expression::Id::HostId:
+ return "host";
+ case Expression::Id::NopId:
+ return "nop";
+ case Expression::Id::UnreachableId:
+ return "unreachable";
+ case Expression::Id::AtomicCmpxchgId:
+ return "atomic_cmpxchg";
+ case Expression::Id::AtomicRMWId:
+ return "atomic_rmw";
+ case Expression::Id::AtomicWaitId:
+ return "atomic_wait";
+ case Expression::Id::AtomicNotifyId:
+ return "atomic_notify";
+ case Expression::Id::SIMDExtractId:
+ return "simd_extract";
+ case Expression::Id::SIMDReplaceId:
+ return "simd_replace";
+ case Expression::Id::SIMDShuffleId:
+ return "simd_shuffle";
+ case Expression::Id::SIMDBitselectId:
+ return "simd_bitselect";
+ case Expression::Id::SIMDShiftId:
+ return "simd_shift";
+ case Expression::Id::MemoryInitId:
+ return "memory_init";
+ case Expression::Id::DataDropId:
+ return "data_drop";
+ case Expression::Id::MemoryCopyId:
+ return "memory_copy";
+ case Expression::Id::MemoryFillId:
+ return "memory_fill";
+ case Expression::Id::NumExpressionIds:
+ WASM_UNREACHABLE();
}
WASM_UNREACHABLE();
}
@@ -134,8 +171,8 @@ struct TypeSeeker : public PostWalker<TypeSeeker> {
Name targetName;
std::vector<Type> types;
-
- TypeSeeker(Expression* target, Name targetName) : target(target), targetName(targetName) {
+ TypeSeeker(Expression* target, Name targetName)
+ : target(target), targetName(targetName) {
Expression* temp = target;
walk(temp);
}
@@ -148,9 +185,11 @@ struct TypeSeeker : public PostWalker<TypeSeeker> {
void visitSwitch(Switch* curr) {
for (auto name : curr->targets) {
- if (name == targetName) types.push_back(curr->value ? curr->value->type : none);
+ if (name == targetName)
+ types.push_back(curr->value ? curr->value->type : none);
}
- if (curr->default_ == targetName) types.push_back(curr->value ? curr->value->type : none);
+ if (curr->default_ == targetName)
+ types.push_back(curr->value ? curr->value->type : none);
}
void visitBlock(Block* curr) {
@@ -161,7 +200,9 @@ struct TypeSeeker : public PostWalker<TypeSeeker> {
types.push_back(none);
}
} else if (curr->name == targetName) {
- types.clear(); // ignore all breaks til now, they were captured by someone with the same name
+ // ignore all breaks til now, they were captured by someone with the same
+ // name
+ types.clear();
}
}
@@ -169,7 +210,9 @@ struct TypeSeeker : public PostWalker<TypeSeeker> {
if (curr == target) {
types.push_back(curr->body->type);
} else if (curr->name == targetName) {
- types.clear(); // ignore all breaks til now, they were captured by someone with the same name
+ // ignore all breaks til now, they were captured by someone with the same
+ // name
+ types.clear();
}
}
};
@@ -177,8 +220,8 @@ struct TypeSeeker : public PostWalker<TypeSeeker> {
static Type mergeTypes(std::vector<Type>& types) {
Type type = unreachable;
for (auto other : types) {
- // once none, stop. it then indicates a poison value, that must not be consumed
- // and ignore unreachable
+ // once none, stop. it then indicates a poison value, that must not be
+ // consumed and ignore unreachable
if (type != none) {
if (other == none) {
type = none;
@@ -186,7 +229,8 @@ static Type mergeTypes(std::vector<Type>& types) {
if (type == unreachable) {
type = other;
} else if (type != other) {
- type = none; // poison value, we saw multiple types; this should not be consumed
+ // poison value, we saw multiple types; this should not be consumed
+ type = none;
}
}
}
@@ -196,17 +240,23 @@ static Type mergeTypes(std::vector<Type>& types) {
// a block is unreachable if one of its elements is unreachable,
// and there are no branches to it
-static void handleUnreachable(Block* block, bool breakabilityKnown=false, bool hasBreak=false) {
- if (block->type == unreachable) return; // nothing to do
- if (block->list.size() == 0) return; // nothing to do
+static void handleUnreachable(Block* block,
+ bool breakabilityKnown = false,
+ bool hasBreak = false) {
+ if (block->type == unreachable)
+ return; // nothing to do
+ if (block->list.size() == 0)
+ return; // nothing to do
// if we are concrete, stop - even an unreachable child
// won't change that (since we have a break with a value,
// or the final child flows out a value)
- if (isConcreteType(block->type)) return;
+ if (isConcreteType(block->type))
+ return;
// look for an unreachable child
for (auto* child : block->list) {
if (child->type == unreachable) {
- // there is an unreachable child, so we are unreachable, unless we have a break
+ // there is an unreachable child, so we are unreachable, unless we have a
+ // break
if (!breakabilityKnown) {
hasBreak = BranchUtils::BranchSeeker::hasNamed(block, block->name);
}
@@ -230,9 +280,11 @@ void Block::finalize() {
// (return)
// (i32.const 10)
// )
- if (isConcreteType(type)) return;
+ if (isConcreteType(type))
+ return;
// if we are unreachable, we are done
- if (type == unreachable) return;
+ if (type == unreachable)
+ return;
// we may still be unreachable if we have an unreachable
// child
for (auto* child : list) {
@@ -268,7 +320,9 @@ void Block::finalize(Type type_, bool hasBreak) {
void If::finalize(Type type_) {
type = type_;
- if (type == none && (condition->type == unreachable || (ifFalse && ifTrue->type == unreachable && ifFalse->type == unreachable))) {
+ if (type == none && (condition->type == unreachable ||
+ (ifFalse && ifTrue->type == unreachable &&
+ ifFalse->type == unreachable))) {
type = unreachable;
}
}
@@ -307,9 +361,7 @@ void Loop::finalize(Type type_) {
}
}
-void Loop::finalize() {
- type = body->type;
-}
+void Loop::finalize() { type = body->type; }
void Break::finalize() {
if (condition) {
@@ -325,12 +377,9 @@ void Break::finalize() {
}
}
-void Switch::finalize() {
- type = unreachable;
-}
+void Switch::finalize() { type = unreachable; }
-template<typename T>
-void handleUnreachableOperands(T* curr) {
+template<typename T> void handleUnreachableOperands(T* curr) {
for (auto* child : curr->operands) {
if (child->type == unreachable) {
curr->type = unreachable;
@@ -339,9 +388,7 @@ void handleUnreachableOperands(T* curr) {
}
}
-void Call::finalize() {
- handleUnreachableOperands(this);
-}
+void Call::finalize() { handleUnreachableOperands(this); }
void CallIndirect::finalize() {
handleUnreachableOperands(this);
@@ -351,29 +398,31 @@ void CallIndirect::finalize() {
}
bool FunctionType::structuralComparison(FunctionType& b) {
- if (result != b.result) return false;
- if (params.size() != b.params.size()) return false;
+ if (result != b.result)
+ return false;
+ if (params.size() != b.params.size())
+ return false;
for (size_t i = 0; i < params.size(); i++) {
- if (params[i] != b.params[i]) return false;
+ if (params[i] != b.params[i])
+ return false;
}
return true;
}
bool FunctionType::operator==(FunctionType& b) {
- if (name != b.name) return false;
+ if (name != b.name)
+ return false;
return structuralComparison(b);
}
-bool FunctionType::operator!=(FunctionType& b) {
- return !(*this == b);
-}
+bool FunctionType::operator!=(FunctionType& b) { return !(*this == b); }
-bool SetLocal::isTee() {
- return type != none;
-}
+bool SetLocal::isTee() { return type != none; }
void SetLocal::setTee(bool is) {
- if (is) type = value->type;
- else type = none;
+ if (is)
+ type = value->type;
+ else
+ type = none;
finalize(); // type may need to be unreachable
}
@@ -415,14 +464,16 @@ void AtomicRMW::finalize() {
}
void AtomicCmpxchg::finalize() {
- if (ptr->type == unreachable || expected->type == unreachable || replacement->type == unreachable) {
+ if (ptr->type == unreachable || expected->type == unreachable ||
+ replacement->type == unreachable) {
type = unreachable;
}
}
void AtomicWait::finalize() {
type = i32;
- if (ptr->type == unreachable || expected->type == unreachable || timeout->type == unreachable) {
+ if (ptr->type == unreachable || expected->type == unreachable ||
+ timeout->type == unreachable) {
type = unreachable;
}
}
@@ -441,11 +492,20 @@ void SIMDExtract::finalize() {
case ExtractLaneUVecI8x16:
case ExtractLaneSVecI16x8:
case ExtractLaneUVecI16x8:
- case ExtractLaneVecI32x4: type = i32; break;
- case ExtractLaneVecI64x2: type = i64; break;
- case ExtractLaneVecF32x4: type = f32; break;
- case ExtractLaneVecF64x2: type = f64; break;
- default: WASM_UNREACHABLE();
+ case ExtractLaneVecI32x4:
+ type = i32;
+ break;
+ case ExtractLaneVecI64x2:
+ type = i64;
+ break;
+ case ExtractLaneVecF32x4:
+ type = f32;
+ break;
+ case ExtractLaneVecF64x2:
+ type = f64;
+ break;
+ default:
+ WASM_UNREACHABLE();
}
if (vec->type == unreachable) {
type = unreachable;
@@ -471,7 +531,8 @@ void SIMDShuffle::finalize() {
void SIMDBitselect::finalize() {
assert(left && right && cond);
type = v128;
- if (left->type == unreachable || right->type == unreachable || cond->type == unreachable) {
+ if (left->type == unreachable || right->type == unreachable ||
+ cond->type == unreachable) {
type = unreachable;
}
}
@@ -479,19 +540,19 @@ void SIMDBitselect::finalize() {
void MemoryInit::finalize() {
assert(dest && offset && size);
type = none;
- if (dest->type == unreachable || offset->type == unreachable || size->type == unreachable) {
+ if (dest->type == unreachable || offset->type == unreachable ||
+ size->type == unreachable) {
type = unreachable;
}
}
-void DataDrop::finalize() {
- type = none;
-}
+void DataDrop::finalize() { type = none; }
void MemoryCopy::finalize() {
assert(dest && source && size);
type = none;
- if (dest->type == unreachable || source->type == unreachable || size->type == unreachable) {
+ if (dest->type == unreachable || source->type == unreachable ||
+ size->type == unreachable) {
type = unreachable;
}
}
@@ -499,7 +560,8 @@ void MemoryCopy::finalize() {
void MemoryFill::finalize() {
assert(dest && value && size);
type = none;
- if (dest->type == unreachable || value->type == unreachable || size->type == unreachable) {
+ if (dest->type == unreachable || value->type == unreachable ||
+ size->type == unreachable) {
type = unreachable;
}
}
@@ -518,13 +580,9 @@ Const* Const::set(Literal value_) {
return this;
}
-void Const::finalize() {
- type = value.type;
-}
+void Const::finalize() { type = value.type; }
-bool Unary::isRelational() {
- return op == EqZInt32 || op == EqZInt64;
-}
+bool Unary::isRelational() { return op == EqZInt32 || op == EqZInt64; }
void Unary::finalize() {
if (value->type == unreachable) {
@@ -551,14 +609,33 @@ void Unary::finalize() {
case FloorFloat64:
case TruncFloat64:
case NearestFloat64:
- case SqrtFloat64: type = value->type; break;
+ case SqrtFloat64:
+ type = value->type;
+ break;
case EqZInt32:
- case EqZInt64: type = i32; break;
- case ExtendS8Int32: case ExtendS16Int32: type = i32; break;
- case ExtendSInt32: case ExtendUInt32: case ExtendS8Int64: case ExtendS16Int64: case ExtendS32Int64: type = i64; break;
- case WrapInt64: type = i32; break;
- case PromoteFloat32: type = f64; break;
- case DemoteFloat64: type = f32; break;
+ case EqZInt64:
+ type = i32;
+ break;
+ case ExtendS8Int32:
+ case ExtendS16Int32:
+ type = i32;
+ break;
+ case ExtendSInt32:
+ case ExtendUInt32:
+ case ExtendS8Int64:
+ case ExtendS16Int64:
+ case ExtendS32Int64:
+ type = i64;
+ break;
+ case WrapInt64:
+ type = i32;
+ break;
+ case PromoteFloat32:
+ type = f64;
+ break;
+ case DemoteFloat64:
+ type = f32;
+ break;
case TruncSFloat32ToInt32:
case TruncUFloat32ToInt32:
case TruncSFloat64ToInt32:
@@ -567,7 +644,9 @@ void Unary::finalize() {
case TruncSatUFloat32ToInt32:
case TruncSatSFloat64ToInt32:
case TruncSatUFloat64ToInt32:
- case ReinterpretFloat32: type = i32; break;
+ case ReinterpretFloat32:
+ type = i32;
+ break;
case TruncSFloat32ToInt64:
case TruncUFloat32ToInt64:
case TruncSFloat64ToInt64:
@@ -576,17 +655,23 @@ void Unary::finalize() {
case TruncSatUFloat32ToInt64:
case TruncSatSFloat64ToInt64:
case TruncSatUFloat64ToInt64:
- case ReinterpretFloat64: type = i64; break;
+ case ReinterpretFloat64:
+ type = i64;
+ break;
case ReinterpretInt32:
case ConvertSInt32ToFloat32:
case ConvertUInt32ToFloat32:
case ConvertSInt64ToFloat32:
- case ConvertUInt64ToFloat32: type = f32; break;
+ case ConvertUInt64ToFloat32:
+ type = f32;
+ break;
case ReinterpretInt64:
case ConvertSInt32ToFloat64:
case ConvertUInt32ToFloat64:
case ConvertSInt64ToFloat64:
- case ConvertUInt64ToFloat64: type = f64; break;
+ case ConvertUInt64ToFloat64:
+ type = f64;
+ break;
case SplatVecI8x16:
case SplatVecI16x8:
case SplatVecI32x4:
@@ -611,7 +696,9 @@ void Unary::finalize() {
case ConvertSVecI32x4ToVecF32x4:
case ConvertUVecI32x4ToVecF32x4:
case ConvertSVecI64x2ToVecF64x2:
- case ConvertUVecI64x2ToVecF64x2: type = v128; break;
+ case ConvertUVecI64x2ToVecF64x2:
+ type = v128;
+ break;
case AnyTrueVecI8x16:
case AllTrueVecI8x16:
case AnyTrueVecI16x8:
@@ -619,8 +706,11 @@ void Unary::finalize() {
case AnyTrueVecI32x4:
case AllTrueVecI32x4:
case AnyTrueVecI64x2:
- case AllTrueVecI64x2: type = i32; break;
- case InvalidUnary: WASM_UNREACHABLE();
+ case AllTrueVecI64x2:
+ type = i32;
+ break;
+ case InvalidUnary:
+ WASM_UNREACHABLE();
}
}
@@ -657,8 +747,10 @@ bool Binary::isRelational() {
case LtFloat32:
case LeFloat32:
case GtFloat32:
- case GeFloat32: return true;
- default: return false;
+ case GeFloat32:
+ return true;
+ default:
+ return false;
}
}
@@ -675,7 +767,8 @@ void Binary::finalize() {
void Select::finalize() {
assert(ifTrue && ifFalse);
- if (ifTrue->type == unreachable || ifFalse->type == unreachable || condition->type == unreachable) {
+ if (ifTrue->type == unreachable || ifFalse->type == unreachable ||
+ condition->type == unreachable) {
type = unreachable;
} else {
type = ifTrue->type;
@@ -708,33 +801,21 @@ void Host::finalize() {
}
}
-size_t Function::getNumParams() {
- return params.size();
-}
+size_t Function::getNumParams() { return params.size(); }
-size_t Function::getNumVars() {
- return vars.size();
-}
+size_t Function::getNumVars() { return vars.size(); }
-size_t Function::getNumLocals() {
- return params.size() + vars.size();
-}
+size_t Function::getNumLocals() { return params.size() + vars.size(); }
-bool Function::isParam(Index index) {
- return index < params.size();
-}
+bool Function::isParam(Index index) { return index < params.size(); }
-bool Function::isVar(Index index) {
- return index >= params.size();
-}
+bool Function::isVar(Index index) { return index >= params.size(); }
bool Function::hasLocalName(Index index) const {
return localNames.find(index) != localNames.end();
}
-Name Function::getLocalName(Index index) {
- return localNames.at(index);
-}
+Name Function::getLocalName(Index index) { return localNames.at(index); }
Name Function::getLocalNameOrDefault(Index index) {
auto nameIt = localNames.find(index);
@@ -761,9 +842,7 @@ Index Function::getLocalIndex(Name name) {
return iter->second;
}
-Index Function::getVarIndexBase() {
- return params.size();
-}
+Index Function::getVarIndexBase() { return params.size(); }
Type Function::getLocalType(Index index) {
if (isParam(index)) {
@@ -775,9 +854,7 @@ Type Function::getLocalType(Index index) {
}
}
-void Function::clearNames() {
- localNames.clear();
-}
+void Function::clearNames() { localNames.clear(); }
void Function::clearDebugInfo() {
localIndices.clear();
@@ -914,9 +991,7 @@ Global* Module::addGlobal(Global* curr) {
return curr;
}
-void Module::addStart(const Name& s) {
- start = s;
-}
+void Module::addStart(const Name& s) { start = s; }
void Module::removeFunctionType(Name name) {
for (size_t i = 0; i < functionTypes.size(); i++) {
@@ -979,8 +1054,6 @@ void Module::updateMaps() {
}
}
-void Module::clearDebugInfo() {
- debugInfoFileNames.clear();
-}
+void Module::clearDebugInfo() { debugInfoFileNames.clear(); }
} // namespace wasm
diff --git a/src/wasm2js.h b/src/wasm2js.h
index be794decb..515b9335a 100644
--- a/src/wasm2js.h
+++ b/src/wasm2js.h
@@ -25,16 +25,11 @@
#include <cmath>
#include <numeric>
-#include "asmjs/shared-constants.h"
+#include "abi/js.h"
+#include "asm_v_wasm.h"
#include "asmjs/asmangle.h"
-#include "wasm.h"
-#include "wasm-builder.h"
-#include "wasm-io.h"
-#include "wasm-validator.h"
+#include "asmjs/shared-constants.h"
#include "emscripten-optimizer/optimizer.h"
-#include "mixed_arena.h"
-#include "asm_v_wasm.h"
-#include "abi/js.h"
#include "ir/effects.h"
#include "ir/find_all.h"
#include "ir/import-utils.h"
@@ -43,25 +38,34 @@
#include "ir/names.h"
#include "ir/table-utils.h"
#include "ir/utils.h"
+#include "mixed_arena.h"
#include "passes/passes.h"
#include "support/base64.h"
+#include "wasm-builder.h"
+#include "wasm-io.h"
+#include "wasm-validator.h"
+#include "wasm.h"
namespace wasm {
using namespace cashew;
-IString ASM_FUNC("asmFunc"),
- ABORT_FUNC("abort"),
- FUNCTION_TABLE("FUNCTION_TABLE"),
- NO_RESULT("wasm2js$noresult"), // no result at all
- EXPRESSION_RESULT("wasm2js$expresult"); // result in an expression, no temp var
+IString ASM_FUNC("asmFunc");
+IString ABORT_FUNC("abort");
+IString FUNCTION_TABLE("FUNCTION_TABLE");
+IString NO_RESULT("wasm2js$noresult"); // no result at all
+// result in an expression, no temp var
+IString EXPRESSION_RESULT("wasm2js$expresult");
// Appends extra to block, flattening out if extra is a block as well
void flattenAppend(Ref ast, Ref extra) {
int index;
- if (ast[0] == BLOCK || ast[0] == TOPLEVEL) index = 1;
- else if (ast[0] == DEFUN) index = 3;
- else abort();
+ if (ast[0] == BLOCK || ast[0] == TOPLEVEL)
+ index = 1;
+ else if (ast[0] == DEFUN)
+ index = 3;
+ else
+ abort();
if (extra->isArray() && extra[0] == BLOCK) {
for (size_t i = 0; i < extra[1]->size(); i++) {
ast[index]->push_back(extra[1][i]);
@@ -80,9 +84,7 @@ void sequenceAppend(Ref& ast, Ref extra) {
ast = ValueBuilder::makeSeq(ast, extra);
}
-IString stringToIString(std::string str) {
- return IString(str.c_str(), false);
-}
+IString stringToIString(std::string str) { return IString(str.c_str(), false); }
// Used when taking a wasm name and generating a JS identifier. Each scope here
// is used to ensure that all names have a unique name but the same wasm name
@@ -124,7 +126,7 @@ public:
Wasm2JSBuilder(Flags f, PassOptions options) : flags(f), options(options) {}
Ref processWasm(Module* wasm, Name funcName = ASM_FUNC);
- Ref processFunction(Module* wasm, Function* func, bool standalone=false);
+ Ref processFunction(Module* wasm, Function* func, bool standalone = false);
Ref processStandaloneFunction(Module* wasm, Function* func) {
return processFunction(wasm, func, true);
}
@@ -142,7 +144,9 @@ public:
} else {
size_t index = temps[type]++;
ret = IString((std::string("wasm2js_") + printType(type) + "$" +
- std::to_string(index)).c_str(), false);
+ std::to_string(index))
+ .c_str(),
+ false);
}
if (func->localIndices.find(ret) == func->localIndices.end()) {
Builder::addVar(func, ret, type);
@@ -151,9 +155,7 @@ public:
}
// Free a temp var.
- void freeTemp(Type type, IString temp) {
- frees[type].push_back(temp);
- }
+ void freeTemp(Type type, IString temp) { frees[type].push_back(temp); }
// Generates a mangled name from `name` within the specified scope.
//
@@ -170,7 +172,7 @@ public:
// First up check our cached of mangled names to avoid doing extra work
// below
- auto &mangledScope = mangledNames[(int) scope];
+ auto& mangledScope = mangledNames[(int)scope];
auto it = mangledScope.find(name.c_str());
if (it != mangledScope.end()) {
return it->second;
@@ -200,13 +202,15 @@ public:
// it's a bug currently if they're not globally unique. This should
// probably be fixed via a different namespace for exports or something
// like that.
- // XXX This is not actually a valid check atm, since functions are not in the
- // global-most scope, but rather in the "asmFunc" scope which is inside it.
- // Also, for emscripten style glue, we emit the exports as a return, so there
- // is no name placed into the scope. For these reasons, just warn here, don't
- // error.
+ // XXX This is not actually a valid check atm, since functions are not in
+ // the global-most scope, but rather in the "asmFunc" scope which is
+ // inside it. Also, for emscripten style glue, we emit the exports as
+ // a return, so there is no name placed into the scope. For these
+ // reasons, just warn here, don't error.
if (scope == NameScope::Top) {
- std::cerr << "wasm2js: warning: global scope may be colliding with other scope: " << mangled << '\n';
+ std::cerr << "wasm2js: warning: global scope may be colliding with "
+ "other scope: "
+ << mangled << '\n';
}
}
allMangledNames.insert(ret);
@@ -225,7 +229,7 @@ private:
// Mangled names cache by interned names.
// Utilizes the usually reused underlying cstring's pointer as the key.
- std::unordered_map<const char*, IString> mangledNames[(int) NameScope::Max];
+ std::unordered_map<const char*, IString> mangledNames[(int)NameScope::Max];
std::unordered_set<IString> allMangledNames;
// If a function is callable from outside, we'll need to cast the inputs
@@ -242,8 +246,8 @@ private:
void addMemoryGrowthFuncs(Ref ast, Module* wasm);
Wasm2JSBuilder() = delete;
- Wasm2JSBuilder(const Wasm2JSBuilder &) = delete;
- Wasm2JSBuilder &operator=(const Wasm2JSBuilder&) = delete;
+ Wasm2JSBuilder(const Wasm2JSBuilder&) = delete;
+ Wasm2JSBuilder& operator=(const Wasm2JSBuilder&) = delete;
};
Ref Wasm2JSBuilder::processWasm(Module* wasm, Name funcName) {
@@ -299,27 +303,24 @@ Ref Wasm2JSBuilder::processWasm(Module* wasm, Name funcName) {
ValueBuilder::appendArgumentToFunction(asmFunc, GLOBAL);
ValueBuilder::appendArgumentToFunction(asmFunc, ENV);
ValueBuilder::appendArgumentToFunction(asmFunc, BUFFER);
- asmFunc[3]->push_back(ValueBuilder::makeStatement(ValueBuilder::makeString(ALMOST_ASM)));
+ asmFunc[3]->push_back(
+ ValueBuilder::makeStatement(ValueBuilder::makeString(ALMOST_ASM)));
// add memory import
if (wasm->memory.exists && wasm->memory.imported()) {
Ref theVar = ValueBuilder::makeVar();
asmFunc[3]->push_back(theVar);
- ValueBuilder::appendToVar(theVar,
+ ValueBuilder::appendToVar(
+ theVar,
"memory",
- ValueBuilder::makeDot(
- ValueBuilder::makeName(ENV),
- ValueBuilder::makeName("memory")
- )
- );
+ ValueBuilder::makeDot(ValueBuilder::makeName(ENV),
+ ValueBuilder::makeName("memory")));
}
// create heaps, etc
addBasics(asmFunc[3]);
- ModuleUtils::iterImportedFunctions(*wasm, [&](Function* import) {
- addFunctionImport(asmFunc[3], import);
- });
- ModuleUtils::iterImportedGlobals(*wasm, [&](Global* import) {
- addGlobalImport(asmFunc[3], import);
- });
+ ModuleUtils::iterImportedFunctions(
+ *wasm, [&](Function* import) { addFunctionImport(asmFunc[3], import); });
+ ModuleUtils::iterImportedGlobals(
+ *wasm, [&](Global* import) { addGlobalImport(asmFunc[3], import); });
// make sure exports get their expected names
for (auto& e : wasm->exports) {
@@ -350,13 +351,14 @@ Ref Wasm2JSBuilder::processWasm(Module* wasm, Name funcName) {
Builder builder(allocator);
std::vector<Type> params;
std::vector<Type> vars;
- asmFunc[3]->push_back(processFunction(wasm, builder.makeFunction(
- WASM_FETCH_HIGH_BITS,
- std::move(params),
- i32,
- std::move(vars),
- builder.makeReturn(builder.makeGetGlobal(INT64_TO_32_HIGH_BITS, i32))
- )));
+ asmFunc[3]->push_back(processFunction(
+ wasm,
+ builder.makeFunction(WASM_FETCH_HIGH_BITS,
+ std::move(params),
+ i32,
+ std::move(vars),
+ builder.makeReturn(builder.makeGetGlobal(
+ INT64_TO_32_HIGH_BITS, i32)))));
auto e = new Export();
e->name = WASM_FETCH_HIGH_BITS;
e->value = WASM_FETCH_HIGH_BITS;
@@ -378,23 +380,17 @@ void Wasm2JSBuilder::addBasics(Ref ast) {
auto addHeap = [&](IString name, IString view) {
Ref theVar = ValueBuilder::makeVar();
ast->push_back(theVar);
- ValueBuilder::appendToVar(theVar,
+ ValueBuilder::appendToVar(
+ theVar,
name,
- ValueBuilder::makeNew(
- ValueBuilder::makeCall(
- ValueBuilder::makeDot(
- ValueBuilder::makeName(GLOBAL),
- view
- ),
- ValueBuilder::makeName(BUFFER)
- )
- )
- );
+ ValueBuilder::makeNew(ValueBuilder::makeCall(
+ ValueBuilder::makeDot(ValueBuilder::makeName(GLOBAL), view),
+ ValueBuilder::makeName(BUFFER))));
};
- addHeap(HEAP8, INT8ARRAY);
+ addHeap(HEAP8, INT8ARRAY);
addHeap(HEAP16, INT16ARRAY);
addHeap(HEAP32, INT32ARRAY);
- addHeap(HEAPU8, UINT8ARRAY);
+ addHeap(HEAPU8, UINT8ARRAY);
addHeap(HEAPU16, UINT16ARRAY);
addHeap(HEAPU32, UINT32ARRAY);
addHeap(HEAPF32, FLOAT32ARRAY);
@@ -403,16 +399,11 @@ void Wasm2JSBuilder::addBasics(Ref ast) {
auto addMath = [&](IString name, IString base) {
Ref theVar = ValueBuilder::makeVar();
ast->push_back(theVar);
- ValueBuilder::appendToVar(theVar,
+ ValueBuilder::appendToVar(
+ theVar,
name,
ValueBuilder::makeDot(
- ValueBuilder::makeDot(
- ValueBuilder::makeName(GLOBAL),
- MATH
- ),
- base
- )
- );
+ ValueBuilder::makeDot(ValueBuilder::makeName(GLOBAL), MATH), base));
};
addMath(MATH_IMUL, IMUL);
addMath(MATH_FROUND, FROUND);
@@ -426,61 +417,54 @@ void Wasm2JSBuilder::addBasics(Ref ast) {
// abort function
Ref abortVar = ValueBuilder::makeVar();
ast->push_back(abortVar);
- ValueBuilder::appendToVar(abortVar,
+ ValueBuilder::appendToVar(
+ abortVar,
"abort",
- ValueBuilder::makeDot(
- ValueBuilder::makeName(ENV),
- ABORT_FUNC
- )
- );
+ ValueBuilder::makeDot(ValueBuilder::makeName(ENV), ABORT_FUNC));
// TODO: this shouldn't be needed once we stop generating literal asm.js code
// NaN and Infinity variables
Ref nanVar = ValueBuilder::makeVar();
ast->push_back(nanVar);
- ValueBuilder::appendToVar(nanVar,
+ ValueBuilder::appendToVar(
+ nanVar,
"nan",
- ValueBuilder::makeDot(ValueBuilder::makeName(GLOBAL), "NaN")
- );
+ ValueBuilder::makeDot(ValueBuilder::makeName(GLOBAL), "NaN"));
Ref infinityVar = ValueBuilder::makeVar();
ast->push_back(infinityVar);
- ValueBuilder::appendToVar(infinityVar,
+ ValueBuilder::appendToVar(
+ infinityVar,
"infinity",
- ValueBuilder::makeDot(ValueBuilder::makeName(GLOBAL), "Infinity")
- );
+ ValueBuilder::makeDot(ValueBuilder::makeName(GLOBAL), "Infinity"));
}
void Wasm2JSBuilder::addFunctionImport(Ref ast, Function* import) {
- // The scratch memory helpers are emitted in the glue, see code and comments below.
+ // The scratch memory helpers are emitted in the glue, see code and comments
+ // below.
if (ABI::wasm2js::isScratchMemoryHelper(import->base)) {
return;
}
Ref theVar = ValueBuilder::makeVar();
ast->push_back(theVar);
- Ref module = ValueBuilder::makeName(ENV); // TODO: handle nested module imports
- ValueBuilder::appendToVar(theVar,
+ // TODO: handle nested module imports
+ Ref module = ValueBuilder::makeName(ENV);
+ ValueBuilder::appendToVar(
+ theVar,
fromName(import->name, NameScope::Top),
- ValueBuilder::makeDot(
- module,
- fromName(import->base, NameScope::Top)
- )
- );
+ ValueBuilder::makeDot(module, fromName(import->base, NameScope::Top)));
}
void Wasm2JSBuilder::addGlobalImport(Ref ast, Global* import) {
Ref theVar = ValueBuilder::makeVar();
ast->push_back(theVar);
- Ref module = ValueBuilder::makeName(ENV); // TODO: handle nested module imports
- Ref value = ValueBuilder::makeDot(
- module,
- fromName(import->base, NameScope::Top)
- );
+ // TODO: handle nested module imports
+ Ref module = ValueBuilder::makeName(ENV);
+ Ref value =
+ ValueBuilder::makeDot(module, fromName(import->base, NameScope::Top));
if (import->type == i32) {
value = makeAsmCoercion(value, ASM_INT);
}
- ValueBuilder::appendToVar(theVar,
- fromName(import->name, NameScope::Top),
- value
- );
+ ValueBuilder::appendToVar(
+ theVar, fromName(import->name, NameScope::Top), value);
}
void Wasm2JSBuilder::addTable(Ref ast, Module* wasm) {
@@ -505,7 +489,8 @@ void Wasm2JSBuilder::addTable(Ref ast, Module* wasm) {
if (!wasm->table.imported()) {
Ref theVar = ValueBuilder::makeVar();
ast->push_back(theVar);
- ValueBuilder::appendToVar(theVar, FUNCTION_TABLE, ValueBuilder::makeArray());
+ ValueBuilder::appendToVar(
+ theVar, FUNCTION_TABLE, ValueBuilder::makeArray());
}
// TODO: optimize for size
@@ -519,21 +504,14 @@ void Wasm2JSBuilder::addTable(Ref ast, Module* wasm) {
index = ValueBuilder::makeBinary(
ValueBuilder::makeName(stringToIString(asmangle(get->name.str))),
PLUS,
- ValueBuilder::makeNum(i)
- );
+ ValueBuilder::makeNum(i));
} else {
WASM_UNREACHABLE();
}
- ast->push_back(ValueBuilder::makeStatement(
- ValueBuilder::makeBinary(
- ValueBuilder::makeSub(
- ValueBuilder::makeName(FUNCTION_TABLE),
- index
- ),
- SET,
- ValueBuilder::makeName(fromName(segment.data[i], NameScope::Top))
- )
- ));
+ ast->push_back(ValueBuilder::makeStatement(ValueBuilder::makeBinary(
+ ValueBuilder::makeSub(ValueBuilder::makeName(FUNCTION_TABLE), index),
+ SET,
+ ValueBuilder::makeName(fromName(segment.data[i], NameScope::Top)))));
}
}
}
@@ -546,49 +524,37 @@ void Wasm2JSBuilder::addExports(Ref ast, Module* wasm) {
ValueBuilder::appendToObjectWithQuotes(
exports,
fromName(export_->name, NameScope::Top),
- ValueBuilder::makeName(fromName(export_->value, NameScope::Top))
- );
+ ValueBuilder::makeName(fromName(export_->value, NameScope::Top)));
}
if (export_->kind == ExternalKind::Memory) {
Ref descs = ValueBuilder::makeObject();
Ref growDesc = ValueBuilder::makeObject();
+ ValueBuilder::appendToObjectWithQuotes(descs, IString("grow"), growDesc);
ValueBuilder::appendToObjectWithQuotes(
- descs,
- IString("grow"),
- growDesc);
- ValueBuilder::appendToObjectWithQuotes(
- growDesc,
- IString("value"),
- ValueBuilder::makeName(WASM_GROW_MEMORY));
+ growDesc, IString("value"), ValueBuilder::makeName(WASM_GROW_MEMORY));
Ref bufferDesc = ValueBuilder::makeObject();
Ref bufferGetter = ValueBuilder::makeFunction(IString(""));
- bufferGetter[3]->push_back(ValueBuilder::makeReturn(
- ValueBuilder::makeName(BUFFER)
- ));
+ bufferGetter[3]->push_back(
+ ValueBuilder::makeReturn(ValueBuilder::makeName(BUFFER)));
ValueBuilder::appendToObjectWithQuotes(
- bufferDesc,
- IString("get"),
- bufferGetter);
+ bufferDesc, IString("get"), bufferGetter);
ValueBuilder::appendToObjectWithQuotes(
- descs,
- IString("buffer"),
- bufferDesc);
+ descs, IString("buffer"), bufferDesc);
Ref memory = ValueBuilder::makeCall(
- ValueBuilder::makeDot(ValueBuilder::makeName(IString("Object")), IString("create")),
- ValueBuilder::makeDot(ValueBuilder::makeName(IString("Object")), IString("prototype")));
- ValueBuilder::appendToCall(
- memory,
- descs);
+ ValueBuilder::makeDot(ValueBuilder::makeName(IString("Object")),
+ IString("create")),
+ ValueBuilder::makeDot(ValueBuilder::makeName(IString("Object")),
+ IString("prototype")));
+ ValueBuilder::appendToCall(memory, descs);
ValueBuilder::appendToObjectWithQuotes(
- exports,
- fromName(export_->name, NameScope::Top),
- memory);
+ exports, fromName(export_->name, NameScope::Top), memory);
}
}
if (wasm->memory.exists && wasm->memory.max > wasm->memory.initial) {
addMemoryGrowthFuncs(ast, wasm);
}
- ast->push_back(ValueBuilder::makeStatement(ValueBuilder::makeReturn(exports)));
+ ast->push_back(
+ ValueBuilder::makeStatement(ValueBuilder::makeReturn(exports)));
}
void Wasm2JSBuilder::addGlobal(Ref ast, Global* global) {
@@ -600,38 +566,38 @@ void Wasm2JSBuilder::addGlobal(Ref ast, Global* global) {
break;
}
case Type::f32: {
- theValue = ValueBuilder::makeCall(MATH_FROUND,
- makeAsmCoercion(ValueBuilder::makeDouble(const_->value.getf32()), ASM_DOUBLE)
- );
+ theValue = ValueBuilder::makeCall(
+ MATH_FROUND,
+ makeAsmCoercion(ValueBuilder::makeDouble(const_->value.getf32()),
+ ASM_DOUBLE));
break;
}
case Type::f64: {
- theValue = makeAsmCoercion(ValueBuilder::makeDouble(const_->value.getf64()), ASM_DOUBLE);
+ theValue = makeAsmCoercion(
+ ValueBuilder::makeDouble(const_->value.getf64()), ASM_DOUBLE);
break;
}
- default: {
- assert(false && "Top const type not supported");
- }
+ default: { assert(false && "Top const type not supported"); }
}
Ref theVar = ValueBuilder::makeVar();
ast->push_back(theVar);
- ValueBuilder::appendToVar(theVar,
- fromName(global->name, NameScope::Top),
- theValue
- );
+ ValueBuilder::appendToVar(
+ theVar, fromName(global->name, NameScope::Top), theValue);
} else if (auto* get = global->init->dynCast<GetGlobal>()) {
Ref theVar = ValueBuilder::makeVar();
ast->push_back(theVar);
- ValueBuilder::appendToVar(theVar,
+ ValueBuilder::appendToVar(
+ theVar,
fromName(global->name, NameScope::Top),
- ValueBuilder::makeName(fromName(get->name, NameScope::Top))
- );
+ ValueBuilder::makeName(fromName(get->name, NameScope::Top)));
} else {
assert(false && "Top init type not supported");
}
}
-Ref Wasm2JSBuilder::processFunction(Module* m, Function* func, bool standaloneFunction) {
+Ref Wasm2JSBuilder::processFunction(Module* m,
+ Function* func,
+ bool standaloneFunction) {
if (standaloneFunction) {
// We are only printing a function, not a whole module. Prepare it for
// translation now (if there were a module, we'd have done this for all
@@ -657,22 +623,17 @@ Ref Wasm2JSBuilder::processFunction(Module* m, Function* func, bool standaloneFu
temps.resize(std::max(i32, std::max(f32, f64)) + 1);
temps[i32] = temps[f32] = temps[f64] = 0;
// arguments
- bool needCoercions = options.optimizeLevel == 0 || standaloneFunction || functionsCallableFromOutside.count(func->name);
+ bool needCoercions = options.optimizeLevel == 0 || standaloneFunction ||
+ functionsCallableFromOutside.count(func->name);
for (Index i = 0; i < func->getNumParams(); i++) {
IString name = fromName(func->getLocalNameOrGeneric(i), NameScope::Local);
ValueBuilder::appendArgumentToFunction(ret, name);
if (needCoercions) {
- ret[3]->push_back(
- ValueBuilder::makeStatement(
- ValueBuilder::makeBinary(
- ValueBuilder::makeName(name), SET,
- makeAsmCoercion(
- ValueBuilder::makeName(name),
- wasmToAsmType(func->getLocalType(i))
- )
- )
- )
- );
+ ret[3]->push_back(ValueBuilder::makeStatement(ValueBuilder::makeBinary(
+ ValueBuilder::makeName(name),
+ SET,
+ makeAsmCoercion(ValueBuilder::makeName(name),
+ wasmToAsmType(func->getLocalType(i))))));
}
}
Ref theVar = ValueBuilder::makeVar();
@@ -685,20 +646,21 @@ Ref Wasm2JSBuilder::processFunction(Module* m, Function* func, bool standaloneFu
ValueBuilder::appendToVar(
theVar,
fromName(func->getLocalNameOrGeneric(i), NameScope::Local),
- makeAsmCoercedZero(wasmToAsmType(func->getLocalType(i)))
- );
+ makeAsmCoercedZero(wasmToAsmType(func->getLocalType(i))));
}
if (theVar[1]->size() == 0) {
ret[3]->splice(theVarIndex, 1);
}
- // checks
- assert(frees[i32].size() == temps[i32]); // all temp vars should be free at the end
- assert(frees[f32].size() == temps[f32]); // all temp vars should be free at the end
- assert(frees[f64].size() == temps[f64]); // all temp vars should be free at the end
+ // checks: all temp vars should be free at the end
+ assert(frees[i32].size() == temps[i32]);
+ assert(frees[f32].size() == temps[f32]);
+ assert(frees[f64].size() == temps[f64]);
return ret;
}
-Ref Wasm2JSBuilder::processFunctionBody(Module* m, Function* func, bool standaloneFunction) {
+Ref Wasm2JSBuilder::processFunctionBody(Module* m,
+ Function* func,
+ bool standaloneFunction) {
struct ExpressionProcessor : public Visitor<ExpressionProcessor, Ref> {
Wasm2JSBuilder* parent;
IString result; // TODO: remove
@@ -707,8 +669,12 @@ Ref Wasm2JSBuilder::processFunctionBody(Module* m, Function* func, bool standalo
bool standaloneFunction;
MixedArena allocator;
- ExpressionProcessor(Wasm2JSBuilder* parent, Module* m, Function* func, bool standaloneFunction)
- : parent(parent), func(func), module(m), standaloneFunction(standaloneFunction) {}
+ ExpressionProcessor(Wasm2JSBuilder* parent,
+ Module* m,
+ Function* func,
+ bool standaloneFunction)
+ : parent(parent), func(func), module(m),
+ standaloneFunction(standaloneFunction) {}
// A scoped temporary variable.
struct ScopedTemp {
@@ -716,11 +682,15 @@ Ref Wasm2JSBuilder::processFunctionBody(Module* m, Function* func, bool standalo
Type type;
IString temp; // TODO: switch to indexes; avoid names
bool needFree;
- // @param possible if provided, this is a variable we can use as our temp. it has already been
- // allocated in a higher scope, and we can just assign to it as our result is
- // going there anyhow.
- ScopedTemp(Type type, Wasm2JSBuilder* parent, Function* func,
- IString possible = NO_RESULT) : parent(parent), type(type) {
+ // @param possible if provided, this is a variable we can use as our temp.
+ // it has already been allocated in a higher scope, and we
+ // can just assign to it as our result is going there
+ // anyhow.
+ ScopedTemp(Type type,
+ Wasm2JSBuilder* parent,
+ Function* func,
+ IString possible = NO_RESULT)
+ : parent(parent), type(type) {
assert(possible != EXPRESSION_RESULT);
if (possible == NO_RESULT) {
temp = parent->getTemp(type, func);
@@ -736,19 +706,17 @@ Ref Wasm2JSBuilder::processFunctionBody(Module* m, Function* func, bool standalo
}
}
- IString getName() {
- return temp;
- }
- Ref getAstName() {
- return ValueBuilder::makeName(temp);
- }
+ IString getName() { return temp; }
+ Ref getAstName() { return ValueBuilder::makeName(temp); }
};
Ref visit(Expression* curr, IString nextResult) {
IString old = result;
result = nextResult;
Ref ret = Visitor::visit(curr);
- result = old; // keep it consistent for the rest of this frame, which may call visit on multiple children
+ // keep it consistent for the rest of this frame, which may call visit on
+ // multiple children
+ result = old;
return ret;
}
@@ -759,7 +727,8 @@ Ref Wasm2JSBuilder::processFunctionBody(Module* m, Function* func, bool standalo
Ref visitAndAssign(Expression* curr, IString result) {
assert(result != NO_RESULT);
Ref ret = visit(curr, result);
- return ValueBuilder::makeStatement(ValueBuilder::makeBinary(ValueBuilder::makeName(result), SET, ret));
+ return ValueBuilder::makeStatement(
+ ValueBuilder::makeBinary(ValueBuilder::makeName(result), SET, ret));
}
Ref visitAndAssign(Expression* curr, ScopedTemp& temp) {
@@ -768,18 +737,18 @@ Ref Wasm2JSBuilder::processFunctionBody(Module* m, Function* func, bool standalo
// Expressions with control flow turn into a block, which we must
// then handle, even if we are an expression.
- bool isBlock(Ref ast) {
- return !!ast && ast->isArray() && ast[0] == BLOCK;
- }
+ bool isBlock(Ref ast) { return !!ast && ast->isArray() && ast[0] == BLOCK; }
Ref blockify(Ref ast) {
- if (isBlock(ast)) return ast;
+ if (isBlock(ast))
+ return ast;
Ref ret = ValueBuilder::makeBlock();
ret[1]->push_back(ValueBuilder::makeStatement(ast));
return ret;
}
- // Breaks to the top of a loop should be emitted as continues, to that loop's main label
+ // Breaks to the top of a loop should be emitted as continues, to that
+ // loop's main label
std::unordered_set<Name> continueLabels;
IString fromName(Name name, NameScope scope) {
@@ -791,15 +760,17 @@ Ref Wasm2JSBuilder::processFunctionBody(Module* m, Function* func, bool standalo
Ref visitBlock(Block* curr) {
Ref ret = ValueBuilder::makeBlock();
size_t size = curr->list.size();
- auto noResults = result == NO_RESULT ? size : size-1;
+ auto noResults = result == NO_RESULT ? size : size - 1;
for (size_t i = 0; i < noResults; i++) {
- flattenAppend(ret, ValueBuilder::makeStatement(visit(curr->list[i], NO_RESULT)));
+ flattenAppend(
+ ret, ValueBuilder::makeStatement(visit(curr->list[i], NO_RESULT)));
}
if (result != NO_RESULT) {
- flattenAppend(ret, visitAndAssign(curr->list[size-1], result));
+ flattenAppend(ret, visitAndAssign(curr->list[size - 1], result));
}
if (curr->name.is()) {
- ret = ValueBuilder::makeLabel(fromName(curr->name, NameScope::Label), ret);
+ ret =
+ ValueBuilder::makeLabel(fromName(curr->name, NameScope::Label), ret);
}
return ret;
}
@@ -822,7 +793,8 @@ Ref Wasm2JSBuilder::processFunctionBody(Module* m, Function* func, bool standalo
if (curr->body->type != unreachable) {
assert(curr->body->type == none); // flat IR
body = blockify(body);
- flattenAppend(body, ValueBuilder::makeBreak(fromName(asmLabel, NameScope::Label)));
+ flattenAppend(
+ body, ValueBuilder::makeBreak(fromName(asmLabel, NameScope::Label)));
}
Ref ret = ValueBuilder::makeWhile(ValueBuilder::makeInt(1), body);
return ValueBuilder::makeLabel(fromName(asmLabel, NameScope::Label), ret);
@@ -860,17 +832,23 @@ Ref Wasm2JSBuilder::processFunctionBody(Module* m, Function* func, bool standalo
ret[1]->push_back(theSwitch);
for (size_t i = 0; i < curr->targets.size(); i++) {
ValueBuilder::appendCaseToSwitch(theSwitch, ValueBuilder::makeNum(i));
- ValueBuilder::appendCodeToSwitch(theSwitch, blockify(makeBreakOrContinue(curr->targets[i])), false);
+ ValueBuilder::appendCodeToSwitch(
+ theSwitch, blockify(makeBreakOrContinue(curr->targets[i])), false);
}
ValueBuilder::appendDefaultToSwitch(theSwitch);
- ValueBuilder::appendCodeToSwitch(theSwitch, blockify(makeBreakOrContinue(curr->default_)), false);
+ ValueBuilder::appendCodeToSwitch(
+ theSwitch, blockify(makeBreakOrContinue(curr->default_)), false);
return ret;
}
Ref visitCall(Call* curr) {
- Ref theCall = ValueBuilder::makeCall(fromName(curr->target, NameScope::Top));
- // For wasm => wasm calls, we don't need coercions. TODO: even imports might be safe?
- bool needCoercions = parent->options.optimizeLevel == 0 || standaloneFunction || module->getFunction(curr->target)->imported();
+ Ref theCall =
+ ValueBuilder::makeCall(fromName(curr->target, NameScope::Top));
+ // For wasm => wasm calls, we don't need coercions. TODO: even imports
+ // might be safe?
+ bool needCoercions = parent->options.optimizeLevel == 0 ||
+ standaloneFunction ||
+ module->getFunction(curr->target)->imported();
for (auto operand : curr->operands) {
auto value = visit(operand, EXPRESSION_RESULT);
if (needCoercions) {
@@ -885,12 +863,14 @@ Ref Wasm2JSBuilder::processFunctionBody(Module* m, Function* func, bool standalo
}
Ref visitCallIndirect(CallIndirect* curr) {
- // If the target has effects that interact with the operands, we must reorder it to the start.
+ // If the target has effects that interact with the operands, we must
+ // reorder it to the start.
bool mustReorder = false;
EffectAnalyzer targetEffects(parent->options, curr->target);
if (targetEffects.hasAnything()) {
for (auto* operand : curr->operands) {
- if (targetEffects.invalidates(EffectAnalyzer(parent->options, operand))) {
+ if (targetEffects.invalidates(
+ EffectAnalyzer(parent->options, operand))) {
mustReorder = true;
break;
}
@@ -907,13 +887,12 @@ Ref Wasm2JSBuilder::processFunctionBody(Module* m, Function* func, bool standalo
}
sequenceAppend(ret, visitAndAssign(curr->target, idx));
Ref theCall = ValueBuilder::makeCall(ValueBuilder::makeSub(
- ValueBuilder::makeName(FUNCTION_TABLE),
- idx.getAstName()
- ));
+ ValueBuilder::makeName(FUNCTION_TABLE), idx.getAstName()));
for (size_t i = 0; i < temps.size(); i++) {
IString temp = temps[i]->temp;
- auto &operand = curr->operands[i];
- theCall[2]->push_back(makeAsmCoercion(ValueBuilder::makeName(temp), wasmToAsmType(operand->type)));
+ auto& operand = curr->operands[i];
+ theCall[2]->push_back(makeAsmCoercion(ValueBuilder::makeName(temp),
+ wasmToAsmType(operand->type)));
}
theCall = makeAsmCoercion(theCall, wasmToAsmType(curr->type));
sequenceAppend(ret, theCall);
@@ -923,10 +902,9 @@ Ref Wasm2JSBuilder::processFunctionBody(Module* m, Function* func, bool standalo
return ret;
} else {
// Target has no side effects, emit simple code
- Ref theCall = ValueBuilder::makeCall(ValueBuilder::makeSub(
- ValueBuilder::makeName(FUNCTION_TABLE),
- visit(curr->target, EXPRESSION_RESULT)
- ));
+ Ref theCall = ValueBuilder::makeCall(
+ ValueBuilder::makeSub(ValueBuilder::makeName(FUNCTION_TABLE),
+ visit(curr->target, EXPRESSION_RESULT)));
for (auto* operand : curr->operands) {
theCall[2]->push_back(visit(operand, EXPRESSION_RESULT));
}
@@ -936,26 +914,26 @@ Ref Wasm2JSBuilder::processFunctionBody(Module* m, Function* func, bool standalo
}
// TODO: remove
- Ref makeSetVar(Expression* curr, Expression* value, Name name, NameScope scope) {
+ Ref makeSetVar(Expression* curr,
+ Expression* value,
+ Name name,
+ NameScope scope) {
return ValueBuilder::makeBinary(
- ValueBuilder::makeName(fromName(name, scope)), SET,
- visit(value, EXPRESSION_RESULT)
- );
+ ValueBuilder::makeName(fromName(name, scope)),
+ SET,
+ visit(value, EXPRESSION_RESULT));
}
Ref visitGetLocal(GetLocal* curr) {
return ValueBuilder::makeName(
- fromName(func->getLocalNameOrGeneric(curr->index), NameScope::Local)
- );
+ fromName(func->getLocalNameOrGeneric(curr->index), NameScope::Local));
}
Ref visitSetLocal(SetLocal* curr) {
- return makeSetVar(
- curr,
- curr->value,
- func->getLocalNameOrGeneric(curr->index),
- NameScope::Local
- );
+ return makeSetVar(curr,
+ curr->value,
+ func->getLocalNameOrGeneric(curr->index),
+ NameScope::Local);
}
Ref visitGetGlobal(GetGlobal* curr) {
@@ -987,8 +965,10 @@ Ref Wasm2JSBuilder::processFunctionBody(Module* m, Function* func, bool standalo
rest = makeAsmCoercion(visit(&load, EXPRESSION_RESULT), ASM_INT);
for (size_t i = 1; i < curr->bytes; i++) {
++load.offset;
- Ref add = makeAsmCoercion(visit(&load, EXPRESSION_RESULT), ASM_INT);
- add = ValueBuilder::makeBinary(add, LSHIFT, ValueBuilder::makeNum(8*i));
+ Ref add =
+ makeAsmCoercion(visit(&load, EXPRESSION_RESULT), ASM_INT);
+ add = ValueBuilder::makeBinary(
+ add, LSHIFT, ValueBuilder::makeNum(8 * i));
rest = ValueBuilder::makeBinary(rest, OR, add);
}
break;
@@ -1008,18 +988,21 @@ Ref Wasm2JSBuilder::processFunctionBody(Module* m, Function* func, bool standalo
switch (curr->bytes) {
case 1:
ret = ValueBuilder::makeSub(
- ValueBuilder::makeName(LoadUtils::isSignRelevant(curr) && curr->signed_ ? HEAP8 : HEAPU8),
- ValueBuilder::makePtrShift(ptr, 0));
+ ValueBuilder::makeName(
+ LoadUtils::isSignRelevant(curr) && curr->signed_ ? HEAP8
+ : HEAPU8),
+ ValueBuilder::makePtrShift(ptr, 0));
break;
case 2:
ret = ValueBuilder::makeSub(
- ValueBuilder::makeName(LoadUtils::isSignRelevant(curr) && curr->signed_ ? HEAP16 : HEAPU16),
- ValueBuilder::makePtrShift(ptr, 1));
+ ValueBuilder::makeName(
+ LoadUtils::isSignRelevant(curr) && curr->signed_ ? HEAP16
+ : HEAPU16),
+ ValueBuilder::makePtrShift(ptr, 1));
break;
case 4:
- ret = ValueBuilder::makeSub(
- ValueBuilder::makeName(HEAP32),
- ValueBuilder::makePtrShift(ptr, 2));
+ ret = ValueBuilder::makeSub(ValueBuilder::makeName(HEAP32),
+ ValueBuilder::makePtrShift(ptr, 2));
break;
default: {
std::cerr << "Unhandled number of bytes in i32 load: "
@@ -1042,10 +1025,11 @@ Ref Wasm2JSBuilder::processFunctionBody(Module* m, Function* func, bool standalo
abort();
}
}
- // Coercions are not actually needed, as if the user reads beyond valid memory, it's
- // undefined behavior anyhow, and so we don't care much about slowness of undefined
- // values etc.
- bool needCoercions = parent->options.optimizeLevel == 0 || standaloneFunction;
+ // Coercions are not actually needed, as if the user reads beyond valid
+ // memory, it's undefined behavior anyhow, and so we don't care much about
+ // slowness of undefined values etc.
+ bool needCoercions =
+ parent->options.optimizeLevel == 0 || standaloneFunction;
if (needCoercions) {
ret = makeAsmCoercion(ret, wasmToAsmType(curr->type));
}
@@ -1053,7 +1037,8 @@ Ref Wasm2JSBuilder::processFunctionBody(Module* m, Function* func, bool standalo
}
Ref visitStore(Store* curr) {
- if (module->memory.initial < module->memory.max && curr->type != unreachable) {
+ if (module->memory.initial < module->memory.max &&
+ curr->type != unreachable) {
// In JS, if memory grows then it is dangerous to write
// HEAP[f()] = ..
// or
@@ -1117,7 +1102,7 @@ Ref Wasm2JSBuilder::processFunctionBody(Module* m, Function* func, bool standalo
_255.type = i32;
for (size_t i = 0; i < curr->bytes; i++) {
Const shift(allocator);
- shift.value = Literal(int32_t(8*i));
+ shift.value = Literal(int32_t(8 * i));
shift.type = i32;
Binary shifted(allocator);
shifted.op = ShrUInt32;
@@ -1126,7 +1111,8 @@ Ref Wasm2JSBuilder::processFunctionBody(Module* m, Function* func, bool standalo
shifted.type = i32;
Binary anded(allocator);
anded.op = AndInt32;
- anded.left = i > 0 ? static_cast<Expression*>(&shifted) : static_cast<Expression*>(&getValue);
+ anded.left = i > 0 ? static_cast<Expression*>(&shifted)
+ : static_cast<Expression*>(&getValue);
anded.right = &_255;
anded.type = i32;
store.value = &anded;
@@ -1141,12 +1127,13 @@ Ref Wasm2JSBuilder::processFunctionBody(Module* m, Function* func, bool standalo
break;
}
default: {
- std::cerr << "Unhandled type in store: " << curr->valueType
+ std::cerr << "Unhandled type in store: " << curr->valueType
<< std::endl;
abort();
}
}
- return ValueBuilder::makeSeq(ValueBuilder::makeSeq(ptrSet, valueSet), rest);
+ return ValueBuilder::makeSeq(ValueBuilder::makeSeq(ptrSet, valueSet),
+ rest);
}
// normal store
Ref ptr = makePointer(curr->ptr, curr->offset);
@@ -1155,15 +1142,31 @@ Ref Wasm2JSBuilder::processFunctionBody(Module* m, Function* func, bool standalo
switch (curr->valueType) {
case i32: {
switch (curr->bytes) {
- case 1: ret = ValueBuilder::makeSub(ValueBuilder::makeName(HEAP8), ValueBuilder::makePtrShift(ptr, 0)); break;
- case 2: ret = ValueBuilder::makeSub(ValueBuilder::makeName(HEAP16), ValueBuilder::makePtrShift(ptr, 1)); break;
- case 4: ret = ValueBuilder::makeSub(ValueBuilder::makeName(HEAP32), ValueBuilder::makePtrShift(ptr, 2)); break;
- default: abort();
+ case 1:
+ ret = ValueBuilder::makeSub(ValueBuilder::makeName(HEAP8),
+ ValueBuilder::makePtrShift(ptr, 0));
+ break;
+ case 2:
+ ret = ValueBuilder::makeSub(ValueBuilder::makeName(HEAP16),
+ ValueBuilder::makePtrShift(ptr, 1));
+ break;
+ case 4:
+ ret = ValueBuilder::makeSub(ValueBuilder::makeName(HEAP32),
+ ValueBuilder::makePtrShift(ptr, 2));
+ break;
+ default:
+ abort();
}
break;
}
- case f32: ret = ValueBuilder::makeSub(ValueBuilder::makeName(HEAPF32), ValueBuilder::makePtrShift(ptr, 2)); break;
- case f64: ret = ValueBuilder::makeSub(ValueBuilder::makeName(HEAPF64), ValueBuilder::makePtrShift(ptr, 3)); break;
+ case f32:
+ ret = ValueBuilder::makeSub(ValueBuilder::makeName(HEAPF32),
+ ValueBuilder::makePtrShift(ptr, 2));
+ break;
+ case f64:
+ ret = ValueBuilder::makeSub(ValueBuilder::makeName(HEAPF64),
+ ValueBuilder::makePtrShift(ptr, 3));
+ break;
default: {
std::cerr << "Unhandled type in store: " << curr->valueType
<< std::endl;
@@ -1173,19 +1176,18 @@ Ref Wasm2JSBuilder::processFunctionBody(Module* m, Function* func, bool standalo
return ValueBuilder::makeBinary(ret, SET, value);
}
- Ref visitDrop(Drop* curr) {
- return visit(curr->value, NO_RESULT);
- }
+ Ref visitDrop(Drop* curr) { return visit(curr->value, NO_RESULT); }
Ref visitConst(Const* curr) {
switch (curr->type) {
- case i32: return ValueBuilder::makeInt(curr->value.geti32());
+ case i32:
+ return ValueBuilder::makeInt(curr->value.geti32());
// An i64 argument translates to two actual arguments to asm.js
// functions, so we do a bit of a hack here to get our one `Ref` to look
// like two function arguments.
case i64: {
- auto lo = (unsigned) curr->value.geti64();
- auto hi = (unsigned) (curr->value.geti64() >> 32);
+ auto lo = (unsigned)curr->value.geti64();
+ auto hi = (unsigned)(curr->value.geti64() >> 32);
std::ostringstream out;
out << lo << "," << hi;
std::string os = out.str();
@@ -1203,11 +1205,15 @@ Ref Wasm2JSBuilder::processFunctionBody(Module* m, Function* func, bool standalo
case f64: {
double d = curr->value.getf64();
if (d == 0 && std::signbit(d)) { // negative zero
- return ValueBuilder::makeUnary(PLUS, ValueBuilder::makeUnary(MINUS, ValueBuilder::makeDouble(0)));
+ return ValueBuilder::makeUnary(
+ PLUS,
+ ValueBuilder::makeUnary(MINUS, ValueBuilder::makeDouble(0)));
}
- return ValueBuilder::makeUnary(PLUS, ValueBuilder::makeDouble(curr->value.getf64()));
+ return ValueBuilder::makeUnary(
+ PLUS, ValueBuilder::makeDouble(curr->value.getf64()));
}
- default: abort();
+ default:
+ abort();
}
}
@@ -1218,37 +1224,37 @@ Ref Wasm2JSBuilder::processFunctionBody(Module* m, Function* func, bool standalo
switch (curr->op) {
case ClzInt32:
return ValueBuilder::makeCall(
- MATH_CLZ32,
- visit(curr->value, EXPRESSION_RESULT)
- );
+ MATH_CLZ32, visit(curr->value, EXPRESSION_RESULT));
case CtzInt32:
case PopcntInt32:
std::cerr << "i32 unary should have been removed: " << curr
<< std::endl;
WASM_UNREACHABLE();
case EqZInt32:
- // XXX !x does change the type to bool, which is correct, but may be slower?
- return ValueBuilder::makeUnary(L_NOT, visit(curr->value, EXPRESSION_RESULT));
+ // XXX !x does change the type to bool, which is correct, but may
+ // be slower?
+ return ValueBuilder::makeUnary(
+ L_NOT, visit(curr->value, EXPRESSION_RESULT));
case ReinterpretFloat32: {
- ABI::wasm2js::ensureScratchMemoryHelpers(module, ABI::wasm2js::SCRATCH_STORE_F32);
- ABI::wasm2js::ensureScratchMemoryHelpers(module, ABI::wasm2js::SCRATCH_LOAD_I32);
-
- Ref store = ValueBuilder::makeCall(
- ABI::wasm2js::SCRATCH_STORE_F32,
- visit(curr->value, EXPRESSION_RESULT)
- );
- Ref load = ValueBuilder::makeCall(ABI::wasm2js::SCRATCH_LOAD_I32, ValueBuilder::makeInt(0));
+ ABI::wasm2js::ensureScratchMemoryHelpers(
+ module, ABI::wasm2js::SCRATCH_STORE_F32);
+ ABI::wasm2js::ensureScratchMemoryHelpers(
+ module, ABI::wasm2js::SCRATCH_LOAD_I32);
+
+ Ref store =
+ ValueBuilder::makeCall(ABI::wasm2js::SCRATCH_STORE_F32,
+ visit(curr->value, EXPRESSION_RESULT));
+ Ref load = ValueBuilder::makeCall(ABI::wasm2js::SCRATCH_LOAD_I32,
+ ValueBuilder::makeInt(0));
return ValueBuilder::makeSeq(store, load);
}
// generate (~~expr), what Emscripten does
case TruncSFloat32ToInt32:
case TruncSFloat64ToInt32:
return ValueBuilder::makeUnary(
- B_NOT,
- ValueBuilder::makeUnary(
- B_NOT,
- visit(curr->value, EXPRESSION_RESULT)
- ));
+ B_NOT,
+ ValueBuilder::makeUnary(B_NOT,
+ visit(curr->value, EXPRESSION_RESULT)));
// generate (~~expr >>> 0), what Emscripten does
case TruncUFloat32ToInt32:
@@ -1257,13 +1263,9 @@ Ref Wasm2JSBuilder::processFunctionBody(Module* m, Function* func, bool standalo
ValueBuilder::makeUnary(
B_NOT,
ValueBuilder::makeUnary(
- B_NOT,
- visit(curr->value, EXPRESSION_RESULT)
- )
- ),
+ B_NOT, visit(curr->value, EXPRESSION_RESULT))),
TRSHIFT,
- ValueBuilder::makeNum(0)
- );
+ ValueBuilder::makeNum(0));
default: {
std::cerr << "Unhandled unary i32 operator: " << curr
@@ -1279,37 +1281,27 @@ Ref Wasm2JSBuilder::processFunctionBody(Module* m, Function* func, bool standalo
case NegFloat32:
case NegFloat64:
ret = ValueBuilder::makeUnary(
- MINUS,
- visit(curr->value, EXPRESSION_RESULT)
- );
+ MINUS, visit(curr->value, EXPRESSION_RESULT));
break;
case AbsFloat32:
case AbsFloat64:
ret = ValueBuilder::makeCall(
- MATH_ABS,
- visit(curr->value, EXPRESSION_RESULT)
- );
+ MATH_ABS, visit(curr->value, EXPRESSION_RESULT));
break;
case CeilFloat32:
case CeilFloat64:
ret = ValueBuilder::makeCall(
- MATH_CEIL,
- visit(curr->value, EXPRESSION_RESULT)
- );
+ MATH_CEIL, visit(curr->value, EXPRESSION_RESULT));
break;
case FloorFloat32:
case FloorFloat64:
ret = ValueBuilder::makeCall(
- MATH_FLOOR,
- visit(curr->value, EXPRESSION_RESULT)
- );
+ MATH_FLOOR, visit(curr->value, EXPRESSION_RESULT));
break;
case SqrtFloat32:
case SqrtFloat64:
ret = ValueBuilder::makeCall(
- MATH_SQRT,
- visit(curr->value, EXPRESSION_RESULT)
- );
+ MATH_SQRT, visit(curr->value, EXPRESSION_RESULT));
break;
case PromoteFloat32:
return makeAsmCoercion(visit(curr->value, EXPRESSION_RESULT),
@@ -1318,14 +1310,15 @@ Ref Wasm2JSBuilder::processFunctionBody(Module* m, Function* func, bool standalo
return makeAsmCoercion(visit(curr->value, EXPRESSION_RESULT),
ASM_FLOAT);
case ReinterpretInt32: {
- ABI::wasm2js::ensureScratchMemoryHelpers(module, ABI::wasm2js::SCRATCH_STORE_I32);
- ABI::wasm2js::ensureScratchMemoryHelpers(module, ABI::wasm2js::SCRATCH_LOAD_F32);
-
- Ref store = ValueBuilder::makeCall(
- ABI::wasm2js::SCRATCH_STORE_I32,
- ValueBuilder::makeNum(0),
- visit(curr->value, EXPRESSION_RESULT)
- );
+ ABI::wasm2js::ensureScratchMemoryHelpers(
+ module, ABI::wasm2js::SCRATCH_STORE_I32);
+ ABI::wasm2js::ensureScratchMemoryHelpers(
+ module, ABI::wasm2js::SCRATCH_LOAD_F32);
+
+ Ref store =
+ ValueBuilder::makeCall(ABI::wasm2js::SCRATCH_STORE_I32,
+ ValueBuilder::makeNum(0),
+ visit(curr->value, EXPRESSION_RESULT));
Ref load = ValueBuilder::makeCall(ABI::wasm2js::SCRATCH_LOAD_F32);
return ValueBuilder::makeSeq(store, load);
}
@@ -1333,40 +1326,33 @@ Ref Wasm2JSBuilder::processFunctionBody(Module* m, Function* func, bool standalo
case ConvertSInt32ToFloat32:
return makeAsmCoercion(
makeAsmCoercion(visit(curr->value, EXPRESSION_RESULT), ASM_INT),
- ASM_FLOAT
- );
+ ASM_FLOAT);
case ConvertSInt32ToFloat64:
return makeAsmCoercion(
makeAsmCoercion(visit(curr->value, EXPRESSION_RESULT), ASM_INT),
- ASM_DOUBLE
- );
+ ASM_DOUBLE);
// Generate (expr >>> 0), followed by a coercion
case ConvertUInt32ToFloat32:
return makeAsmCoercion(
- ValueBuilder::makeBinary(
- visit(curr->value, EXPRESSION_RESULT),
- TRSHIFT,
- ValueBuilder::makeInt(0)
- ),
- ASM_FLOAT
- );
+ ValueBuilder::makeBinary(visit(curr->value, EXPRESSION_RESULT),
+ TRSHIFT,
+ ValueBuilder::makeInt(0)),
+ ASM_FLOAT);
case ConvertUInt32ToFloat64:
return makeAsmCoercion(
- ValueBuilder::makeBinary(
- visit(curr->value, EXPRESSION_RESULT),
- TRSHIFT,
- ValueBuilder::makeInt(0)
- ),
- ASM_DOUBLE
- );
+ ValueBuilder::makeBinary(visit(curr->value, EXPRESSION_RESULT),
+ TRSHIFT,
+ ValueBuilder::makeInt(0)),
+ ASM_DOUBLE);
// TODO: more complex unary conversions
case NearestFloat32:
case NearestFloat64:
case TruncFloat32:
case TruncFloat64:
- std::cerr << "operation should have been removed in previous passes"
- << std::endl;
+ std::cerr
+ << "operation should have been removed in previous passes"
+ << std::endl;
WASM_UNREACHABLE();
default:
@@ -1409,19 +1395,23 @@ Ref Wasm2JSBuilder::processFunctionBody(Module* m, Function* func, bool standalo
}
}
case DivSInt32:
- ret = ValueBuilder::makeBinary(makeSigning(left, ASM_SIGNED), DIV,
+ ret = ValueBuilder::makeBinary(makeSigning(left, ASM_SIGNED),
+ DIV,
makeSigning(right, ASM_SIGNED));
break;
case DivUInt32:
- ret = ValueBuilder::makeBinary(makeSigning(left, ASM_UNSIGNED), DIV,
+ ret = ValueBuilder::makeBinary(makeSigning(left, ASM_UNSIGNED),
+ DIV,
makeSigning(right, ASM_UNSIGNED));
break;
case RemSInt32:
- ret = ValueBuilder::makeBinary(makeSigning(left, ASM_SIGNED), MOD,
+ ret = ValueBuilder::makeBinary(makeSigning(left, ASM_SIGNED),
+ MOD,
makeSigning(right, ASM_SIGNED));
break;
case RemUInt32:
- ret = ValueBuilder::makeBinary(makeSigning(left, ASM_UNSIGNED), MOD,
+ ret = ValueBuilder::makeBinary(makeSigning(left, ASM_UNSIGNED),
+ MOD,
makeSigning(right, ASM_UNSIGNED));
break;
case AndInt32:
@@ -1443,36 +1433,46 @@ Ref Wasm2JSBuilder::processFunctionBody(Module* m, Function* func, bool standalo
ret = ValueBuilder::makeBinary(left, RSHIFT, right);
break;
case EqInt32: {
- return ValueBuilder::makeBinary(makeSigning(left, ASM_SIGNED), EQ,
+ return ValueBuilder::makeBinary(makeSigning(left, ASM_SIGNED),
+ EQ,
makeSigning(right, ASM_SIGNED));
}
case NeInt32: {
- return ValueBuilder::makeBinary(makeSigning(left, ASM_SIGNED), NE,
+ return ValueBuilder::makeBinary(makeSigning(left, ASM_SIGNED),
+ NE,
makeSigning(right, ASM_SIGNED));
}
case LtSInt32:
- return ValueBuilder::makeBinary(makeSigning(left, ASM_SIGNED), LT,
+ return ValueBuilder::makeBinary(makeSigning(left, ASM_SIGNED),
+ LT,
makeSigning(right, ASM_SIGNED));
case LtUInt32:
- return ValueBuilder::makeBinary(makeSigning(left, ASM_UNSIGNED), LT,
+ return ValueBuilder::makeBinary(makeSigning(left, ASM_UNSIGNED),
+ LT,
makeSigning(right, ASM_UNSIGNED));
case LeSInt32:
- return ValueBuilder::makeBinary(makeSigning(left, ASM_SIGNED), LE,
+ return ValueBuilder::makeBinary(makeSigning(left, ASM_SIGNED),
+ LE,
makeSigning(right, ASM_SIGNED));
case LeUInt32:
- return ValueBuilder::makeBinary(makeSigning(left, ASM_UNSIGNED), LE,
+ return ValueBuilder::makeBinary(makeSigning(left, ASM_UNSIGNED),
+ LE,
makeSigning(right, ASM_UNSIGNED));
case GtSInt32:
- return ValueBuilder::makeBinary(makeSigning(left, ASM_SIGNED), GT,
+ return ValueBuilder::makeBinary(makeSigning(left, ASM_SIGNED),
+ GT,
makeSigning(right, ASM_SIGNED));
case GtUInt32:
- return ValueBuilder::makeBinary(makeSigning(left, ASM_UNSIGNED), GT,
+ return ValueBuilder::makeBinary(makeSigning(left, ASM_UNSIGNED),
+ GT,
makeSigning(right, ASM_UNSIGNED));
case GeSInt32:
- return ValueBuilder::makeBinary(makeSigning(left, ASM_SIGNED), GE,
+ return ValueBuilder::makeBinary(makeSigning(left, ASM_SIGNED),
+ GE,
makeSigning(right, ASM_SIGNED));
case GeUInt32:
- return ValueBuilder::makeBinary(makeSigning(left, ASM_UNSIGNED), GE,
+ return ValueBuilder::makeBinary(makeSigning(left, ASM_UNSIGNED),
+ GE,
makeSigning(right, ASM_UNSIGNED));
case EqFloat32:
case EqFloat64:
@@ -1497,7 +1497,8 @@ Ref Wasm2JSBuilder::processFunctionBody(Module* m, Function* func, bool standalo
std::cerr << "should be removed already" << std::endl;
WASM_UNREACHABLE();
default: {
- std::cerr << "Unhandled i32 binary operator: " << curr << std::endl;
+ std::cerr << "Unhandled i32 binary operator: " << curr
+ << std::endl;
abort();
}
}
@@ -1505,10 +1506,10 @@ Ref Wasm2JSBuilder::processFunctionBody(Module* m, Function* func, bool standalo
}
case f32:
case f64:
- switch (curr->op) {
- case AddFloat32:
- case AddFloat64:
- ret = ValueBuilder::makeBinary(left, PLUS, right);
+ switch (curr->op) {
+ case AddFloat32:
+ case AddFloat64:
+ ret = ValueBuilder::makeBinary(left, PLUS, right);
break;
case SubFloat32:
case SubFloat64:
@@ -1533,7 +1534,8 @@ Ref Wasm2JSBuilder::processFunctionBody(Module* m, Function* func, bool standalo
case CopySignFloat32:
case CopySignFloat64:
default:
- std::cerr << "Unhandled binary float operator: " << curr << std::endl;
+ std::cerr << "Unhandled binary float operator: " << curr
+ << std::endl;
abort();
}
if (curr->type == f32) {
@@ -1548,48 +1550,41 @@ Ref Wasm2JSBuilder::processFunctionBody(Module* m, Function* func, bool standalo
}
Ref visitSelect(Select* curr) {
- // If the condition has effects that interact with the operands, we must reorder it to the start.
- // We must also use locals if the values have side effects, as a JS conditional does not
- // visit both sides.
+ // If the condition has effects that interact with the operands, we must
+ // reorder it to the start. We must also use locals if the values have
+ // side effects, as a JS conditional does not visit both sides.
bool useLocals = false;
EffectAnalyzer conditionEffects(parent->options, curr->condition);
EffectAnalyzer ifTrueEffects(parent->options, curr->ifTrue);
EffectAnalyzer ifFalseEffects(parent->options, curr->ifFalse);
if (conditionEffects.invalidates(ifTrueEffects) ||
conditionEffects.invalidates(ifFalseEffects) ||
- ifTrueEffects.hasSideEffects() ||
- ifFalseEffects.hasSideEffects()) {
+ ifTrueEffects.hasSideEffects() || ifFalseEffects.hasSideEffects()) {
useLocals = true;
}
if (useLocals) {
ScopedTemp tempIfTrue(curr->type, parent, func),
- tempIfFalse(curr->type, parent, func),
- tempCondition(i32, parent, func);
+ tempIfFalse(curr->type, parent, func),
+ tempCondition(i32, parent, func);
Ref ifTrue = visit(curr->ifTrue, EXPRESSION_RESULT);
Ref ifFalse = visit(curr->ifFalse, EXPRESSION_RESULT);
Ref condition = visit(curr->condition, EXPRESSION_RESULT);
- return
+ return ValueBuilder::makeSeq(
+ ValueBuilder::makeBinary(tempIfTrue.getAstName(), SET, ifTrue),
ValueBuilder::makeSeq(
- ValueBuilder::makeBinary(tempIfTrue.getAstName(), SET, ifTrue),
+ ValueBuilder::makeBinary(tempIfFalse.getAstName(), SET, ifFalse),
ValueBuilder::makeSeq(
- ValueBuilder::makeBinary(tempIfFalse.getAstName(), SET, ifFalse),
- ValueBuilder::makeSeq(
- ValueBuilder::makeBinary(tempCondition.getAstName(), SET, condition),
- ValueBuilder::makeConditional(
- tempCondition.getAstName(),
- tempIfTrue.getAstName(),
- tempIfFalse.getAstName()
- )
- )
- )
- );
+ ValueBuilder::makeBinary(
+ tempCondition.getAstName(), SET, condition),
+ ValueBuilder::makeConditional(tempCondition.getAstName(),
+ tempIfTrue.getAstName(),
+ tempIfFalse.getAstName()))));
} else {
// Simple case without reordering.
return ValueBuilder::makeConditional(
visit(curr->condition, EXPRESSION_RESULT),
visit(curr->ifTrue, EXPRESSION_RESULT),
- visit(curr->ifFalse, EXPRESSION_RESULT)
- );
+ visit(curr->ifFalse, EXPRESSION_RESULT));
}
}
@@ -1598,7 +1593,9 @@ Ref Wasm2JSBuilder::processFunctionBody(Module* m, Function* func, bool standalo
return ValueBuilder::makeReturn(Ref());
}
Ref val = visit(curr->value, EXPRESSION_RESULT);
- bool needCoercion = parent->options.optimizeLevel == 0 || standaloneFunction || parent->functionsCallableFromOutside.count(func->name);
+ bool needCoercion =
+ parent->options.optimizeLevel == 0 || standaloneFunction ||
+ parent->functionsCallableFromOutside.count(func->name);
if (needCoercion) {
val = makeAsmCoercion(val, wasmToAsmType(curr->value->type));
}
@@ -1607,11 +1604,12 @@ Ref Wasm2JSBuilder::processFunctionBody(Module* m, Function* func, bool standalo
Ref visitHost(Host* curr) {
if (curr->op == HostOp::GrowMemory) {
- if (module->memory.exists && module->memory.max > module->memory.initial) {
- return ValueBuilder::makeCall(WASM_GROW_MEMORY,
- makeAsmCoercion(
- visit(curr->operands[0], EXPRESSION_RESULT),
- wasmToAsmType(curr->operands[0]->type)));
+ if (module->memory.exists &&
+ module->memory.max > module->memory.initial) {
+ return ValueBuilder::makeCall(
+ WASM_GROW_MEMORY,
+ makeAsmCoercion(visit(curr->operands[0], EXPRESSION_RESULT),
+ wasmToAsmType(curr->operands[0]->type)));
} else {
return ValueBuilder::makeCall(ABORT_FUNC);
}
@@ -1621,9 +1619,7 @@ Ref Wasm2JSBuilder::processFunctionBody(Module* m, Function* func, bool standalo
WASM_UNREACHABLE(); // TODO
}
- Ref visitNop(Nop* curr) {
- return ValueBuilder::makeToplevel();
- }
+ Ref visitNop(Nop* curr) { return ValueBuilder::makeToplevel(); }
Ref visitUnreachable(Unreachable* curr) {
return ValueBuilder::makeCall(ABORT_FUNC);
@@ -1634,14 +1630,15 @@ Ref Wasm2JSBuilder::processFunctionBody(Module* m, Function* func, bool standalo
auto ret = visit(ptr, EXPRESSION_RESULT);
if (offset) {
ret = makeAsmCoercion(
- ValueBuilder::makeBinary(ret, PLUS, ValueBuilder::makeNum(offset)),
- ASM_INT);
+ ValueBuilder::makeBinary(ret, PLUS, ValueBuilder::makeNum(offset)),
+ ASM_INT);
}
return ret;
}
};
- return ExpressionProcessor(this, m, func, standaloneFunction).visit(func->body, NO_RESULT);
+ return ExpressionProcessor(this, m, func, standaloneFunction)
+ .visit(func->body, NO_RESULT);
}
void Wasm2JSBuilder::addMemoryGrowthFuncs(Ref ast, Module* wasm) {
@@ -1649,50 +1646,43 @@ void Wasm2JSBuilder::addMemoryGrowthFuncs(Ref ast, Module* wasm) {
ValueBuilder::appendArgumentToFunction(growMemoryFunc, IString("pagesToAdd"));
growMemoryFunc[3]->push_back(
- ValueBuilder::makeStatement(
- ValueBuilder::makeBinary(
- ValueBuilder::makeName(IString("pagesToAdd")), SET,
- makeAsmCoercion(
- ValueBuilder::makeName(IString("pagesToAdd")),
- AsmType::ASM_INT
- )
- )
- )
- );
+ ValueBuilder::makeStatement(ValueBuilder::makeBinary(
+ ValueBuilder::makeName(IString("pagesToAdd")),
+ SET,
+ makeAsmCoercion(ValueBuilder::makeName(IString("pagesToAdd")),
+ AsmType::ASM_INT))));
Ref oldPages = ValueBuilder::makeVar();
growMemoryFunc[3]->push_back(oldPages);
ValueBuilder::appendToVar(
oldPages,
IString("oldPages"),
- makeAsmCoercion(ValueBuilder::makeCall(WASM_CURRENT_MEMORY), AsmType::ASM_INT));
+ makeAsmCoercion(ValueBuilder::makeCall(WASM_CURRENT_MEMORY),
+ AsmType::ASM_INT));
Ref newPages = ValueBuilder::makeVar();
growMemoryFunc[3]->push_back(newPages);
ValueBuilder::appendToVar(
newPages,
IString("newPages"),
- makeAsmCoercion(ValueBuilder::makeBinary(
- ValueBuilder::makeName(IString("oldPages")),
- PLUS,
- ValueBuilder::makeName(IString("pagesToAdd"))
- ), AsmType::ASM_INT));
+ makeAsmCoercion(
+ ValueBuilder::makeBinary(ValueBuilder::makeName(IString("oldPages")),
+ PLUS,
+ ValueBuilder::makeName(IString("pagesToAdd"))),
+ AsmType::ASM_INT));
Ref block = ValueBuilder::makeBlock();
growMemoryFunc[3]->push_back(ValueBuilder::makeIf(
ValueBuilder::makeBinary(
- ValueBuilder::makeBinary(
- ValueBuilder::makeName(IString("oldPages")),
- LT,
- ValueBuilder::makeName(IString("newPages"))
- ),
+ ValueBuilder::makeBinary(ValueBuilder::makeName(IString("oldPages")),
+ LT,
+ ValueBuilder::makeName(IString("newPages"))),
IString("&&"),
- ValueBuilder::makeBinary(
- ValueBuilder::makeName(IString("newPages")),
- LT,
- ValueBuilder::makeInt(Memory::kMaxSize)
- )
- ), block, NULL));
+ ValueBuilder::makeBinary(ValueBuilder::makeName(IString("newPages")),
+ LT,
+ ValueBuilder::makeInt(Memory::kMaxSize))),
+ block,
+ NULL));
Ref newBuffer = ValueBuilder::makeVar();
ValueBuilder::appendToBlock(block, newBuffer);
@@ -1701,110 +1691,79 @@ void Wasm2JSBuilder::addMemoryGrowthFuncs(Ref ast, Module* wasm) {
IString("newBuffer"),
ValueBuilder::makeNew(ValueBuilder::makeCall(
ARRAY_BUFFER,
- ValueBuilder::makeCall(
- MATH_IMUL,
- ValueBuilder::makeName(IString("newPages")),
- ValueBuilder::makeInt(Memory::kPageSize)))));
+ ValueBuilder::makeCall(MATH_IMUL,
+ ValueBuilder::makeName(IString("newPages")),
+ ValueBuilder::makeInt(Memory::kPageSize)))));
Ref newHEAP8 = ValueBuilder::makeVar();
ValueBuilder::appendToBlock(block, newHEAP8);
ValueBuilder::appendToVar(
newHEAP8,
IString("newHEAP8"),
- ValueBuilder::makeNew(
- ValueBuilder::makeCall(
- ValueBuilder::makeDot(
- ValueBuilder::makeName(GLOBAL),
- INT8ARRAY
- ),
- ValueBuilder::makeName(IString("newBuffer"))
- )
- ));
-
- ValueBuilder::appendToBlock(block,
+ ValueBuilder::makeNew(ValueBuilder::makeCall(
+ ValueBuilder::makeDot(ValueBuilder::makeName(GLOBAL), INT8ARRAY),
+ ValueBuilder::makeName(IString("newBuffer")))));
+
+ ValueBuilder::appendToBlock(
+ block,
ValueBuilder::makeCall(
- ValueBuilder::makeDot(
- ValueBuilder::makeName(IString("newHEAP8")),
- IString("set")
- ),
- ValueBuilder::makeName(HEAP8)
- )
- );
-
- ValueBuilder::appendToBlock(block,
- ValueBuilder::makeBinary(
- ValueBuilder::makeName(HEAP8),
- SET,
- ValueBuilder::makeName(IString("newHEAP8"))
- )
- );
+ ValueBuilder::makeDot(ValueBuilder::makeName(IString("newHEAP8")),
+ IString("set")),
+ ValueBuilder::makeName(HEAP8)));
+
+ ValueBuilder::appendToBlock(
+ block,
+ ValueBuilder::makeBinary(ValueBuilder::makeName(HEAP8),
+ SET,
+ ValueBuilder::makeName(IString("newHEAP8"))));
auto setHeap = [&](IString name, IString view) {
- ValueBuilder::appendToBlock(block,
+ ValueBuilder::appendToBlock(
+ block,
ValueBuilder::makeBinary(
ValueBuilder::makeName(name),
SET,
- ValueBuilder::makeNew(
- ValueBuilder::makeCall(
- ValueBuilder::makeDot(
- ValueBuilder::makeName(GLOBAL),
- view
- ),
- ValueBuilder::makeName(IString("newBuffer"))
- )
- )
- )
- );
+ ValueBuilder::makeNew(ValueBuilder::makeCall(
+ ValueBuilder::makeDot(ValueBuilder::makeName(GLOBAL), view),
+ ValueBuilder::makeName(IString("newBuffer"))))));
};
setHeap(HEAP16, INT16ARRAY);
setHeap(HEAP32, INT32ARRAY);
- setHeap(HEAPU8, UINT8ARRAY);
+ setHeap(HEAPU8, UINT8ARRAY);
setHeap(HEAPU16, UINT16ARRAY);
setHeap(HEAPU32, UINT32ARRAY);
setHeap(HEAPF32, FLOAT32ARRAY);
setHeap(HEAPF64, FLOAT64ARRAY);
- ValueBuilder::appendToBlock(block,
- ValueBuilder::makeBinary(
- ValueBuilder::makeName(BUFFER),
- SET,
- ValueBuilder::makeName(IString("newBuffer"))
- )
- );
+ ValueBuilder::appendToBlock(
+ block,
+ ValueBuilder::makeBinary(ValueBuilder::makeName(BUFFER),
+ SET,
+ ValueBuilder::makeName(IString("newBuffer"))));
// apply the changes to the memory import
if (wasm->memory.imported()) {
- ValueBuilder::appendToBlock(block,
+ ValueBuilder::appendToBlock(
+ block,
ValueBuilder::makeBinary(
- ValueBuilder::makeDot(
- ValueBuilder::makeName("memory"),
- ValueBuilder::makeName(BUFFER)
- ),
+ ValueBuilder::makeDot(ValueBuilder::makeName("memory"),
+ ValueBuilder::makeName(BUFFER)),
SET,
- ValueBuilder::makeName(IString("newBuffer"))
- )
- );
+ ValueBuilder::makeName(IString("newBuffer"))));
}
growMemoryFunc[3]->push_back(
- ValueBuilder::makeReturn(
- ValueBuilder::makeName(IString("oldPages"))));
+ ValueBuilder::makeReturn(ValueBuilder::makeName(IString("oldPages"))));
Ref currentMemoryFunc = ValueBuilder::makeFunction(WASM_CURRENT_MEMORY);
currentMemoryFunc[3]->push_back(ValueBuilder::makeReturn(
- makeAsmCoercion(
- ValueBuilder::makeBinary(
- ValueBuilder::makeDot(
- ValueBuilder::makeName(BUFFER),
- IString("byteLength")
- ),
- DIV,
- ValueBuilder::makeInt(Memory::kPageSize)
- ),
- AsmType::ASM_INT
- )
- ));
+ makeAsmCoercion(ValueBuilder::makeBinary(
+ ValueBuilder::makeDot(ValueBuilder::makeName(BUFFER),
+ IString("byteLength")),
+ DIV,
+ ValueBuilder::makeInt(Memory::kPageSize)),
+ AsmType::ASM_INT)));
ast->push_back(growMemoryFunc);
ast->push_back(currentMemoryFunc);
}
@@ -1814,7 +1773,11 @@ void Wasm2JSBuilder::addMemoryGrowthFuncs(Ref ast, Module* wasm) {
// "glue" around that.
class Wasm2JSGlue {
public:
- Wasm2JSGlue(Module& wasm, Output& out, Wasm2JSBuilder::Flags flags, Name moduleName) : wasm(wasm), out(out), flags(flags), moduleName(moduleName) {}
+ Wasm2JSGlue(Module& wasm,
+ Output& out,
+ Wasm2JSBuilder::Flags flags,
+ Name moduleName)
+ : wasm(wasm), out(out), flags(flags), moduleName(moduleName) {}
void emitPre();
void emitPost();
@@ -1830,7 +1793,9 @@ private:
void emitPostEmscripten();
void emitPostES6();
- void emitMemory(std::string buffer, std::string segmentWriter, std::function<std::string (std::string)> accessGlobal);
+ void emitMemory(std::string buffer,
+ std::string segmentWriter,
+ std::function<std::string(std::string)> accessGlobal);
void emitScratchMemorySupport();
};
@@ -1845,7 +1810,8 @@ void Wasm2JSGlue::emitPre() {
}
void Wasm2JSGlue::emitPreEmscripten() {
- out << "function instantiate(asmLibraryArg, wasmMemory, FUNCTION_TABLE) {\n\n";
+ out
+ << "function instantiate(asmLibraryArg, wasmMemory, FUNCTION_TABLE) {\n\n";
}
void Wasm2JSGlue::emitPreES6() {
@@ -1853,7 +1819,8 @@ void Wasm2JSGlue::emitPreES6() {
auto noteImport = [&](Name module, Name base) {
// Right now codegen requires a flat namespace going into the module,
- // meaning we don't support importing the same name from multiple namespaces yet.
+ // meaning we don't support importing the same name from multiple namespaces
+ // yet.
if (baseModuleMap.count(base) && baseModuleMap[base] != module) {
Fatal() << "the name " << base << " cannot be imported from "
<< "two different modules yet\n";
@@ -1861,20 +1828,16 @@ void Wasm2JSGlue::emitPreES6() {
}
baseModuleMap[base] = module;
- out << "import { "
- << base.str
- << " } from '"
- << module.str
- << "';\n";
+ out << "import { " << base.str << " } from '" << module.str << "';\n";
};
ImportInfo imports(wasm);
- ModuleUtils::iterImportedGlobals(wasm, [&](Global* import) {
- noteImport(import->module, import->base);
- });
+ ModuleUtils::iterImportedGlobals(
+ wasm, [&](Global* import) { noteImport(import->module, import->base); });
ModuleUtils::iterImportedFunctions(wasm, [&](Function* import) {
- // The scratch memory helpers are emitted in the glue, see code and comments below.
+ // The scratch memory helpers are emitted in the glue, see code and comments
+ // below.
if (ABI::wasm2js::isScratchMemoryHelper(import->base)) {
return;
}
@@ -1932,8 +1895,7 @@ void Wasm2JSGlue::emitPostES6() {
{
auto pages = wasm.memory.initial == 0 ? 1 : wasm.memory.initial.addr;
out << "var mem" << moduleName.str << " = new ArrayBuffer("
- << pages * Memory::kPageSize
- << ");\n";
+ << pages * Memory::kPageSize << ");\n";
}
emitMemory(std::string("mem") + moduleName.str,
@@ -1943,23 +1905,24 @@ void Wasm2JSGlue::emitPostES6() {
// Actually invoke the `asmFunc` generated function, passing in all global
// values followed by all imports
out << "var ret" << moduleName.str << " = " << moduleName.str << "({"
- << "Math,"
- << "Int8Array,"
- << "Uint8Array,"
- << "Int16Array,"
- << "Uint16Array,"
- << "Int32Array,"
- << "Uint32Array,"
- << "Float32Array,"
- << "Float64Array,"
- << "NaN,"
- << "Infinity"
- << "}, {";
+ << "Math,"
+ << "Int8Array,"
+ << "Uint8Array,"
+ << "Int16Array,"
+ << "Uint16Array,"
+ << "Int32Array,"
+ << "Uint32Array,"
+ << "Float32Array,"
+ << "Float64Array,"
+ << "NaN,"
+ << "Infinity"
+ << "}, {";
out << "abort:function() { throw new Error('abort'); }";
ModuleUtils::iterImportedFunctions(wasm, [&](Function* import) {
- // The scratch memory helpers are emitted in the glue, see code and comments below.
+ // The scratch memory helpers are emitted in the glue, see code and comments
+ // below.
if (ABI::wasm2js::isScratchMemoryHelper(import->base)) {
return;
}
@@ -1984,25 +1947,24 @@ void Wasm2JSGlue::emitPostES6() {
continue;
}
std::ostringstream export_name;
- for (auto *ptr = exp->name.str; *ptr; ptr++) {
+ for (auto* ptr = exp->name.str; *ptr; ptr++) {
if (*ptr == '-') {
export_name << '_';
} else {
export_name << *ptr;
}
}
- out << "export var "
- << asmangle(exp->name.str)
- << " = ret"
- << moduleName.str
- << "."
- << asmangle(exp->name.str)
- << ";\n";
+ out << "export var " << asmangle(exp->name.str) << " = ret"
+ << moduleName.str << "." << asmangle(exp->name.str) << ";\n";
}
}
-void Wasm2JSGlue::emitMemory(std::string buffer, std::string segmentWriter, std::function<std::string (std::string)> accessGlobal) {
- if (wasm.memory.segments.empty()) return;
+void Wasm2JSGlue::emitMemory(
+ std::string buffer,
+ std::string segmentWriter,
+ std::function<std::string(std::string)> accessGlobal) {
+ if (wasm.memory.segments.empty())
+ return;
auto expr = R"(
function(mem) {
@@ -2022,11 +1984,11 @@ void Wasm2JSGlue::emitMemory(std::string buffer, std::string segmentWriter, std:
)";
// var assign$name = ($expr)(mem$name);
- out << "var " << segmentWriter
- << " = (" << expr << ")(" << buffer << ");\n";
+ out << "var " << segmentWriter << " = (" << expr << ")(" << buffer << ");\n";
auto globalOffset = [&](const Memory::Segment& segment) {
- if (auto* c = segment.offset->template dynCast<Const>()) {;
+ if (auto* c = segment.offset->template dynCast<Const>()) {
+ ;
return std::to_string(c->value.getInteger());
}
if (auto* get = segment.offset->template dynCast<GetGlobal>()) {
@@ -2039,11 +2001,8 @@ void Wasm2JSGlue::emitMemory(std::string buffer, std::string segmentWriter, std:
for (auto& seg : wasm.memory.segments) {
assert(!seg.isPassive && "passive segments not implemented yet");
- out << segmentWriter << "("
- << globalOffset(seg)
- << ", \""
- << base64Encode(seg.data)
- << "\");\n";
+ out << segmentWriter << "(" << globalOffset(seg) << ", \""
+ << base64Encode(seg.data) << "\");\n";
}
}
@@ -2058,7 +2017,8 @@ void Wasm2JSGlue::emitScratchMemorySupport() {
needScratchMemory = true;
}
});
- if (!needScratchMemory) return;
+ if (!needScratchMemory)
+ return;
out << R"(
var scratchBuffer = new ArrayBuffer(8);