diff options
Diffstat (limited to 'src/wasm/wasm-s-parser.cpp')
-rw-r--r-- | src/wasm/wasm-s-parser.cpp | 129 |
1 files changed, 69 insertions, 60 deletions
diff --git a/src/wasm/wasm-s-parser.cpp b/src/wasm/wasm-s-parser.cpp index 38954af1f..c6331afc0 100644 --- a/src/wasm/wasm-s-parser.cpp +++ b/src/wasm/wasm-s-parser.cpp @@ -666,6 +666,7 @@ Expression* SExpressionWasmBuilder::makeExpression(Element& s) { 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 makeAtomicRMW(s, type); } abort_on(op); } @@ -1125,46 +1126,57 @@ Expression* SExpressionWasmBuilder::makeConst(Element& s, WasmType type) { return ret; } - -Expression* SExpressionWasmBuilder::makeLoad(Element& s, WasmType type, bool isAtomic) { - const char *extra = strchr(s[0]->c_str(), '.') + 5; // after "type.load" - if (isAtomic) extra += 7; // after "type.atomic.load" - auto* ret = allocator.alloc<Load>(); - ret->isAtomic = isAtomic; - ret->type = type; - ret->bytes = getWasmTypeSize(type); - if (extra[0] == '8') { - ret->bytes = 1; - extra++; - } else if (extra[0] == '1') { - if (extra[1] != '6') throw ParseException("expected load16"); - ret->bytes = 2; - extra += 2; - } else if (extra[0] == '3') { - if (extra[1] != '2') throw ParseException("expected load32"); - ret->bytes = 4; - extra += 2; +static uint8_t parseMemBytes(const char** in, uint8_t fallback) { + uint8_t ret; + const char* s = *in; + if (s[0] == '8') { + ret = 1; + (*in)++; + } else if (s[0] == '1') { + if (s[1] != '6') throw ParseException("expected 16 for memop size"); + ret = 2; + *in += 2; + } else if (s[0] == '3') { + if (s[1] != '2') throw ParseException("expected 32 for memop size");; + ret = 4; + *in += 2; + } else { + ret = fallback; } - ret->signed_ = extra[0] && extra[1] == 's'; + return ret; +} + +static size_t parseMemAttributes(Element& s, Address* offset, Address* align, Address fallback) { size_t i = 1; - ret->offset = 0; - ret->align = ret->bytes; + *offset = 0; + *align = fallback; while (!s[i]->isList()) { const char *str = s[i]->c_str(); const char *eq = strchr(str, '='); - if (!eq) throw ParseException("no = in load attribute"); + if (!eq) throw ParseException("missing = in memory attribute"); eq++; + uint64_t value = atoll(eq); if (str[0] == 'a') { - uint64_t align = atoll(eq); - if (align > std::numeric_limits<uint32_t>::max()) throw ParseException("bad align"); - ret->align = align; + if (value > std::numeric_limits<uint32_t>::max()) throw ParseException("bad align"); + *align = value; } else if (str[0] == 'o') { - uint64_t offset = atoll(eq); - if (offset > std::numeric_limits<uint32_t>::max()) throw ParseException("bad offset"); - ret->offset = (uint32_t)offset; - } else throw ParseException("bad load attribute"); + if (value > std::numeric_limits<uint32_t>::max()) throw ParseException("bad offset"); + *offset = value; + } else throw ParseException("bad memory attribute"); i++; } + return i; +} + +Expression* SExpressionWasmBuilder::makeLoad(Element& s, WasmType type, bool isAtomic) { + const char *extra = strchr(s[0]->c_str(), '.') + 5; // after "type.load" + if (isAtomic) extra += 7; // after "type.atomic.load" + auto* ret = allocator.alloc<Load>(); + ret->isAtomic = isAtomic; + ret->type = type; + ret->bytes = parseMemBytes(&extra, getWasmTypeSize(type)); + ret->signed_ = extra[0] && extra[1] == 's'; + size_t i = parseMemAttributes(s, &ret->offset, &ret->align, ret->bytes); ret->ptr = parseExpression(s[i]); ret->finalize(); return ret; @@ -1176,36 +1188,33 @@ Expression* SExpressionWasmBuilder::makeStore(Element& s, WasmType type, bool is auto ret = allocator.alloc<Store>(); ret->isAtomic = isAtomic; ret->valueType = type; - ret->bytes = getWasmTypeSize(type); - if (extra[0] == '8') { - ret->bytes = 1; - extra++; - } else if (extra[0] == '1') { - if (extra[1] != '6') throw ParseException("expected store16"); - ret->bytes = 2; - extra += 2; - } else if (extra[0] == '3') { - if (extra[1] != '2') throw ParseException("expected store32");; - ret->bytes = 4; - extra += 2; - } - size_t i = 1; - ret->offset = 0; - ret->align = ret->bytes; - while (!s[i]->isList()) { - const char *str = s[i]->c_str(); - const char *eq = strchr(str, '='); - if (!eq) throw ParseException("missing = in store attribute");; - eq++; - if (str[0] == 'a') { - uint64_t align = atoll(eq); - if (align > std::numeric_limits<uint32_t>::max()) throw ParseException("bad align"); - ret->align = align; - } else if (str[0] == 'o') { - ret->offset = atoi(eq); - } else throw ParseException("bad store attribute"); - i++; - } + ret->bytes = parseMemBytes(&extra, getWasmTypeSize(type)); + size_t i = parseMemAttributes(s, &ret->offset, &ret->align, ret->bytes); + + ret->ptr = parseExpression(s[i]); + ret->value = parseExpression(s[i+1]); + ret->finalize(); + return ret; +} + +Expression* SExpressionWasmBuilder::makeAtomicRMW(Element& s, WasmType type) { + const char* extra = strchr(s[0]->c_str(), '.') + 11; // afer "type.atomic.rmw" + auto ret = allocator.alloc<AtomicRMW>(); + ret->type = type; + ret->bytes = parseMemBytes(&extra, getWasmTypeSize(type)); + extra = strchr(extra, '.'); // after the optional '_u' and before the opcode + if (!extra) throw ParseException("malformed atomic rmw instruction"); + extra++; // after the '.' + 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"); ret->ptr = parseExpression(s[i]); ret->value = parseExpression(s[i+1]); ret->finalize(); |