diff options
Diffstat (limited to 'src/wasm-ir-builder.h')
-rw-r--r-- | src/wasm-ir-builder.h | 95 |
1 files changed, 67 insertions, 28 deletions
diff --git a/src/wasm-ir-builder.h b/src/wasm-ir-builder.h index 84ac26979..250d5d17c 100644 --- a/src/wasm-ir-builder.h +++ b/src/wasm-ir-builder.h @@ -80,15 +80,18 @@ public: // the corresponding `makeXYZ` function below instead of `visitXYZStart`, but // either way must call `visitEnd` and friends at the appropriate times. Result<> visitFunctionStart(Function* func); - Result<> visitBlockStart(Block* block); - Result<> visitIfStart(If* iff, Name label = {}); + Result<> visitBlockStart(Block* block, Type inputType = Type::none); + Result<> visitIfStart(If* iff, Name label = {}, Type inputType = Type::none); Result<> visitElse(); - Result<> visitLoopStart(Loop* iff); - Result<> visitTryStart(Try* tryy, Name label = {}); + Result<> visitLoopStart(Loop* iff, Type inputType = Type::none); + Result<> + visitTryStart(Try* tryy, Name label = {}, Type inputType = Type::none); Result<> visitCatch(Name tag); Result<> visitCatchAll(); Result<> visitDelegate(Index label); - Result<> visitTryTableStart(TryTable* trytable, Name label = {}); + Result<> visitTryTableStart(TryTable* trytable, + Name label = {}, + Type inputType = Type::none); Result<> visitEnd(); // Used to visit break nodes when traversing a single block without its @@ -113,9 +116,9 @@ public: // nodes. This is generally safer than calling `visit` because the function // signatures ensure that there are no missing fields. Result<> makeNop(); - Result<> makeBlock(Name label, Type type); - Result<> makeIf(Name label, Type type); - Result<> makeLoop(Name label, Type type); + Result<> makeBlock(Name label, Signature sig); + Result<> makeIf(Name label, Signature sig); + Result<> makeLoop(Name label, Signature sig); Result<> makeBreak(Index label, bool isConditional); Result<> makeSwitch(const std::vector<Index>& labels, Index defaultLabel); // Unlike Builder::makeCall, this assumes the function already exists. @@ -180,9 +183,9 @@ public: Result<> makeTableFill(Name table); Result<> makeTableCopy(Name destTable, Name srcTable); Result<> makeTableInit(Name elem, Name table); - Result<> makeTry(Name label, Type type); + Result<> makeTry(Name label, Signature sig); Result<> makeTryTable(Name label, - Type type, + Signature sig, const std::vector<Name>& tags, const std::vector<Index>& labels, const std::vector<bool>& isRefs); @@ -323,13 +326,21 @@ private: // The branch label name for this scope. Always fresh, never shadowed. Name label; + // For Try/Catch/CatchAll scopes, we need to separately track a label used // for branches, since the normal label is only used for delegates. Name branchLabel; bool labelUsed = false; + // If the control flow scope has an input type, we need to lower it using a + // scratch local because we cannot represent control flow input in the IR. + Type inputType; + Index inputLocal = -1; + + // The stack of instructions being built in this scope. std::vector<Expression*> exprStack; + // Whether we have seen an unreachable instruction and are in // stack-polymorphic unreachable mode. bool unreachable = false; @@ -338,29 +349,39 @@ private: size_t startPos = 0; ScopeCtx() : scope(NoScope{}) {} - ScopeCtx(Scope scope) : scope(scope) {} - ScopeCtx(Scope scope, Name label, bool labelUsed) - : scope(scope), label(label), labelUsed(labelUsed) {} + ScopeCtx(Scope scope, Type inputType) + : scope(scope), inputType(inputType) {} + ScopeCtx( + Scope scope, Name label, bool labelUsed, Type inputType, Index inputLocal) + : scope(scope), label(label), labelUsed(labelUsed), inputType(inputType), + inputLocal(inputLocal) {} ScopeCtx(Scope scope, Name label, bool labelUsed, Name branchLabel) : scope(scope), label(label), branchLabel(branchLabel), labelUsed(labelUsed) {} static ScopeCtx makeFunc(Function* func) { - return ScopeCtx(FuncScope{func}); + return ScopeCtx(FuncScope{func}, Type::none); } - static ScopeCtx makeBlock(Block* block) { - return ScopeCtx(BlockScope{block}); + static ScopeCtx makeBlock(Block* block, Type inputType) { + return ScopeCtx(BlockScope{block}, inputType); } - static ScopeCtx makeIf(If* iff, Name originalLabel = {}) { - return ScopeCtx(IfScope{iff, originalLabel}); + static ScopeCtx makeIf(If* iff, Name originalLabel, Type inputType) { + return ScopeCtx(IfScope{iff, originalLabel}, inputType); } - static ScopeCtx - makeElse(If* iff, Name originalLabel, Name label, bool labelUsed) { - return ScopeCtx(ElseScope{iff, originalLabel}, label, labelUsed); + static ScopeCtx makeElse(If* iff, + Name originalLabel, + Name label, + bool labelUsed, + Type inputType, + Index inputLocal) { + return ScopeCtx( + ElseScope{iff, originalLabel}, label, labelUsed, inputType, inputLocal); } - static ScopeCtx makeLoop(Loop* loop) { return ScopeCtx(LoopScope{loop}); } - static ScopeCtx makeTry(Try* tryy, Name originalLabel = {}) { - return ScopeCtx(TryScope{tryy, originalLabel}); + static ScopeCtx makeLoop(Loop* loop, Type inputType) { + return ScopeCtx(LoopScope{loop}, inputType); + } + static ScopeCtx makeTry(Try* tryy, Name originalLabel, Type inputType) { + return ScopeCtx(TryScope{tryy, originalLabel}, inputType); } static ScopeCtx makeCatch(Try* tryy, Name originalLabel, @@ -378,8 +399,9 @@ private: return ScopeCtx( CatchAllScope{tryy, originalLabel}, label, labelUsed, branchLabel); } - static ScopeCtx makeTryTable(TryTable* trytable, Name originalLabel = {}) { - return ScopeCtx(TryTableScope{trytable, originalLabel}); + static ScopeCtx + makeTryTable(TryTable* trytable, Name originalLabel, Type inputType) { + return ScopeCtx(TryTableScope{trytable, originalLabel}, inputType); } bool isNone() { return std::get_if<NoScope>(&scope); } @@ -518,6 +540,7 @@ private: } WASM_UNREACHABLE("unexpected scope kind"); } + bool isDelimiter() { return getElse() || getCatch() || getCatchAll(); } }; // The stack of block contexts currently being parsed. @@ -541,7 +564,7 @@ private: Index blockHint = 0; Index labelHint = 0; - void pushScope(ScopeCtx scope) { + Result<> pushScope(ScopeCtx&& scope) { if (auto label = scope.getOriginalLabel()) { // Assign a fresh label to the scope, if necessary. if (!scope.label) { @@ -554,7 +577,21 @@ private: scope.startPos = lastBinaryPos; lastBinaryPos = *binaryPos; } - scopeStack.push_back(scope); + bool hasInput = scope.inputType != Type::none; + Index inputLocal = scope.inputLocal; + if (hasInput && !scope.isDelimiter()) { + if (inputLocal == Index(-1)) { + auto scratch = addScratchLocal(scope.inputType); + CHECK_ERR(scratch); + inputLocal = scope.inputLocal = *scratch; + } + CHECK_ERR(makeLocalSet(inputLocal)); + } + scopeStack.emplace_back(std::move(scope)); + if (hasInput) { + CHECK_ERR(makeLocalGet(inputLocal)); + } + return Ok{}; } ScopeCtx& getScope() { @@ -610,6 +647,8 @@ private: Result<Type> getLabelType(Index label); Result<Type> getLabelType(Name labelName); + void fixLoopWithInput(Loop* loop, Type inputType, Index scratch); + void dump(); }; |