@@ -80,15 +80,18 @@ class IRBuilder : public UnifiedExpressionVisitor<IRBuilder, Result<>> {
8080 // the corresponding `makeXYZ` function below instead of `visitXYZStart`, but
8181 // either way must call `visitEnd` and friends at the appropriate times.
8282 Result<> visitFunctionStart (Function* func);
83- Result<> visitBlockStart (Block* block);
84- Result<> visitIfStart (If* iff, Name label = {});
83+ Result<> visitBlockStart (Block* block, Type inputType = Type::none );
84+ Result<> visitIfStart (If* iff, Name label = {}, Type inputType = Type::none );
8585 Result<> visitElse ();
86- Result<> visitLoopStart (Loop* iff);
87- Result<> visitTryStart (Try* tryy, Name label = {});
86+ Result<> visitLoopStart (Loop* iff, Type inputType = Type::none);
87+ Result<>
88+ visitTryStart (Try* tryy, Name label = {}, Type inputType = Type::none);
8889 Result<> visitCatch (Name tag);
8990 Result<> visitCatchAll ();
9091 Result<> visitDelegate (Index label);
91- Result<> visitTryTableStart (TryTable* trytable, Name label = {});
92+ Result<> visitTryTableStart (TryTable* trytable,
93+ Name label = {},
94+ Type inputType = Type::none);
9295 Result<> visitEnd ();
9396
9497 // Used to visit break nodes when traversing a single block without its
@@ -113,9 +116,9 @@ class IRBuilder : public UnifiedExpressionVisitor<IRBuilder, Result<>> {
113116 // nodes. This is generally safer than calling `visit` because the function
114117 // signatures ensure that there are no missing fields.
115118 Result<> makeNop ();
116- Result<> makeBlock (Name label, Type type );
117- Result<> makeIf (Name label, Type type );
118- Result<> makeLoop (Name label, Type type );
119+ Result<> makeBlock (Name label, Signature sig );
120+ Result<> makeIf (Name label, Signature sig );
121+ Result<> makeLoop (Name label, Signature sig );
119122 Result<> makeBreak (Index label, bool isConditional);
120123 Result<> makeSwitch (const std::vector<Index>& labels, Index defaultLabel);
121124 // Unlike Builder::makeCall, this assumes the function already exists.
@@ -180,9 +183,9 @@ class IRBuilder : public UnifiedExpressionVisitor<IRBuilder, Result<>> {
180183 Result<> makeTableFill (Name table);
181184 Result<> makeTableCopy (Name destTable, Name srcTable);
182185 Result<> makeTableInit (Name elem, Name table);
183- Result<> makeTry (Name label, Type type );
186+ Result<> makeTry (Name label, Signature sig );
184187 Result<> makeTryTable (Name label,
185- Type type ,
188+ Signature sig ,
186189 const std::vector<Name>& tags,
187190 const std::vector<Index>& labels,
188191 const std::vector<bool >& isRefs);
@@ -323,13 +326,21 @@ class IRBuilder : public UnifiedExpressionVisitor<IRBuilder, Result<>> {
323326
324327 // The branch label name for this scope. Always fresh, never shadowed.
325328 Name label;
329+
326330 // For Try/Catch/CatchAll scopes, we need to separately track a label used
327331 // for branches, since the normal label is only used for delegates.
328332 Name branchLabel;
329333
330334 bool labelUsed = false ;
331335
336+ // If the control flow scope has an input type, we need to lower it using a
337+ // scratch local because we cannot represent control flow input in the IR.
338+ Type inputType;
339+ Index inputLocal = -1 ;
340+
341+ // The stack of instructions being built in this scope.
332342 std::vector<Expression*> exprStack;
343+
333344 // Whether we have seen an unreachable instruction and are in
334345 // stack-polymorphic unreachable mode.
335346 bool unreachable = false ;
@@ -338,29 +349,39 @@ class IRBuilder : public UnifiedExpressionVisitor<IRBuilder, Result<>> {
338349 size_t startPos = 0 ;
339350
340351 ScopeCtx () : scope(NoScope{}) {}
341- ScopeCtx (Scope scope) : scope(scope) {}
342- ScopeCtx (Scope scope, Name label, bool labelUsed)
343- : scope(scope), label(label), labelUsed(labelUsed) {}
352+ ScopeCtx (Scope scope, Type inputType)
353+ : scope(scope), inputType(inputType) {}
354+ ScopeCtx (
355+ Scope scope, Name label, bool labelUsed, Type inputType, Index inputLocal)
356+ : scope(scope), label(label), labelUsed(labelUsed), inputType(inputType),
357+ inputLocal (inputLocal) {}
344358 ScopeCtx (Scope scope, Name label, bool labelUsed, Name branchLabel)
345359 : scope(scope), label(label), branchLabel(branchLabel),
346360 labelUsed(labelUsed) {}
347361
348362 static ScopeCtx makeFunc (Function* func) {
349- return ScopeCtx (FuncScope{func});
363+ return ScopeCtx (FuncScope{func}, Type::none );
350364 }
351- static ScopeCtx makeBlock (Block* block) {
352- return ScopeCtx (BlockScope{block});
365+ static ScopeCtx makeBlock (Block* block, Type inputType ) {
366+ return ScopeCtx (BlockScope{block}, inputType );
353367 }
354- static ScopeCtx makeIf (If* iff, Name originalLabel = {} ) {
355- return ScopeCtx (IfScope{iff, originalLabel});
368+ static ScopeCtx makeIf (If* iff, Name originalLabel, Type inputType ) {
369+ return ScopeCtx (IfScope{iff, originalLabel}, inputType );
356370 }
357- static ScopeCtx
358- makeElse (If* iff, Name originalLabel, Name label, bool labelUsed) {
359- return ScopeCtx (ElseScope{iff, originalLabel}, label, labelUsed);
371+ static ScopeCtx makeElse (If* iff,
372+ Name originalLabel,
373+ Name label,
374+ bool labelUsed,
375+ Type inputType,
376+ Index inputLocal) {
377+ return ScopeCtx (
378+ ElseScope{iff, originalLabel}, label, labelUsed, inputType, inputLocal);
360379 }
361- static ScopeCtx makeLoop (Loop* loop) { return ScopeCtx (LoopScope{loop}); }
362- static ScopeCtx makeTry (Try* tryy, Name originalLabel = {}) {
363- return ScopeCtx (TryScope{tryy, originalLabel});
380+ static ScopeCtx makeLoop (Loop* loop, Type inputType) {
381+ return ScopeCtx (LoopScope{loop}, inputType);
382+ }
383+ static ScopeCtx makeTry (Try* tryy, Name originalLabel, Type inputType) {
384+ return ScopeCtx (TryScope{tryy, originalLabel}, inputType);
364385 }
365386 static ScopeCtx makeCatch (Try* tryy,
366387 Name originalLabel,
@@ -378,8 +399,9 @@ class IRBuilder : public UnifiedExpressionVisitor<IRBuilder, Result<>> {
378399 return ScopeCtx (
379400 CatchAllScope{tryy, originalLabel}, label, labelUsed, branchLabel);
380401 }
381- static ScopeCtx makeTryTable (TryTable* trytable, Name originalLabel = {}) {
382- return ScopeCtx (TryTableScope{trytable, originalLabel});
402+ static ScopeCtx
403+ makeTryTable (TryTable* trytable, Name originalLabel, Type inputType) {
404+ return ScopeCtx (TryTableScope{trytable, originalLabel}, inputType);
383405 }
384406
385407 bool isNone () { return std::get_if<NoScope>(&scope); }
@@ -518,6 +540,7 @@ class IRBuilder : public UnifiedExpressionVisitor<IRBuilder, Result<>> {
518540 }
519541 WASM_UNREACHABLE (" unexpected scope kind" );
520542 }
543+ bool isDelimiter () { return getElse () || getCatch () || getCatchAll (); }
521544 };
522545
523546 // The stack of block contexts currently being parsed.
@@ -541,7 +564,7 @@ class IRBuilder : public UnifiedExpressionVisitor<IRBuilder, Result<>> {
541564 Index blockHint = 0 ;
542565 Index labelHint = 0 ;
543566
544- void pushScope (ScopeCtx scope) {
567+ Result<> pushScope (ScopeCtx&& scope) {
545568 if (auto label = scope.getOriginalLabel ()) {
546569 // Assign a fresh label to the scope, if necessary.
547570 if (!scope.label ) {
@@ -554,7 +577,21 @@ class IRBuilder : public UnifiedExpressionVisitor<IRBuilder, Result<>> {
554577 scope.startPos = lastBinaryPos;
555578 lastBinaryPos = *binaryPos;
556579 }
557- scopeStack.push_back (scope);
580+ bool hasInput = scope.inputType != Type::none;
581+ Index inputLocal = scope.inputLocal ;
582+ if (hasInput && !scope.isDelimiter ()) {
583+ if (inputLocal == Index (-1 )) {
584+ auto scratch = addScratchLocal (scope.inputType );
585+ CHECK_ERR (scratch);
586+ inputLocal = scope.inputLocal = *scratch;
587+ }
588+ CHECK_ERR (makeLocalSet (inputLocal));
589+ }
590+ scopeStack.emplace_back (std::move (scope));
591+ if (hasInput) {
592+ CHECK_ERR (makeLocalGet (inputLocal));
593+ }
594+ return Ok{};
558595 }
559596
560597 ScopeCtx& getScope () {
@@ -610,6 +647,8 @@ class IRBuilder : public UnifiedExpressionVisitor<IRBuilder, Result<>> {
610647 Result<Type> getLabelType (Index label);
611648 Result<Type> getLabelType (Name labelName);
612649
650+ void fixLoopWithInput (Loop* loop, Type inputType, Index scratch);
651+
613652 void dump ();
614653};
615654
0 commit comments