1 /*
2  * Copyright 2016 WebAssembly Community Group participants
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *     http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #ifndef wasm_wasm_builder_h
18 #define wasm_wasm_builder_h
19 
20 #include "ir/manipulation.h"
21 #include "wasm.h"
22 
23 namespace wasm {
24 
25 // Useful data structures
26 
27 struct NameType {
28   Name name;
29   Type type;
NameTypeNameType30   NameType() : name(nullptr), type(Type::none) {}
NameTypeNameType31   NameType(Name name, Type type) : name(name), type(type) {}
32 };
33 
34 // General AST node builder
35 
36 class Builder {
37   Module& wasm;
38 
39 public:
Builder(Module & wasm)40   Builder(Module& wasm) : wasm(wasm) {}
41 
42   // make* functions, other globals
43 
44   Function* makeFunction(Name name,
45                          Signature sig,
46                          std::vector<Type>&& vars,
47                          Expression* body = nullptr) {
48     auto* func = new Function;
49     func->name = name;
50     func->sig = sig;
51     func->body = body;
52     func->vars.swap(vars);
53     return func;
54   }
55 
56   Function* makeFunction(Name name,
57                          std::vector<NameType>&& params,
58                          Type resultType,
59                          std::vector<NameType>&& vars,
60                          Expression* body = nullptr) {
61     auto* func = new Function;
62     func->name = name;
63     func->body = body;
64     std::vector<Type> paramVec;
65     for (auto& param : params) {
66       paramVec.push_back(param.type);
67       Index index = func->localNames.size();
68       func->localIndices[param.name] = index;
69       func->localNames[index] = param.name;
70     }
71     func->sig = Signature(Type(paramVec), resultType);
72     for (auto& var : vars) {
73       func->vars.push_back(var.type);
74       Index index = func->localNames.size();
75       func->localIndices[var.name] = index;
76       func->localNames[index] = var.name;
77     }
78     return func;
79   }
80 
makeExport(Name name,Name value,ExternalKind kind)81   Export* makeExport(Name name, Name value, ExternalKind kind) {
82     auto* export_ = new Export();
83     export_->name = name;
84     export_->value = value;
85     export_->kind = kind;
86     return export_;
87   }
88 
89   // IR nodes
90 
makeNop()91   Nop* makeNop() { return wasm.allocator.alloc<Nop>(); }
92   Block* makeBlock(Expression* first = nullptr) {
93     auto* ret = wasm.allocator.alloc<Block>();
94     if (first) {
95       ret->list.push_back(first);
96       ret->finalize();
97     }
98     return ret;
99   }
100   Block* makeBlock(Name name, Expression* first = nullptr) {
101     auto* ret = makeBlock(first);
102     ret->name = name;
103     ret->finalize();
104     return ret;
105   }
makeBlock(const std::vector<Expression * > & items)106   Block* makeBlock(const std::vector<Expression*>& items) {
107     auto* ret = wasm.allocator.alloc<Block>();
108     ret->list.set(items);
109     ret->finalize();
110     return ret;
111   }
makeBlock(const std::vector<Expression * > & items,Type type)112   Block* makeBlock(const std::vector<Expression*>& items, Type type) {
113     auto* ret = wasm.allocator.alloc<Block>();
114     ret->list.set(items);
115     ret->finalize(type);
116     return ret;
117   }
makeBlock(const ExpressionList & items)118   Block* makeBlock(const ExpressionList& items) {
119     auto* ret = wasm.allocator.alloc<Block>();
120     ret->list.set(items);
121     ret->finalize();
122     return ret;
123   }
makeBlock(const ExpressionList & items,Type type)124   Block* makeBlock(const ExpressionList& items, Type type) {
125     auto* ret = wasm.allocator.alloc<Block>();
126     ret->list.set(items);
127     ret->finalize(type);
128     return ret;
129   }
makeBlock(Name name,const ExpressionList & items)130   Block* makeBlock(Name name, const ExpressionList& items) {
131     auto* ret = wasm.allocator.alloc<Block>();
132     ret->name = name;
133     ret->list.set(items);
134     ret->finalize();
135     return ret;
136   }
makeBlock(Name name,const ExpressionList & items,Type type)137   Block* makeBlock(Name name, const ExpressionList& items, Type type) {
138     auto* ret = wasm.allocator.alloc<Block>();
139     ret->name = name;
140     ret->list.set(items);
141     ret->finalize(type);
142     return ret;
143   }
144   If* makeIf(Expression* condition,
145              Expression* ifTrue,
146              Expression* ifFalse = nullptr) {
147     auto* ret = wasm.allocator.alloc<If>();
148     ret->condition = condition;
149     ret->ifTrue = ifTrue;
150     ret->ifFalse = ifFalse;
151     ret->finalize();
152     return ret;
153   }
makeIf(Expression * condition,Expression * ifTrue,Expression * ifFalse,Type type)154   If* makeIf(Expression* condition,
155              Expression* ifTrue,
156              Expression* ifFalse,
157              Type type) {
158     auto* ret = wasm.allocator.alloc<If>();
159     ret->condition = condition;
160     ret->ifTrue = ifTrue;
161     ret->ifFalse = ifFalse;
162     ret->finalize(type);
163     return ret;
164   }
makeLoop(Name name,Expression * body)165   Loop* makeLoop(Name name, Expression* body) {
166     auto* ret = wasm.allocator.alloc<Loop>();
167     ret->name = name;
168     ret->body = body;
169     ret->finalize();
170     return ret;
171   }
makeLoop(Name name,Expression * body,Type type)172   Loop* makeLoop(Name name, Expression* body, Type type) {
173     auto* ret = wasm.allocator.alloc<Loop>();
174     ret->name = name;
175     ret->body = body;
176     ret->finalize(type);
177     return ret;
178   }
179   Break* makeBreak(Name name,
180                    Expression* value = nullptr,
181                    Expression* condition = nullptr) {
182     auto* ret = wasm.allocator.alloc<Break>();
183     ret->name = name;
184     ret->value = value;
185     ret->condition = condition;
186     ret->finalize();
187     return ret;
188   }
189   template<typename T>
190   Switch* makeSwitch(T& list,
191                      Name default_,
192                      Expression* condition,
193                      Expression* value = nullptr) {
194     auto* ret = wasm.allocator.alloc<Switch>();
195     ret->targets.set(list);
196     ret->default_ = default_;
197     ret->value = value;
198     ret->condition = condition;
199     return ret;
200   }
201   Call* makeCall(Name target,
202                  const std::vector<Expression*>& args,
203                  Type type,
204                  bool isReturn = false) {
205     auto* call = wasm.allocator.alloc<Call>();
206     // not all functions may exist yet, so type must be provided
207     call->type = type;
208     call->target = target;
209     call->operands.set(args);
210     call->isReturn = isReturn;
211     return call;
212   }
213   template<typename T>
214   Call* makeCall(Name target, const T& args, Type type, bool isReturn = false) {
215     auto* call = wasm.allocator.alloc<Call>();
216     // not all functions may exist yet, so type must be provided
217     call->type = type;
218     call->target = target;
219     call->operands.set(args);
220     call->isReturn = isReturn;
221     call->finalize();
222     return call;
223   }
224   CallIndirect* makeCallIndirect(Expression* target,
225                                  const std::vector<Expression*>& args,
226                                  Signature sig,
227                                  bool isReturn = false) {
228     auto* call = wasm.allocator.alloc<CallIndirect>();
229     call->sig = sig;
230     call->type = sig.results;
231     call->target = target;
232     call->operands.set(args);
233     call->isReturn = isReturn;
234     call->finalize();
235     return call;
236   }
makeLocalGet(Index index,Type type)237   LocalGet* makeLocalGet(Index index, Type type) {
238     auto* ret = wasm.allocator.alloc<LocalGet>();
239     ret->index = index;
240     ret->type = type;
241     return ret;
242   }
makeLocalSet(Index index,Expression * value)243   LocalSet* makeLocalSet(Index index, Expression* value) {
244     auto* ret = wasm.allocator.alloc<LocalSet>();
245     ret->index = index;
246     ret->value = value;
247     ret->makeSet();
248     ret->finalize();
249     return ret;
250   }
makeLocalTee(Index index,Expression * value,Type type)251   LocalSet* makeLocalTee(Index index, Expression* value, Type type) {
252     auto* ret = wasm.allocator.alloc<LocalSet>();
253     ret->index = index;
254     ret->value = value;
255     ret->makeTee(type);
256     return ret;
257   }
makeGlobalGet(Name name,Type type)258   GlobalGet* makeGlobalGet(Name name, Type type) {
259     auto* ret = wasm.allocator.alloc<GlobalGet>();
260     ret->name = name;
261     ret->type = type;
262     return ret;
263   }
makeGlobalSet(Name name,Expression * value)264   GlobalSet* makeGlobalSet(Name name, Expression* value) {
265     auto* ret = wasm.allocator.alloc<GlobalSet>();
266     ret->name = name;
267     ret->value = value;
268     ret->finalize();
269     return ret;
270   }
makeLoad(unsigned bytes,bool signed_,uint32_t offset,unsigned align,Expression * ptr,Type type)271   Load* makeLoad(unsigned bytes,
272                  bool signed_,
273                  uint32_t offset,
274                  unsigned align,
275                  Expression* ptr,
276                  Type type) {
277     auto* ret = wasm.allocator.alloc<Load>();
278     ret->isAtomic = false;
279     ret->bytes = bytes;
280     ret->signed_ = signed_;
281     ret->offset = offset;
282     ret->align = align;
283     ret->ptr = ptr;
284     ret->type = type;
285     return ret;
286   }
287   Load*
makeAtomicLoad(unsigned bytes,uint32_t offset,Expression * ptr,Type type)288   makeAtomicLoad(unsigned bytes, uint32_t offset, Expression* ptr, Type type) {
289     Load* load = makeLoad(bytes, false, offset, bytes, ptr, type);
290     load->isAtomic = true;
291     return load;
292   }
makeAtomicWait(Expression * ptr,Expression * expected,Expression * timeout,Type expectedType,Address offset)293   AtomicWait* makeAtomicWait(Expression* ptr,
294                              Expression* expected,
295                              Expression* timeout,
296                              Type expectedType,
297                              Address offset) {
298     auto* wait = wasm.allocator.alloc<AtomicWait>();
299     wait->offset = offset;
300     wait->ptr = ptr;
301     wait->expected = expected;
302     wait->timeout = timeout;
303     wait->expectedType = expectedType;
304     wait->finalize();
305     return wait;
306   }
307   AtomicNotify*
makeAtomicNotify(Expression * ptr,Expression * notifyCount,Address offset)308   makeAtomicNotify(Expression* ptr, Expression* notifyCount, Address offset) {
309     auto* notify = wasm.allocator.alloc<AtomicNotify>();
310     notify->offset = offset;
311     notify->ptr = ptr;
312     notify->notifyCount = notifyCount;
313     notify->finalize();
314     return notify;
315   }
makeAtomicFence()316   AtomicFence* makeAtomicFence() { return wasm.allocator.alloc<AtomicFence>(); }
makeStore(unsigned bytes,uint32_t offset,unsigned align,Expression * ptr,Expression * value,Type type)317   Store* makeStore(unsigned bytes,
318                    uint32_t offset,
319                    unsigned align,
320                    Expression* ptr,
321                    Expression* value,
322                    Type type) {
323     auto* ret = wasm.allocator.alloc<Store>();
324     ret->isAtomic = false;
325     ret->bytes = bytes;
326     ret->offset = offset;
327     ret->align = align;
328     ret->ptr = ptr;
329     ret->value = value;
330     ret->valueType = type;
331     ret->finalize();
332     assert(ret->value->type.isConcrete() ? ret->value->type == type : true);
333     return ret;
334   }
makeAtomicStore(unsigned bytes,uint32_t offset,Expression * ptr,Expression * value,Type type)335   Store* makeAtomicStore(unsigned bytes,
336                          uint32_t offset,
337                          Expression* ptr,
338                          Expression* value,
339                          Type type) {
340     Store* store = makeStore(bytes, offset, bytes, ptr, value, type);
341     store->isAtomic = true;
342     return store;
343   }
makeAtomicRMW(AtomicRMWOp op,unsigned bytes,uint32_t offset,Expression * ptr,Expression * value,Type type)344   AtomicRMW* makeAtomicRMW(AtomicRMWOp op,
345                            unsigned bytes,
346                            uint32_t offset,
347                            Expression* ptr,
348                            Expression* value,
349                            Type type) {
350     auto* ret = wasm.allocator.alloc<AtomicRMW>();
351     ret->op = op;
352     ret->bytes = bytes;
353     ret->offset = offset;
354     ret->ptr = ptr;
355     ret->value = value;
356     ret->type = type;
357     ret->finalize();
358     return ret;
359   }
makeAtomicCmpxchg(unsigned bytes,uint32_t offset,Expression * ptr,Expression * expected,Expression * replacement,Type type)360   AtomicCmpxchg* makeAtomicCmpxchg(unsigned bytes,
361                                    uint32_t offset,
362                                    Expression* ptr,
363                                    Expression* expected,
364                                    Expression* replacement,
365                                    Type type) {
366     auto* ret = wasm.allocator.alloc<AtomicCmpxchg>();
367     ret->bytes = bytes;
368     ret->offset = offset;
369     ret->ptr = ptr;
370     ret->expected = expected;
371     ret->replacement = replacement;
372     ret->type = type;
373     ret->finalize();
374     return ret;
375   }
376   SIMDExtract*
makeSIMDExtract(SIMDExtractOp op,Expression * vec,uint8_t index)377   makeSIMDExtract(SIMDExtractOp op, Expression* vec, uint8_t index) {
378     auto* ret = wasm.allocator.alloc<SIMDExtract>();
379     ret->op = op;
380     ret->vec = vec;
381     ret->index = index;
382     ret->finalize();
383     return ret;
384   }
makeSIMDReplace(SIMDReplaceOp op,Expression * vec,uint8_t index,Expression * value)385   SIMDReplace* makeSIMDReplace(SIMDReplaceOp op,
386                                Expression* vec,
387                                uint8_t index,
388                                Expression* value) {
389     auto* ret = wasm.allocator.alloc<SIMDReplace>();
390     ret->op = op;
391     ret->vec = vec;
392     ret->index = index;
393     ret->value = value;
394     ret->finalize();
395     return ret;
396   }
makeSIMDShuffle(Expression * left,Expression * right,const std::array<uint8_t,16> & mask)397   SIMDShuffle* makeSIMDShuffle(Expression* left,
398                                Expression* right,
399                                const std::array<uint8_t, 16>& mask) {
400     auto* ret = wasm.allocator.alloc<SIMDShuffle>();
401     ret->left = left;
402     ret->right = right;
403     ret->mask = mask;
404     ret->finalize();
405     return ret;
406   }
makeSIMDTernary(SIMDTernaryOp op,Expression * a,Expression * b,Expression * c)407   SIMDTernary* makeSIMDTernary(SIMDTernaryOp op,
408                                Expression* a,
409                                Expression* b,
410                                Expression* c) {
411     auto* ret = wasm.allocator.alloc<SIMDTernary>();
412     ret->op = op;
413     ret->a = a;
414     ret->b = b;
415     ret->c = c;
416     ret->finalize();
417     return ret;
418   }
makeSIMDShift(SIMDShiftOp op,Expression * vec,Expression * shift)419   SIMDShift* makeSIMDShift(SIMDShiftOp op, Expression* vec, Expression* shift) {
420     auto* ret = wasm.allocator.alloc<SIMDShift>();
421     ret->op = op;
422     ret->vec = vec;
423     ret->shift = shift;
424     ret->finalize();
425     return ret;
426   }
427   SIMDLoad*
makeSIMDLoad(SIMDLoadOp op,Address offset,Address align,Expression * ptr)428   makeSIMDLoad(SIMDLoadOp op, Address offset, Address align, Expression* ptr) {
429     auto* ret = wasm.allocator.alloc<SIMDLoad>();
430     ret->op = op;
431     ret->offset = offset;
432     ret->align = align;
433     ret->ptr = ptr;
434     ret->finalize();
435     return ret;
436   }
makeMemoryInit(uint32_t segment,Expression * dest,Expression * offset,Expression * size)437   MemoryInit* makeMemoryInit(uint32_t segment,
438                              Expression* dest,
439                              Expression* offset,
440                              Expression* size) {
441     auto* ret = wasm.allocator.alloc<MemoryInit>();
442     ret->segment = segment;
443     ret->dest = dest;
444     ret->offset = offset;
445     ret->size = size;
446     ret->finalize();
447     return ret;
448   }
makeDataDrop(uint32_t segment)449   DataDrop* makeDataDrop(uint32_t segment) {
450     auto* ret = wasm.allocator.alloc<DataDrop>();
451     ret->segment = segment;
452     ret->finalize();
453     return ret;
454   }
455   MemoryCopy*
makeMemoryCopy(Expression * dest,Expression * source,Expression * size)456   makeMemoryCopy(Expression* dest, Expression* source, Expression* size) {
457     auto* ret = wasm.allocator.alloc<MemoryCopy>();
458     ret->dest = dest;
459     ret->source = source;
460     ret->size = size;
461     ret->finalize();
462     return ret;
463   }
464   MemoryFill*
makeMemoryFill(Expression * dest,Expression * value,Expression * size)465   makeMemoryFill(Expression* dest, Expression* value, Expression* size) {
466     auto* ret = wasm.allocator.alloc<MemoryFill>();
467     ret->dest = dest;
468     ret->value = value;
469     ret->size = size;
470     ret->finalize();
471     return ret;
472   }
makeConst(Literal value)473   Const* makeConst(Literal value) {
474     assert(value.type.isNumber());
475     auto* ret = wasm.allocator.alloc<Const>();
476     ret->value = value;
477     ret->type = value.type;
478     return ret;
479   }
makeConst(T x)480   template<typename T> Const* makeConst(T x) { return makeConst(Literal(x)); }
makeUnary(UnaryOp op,Expression * value)481   Unary* makeUnary(UnaryOp op, Expression* value) {
482     auto* ret = wasm.allocator.alloc<Unary>();
483     ret->op = op;
484     ret->value = value;
485     ret->finalize();
486     return ret;
487   }
makeConstPtr(uint64_t val)488   Const* makeConstPtr(uint64_t val) {
489     return makeConst(Literal::makeFromInt64(val, wasm.memory.indexType));
490   }
makeBinary(BinaryOp op,Expression * left,Expression * right)491   Binary* makeBinary(BinaryOp op, Expression* left, Expression* right) {
492     auto* ret = wasm.allocator.alloc<Binary>();
493     ret->op = op;
494     ret->left = left;
495     ret->right = right;
496     ret->finalize();
497     return ret;
498   }
499   Select*
makeSelect(Expression * condition,Expression * ifTrue,Expression * ifFalse)500   makeSelect(Expression* condition, Expression* ifTrue, Expression* ifFalse) {
501     auto* ret = wasm.allocator.alloc<Select>();
502     ret->condition = condition;
503     ret->ifTrue = ifTrue;
504     ret->ifFalse = ifFalse;
505     ret->finalize();
506     return ret;
507   }
makeSelect(Expression * condition,Expression * ifTrue,Expression * ifFalse,Type type)508   Select* makeSelect(Expression* condition,
509                      Expression* ifTrue,
510                      Expression* ifFalse,
511                      Type type) {
512     auto* ret = wasm.allocator.alloc<Select>();
513     ret->condition = condition;
514     ret->ifTrue = ifTrue;
515     ret->ifFalse = ifFalse;
516     ret->finalize(type);
517     return ret;
518   }
519   Return* makeReturn(Expression* value = nullptr) {
520     auto* ret = wasm.allocator.alloc<Return>();
521     ret->value = value;
522     return ret;
523   }
makeMemorySize()524   MemorySize* makeMemorySize() {
525     auto* ret = wasm.allocator.alloc<MemorySize>();
526     if (wasm.memory.is64()) {
527       ret->make64();
528     }
529     ret->finalize();
530     return ret;
531   }
makeMemoryGrow(Expression * delta)532   MemoryGrow* makeMemoryGrow(Expression* delta) {
533     auto* ret = wasm.allocator.alloc<MemoryGrow>();
534     if (wasm.memory.is64()) {
535       ret->make64();
536     }
537     ret->delta = delta;
538     ret->finalize();
539     return ret;
540   }
makeRefNull(Type type)541   RefNull* makeRefNull(Type type) {
542     auto* ret = wasm.allocator.alloc<RefNull>();
543     ret->finalize(type);
544     return ret;
545   }
makeRefIsNull(Expression * value)546   RefIsNull* makeRefIsNull(Expression* value) {
547     auto* ret = wasm.allocator.alloc<RefIsNull>();
548     ret->value = value;
549     ret->finalize();
550     return ret;
551   }
makeRefFunc(Name func)552   RefFunc* makeRefFunc(Name func) {
553     auto* ret = wasm.allocator.alloc<RefFunc>();
554     ret->func = func;
555     ret->finalize();
556     return ret;
557   }
makeRefEq(Expression * left,Expression * right)558   RefEq* makeRefEq(Expression* left, Expression* right) {
559     auto* ret = wasm.allocator.alloc<RefEq>();
560     ret->left = left;
561     ret->right = right;
562     ret->finalize();
563     return ret;
564   }
makeTry(Expression * body,Expression * catchBody)565   Try* makeTry(Expression* body, Expression* catchBody) {
566     auto* ret = wasm.allocator.alloc<Try>();
567     ret->body = body;
568     ret->catchBody = catchBody;
569     ret->finalize();
570     return ret;
571   }
makeTry(Expression * body,Expression * catchBody,Type type)572   Try* makeTry(Expression* body, Expression* catchBody, Type type) {
573     auto* ret = wasm.allocator.alloc<Try>();
574     ret->body = body;
575     ret->catchBody = catchBody;
576     ret->finalize(type);
577     return ret;
578   }
makeThrow(Event * event,const std::vector<Expression * > & args)579   Throw* makeThrow(Event* event, const std::vector<Expression*>& args) {
580     return makeThrow(event->name, args);
581   }
makeThrow(Name event,const std::vector<Expression * > & args)582   Throw* makeThrow(Name event, const std::vector<Expression*>& args) {
583     auto* ret = wasm.allocator.alloc<Throw>();
584     ret->event = event;
585     ret->operands.set(args);
586     ret->finalize();
587     return ret;
588   }
makeRethrow(Expression * exnref)589   Rethrow* makeRethrow(Expression* exnref) {
590     auto* ret = wasm.allocator.alloc<Rethrow>();
591     ret->exnref = exnref;
592     ret->finalize();
593     return ret;
594   }
makeBrOnExn(Name name,Event * event,Expression * exnref)595   BrOnExn* makeBrOnExn(Name name, Event* event, Expression* exnref) {
596     return makeBrOnExn(name, event->name, exnref, event->sig.params);
597   }
makeBrOnExn(Name name,Name event,Expression * exnref,Type sent)598   BrOnExn* makeBrOnExn(Name name, Name event, Expression* exnref, Type sent) {
599     auto* ret = wasm.allocator.alloc<BrOnExn>();
600     ret->name = name;
601     ret->event = event;
602     ret->exnref = exnref;
603     // Copy params info into BrOnExn, because it is necessary when BrOnExn is
604     // refinalized without the module.
605     ret->sent = sent;
606     ret->finalize();
607     return ret;
608   }
makeUnreachable()609   Unreachable* makeUnreachable() { return wasm.allocator.alloc<Unreachable>(); }
makePop(Type type)610   Pop* makePop(Type type) {
611     auto* ret = wasm.allocator.alloc<Pop>();
612     ret->type = type;
613     ret->finalize();
614     return ret;
615   }
makeTupleMake(ListType && operands)616   template<typename ListType> TupleMake* makeTupleMake(ListType&& operands) {
617     auto* ret = wasm.allocator.alloc<TupleMake>();
618     ret->operands.set(operands);
619     ret->finalize();
620     return ret;
621   }
makeTupleExtract(Expression * tuple,Index index)622   TupleExtract* makeTupleExtract(Expression* tuple, Index index) {
623     auto* ret = wasm.allocator.alloc<TupleExtract>();
624     ret->tuple = tuple;
625     ret->index = index;
626     ret->finalize();
627     return ret;
628   }
makeI31New(Expression * value)629   I31New* makeI31New(Expression* value) {
630     auto* ret = wasm.allocator.alloc<I31New>();
631     ret->value = value;
632     ret->finalize();
633     return ret;
634   }
makeI31Get(Expression * i31,bool signed_)635   I31Get* makeI31Get(Expression* i31, bool signed_) {
636     auto* ret = wasm.allocator.alloc<I31Get>();
637     ret->i31 = i31;
638     ret->signed_ = signed_;
639     ret->finalize();
640     return ret;
641   }
makeRefTest()642   RefTest* makeRefTest() {
643     auto* ret = wasm.allocator.alloc<RefTest>();
644     WASM_UNREACHABLE("TODO (gc): ref.test");
645     ret->finalize();
646     return ret;
647   }
makeRefCast()648   RefCast* makeRefCast() {
649     auto* ret = wasm.allocator.alloc<RefCast>();
650     WASM_UNREACHABLE("TODO (gc): ref.cast");
651     ret->finalize();
652     return ret;
653   }
makeBrOnCast()654   BrOnCast* makeBrOnCast() {
655     auto* ret = wasm.allocator.alloc<BrOnCast>();
656     WASM_UNREACHABLE("TODO (gc): br_on_cast");
657     ret->finalize();
658     return ret;
659   }
makeRttCanon()660   RttCanon* makeRttCanon() {
661     auto* ret = wasm.allocator.alloc<RttCanon>();
662     WASM_UNREACHABLE("TODO (gc): rtt.canon");
663     ret->finalize();
664     return ret;
665   }
makeRttSub()666   RttSub* makeRttSub() {
667     auto* ret = wasm.allocator.alloc<RttSub>();
668     WASM_UNREACHABLE("TODO (gc): rtt.sub");
669     ret->finalize();
670     return ret;
671   }
makeStructNew()672   StructNew* makeStructNew() {
673     auto* ret = wasm.allocator.alloc<StructNew>();
674     WASM_UNREACHABLE("TODO (gc): struct.new");
675     ret->finalize();
676     return ret;
677   }
makeStructGet()678   StructGet* makeStructGet() {
679     auto* ret = wasm.allocator.alloc<StructGet>();
680     WASM_UNREACHABLE("TODO (gc): struct.get");
681     ret->finalize();
682     return ret;
683   }
makeStructSet()684   StructSet* makeStructSet() {
685     auto* ret = wasm.allocator.alloc<StructSet>();
686     WASM_UNREACHABLE("TODO (gc): struct.set");
687     ret->finalize();
688     return ret;
689   }
makeArrayNew()690   ArrayNew* makeArrayNew() {
691     auto* ret = wasm.allocator.alloc<ArrayNew>();
692     WASM_UNREACHABLE("TODO (gc): array.new");
693     ret->finalize();
694     return ret;
695   }
makeArrayGet()696   ArrayGet* makeArrayGet() {
697     auto* ret = wasm.allocator.alloc<ArrayGet>();
698     WASM_UNREACHABLE("TODO (gc): array.get");
699     ret->finalize();
700     return ret;
701   }
makeArraySet()702   ArraySet* makeArraySet() {
703     auto* ret = wasm.allocator.alloc<ArraySet>();
704     WASM_UNREACHABLE("TODO (gc): array.set");
705     ret->finalize();
706     return ret;
707   }
makeArrayLen()708   ArrayLen* makeArrayLen() {
709     auto* ret = wasm.allocator.alloc<ArrayLen>();
710     WASM_UNREACHABLE("TODO (gc): array.len");
711     ret->finalize();
712     return ret;
713   }
714 
715   // Additional helpers
716 
makeDrop(Expression * value)717   Drop* makeDrop(Expression* value) {
718     auto* ret = wasm.allocator.alloc<Drop>();
719     ret->value = value;
720     ret->finalize();
721     return ret;
722   }
723 
724   // Make a constant expression. This might be a wasm Const, or something
725   // else of constant value like ref.null.
makeConstantExpression(Literal value)726   Expression* makeConstantExpression(Literal value) {
727     TODO_SINGLE_COMPOUND(value.type);
728     switch (value.type.getBasic()) {
729       case Type::funcref:
730         if (!value.isNull()) {
731           return makeRefFunc(value.getFunc());
732         }
733         return makeRefNull(value.type);
734       case Type::externref:
735       case Type::exnref: // TODO: ExceptionPackage?
736       case Type::anyref:
737       case Type::eqref:
738         assert(value.isNull() && "unexpected non-null reference type literal");
739         return makeRefNull(value.type);
740       case Type::i31ref:
741         return makeI31New(makeConst(value.geti31()));
742       default:
743         assert(value.type.isNumber());
744         return makeConst(value);
745     }
746   }
747 
makeConstantExpression(Literals values)748   Expression* makeConstantExpression(Literals values) {
749     assert(values.size() > 0);
750     if (values.size() == 1) {
751       return makeConstantExpression(values[0]);
752     } else {
753       std::vector<Expression*> consts;
754       for (auto value : values) {
755         consts.push_back(makeConstantExpression(value));
756       }
757       return makeTupleMake(consts);
758     }
759   }
760 
761   // Additional utility functions for building on top of nodes
762   // Convenient to have these on Builder, as it has allocation built in
763 
addParam(Function * func,Name name,Type type)764   static Index addParam(Function* func, Name name, Type type) {
765     // only ok to add a param if no vars, otherwise indices are invalidated
766     assert(func->localIndices.size() == func->sig.params.size());
767     assert(name.is());
768     std::vector<Type> params(func->sig.params.begin(), func->sig.params.end());
769     params.push_back(type);
770     func->sig.params = Type(params);
771     Index index = func->localNames.size();
772     func->localIndices[name] = index;
773     func->localNames[index] = name;
774     return index;
775   }
776 
addVar(Function * func,Name name,Type type)777   static Index addVar(Function* func, Name name, Type type) {
778     // always ok to add a var, it does not affect other indices
779     assert(type.isConcrete());
780     Index index = func->getNumLocals();
781     if (name.is()) {
782       func->localIndices[name] = index;
783       func->localNames[index] = name;
784     }
785     func->vars.emplace_back(type);
786     return index;
787   }
788 
addVar(Function * func,Type type)789   static Index addVar(Function* func, Type type) {
790     return addVar(func, Name(), type);
791   }
792 
clearLocalNames(Function * func)793   static void clearLocalNames(Function* func) {
794     func->localNames.clear();
795     func->localIndices.clear();
796   }
797 
clearLocals(Function * func)798   static void clearLocals(Function* func) {
799     func->sig.params = Type::none;
800     func->vars.clear();
801     clearLocalNames(func);
802   }
803 
804   // ensure a node is a block, if it isn't already, and optionally append to the
805   // block
806   Block* blockify(Expression* any, Expression* append = nullptr) {
807     Block* block = nullptr;
808     if (any) {
809       block = any->dynCast<Block>();
810     }
811     if (!block) {
812       block = makeBlock(any);
813     }
814     if (append) {
815       block->list.push_back(append);
816       block->finalize();
817     }
818     return block;
819   }
820 
821   template<typename... Ts>
blockify(Expression * any,Expression * append,Ts...args)822   Block* blockify(Expression* any, Expression* append, Ts... args) {
823     return blockify(blockify(any, append), args...);
824   }
825 
826   // ensure a node is a block, if it isn't already, and optionally append to the
827   // block this variant sets a name for the block, so it will not reuse a block
828   // already named
829   Block*
830   blockifyWithName(Expression* any, Name name, Expression* append = nullptr) {
831     Block* block = nullptr;
832     if (any) {
833       block = any->dynCast<Block>();
834     }
835     if (!block || block->name.is()) {
836       block = makeBlock(any);
837     }
838     block->name = name;
839     if (append) {
840       block->list.push_back(append);
841       block->finalize();
842     }
843     return block;
844   }
845 
846   // a helper for the common pattern of a sequence of two expressions. Similar
847   // to blockify, but does *not* reuse a block if the first is one.
makeSequence(Expression * left,Expression * right)848   Block* makeSequence(Expression* left, Expression* right) {
849     auto* block = makeBlock(left);
850     block->list.push_back(right);
851     block->finalize();
852     return block;
853   }
854 
makeSequence(Expression * left,Expression * right,Type type)855   Block* makeSequence(Expression* left, Expression* right, Type type) {
856     auto* block = makeBlock(left);
857     block->list.push_back(right);
858     block->finalize(type);
859     return block;
860   }
861 
862   // Grab a slice out of a block, replacing it with nops, and returning
863   // either another block with the contents (if more than 1) or a single
864   // expression
stealSlice(Block * input,Index from,Index to)865   Expression* stealSlice(Block* input, Index from, Index to) {
866     Expression* ret;
867     if (to == from + 1) {
868       // just one
869       ret = input->list[from];
870     } else {
871       auto* block = wasm.allocator.alloc<Block>();
872       for (Index i = from; i < to; i++) {
873         block->list.push_back(input->list[i]);
874       }
875       block->finalize();
876       ret = block;
877     }
878     if (to == input->list.size()) {
879       input->list.resize(from);
880     } else {
881       for (Index i = from; i < to; i++) {
882         input->list[i] = wasm.allocator.alloc<Nop>();
883       }
884     }
885     input->finalize();
886     return ret;
887   }
888 
889   // Drop an expression if it has a concrete type
dropIfConcretelyTyped(Expression * curr)890   Expression* dropIfConcretelyTyped(Expression* curr) {
891     if (!curr->type.isConcrete()) {
892       return curr;
893     }
894     return makeDrop(curr);
895   }
896 
flip(If * iff)897   void flip(If* iff) {
898     std::swap(iff->ifTrue, iff->ifFalse);
899     iff->condition = makeUnary(EqZInt32, iff->condition);
900   }
901 
902   // returns a replacement with the precise same type, and with
903   // minimal contents. as a replacement, this may reuse the
904   // input node
replaceWithIdenticalType(T * curr)905   template<typename T> Expression* replaceWithIdenticalType(T* curr) {
906     if (curr->type.isTuple()) {
907       return makeConstantExpression(Literal::makeZeros(curr->type));
908     }
909     Literal value;
910     // TODO: reuse node conditionally when possible for literals
911     TODO_SINGLE_COMPOUND(curr->type);
912     switch (curr->type.getBasic()) {
913       case Type::i32:
914         value = Literal(int32_t(0));
915         break;
916       case Type::i64:
917         value = Literal(int64_t(0));
918         break;
919       case Type::f32:
920         value = Literal(float(0));
921         break;
922       case Type::f64:
923         value = Literal(double(0));
924         break;
925       case Type::v128: {
926         std::array<uint8_t, 16> bytes;
927         bytes.fill(0);
928         value = Literal(bytes.data());
929         break;
930       }
931       case Type::funcref:
932       case Type::externref:
933       case Type::exnref:
934       case Type::anyref:
935       case Type::eqref:
936         return ExpressionManipulator::refNull(curr, curr->type);
937       case Type::i31ref:
938         return makeI31New(makeConst(0));
939       case Type::none:
940         return ExpressionManipulator::nop(curr);
941       case Type::unreachable:
942         return ExpressionManipulator::unreachable(curr);
943     }
944     return makeConst(value);
945   }
946 
947   // Module-level helpers
948 
949   enum Mutability { Mutable, Immutable };
950 
951   static Global*
makeGlobal(Name name,Type type,Expression * init,Mutability mutable_)952   makeGlobal(Name name, Type type, Expression* init, Mutability mutable_) {
953     auto* glob = new Global;
954     glob->name = name;
955     glob->type = type;
956     glob->init = init;
957     glob->mutable_ = mutable_ == Mutable;
958     return glob;
959   }
960 
makeEvent(Name name,uint32_t attribute,Signature sig)961   static Event* makeEvent(Name name, uint32_t attribute, Signature sig) {
962     auto* event = new Event;
963     event->name = name;
964     event->attribute = attribute;
965     event->sig = sig;
966     return event;
967   }
968 };
969 
970 } // namespace wasm
971 
972 #endif // wasm_wasm_builder_h
973