diff options
Diffstat (limited to 'src/wasm-s-parser.h')
-rw-r--r-- | src/wasm-s-parser.h | 355 |
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); } |