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