/* * Copyright 2016 WebAssembly Community Group participants * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef wasm_wasm_builder_h #define wasm_wasm_builder_h #include "ir/manipulation.h" #include "wasm.h" namespace wasm { // Useful data structures struct NameType { Name name; Type type; NameType() : name(nullptr), type(none) {} NameType(Name name, Type type) : name(name), type(type) {} }; // General AST node builder class Builder { MixedArena& allocator; public: Builder(MixedArena& allocator) : allocator(allocator) {} Builder(Module& wasm) : allocator(wasm.allocator) {} // make* functions, other globals Function* makeFunction(Name name, std::vector&& params, Type resultType, std::vector&& vars, Expression* body = nullptr) { auto* func = new Function; func->name = name; func->result = resultType; func->body = body; func->params.swap(params); func->vars.swap(vars); return func; } Function* makeFunction(Name name, std::vector&& params, Type resultType, std::vector&& vars, Expression* body = nullptr) { auto* func = new Function; func->name = name; func->result = resultType; func->body = body; for (auto& param : params) { func->params.push_back(param.type); Index index = func->localNames.size(); func->localIndices[param.name] = index; func->localNames[index] = param.name; } for (auto& var : vars) { func->vars.push_back(var.type); Index index = func->localNames.size(); func->localIndices[var.name] = index; func->localNames[index] = var.name; } return func; } Export* makeExport(Name name, Name value, ExternalKind kind) { auto* export_ = new Export(); export_->name = name; export_->value = value; export_->kind = ExternalKind::Function; return export_; } // IR nodes Nop* makeNop() { return allocator.alloc(); } Block* makeBlock(Expression* first = nullptr) { auto* ret = allocator.alloc(); if (first) { ret->list.push_back(first); ret->finalize(); } return ret; } Block* makeBlock(Name name, Expression* first = nullptr) { auto* ret = makeBlock(first); ret->name = name; ret->finalize(); return ret; } Block* makeBlock(const std::vector& items) { auto* ret = allocator.alloc(); ret->list.set(items); ret->finalize(); return ret; } Block* makeBlock(const ExpressionList& items) { auto* ret = allocator.alloc(); ret->list.set(items); ret->finalize(); return ret; } Block* makeBlock(const ExpressionList& items, Type type) { auto* ret = allocator.alloc(); ret->list.set(items); ret->finalize(type); return ret; } Block* makeBlock(Name name, const ExpressionList& items) { auto* ret = allocator.alloc(); ret->name = name; ret->list.set(items); ret->finalize(); return ret; } Block* makeBlock(Name name, const ExpressionList& items, Type type) { auto* ret = allocator.alloc(); ret->name = name; ret->list.set(items); ret->finalize(type); return ret; } If* makeIf(Expression* condition, Expression* ifTrue, Expression* ifFalse = nullptr) { auto* ret = allocator.alloc(); ret->condition = condition; ret->ifTrue = ifTrue; ret->ifFalse = ifFalse; ret->finalize(); return ret; } If* makeIf(Expression* condition, Expression* ifTrue, Expression* ifFalse, Type type) { auto* ret = allocator.alloc(); ret->condition = condition; ret->ifTrue = ifTrue; ret->ifFalse = ifFalse; ret->finalize(type); return ret; } Loop* makeLoop(Name name, Expression* body) { auto* ret = allocator.alloc(); ret->name = name; ret->body = body; ret->finalize(); return ret; } Break* makeBreak(Name name, Expression* value = nullptr, Expression* condition = nullptr) { auto* ret = allocator.alloc(); ret->name = name; ret->value = value; ret->condition = condition; ret->finalize(); return ret; } template Switch* makeSwitch(T& list, Name default_, Expression* condition, Expression* value = nullptr) { auto* ret = allocator.alloc(); ret->targets.set(list); ret->default_ = default_; ret->value = value; ret->condition = condition; return ret; } Call* makeCall(Name target, const std::vector& args, Type type) { auto* call = allocator.alloc(); // not all functions may exist yet, so type must be provided call->type = type; call->target = target; call->operands.set(args); return call; } template Call* makeCall(Name target, const T& args, Type type) { auto* call = allocator.alloc(); // not all functions may exist yet, so type must be provided call->type = type; call->target = target; call->operands.set(args); return call; } CallIndirect* makeCallIndirect(FunctionType* type, Expression* target, const std::vector& args) { auto* call = allocator.alloc(); call->fullType = type->name; call->type = type->result; call->target = target; call->operands.set(args); return call; } CallIndirect* makeCallIndirect(Name fullType, Expression* target, const std::vector& args, Type type) { auto* call = allocator.alloc(); call->fullType = fullType; call->type = type; call->target = target; call->operands.set(args); return call; } // FunctionType GetLocal* makeGetLocal(Index index, Type type) { auto* ret = allocator.alloc(); ret->index = index; ret->type = type; return ret; } SetLocal* makeSetLocal(Index index, Expression* value) { auto* ret = allocator.alloc(); ret->index = index; ret->value = value; ret->finalize(); return ret; } SetLocal* makeTeeLocal(Index index, Expression* value) { auto* ret = allocator.alloc(); ret->index = index; ret->value = value; ret->setTee(true); return ret; } GetGlobal* makeGetGlobal(Name name, Type type) { auto* ret = allocator.alloc(); ret->name = name; ret->type = type; return ret; } SetGlobal* makeSetGlobal(Name name, Expression* value) { auto* ret = allocator.alloc(); ret->name = name; ret->value = value; ret->finalize(); return ret; } Load* makeLoad(unsigned bytes, bool signed_, uint32_t offset, unsigned align, Expression* ptr, Type type) { auto* ret = allocator.alloc(); ret->isAtomic = false; ret->bytes = bytes; ret->signed_ = signed_; ret->offset = offset; ret->align = align; ret->ptr = ptr; ret->type = type; return ret; } Load* makeAtomicLoad(unsigned bytes, uint32_t offset, Expression* ptr, Type type) { Load* load = makeLoad(bytes, false, offset, bytes, ptr, type); load->isAtomic = true; return load; } AtomicWait* makeAtomicWait(Expression* ptr, Expression* expected, Expression* timeout, Type expectedType, Address offset) { auto* wait = allocator.alloc(); wait->offset = offset; wait->ptr = ptr; wait->expected = expected; wait->timeout = timeout; wait->expectedType = expectedType; wait->finalize(); return wait; } AtomicNotify* makeAtomicNotify(Expression* ptr, Expression* notifyCount, Address offset) { auto* notify = allocator.alloc(); notify->offset = offset; notify->ptr = ptr; notify->notifyCount = notifyCount; notify->finalize(); return notify; } Store* makeStore(unsigned bytes, uint32_t offset, unsigned align, Expression* ptr, Expression* value, Type type) { auto* ret = allocator.alloc(); ret->isAtomic = false; ret->bytes = bytes; ret->offset = offset; ret->align = align; ret->ptr = ptr; ret->value = value; ret->valueType = type; ret->finalize(); assert(isConcreteType(ret->value->type) ? ret->value->type == type : true); return ret; } Store* makeAtomicStore(unsigned bytes, uint32_t offset, Expression* ptr, Expression* value, Type type) { Store* store = makeStore(bytes, offset, bytes, ptr, value, type); store->isAtomic = true; return store; } AtomicRMW* makeAtomicRMW(AtomicRMWOp op, unsigned bytes, uint32_t offset, Expression* ptr, Expression* value, Type type) { auto* ret = allocator.alloc(); ret->op = op; ret->bytes = bytes; ret->offset = offset; ret->ptr = ptr; ret->value = value; ret->type = type; ret->finalize(); return ret; } AtomicCmpxchg* makeAtomicCmpxchg(unsigned bytes, uint32_t offset, Expression* ptr, Expression* expected, Expression* replacement, Type type) { auto* ret = allocator.alloc(); ret->bytes = bytes; ret->offset = offset; ret->ptr = ptr; ret->expected = expected; ret->replacement = replacement; ret->type = type; ret->finalize(); return ret; } SIMDExtract* makeSIMDExtract(SIMDExtractOp op, Expression* vec, uint8_t index) { auto* ret = allocator.alloc(); ret->op = op; ret->vec = vec; ret->index = index; ret->finalize(); return ret; } SIMDReplace* makeSIMDReplace(SIMDReplaceOp op, Expression* vec, uint8_t index, Expression* value) { auto* ret = allocator.alloc(); ret->op = op; ret->vec = vec; ret->index = index; ret->value = value; ret->finalize(); return ret; } SIMDShuffle* makeSIMDShuffle(Expression* left, Expression* right, const std::array& mask) { auto* ret = allocator.alloc(); ret->left = left; ret->right = right; ret->mask = mask; ret->finalize(); return ret; } SIMDBitselect* makeSIMDBitselect(Expression* left, Expression* right, Expression* cond) { auto* ret = allocator.alloc(); ret->left = left; ret->right = right; ret->cond = cond; ret->finalize(); return ret; } SIMDShift* makeSIMDShift(SIMDShiftOp op, Expression* vec, Expression* shift) { auto* ret = allocator.alloc(); ret->op = op; ret->vec = vec; ret->shift = shift; ret->finalize(); return ret; } MemoryInit* makeMemoryInit(uint32_t segment, Expression* dest, Expression* offset, Expression* size) { auto* ret = allocator.alloc(); ret->segment = segment; ret->dest = dest; ret->offset = offset; ret->size = size; ret->finalize(); return ret; } DataDrop* makeDataDrop(uint32_t segment) { auto* ret = allocator.alloc(); ret->segment = segment; ret->finalize(); return ret; } MemoryCopy* makeMemoryCopy(Expression* dest, Expression* source, Expression* size) { auto* ret = allocator.alloc(); ret->dest = dest; ret->source = source; ret->size = size; ret->finalize(); return ret; } MemoryFill* makeMemoryFill(Expression* dest, Expression* value, Expression* size) { auto* ret = allocator.alloc(); ret->dest = dest; ret->value = value; ret->size = size; ret->finalize(); return ret; } Const* makeConst(Literal value) { assert(isConcreteType(value.type)); auto* ret = allocator.alloc(); ret->value = value; ret->type = value.type; return ret; } Unary* makeUnary(UnaryOp op, Expression* value) { auto* ret = allocator.alloc(); ret->op = op; ret->value = value; ret->finalize(); return ret; } Binary* makeBinary(BinaryOp op, Expression* left, Expression* right) { auto* ret = allocator.alloc(); ret->op = op; ret->left = left; ret->right = right; ret->finalize(); return ret; } Select* makeSelect(Expression* condition, Expression* ifTrue, Expression* ifFalse) { auto* ret = allocator.alloc