summaryrefslogtreecommitdiff
path: root/src/wasm-s-parser.h
diff options
context:
space:
mode:
Diffstat (limited to 'src/wasm-s-parser.h')
-rw-r--r--src/wasm-s-parser.h355
1 files changed, 113 insertions, 242 deletions
diff --git a/src/wasm-s-parser.h b/src/wasm-s-parser.h
index 2e01bfc5f..6061dacc5 100644
--- a/src/wasm-s-parser.h
+++ b/src/wasm-s-parser.h
@@ -5,41 +5,18 @@
//
#include <cmath>
-#include <sstream>
#include "wasm.h"
#include "mixed_arena.h"
+#include "shared-constants.h"
+#include "parsing.h"
namespace wasm {
-int debug = 0; // wasm::debug is set in main(), typically from an env var
-
using namespace cashew;
// Globals
-IString MODULE("module"),
- 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"),
- INFINITY_("infinity"),
- NEG_INFINITY("-infinity"),
- NAN_("nan"),
- NEG_NAN("-nan"),
- CASE("case"),
- BR("br"),
- FAKE_RETURN("fake_return_waka123");
-
int unhex(char c) {
if (c >= '0' && c <= '9') return c - '0';
if (c >= 'a' && c <= 'f') return c - 'a' + 10;
@@ -176,7 +153,7 @@ private:
while (1) {
while (isspace(input[0])) input++;
if (input[0] == ';' && input[1] == ';') {
- while (input[0] != '\n') input++;
+ while (input[0] && input[0] != '\n') input++;
} else if (input[0] == '(' && input[1] == ';') {
input = strstr(input, ";)") + 2;
} else {
@@ -232,15 +209,21 @@ private:
//
class SExpressionWasmBuilder {
- Module& wasm;
- MixedArena allocator;
+ AllocatingModule& wasm;
+ MixedArena& allocator;
std::function<void ()> onError;
int functionCounter;
+ std::map<Name, WasmType> functionTypes; // we need to know function return types before we parse their contents
public:
// Assumes control of and modifies the input.
- SExpressionWasmBuilder(Module& wasm, Element& module, std::function<void ()> onError) : wasm(wasm), onError(onError), functionCounter(0) {
+ SExpressionWasmBuilder(AllocatingModule& wasm, Element& module, std::function<void ()> onError) : wasm(wasm), allocator(wasm.allocator), onError(onError) {
assert(module[0]->str() == MODULE);
+ functionCounter = 0;
+ for (unsigned i = 1; i < module.size(); i++) {
+ preParseFunctionType(*module[i]);
+ }
+ functionCounter = 0;
for (unsigned i = 1; i < module.size(); i++) {
parseModuleElement(*module[i]);
}
@@ -248,6 +231,38 @@ public:
private:
+ // pre-parse types and function definitions, so we know function return types before parsing their contents
+ void preParseFunctionType(Element& s) {
+ IString id = s[0]->str();
+ if (id == TYPE) return parseType(s);
+ if (id != FUNC) return;
+ size_t i = 1;
+ Name name;
+ if (s[i]->isStr()) {
+ name = s[i]->str();
+ i++;
+ } else {
+ // unnamed, use an index
+ name = Name::fromInt(functionCounter);
+ }
+ functionCounter++;
+ for (;i < s.size(); i++) {
+ Element& curr = *s[i];
+ IString id = curr[0]->str();
+ if (id == RESULT) {
+ functionTypes[name] = stringToWasmType(curr[1]->str());
+ return;
+ } else if (id == TYPE) {
+ Name name = curr[1]->str();
+ if (wasm.functionTypesMap.find(name) == wasm.functionTypesMap.end()) onError();
+ FunctionType* type = wasm.functionTypesMap[name];
+ functionTypes[name] = type->result;
+ return;
+ }
+ }
+ functionTypes[name] = none;
+ }
+
void parseModuleElement(Element& curr) {
IString id = curr[0]->str();
if (id == FUNC) return parseFunction(curr);
@@ -255,7 +270,7 @@ private:
if (id == EXPORT) return parseExport(curr);
if (id == IMPORT) return parseImport(curr);
if (id == TABLE) return parseTable(curr);
- if (id == TYPE) return parseType(curr);
+ if (id == TYPE) return; // already done
std::cerr << "bad module element " << id.str << '\n';
onError();
}
@@ -402,8 +417,8 @@ public:
if (op[2] == 'p') return makeBinary(s, BinaryOp::CopySign, type);
if (op[2] == 'n') {
if (op[3] == 'v') {
- if (op[8] == 's') return makeConvert(s, op[11] == '3' ? ConvertOp::ConvertSInt32 : ConvertOp::ConvertSInt64, type);
- if (op[8] == 'u') return makeConvert(s, op[11] == '3' ? ConvertOp::ConvertUInt32 : ConvertOp::ConvertUInt64, type);
+ if (op[8] == 's') return makeUnary(s, op[11] == '3' ? UnaryOp::ConvertSInt32 : UnaryOp::ConvertSInt64, type);
+ if (op[8] == 'u') return makeUnary(s, op[11] == '3' ? UnaryOp::ConvertUInt32 : UnaryOp::ConvertUInt64, type);
}
if (op[3] == 's') return makeConst(s, type);
}
@@ -416,12 +431,12 @@ public:
if (op[3] == '_') return makeBinary(s, op[4] == 'u' ? BinaryOp::DivU : BinaryOp::DivS, type);
if (op[3] == 0) return makeBinary(s, BinaryOp::Div, type);
}
- if (op[1] == 'e') return makeConvert(s, ConvertOp::DemoteFloat64, type);
+ if (op[1] == 'e') return makeUnary(s, UnaryOp::DemoteFloat64, type);
abort_on(op);
}
case 'e': {
- if (op[1] == 'q') return makeCompare(s, RelationalOp::Eq, type);
- if (op[1] == 'x') return makeConvert(s, op[7] == 'u' ? ConvertOp::ExtendUInt32 : ConvertOp::ExtendSInt32, type);
+ if (op[1] == 'q') return makeBinary(s, BinaryOp::Eq, type);
+ if (op[1] == 'x') return makeUnary(s, op[7] == 'u' ? UnaryOp::ExtendUInt32 : UnaryOp::ExtendSInt32, type);
abort_on(op);
}
case 'f': {
@@ -430,23 +445,23 @@ public:
}
case 'g': {
if (op[1] == 't') {
- if (op[2] == '_') return makeCompare(s, op[3] == 'u' ? RelationalOp::GtU : RelationalOp::GtS, type);
- if (op[2] == 0) return makeCompare(s, RelationalOp::Gt, type);
+ if (op[2] == '_') return makeBinary(s, op[3] == 'u' ? BinaryOp::GtU : BinaryOp::GtS, type);
+ if (op[2] == 0) return makeBinary(s, BinaryOp::Gt, type);
}
if (op[1] == 'e') {
- if (op[2] == '_') return makeCompare(s, op[3] == 'u' ? RelationalOp::GeU : RelationalOp::GeS, type);
- if (op[2] == 0) return makeCompare(s, RelationalOp::Ge, type);
+ if (op[2] == '_') return makeBinary(s, op[3] == 'u' ? BinaryOp::GeU : BinaryOp::GeS, type);
+ if (op[2] == 0) return makeBinary(s, BinaryOp::Ge, type);
}
abort_on(op);
}
case 'l': {
if (op[1] == 't') {
- if (op[2] == '_') return makeCompare(s, op[3] == 'u' ? RelationalOp::LtU : RelationalOp::LtS, type);
- if (op[2] == 0) return makeCompare(s, RelationalOp::Lt, type);
+ if (op[2] == '_') return makeBinary(s, op[3] == 'u' ? BinaryOp::LtU : BinaryOp::LtS, type);
+ if (op[2] == 0) return makeBinary(s, BinaryOp::Lt, type);
}
if (op[1] == 'e') {
- if (op[2] == '_') return makeCompare(s, op[3] == 'u' ? RelationalOp::LeU : RelationalOp::LeS, type);
- if (op[2] == 0) return makeCompare(s, RelationalOp::Le, type);
+ if (op[2] == '_') return makeBinary(s, op[3] == 'u' ? BinaryOp::LeU : BinaryOp::LeS, type);
+ if (op[2] == 0) return makeBinary(s, BinaryOp::Le, type);
}
if (op[1] == 'o') return makeLoad(s, type);
abort_on(op);
@@ -459,7 +474,7 @@ public:
}
case 'n': {
if (op[1] == 'e') {
- if (op[2] == 0) return makeCompare(s, RelationalOp::Ne, type);
+ if (op[2] == 0) return makeBinary(s, BinaryOp::Ne, type);
if (op[2] == 'a') return makeUnary(s, UnaryOp::Nearest, type);
if (op[2] == 'g') return makeUnary(s, UnaryOp::Neg, type);
}
@@ -470,14 +485,14 @@ public:
abort_on(op);
}
case 'p': {
- if (op[1] == 'r') return makeConvert(s, ConvertOp::PromoteFloat32, type);
+ if (op[1] == 'r') return makeUnary(s, UnaryOp::PromoteFloat32, type);
if (op[1] == 'o') return makeUnary(s, UnaryOp::Popcnt, type);
abort_on(op);
}
case 'r': {
if (op[1] == 'e') {
if (op[2] == 'm') return makeBinary(s, op[4] == 'u' ? BinaryOp::RemU : BinaryOp::RemS, type);
- if (op[2] == 'i') return makeConvert(s, isWasmTypeFloat(type) ? ConvertOp::ReinterpretInt : ConvertOp::ReinterpretFloat, type);
+ if (op[2] == 'i') return makeUnary(s, isWasmTypeFloat(type) ? UnaryOp::ReinterpretInt : UnaryOp::ReinterpretFloat, type);
}
abort_on(op);
}
@@ -494,14 +509,14 @@ public:
}
case 't': {
if (op[1] == 'r') {
- if (op[6] == 's') return makeConvert(s, op[9] == '3' ? ConvertOp::TruncSFloat32 : ConvertOp::TruncSFloat64, type);
- if (op[6] == 'u') return makeConvert(s, op[9] == '3' ? ConvertOp::TruncUFloat32 : ConvertOp::TruncUFloat64, type);
+ if (op[6] == 's') return makeUnary(s, op[9] == '3' ? UnaryOp::TruncSFloat32 : UnaryOp::TruncSFloat64, type);
+ if (op[6] == 'u') return makeUnary(s, op[9] == '3' ? UnaryOp::TruncUFloat32 : UnaryOp::TruncUFloat64, type);
if (op[2] == 'u') return makeUnary(s, UnaryOp::Trunc, type);
}
abort_on(op);
}
case 'w': {
- if (op[1] == 'r') return makeConvert(s, ConvertOp::WrapInt64, type);
+ if (op[1] == 'r') return makeUnary(s, UnaryOp::WrapInt64, type);
abort_on(op);
}
case 'x': {
@@ -540,7 +555,6 @@ public:
abort_on(str);
}
case 'l': {
- if (str[1] == 'a') return makeLabel(s);
if (str[1] == 'o') return makeLoop(s);
abort_on(str);
}
@@ -584,7 +598,7 @@ private:
ret->op = op;
ret->left = parseExpression(s[1]);
ret->right = parseExpression(s[2]);
- ret->type = type;
+ ret->finalize();
return ret;
}
@@ -596,23 +610,6 @@ private:
return ret;
}
- Expression* makeCompare(Element& s, RelationalOp op, WasmType type) {
- auto ret = allocator.alloc<Compare>();
- ret->op = op;
- ret->left = parseExpression(s[1]);
- ret->right = parseExpression(s[2]);
- ret->inputType = type;
- return ret;
- }
-
- Expression* makeConvert(Element& s, ConvertOp op, WasmType type) {
- auto ret = allocator.alloc<Convert>();
- ret->op = op;
- ret->value = parseExpression(s[1]);
- ret->type = type;
- return ret;
- }
-
Expression* makeSelect(Element& s, WasmType type) {
auto ret = allocator.alloc<Select>();
ret->condition = parseExpression(s[1]);
@@ -630,6 +627,7 @@ private:
} else {
parseCallOperands(s, 1, ret);
}
+ ret->finalize();
return ret;
}
@@ -666,151 +664,21 @@ private:
if (s[1]->isStr()) {
ret->name = s[1]->str();
i++;
+ } else {
+ ret->name = getPrefixedName("block");
}
+ labelStack.push_back(ret->name);
for (; i < s.size(); i++) {
ret->list.push_back(parseExpression(s[i]));
}
+ labelStack.pop_back();
+ ret->type = ret->list.back()->type;
return ret;
}
Expression* makeConst(Element& s, WasmType type) {
- const char *str = s[1]->c_str();
- auto ret = allocator.alloc<Const>();
- ret->type = ret->value.type = type;
- if (isWasmTypeFloat(type)) {
- if (s[1]->str() == INFINITY_) {
- switch (type) {
- case f32: ret->value.f32 = std::numeric_limits<float>::infinity(); break;
- case f64: ret->value.f64 = std::numeric_limits<double>::infinity(); break;
- default: onError();
- }
- //std::cerr << "make constant " << str << " ==> " << ret->value << '\n';
- return ret;
- }
- if (s[1]->str() == NEG_INFINITY) {
- switch (type) {
- case f32: ret->value.f32 = -std::numeric_limits<float>::infinity(); break;
- case f64: ret->value.f64 = -std::numeric_limits<double>::infinity(); break;
- default: onError();
- }
- //std::cerr << "make constant " << str << " ==> " << ret->value << '\n';
- return ret;
- }
- if (s[1]->str() == NAN_) {
- switch (type) {
- case f32: ret->value.f32 = std::nan(""); break;
- case f64: ret->value.f64 = std::nan(""); break;
- default: onError();
- }
- //std::cerr << "make constant " << str << " ==> " << ret->value << '\n';
- return ret;
- }
- bool negative = str[0] == '-';
- const char *positive = negative ? str + 1 : str;
- if (positive[0] == '+') positive++;
- if (positive[0] == 'n' && positive[1] == 'a' && positive[2] == 'n') {
- const char * modifier = positive[3] == ':' ? positive + 4 : nullptr;
- assert(modifier ? positive[4] == '0' && positive[5] == 'x' : 1);
- switch (type) {
- case f32: {
- union {
- uint32_t pattern;
- float f;
- } u;
- if (modifier) {
- std::istringstream istr(modifier);
- istr >> std::hex >> u.pattern;
- u.pattern |= 0x7f800000;
- } else {
- u.pattern = 0x7fc00000;
- }
- if (negative) u.pattern |= 0x80000000;
- if (!isnan(u.f)) u.pattern |= 1;
- assert(isnan(u.f));
- ret->value.f32 = u.f;
- break;
- }
- case f64: {
- union {
- uint64_t pattern;
- double d;
- } u;
- if (modifier) {
- std::istringstream istr(modifier);
- istr >> std::hex >> u.pattern;
- u.pattern |= 0x7ff0000000000000LL;
- } else {
- u.pattern = 0x7ff8000000000000L;
- }
- if (negative) u.pattern |= 0x8000000000000000LL;
- if (!isnan(u.d)) u.pattern |= 1;
- assert(isnan(u.d));
- ret->value.f64 = u.d;
- break;
- }
- default: onError();
- }
- //std::cerr << "make constant " << str << " ==> " << ret->value << '\n';
- return ret;
- }
- if (s[1]->str() == NEG_NAN) {
- switch (type) {
- case f32: ret->value.f32 = -std::nan(""); break;
- case f64: ret->value.f64 = -std::nan(""); break;
- default: onError();
- }
- //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')) {
- bool negative = str[0] == '-';
- if (negative) str++;
- std::istringstream istr(str);
- uint32_t temp;
- istr >> std::hex >> temp;
- ret->value.i32 = negative ? -temp : temp;
- } else {
- std::istringstream istr(str);
- int32_t temp;
- istr >> temp;
- ret->value.i32 = temp;
- }
- break;
- }
- case i64: {
- if ((str[0] == '0' && str[1] == 'x') || (str[0] == '-' && str[1] == '0' && str[2] == 'x')) {
- bool negative = str[0] == '-';
- if (negative) str++;
- std::istringstream istr(str);
- uint64_t temp;
- istr >> std::hex >> temp;
- ret->value.i64 = negative ? -temp : temp;
- } else {
- std::istringstream istr(str);
- int64_t temp;
- istr >> temp;
- ret->value.i64 = temp;
- }
- break;
- }
- case f32: {
- char *end;
- ret->value.f32 = strtof(str, &end);
- assert(!isnan(ret->value.f32));
- break;
- }
- case f64: {
- char *end;
- ret->value.f64 = strtod(str, &end);
- assert(!isnan(ret->value.f64));
- break;
- }
- default: onError();
- }
- //std::cerr << "make constant " << str << " ==> " << ret->value << '\n';
+ auto ret = parseConst(s[1]->str(), type, allocator);
+ if (!ret) onError();
return ret;
}
@@ -896,31 +764,20 @@ private:
ret->ifTrue = parseExpression(s[2]);
if (s.size() == 4) {
ret->ifFalse = parseExpression(s[3]);
+ ret->type = ret->ifTrue->type == ret->ifFalse->type ? ret->ifTrue->type : none; // if not the same type, this does not return a value
}
return ret;
}
- Expression* makeLabel(Element& s) {
- auto ret = allocator.alloc<Label>();
- size_t i = 1;
- if (s[i]->isStr()) {
- ret->name = s[i]->str();
- i++;
- } else {
- ret->name = getPrefixedName("label");
- }
- labelStack.push_back(ret->name);
- ret->body = parseExpression(s[i]);
- labelStack.pop_back();
- return ret;
- }
-
Expression* makeMaybeBlock(Element& s, size_t i, size_t stopAt=-1) {
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]));
}
+ if (ret->list.size() > 0) {
+ ret->type = ret->list.back()->type;
+ }
return ret;
}
@@ -950,6 +807,7 @@ private:
Expression* makeCall(Element& s) {
auto ret = allocator.alloc<Call>();
ret->target = s[1]->str();
+ ret->type = functionTypes[ret->target];
parseCallOperands(s, 2, ret);
return ret;
}
@@ -957,6 +815,8 @@ private:
Expression* makeCallImport(Element& s) {
auto ret = allocator.alloc<CallImport>();
ret->target = s[1]->str();
+ Import* import = wasm.importsMap[ret->target];
+ ret->type = import->type.result;
parseCallOperands(s, 2, ret);
return ret;
}
@@ -965,7 +825,8 @@ private:
auto ret = allocator.alloc<CallIndirect>();
IString type = s[1]->str();
assert(wasm.functionTypesMap.find(type) != wasm.functionTypesMap.end());
- ret->type = wasm.functionTypesMap[type];
+ ret->fullType = wasm.functionTypesMap[type];
+ ret->type = ret->fullType->result;
ret->target = parseExpression(s[2]);
parseCallOperands(s, 3, ret);
return ret;
@@ -981,16 +842,22 @@ private:
Expression* makeBreak(Element& s) {
auto ret = allocator.alloc<Break>();
- if (s[1]->dollared()) {
- ret->name = s[1]->str();
+ size_t i = 1;
+ if (s[0]->str() == BR_IF) {
+ ret->condition = parseExpression(s[i]);
+ i++;
+ }
+ if (s[i]->dollared()) {
+ ret->name = s[i]->str();
} else {
// offset, break to nth outside label
- size_t offset = atol(s[1]->c_str());
+ size_t offset = atol(s[i]->c_str());
assert(offset < labelStack.size());
ret->name = labelStack[labelStack.size() - 1 - offset];
}
- if (s.size() == 3) {
- ret->value = parseExpression(s[2]);
+ i++;
+ if (i < s.size()) {
+ ret->value = parseExpression(s[i]);
}
return ret;
}
@@ -1082,23 +949,27 @@ private:
im->module = s[2]->str();
if (!s[3]->isStr()) onError();
im->base = s[3]->str();
- Element& params = *s[4];
- IString id = params[0]->str();
- if (id == PARAM) {
- for (size_t i = 1; i < params.size(); i++) {
- im->type.params.push_back(stringToWasmType(params[i]->str()));
+ if (s.size() > 4) {
+ Element& params = *s[4];
+ IString id = params[0]->str();
+ if (id == PARAM) {
+ for (size_t i = 1; i < params.size(); i++) {
+ im->type.params.push_back(stringToWasmType(params[i]->str()));
+ }
+ } else if (id == RESULT) {
+ im->type.result = stringToWasmType(params[1]->str());
+ } else if (id == TYPE) {
+ IString name = params[1]->str();
+ assert(wasm.functionTypesMap.find(name) != wasm.functionTypesMap.end());
+ im->type = *wasm.functionTypesMap[name];
+ } else {
+ onError();
+ }
+ if (s.size() > 5) {
+ Element& result = *s[5];
+ assert(result[0]->str() == RESULT);
+ im->type.result = stringToWasmType(result[1]->str());
}
- } else if (id == TYPE) {
- IString name = params[1]->str();
- assert(wasm.functionTypesMap.find(name) != wasm.functionTypesMap.end());
- im->type = *wasm.functionTypesMap[name];
- } else {
- onError();
- }
- if (s.size() > 5) {
- Element& result = *s[5];
- assert(result[0]->str() == RESULT);
- im->type.result = stringToWasmType(result[1]->str());
}
wasm.addImport(im);
}