summaryrefslogtreecommitdiff
path: root/src/wasm/wasm-ir-builder.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/wasm/wasm-ir-builder.cpp')
-rw-r--r--src/wasm/wasm-ir-builder.cpp454
1 files changed, 287 insertions, 167 deletions
diff --git a/src/wasm/wasm-ir-builder.cpp b/src/wasm/wasm-ir-builder.cpp
index 6786816f3..7e163fe4e 100644
--- a/src/wasm/wasm-ir-builder.cpp
+++ b/src/wasm/wasm-ir-builder.cpp
@@ -39,14 +39,6 @@ Result<> validateTypeAnnotation(HeapType type, Expression* child) {
} // anonymous namespace
-std::vector<Expression*>& IRBuilder::getExprStack() {
- if (scopeStack.empty()) {
- // We are not in a function, so push a dummy scope.
- scopeStack.push_back({{}, Type::none});
- }
- return scopeStack.back().exprStack;
-}
-
Result<Index> IRBuilder::addScratchLocal(Type type) {
if (!func) {
return Err{"scratch local required, but there is no function context"};
@@ -55,125 +47,141 @@ Result<Index> IRBuilder::addScratchLocal(Type type) {
return Builder::addVar(func, name, type);
}
-Result<> IRBuilder::push(Expression* expr) {
- auto& exprStack = getExprStack();
+MaybeResult<IRBuilder::HoistedVal> IRBuilder::hoistLastValue() {
+ auto& stack = getScope().exprStack;
+ int index = stack.size() - 1;
+ for (; index >= 0; --index) {
+ if (stack[index]->type != Type::none) {
+ break;
+ }
+ }
+ if (index < 0) {
+ // There is no value-producing or unreachable expression.
+ return {};
+ }
+ if (unsigned(index) == stack.size() - 1) {
+ // Value-producing expression already on top of the stack.
+ return HoistedVal{Index(index), nullptr};
+ }
+ auto*& expr = stack[index];
+ auto type = expr->type;
+ if (type == Type::unreachable) {
+ // Make sure the top of the stack also has an unreachable expression.
+ if (stack.back()->type != Type::unreachable) {
+ push(builder.makeUnreachable());
+ }
+ return HoistedVal{Index(index), nullptr};
+ }
+ // Hoist with a scratch local.
+ auto scratchIdx = addScratchLocal(type);
+ CHECK_ERR(scratchIdx);
+ expr = builder.makeLocalSet(*scratchIdx, expr);
+ auto* get = builder.makeLocalGet(*scratchIdx, type);
+ push(get);
+ return HoistedVal{Index(index), get};
+}
+
+Result<> IRBuilder::packageHoistedValue(const HoistedVal& hoisted) {
+ auto& scope = getScope();
+ assert(!scope.exprStack.empty());
+
+ auto packageAsBlock = [&](Type type) {
+ // Create a block containing the producer of the hoisted value, the final
+ // get of the hoisted value, and everything in between.
+ std::vector<Expression*> exprs(scope.exprStack.begin() + hoisted.valIndex,
+ scope.exprStack.end());
+ auto* block = builder.makeBlock(exprs, type);
+ scope.exprStack.resize(hoisted.valIndex);
+ push(block);
+ };
+
+ auto type = scope.exprStack.back()->type;
+
+ if (!type.isTuple()) {
+ if (hoisted.get) {
+ packageAsBlock(type);
+ }
+ return Ok{};
+ }
+
+ // We need to break up the hoisted tuple. Create and push a block setting the
+ // tuple to a local and returning its first element, then push additional gets
+ // of each of its subsequent elements. Reuse the scratch local we used for
+ // hoisting, if it exists.
+ Index scratchIdx;
+ if (hoisted.get) {
+ // Update the get on top of the stack to just return the first element.
+ scope.exprStack.back() = builder.makeTupleExtract(hoisted.get, 0);
+ packageAsBlock(type[0]);
+ scratchIdx = hoisted.get->index;
+ } else {
+ auto scratch = addScratchLocal(type);
+ CHECK_ERR(scratch);
+ auto* block = builder.makeSequence(
+ builder.makeLocalSet(*scratch, scope.exprStack.back()),
+ builder.makeTupleExtract(builder.makeLocalGet(*scratch, type), 0),
+ type[0]);
+ scope.exprStack.pop_back();
+ push(block);
+ scratchIdx = *scratch;
+ }
+ for (Index i = 1, size = type.size(); i < size; ++i) {
+ push(builder.makeTupleExtract(builder.makeLocalGet(scratchIdx, type), i));
+ }
+ return Ok{};
+}
+
+void IRBuilder::push(Expression* expr) {
+ auto& scope = getScope();
if (expr->type == Type::unreachable) {
// We want to avoid popping back past this most recent unreachable
// instruction. Drop all prior instructions so they won't be consumed by
// later instructions but will still be emitted for their side effects, if
// any.
- for (auto& expr : exprStack) {
+ for (auto& expr : scope.exprStack) {
expr = builder.dropIfConcretelyTyped(expr);
}
- unreachable = true;
- exprStack.push_back(expr);
- } else if (expr->type.isTuple()) {
- auto scratchIdx = addScratchLocal(expr->type);
- CHECK_ERR(scratchIdx);
- CHECK_ERR(push(builder.makeLocalSet(*scratchIdx, expr)));
- for (Index i = 0; i < expr->type.size(); ++i) {
- CHECK_ERR(push(builder.makeTupleExtract(
- builder.makeLocalGet(*scratchIdx, expr->type), i)));
- }
- } else {
- exprStack.push_back(expr);
+ scope.unreachable = true;
}
- return Ok{};
+ scope.exprStack.push_back(expr);
}
Result<Expression*> IRBuilder::pop() {
- auto& exprStack = getExprStack();
+ auto& scope = getScope();
// Find the suffix of expressions that do not produce values.
- auto firstNone = exprStack.size();
- for (; firstNone > 0; --firstNone) {
- auto* expr = exprStack[firstNone - 1];
- if (expr->type != Type::none) {
- break;
- }
- }
+ auto hoisted = hoistLastValue();
+ CHECK_ERR(hoisted);
- if (firstNone == 0) {
+ if (!hoisted) {
// There are no expressions that produce values.
- if (unreachable) {
+ if (scope.unreachable) {
return builder.makeUnreachable();
}
return Err{"popping from empty stack"};
}
- if (firstNone == exprStack.size()) {
- // The last expression produced a value.
- auto expr = exprStack.back();
- exprStack.pop_back();
- return expr;
- }
+ CHECK_ERR(packageHoistedValue(*hoisted));
- // We need to assemble a block of expressions that returns the value of the
- // first one using a scratch local (unless it's unreachable, in which case
- // we can throw the following expressions away).
- auto* expr = exprStack[firstNone - 1];
- if (expr->type == Type::unreachable) {
- exprStack.resize(firstNone - 1);
- return expr;
+ auto* ret = scope.exprStack.back();
+ scope.exprStack.pop_back();
+ return ret;
+}
+
+Result<Expression*> IRBuilder::build() {
+ if (scopeStack.empty()) {
+ return builder.makeNop();
}
- auto scratchIdx = addScratchLocal(expr->type);
- CHECK_ERR(scratchIdx);
- std::vector<Expression*> exprs;
- exprs.reserve(exprStack.size() - firstNone + 2);
- exprs.push_back(builder.makeLocalSet(*scratchIdx, expr));
- exprs.insert(exprs.end(), exprStack.begin() + firstNone, exprStack.end());
- exprs.push_back(builder.makeLocalGet(*scratchIdx, expr->type));
-
- exprStack.resize(firstNone - 1);
- return builder.makeBlock(exprs, expr->type);
-}
-
-Expression* IRBuilder::build() {
- auto& exprStack = getExprStack();
- assert(scopeStack.size() == 1);
- assert(exprStack.size() == 1);
-
- auto e = exprStack.back();
- exprStack.clear();
- unreachable = false;
- return e;
-}
-
-Result<std::vector<Expression*>> IRBuilder::finishInstrs() {
- auto& exprStack = getExprStack();
- auto type = getResultType();
-
- // We have finished parsing a sequence of instructions. Fix up the parsed
- // instructions and reset the context for the next sequence.
- if (type.isTuple()) {
- std::vector<Expression*> elems(type.size());
- bool hadUnreachableElem = false;
- for (size_t i = 0; i < elems.size(); ++i) {
- auto elem = pop();
- CHECK_ERR(elem);
- elems[elems.size() - 1 - i] = *elem;
- if ((*elem)->type == Type::unreachable) {
- // We don't want to pop back past an unreachable here. Push the
- // unreachable back and throw away any post-unreachable values we have
- // popped.
- exprStack.push_back(*elem);
- hadUnreachableElem = true;
- break;
- }
- }
- if (!hadUnreachableElem) {
- exprStack.push_back(builder.makeTupleMake(std::move(elems)));
- }
- } else if (type != Type::none) {
- // Ensure the last expression produces the value.
- auto expr = pop();
- CHECK_ERR(expr);
- exprStack.push_back(*expr);
+ if (scopeStack.size() > 1 || scopeStack.back().block != nullptr) {
+ return Err{"unfinished block context"};
}
- unreachable = false;
- auto ret = std::move(exprStack);
- scopeStack.pop_back();
- return ret;
+ if (scopeStack.back().exprStack.size() > 1) {
+ return Err{"unused expressions without block context"};
+ }
+ assert(scopeStack.back().exprStack.size() == 1);
+ auto* expr = scopeStack.back().exprStack.back();
+ scopeStack.clear();
+ return expr;
}
Result<> IRBuilder::visit(Expression* curr) {
@@ -185,7 +193,8 @@ Result<> IRBuilder::visit(Expression* curr) {
// for other kinds of nodes as well, as done above.
ReFinalizeNode{}.visit(curr);
}
- return push(curr);
+ push(curr);
+ return Ok{};
}
// Handle the common case of instructions with a constant number of children
@@ -224,7 +233,7 @@ Result<> IRBuilder::visitExpression(Expression* curr) {
}
Result<> IRBuilder::visitBlock(Block* curr) {
- // TODO: Handle popping scope and filling block here instead of externally.
+ scopeStack.push_back({{}, curr});
return Ok{};
}
@@ -272,9 +281,75 @@ Result<> IRBuilder::visitArrayNew(ArrayNew* curr) {
return Ok{};
}
-Result<> IRBuilder::makeNop() { return push(builder.makeNop()); }
+Result<> IRBuilder::visitEnd() {
+ if (scopeStack.empty() || !scopeStack.back().block) {
+ return Err{"unexpected end"};
+ }
-Result<> IRBuilder::makeBlock() { return push(builder.makeBlock()); }
+ auto& scope = scopeStack.back();
+ Block* block = scope.block;
+ if (block->type.isTuple()) {
+ if (scope.unreachable) {
+ // We may not have enough concrete values on the stack to construct the
+ // full tuple, and if we tried to fill out the beginning of a tuple.make
+ // with additional popped `unreachable`s, that could cause a trap to
+ // happen before important side effects. Instead, just drop everything on
+ // the stack and finish with a single unreachable.
+ //
+ // TODO: Validate that the available expressions are a correct suffix of
+ // the expected type, since this will no longer be caught by normal
+ // validation?
+ for (auto& expr : scope.exprStack) {
+ expr = builder.dropIfConcretelyTyped(expr);
+ }
+ if (scope.exprStack.back()->type != Type::unreachable) {
+ scope.exprStack.push_back(builder.makeUnreachable());
+ }
+ } else {
+ auto hoisted = hoistLastValue();
+ CHECK_ERR(hoisted);
+ auto hoistedType = scope.exprStack.back()->type;
+ if (hoistedType.size() != block->type.size()) {
+ // We cannot propagate the hoisted value directly because it does not
+ // have the correct number of elements. Break it up if necessary and
+ // construct our returned tuple from parts.
+ CHECK_ERR(packageHoistedValue(*hoisted));
+ std::vector<Expression*> elems(block->type.size());
+ for (size_t i = 0; i < elems.size(); ++i) {
+ auto elem = pop();
+ CHECK_ERR(elem);
+ elems[elems.size() - 1 - i] = *elem;
+ }
+ scope.exprStack.push_back(builder.makeTupleMake(std::move(elems)));
+ }
+ }
+ } else if (block->type.isConcrete()) {
+ // If the value is buried in none-typed expressions, we have to bring it to
+ // the top.
+ auto hoisted = hoistLastValue();
+ CHECK_ERR(hoisted);
+ }
+ block->list.set(scope.exprStack);
+ // TODO: Track branches so we can know whether this block is a target and
+ // finalize more efficiently.
+ block->finalize(block->type);
+ scopeStack.pop_back();
+ push(block);
+ return Ok{};
+}
+
+Result<> IRBuilder::makeNop() {
+ push(builder.makeNop());
+ return Ok{};
+}
+
+Result<> IRBuilder::makeBlock(Name label, Type type) {
+ auto* block = wasm.allocator.alloc<Block>();
+ block->name = label;
+ block->type = type;
+ scopeStack.push_back({{}, block});
+ return Ok{};
+}
// Result<> IRBuilder::makeIf() {}
@@ -289,30 +364,34 @@ Result<> IRBuilder::makeBlock() { return push(builder.makeBlock()); }
// Result<> IRBuilder::makeCallIndirect() {}
Result<> IRBuilder::makeLocalGet(Index local) {
- return push(builder.makeLocalGet(local, func->getLocalType(local)));
+ push(builder.makeLocalGet(local, func->getLocalType(local)));
+ return Ok{};
}
Result<> IRBuilder::makeLocalSet(Index local) {
LocalSet curr;
CHECK_ERR(visitLocalSet(&curr));
- return push(builder.makeLocalSet(local, curr.value));
+ push(builder.makeLocalSet(local, curr.value));
+ return Ok{};
}
Result<> IRBuilder::makeLocalTee(Index local) {
LocalSet curr;
CHECK_ERR(visitLocalSet(&curr));
- return push(
- builder.makeLocalTee(local, curr.value, func->getLocalType(local)));
+ push(builder.makeLocalTee(local, curr.value, func->getLocalType(local)));
+ return Ok{};
}
Result<> IRBuilder::makeGlobalGet(Name global) {
- return push(builder.makeGlobalGet(global, wasm.getGlobal(global)->type));
+ push(builder.makeGlobalGet(global, wasm.getGlobal(global)->type));
+ return Ok{};
}
Result<> IRBuilder::makeGlobalSet(Name global) {
GlobalSet curr;
CHECK_ERR(visitGlobalSet(&curr));
- return push(builder.makeGlobalSet(global, curr.value));
+ push(builder.makeGlobalSet(global, curr.value));
+ return Ok{};
}
Result<> IRBuilder::makeLoad(unsigned bytes,
@@ -323,23 +402,25 @@ Result<> IRBuilder::makeLoad(unsigned bytes,
Name mem) {
Load curr;
CHECK_ERR(visitLoad(&curr));
- return push(
- builder.makeLoad(bytes, signed_, offset, align, curr.ptr, type, mem));
+ push(builder.makeLoad(bytes, signed_, offset, align, curr.ptr, type, mem));
+ return Ok{};
}
Result<> IRBuilder::makeStore(
unsigned bytes, Address offset, unsigned align, Type type, Name mem) {
Store curr;
CHECK_ERR(visitStore(&curr));
- return push(
+ push(
builder.makeStore(bytes, offset, align, curr.ptr, curr.value, type, mem));
+ return Ok{};
}
Result<>
IRBuilder::makeAtomicLoad(unsigned bytes, Address offset, Type type, Name mem) {
Load curr;
CHECK_ERR(visitLoad(&curr));
- return push(builder.makeAtomicLoad(bytes, offset, curr.ptr, type, mem));
+ push(builder.makeAtomicLoad(bytes, offset, curr.ptr, type, mem));
+ return Ok{};
}
Result<> IRBuilder::makeAtomicStore(unsigned bytes,
@@ -348,16 +429,17 @@ Result<> IRBuilder::makeAtomicStore(unsigned bytes,
Name mem) {
Store curr;
CHECK_ERR(visitStore(&curr));
- return push(
- builder.makeAtomicStore(bytes, offset, curr.ptr, curr.value, type, mem));
+ push(builder.makeAtomicStore(bytes, offset, curr.ptr, curr.value, type, mem));
+ return Ok{};
}
Result<> IRBuilder::makeAtomicRMW(
AtomicRMWOp op, unsigned bytes, Address offset, Type type, Name mem) {
AtomicRMW curr;
CHECK_ERR(visitAtomicRMW(&curr));
- return push(
+ push(
builder.makeAtomicRMW(op, bytes, offset, curr.ptr, curr.value, type, mem));
+ return Ok{};
}
Result<> IRBuilder::makeAtomicCmpxchg(unsigned bytes,
@@ -366,56 +448,64 @@ Result<> IRBuilder::makeAtomicCmpxchg(unsigned bytes,
Name mem) {
AtomicCmpxchg curr;
CHECK_ERR(visitAtomicCmpxchg(&curr));
- return push(builder.makeAtomicCmpxchg(
+ push(builder.makeAtomicCmpxchg(
bytes, offset, curr.ptr, curr.expected, curr.replacement, type, mem));
+ return Ok{};
}
Result<> IRBuilder::makeAtomicWait(Type type, Address offset, Name mem) {
AtomicWait curr;
CHECK_ERR(visitAtomicWait(&curr));
- return push(builder.makeAtomicWait(
+ push(builder.makeAtomicWait(
curr.ptr, curr.expected, curr.timeout, type, offset, mem));
+ return Ok{};
}
Result<> IRBuilder::makeAtomicNotify(Address offset, Name mem) {
AtomicNotify curr;
CHECK_ERR(visitAtomicNotify(&curr));
- return push(
- builder.makeAtomicNotify(curr.ptr, curr.notifyCount, offset, mem));
+ push(builder.makeAtomicNotify(curr.ptr, curr.notifyCount, offset, mem));
+ return Ok{};
}
Result<> IRBuilder::makeAtomicFence() {
- return push(builder.makeAtomicFence());
+ push(builder.makeAtomicFence());
+ return Ok{};
}
Result<> IRBuilder::makeSIMDExtract(SIMDExtractOp op, uint8_t lane) {
SIMDExtract curr;
CHECK_ERR(visitSIMDExtract(&curr));
- return push(builder.makeSIMDExtract(op, curr.vec, lane));
+ push(builder.makeSIMDExtract(op, curr.vec, lane));
+ return Ok{};
}
Result<> IRBuilder::makeSIMDReplace(SIMDReplaceOp op, uint8_t lane) {
SIMDReplace curr;
CHECK_ERR(visitSIMDReplace(&curr));
- return push(builder.makeSIMDReplace(op, curr.vec, lane, curr.value));
+ push(builder.makeSIMDReplace(op, curr.vec, lane, curr.value));
+ return Ok{};
}
Result<> IRBuilder::makeSIMDShuffle(const std::array<uint8_t, 16>& lanes) {
SIMDShuffle curr;
CHECK_ERR(visitSIMDShuffle(&curr));
- return push(builder.makeSIMDShuffle(curr.left, curr.right, lanes));
+ push(builder.makeSIMDShuffle(curr.left, curr.right, lanes));
+ return Ok{};
}
Result<> IRBuilder::makeSIMDTernary(SIMDTernaryOp op) {
SIMDTernary curr;
CHECK_ERR(visitSIMDTernary(&curr));
- return push(builder.makeSIMDTernary(op, curr.a, curr.b, curr.c));
+ push(builder.makeSIMDTernary(op, curr.a, curr.b, curr.c));
+ return Ok{};
}
Result<> IRBuilder::makeSIMDShift(SIMDShiftOp op) {
SIMDShift curr;
CHECK_ERR(visitSIMDShift(&curr));
- return push(builder.makeSIMDShift(op, curr.vec, curr.shift));
+ push(builder.makeSIMDShift(op, curr.vec, curr.shift));
+ return Ok{};
}
Result<> IRBuilder::makeSIMDLoad(SIMDLoadOp op,
@@ -424,7 +514,8 @@ Result<> IRBuilder::makeSIMDLoad(SIMDLoadOp op,
Name mem) {
SIMDLoad curr;
CHECK_ERR(visitSIMDLoad(&curr));
- return push(builder.makeSIMDLoad(op, offset, align, curr.ptr, mem));
+ push(builder.makeSIMDLoad(op, offset, align, curr.ptr, mem));
+ return Ok{};
}
Result<> IRBuilder::makeSIMDLoadStoreLane(SIMDLoadStoreLaneOp op,
@@ -434,48 +525,55 @@ Result<> IRBuilder::makeSIMDLoadStoreLane(SIMDLoadStoreLaneOp op,
Name mem) {
SIMDLoadStoreLane curr;
CHECK_ERR(visitSIMDLoadStoreLane(&curr));
- return push(builder.makeSIMDLoadStoreLane(
+ push(builder.makeSIMDLoadStoreLane(
op, offset, align, lane, curr.ptr, curr.vec, mem));
+ return Ok{};
}
Result<> IRBuilder::makeMemoryInit(Name data, Name mem) {
MemoryInit curr;
CHECK_ERR(visitMemoryInit(&curr));
- return push(
- builder.makeMemoryInit(data, curr.dest, curr.offset, curr.size, mem));
+ push(builder.makeMemoryInit(data, curr.dest, curr.offset, curr.size, mem));
+ return Ok{};
}
Result<> IRBuilder::makeDataDrop(Name data) {
- return push(builder.makeDataDrop(data));
+ push(builder.makeDataDrop(data));
+ return Ok{};
}
Result<> IRBuilder::makeMemoryCopy(Name destMem, Name srcMem) {
MemoryCopy curr;
CHECK_ERR(visitMemoryCopy(&curr));
- return push(
+ push(
builder.makeMemoryCopy(curr.dest, curr.source, curr.size, destMem, srcMem));
+ return Ok{};
}
Result<> IRBuilder::makeMemoryFill(Name mem) {
MemoryFill curr;
CHECK_ERR(visitMemoryFill(&curr));
- return push(builder.makeMemoryFill(curr.dest, curr.value, curr.size, mem));
+ push(builder.makeMemoryFill(curr.dest, curr.value, curr.size, mem));
+ return Ok{};
}
Result<> IRBuilder::makeConst(Literal val) {
- return push(builder.makeConst(val));
+ push(builder.makeConst(val));
+ return Ok{};
}
Result<> IRBuilder::makeUnary(UnaryOp op) {
Unary curr;
CHECK_ERR(visitUnary(&curr));
- return push(builder.makeUnary(op, curr.value));
+ push(builder.makeUnary(op, curr.value));
+ return Ok{};
}
Result<> IRBuilder::makeBinary(BinaryOp op) {
Binary curr;
CHECK_ERR(visitBinary(&curr));
- return push(builder.makeBinary(op, curr.left, curr.right));
+ push(builder.makeBinary(op, curr.left, curr.right));
+ return Ok{};
}
Result<> IRBuilder::makeSelect(std::optional<Type> type) {
@@ -487,45 +585,53 @@ Result<> IRBuilder::makeSelect(std::optional<Type> type) {
if (type && !Type::isSubType(built->type, *type)) {
return Err{"select type does not match expected type"};
}
- return push(built);
+ push(built);
+ return Ok{};
}
Result<> IRBuilder::makeDrop() {
Drop curr;
CHECK_ERR(visitDrop(&curr));
- return push(builder.makeDrop(curr.value));
+ push(builder.makeDrop(curr.value));
+ return Ok{};
}
Result<> IRBuilder::makeReturn() {
Return curr;
CHECK_ERR(visitReturn(&curr));
- return push(builder.makeReturn(curr.value));
+ push(builder.makeReturn(curr.value));
+ return Ok{};
}
Result<> IRBuilder::makeMemorySize(Name mem) {
- return push(builder.makeMemorySize(mem));
+ push(builder.makeMemorySize(mem));
+ return Ok{};
}
Result<> IRBuilder::makeMemoryGrow(Name mem) {
MemoryGrow curr;
CHECK_ERR(visitMemoryGrow(&curr));
- return push(builder.makeMemoryGrow(curr.delta, mem));
+ push(builder.makeMemoryGrow(curr.delta, mem));
+ return Ok{};
}
Result<> IRBuilder::makeUnreachable() {
- return push(builder.makeUnreachable());
+ push(builder.makeUnreachable());
+ return Ok{};
}
// Result<> IRBuilder::makePop() {}
Result<> IRBuilder::makeRefNull(HeapType type) {
- return push(builder.makeRefNull(type));
+ push(builder.makeRefNull(type));
+ return Ok{};
}
Result<> IRBuilder::makeRefIsNull() {
RefIsNull curr;
CHECK_ERR(visitRefIsNull(&curr));
- return push(builder.makeRefIsNull(curr.value));
+ push(builder.makeRefIsNull(curr.value));
+ return Ok{};
}
// Result<> IRBuilder::makeRefFunc() {}
@@ -533,7 +639,8 @@ Result<> IRBuilder::makeRefIsNull() {
Result<> IRBuilder::makeRefEq() {
RefEq curr;
CHECK_ERR(visitRefEq(&curr));
- return push(builder.makeRefEq(curr.left, curr.right));
+ push(builder.makeRefEq(curr.left, curr.right));
+ return Ok{};
}
// Result<> IRBuilder::makeTableGet() {}
@@ -557,13 +664,15 @@ Result<> IRBuilder::makeRefEq() {
Result<> IRBuilder::makeI31New() {
I31New curr;
CHECK_ERR(visitI31New(&curr));
- return push(builder.makeI31New(curr.value));
+ push(builder.makeI31New(curr.value));
+ return Ok{};
}
Result<> IRBuilder::makeI31Get(bool signed_) {
I31Get curr;
CHECK_ERR(visitI31Get(&curr));
- return push(builder.makeI31Get(curr.i31, signed_));
+ push(builder.makeI31Get(curr.i31, signed_));
+ return Ok{};
}
// Result<> IRBuilder::makeCallRef() {}
@@ -579,11 +688,13 @@ Result<> IRBuilder::makeStructNew(HeapType type) {
// Differentiate from struct.new_default with a non-empty expression list.
curr.operands.resize(type.getStruct().fields.size());
CHECK_ERR(visitStructNew(&curr));
- return push(builder.makeStructNew(type, std::move(curr.operands)));
+ push(builder.makeStructNew(type, std::move(curr.operands)));
+ return Ok{};
}
Result<> IRBuilder::makeStructNewDefault(HeapType type) {
- return push(builder.makeStructNew(type, {}));
+ push(builder.makeStructNew(type, {}));
+ return Ok{};
}
Result<> IRBuilder::makeStructGet(HeapType type, Index field, bool signed_) {
@@ -591,15 +702,16 @@ Result<> IRBuilder::makeStructGet(HeapType type, Index field, bool signed_) {
StructGet curr;
CHECK_ERR(visitStructGet(&curr));
CHECK_ERR(validateTypeAnnotation(type, curr.ref));
- return push(
- builder.makeStructGet(field, curr.ref, fields[field].type, signed_));
+ push(builder.makeStructGet(field, curr.ref, fields[field].type, signed_));
+ return Ok{};
}
Result<> IRBuilder::makeStructSet(HeapType type, Index field) {
StructSet curr;
CHECK_ERR(visitStructSet(&curr));
CHECK_ERR(validateTypeAnnotation(type, curr.ref));
- return push(builder.makeStructSet(field, curr.ref, curr.value));
+ push(builder.makeStructSet(field, curr.ref, curr.value));
+ return Ok{};
}
Result<> IRBuilder::makeArrayNew(HeapType type) {
@@ -607,25 +719,29 @@ Result<> IRBuilder::makeArrayNew(HeapType type) {
// Differentiate from array.new_default with dummy initializer.
curr.init = (Expression*)0x01;
CHECK_ERR(visitArrayNew(&curr));
- return push(builder.makeArrayNew(type, curr.size, curr.init));
+ push(builder.makeArrayNew(type, curr.size, curr.init));
+ return Ok{};
}
Result<> IRBuilder::makeArrayNewDefault(HeapType type) {
ArrayNew curr;
CHECK_ERR(visitArrayNew(&curr));
- return push(builder.makeArrayNew(type, curr.size));
+ push(builder.makeArrayNew(type, curr.size));
+ return Ok{};
}
Result<> IRBuilder::makeArrayNewData(HeapType type, Name data) {
ArrayNewData curr;
CHECK_ERR(visitArrayNewData(&curr));
- return push(builder.makeArrayNewData(type, data, curr.offset, curr.size));
+ push(builder.makeArrayNewData(type, data, curr.offset, curr.size));
+ return Ok{};
}
Result<> IRBuilder::makeArrayNewElem(HeapType type, Name elem) {
ArrayNewElem curr;
CHECK_ERR(visitArrayNewElem(&curr));
- return push(builder.makeArrayNewElem(type, elem, curr.offset, curr.size));
+ push(builder.makeArrayNewElem(type, elem, curr.offset, curr.size));
+ return Ok{};
}
// Result<> IRBuilder::makeArrayNewFixed() {}
@@ -634,21 +750,24 @@ Result<> IRBuilder::makeArrayGet(HeapType type, bool signed_) {
ArrayGet curr;
CHECK_ERR(visitArrayGet(&curr));
CHECK_ERR(validateTypeAnnotation(type, curr.ref));
- return push(builder.makeArrayGet(
+ push(builder.makeArrayGet(
curr.ref, curr.index, type.getArray().element.type, signed_));
+ return Ok{};
}
Result<> IRBuilder::makeArraySet(HeapType type) {
ArraySet curr;
CHECK_ERR(visitArraySet(&curr));
CHECK_ERR(validateTypeAnnotation(type, curr.ref));
- return push(builder.makeArraySet(curr.ref, curr.index, curr.value));
+ push(builder.makeArraySet(curr.ref, curr.index, curr.value));
+ return Ok{};
}
Result<> IRBuilder::makeArrayLen() {
ArrayLen curr;
CHECK_ERR(visitArrayLen(&curr));
- return push(builder.makeArrayLen(curr.ref));
+ push(builder.makeArrayLen(curr.ref));
+ return Ok{};
}
Result<> IRBuilder::makeArrayCopy(HeapType destType, HeapType srcType) {
@@ -656,16 +775,17 @@ Result<> IRBuilder::makeArrayCopy(HeapType destType, HeapType srcType) {
CHECK_ERR(visitArrayCopy(&curr));
CHECK_ERR(validateTypeAnnotation(destType, curr.destRef));
CHECK_ERR(validateTypeAnnotation(srcType, curr.srcRef));
- return push(builder.makeArrayCopy(
+ push(builder.makeArrayCopy(
curr.destRef, curr.destIndex, curr.srcRef, curr.srcIndex, curr.length));
+ return Ok{};
}
Result<> IRBuilder::makeArrayFill(HeapType type) {
ArrayFill curr;
CHECK_ERR(visitArrayFill(&curr));
CHECK_ERR(validateTypeAnnotation(type, curr.ref));
- return push(
- builder.makeArrayFill(curr.ref, curr.index, curr.value, curr.size));
+ push(builder.makeArrayFill(curr.ref, curr.index, curr.value, curr.size));
+ return Ok{};
}
// Result<> IRBuilder::makeArrayInitData() {}