Source code

Revision control

Copy as Markdown

Other Tools

/*
* 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
*
*
* 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 <algorithm>
#include <array>
#include <cassert>
#include <cinttypes>
#include <cstdarg>
#include <cstdio>
#include <iterator>
#include <map>
#include <string>
#include <vector>
#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<BlockExpr>(&expr)->block.decl.sig.GetNumResults()};
case ExprType::Br:
return {GetLabelArity(cast<BrExpr>(&expr)->var), 1, true};
case ExprType::BrIf: {
Index arity = GetLabelArity(cast<BrIfExpr>(&expr)->var);
return {arity + 1, arity};
}
case ExprType::BrTable:
return {GetLabelArity(cast<BrTableExpr>(&expr)->default_target) + 1, 1,
true};
case ExprType::Call: {
const Var& var = cast<CallExpr>(&expr)->var;
return {GetFuncParamCount(var), GetFuncResultCount(var)};
}
case ExprType::ReturnCall: {
const Var& var = cast<ReturnCallExpr>(&expr)->var;
return {GetFuncParamCount(var), GetFuncResultCount(var), true};
}
case ExprType::CallIndirect: {
const auto* ci_expr = cast<CallIndirectExpr>(&expr);
return {ci_expr->decl.GetNumParams() + 1, ci_expr->decl.GetNumResults()};
}
case ExprType::CallRef: {
const Var& var = cast<CallRefExpr>(&expr)->function_type_index;
return {GetFuncParamCount(var) + 1, GetFuncResultCount(var)};
}
case ExprType::ReturnCallIndirect: {
const auto* rci_expr = cast<ReturnCallIndirectExpr>(&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<IfExpr>(&expr)->true_.decl.sig.GetNumResults()};
case ExprType::Loop:
return {0, cast<LoopExpr>(&expr)->block.decl.sig.GetNumResults()};
case ExprType::Nop:
return {0, 0};
case ExprType::Return:
return {static_cast<Index>(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<ThrowExpr>(&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<TryExpr>(&expr)->block.decl.sig.GetNumResults()};
case ExprType::Ternary:
return {3, 1};
case ExprType::SimdLaneOp: {
const Opcode opcode = cast<SimdLaneOpExpr>(&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;
}