Skip to content

Commit 009851f

Browse files
tlivelyradekdoulik
authored andcommitted
[Parser] Parse tuple operations (WebAssembly#6174)
Parse `tuple.make`, `tuple.extract`, and `tuple.drop`. Also slightly improve the way we break up tuples into individual elements in IRBuilder by using a `local.tee` instead of a block containing a `local.set` and `local.get`.
1 parent 688cd37 commit 009851f

File tree

7 files changed

+194
-137
lines changed

7 files changed

+194
-137
lines changed

src/parser/contexts.h

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -430,6 +430,9 @@ struct NullInstrParserCtx {
430430
Result<> makeTableCopy(Index, TableIdxT*, TableIdxT*) { return Ok{}; }
431431
Result<> makeThrow(Index, TagIdxT) { return Ok{}; }
432432
Result<> makeRethrow(Index, LabelIdxT) { return Ok{}; }
433+
Result<> makeTupleMake(Index, uint32_t) { return Ok{}; }
434+
Result<> makeTupleExtract(Index, uint32_t, uint32_t) { return Ok{}; }
435+
Result<> makeTupleDrop(Index, uint32_t) { return Ok{}; }
433436
template<typename HeapTypeT> Result<> makeCallRef(Index, HeapTypeT, bool) {
434437
return Ok{};
435438
}
@@ -1624,6 +1627,18 @@ struct ParseDefsCtx : TypeParserCtx<ParseDefsCtx> {
16241627
return withLoc(pos, irBuilder.makeRethrow(label));
16251628
}
16261629

1630+
Result<> makeTupleMake(Index pos, uint32_t arity) {
1631+
return withLoc(pos, irBuilder.makeTupleMake(arity));
1632+
}
1633+
1634+
Result<> makeTupleExtract(Index pos, uint32_t arity, uint32_t index) {
1635+
return withLoc(pos, irBuilder.makeTupleExtract(arity, index));
1636+
}
1637+
1638+
Result<> makeTupleDrop(Index pos, uint32_t arity) {
1639+
return withLoc(pos, irBuilder.makeTupleDrop(arity));
1640+
}
1641+
16271642
Result<> makeCallRef(Index pos, HeapType type, bool isReturn) {
16281643
return withLoc(pos, irBuilder.makeCallRef(type, isReturn));
16291644
}

src/parser/parsers.h

Lines changed: 26 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ template<typename Ctx> Result<typename Ctx::LimitsT> limits64(Ctx&);
4141
template<typename Ctx> Result<typename Ctx::MemTypeT> memtype(Ctx&);
4242
template<typename Ctx> Result<typename Ctx::TableTypeT> tabletype(Ctx&);
4343
template<typename Ctx> Result<typename Ctx::GlobalTypeT> globaltype(Ctx&);
44+
template<typename Ctx> Result<uint32_t> tupleArity(Ctx&);
4445

4546
// Instructions
4647
template<typename Ctx> MaybeResult<> foldedBlockinstr(Ctx&);
@@ -605,6 +606,18 @@ template<typename Ctx> Result<typename Ctx::GlobalTypeT> globaltype(Ctx& ctx) {
605606
return ctx.makeGlobalType(mutability, *type);
606607
}
607608

609+
// arity ::= x:u32 (if x >=2 )
610+
template<typename Ctx> Result<uint32_t> tupleArity(Ctx& ctx) {
611+
auto arity = ctx.in.takeU32();
612+
if (!arity) {
613+
return ctx.in.err("expected tuple arity");
614+
}
615+
if (*arity < 2) {
616+
return ctx.in.err("tuple arity must be at least 2");
617+
}
618+
return *arity;
619+
}
620+
608621
// ============
609622
// Instructions
610623
// ============
@@ -1512,15 +1525,25 @@ template<typename Ctx> Result<> makeRethrow(Ctx& ctx, Index pos) {
15121525
}
15131526

15141527
template<typename Ctx> Result<> makeTupleMake(Ctx& ctx, Index pos) {
1515-
return ctx.in.err("unimplemented instruction");
1528+
auto arity = tupleArity(ctx);
1529+
CHECK_ERR(arity);
1530+
return ctx.makeTupleMake(pos, *arity);
15161531
}
15171532

15181533
template<typename Ctx> Result<> makeTupleExtract(Ctx& ctx, Index pos) {
1519-
return ctx.in.err("unimplemented instruction");
1534+
auto arity = tupleArity(ctx);
1535+
CHECK_ERR(arity);
1536+
auto index = ctx.in.takeU32();
1537+
if (!index) {
1538+
return ctx.in.err("expected tuple index");
1539+
}
1540+
return ctx.makeTupleExtract(pos, *arity, *index);
15201541
}
15211542

15221543
template<typename Ctx> Result<> makeTupleDrop(Ctx& ctx, Index pos) {
1523-
return ctx.in.err("unimplemented instruction");
1544+
auto arity = tupleArity(ctx);
1545+
CHECK_ERR(arity);
1546+
return ctx.makeTupleDrop(pos, *arity);
15241547
}
15251548

15261549
template<typename Ctx>

src/wasm-ir-builder.h

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -157,8 +157,9 @@ class IRBuilder : public UnifiedExpressionVisitor<IRBuilder, Result<>> {
157157
[[nodiscard]] Result<> makeTry(Name label, Type type);
158158
[[nodiscard]] Result<> makeThrow(Name tag);
159159
[[nodiscard]] Result<> makeRethrow(Index label);
160-
// [[nodiscard]] Result<> makeTupleMake();
161-
// [[nodiscard]] Result<> makeTupleExtract();
160+
[[nodiscard]] Result<> makeTupleMake(uint32_t arity);
161+
[[nodiscard]] Result<> makeTupleExtract(uint32_t arity, uint32_t index);
162+
[[nodiscard]] Result<> makeTupleDrop(uint32_t arity);
162163
[[nodiscard]] Result<> makeRefI31();
163164
[[nodiscard]] Result<> makeI31Get(bool signed_);
164165
[[nodiscard]] Result<> makeCallRef(HeapType type, bool isReturn);
@@ -217,6 +218,10 @@ class IRBuilder : public UnifiedExpressionVisitor<IRBuilder, Result<>> {
217218
[[nodiscard]] Result<> visitThrow(Throw*);
218219
[[nodiscard]] Result<> visitStringNew(StringNew*);
219220
[[nodiscard]] Result<> visitStringEncode(StringEncode*);
221+
[[nodiscard]] Result<> visitTupleMake(TupleMake*);
222+
[[nodiscard]] Result<>
223+
visitTupleExtract(TupleExtract*,
224+
std::optional<uint32_t> arity = std::nullopt);
220225

221226
private:
222227
Module& wasm;

src/wasm.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1501,6 +1501,7 @@ class TupleMake : public SpecificExpression<Expression::TupleMakeId> {
15011501

15021502
class TupleExtract : public SpecificExpression<Expression::TupleExtractId> {
15031503
public:
1504+
TupleExtract() = default;
15041505
TupleExtract(MixedArena& allocator) {}
15051506

15061507
Expression* tuple;

src/wasm/wasm-ir-builder.cpp

Lines changed: 54 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -107,17 +107,17 @@ Result<> IRBuilder::packageHoistedValue(const HoistedVal& hoisted,
107107

108108
auto type = scope.exprStack.back()->type;
109109

110-
if (type.size() == sizeHint) {
110+
if (type.size() == sizeHint || type.size() <= 1) {
111111
if (hoisted.get) {
112112
packageAsBlock(type);
113113
}
114114
return Ok{};
115115
}
116116

117-
// We need to break up the hoisted tuple. Create and push a block setting the
118-
// tuple to a local and returning its first element, then push additional gets
119-
// of each of its subsequent elements. Reuse the scratch local we used for
120-
// hoisting, if it exists.
117+
// We need to break up the hoisted tuple. Create and push an expression
118+
// setting the tuple to a local and returning its first element, then push
119+
// additional gets of each of its subsequent elements. Reuse the scratch local
120+
// we used for hoisting, if it exists.
121121
Index scratchIdx;
122122
if (hoisted.get) {
123123
// Update the get on top of the stack to just return the first element.
@@ -127,12 +127,8 @@ Result<> IRBuilder::packageHoistedValue(const HoistedVal& hoisted,
127127
} else {
128128
auto scratch = addScratchLocal(type);
129129
CHECK_ERR(scratch);
130-
auto* block = builder.makeSequence(
131-
builder.makeLocalSet(*scratch, scope.exprStack.back()),
132-
builder.makeTupleExtract(builder.makeLocalGet(*scratch, type), 0),
133-
type[0]);
134-
scope.exprStack.pop_back();
135-
push(block);
130+
scope.exprStack.back() = builder.makeTupleExtract(
131+
builder.makeLocalTee(*scratch, scope.exprStack.back(), type), 0);
136132
scratchIdx = *scratch;
137133
}
138134
for (Index i = 1, size = type.size(); i < size; ++i) {
@@ -560,6 +556,33 @@ Result<> IRBuilder::visitStringEncode(StringEncode* curr) {
560556
WASM_UNREACHABLE("unexpected op");
561557
}
562558

559+
Result<> IRBuilder::visitTupleMake(TupleMake* curr) {
560+
assert(curr->operands.size() >= 2);
561+
for (size_t i = 0, size = curr->operands.size(); i < size; ++i) {
562+
auto elem = pop();
563+
CHECK_ERR(elem);
564+
curr->operands[size - 1 - i] = *elem;
565+
}
566+
return Ok{};
567+
}
568+
569+
Result<> IRBuilder::visitTupleExtract(TupleExtract* curr,
570+
std::optional<uint32_t> arity) {
571+
if (!arity) {
572+
if (curr->tuple->type == Type::unreachable) {
573+
// Fallback to an arbitrary valid arity.
574+
arity = 2;
575+
} else {
576+
arity = curr->tuple->type.size();
577+
}
578+
}
579+
assert(*arity >= 2);
580+
auto tuple = pop(*arity);
581+
CHECK_ERR(tuple);
582+
curr->tuple = *tuple;
583+
return Ok{};
584+
}
585+
563586
Result<> IRBuilder::visitFunctionStart(Function* func) {
564587
if (!scopeStack.empty()) {
565588
return Err{"unexpected start of function"};
@@ -1332,9 +1355,27 @@ Result<> IRBuilder::makeRethrow(Index label) {
13321355
return Ok{};
13331356
}
13341357

1335-
// Result<> IRBuilder::makeTupleMake() {}
1358+
Result<> IRBuilder::makeTupleMake(uint32_t arity) {
1359+
TupleMake curr(wasm.allocator);
1360+
curr.operands.resize(arity);
1361+
CHECK_ERR(visitTupleMake(&curr));
1362+
push(builder.makeTupleMake(curr.operands));
1363+
return Ok{};
1364+
}
1365+
1366+
Result<> IRBuilder::makeTupleExtract(uint32_t arity, uint32_t index) {
1367+
TupleExtract curr;
1368+
CHECK_ERR(visitTupleExtract(&curr, arity));
1369+
push(builder.makeTupleExtract(curr.tuple, index));
1370+
return Ok{};
1371+
}
13361372

1337-
// Result<> IRBuilder::makeTupleExtract() {}
1373+
Result<> IRBuilder::makeTupleDrop(uint32_t arity) {
1374+
Drop curr;
1375+
CHECK_ERR(visitDrop(&curr, arity));
1376+
push(builder.makeDrop(curr.value));
1377+
return Ok{};
1378+
}
13381379

13391380
Result<> IRBuilder::makeRefI31() {
13401381
RefI31 curr;

test/lit/passes/outlining.wast

Lines changed: 4 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -645,13 +645,10 @@
645645
;; CHECK-NEXT: (local $scratch_1 (i32 i32))
646646
;; CHECK-NEXT: (drop
647647
;; CHECK-NEXT: (i32.add
648-
;; CHECK-NEXT: (block (result i32)
649-
;; CHECK-NEXT: (local.set $scratch
648+
;; CHECK-NEXT: (tuple.extract 2 0
649+
;; CHECK-NEXT: (local.tee $scratch
650650
;; CHECK-NEXT: (call $outline$)
651651
;; CHECK-NEXT: )
652-
;; CHECK-NEXT: (tuple.extract 2 0
653-
;; CHECK-NEXT: (local.get $scratch)
654-
;; CHECK-NEXT: )
655652
;; CHECK-NEXT: )
656653
;; CHECK-NEXT: (tuple.extract 2 1
657654
;; CHECK-NEXT: (local.get $scratch)
@@ -660,13 +657,10 @@
660657
;; CHECK-NEXT: )
661658
;; CHECK-NEXT: (drop
662659
;; CHECK-NEXT: (i32.mul
663-
;; CHECK-NEXT: (block (result i32)
664-
;; CHECK-NEXT: (local.set $scratch_1
660+
;; CHECK-NEXT: (tuple.extract 2 0
661+
;; CHECK-NEXT: (local.tee $scratch_1
665662
;; CHECK-NEXT: (call $outline$)
666663
;; CHECK-NEXT: )
667-
;; CHECK-NEXT: (tuple.extract 2 0
668-
;; CHECK-NEXT: (local.get $scratch_1)
669-
;; CHECK-NEXT: )
670664
;; CHECK-NEXT: )
671665
;; CHECK-NEXT: (tuple.extract 2 1
672666
;; CHECK-NEXT: (local.get $scratch_1)

0 commit comments

Comments
 (0)