summaryrefslogtreecommitdiff
path: root/src/wasm/wasm-s-parser.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/wasm/wasm-s-parser.cpp')
-rw-r--r--src/wasm/wasm-s-parser.cpp302
1 files changed, 12 insertions, 290 deletions
diff --git a/src/wasm/wasm-s-parser.cpp b/src/wasm/wasm-s-parser.cpp
index 79407a3f8..34022b72b 100644
--- a/src/wasm/wasm-s-parser.cpp
+++ b/src/wasm/wasm-s-parser.cpp
@@ -658,241 +658,19 @@ Expression* SExpressionWasmBuilder::parseExpression(Element& s) {
}
Expression* SExpressionWasmBuilder::makeExpression(Element& s) {
- IString id = s[0]->str();
- const char *str = id.str;
- const char *dot = strchr(str, '.');
- if (dot) {
- // type.operation (e.g. i32.add)
- Type type = stringToType(str, false, true);
- // Local copy to index into op without bounds checking.
- enum { maxNameSize = 15 };
- char op[maxNameSize + 1] = {'\0'};
- strncpy(op, dot + 1, maxNameSize);
-#define BINARY_INT_OR_FLOAT(op) (type == i32 ? BinaryOp::op##Int32 : (type == i64 ? BinaryOp::op##Int64 : (type == f32 ? BinaryOp::op##Float32 : BinaryOp::op##Float64)))
-#define BINARY_INT(op) (type == i32 ? BinaryOp::op##Int32 : BinaryOp::op##Int64)
-#define BINARY_FLOAT(op) (type == f32 ? BinaryOp::op##Float32 : BinaryOp::op##Float64)
- switch (op[0]) {
- case 'a': {
- if (op[1] == 'b') return makeUnary(s, type == f32 ? UnaryOp::AbsFloat32 : UnaryOp::AbsFloat64, type);
- if (op[1] == 'd') return makeBinary(s, BINARY_INT_OR_FLOAT(Add), type);
- if (op[1] == 'n') return makeBinary(s, BINARY_INT(And), type);
- if (op[1] == 't' && !strncmp(op, "atomic.", strlen("atomic."))) {
- if (op[7] == 'l') return makeLoad(s, type, /*isAtomic=*/true);
- if (op[7] == 's') return makeStore(s, type, /*isAtomic=*/true);
- if (op[7] == 'r') return makeAtomicRMWOrCmpxchg(s, type);
- }
- abort_on(op);
- }
- case 'c': {
- if (op[1] == 'e') return makeUnary(s, type == f32 ? UnaryOp::CeilFloat32 : UnaryOp::CeilFloat64, type);
- if (op[1] == 'l') return makeUnary(s, type == i32 ? UnaryOp::ClzInt32 : UnaryOp::ClzInt64, type);
- if (op[1] == 'o') {
- if (op[2] == 'p') return makeBinary(s, BINARY_FLOAT(CopySign), type);
- if (op[2] == 'n') {
- if (op[3] == 'v') {
- if (op[8] == 's') return makeUnary(s, op[11] == '3' ? (type == f32 ? UnaryOp::ConvertSInt32ToFloat32 : UnaryOp::ConvertSInt32ToFloat64) : (type == f32 ? UnaryOp::ConvertSInt64ToFloat32 : UnaryOp::ConvertSInt64ToFloat64), type);
- if (op[8] == 'u') return makeUnary(s, op[11] == '3' ? (type == f32 ? UnaryOp::ConvertUInt32ToFloat32 : UnaryOp::ConvertUInt32ToFloat64) : (type == f32 ? UnaryOp::ConvertUInt64ToFloat32 : UnaryOp::ConvertUInt64ToFloat64), type);
- }
- if (op[3] == 's') return makeConst(s, type);
- }
- }
- if (op[1] == 't') return makeUnary(s, type == i32 ? UnaryOp::CtzInt32 : UnaryOp::CtzInt64, type);
- abort_on(op);
- }
- case 'd': {
- if (op[1] == 'i') {
- if (op[3] == '_') return makeBinary(s, op[4] == 'u' ? BINARY_INT(DivU) : BINARY_INT(DivS), type);
- if (op[3] == 0) return makeBinary(s, BINARY_FLOAT(Div), type);
- }
- if (op[1] == 'e') return makeUnary(s, UnaryOp::DemoteFloat64, type);
- abort_on(op);
- }
- case 'e': {
- if (op[1] == 'q') {
- if (op[2] == 0) return makeBinary(s, BINARY_INT_OR_FLOAT(Eq), type);
- if (op[2] == 'z') return makeUnary(s, type == i32 ? UnaryOp::EqZInt32 : UnaryOp::EqZInt64, type);
- }
- if (op[1] == 'x') {
- if (op[6] == '8') return makeUnary(s, type == i32 ? UnaryOp::ExtendS8Int32 : UnaryOp::ExtendS8Int64, type);
- if (op[6] == '1') return makeUnary(s, type == i32 ? UnaryOp::ExtendS16Int32 : UnaryOp::ExtendS16Int64, type);
- if (op[6] == '3') return makeUnary(s, UnaryOp::ExtendS32Int64, type);
- return makeUnary(s, op[7] == 'u' ? UnaryOp::ExtendUInt32 : UnaryOp::ExtendSInt32, type);
- }
- abort_on(op);
- }
- case 'f': {
- if (op[1] == 'l') return makeUnary(s, type == f32 ? UnaryOp::FloorFloat32 : UnaryOp::FloorFloat64, type);
- abort_on(op);
- }
- case 'g': {
- if (op[1] == 't') {
- if (op[2] == '_') return makeBinary(s, op[3] == 'u' ? BINARY_INT(GtU) : BINARY_INT(GtS), type);
- if (op[2] == 0) return makeBinary(s, BINARY_FLOAT(Gt), type);
- }
- if (op[1] == 'e') {
- if (op[2] == '_') return makeBinary(s, op[3] == 'u' ? BINARY_INT(GeU) : BINARY_INT(GeS), type);
- if (op[2] == 0) return makeBinary(s, BINARY_FLOAT(Ge), type);
- }
- abort_on(op);
- }
- case 'l': {
- if (op[1] == 't') {
- if (op[2] == '_') return makeBinary(s, op[3] == 'u' ? BINARY_INT(LtU) : BINARY_INT(LtS), type);
- if (op[2] == 0) return makeBinary(s, BINARY_FLOAT(Lt), type);
- }
- if (op[1] == 'e') {
- if (op[2] == '_') return makeBinary(s, op[3] == 'u' ? BINARY_INT(LeU) : BINARY_INT(LeS), type);
- if (op[2] == 0) return makeBinary(s, BINARY_FLOAT(Le), type);
- }
- if (op[1] == 'o') return makeLoad(s, type, /*isAtomic=*/false);
- abort_on(op);
- }
- case 'm': {
- if (op[1] == 'i') return makeBinary(s, BINARY_FLOAT(Min), type);
- if (op[1] == 'a') return makeBinary(s, BINARY_FLOAT(Max), type);
- if (op[1] == 'u') return makeBinary(s, BINARY_INT_OR_FLOAT(Mul), type);
- abort_on(op);
- }
- case 'n': {
- if (op[1] == 'e') {
- if (op[2] == 0) return makeBinary(s, BINARY_INT_OR_FLOAT(Ne), type);
- if (op[2] == 'a') return makeUnary(s, type == f32 ? UnaryOp::NearestFloat32 : UnaryOp::NearestFloat64, type);
- if (op[2] == 'g') return makeUnary(s, type == f32 ? UnaryOp::NegFloat32 : UnaryOp::NegFloat64, type);
- }
- abort_on(op);
- }
- case 'o': {
- if (op[1] == 'r') return makeBinary(s, BINARY_INT(Or), type);
- abort_on(op);
- }
- case 'p': {
- if (op[1] == 'r') return makeUnary(s, UnaryOp::PromoteFloat32, type);
- if (op[1] == 'o') return makeUnary(s, type == i32 ? UnaryOp::PopcntInt32 : UnaryOp::PopcntInt64, type);
- abort_on(op);
- }
- case 'r': {
- if (op[1] == 'e') {
- if (op[2] == 'm') return makeBinary(s, op[4] == 'u' ? BINARY_INT(RemU) : BINARY_INT(RemS), type);
- if (op[2] == 'i') return makeUnary(s, isFloatType(type) ? (type == f32 ? UnaryOp::ReinterpretInt32 : UnaryOp::ReinterpretInt64) : (type == i32 ? UnaryOp::ReinterpretFloat32 : UnaryOp::ReinterpretFloat64), type);
- }
- if (op[1] == 'o' && op[2] == 't') {
- return makeBinary(s, op[3] == 'l' ? BINARY_INT(RotL) : BINARY_INT(RotR), type);
- }
- abort_on(op);
- }
- case 's': {
- if (op[1] == 'h') {
- if (op[2] == 'l') return makeBinary(s, BINARY_INT(Shl), type);
- return makeBinary(s, op[4] == 'u' ? BINARY_INT(ShrU) : BINARY_INT(ShrS), type);
- }
- if (op[1] == 'u') return makeBinary(s, BINARY_INT_OR_FLOAT(Sub), type);
- if (op[1] == 'q') return makeUnary(s, type == f32 ? UnaryOp::SqrtFloat32 : UnaryOp::SqrtFloat64, type);
- if (op[1] == 't') return makeStore(s, type, /*isAtomic=*/false);
- abort_on(op);
- }
- case 't': {
- if (op[1] == 'r') {
- if (op[6] == 's') return makeUnary(s, op[9] == '3' ? (type == i32 ? UnaryOp::TruncSFloat32ToInt32 : UnaryOp::TruncSFloat32ToInt64) : (type == i32 ? UnaryOp::TruncSFloat64ToInt32 : UnaryOp::TruncSFloat64ToInt64), type);
- if (op[6] == 'u') return makeUnary(s, op[9] == '3' ? (type == i32 ? UnaryOp::TruncUFloat32ToInt32 : UnaryOp::TruncUFloat32ToInt64) : (type == i32 ? UnaryOp::TruncUFloat64ToInt32 : UnaryOp::TruncUFloat64ToInt64), type);
- if (op[2] == 'u') return makeUnary(s, type == f32 ? UnaryOp::TruncFloat32 : UnaryOp::TruncFloat64, type);
- }
- abort_on(op);
- }
- case 'w': {
- if (!strncmp(op, "wait", strlen("wait"))) return makeAtomicWait(s, type);
- if (op[1] == 'r') return makeUnary(s, UnaryOp::WrapInt64, type);
- abort_on(op);
- }
- case 'x': {
- if (op[1] == 'o') return makeBinary(s, BINARY_INT(Xor), type);
- abort_on(op);
- }
- default: abort_on(op);
- }
- } else {
- // other expression
- switch (str[0]) {
- case 'b': {
- if (str[1] == 'l') return makeBlock(s);
- if (str[1] == 'r') {
- if (str[2] == '_' && str[3] == 't') return makeBreakTable(s);
- return makeBreak(s);
- }
- abort_on(str);
- }
- case 'c': {
- if (str[1] == 'a') {
- if (id == CALL) return makeCall(s);
- if (id == CALL_INDIRECT) return makeCallIndirect(s);
- } else if (str[1] == 'u') return makeHost(s, HostOp::CurrentMemory);
- abort_on(str);
- }
- case 'd': {
- if (str[1] == 'r') return makeDrop(s);
- abort_on(str);
- }
- case 'e': {
- if (str[1] == 'l') return makeThenOrElse(s);
- abort_on(str);
- }
- case 'g': {
- if (str[1] == 'e') {
- if (str[4] == 'l') return makeGetLocal(s);
- if (str[4] == 'g') return makeGetGlobal(s);
- }
- if (str[1] == 'r') return makeHost(s, HostOp::GrowMemory);
- abort_on(str);
- }
- case 'h': {
- abort_on(str);
- }
- case 'i': {
- if (str[1] == 'f') return makeIf(s);
- abort_on(str);
- }
- case 'l': {
- if (str[1] == 'o') return makeLoop(s);
- abort_on(str);
- }
- case 'n': {
- if (str[1] == 'o') return allocator.alloc<Nop>();
- abort_on(str);
- }
- case 'p': {
- abort_on(str);
- }
- case 's': {
- if (str[1] == 'e' && str[2] == 't') {
- if (str[4] == 'l') return makeSetLocal(s);
- if (str[4] == 'g') return makeSetGlobal(s);
- }
- if (str[1] == 'e' && str[2] == 'l') return makeSelect(s);
- abort_on(str);
- }
- case 'r': {
- if (str[1] == 'e') return makeReturn(s);
- abort_on(str);
- }
- case 't': {
- if (str[1] == 'h') return makeThenOrElse(s);
- if (str[1] == 'e' && str[2] == 'e') return makeTeeLocal(s);
- abort_on(str);
- }
- case 'u': {
- if (str[1] == 'n') return allocator.alloc<Unreachable>();
- abort_on(str);
- }
- case 'w': {
- if (!strncmp(str, "wake", strlen("wake"))) return makeAtomicWake(s);
- abort_on(str);
- }
- default: abort_on(str);
- }
- }
- abort_on("unrecognized input string for parsing");
+#define INSTRUCTION_PARSER
+#include "gen-s-parser.inc"
}
-Expression* SExpressionWasmBuilder::makeBinary(Element& s, BinaryOp op, Type type) {
+Expression* SExpressionWasmBuilder::makeUnreachable() {
+ return allocator.alloc<Unreachable>();
+}
+
+Expression* SExpressionWasmBuilder::makeNop() {
+ return allocator.alloc<Nop>();
+}
+
+Expression* SExpressionWasmBuilder::makeBinary(Element& s, BinaryOp op) {
auto ret = allocator.alloc<Binary>();
ret->op = op;
ret->left = parseExpression(s[1]);
@@ -902,67 +680,11 @@ Expression* SExpressionWasmBuilder::makeBinary(Element& s, BinaryOp op, Type typ
}
-Expression* SExpressionWasmBuilder::makeUnary(Element& s, UnaryOp op, Type type) {
+Expression* SExpressionWasmBuilder::makeUnary(Element& s, UnaryOp op) {
auto ret = allocator.alloc<Unary>();
ret->op = op;
ret->value = parseExpression(s[1]);
ret->finalize();
- // type is the reported type, e.g. i64.ctz reports i64 (but has a return type of i32, in this case)
- // verify the reported type is correct
- switch (op) {
- case EqZInt32:
- case NegFloat32:
- case AbsFloat32:
- case CeilFloat32:
- case FloorFloat32:
- case TruncFloat32:
- case NearestFloat32:
- case SqrtFloat32:
- case ClzInt32:
- case CtzInt32:
- case PopcntInt32:
- case EqZInt64:
- case NegFloat64:
- case AbsFloat64:
- case CeilFloat64:
- case FloorFloat64:
- case TruncFloat64:
- case NearestFloat64:
- case SqrtFloat64:
- case ClzInt64:
- case CtzInt64:
- case PopcntInt64: {
- if (ret->value->type != unreachable && type != ret->value->type) throw ParseException(std::string("bad type for ") + getExpressionName(ret) + ": " + printType(type) + " vs value type " + printType(ret->value->type), s.line, s.col);
- break;
- }
- case ExtendSInt32: case ExtendUInt32:
- case ExtendS8Int32: case ExtendS16Int32:
- case ExtendS8Int64: case ExtendS16Int64: case ExtendS32Int64:
- case WrapInt64:
- case PromoteFloat32:
- case DemoteFloat64:
- case TruncSFloat32ToInt32:
- case TruncUFloat32ToInt32:
- case TruncSFloat64ToInt32:
- case TruncUFloat64ToInt32:
- case ReinterpretFloat32:
- case TruncSFloat32ToInt64:
- case TruncUFloat32ToInt64:
- case TruncSFloat64ToInt64:
- case TruncUFloat64ToInt64:
- case ReinterpretFloat64:
- case ReinterpretInt32:
- case ConvertSInt32ToFloat32:
- case ConvertUInt32ToFloat32:
- case ConvertSInt64ToFloat32:
- case ConvertUInt64ToFloat32:
- case ReinterpretInt64:
- case ConvertSInt32ToFloat64:
- case ConvertUInt32ToFloat64:
- case ConvertSInt64ToFloat64:
- case ConvertUInt64ToFloat64: break;
- default: WASM_UNREACHABLE();
- }
return ret;
}