Skip to content

Commit 98cef80

Browse files
authored
Unify method pairs with and without Type param (#6184)
As suggested in #6181 (comment), using `std::optional<Type>`, this unifies two different versions of `make***`, for block-like structures (`block`, `if`, `loop`, `try`, and `try_table`) with and without a type parameter. This also allows unifying of `finalize` methods, with and without a type. This also sets `breakability` argument of `Block::finalize` to `Unknown` so we can only have one `Block::finalize` that handles all cases. This also adds an optional `std::optional<Type> type` parameter to `blockifyWithName`, and `makeSequence` functions in `wasm-builder.h`. blockify was not included because it has a variadic parameter.
1 parent fb7d00b commit 98cef80

File tree

4 files changed

+125
-195
lines changed

4 files changed

+125
-195
lines changed

src/wasm-builder.h

Lines changed: 40 additions & 94 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
#include "ir/manipulation.h"
2121
#include "parsing.h"
2222
#include "wasm.h"
23+
#include <optional>
2324

2425
namespace wasm {
2526

@@ -189,69 +190,47 @@ class Builder {
189190
bool>;
190191

191192
template<typename T, bool_if_not_expr_t<T> = true>
192-
Block* makeBlock(const T& items) {
193-
auto* ret = wasm.allocator.alloc<Block>();
194-
ret->list.set(items);
195-
ret->finalize();
196-
return ret;
197-
}
198-
199-
template<typename T, bool_if_not_expr_t<T> = true>
200-
Block* makeBlock(const T& items, Type type) {
193+
Block* makeBlock(const T& items, std::optional<Type> type = std::nullopt) {
201194
auto* ret = wasm.allocator.alloc<Block>();
202195
ret->list.set(items);
203196
ret->finalize(type);
204197
return ret;
205198
}
206199

207200
template<typename T, bool_if_not_expr_t<T> = true>
208-
Block* makeBlock(Name name, const T& items, Type type) {
201+
Block* makeBlock(Name name,
202+
const T& items,
203+
std::optional<Type> type = std::nullopt) {
209204
auto* ret = wasm.allocator.alloc<Block>();
210205
ret->name = name;
211206
ret->list.set(items);
212207
ret->finalize(type);
213208
return ret;
214209
}
215-
Block* makeBlock(std::initializer_list<Expression*>&& items) {
216-
return makeBlock(items);
217-
}
218-
Block* makeBlock(std::initializer_list<Expression*>&& items, Type type) {
210+
Block* makeBlock(std::initializer_list<Expression*>&& items,
211+
std::optional<Type> type = std::nullopt) {
219212
return makeBlock(items, type);
220213
}
221-
Block*
222-
makeBlock(Name name, std::initializer_list<Expression*>&& items, Type type) {
214+
Block* makeBlock(Name name,
215+
std::initializer_list<Expression*>&& items,
216+
std::optional<Type> type = std::nullopt) {
223217
return makeBlock(name, items, type);
224218
}
225219

226220
If* makeIf(Expression* condition,
227221
Expression* ifTrue,
228-
Expression* ifFalse = nullptr) {
229-
auto* ret = wasm.allocator.alloc<If>();
230-
ret->condition = condition;
231-
ret->ifTrue = ifTrue;
232-
ret->ifFalse = ifFalse;
233-
ret->finalize();
234-
return ret;
235-
}
236-
If* makeIf(Expression* condition,
237-
Expression* ifTrue,
238-
Expression* ifFalse,
239-
Type type) {
222+
Expression* ifFalse = nullptr,
223+
std::optional<Type> type = std::nullopt) {
240224
auto* ret = wasm.allocator.alloc<If>();
241225
ret->condition = condition;
242226
ret->ifTrue = ifTrue;
243227
ret->ifFalse = ifFalse;
244228
ret->finalize(type);
245229
return ret;
246230
}
247-
Loop* makeLoop(Name name, Expression* body) {
248-
auto* ret = wasm.allocator.alloc<Loop>();
249-
ret->name = name;
250-
ret->body = body;
251-
ret->finalize();
252-
return ret;
253-
}
254-
Loop* makeLoop(Name name, Expression* body, Type type) {
231+
Loop* makeLoop(Name name,
232+
Expression* body,
233+
std::optional<Type> type = std::nullopt) {
255234
auto* ret = wasm.allocator.alloc<Loop>();
256235
ret->name = name;
257236
ret->body = body;
@@ -792,77 +771,47 @@ class Builder {
792771
const std::vector<Name>& catchTags,
793772
const std::vector<Expression*>& catchBodies,
794773
Name delegateTarget,
795-
Type type,
796-
bool hasType) { // differentiate whether a type was passed in
774+
std::optional<Type> type = std::nullopt) {
797775
auto* ret = wasm.allocator.alloc<Try>();
798776
ret->name = name;
799777
ret->body = body;
800778
ret->catchTags.set(catchTags);
801779
ret->catchBodies.set(catchBodies);
802-
if (hasType) {
803-
ret->finalize(type);
804-
} else {
805-
ret->finalize();
806-
}
780+
ret->finalize(type);
807781
return ret;
808782
}
809783

810784
public:
811-
Try* makeTry(Expression* body,
812-
const std::vector<Name>& catchTags,
813-
const std::vector<Expression*>& catchBodies) {
814-
return makeTry(
815-
Name(), body, catchTags, catchBodies, Name(), Type::none, false);
816-
}
785+
// TODO delete?
817786
Try* makeTry(Expression* body,
818787
const std::vector<Name>& catchTags,
819788
const std::vector<Expression*>& catchBodies,
820-
Type type) {
821-
return makeTry(Name(), body, catchTags, catchBodies, Name(), type, true);
822-
}
823-
Try* makeTry(Name name,
824-
Expression* body,
825-
const std::vector<Name>& catchTags,
826-
const std::vector<Expression*>& catchBodies) {
827-
return makeTry(
828-
name, body, catchTags, catchBodies, Name(), Type::none, false);
789+
std::optional<Type> type = std::nullopt) {
790+
return makeTry(Name(), body, catchTags, catchBodies, Name(), type);
829791
}
830792
Try* makeTry(Name name,
831793
Expression* body,
832794
const std::vector<Name>& catchTags,
833795
const std::vector<Expression*>& catchBodies,
834-
Type type) {
835-
return makeTry(name, body, catchTags, catchBodies, Name(), type, true);
836-
}
837-
Try* makeTry(Expression* body, Name delegateTarget) {
838-
return makeTry(Name(), body, {}, {}, delegateTarget, Type::none, false);
839-
}
840-
Try* makeTry(Expression* body, Name delegateTarget, Type type) {
841-
return makeTry(Name(), body, {}, {}, delegateTarget, type, true);
796+
std::optional<Type> type = std::nullopt) {
797+
return makeTry(name, body, catchTags, catchBodies, Name(), type);
842798
}
843-
Try* makeTry(Name name, Expression* body, Name delegateTarget) {
844-
return makeTry(name, body, {}, {}, delegateTarget, Type::none, false);
845-
}
846-
Try* makeTry(Name name, Expression* body, Name delegateTarget, Type type) {
847-
return makeTry(name, body, {}, {}, delegateTarget, type, true);
799+
Try* makeTry(Expression* body,
800+
Name delegateTarget,
801+
std::optional<Type> type = std::nullopt) {
802+
return makeTry(Name(), body, {}, {}, delegateTarget, type);
848803
}
849-
TryTable* makeTryTable(Expression* body,
850-
const std::vector<Name>& catchTags,
851-
const std::vector<Name>& catchDests,
852-
const std::vector<bool>& catchRefs) {
853-
auto* ret = wasm.allocator.alloc<TryTable>();
854-
ret->body = body;
855-
ret->catchTags.set(catchTags);
856-
ret->catchDests.set(catchDests);
857-
ret->catchRefs.set(catchRefs);
858-
ret->finalize(&wasm);
859-
return ret;
804+
Try* makeTry(Name name,
805+
Expression* body,
806+
Name delegateTarget,
807+
std::optional<Type> type = std::nullopt) {
808+
return makeTry(name, body, {}, {}, delegateTarget, type);
860809
}
861810
TryTable* makeTryTable(Expression* body,
862811
const std::vector<Name>& catchTags,
863812
const std::vector<Name>& catchDests,
864813
const std::vector<bool>& catchRefs,
865-
Type type) {
814+
std::optional<Type> type = std::nullopt) {
866815
auto* ret = wasm.allocator.alloc<TryTable>();
867816
ret->body = body;
868817
ret->catchTags.set(catchTags);
@@ -1359,8 +1308,10 @@ class Builder {
13591308
// ensure a node is a block, if it isn't already, and optionally append to the
13601309
// block this variant sets a name for the block, so it will not reuse a block
13611310
// already named
1362-
Block*
1363-
blockifyWithName(Expression* any, Name name, Expression* append = nullptr) {
1311+
Block* blockifyWithName(Expression* any,
1312+
Name name,
1313+
Expression* append = nullptr,
1314+
std::optional<Type> type = std::nullopt) {
13641315
Block* block = nullptr;
13651316
if (any) {
13661317
block = any->dynCast<Block>();
@@ -1371,21 +1322,16 @@ class Builder {
13711322
block->name = name;
13721323
if (append) {
13731324
block->list.push_back(append);
1374-
block->finalize();
1325+
block->finalize(type);
13751326
}
13761327
return block;
13771328
}
13781329

13791330
// a helper for the common pattern of a sequence of two expressions. Similar
13801331
// to blockify, but does *not* reuse a block if the first is one.
1381-
Block* makeSequence(Expression* left, Expression* right) {
1382-
auto* block = makeBlock(left);
1383-
block->list.push_back(right);
1384-
block->finalize();
1385-
return block;
1386-
}
1387-
1388-
Block* makeSequence(Expression* left, Expression* right, Type type) {
1332+
Block* makeSequence(Expression* left,
1333+
Expression* right,
1334+
std::optional<Type> type = std::nullopt) {
13891335
auto* block = makeBlock(left);
13901336
block->list.push_back(right);
13911337
block->finalize(type);

src/wasm.h

Lines changed: 28 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -828,23 +828,21 @@ class Block : public SpecificExpression<Expression::BlockId> {
828828
Name name;
829829
ExpressionList list;
830830

831-
// set the type purely based on its contents. this scans the block, so it is
832-
// not fast.
833-
void finalize();
834-
835-
// set the type given you know its type, which is the case when parsing
836-
// s-expression or binary, as explicit types are given. the only additional
837-
// work this does is to set the type to unreachable in the cases that is
838-
// needed (which may require scanning the block)
839-
void finalize(Type type_);
840-
841831
enum Breakability { Unknown, HasBreak, NoBreak };
842832

843-
// set the type given you know its type, and you know if there is a break to
844-
// this block. this avoids the need to scan the contents of the block in the
845-
// case that it might be unreachable, so it is recommended if you already know
846-
// the type and breakability anyhow.
847-
void finalize(Type type_, Breakability breakability);
833+
// If type_ is not given, set the type purely based on its contents. this
834+
// scans the block, so it is not fast.
835+
// If type_ is given, set the type given you know its type, which is the case
836+
// when parsing s-expression or binary, as explicit types are given. the only
837+
// additional work this does is to set the type to unreachable in the cases
838+
// that is needed (which may require scanning the block)
839+
//
840+
// If breakability is given, you know if there is a break to this block. this
841+
// avoids the need to scan the contents of the block in the case that it might
842+
// be unreachable, so it is recommended if you already know the type and
843+
// breakability anyhow.
844+
void finalize(std::optional<Type> type_ = std::nullopt,
845+
Breakability breakability = Unknown);
848846
};
849847

850848
class If : public SpecificExpression<Expression::IfId> {
@@ -856,14 +854,12 @@ class If : public SpecificExpression<Expression::IfId> {
856854
Expression* ifTrue;
857855
Expression* ifFalse;
858856

859-
// set the type given you know its type, which is the case when parsing
860-
// s-expression or binary, as explicit types are given. the only additional
861-
// work this does is to set the type to unreachable in the cases that is
862-
// needed.
863-
void finalize(Type type_);
864-
865-
// set the type purely based on its contents.
866-
void finalize();
857+
// If type_ is not given, set the type purely based on its contents.
858+
// If type_ is given, set the type given you know its type, which is the case
859+
// when parsing s-expression or binary, as explicit types are given. the only
860+
// additional work this does is to set the type to unreachable in the cases
861+
// that is needed.
862+
void finalize(std::optional<Type> type_ = std::nullopt);
867863
};
868864

869865
class Loop : public SpecificExpression<Expression::LoopId> {
@@ -874,14 +870,12 @@ class Loop : public SpecificExpression<Expression::LoopId> {
874870
Name name;
875871
Expression* body;
876872

877-
// set the type given you know its type, which is the case when parsing
878-
// s-expression or binary, as explicit types are given. the only additional
879-
// work this does is to set the type to unreachable in the cases that is
880-
// needed.
881-
void finalize(Type type_);
882-
883-
// set the type purely based on its contents.
884-
void finalize();
873+
// If type_ is not given, set the type purely based on its contents.
874+
// If type_ is given, set the type given you know its type, which is the case
875+
// when parsing s-expression or binary, as explicit types are given. the only
876+
// additional work this does is to set the type to unreachable in the cases
877+
// that is needed.
878+
void finalize(std::optional<Type> type_ = std::nullopt);
885879
};
886880

887881
class Break : public SpecificExpression<Expression::BreakId> {
@@ -1472,8 +1466,7 @@ class Try : public SpecificExpression<Expression::TryId> {
14721466
}
14731467
bool isCatch() const { return !catchBodies.empty(); }
14741468
bool isDelegate() const { return delegateTarget.is(); }
1475-
void finalize();
1476-
void finalize(Type type_);
1469+
void finalize(std::optional<Type> type_ = std::nullopt);
14771470
};
14781471

14791472
// 'try_table' from the new EH proposal
@@ -1497,8 +1490,8 @@ class TryTable : public SpecificExpression<Expression::TryTableId> {
14971490
// When 'Module*' parameter is given, we cache catch tags' types into
14981491
// 'sentTypes' array, so that the types can be accessed in other analyses
14991492
// without accessing the module.
1500-
void finalize(Module* wasm = nullptr);
1501-
void finalize(Type type_, Module* wasm = nullptr);
1493+
void finalize(std::optional<Type> type_ = std::nullopt,
1494+
Module* wasm = nullptr);
15021495

15031496
// Caches tags' types in the catch clauses in order not to query the module
15041497
// every time we query the sent types

0 commit comments

Comments
 (0)