summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorAlon Zakai <alonzakai@gmail.com>2016-06-26 11:00:02 -0700
committerGitHub <noreply@github.com>2016-06-26 11:00:02 -0700
commit45b358706c86415c5982f9e777fa9e19a33b27a3 (patch)
treed1caa4180c8d0f4a76319fd11f8b18f9f446e6c3 /src
parentc410d93d3af9813f889b4011f964d4becf43bc27 (diff)
parent87f3020cf4e666a6eb6620106e48ee042cd2f666 (diff)
downloadbinaryen-45b358706c86415c5982f9e777fa9e19a33b27a3.tar.gz
binaryen-45b358706c86415c5982f9e777fa9e19a33b27a3.tar.bz2
binaryen-45b358706c86415c5982f9e777fa9e19a33b27a3.zip
Merge pull request #602 from WebAssembly/dsl-nice
Use a DSL in OptimizeInstructions
Diffstat (limited to 'src')
-rw-r--r--src/asm2wasm.h1
-rw-r--r--src/asmjs/shared-constants.cpp35
-rw-r--r--src/asmjs/shared-constants.h35
-rw-r--r--src/ast_utils.h126
-rw-r--r--src/parsing.h5
-rw-r--r--src/passes/OptimizeInstructions.cpp186
-rw-r--r--src/passes/OptimizeInstructions.wast152
-rw-r--r--src/passes/OptimizeInstructions.wast.processed152
-rw-r--r--src/shared-constants.h56
-rw-r--r--src/shell-interface.h1
-rw-r--r--src/wasm-binary.h22
-rw-r--r--src/wasm-builder.h48
-rw-r--r--src/wasm-linker.cpp9
-rw-r--r--src/wasm-s-parser.h3
-rw-r--r--src/wasm.cpp55
15 files changed, 736 insertions, 150 deletions
diff --git a/src/asm2wasm.h b/src/asm2wasm.h
index c4cc766aa..2233a10ae 100644
--- a/src/asm2wasm.h
+++ b/src/asm2wasm.h
@@ -25,6 +25,7 @@
#include "wasm.h"
#include "emscripten-optimizer/optimizer.h"
#include "mixed_arena.h"
+#include "shared-constants.h"
#include "asmjs/shared-constants.h"
#include "asm_v_wasm.h"
#include "passes/passes.h"
diff --git a/src/asmjs/shared-constants.cpp b/src/asmjs/shared-constants.cpp
index bc1c0fa3d..b2321a209 100644
--- a/src/asmjs/shared-constants.cpp
+++ b/src/asmjs/shared-constants.cpp
@@ -47,35 +47,9 @@ cashew::IString GLOBAL("global"),
SQRT("sqrt"),
I32_TEMP("asm2wasm_i32_temp"),
DEBUGGER("debugger"),
- GROW_WASM_MEMORY("__growWasmMemory"),
- NEW_SIZE("newSize"),
- MODULE("module"),
- START("start"),
- FUNC("func"),
- PARAM("param"),
- RESULT("result"),
- MEMORY("memory"),
- SEGMENT("segment"),
- EXPORT("export"),
- IMPORT("import"),
- TABLE("table"),
- LOCAL("local"),
- TYPE("type"),
- CALL("call"),
- CALL_IMPORT("call_import"),
- CALL_INDIRECT("call_indirect"),
- BLOCK("block"),
- BR_IF("br_if"),
- THEN("then"),
- ELSE("else"),
- NEG_INFINITY("-infinity"),
- NEG_NAN("-nan"),
- CASE("case"),
- BR("br"),
USE_ASM("use asm"),
BUFFER("buffer"),
ENV("env"),
- FAKE_RETURN("fake_return_waka123"),
MATH_IMUL("Math_imul"),
MATH_CLZ32("Math_clz32"),
MATH_CTZ32("Math_ctz32"),
@@ -87,13 +61,6 @@ cashew::IString GLOBAL("global"),
MATH_NEAREST("Math_NEAREST"),
MATH_SQRT("Math_sqrt"),
MATH_MIN("Math_max"),
- MATH_MAX("Math_min"),
- ASSERT_RETURN("assert_return"),
- ASSERT_TRAP("assert_trap"),
- ASSERT_INVALID("assert_invalid"),
- SPECTEST("spectest"),
- PRINT("print"),
- INVOKE("invoke"),
- EXIT("exit");
+ MATH_MAX("Math_min");
}
diff --git a/src/asmjs/shared-constants.h b/src/asmjs/shared-constants.h
index 2f6c608ba..fb32340ab 100644
--- a/src/asmjs/shared-constants.h
+++ b/src/asmjs/shared-constants.h
@@ -50,35 +50,9 @@ extern cashew::IString GLOBAL,
SQRT,
I32_TEMP,
DEBUGGER,
- GROW_WASM_MEMORY,
- NEW_SIZE,
- MODULE,
- START,
- FUNC,
- PARAM,
- RESULT,
- MEMORY,
- SEGMENT,
- EXPORT,
- IMPORT,
- TABLE,
- LOCAL,
- TYPE,
- CALL,
- CALL_IMPORT,
- CALL_INDIRECT,
- BLOCK,
- BR_IF,
- THEN,
- ELSE,
- NEG_INFINITY,
- NEG_NAN,
- CASE,
- BR,
USE_ASM,
BUFFER,
ENV,
- FAKE_RETURN,
MATH_IMUL,
MATH_CLZ32,
MATH_CTZ32,
@@ -90,14 +64,7 @@ extern cashew::IString GLOBAL,
MATH_NEAREST,
MATH_SQRT,
MATH_MIN,
- MATH_MAX,
- ASSERT_RETURN,
- ASSERT_TRAP,
- ASSERT_INVALID,
- SPECTEST,
- PRINT,
- INVOKE,
- EXIT;
+ MATH_MAX;
}
diff --git a/src/ast_utils.h b/src/ast_utils.h
index 8952114bc..77bfaf1f3 100644
--- a/src/ast_utils.h
+++ b/src/ast_utils.h
@@ -20,6 +20,7 @@
#include "support/hash.h"
#include "wasm.h"
#include "wasm-traversal.h"
+#include "wasm-builder.h"
namespace wasm {
@@ -210,6 +211,117 @@ struct ExpressionManipulator {
new (output) OutputType(allocator);
return output;
}
+
+ template<typename T>
+ static Expression* flexibleCopy(Expression* original, Module& wasm, T& custom) {
+ struct Copier : public Visitor<Copier, Expression*> {
+ Module& wasm;
+ T& custom;
+
+ Builder builder;
+
+ Copier(Module& wasm, T& custom) : wasm(wasm), custom(custom), builder(wasm) {}
+
+ Expression* copy(Expression* curr) {
+ if (!curr) return nullptr;
+ auto* ret = custom.copy(curr);
+ if (ret) return ret;
+ return Visitor<Copier, Expression*>::visit(curr);
+ }
+
+ Expression* visitBlock(Block *curr) {
+ auto* ret = builder.makeBlock();
+ for (Index i = 0; i < curr->list.size(); i++) {
+ ret->list.push_back(copy(curr->list[i]));
+ }
+ ret->name = curr->name;
+ ret->finalize(curr->type);
+ return ret;
+ }
+ Expression* visitIf(If *curr) {
+ return builder.makeIf(copy(curr->condition), copy(curr->ifTrue), copy(curr->ifFalse));
+ }
+ Expression* visitLoop(Loop *curr) {
+ return builder.makeLoop(curr->out, curr->in, copy(curr->body));
+ }
+ 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* 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* visitCallImport(CallImport *curr) {
+ auto* ret = builder.makeCallImport(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, 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) {
+ return builder.makeGetLocal(curr->index, curr->type);
+ }
+ Expression* visitSetLocal(SetLocal *curr) {
+ return builder.makeSetLocal(curr->index, copy(curr->value));
+ }
+ Expression* visitLoad(Load *curr) {
+ return builder.makeLoad(curr->bytes, curr->signed_, curr->offset, curr->align, copy(curr->ptr), curr->type);
+ }
+ Expression* visitStore(Store *curr) {
+ return builder.makeStore(curr->bytes, curr->offset, curr->align, copy(curr->ptr), copy(curr->value));
+ }
+ Expression* visitConst(Const *curr) {
+ return builder.makeConst(curr->value);
+ }
+ Expression* visitUnary(Unary *curr) {
+ return builder.makeUnary(curr->op, copy(curr->value));
+ }
+ 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* visitReturn(Return *curr) {
+ return builder.makeReturn(copy(curr->value));
+ }
+ Expression* visitHost(Host *curr) {
+ assert(curr->operands.size() == 0);
+ return builder.makeHost(curr->op, curr->nameOperand, {});
+ }
+ Expression* visitNop(Nop *curr) {
+ return builder.makeNop();
+ }
+ Expression* visitUnreachable(Unreachable *curr) {
+ return builder.makeUnreachable();
+ }
+ };
+
+ Copier copier(wasm, custom);
+ return copier.copy(original);
+ }
+
+ static Expression* copy(Expression* original, Module& wasm) {
+ struct Copier {
+ Expression* copy(Expression* curr) {
+ return nullptr;
+ }
+ } copier;
+ return flexibleCopy(original, wasm, copier);
+ }
};
struct ExpressionAnalyzer {
@@ -242,7 +354,8 @@ struct ExpressionAnalyzer {
return func->result != none;
}
- static bool equal(Expression* left, Expression* right) {
+ template<typename T>
+ static bool flexibleEqual(Expression* left, Expression* right, T& comparer) {
std::vector<Name> nameStack;
std::map<Name, std::vector<Name>> rightNames; // for each name on the left, the stack of names on the right (a stack, since names are scoped and can nest duplicatively
Nop popNameMarker;
@@ -284,6 +397,8 @@ struct ExpressionAnalyzer {
popName();
continue;
}
+ if (comparer.compare(left, right)) continue; // comparison hook, before all the rest
+ // continue with normal structural comparison
if (left->_id != right->_id) return false;
#define PUSH(clazz, what) \
leftStack.push_back(left->cast<clazz>()->what); \
@@ -426,6 +541,15 @@ struct ExpressionAnalyzer {
return true;
}
+ static bool equal(Expression* left, Expression* right) {
+ struct Comparer {
+ bool compare(Expression* left, Expression* right) {
+ return false;
+ }
+ } comparer;
+ return flexibleEqual(left, right, comparer);
+ }
+
// hash an expression, ignoring superficial details like specific internal names
static uint32_t hash(Expression* curr) {
uint32_t digest = 0;
diff --git a/src/parsing.h b/src/parsing.h
index 6745ad7cd..f5df77bad 100644
--- a/src/parsing.h
+++ b/src/parsing.h
@@ -21,6 +21,7 @@
#include <sstream>
#include <string>
+#include "shared-constants.h"
#include "asmjs/shared-constants.h"
#include "mixed_arena.h"
#include "support/utilities.h"
@@ -34,7 +35,7 @@ inline Expression* parseConst(cashew::IString s, WasmType type, MixedArena& allo
auto ret = allocator.alloc<Const>();
ret->type = type;
if (isWasmTypeFloat(type)) {
- if (s == INFINITY_) {
+ 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;
@@ -52,7 +53,7 @@ inline Expression* parseConst(cashew::IString s, WasmType type, MixedArena& allo
//std::cerr << "make constant " << str << " ==> " << ret->value << '\n';
return ret;
}
- if (s == NAN_) {
+ if (s == _NAN) {
switch (type) {
case f32: ret->value = Literal(float(std::nan(""))); break;
case f64: ret->value = Literal(double(std::nan(""))); break;
diff --git a/src/passes/OptimizeInstructions.cpp b/src/passes/OptimizeInstructions.cpp
index efa9409a7..9fa059327 100644
--- a/src/passes/OptimizeInstructions.cpp
+++ b/src/passes/OptimizeInstructions.cpp
@@ -22,66 +22,152 @@
#include <wasm.h>
#include <pass.h>
+#include <wasm-s-parser.h>
namespace wasm {
-struct OptimizeInstructions : public WalkerPass<PostWalker<OptimizeInstructions, Visitor<OptimizeInstructions>>> {
- bool isFunctionParallel() override { return true; }
+Name I32_EXPR = "i32.expr",
+ I64_EXPR = "i64.expr",
+ F32_EXPR = "f32.expr",
+ F64_EXPR = "f64.expr",
+ ANY_EXPR = "any.expr";
- Pass* create() override { return new OptimizeInstructions; }
+// A pattern
+struct Pattern {
+ Expression* input;
+ Expression* output;
+
+ Pattern(Expression* input, Expression* output) : input(input), output(output) {}
+};
+
+// Database of patterns
+struct PatternDatabase {
+ Module wasm;
+
+ char* input;
+
+ std::map<Expression::Id, std::vector<Pattern>> patternMap; // root expression id => list of all patterns for it TODO optimize more
+
+ PatternDatabase() {
+ // TODO: do this on first use, with a lock, to avoid startup pause
+ // generate module
+ input = strdup(
+ #include "OptimizeInstructions.wast.processed"
+ );
+ SExpressionParser parser(input);
+ Element& root = *parser.root;
+ SExpressionWasmBuilder builder(wasm, *root[0]);
+ // parse module form
+ auto* func = wasm.getFunction("patterns");
+ auto* body = func->body->cast<Block>();
+ for (auto* item : body->list) {
+ auto* pair = item->cast<Block>();
+ patternMap[pair->list[0]->_id].emplace_back(pair->list[0], pair->list[1]);
+ }
+ }
+
+ ~PatternDatabase() {
+ free(input);
+ };
+};
+
+static PatternDatabase database;
+
+// Check for matches and apply them
+struct Match {
+ Module& wasm;
+ Pattern& pattern;
+
+ Match(Module& wasm, Pattern& pattern) : wasm(wasm), pattern(pattern) {}
+
+ std::vector<Expression*> wildcards; // id in i32.any(id) etc. => the expression it represents in this match
- void visitIf(If* curr) {
- // flip branches to get rid of an i32.eqz
- if (curr->ifFalse) {
- auto condition = curr->condition->dynCast<Unary>();
- if (condition && condition->op == EqZInt32 && condition->value->type == i32) {
- curr->condition = condition->value;
- std::swap(curr->ifTrue, curr->ifFalse);
+ // Comparing/checking
+
+ // Check if we can match to this pattern, updating ourselves with the info if so
+ bool check(Expression* seen) {
+ // compare seen to the pattern input, doing a special operation for our "wildcards"
+ assert(wildcards.size() == 0);
+ return ExpressionAnalyzer::flexibleEqual(pattern.input, seen, *this);
+ }
+
+ bool compare(Expression* subInput, Expression* subSeen) {
+ CallImport* call = subInput->dynCast<CallImport>();
+ if (!call || call->operands.size() != 1 || call->operands[0]->type != i32 || !call->operands[0]->is<Const>()) return false;
+ Index index = call->operands[0]->cast<Const>()->value.geti32();
+ // handle our special functions
+ auto checkMatch = [&](WasmType type) {
+ if (type != none && subSeen->type != type) return false;
+ while (index >= wildcards.size()) {
+ wildcards.push_back(nullptr);
}
+ if (!wildcards[index]) {
+ // new wildcard
+ wildcards[index] = subSeen; // NB: no need to copy
+ return true;
+ } else {
+ // We are seeing this index for a second or later time, check it matches
+ return ExpressionAnalyzer::equal(subSeen, wildcards[index]);
+ };
+ };
+ if (call->target == I32_EXPR) {
+ if (checkMatch(i32)) return true;
+ } else if (call->target == I64_EXPR) {
+ if (checkMatch(i64)) return true;
+ } else if (call->target == F32_EXPR) {
+ if (checkMatch(f32)) return true;
+ } else if (call->target == F64_EXPR) {
+ if (checkMatch(f64)) return true;
+ } else if (call->target == ANY_EXPR) {
+ if (checkMatch(none)) return true;
}
+ return false;
+ }
+
+ // Applying/copying
+
+ // Apply the match, generate an output expression from the matched input, performing substitutions as necessary
+ Expression* apply() {
+ return ExpressionManipulator::flexibleCopy(pattern.output, wasm, *this);
}
- void visitUnary(Unary* curr) {
- if (curr->op == EqZInt32) {
- // fold comparisons that flow into an EqZ
- auto* child = curr->value->dynCast<Binary>();
- if (child && (child->type == i32 || child->type == i64)) {
- switch (child->op) {
- case EqInt32: child->op = NeInt32; break;
- case NeInt32: child->op = EqInt32; break;
- case LtSInt32: child->op = GeSInt32; break;
- case LtUInt32: child->op = GeUInt32; break;
- case LeSInt32: child->op = GtSInt32; break;
- case LeUInt32: child->op = GtUInt32; break;
- case GtSInt32: child->op = LeSInt32; break;
- case GtUInt32: child->op = LeUInt32; break;
- case GeSInt32: child->op = LtSInt32; break;
- case GeUInt32: child->op = LtUInt32; break;
- case EqInt64: child->op = NeInt64; break;
- case NeInt64: child->op = EqInt64; break;
- case LtSInt64: child->op = GeSInt64; break;
- case LtUInt64: child->op = GeUInt64; break;
- case LeSInt64: child->op = GtSInt64; break;
- case LeUInt64: child->op = GtUInt64; break;
- case GtSInt64: child->op = LeSInt64; break;
- case GtUInt64: child->op = LeUInt64; break;
- case GeSInt64: child->op = LtSInt64; break;
- case GeUInt64: child->op = LtUInt64; break;
- case EqFloat32: child->op = NeFloat32; break;
- case NeFloat32: child->op = EqFloat32; break;
- case LtFloat32: child->op = GeFloat32; break;
- case LeFloat32: child->op = GtFloat32; break;
- case GtFloat32: child->op = LeFloat32; break;
- case GeFloat32: child->op = LtFloat32; break;
- case EqFloat64: child->op = NeFloat64; break;
- case NeFloat64: child->op = EqFloat64; break;
- case LtFloat64: child->op = GeFloat64; break;
- case LeFloat64: child->op = GtFloat64; break;
- case GtFloat64: child->op = LeFloat64; break;
- case GeFloat64: child->op = LtFloat64; break;
- default: return;
+
+ // When copying a wildcard, perform the substitution.
+ // TODO: we can reuse nodes, not copying a wildcard when it appears just once, and we can reuse other individual nodes when they are discarded anyhow.
+ Expression* copy(Expression* curr) {
+ CallImport* call = curr->dynCast<CallImport>();
+ if (!call || call->operands.size() != 1 || call->operands[0]->type != i32 || !call->operands[0]->is<Const>()) return nullptr;
+ Index index = call->operands[0]->cast<Const>()->value.geti32();
+ // handle our special functions
+ if (call->target == I32_EXPR || call->target == I64_EXPR || call->target == F32_EXPR || call->target == F64_EXPR || call->target == ANY_EXPR) {
+ return ExpressionManipulator::copy(wildcards.at(index), wasm);
+ }
+ return nullptr;
+ }
+};
+
+// Main pass class
+struct OptimizeInstructions : public WalkerPass<PostWalker<OptimizeInstructions, UnifiedExpressionVisitor<OptimizeInstructions>>> {
+ bool isFunctionParallel() override { return true; }
+
+ Pass* create() override { return new 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
+ while (1) {
+ auto iter = database.patternMap.find(curr->_id);
+ if (iter == database.patternMap.end()) return;
+ auto& patterns = iter->second;
+ bool more = false;
+ for (auto& pattern : patterns) {
+ Match match(*getModule(), pattern);
+ if (match.check(curr)) {
+ curr = match.apply();
+ replaceCurrent(curr);
+ more = true;
+ break; // exit pattern for loop, return to main while loop
}
- replaceCurrent(child);
}
+ if (!more) break;
}
}
};
diff --git a/src/passes/OptimizeInstructions.wast b/src/passes/OptimizeInstructions.wast
new file mode 100644
index 000000000..83459ad14
--- /dev/null
+++ b/src/passes/OptimizeInstructions.wast
@@ -0,0 +1,152 @@
+
+;; This file contains patterns for OptimizeInstructions. Basically, we use a DSL for the patterns,
+;; and the DSL is just wasm itself, plus some functions with special meanings
+;;
+;; This file is converted into OptimizeInstructions.wast.processed by
+;; scripts/process_optimize_instructions.py
+;; which makes it importable by C++. Then we just #include it there, avoiding the need to ship
+;; a data file on the side.
+
+(module
+ ;; "expr" represents an arbitrary expression. The input is an id, so the same expression
+ ;; can appear more than once. The type (i32 in i32.expr, etc.) is the return type, as this
+ ;; needs to have the right type for where it is placed.
+ (import $i32.expr "dsl" "i32.expr" (param i32) (result i32))
+ (import $i64.expr "dsl" "i64.expr" (param i32) (result i64))
+ (import $f32.expr "dsl" "f32.expr" (param i32) (result f32))
+ (import $f64.expr "dsl" "f64.expr" (param i32) (result f64))
+ (import $any.expr "dsl" "any.expr" (param i32) (result i32)) ;; ignorable return type
+
+ ;; main function. each block here is a pattern pair of input => output
+ (func $patterns
+ (block
+ ;; flip if-else arms to get rid of an eqz
+ (if
+ (i32.eqz
+ (call_import $i32.expr (i32.const 0))
+ )
+ (call_import $any.expr (i32.const 1))
+ (call_import $any.expr (i32.const 2))
+ )
+ (if
+ (call_import $i32.expr (i32.const 0))
+ (call_import $any.expr (i32.const 2))
+ (call_import $any.expr (i32.const 1))
+ )
+ )
+ ;; De Morgans Laws
+ (block
+ (i32.eqz (i32.eq (call_import $i32.expr (i32.const 0)) (call_import $i32.expr (i32.const 1))))
+ (i32.ne (call_import $i32.expr (i32.const 0)) (call_import $i32.expr (i32.const 1)))
+ )
+ (block
+ (i32.eqz (i32.ne (call_import $i32.expr (i32.const 0)) (call_import $i32.expr (i32.const 1))))
+ (i32.eq (call_import $i32.expr (i32.const 0)) (call_import $i32.expr (i32.const 1)))
+ )
+ (block
+ (i32.eqz (i32.lt_s (call_import $i32.expr (i32.const 0)) (call_import $i32.expr (i32.const 1))))
+ (i32.ge_s (call_import $i32.expr (i32.const 0)) (call_import $i32.expr (i32.const 1)))
+ )
+ (block
+ (i32.eqz (i32.lt_u (call_import $i32.expr (i32.const 0)) (call_import $i32.expr (i32.const 1))))
+ (i32.ge_u (call_import $i32.expr (i32.const 0)) (call_import $i32.expr (i32.const 1)))
+ )
+ (block
+ (i32.eqz (i32.le_s (call_import $i32.expr (i32.const 0)) (call_import $i32.expr (i32.const 1))))
+ (i32.gt_s (call_import $i32.expr (i32.const 0)) (call_import $i32.expr (i32.const 1)))
+ )
+ (block
+ (i32.eqz (i32.le_u (call_import $i32.expr (i32.const 0)) (call_import $i32.expr (i32.const 1))))
+ (i32.gt_u (call_import $i32.expr (i32.const 0)) (call_import $i32.expr (i32.const 1)))
+ )
+ (block
+ (i32.eqz (i32.gt_s (call_import $i32.expr (i32.const 0)) (call_import $i32.expr (i32.const 1))))
+ (i32.le_s (call_import $i32.expr (i32.const 0)) (call_import $i32.expr (i32.const 1)))
+ )
+ (block
+ (i32.eqz (i32.gt_u (call_import $i32.expr (i32.const 0)) (call_import $i32.expr (i32.const 1))))
+ (i32.le_u (call_import $i32.expr (i32.const 0)) (call_import $i32.expr (i32.const 1)))
+ )
+ (block
+ (i32.eqz (i32.ge_s (call_import $i32.expr (i32.const 0)) (call_import $i32.expr (i32.const 1))))
+ (i32.lt_s (call_import $i32.expr (i32.const 0)) (call_import $i32.expr (i32.const 1)))
+ )
+ (block
+ (i32.eqz (i32.ge_u (call_import $i32.expr (i32.const 0)) (call_import $i32.expr (i32.const 1))))
+ (i32.lt_u (call_import $i32.expr (i32.const 0)) (call_import $i32.expr (i32.const 1)))
+ )
+ (block
+ (i32.eqz (i64.eq (call_import $i64.expr (i32.const 0)) (call_import $i64.expr (i32.const 1))))
+ (i64.ne (call_import $i64.expr (i32.const 0)) (call_import $i64.expr (i32.const 1)))
+ )
+ (block
+ (i32.eqz (i64.ne (call_import $i64.expr (i32.const 0)) (call_import $i64.expr (i32.const 1))))
+ (i64.eq (call_import $i64.expr (i32.const 0)) (call_import $i64.expr (i32.const 1)))
+ )
+ (block
+ (i32.eqz (i64.lt_s (call_import $i64.expr (i32.const 0)) (call_import $i64.expr (i32.const 1))))
+ (i64.ge_s (call_import $i64.expr (i32.const 0)) (call_import $i64.expr (i32.const 1)))
+ )
+ (block
+ (i32.eqz (i64.lt_u (call_import $i64.expr (i32.const 0)) (call_import $i64.expr (i32.const 1))))
+ (i64.ge_u (call_import $i64.expr (i32.const 0)) (call_import $i64.expr (i32.const 1)))
+ )
+ (block
+ (i32.eqz (i64.le_s (call_import $i64.expr (i32.const 0)) (call_import $i64.expr (i32.const 1))))
+ (i64.gt_s (call_import $i64.expr (i32.const 0)) (call_import $i64.expr (i32.const 1)))
+ )
+ (block
+ (i32.eqz (i64.le_u (call_import $i64.expr (i32.const 0)) (call_import $i64.expr (i32.const 1))))
+ (i64.gt_u (call_import $i64.expr (i32.const 0)) (call_import $i64.expr (i32.const 1)))
+ )
+ (block
+ (i32.eqz (i64.gt_s (call_import $i64.expr (i32.const 0)) (call_import $i64.expr (i32.const 1))))
+ (i64.le_s (call_import $i64.expr (i32.const 0)) (call_import $i64.expr (i32.const 1)))
+ )
+ (block
+ (i32.eqz (i64.gt_u (call_import $i64.expr (i32.const 0)) (call_import $i64.expr (i32.const 1))))
+ (i64.le_u (call_import $i64.expr (i32.const 0)) (call_import $i64.expr (i32.const 1)))
+ )
+ (block
+ (i32.eqz (i64.ge_s (call_import $i64.expr (i32.const 0)) (call_import $i64.expr (i32.const 1))))
+ (i64.lt_s (call_import $i64.expr (i32.const 0)) (call_import $i64.expr (i32.const 1)))
+ )
+ (block
+ (i32.eqz (i64.ge_u (call_import $i64.expr (i32.const 0)) (call_import $i64.expr (i32.const 1))))
+ (i64.lt_u (call_import $i64.expr (i32.const 0)) (call_import $i64.expr (i32.const 1)))
+ )
+ (block
+ (i32.eqz (f32.eq (call_import $f32.expr (i32.const 0)) (call_import $f32.expr (i32.const 1))))
+ (f32.ne (call_import $f32.expr (i32.const 0)) (call_import $f32.expr (i32.const 1)))
+ )
+ (block
+ (i32.eqz (f32.ne (call_import $f32.expr (i32.const 0)) (call_import $f32.expr (i32.const 1))))
+ (f32.eq (call_import $f32.expr (i32.const 0)) (call_import $f32.expr (i32.const 1)))
+ )
+ (block
+ (i32.eqz (f32.lt (call_import $f32.expr (i32.const 0)) (call_import $f32.expr (i32.const 1))))
+ (f32.ge (call_import $f32.expr (i32.const 0)) (call_import $f32.expr (i32.const 1)))
+ )
+ (block
+ (i32.eqz (f32.le (call_import $f32.expr (i32.const 0)) (call_import $f32.expr (i32.const 1))))
+ (f32.gt (call_import $f32.expr (i32.const 0)) (call_import $f32.expr (i32.const 1)))
+ )
+ (block
+ (i32.eqz (f64.eq (call_import $f64.expr (i32.const 0)) (call_import $f64.expr (i32.const 1))))
+ (f64.ne (call_import $f64.expr (i32.const 0)) (call_import $f64.expr (i32.const 1)))
+ )
+ (block
+ (i32.eqz (f64.ne (call_import $f64.expr (i32.const 0)) (call_import $f64.expr (i32.const 1))))
+ (f64.eq (call_import $f64.expr (i32.const 0)) (call_import $f64.expr (i32.const 1)))
+ )
+ (block
+ (i32.eqz (f64.lt (call_import $f64.expr (i32.const 0)) (call_import $f64.expr (i32.const 1))))
+ (f64.ge (call_import $f64.expr (i32.const 0)) (call_import $f64.expr (i32.const 1)))
+ )
+ (block
+ (i32.eqz (f64.le (call_import $f64.expr (i32.const 0)) (call_import $f64.expr (i32.const 1))))
+ (f64.gt (call_import $f64.expr (i32.const 0)) (call_import $f64.expr (i32.const 1)))
+ )
+ )
+)
+
diff --git a/src/passes/OptimizeInstructions.wast.processed b/src/passes/OptimizeInstructions.wast.processed
new file mode 100644
index 000000000..6bd251c95
--- /dev/null
+++ b/src/passes/OptimizeInstructions.wast.processed
@@ -0,0 +1,152 @@
+"\n"
+";; This file contains patterns for OptimizeInstructions. Basically, we use a DSL for the patterns,\n"
+";; and the DSL is just wasm itself, plus some functions with special meanings\n"
+";;\n"
+";; This file is converted into OptimizeInstructions.wast.processed by\n"
+";; scripts/process_optimize_instructions.py\n"
+";; which makes it importable by C++. Then we just #include it there, avoiding the need to ship\n"
+";; a data file on the side.\n"
+"\n"
+"(module\n"
+";; \"expr\" represents an arbitrary expression. The input is an id, so the same expression\n"
+";; can appear more than once. The type (i32 in i32.expr, etc.) is the return type, as this\n"
+";; needs to have the right type for where it is placed.\n"
+"(import $i32.expr \"dsl\" \"i32.expr\" (param i32) (result i32))\n"
+"(import $i64.expr \"dsl\" \"i64.expr\" (param i32) (result i64))\n"
+"(import $f32.expr \"dsl\" \"f32.expr\" (param i32) (result f32))\n"
+"(import $f64.expr \"dsl\" \"f64.expr\" (param i32) (result f64))\n"
+"(import $any.expr \"dsl\" \"any.expr\" (param i32) (result i32)) ;; ignorable return type\n"
+"\n"
+";; main function. each block here is a pattern pair of input => output\n"
+"(func $patterns\n"
+"(block\n"
+";; flip if-else arms to get rid of an eqz\n"
+"(if\n"
+"(i32.eqz\n"
+"(call_import $i32.expr (i32.const 0))\n"
+")\n"
+"(call_import $any.expr (i32.const 1))\n"
+"(call_import $any.expr (i32.const 2))\n"
+")\n"
+"(if\n"
+"(call_import $i32.expr (i32.const 0))\n"
+"(call_import $any.expr (i32.const 2))\n"
+"(call_import $any.expr (i32.const 1))\n"
+")\n"
+")\n"
+";; De Morgans Laws\n"
+"(block\n"
+"(i32.eqz (i32.eq (call_import $i32.expr (i32.const 0)) (call_import $i32.expr (i32.const 1))))\n"
+"(i32.ne (call_import $i32.expr (i32.const 0)) (call_import $i32.expr (i32.const 1)))\n"
+")\n"
+"(block\n"
+"(i32.eqz (i32.ne (call_import $i32.expr (i32.const 0)) (call_import $i32.expr (i32.const 1))))\n"
+"(i32.eq (call_import $i32.expr (i32.const 0)) (call_import $i32.expr (i32.const 1)))\n"
+")\n"
+"(block\n"
+"(i32.eqz (i32.lt_s (call_import $i32.expr (i32.const 0)) (call_import $i32.expr (i32.const 1))))\n"
+"(i32.ge_s (call_import $i32.expr (i32.const 0)) (call_import $i32.expr (i32.const 1)))\n"
+")\n"
+"(block\n"
+"(i32.eqz (i32.lt_u (call_import $i32.expr (i32.const 0)) (call_import $i32.expr (i32.const 1))))\n"
+"(i32.ge_u (call_import $i32.expr (i32.const 0)) (call_import $i32.expr (i32.const 1)))\n"
+")\n"
+"(block\n"
+"(i32.eqz (i32.le_s (call_import $i32.expr (i32.const 0)) (call_import $i32.expr (i32.const 1))))\n"
+"(i32.gt_s (call_import $i32.expr (i32.const 0)) (call_import $i32.expr (i32.const 1)))\n"
+")\n"
+"(block\n"
+"(i32.eqz (i32.le_u (call_import $i32.expr (i32.const 0)) (call_import $i32.expr (i32.const 1))))\n"
+"(i32.gt_u (call_import $i32.expr (i32.const 0)) (call_import $i32.expr (i32.const 1)))\n"
+")\n"
+"(block\n"
+"(i32.eqz (i32.gt_s (call_import $i32.expr (i32.const 0)) (call_import $i32.expr (i32.const 1))))\n"
+"(i32.le_s (call_import $i32.expr (i32.const 0)) (call_import $i32.expr (i32.const 1)))\n"
+")\n"
+"(block\n"
+"(i32.eqz (i32.gt_u (call_import $i32.expr (i32.const 0)) (call_import $i32.expr (i32.const 1))))\n"
+"(i32.le_u (call_import $i32.expr (i32.const 0)) (call_import $i32.expr (i32.const 1)))\n"
+")\n"
+"(block\n"
+"(i32.eqz (i32.ge_s (call_import $i32.expr (i32.const 0)) (call_import $i32.expr (i32.const 1))))\n"
+"(i32.lt_s (call_import $i32.expr (i32.const 0)) (call_import $i32.expr (i32.const 1)))\n"
+")\n"
+"(block\n"
+"(i32.eqz (i32.ge_u (call_import $i32.expr (i32.const 0)) (call_import $i32.expr (i32.const 1))))\n"
+"(i32.lt_u (call_import $i32.expr (i32.const 0)) (call_import $i32.expr (i32.const 1)))\n"
+")\n"
+"(block\n"
+"(i32.eqz (i64.eq (call_import $i64.expr (i32.const 0)) (call_import $i64.expr (i32.const 1))))\n"
+"(i64.ne (call_import $i64.expr (i32.const 0)) (call_import $i64.expr (i32.const 1)))\n"
+")\n"
+"(block\n"
+"(i32.eqz (i64.ne (call_import $i64.expr (i32.const 0)) (call_import $i64.expr (i32.const 1))))\n"
+"(i64.eq (call_import $i64.expr (i32.const 0)) (call_import $i64.expr (i32.const 1)))\n"
+")\n"
+"(block\n"
+"(i32.eqz (i64.lt_s (call_import $i64.expr (i32.const 0)) (call_import $i64.expr (i32.const 1))))\n"
+"(i64.ge_s (call_import $i64.expr (i32.const 0)) (call_import $i64.expr (i32.const 1)))\n"
+")\n"
+"(block\n"
+"(i32.eqz (i64.lt_u (call_import $i64.expr (i32.const 0)) (call_import $i64.expr (i32.const 1))))\n"
+"(i64.ge_u (call_import $i64.expr (i32.const 0)) (call_import $i64.expr (i32.const 1)))\n"
+")\n"
+"(block\n"
+"(i32.eqz (i64.le_s (call_import $i64.expr (i32.const 0)) (call_import $i64.expr (i32.const 1))))\n"
+"(i64.gt_s (call_import $i64.expr (i32.const 0)) (call_import $i64.expr (i32.const 1)))\n"
+")\n"
+"(block\n"
+"(i32.eqz (i64.le_u (call_import $i64.expr (i32.const 0)) (call_import $i64.expr (i32.const 1))))\n"
+"(i64.gt_u (call_import $i64.expr (i32.const 0)) (call_import $i64.expr (i32.const 1)))\n"
+")\n"
+"(block\n"
+"(i32.eqz (i64.gt_s (call_import $i64.expr (i32.const 0)) (call_import $i64.expr (i32.const 1))))\n"
+"(i64.le_s (call_import $i64.expr (i32.const 0)) (call_import $i64.expr (i32.const 1)))\n"
+")\n"
+"(block\n"
+"(i32.eqz (i64.gt_u (call_import $i64.expr (i32.const 0)) (call_import $i64.expr (i32.const 1))))\n"
+"(i64.le_u (call_import $i64.expr (i32.const 0)) (call_import $i64.expr (i32.const 1)))\n"
+")\n"
+"(block\n"
+"(i32.eqz (i64.ge_s (call_import $i64.expr (i32.const 0)) (call_import $i64.expr (i32.const 1))))\n"
+"(i64.lt_s (call_import $i64.expr (i32.const 0)) (call_import $i64.expr (i32.const 1)))\n"
+")\n"
+"(block\n"
+"(i32.eqz (i64.ge_u (call_import $i64.expr (i32.const 0)) (call_import $i64.expr (i32.const 1))))\n"
+"(i64.lt_u (call_import $i64.expr (i32.const 0)) (call_import $i64.expr (i32.const 1)))\n"
+")\n"
+"(block\n"
+"(i32.eqz (f32.eq (call_import $f32.expr (i32.const 0)) (call_import $f32.expr (i32.const 1))))\n"
+"(f32.ne (call_import $f32.expr (i32.const 0)) (call_import $f32.expr (i32.const 1)))\n"
+")\n"
+"(block\n"
+"(i32.eqz (f32.ne (call_import $f32.expr (i32.const 0)) (call_import $f32.expr (i32.const 1))))\n"
+"(f32.eq (call_import $f32.expr (i32.const 0)) (call_import $f32.expr (i32.const 1)))\n"
+")\n"
+"(block\n"
+"(i32.eqz (f32.lt (call_import $f32.expr (i32.const 0)) (call_import $f32.expr (i32.const 1))))\n"
+"(f32.ge (call_import $f32.expr (i32.const 0)) (call_import $f32.expr (i32.const 1)))\n"
+")\n"
+"(block\n"
+"(i32.eqz (f32.le (call_import $f32.expr (i32.const 0)) (call_import $f32.expr (i32.const 1))))\n"
+"(f32.gt (call_import $f32.expr (i32.const 0)) (call_import $f32.expr (i32.const 1)))\n"
+")\n"
+"(block\n"
+"(i32.eqz (f64.eq (call_import $f64.expr (i32.const 0)) (call_import $f64.expr (i32.const 1))))\n"
+"(f64.ne (call_import $f64.expr (i32.const 0)) (call_import $f64.expr (i32.const 1)))\n"
+")\n"
+"(block\n"
+"(i32.eqz (f64.ne (call_import $f64.expr (i32.const 0)) (call_import $f64.expr (i32.const 1))))\n"
+"(f64.eq (call_import $f64.expr (i32.const 0)) (call_import $f64.expr (i32.const 1)))\n"
+")\n"
+"(block\n"
+"(i32.eqz (f64.lt (call_import $f64.expr (i32.const 0)) (call_import $f64.expr (i32.const 1))))\n"
+"(f64.ge (call_import $f64.expr (i32.const 0)) (call_import $f64.expr (i32.const 1)))\n"
+")\n"
+"(block\n"
+"(i32.eqz (f64.le (call_import $f64.expr (i32.const 0)) (call_import $f64.expr (i32.const 1))))\n"
+"(f64.gt (call_import $f64.expr (i32.const 0)) (call_import $f64.expr (i32.const 1)))\n"
+")\n"
+")\n"
+")\n"
+"\n"
diff --git a/src/shared-constants.h b/src/shared-constants.h
new file mode 100644
index 000000000..fb94ff11b
--- /dev/null
+++ b/src/shared-constants.h
@@ -0,0 +1,56 @@
+/*
+ * Copyright 2016 WebAssembly Community Group participants
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+namespace wasm {
+
+extern Name GROW_WASM_MEMORY,
+ NEW_SIZE,
+ MODULE,
+ START,
+ FUNC,
+ PARAM,
+ RESULT,
+ MEMORY,
+ SEGMENT,
+ EXPORT,
+ IMPORT,
+ TABLE,
+ LOCAL,
+ TYPE,
+ CALL,
+ CALL_IMPORT,
+ CALL_INDIRECT,
+ BLOCK,
+ BR_IF,
+ THEN,
+ ELSE,
+ _NAN,
+ _INFINITY,
+ NEG_INFINITY,
+ NEG_NAN,
+ CASE,
+ BR,
+ FAKE_RETURN,
+ ASSERT_RETURN,
+ ASSERT_TRAP,
+ ASSERT_INVALID,
+ SPECTEST,
+ PRINT,
+ INVOKE,
+ EXIT;
+
+} // namespace wasm
+
diff --git a/src/shell-interface.h b/src/shell-interface.h
index 62fc2432a..f6c12e8ca 100644
--- a/src/shell-interface.h
+++ b/src/shell-interface.h
@@ -21,6 +21,7 @@
#ifndef wasm_shell_interface_h
#define wasm_shell_interface_h
+#include "shared-constants.h"
#include "asmjs/shared-constants.h"
#include "wasm.h"
#include "wasm-interpreter.h"
diff --git a/src/wasm-binary.h b/src/wasm-binary.h
index 5cb56f770..a76bf7fa5 100644
--- a/src/wasm-binary.h
+++ b/src/wasm-binary.h
@@ -238,16 +238,16 @@ enum Meta {
};
namespace Section {
- auto Memory = "memory";
- auto Signatures = "type";
- auto ImportTable = "import";
- auto FunctionSignatures = "function";
- auto Functions = "code";
- auto ExportTable = "export";
- auto DataSegments = "data";
- auto FunctionTable = "table";
- auto Names = "name";
- auto Start = "start";
+ extern const char* Memory;
+ extern const char* Signatures;
+ extern const char* ImportTable;
+ extern const char* FunctionSignatures;
+ extern const char* Functions;
+ extern const char* ExportTable;
+ extern const char* DataSegments;
+ extern const char* FunctionTable;
+ extern const char* Names;
+ extern const char* Start;
};
enum FunctionEntry {
@@ -445,7 +445,7 @@ enum TypeForms {
} // namespace BinaryConsts
-int8_t binaryWasmType(WasmType type) {
+inline int8_t binaryWasmType(WasmType type) {
switch (type) {
case none: return 0;
case i32: return 1;
diff --git a/src/wasm-builder.h b/src/wasm-builder.h
index 2eb051251..501124999 100644
--- a/src/wasm-builder.h
+++ b/src/wasm-builder.h
@@ -93,13 +93,23 @@ public:
ret->finalize();
return ret;
}
- // Switch
- // CallBase
- // Call
- // Also do a version which takes a sig?
- CallImport* makeCallImport(Name target, const std::vector<Expression*>& args) {
+ template<typename T>
+ Switch* makeSwitch(T& list, Name default_, Expression* condition, Expression* value = nullptr) {
+ auto* ret = wasm.allocator.alloc<Switch>();
+ ret->targets.set(list);
+ ret->default_ = default_; ret->value = value; ret->condition = condition;
+ return ret;
+ }
+ Call* makeCall(Name target, const std::vector<Expression*>& args, WasmType type) {
+ auto* call = wasm.allocator.alloc<Call>();
+ call->type = type; // not all functions may exist yet, so type must be provided
+ call->target = target;
+ call->operands.set(args);
+ return call;
+ }
+ CallImport* makeCallImport(Name target, const std::vector<Expression*>& args, WasmType type) {
auto* call = wasm.allocator.alloc<CallImport>();
- call->type = wasm.getImport(target)->type->result;
+ call->type = type; // similar to makeCall, for consistency
call->target = target;
call->operands.set(args);
return call;
@@ -112,6 +122,14 @@ public:
call->operands.set(args);
return call;
}
+ CallIndirect* makeCallIndirect(Name fullType, Expression* target, const std::vector<Expression*>& args, WasmType type) {
+ auto* call = wasm.allocator.alloc<CallIndirect>();
+ call->fullType = fullType;
+ call->type = type;
+ call->target = target;
+ call->operands.set(args);
+ return call;
+ }
// FunctionType
GetLocal* makeGetLocal(Index index, WasmType type) {
auto* ret = wasm.allocator.alloc<GetLocal>();
@@ -126,7 +144,12 @@ public:
ret->type = value->type;
return ret;
}
- // Load
+ Load* makeLoad(unsigned bytes, bool signed_, uint32_t offset, unsigned align, Expression *ptr, WasmType type) {
+ auto* ret = wasm.allocator.alloc<Load>();
+ ret->bytes = bytes; ret->signed_ = signed_; ret->offset = offset; ret->align = align; ret->ptr = ptr;
+ ret->type = type;
+ return ret;
+ }
Store* makeStore(unsigned bytes, uint32_t offset, unsigned align, Expression *ptr, Expression *value) {
auto* ret = wasm.allocator.alloc<Store>();
ret->bytes = bytes; ret->offset = offset; ret->align = align; ret->ptr = ptr; ret->value = value;
@@ -152,7 +175,12 @@ public:
ret->finalize();
return ret;
}
- // Select
+ Select* makeSelect(Expression* condition, Expression *ifTrue, Expression *ifFalse) {
+ auto* ret = wasm.allocator.alloc<Select>();
+ ret->condition = condition; ret->ifTrue = ifTrue; ret->ifFalse = ifFalse;
+ ret->finalize();
+ return ret;
+ }
Return* makeReturn(Expression *value) {
auto* ret = wasm.allocator.alloc<Return>();
ret->value = value;
@@ -165,7 +193,9 @@ public:
ret->operands.set(operands);
return ret;
}
- // Unreachable
+ Unreachable* makeUnreachable() {
+ return wasm.allocator.alloc<Unreachable>();
+ }
// Additional utility functions for building on top of nodes
diff --git a/src/wasm-linker.cpp b/src/wasm-linker.cpp
index e89c324b4..34dbc7f9c 100644
--- a/src/wasm-linker.cpp
+++ b/src/wasm-linker.cpp
@@ -25,13 +25,6 @@
using namespace wasm;
cashew::IString EMSCRIPTEN_ASM_CONST("emscripten_asm_const");
-namespace wasm {
-// These are defined (not just declared) in shared-constants.h, so we can't just
-// include that header. TODO: Move the definitions into a cpp file.
-extern cashew::IString ENV;
-extern cashew::IString MEMORY;
-}
-
void Linker::placeStackPointer(Address stackAllocation) {
// ensure this is the first allocation
@@ -403,7 +396,7 @@ Function* Linker::getImportThunk(Name name, const FunctionType* funcType) {
for (Index i = 0; i < funcType->params.size(); ++i) {
args.push_back(wasmBuilder.makeGetLocal(i, funcType->params[i]));
}
- Expression* call = wasmBuilder.makeCallImport(name, args);
+ Expression* call = wasmBuilder.makeCallImport(name, args, funcType->result);
f->body = call;
out.wasm.addFunction(f);
return f;
diff --git a/src/wasm-s-parser.h b/src/wasm-s-parser.h
index 0893a5bba..b31b727b7 100644
--- a/src/wasm-s-parser.h
+++ b/src/wasm-s-parser.h
@@ -28,6 +28,7 @@
#include "wasm.h"
#include "wasm-binary.h"
+#include "shared-constants.h"
#include "asmjs/shared-constants.h"
#include "mixed_arena.h"
#include "parsing.h"
@@ -41,7 +42,7 @@ using namespace cashew;
// Globals
-int unhex(char c) {
+inline 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;
diff --git a/src/wasm.cpp b/src/wasm.cpp
index dd06a8d14..6732f9ca4 100644
--- a/src/wasm.cpp
+++ b/src/wasm.cpp
@@ -20,9 +20,64 @@
namespace wasm {
+// shared constants
+
Name WASM("wasm"),
RETURN_FLOW("*return:)*");
+namespace BinaryConsts {
+namespace Section {
+ const char* Memory = "memory";
+ const char* Signatures = "type";
+ const char* ImportTable = "import";
+ const char* FunctionSignatures = "function";
+ const char* Functions = "code";
+ const char* ExportTable = "export";
+ const char* DataSegments = "data";
+ const char* FunctionTable = "table";
+ const char* Names = "name";
+ const char* Start = "start";
+};
+};
+
+Name GROW_WASM_MEMORY("__growWasmMemory"),
+ NEW_SIZE("newSize"),
+ MODULE("module"),
+ START("start"),
+ FUNC("func"),
+ PARAM("param"),
+ RESULT("result"),
+ MEMORY("memory"),
+ SEGMENT("segment"),
+ EXPORT("export"),
+ IMPORT("import"),
+ TABLE("table"),
+ LOCAL("local"),
+ TYPE("type"),
+ CALL("call"),
+ CALL_IMPORT("call_import"),
+ 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"),
+ FAKE_RETURN("fake_return_waka123"),
+ ASSERT_RETURN("assert_return"),
+ ASSERT_TRAP("assert_trap"),
+ ASSERT_INVALID("assert_invalid"),
+ SPECTEST("spectest"),
+ PRINT("print"),
+ INVOKE("invoke"),
+ EXIT("exit");
+
+// core AST type checking
+
struct TypeSeeker : public PostWalker<TypeSeeker, Visitor<TypeSeeker>> {
Expression* target; // look for this one
Name targetName;