/* * 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. */ #include "wabt/ir-util.h" #include #include #include #include #include #include #include #include #include #include #include "wabt/cast.h" #include "wabt/common.h" #include "wabt/expr-visitor.h" #include "wabt/ir-util.h" #include "wabt/ir.h" #include "wabt/literal.h" #include "wabt/stream.h" #define WABT_TRACING 0 #include "wabt/tracing.h" using namespace wabt; const Label* ModuleContext::GetLabel(const Var& var) const { if (var.is_name()) { for (Index i = GetLabelStackSize(); i > 0; --i) { auto label = &label_stack_[i - 1]; if (label->name == var.name()) { return label; } } } else if (var.index() < GetLabelStackSize()) { auto label = &label_stack_[GetLabelStackSize() - var.index() - 1]; return label; } return nullptr; } Index ModuleContext::GetLabelArity(const Var& var) const { auto label = GetLabel(var); if (!label) { return 0; } return label->label_type == LabelType::Loop ? label->param_types.size() : label->result_types.size(); } Index ModuleContext::GetFuncParamCount(const Var& var) const { const Func* func = module.GetFunc(var); return func ? func->GetNumParams() : 0; } Index ModuleContext::GetFuncResultCount(const Var& var) const { const Func* func = module.GetFunc(var); return func ? func->GetNumResults() : 0; } void ModuleContext::BeginBlock(LabelType label_type, const Block& block) { label_stack_.emplace_back(label_type, block.label, block.decl.sig.param_types, block.decl.sig.result_types); } void ModuleContext::EndBlock() { label_stack_.pop_back(); } void ModuleContext::BeginFunc(const Func& func) { label_stack_.clear(); label_stack_.emplace_back(LabelType::Func, std::string(), TypeVector(), func.decl.sig.result_types); current_func_ = &func; } void ModuleContext::EndFunc() { current_func_ = nullptr; } ModuleContext::Arities ModuleContext::GetExprArity(const Expr& expr) const { switch (expr.type()) { case ExprType::AtomicNotify: case ExprType::AtomicRmw: case ExprType::Binary: case ExprType::Compare: case ExprType::TableGrow: return {2, 1}; case ExprType::AtomicStore: case ExprType::Store: case ExprType::TableSet: return {2, 0}; case ExprType::Block: return {0, cast(&expr)->block.decl.sig.GetNumResults()}; case ExprType::Br: return {GetLabelArity(cast(&expr)->var), 1, true}; case ExprType::BrIf: { Index arity = GetLabelArity(cast(&expr)->var); return {arity + 1, arity}; } case ExprType::BrTable: return {GetLabelArity(cast(&expr)->default_target) + 1, 1, true}; case ExprType::Call: { const Var& var = cast(&expr)->var; return {GetFuncParamCount(var), GetFuncResultCount(var)}; } case ExprType::ReturnCall: { const Var& var = cast(&expr)->var; return {GetFuncParamCount(var), GetFuncResultCount(var), true}; } case ExprType::CallIndirect: { const auto* ci_expr = cast(&expr); return {ci_expr->decl.GetNumParams() + 1, ci_expr->decl.GetNumResults()}; } case ExprType::CallRef: { const Var& var = cast(&expr)->function_type_index; return {GetFuncParamCount(var) + 1, GetFuncResultCount(var)}; } case ExprType::ReturnCallIndirect: { const auto* rci_expr = cast(&expr); return {rci_expr->decl.GetNumParams() + 1, rci_expr->decl.GetNumResults(), true}; } case ExprType::Const: case ExprType::GlobalGet: case ExprType::LocalGet: case ExprType::MemorySize: case ExprType::TableSize: case ExprType::RefNull: case ExprType::RefFunc: return {0, 1}; case ExprType::Unreachable: return {0, 1, true}; case ExprType::DataDrop: case ExprType::ElemDrop: case ExprType::AtomicFence: case ExprType::CodeMetadata: return {0, 0}; case ExprType::MemoryInit: case ExprType::TableInit: case ExprType::MemoryFill: case ExprType::MemoryCopy: case ExprType::TableCopy: case ExprType::TableFill: return {3, 0}; case ExprType::AtomicLoad: case ExprType::Convert: case ExprType::Load: case ExprType::LocalTee: case ExprType::MemoryGrow: case ExprType::Unary: case ExprType::TableGet: case ExprType::RefIsNull: case ExprType::LoadSplat: case ExprType::LoadZero: return {1, 1}; case ExprType::Drop: case ExprType::GlobalSet: case ExprType::LocalSet: return {1, 0}; case ExprType::If: return {1, cast(&expr)->true_.decl.sig.GetNumResults()}; case ExprType::Loop: return {0, cast(&expr)->block.decl.sig.GetNumResults()}; case ExprType::Nop: return {0, 0}; case ExprType::Return: return {static_cast(current_func_->decl.sig.result_types.size()), 1, true}; case ExprType::Rethrow: return {0, 0, true}; case ExprType::AtomicRmwCmpxchg: case ExprType::AtomicWait: case ExprType::Select: return {3, 1}; case ExprType::Throw: { auto throw_ = cast(&expr); Index operand_count = 0; if (Tag* tag = module.GetTag(throw_->var)) { operand_count = tag->decl.sig.param_types.size(); } return {operand_count, 0, true}; } case ExprType::Try: return {0, cast(&expr)->block.decl.sig.GetNumResults()}; case ExprType::Ternary: return {3, 1}; case ExprType::SimdLaneOp: { const Opcode opcode = cast(&expr)->opcode; switch (opcode) { case Opcode::I8X16ExtractLaneS: case Opcode::I8X16ExtractLaneU: case Opcode::I16X8ExtractLaneS: case Opcode::I16X8ExtractLaneU: case Opcode::I32X4ExtractLane: case Opcode::I64X2ExtractLane: case Opcode::F32X4ExtractLane: case Opcode::F64X2ExtractLane: return {1, 1}; case Opcode::I8X16ReplaceLane: case Opcode::I16X8ReplaceLane: case Opcode::I32X4ReplaceLane: case Opcode::I64X2ReplaceLane: case Opcode::F32X4ReplaceLane: case Opcode::F64X2ReplaceLane: return {2, 1}; default: fprintf(stderr, "Invalid Opcode for expr type: %s\n", GetExprTypeName(expr)); assert(0); return {0, 0}; } } case ExprType::SimdLoadLane: case ExprType::SimdStoreLane: { return {2, 1}; } case ExprType::SimdShuffleOp: return {2, 1}; } WABT_UNREACHABLE; }