Skip to content

Commit c290aad

Browse files
authored
[Parser] Support loops (#5966)
Parse loops in the new wat parser and add support for them to the IRBuilder.
1 parent 38197b5 commit c290aad

File tree

5 files changed

+333
-55
lines changed

5 files changed

+333
-55
lines changed

src/parser/contexts.h

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -309,8 +309,12 @@ struct NullInstrParserCtx {
309309
Result<> makeIf(Index, std::optional<Name>, BlockTypeT) {
310310
return Ok{};
311311
}
312-
Result<> visitEnd(Index) { return Ok{}; }
313-
Result<> visitElse(Index) { return Ok{}; }
312+
Result<> visitElse() { return Ok{}; }
313+
template<typename BlockTypeT>
314+
Result<> makeLoop(Index, std::optional<Name>, BlockTypeT) {
315+
return Ok{};
316+
}
317+
Result<> visitEnd() { return Ok{}; }
314318

315319
Result<> makeUnreachable(Index) { return Ok{}; }
316320
Result<> makeNop(Index) { return Ok{}; }
@@ -989,9 +993,17 @@ struct ParseDefsCtx : TypeParserCtx<ParseDefsCtx> {
989993
irBuilder.makeIf(label ? *label : Name{}, type.getSignature().results));
990994
}
991995

992-
Result<> visitEnd(Index pos) { return withLoc(pos, irBuilder.visitEnd()); }
996+
Result<> visitElse() { return withLoc(irBuilder.visitElse()); }
997+
998+
Result<> makeLoop(Index pos, std::optional<Name> label, HeapType type) {
999+
// TODO: validate labels?
1000+
// TODO: Move error on input types to here?
1001+
return withLoc(
1002+
pos,
1003+
irBuilder.makeLoop(label ? *label : Name{}, type.getSignature().results));
1004+
}
9931005

994-
Result<> visitElse(Index pos) { return withLoc(pos, irBuilder.visitElse()); }
1006+
Result<> visitEnd() { return withLoc(irBuilder.visitEnd()); }
9951007

9961008
Result<> makeUnreachable(Index pos) {
9971009
return withLoc(pos, irBuilder.makeUnreachable());

src/parser/parsers.h

Lines changed: 53 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@ template<typename Ctx> Result<typename Ctx::MemargT> memarg(Ctx&, uint32_t);
5555
template<typename Ctx> Result<typename Ctx::BlockTypeT> blocktype(Ctx&);
5656
template<typename Ctx> MaybeResult<> block(Ctx&, bool);
5757
template<typename Ctx> MaybeResult<> ifelse(Ctx&, bool);
58+
template<typename Ctx> MaybeResult<> loop(Ctx&, bool);
5859
template<typename Ctx> Result<> makeUnreachable(Ctx&, Index);
5960
template<typename Ctx> Result<> makeNop(Ctx&, Index);
6061
template<typename Ctx> Result<> makeBinary(Ctx&, Index, BinaryOp op);
@@ -553,6 +554,9 @@ template<typename Ctx> MaybeResult<> foldedBlockinstr(Ctx& ctx) {
553554
if (auto i = ifelse(ctx, true)) {
554555
return i;
555556
}
557+
if (auto i = loop(ctx, true)) {
558+
return i;
559+
}
556560
// TODO: Other block instructions
557561
return {};
558562
}
@@ -564,6 +568,9 @@ template<typename Ctx> MaybeResult<> unfoldedBlockinstr(Ctx& ctx) {
564568
if (auto i = ifelse(ctx, false)) {
565569
return i;
566570
}
571+
if (auto i = loop(ctx, false)) {
572+
return i;
573+
}
567574
// TODO: Other block instructions
568575
return {};
569576
}
@@ -741,14 +748,9 @@ template<typename Ctx> Result<typename Ctx::BlockTypeT> blocktype(Ctx& ctx) {
741748
template<typename Ctx> MaybeResult<> block(Ctx& ctx, bool folded) {
742749
auto pos = ctx.in.getPos();
743750

744-
if (folded) {
745-
if (!ctx.in.takeSExprStart("block"sv)) {
746-
return {};
747-
}
748-
} else {
749-
if (!ctx.in.takeKeyword("block"sv)) {
750-
return {};
751-
}
751+
if ((folded && !ctx.in.takeSExprStart("block"sv)) ||
752+
(!folded && !ctx.in.takeKeyword("block"sv))) {
753+
return {};
752754
}
753755

754756
auto label = ctx.in.takeID();
@@ -774,7 +776,7 @@ template<typename Ctx> MaybeResult<> block(Ctx& ctx, bool folded) {
774776
}
775777
}
776778

777-
return ctx.visitEnd(pos);
779+
return ctx.visitEnd();
778780
}
779781

780782
// if ::= 'if' label blocktype instr1* ('else' id1? instr2*)? 'end' id2?
@@ -783,14 +785,9 @@ template<typename Ctx> MaybeResult<> block(Ctx& ctx, bool folded) {
783785
template<typename Ctx> MaybeResult<> ifelse(Ctx& ctx, bool folded) {
784786
auto pos = ctx.in.getPos();
785787

786-
if (folded) {
787-
if (!ctx.in.takeSExprStart("if"sv)) {
788-
return {};
789-
}
790-
} else {
791-
if (!ctx.in.takeKeyword("if"sv)) {
792-
return {};
793-
}
788+
if ((folded && !ctx.in.takeSExprStart("if"sv)) ||
789+
(!folded && !ctx.in.takeKeyword("if"sv))) {
790+
return {};
794791
}
795792

796793
auto label = ctx.in.takeID();
@@ -821,7 +818,7 @@ template<typename Ctx> MaybeResult<> ifelse(Ctx& ctx, bool folded) {
821818
return ctx.in.err("else label does not match if label");
822819
}
823820

824-
ctx.visitElse(pos);
821+
ctx.visitElse();
825822

826823
CHECK_ERR(instrs(ctx));
827824

@@ -838,14 +835,48 @@ template<typename Ctx> MaybeResult<> ifelse(Ctx& ctx, bool folded) {
838835
if (!ctx.in.takeKeyword("end"sv)) {
839836
return ctx.in.err("expected 'end' at end of if");
840837
}
838+
auto id2 = ctx.in.takeID();
839+
if (id2 && id2 != label) {
840+
return ctx.in.err("end label does not match if label");
841+
}
841842
}
842843

843-
auto id2 = ctx.in.takeID();
844-
if (id2 && id2 != label) {
845-
return ctx.in.err("end label does not match if label");
844+
return ctx.visitEnd();
845+
}
846+
847+
// loop ::= 'loop' label blocktype instr* end id?
848+
// | '(' 'loop' label blocktype instr* ')'
849+
template<typename Ctx> MaybeResult<> loop(Ctx& ctx, bool folded) {
850+
auto pos = ctx.in.getPos();
851+
852+
if ((folded && !ctx.in.takeSExprStart("loop"sv)) ||
853+
(!folded && !ctx.in.takeKeyword("loop"sv))) {
854+
return {};
846855
}
847856

848-
return ctx.visitEnd(pos);
857+
auto label = ctx.in.takeID();
858+
859+
auto type = blocktype(ctx);
860+
CHECK_ERR(type);
861+
862+
ctx.makeLoop(pos, label, *type);
863+
864+
CHECK_ERR(instrs(ctx));
865+
866+
if (folded) {
867+
if (!ctx.in.takeRParen()) {
868+
return ctx.in.err("expected ')' at end of loop");
869+
}
870+
} else {
871+
if (!ctx.in.takeKeyword("end"sv)) {
872+
return ctx.in.err("expected 'end' at end of loop");
873+
}
874+
auto id = ctx.in.takeID();
875+
if (id && id != label) {
876+
return ctx.in.err("end label does not match loop label");
877+
}
878+
}
879+
return ctx.visitEnd();
849880
}
850881

851882
template<typename Ctx> Result<> makeUnreachable(Ctx& ctx, Index pos) {

src/wasm-ir-builder.h

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@ class IRBuilder : public UnifiedExpressionVisitor<IRBuilder, Result<>> {
5454
[[nodiscard]] Result<> visitBlockStart(Block* block);
5555
[[nodiscard]] Result<> visitIfStart(If* iff, Name label = {});
5656
[[nodiscard]] Result<> visitElse();
57+
[[nodiscard]] Result<> visitLoopStart(Loop* iff);
5758
[[nodiscard]] Result<> visitEnd();
5859

5960
// Alternatively, call makeXYZ to have the IRBuilder allocate the nodes. This
@@ -62,7 +63,7 @@ class IRBuilder : public UnifiedExpressionVisitor<IRBuilder, Result<>> {
6263
[[nodiscard]] Result<> makeNop();
6364
[[nodiscard]] Result<> makeBlock(Name label, Type type);
6465
[[nodiscard]] Result<> makeIf(Name label, Type type);
65-
// [[nodiscard]] Result<> makeLoop();
66+
[[nodiscard]] Result<> makeLoop(Name label, Type type);
6667
// [[nodiscard]] Result<> makeBreak();
6768
// [[nodiscard]] Result<> makeSwitch();
6869
// [[nodiscard]] Result<> makeCall();
@@ -199,7 +200,11 @@ class IRBuilder : public UnifiedExpressionVisitor<IRBuilder, Result<>> {
199200
If* iff;
200201
Name label;
201202
};
202-
using Scope = std::variant<NoScope, BlockScope, IfScope, ElseScope>;
203+
struct LoopScope {
204+
Loop* loop;
205+
};
206+
using Scope =
207+
std::variant<NoScope, BlockScope, IfScope, ElseScope, LoopScope>;
203208

204209
// The control flow structure we are building expressions for.
205210
Scope scope;
@@ -221,6 +226,7 @@ class IRBuilder : public UnifiedExpressionVisitor<IRBuilder, Result<>> {
221226
static ScopeCtx makeElse(If* iff, Name label = {}) {
222227
return ScopeCtx(ElseScope{iff, label});
223228
}
229+
static ScopeCtx makeLoop(Loop* loop) { return ScopeCtx(LoopScope{loop}); }
224230

225231
bool isNone() { return std::get_if<NoScope>(&scope); }
226232
Block* getBlock() {
@@ -241,6 +247,12 @@ class IRBuilder : public UnifiedExpressionVisitor<IRBuilder, Result<>> {
241247
}
242248
return nullptr;
243249
}
250+
Loop* getLoop() {
251+
if (auto* loopScope = std::get_if<LoopScope>(&scope)) {
252+
return loopScope->loop;
253+
}
254+
return nullptr;
255+
}
244256
Type getResultType() {
245257
if (auto* block = getBlock()) {
246258
return block->type;
@@ -251,6 +263,9 @@ class IRBuilder : public UnifiedExpressionVisitor<IRBuilder, Result<>> {
251263
if (auto* iff = getElse()) {
252264
return iff->type;
253265
}
266+
if (auto* loop = getLoop()) {
267+
return loop->type;
268+
}
254269
WASM_UNREACHABLE("unexpected scope kind");
255270
}
256271
Name getLabel() {
@@ -263,6 +278,9 @@ class IRBuilder : public UnifiedExpressionVisitor<IRBuilder, Result<>> {
263278
if (auto* elseScope = std::get_if<ElseScope>(&scope)) {
264279
return elseScope->label;
265280
}
281+
if (auto* loop = getLoop()) {
282+
return loop->name;
283+
}
266284
WASM_UNREACHABLE("unexpected scope kind");
267285
}
268286
};

src/wasm/wasm-ir-builder.cpp

Lines changed: 20 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -294,6 +294,11 @@ Result<> IRBuilder::visitIfStart(If* iff, Name label) {
294294
return Ok{};
295295
}
296296

297+
Result<> IRBuilder::visitLoopStart(Loop* loop) {
298+
scopeStack.push_back(ScopeCtx::makeLoop(loop));
299+
return Ok{};
300+
}
301+
297302
Result<Expression*> IRBuilder::finishScope(Block* block) {
298303
if (scopeStack.empty() || scopeStack.back().isNone()) {
299304
return Err{"unexpected end of scope"};
@@ -403,6 +408,13 @@ Result<> IRBuilder::visitEnd() {
403408
block->finalize(block->type);
404409
push(block);
405410
return Ok{};
411+
} else if (auto* loop = scope.getLoop()) {
412+
auto expr = finishScope();
413+
CHECK_ERR(expr);
414+
loop->body = *expr;
415+
loop->finalize(loop->type);
416+
push(loop);
417+
return Ok{};
406418
}
407419
auto label = scope.getLabel();
408420
Expression* scopeExpr = nullptr;
@@ -411,13 +423,13 @@ Result<> IRBuilder::visitEnd() {
411423
CHECK_ERR(expr);
412424
iff->ifTrue = *expr;
413425
iff->ifFalse = nullptr;
414-
iff->finalize();
426+
iff->finalize(iff->type);
415427
scopeExpr = iff;
416428
} else if (auto* iff = scope.getElse()) {
417429
auto expr = finishScope();
418430
CHECK_ERR(expr);
419431
iff->ifFalse = *expr;
420-
iff->finalize();
432+
iff->finalize(iff->type);
421433
scopeExpr = iff;
422434
}
423435
assert(scopeExpr && "unexpected scope kind");
@@ -449,9 +461,12 @@ Result<> IRBuilder::makeIf(Name label, Type type) {
449461
return visitIfStart(iff, label);
450462
}
451463

452-
// Result<> IRBuilder::makeIf() {}
453-
454-
// Result<> IRBuilder::makeLoop() {}
464+
Result<> IRBuilder::makeLoop(Name label, Type type) {
465+
auto* loop = wasm.allocator.alloc<Loop>();
466+
loop->name = label;
467+
loop->type = type;
468+
return visitLoopStart(loop);
469+
}
455470

456471
// Result<> IRBuilder::makeBreak() {}
457472

0 commit comments

Comments
 (0)