summaryrefslogtreecommitdiff
path: root/src/passes
diff options
context:
space:
mode:
authorAlon Zakai <alonzakai@gmail.com>2018-09-19 15:50:30 -0700
committerGitHub <noreply@github.com>2018-09-19 15:50:30 -0700
commitfe88b47749115009da0447e340cbdc86edf30984 (patch)
tree7dfd9aba7086c8aa6dff4877ac1ee3b9d78bc5ce /src/passes
parenta53356ab155a7d8c2f334dc9a3c1432bacbc78fe (diff)
downloadbinaryen-fe88b47749115009da0447e340cbdc86edf30984.tar.gz
binaryen-fe88b47749115009da0447e340cbdc86edf30984.tar.bz2
binaryen-fe88b47749115009da0447e340cbdc86edf30984.zip
Unify imported and non-imported things (#1678)
Fixes #1649 This moves us to a single object for functions, which can be imported or nor, and likewise for globals (as a result, GetGlobals do not need to check if the global is imported or not, etc.). All imported things now inherit from Importable, which has the module and base of the import, and if they are set then it is an import. For convenient iteration, there are a few helpers like ModuleUtils::iterDefinedGlobals(wasm, [&](Global* global) { .. use global .. }); as often iteration only cares about imported or defined (non-imported) things.
Diffstat (limited to 'src/passes')
-rw-r--r--src/passes/DeadArgumentElimination.cpp23
-rw-r--r--src/passes/DeadCodeElimination.cpp5
-rw-r--r--src/passes/DuplicateFunctionElimination.cpp7
-rw-r--r--src/passes/FuncCastEmulation.cpp11
-rw-r--r--src/passes/I64ToI32Lowering.cpp7
-rw-r--r--src/passes/Inlining.cpp29
-rw-r--r--src/passes/InstrumentLocals.cpp14
-rw-r--r--src/passes/InstrumentMemory.cpp14
-rw-r--r--src/passes/LegalizeJSInterface.cpp92
-rw-r--r--src/passes/LogExecution.cpp12
-rw-r--r--src/passes/MergeBlocks.cpp4
-rw-r--r--src/passes/Metrics.cpp29
-rw-r--r--src/passes/NameList.cpp5
-rw-r--r--src/passes/OptimizeInstructions.cpp126
-rw-r--r--src/passes/PostEmscripten.cpp9
-rw-r--r--src/passes/Precompute.cpp11
-rw-r--r--src/passes/Print.cpp133
-rw-r--r--src/passes/PrintCallGraph.cpp35
-rw-r--r--src/passes/RemoveImports.cpp23
-rw-r--r--src/passes/RemoveUnusedModuleElements.cpp73
-rw-r--r--src/passes/SafeHeap.cpp38
-rw-r--r--src/passes/SpillPointers.cpp7
-rw-r--r--src/passes/TrapMode.cpp10
-rw-r--r--src/passes/Vacuum.cpp1
-rw-r--r--src/passes/pass.cpp25
25 files changed, 303 insertions, 440 deletions
diff --git a/src/passes/DeadArgumentElimination.cpp b/src/passes/DeadArgumentElimination.cpp
index b1a1008f4..434ea1ece 100644
--- a/src/passes/DeadArgumentElimination.cpp
+++ b/src/passes/DeadArgumentElimination.cpp
@@ -36,13 +36,14 @@
#include <unordered_map>
#include <unordered_set>
-#include <wasm.h>
-#include <pass.h>
-#include <wasm-builder.h>
-#include <cfg/cfg-traversal.h>
-#include <ir/effects.h>
-#include <passes/opt-utils.h>
-#include <support/sorted_vector.h>
+#include "wasm.h"
+#include "pass.h"
+#include "wasm-builder.h"
+#include "cfg/cfg-traversal.h"
+#include "ir/effects.h"
+#include "ir/module-utils.h"
+#include "passes/opt-utils.h"
+#include "support/sorted_vector.h"
namespace wasm {
@@ -110,7 +111,9 @@ struct DAEScanner : public WalkerPass<CFGWalker<DAEScanner, Visitor<DAEScanner>,
}
void visitCall(Call* curr) {
- info->calls[curr->target].push_back(curr);
+ if (!getModule()->getFunction(curr->target)->imported()) {
+ info->calls[curr->target].push_back(curr);
+ }
}
// main entry point
@@ -196,9 +199,9 @@ struct DAE : public Pass {
void run(PassRunner* runner, Module* module) override {
DAEFunctionInfoMap infoMap;
// Ensure they all exist so the parallel threads don't modify the data structure.
- for (auto& func : module->functions) {
+ ModuleUtils::iterDefinedFunctions(*module, [&](Function* func) {
infoMap[func->name];
- }
+ });
// Check the influence of the table and exports.
for (auto& curr : module->exports) {
if (curr->kind == ExternalKind::Function) {
diff --git a/src/passes/DeadCodeElimination.cpp b/src/passes/DeadCodeElimination.cpp
index 1879b1fc8..87dbacf64 100644
--- a/src/passes/DeadCodeElimination.cpp
+++ b/src/passes/DeadCodeElimination.cpp
@@ -237,7 +237,6 @@ struct DeadCodeElimination : public WalkerPass<PostWalker<DeadCodeElimination>>
case Expression::Id::BreakId: DELEGATE(Break);
case Expression::Id::SwitchId: DELEGATE(Switch);
case Expression::Id::CallId: DELEGATE(Call);
- case Expression::Id::CallImportId: DELEGATE(CallImport);
case Expression::Id::CallIndirectId: DELEGATE(CallIndirect);
case Expression::Id::GetLocalId: DELEGATE(GetLocal);
case Expression::Id::SetLocalId: DELEGATE(SetLocal);
@@ -312,10 +311,6 @@ struct DeadCodeElimination : public WalkerPass<PostWalker<DeadCodeElimination>>
handleCall(curr);
}
- void visitCallImport(CallImport* curr) {
- handleCall(curr);
- }
-
void visitCallIndirect(CallIndirect* curr) {
if (handleCall(curr) != curr) return;
if (isUnreachable(curr->target)) {
diff --git a/src/passes/DuplicateFunctionElimination.cpp b/src/passes/DuplicateFunctionElimination.cpp
index 60667cdd6..b7fcb556c 100644
--- a/src/passes/DuplicateFunctionElimination.cpp
+++ b/src/passes/DuplicateFunctionElimination.cpp
@@ -25,6 +25,7 @@
#include "ir/utils.h"
#include "ir/function-utils.h"
#include "ir/hashed.h"
+#include "ir/module-utils.h"
namespace wasm {
@@ -72,9 +73,9 @@ struct DuplicateFunctionElimination : public Pass {
hasherRunner.run();
// Find hash-equal groups
std::map<uint32_t, std::vector<Function*>> hashGroups;
- for (auto& func : module->functions) {
- hashGroups[hashes[func.get()]].push_back(func.get());
- }
+ ModuleUtils::iterDefinedFunctions(*module, [&](Function* func) {
+ hashGroups[hashes[func]].push_back(func);
+ });
// Find actually equal functions and prepare to replace them
std::map<Name, Name> replacements;
std::set<Name> duplicates;
diff --git a/src/passes/FuncCastEmulation.cpp b/src/passes/FuncCastEmulation.cpp
index 013e9403e..30ae3e5e8 100644
--- a/src/passes/FuncCastEmulation.cpp
+++ b/src/passes/FuncCastEmulation.cpp
@@ -200,18 +200,15 @@ private:
Fatal() << "FuncCastEmulation::makeThunk seems a thunk name already in use. Was the pass already run on this code?";
}
// The item in the table may be a function or a function import.
- auto* func = module->getFunctionOrNull(name);
- Import* imp = nullptr;
- if (!func) imp = module->getImport(name);
- std::vector<Type>& params = func ? func->params : module->getFunctionType(imp->functionType)->params;
- Type type = func ? func->result : module->getFunctionType(imp->functionType)->result;
+ auto* func = module->getFunction(name);
+ std::vector<Type>& params = func->params;
+ Type type = func->result;
Builder builder(*module);
std::vector<Expression*> callOperands;
for (Index i = 0; i < params.size(); i++) {
callOperands.push_back(fromABI(builder.makeGetLocal(i, i64), params[i], module));
}
- Expression* call = func ? (Expression*)builder.makeCall(name, callOperands, type)
- : (Expression*)builder.makeCallImport(name, callOperands, type);
+ auto* call = builder.makeCall(name, callOperands, type);
std::vector<Type> thunkParams;
for (Index i = 0; i < NUM_PARAMS; i++) {
thunkParams.push_back(i64);
diff --git a/src/passes/I64ToI32Lowering.cpp b/src/passes/I64ToI32Lowering.cpp
index 2986deb9f..697df1eef 100644
--- a/src/passes/I64ToI32Lowering.cpp
+++ b/src/passes/I64ToI32Lowering.cpp
@@ -105,7 +105,7 @@ struct I64ToI32Lowering : public WalkerPass<PostWalker<I64ToI32Lowering>> {
auto& curr = module->globals[i];
if (curr->type != i64) continue;
curr->type = i32;
- auto* high = new Global(*curr);
+ auto* high = ModuleUtils::copyGlobal(curr.get(), *module);
high->name = makeHighName(curr->name);
module->addGlobal(high);
}
@@ -361,11 +361,6 @@ struct I64ToI32Lowering : public WalkerPass<PostWalker<I64ToI32Lowering>> {
);
}
- void visitCallImport(CallImport* curr) {
- // imports cannot contain i64s
- return;
- }
-
void visitCallIndirect(CallIndirect* curr) {
visitGenericCall<CallIndirect>(
curr,
diff --git a/src/passes/Inlining.cpp b/src/passes/Inlining.cpp
index a507e5fc8..ebc33bf97 100644
--- a/src/passes/Inlining.cpp
+++ b/src/passes/Inlining.cpp
@@ -32,13 +32,14 @@
#include <atomic>
-#include <wasm.h>
-#include <pass.h>
-#include <wasm-builder.h>
-#include <ir/utils.h>
-#include <ir/literal-utils.h>
-#include <parsing.h>
-#include <passes/opt-utils.h>
+#include "wasm.h"
+#include "pass.h"
+#include "wasm-builder.h"
+#include "ir/literal-utils.h"
+#include "ir/module-utils.h"
+#include "ir/utils.h"
+#include "parsing.h"
+#include "passes/opt-utils.h"
namespace wasm {
@@ -117,11 +118,6 @@ struct FunctionInfoScanner : public WalkerPass<PostWalker<FunctionInfoScanner>>
(*infos)[getFunction()->name].lightweight = false;
}
- void visitCallImport(CallImport* curr) {
- // having a call is not lightweight
- (*infos)[getFunction()->name].lightweight = false;
- }
-
void visitFunction(Function* curr) {
(*infos)[curr->name].size = Measurer::measure(curr->body);
}
@@ -279,9 +275,7 @@ struct Inlining : public Pass {
}
for (auto& segment : module->table.segments) {
for (auto name : segment.data) {
- if (module->getFunctionOrNull(name)) {
- infos[name].usedGlobally = true;
- }
+ infos[name].usedGlobally = true;
}
}
}
@@ -289,12 +283,11 @@ struct Inlining : public Pass {
bool iteration(PassRunner* runner, Module* module) {
// decide which to inline
InliningState state;
- for (auto& func : module->functions) {
- // on the first iteration, allow multiple inlinings per function
+ ModuleUtils::iterDefinedFunctions(*module, [&](Function* func) {
if (infos[func->name].worthInlining(runner->options)) {
state.worthInlining.insert(func->name);
}
- }
+ });
if (state.worthInlining.size() == 0) return false;
// fill in actionsForFunction, as we operate on it in parallel (each function to its own entry)
for (auto& func : module->functions) {
diff --git a/src/passes/InstrumentLocals.cpp b/src/passes/InstrumentLocals.cpp
index 22b8ebf70..4da41da17 100644
--- a/src/passes/InstrumentLocals.cpp
+++ b/src/passes/InstrumentLocals.cpp
@@ -49,6 +49,7 @@
#include "shared-constants.h"
#include "asmjs/shared-constants.h"
#include "asm_v_wasm.h"
+#include "ir/function-type-utils.h"
namespace wasm {
@@ -74,7 +75,7 @@ struct InstrumentLocals : public WalkerPass<PostWalker<InstrumentLocals>> {
default: WASM_UNREACHABLE();
}
replaceCurrent(
- builder.makeCallImport(
+ builder.makeCall(
import,
{
builder.makeConst(Literal(int32_t(id++))),
@@ -97,7 +98,7 @@ struct InstrumentLocals : public WalkerPass<PostWalker<InstrumentLocals>> {
case unreachable: return; // nothing to do here
default: WASM_UNREACHABLE();
}
- curr->value = builder.makeCallImport(
+ curr->value = builder.makeCall(
import,
{
builder.makeConst(Literal(int32_t(id++))),
@@ -123,13 +124,14 @@ private:
Index id = 0;
void addImport(Module* wasm, Name name, std::string sig) {
- auto import = new Import;
+ auto import = new Function;
import->name = name;
import->module = INSTRUMENT;
import->base = name;
- import->functionType = ensureFunctionType(sig, wasm)->name;
- import->kind = ExternalKind::Function;
- wasm->addImport(import);
+ auto* functionType = ensureFunctionType(sig, wasm);
+ import->type = functionType->name;
+ FunctionTypeUtils::fillFunction(import, functionType);
+ wasm->addFunction(import);
}
};
diff --git a/src/passes/InstrumentMemory.cpp b/src/passes/InstrumentMemory.cpp
index d9a5a4316..17b5850f4 100644
--- a/src/passes/InstrumentMemory.cpp
+++ b/src/passes/InstrumentMemory.cpp
@@ -61,6 +61,7 @@
#include "shared-constants.h"
#include "asmjs/shared-constants.h"
#include "asm_v_wasm.h"
+#include "ir/function-type-utils.h"
namespace wasm {
@@ -76,13 +77,14 @@ struct InstrumentMemory : public WalkerPass<PostWalker<InstrumentMemory>> {
makeStoreCall(curr);
}
void addImport(Module *curr, Name name, std::string sig) {
- auto import = new Import;
+ auto import = new Function;
import->name = name;
import->module = INSTRUMENT;
import->base = name;
- import->functionType = ensureFunctionType(sig, curr)->name;
- import->kind = ExternalKind::Function;
- curr->addImport(import);
+ auto* functionType = ensureFunctionType(sig, curr);
+ import->type = functionType->name;
+ FunctionTypeUtils::fillFunction(import, functionType);
+ curr->addFunction(import);
}
void visitModule(Module *curr) {
@@ -94,7 +96,7 @@ private:
std::atomic<Index> id;
Expression* makeLoadCall(Load* curr) {
Builder builder(*getModule());
- curr->ptr = builder.makeCallImport(load,
+ curr->ptr = builder.makeCall(load,
{ builder.makeConst(Literal(int32_t(id.fetch_add(1)))),
builder.makeConst(Literal(int32_t(curr->bytes))),
builder.makeConst(Literal(int32_t(curr->offset.addr))),
@@ -106,7 +108,7 @@ private:
Expression* makeStoreCall(Store* curr) {
Builder builder(*getModule());
- curr->ptr = builder.makeCallImport(store,
+ curr->ptr = builder.makeCall(store,
{ builder.makeConst(Literal(int32_t(id.fetch_add(1)))),
builder.makeConst(Literal(int32_t(curr->bytes))),
builder.makeConst(Literal(int32_t(curr->offset.addr))),
diff --git a/src/passes/LegalizeJSInterface.cpp b/src/passes/LegalizeJSInterface.cpp
index 1f02cd4d7..5f64ad2e6 100644
--- a/src/passes/LegalizeJSInterface.cpp
+++ b/src/passes/LegalizeJSInterface.cpp
@@ -26,11 +26,12 @@
// disallow f32s. TODO: an option to not do that, if it matters?
//
-#include <wasm.h>
-#include <pass.h>
-#include <wasm-builder.h>
-#include <ir/utils.h>
-#include <ir/literal-utils.h>
+#include "wasm.h"
+#include "pass.h"
+#include "wasm-builder.h"
+#include "ir/function-type-utils.h"
+#include "ir/literal-utils.h"
+#include "ir/utils.h"
namespace wasm {
@@ -44,22 +45,23 @@ struct LegalizeJSInterface : public Pass {
for (auto& ex : module->exports) {
if (ex->kind == ExternalKind::Function) {
// if it's an import, ignore it
- if (auto* func = module->getFunctionOrNull(ex->value)) {
- if (isIllegal(func)) {
- auto legalName = makeLegalStub(func, module);
- ex->value = legalName;
- }
+ auto* func = module->getFunction(ex->value);
+ if (isIllegal(func)) {
+ auto legalName = makeLegalStub(func, module);
+ ex->value = legalName;
}
}
}
+ // Avoid iterator invalidation later.
+ std::vector<Function*> originalFunctions;
+ for (auto& func : module->functions) {
+ originalFunctions.push_back(func.get());
+ }
// for each illegal import, we must call a legalized stub instead
- std::vector<Import*> newImports; // add them at the end, to not invalidate the iter
- for (auto& im : module->imports) {
- if (im->kind == ExternalKind::Function && isIllegal(module->getFunctionType(im->functionType))) {
- Name funcName;
- auto* legal = makeLegalStub(im.get(), module, funcName);
- illegalToLegal[im->name] = funcName;
- newImports.push_back(legal);
+ for (auto* im : originalFunctions) {
+ if (im->imported() && isIllegal(module->getFunctionType(im->type))) {
+ auto funcName = makeLegalStubForCalledImport(im, module);
+ illegalImportsToLegal[im->name] = funcName;
// we need to use the legalized version in the table, as the import from JS
// is legal for JS. Our stub makes it look like a native wasm function.
for (auto& segment : module->table.segments) {
@@ -71,13 +73,9 @@ struct LegalizeJSInterface : public Pass {
}
}
}
- if (illegalToLegal.size() > 0) {
- for (auto& pair : illegalToLegal) {
- module->removeImport(pair.first);
- }
-
- for (auto* im : newImports) {
- module->addImport(im);
+ if (illegalImportsToLegal.size() > 0) {
+ for (auto& pair : illegalImportsToLegal) {
+ module->removeFunction(pair.first);
}
// fix up imports: call_import of an illegal must be turned to a call of a legal
@@ -85,15 +83,15 @@ struct LegalizeJSInterface : public Pass {
struct FixImports : public WalkerPass<PostWalker<FixImports>> {
bool isFunctionParallel() override { return true; }
- Pass* create() override { return new FixImports(illegalToLegal); }
+ Pass* create() override { return new FixImports(illegalImportsToLegal); }
- std::map<Name, Name>* illegalToLegal;
+ std::map<Name, Name>* illegalImportsToLegal;
- FixImports(std::map<Name, Name>* illegalToLegal) : illegalToLegal(illegalToLegal) {}
+ FixImports(std::map<Name, Name>* illegalImportsToLegal) : illegalImportsToLegal(illegalImportsToLegal) {}
- void visitCallImport(CallImport* curr) {
- auto iter = illegalToLegal->find(curr->target);
- if (iter == illegalToLegal->end()) return;
+ void visitCall(Call* curr) {
+ auto iter = illegalImportsToLegal->find(curr->target);
+ if (iter == illegalImportsToLegal->end()) return;
if (iter->second == getFunction()->name) return; // inside the stub function itself, is the one safe place to do the call
replaceCurrent(Builder(*getModule()).makeCall(iter->second, curr->operands, curr->type));
@@ -102,7 +100,7 @@ struct LegalizeJSInterface : public Pass {
PassRunner passRunner(module);
passRunner.setIsNested(true);
- passRunner.add<FixImports>(&illegalToLegal);
+ passRunner.add<FixImports>(&illegalImportsToLegal);
passRunner.run();
}
@@ -113,7 +111,7 @@ struct LegalizeJSInterface : public Pass {
private:
// map of illegal to legal names for imports
- std::map<Name, Name> illegalToLegal;
+ std::map<Name, Name> illegalImportsToLegal;
bool needTempRet0Helpers = false;
@@ -179,24 +177,22 @@ private:
}
// wasm calls the import, so it must call a stub that calls the actual legal JS import
- Import* makeLegalStub(Import* im, Module* module, Name& funcName) {
+ Name makeLegalStubForCalledImport(Function* im, Module* module) {
Builder builder(*module);
- auto* type = new FunctionType();
+ auto* type = new FunctionType;
type->name = Name(std::string("legaltype$") + im->name.str);
- auto* legal = new Import();
+ auto* legal = new Function;
legal->name = Name(std::string("legalimport$") + im->name.str);
legal->module = im->module;
legal->base = im->base;
- legal->kind = ExternalKind::Function;
- legal->functionType = type->name;
- auto* func = new Function();
+ legal->type = type->name;
+ auto* func = new Function;
func->name = Name(std::string("legalfunc$") + im->name.str);
- funcName = func->name;
- auto* call = module->allocator.alloc<CallImport>();
+ auto* call = module->allocator.alloc<Call>();
call->target = legal->name;
- auto* imFunctionType = module->getFunctionType(im->functionType);
+ auto* imFunctionType = module->getFunctionType(im->type);
for (auto param : imFunctionType->params) {
if (param == i64) {
@@ -231,10 +227,18 @@ private:
type->result = imFunctionType->result;
}
func->result = imFunctionType->result;
+ FunctionTypeUtils::fillFunction(legal, type);
- module->addFunction(func);
- module->addFunctionType(type);
- return legal;
+ if (!module->getFunctionOrNull(func->name)) {
+ module->addFunction(func);
+ }
+ if (!module->getFunctionTypeOrNull(type->name)) {
+ module->addFunctionType(type);
+ }
+ if (!module->getFunctionOrNull(legal->name)) {
+ module->addFunction(legal);
+ }
+ return func->name;
}
void ensureTempRet0(Module* module) {
diff --git a/src/passes/LogExecution.cpp b/src/passes/LogExecution.cpp
index 8d555fefe..45a29eae9 100644
--- a/src/passes/LogExecution.cpp
+++ b/src/passes/LogExecution.cpp
@@ -30,6 +30,7 @@
#include "shared-constants.h"
#include "asmjs/shared-constants.h"
#include "asm_v_wasm.h"
+#include "ir/function-type-utils.h"
namespace wasm {
@@ -46,13 +47,14 @@ struct LogExecution : public WalkerPass<PostWalker<LogExecution>> {
void visitModule(Module *curr) {
// Add the import
- auto import = new Import;
+ auto import = new Function;
import->name = LOGGER;
import->module = ENV;
import->base = LOGGER;
- import->functionType = ensureFunctionType("vi", curr)->name;
- import->kind = ExternalKind::Function;
- curr->addImport(import);
+ auto* functionType = ensureFunctionType("vi", curr);
+ import->type = functionType->name;
+ FunctionTypeUtils::fillFunction(import, functionType);
+ curr->addFunction(import);
}
private:
@@ -60,7 +62,7 @@ private:
static Index id = 0;
Builder builder(*getModule());
return builder.makeSequence(
- builder.makeCallImport(
+ builder.makeCall(
LOGGER,
{ builder.makeConst(Literal(int32_t(id++))) },
none
diff --git a/src/passes/MergeBlocks.cpp b/src/passes/MergeBlocks.cpp
index a68b202d7..352a0a08d 100644
--- a/src/passes/MergeBlocks.cpp
+++ b/src/passes/MergeBlocks.cpp
@@ -453,10 +453,6 @@ struct MergeBlocks : public WalkerPass<PostWalker<MergeBlocks>> {
handleCall(curr);
}
- void visitCallImport(CallImport* curr) {
- handleCall(curr);
- }
-
void visitCallIndirect(CallIndirect* curr) {
Block* outer = nullptr;
for (Index i = 0; i < curr->operands.size(); i++) {
diff --git a/src/passes/Metrics.cpp b/src/passes/Metrics.cpp
index 81706042b..5176f8762 100644
--- a/src/passes/Metrics.cpp
+++ b/src/passes/Metrics.cpp
@@ -46,25 +46,26 @@ struct Metrics : public WalkerPass<PostWalker<Metrics, UnifiedExpressionVisitor<
}
void doWalkModule(Module* module) {
+ ImportInfo imports(*module);
+
// global things
for (auto& curr : module->functionTypes) {
visitFunctionType(curr.get());
}
- for (auto& curr : module->imports) {
- visitImport(curr.get());
- }
for (auto& curr : module->exports) {
visitExport(curr.get());
}
- for (auto& curr : module->globals) {
- walkGlobal(curr.get());
- }
+ ModuleUtils::iterDefinedGlobals(*module, [&](Global* curr) {
+ walkGlobal(curr);
+ });
walkTable(&module->table);
walkMemory(&module->memory);
+ // add imports
+ counts["[imports]"] = imports.getNumImports();
// add functions
- counts["[funcs]"] = module->functions.size();
+ counts["[funcs]"] = imports.getNumDefinedFunctions();
// add memory and table
if (module->memory.exists) {
Index size = 0;
@@ -89,14 +90,14 @@ struct Metrics : public WalkerPass<PostWalker<Metrics, UnifiedExpressionVisitor<
WasmBinaryWriter writer(module, buffer);
writer.write();
// print for each function
- for (Index i = 0; i < module->functions.size(); i++) {
- auto* func = module->functions[i].get();
+ Index binaryIndex = 0;
+ ModuleUtils::iterDefinedFunctions(*module, [&](Function* func) {
counts.clear();
walkFunction(func);
counts["[vars]"] = func->getNumVars();
- counts["[binary-bytes]"] = writer.tableOfContents.functionBodies[i].size;
+ counts["[binary-bytes]"] = writer.tableOfContents.functionBodies[binaryIndex++].size;
printCounts(std::string("func: ") + func->name.str);
- }
+ });
// print for each export how much code size is due to it, i.e.,
// how much the module could shrink without it.
auto sizeAfterGlobalCleanup = [](Module* module) {
@@ -138,10 +139,10 @@ struct Metrics : public WalkerPass<PostWalker<Metrics, UnifiedExpressionVisitor<
} else {
// add function info
size_t vars = 0;
- for (auto& func : module->functions) {
- walkFunction(func.get());
+ ModuleUtils::iterDefinedFunctions(*module, [&](Function* func) {
+ walkFunction(func);
vars += func->getNumVars();
- }
+ });
counts["[vars]"] = vars;
// print
printCounts("total");
diff --git a/src/passes/NameList.cpp b/src/passes/NameList.cpp
index ebc3a5c55..6b1d528e4 100644
--- a/src/passes/NameList.cpp
+++ b/src/passes/NameList.cpp
@@ -20,15 +20,16 @@
#include "wasm.h"
#include "pass.h"
+#include "ir/module-utils.h"
#include "ir/utils.h"
namespace wasm {
struct NameList : public Pass {
void run(PassRunner* runner, Module* module) override {
- for (auto& func : module->functions) {
+ ModuleUtils::iterDefinedFunctions(*module, [&](Function* func) {
std::cout << " " << func->name << " : " << Measurer::measure(func->body) << '\n';
- }
+ });
}
};
diff --git a/src/passes/OptimizeInstructions.cpp b/src/passes/OptimizeInstructions.cpp
index 73f78611b..255ff4cbd 100644
--- a/src/passes/OptimizeInstructions.cpp
+++ b/src/passes/OptimizeInstructions.cpp
@@ -43,132 +43,6 @@ Name I32_EXPR = "i32.expr",
F64_EXPR = "f64.expr",
ANY_EXPR = "any.expr";
-// A pattern
-struct Pattern {
- Expression* input;
- Expression* output;
-
- Pattern(Expression* input, Expression* output) : input(input), output(output) {}
-};
-
-#if 0
-// Database of patterns
-struct PatternDatabase {
- Module wasm;
-
- char* input;
-
- std::map<Expression::Id, std::vector<Pattern>> patternMap; // root expression id => list of all patterns for it TODO optimize more
-
- PatternDatabase() {
- // generate module
- input = strdup(
- #include "OptimizeInstructions.wast.processed"
- );
- try {
- SExpressionParser parser(input);
- Element& root = *parser.root;
- SExpressionWasmBuilder builder(wasm, *root[0]);
- // parse module form
- auto* func = wasm.getFunction("patterns");
- auto* body = func->body->cast<Block>();
- for (auto* item : body->list) {
- auto* pair = item->cast<Block>();
- patternMap[pair->list[0]->_id].emplace_back(pair->list[0], pair->list[1]);
- }
- } catch (ParseException& p) {
- p.dump(std::cerr);
- Fatal() << "error in parsing wasm binary";
- }
- }
-
- ~PatternDatabase() {
- free(input);
- };
-};
-
-static PatternDatabase* database = nullptr;
-
-struct DatabaseEnsurer {
- DatabaseEnsurer() {
- assert(!database);
- database = new PatternDatabase;
- }
-};
-#endif
-
-// Check for matches and apply them
-struct Match {
- Module& wasm;
- Pattern& pattern;
-
- Match(Module& wasm, Pattern& pattern) : wasm(wasm), pattern(pattern) {}
-
- std::vector<Expression*> wildcards; // id in i32.any(id) etc. => the expression it represents in this match
-
- // Comparing/checking
-
- // Check if we can match to this pattern, updating ourselves with the info if so
- bool check(Expression* seen) {
- // compare seen to the pattern input, doing a special operation for our "wildcards"
- assert(wildcards.size() == 0);
- auto compare = [this](Expression* subInput, Expression* subSeen) {
- CallImport* call = subInput->dynCast<CallImport>();
- if (!call || call->operands.size() != 1 || call->operands[0]->type != i32 || !call->operands[0]->is<Const>()) return false;
- Index index = call->operands[0]->cast<Const>()->value.geti32();
- // handle our special functions
- auto checkMatch = [&](Type type) {
- if (type != none && subSeen->type != type) return false;
- while (index >= wildcards.size()) {
- wildcards.push_back(nullptr);
- }
- if (!wildcards[index]) {
- // new wildcard
- wildcards[index] = subSeen; // NB: no need to copy
- return true;
- } else {
- // We are seeing this index for a second or later time, check it matches
- return ExpressionAnalyzer::equal(subSeen, wildcards[index]);
- };
- };
- if (call->target == I32_EXPR) {
- if (checkMatch(i32)) return true;
- } else if (call->target == I64_EXPR) {
- if (checkMatch(i64)) return true;
- } else if (call->target == F32_EXPR) {
- if (checkMatch(f32)) return true;
- } else if (call->target == F64_EXPR) {
- if (checkMatch(f64)) return true;
- } else if (call->target == ANY_EXPR) {
- if (checkMatch(none)) return true;
- }
- return false;
- };
-
- return ExpressionAnalyzer::flexibleEqual(pattern.input, seen, compare);
- }
-
-
- // Applying/copying
-
- // Apply the match, generate an output expression from the matched input, performing substitutions as necessary
- Expression* apply() {
- // When copying a wildcard, perform the substitution.
- // TODO: we can reuse nodes, not copying a wildcard when it appears just once, and we can reuse other individual nodes when they are discarded anyhow.
- auto copy = [this](Expression* curr) -> Expression* {
- CallImport* call = curr->dynCast<CallImport>();
- if (!call || call->operands.size() != 1 || call->operands[0]->type != i32 || !call->operands[0]->is<Const>()) return nullptr;
- Index index = call->operands[0]->cast<Const>()->value.geti32();
- // handle our special functions
- if (call->target == I32_EXPR || call->target == I64_EXPR || call->target == F32_EXPR || call->target == F64_EXPR || call->target == ANY_EXPR) {
- return ExpressionManipulator::copy(wildcards.at(index), wasm);
- }
- return nullptr;
- };
- return ExpressionManipulator::flexibleCopy(pattern.output, wasm, copy);
- }
-};
-
// Utilities
// returns the maximum amount of bits used in an integer expression
diff --git a/src/passes/PostEmscripten.cpp b/src/passes/PostEmscripten.cpp
index a7f0e6282..72c0d8808 100644
--- a/src/passes/PostEmscripten.cpp
+++ b/src/passes/PostEmscripten.cpp
@@ -92,11 +92,12 @@ struct PostEmscripten : public WalkerPass<PostWalker<PostEmscripten>> {
optimizeMemoryAccess(curr->ptr, curr->offset);
}
- void visitCallImport(CallImport* curr) {
+ void visitCall(Call* curr) {
// special asm.js imports can be optimized
- auto* import = getModule()->getImport(curr->target);
- if (import->module == GLOBAL_MATH) {
- if (import->base == POW) {
+ auto* func = getModule()->getFunction(curr->target);
+ if (!func->imported()) return;
+ if (func->module == GLOBAL_MATH) {
+ if (func->base == POW) {
if (auto* exponent = curr->operands[1]->dynCast<Const>()) {
if (exponent->value == Literal(double(2.0))) {
// This is just a square operation, do a multiply
diff --git a/src/passes/Precompute.cpp b/src/passes/Precompute.cpp
index 9735b91d7..b6b7d5097 100644
--- a/src/passes/Precompute.cpp
+++ b/src/passes/Precompute.cpp
@@ -61,9 +61,6 @@ public:
Flow visitCall(Call* curr) {
return Flow(NOTPRECOMPUTABLE_FLOW);
}
- Flow visitCallImport(CallImport* curr) {
- return Flow(NOTPRECOMPUTABLE_FLOW);
- }
Flow visitCallIndirect(CallIndirect* curr) {
return Flow(NOTPRECOMPUTABLE_FLOW);
}
@@ -89,11 +86,9 @@ public:
return Flow(NOTPRECOMPUTABLE_FLOW);
}
Flow visitGetGlobal(GetGlobal *curr) {
- auto* global = module->getGlobalOrNull(curr->name);
- if (global) {
- if (!global->mutable_) {
- return visit(global->init);
- }
+ auto* global = module->getGlobal(curr->name);
+ if (!global->imported() && !global->mutable_) {
+ return visit(global->init);
}
return Flow(NOTPRECOMPUTABLE_FLOW);
}
diff --git a/src/passes/Print.cpp b/src/passes/Print.cpp
index 77562af4b..3ab1cc75d 100644
--- a/src/passes/Print.cpp
+++ b/src/passes/Print.cpp
@@ -109,10 +109,6 @@ struct PrintExpressionContents : public Visitor<PrintExpressionContents> {
printMedium(o, "call ");
printName(curr->target, o);
}
- void visitCallImport(CallImport* curr) {
- printMedium(o, "call ");
- printName(curr->target, o);
- }
void visitCallIndirect(CallIndirect* curr) {
printMedium(o, "call_indirect (type ") << curr->fullType << ')';
}
@@ -478,6 +474,7 @@ struct PrintSExpression : public Visitor<PrintSExpression> {
}
void decIndent() {
if (!minify) {
+ assert(indent > 0);
indent--;
doIndent(o, indent);
}
@@ -636,11 +633,6 @@ struct PrintSExpression : public Visitor<PrintSExpression> {
PrintExpressionContents(currFunction, o).visit(curr);
printCallOperands(curr);
}
- void visitCallImport(CallImport* curr) {
- o << '(';
- PrintExpressionContents(currFunction, o).visit(curr);
- printCallOperands(curr);
- }
void visitCallIndirect(CallIndirect* curr) {
o << '(';
PrintExpressionContents(currFunction, o).visit(curr);
@@ -818,20 +810,6 @@ struct PrintSExpression : public Visitor<PrintSExpression> {
}
o << ")";
}
- void visitImport(Import* curr) {
- o << '(';
- printMedium(o, "import ");
- printText(o, curr->module.str) << ' ';
- printText(o, curr->base.str) << ' ';
- switch (curr->kind) {
- case ExternalKind::Function: if (curr->functionType.is()) visitFunctionType(currModule->getFunctionType(curr->functionType), &curr->name); break;
- case ExternalKind::Table: printTableHeader(&currModule->table); break;
- case ExternalKind::Memory: printMemoryHeader(&currModule->memory); break;
- case ExternalKind::Global: o << "(global " << curr->name << ' ' << printType(curr->globalType) << ")"; break;
- default: WASM_UNREACHABLE();
- }
- o << ')';
- }
void visitExport(Export* curr) {
o << '(';
printMedium(o, "export ");
@@ -846,19 +824,66 @@ struct PrintSExpression : public Visitor<PrintSExpression> {
o << ' ';
printName(curr->value, o) << "))";
}
+ void emitImportHeader(Importable* curr) {
+ printMedium(o, "import ");
+ printText(o, curr->module.str) << ' ';
+ printText(o, curr->base.str) << ' ';
+ }
void visitGlobal(Global* curr) {
- o << '(';
- printMedium(o, "global ");
- printName(curr->name, o) << ' ';
+ if (curr->imported()) {
+ visitImportedGlobal(curr);
+ } else {
+ visitDefinedGlobal(curr);
+ }
+ }
+ void emitGlobalType(Global* curr) {
if (curr->mutable_) {
- o << "(mut " << printType(curr->type) << ") ";
+ o << "(mut " << printType(curr->type) << ')';
} else {
- o << printType(curr->type) << ' ';
+ o << printType(curr->type);
}
+ }
+ void visitImportedGlobal(Global* curr) {
+ doIndent(o, indent);
+ o << '(';
+ emitImportHeader(curr);
+ o << "(global ";
+ printName(curr->name, o) << ' ';
+ emitGlobalType(curr);
+ o << "))" << maybeNewLine;
+ }
+ void visitDefinedGlobal(Global* curr) {
+ doIndent(o, indent);
+ o << '(';
+ printMedium(o, "global ");
+ printName(curr->name, o) << ' ';
+ emitGlobalType(curr);
+ o << ' ';
visit(curr->init);
o << ')';
+ o << maybeNewLine;
}
void visitFunction(Function* curr) {
+ if (curr->imported()) {
+ visitImportedFunction(curr);
+ } else {
+ visitDefinedFunction(curr);
+ }
+ }
+ void visitImportedFunction(Function* curr) {
+ doIndent(o, indent);
+ currFunction = curr;
+ lastPrintedLocation = { 0, 0, 0 };
+ o << '(';
+ emitImportHeader(curr);
+ if (curr->type.is()) {
+ visitFunctionType(currModule->getFunctionType(curr->type), &curr->name);
+ }
+ o << ')';
+ o << maybeNewLine;
+ }
+ void visitDefinedFunction(Function* curr) {
+ doIndent(o, indent);
currFunction = curr;
lastPrintedLocation = { 0, 0, 0 };
if (currFunction->prologLocation.size()) {
@@ -927,6 +952,7 @@ struct PrintSExpression : public Visitor<PrintSExpression> {
} else {
decIndent();
}
+ o << maybeNewLine;
}
void printTableHeader(Table* curr) {
o << '(';
@@ -937,8 +963,13 @@ struct PrintSExpression : public Visitor<PrintSExpression> {
}
void visitTable(Table* curr) {
if (!curr->exists) return;
- // if table wasn't imported, declare it
- if (!curr->imported) {
+ if (curr->imported()) {
+ doIndent(o, indent);
+ o << '(';
+ emitImportHeader(curr);
+ printTableHeader(&currModule->table);
+ o << ')' << maybeNewLine;
+ } else {
doIndent(o, indent);
printTableHeader(curr);
o << maybeNewLine;
@@ -954,7 +985,7 @@ struct PrintSExpression : public Visitor<PrintSExpression> {
o << ' ';
printName(name, o);
}
- o << ")\n";
+ o << ')' << maybeNewLine;
}
}
void printMemoryHeader(Memory* curr) {
@@ -972,8 +1003,13 @@ struct PrintSExpression : public Visitor<PrintSExpression> {
}
void visitMemory(Memory* curr) {
if (!curr->exists) return;
- // if memory wasn't imported, declare it
- if (!curr->imported) {
+ if (curr->imported()) {
+ doIndent(o, indent);
+ o << '(';
+ emitImportHeader(curr);
+ printMemoryHeader(&currModule->memory);
+ o << ')' << maybeNewLine;
+ } else {
doIndent(o, indent);
printMemoryHeader(curr);
o << '\n';
@@ -1004,7 +1040,7 @@ struct PrintSExpression : public Visitor<PrintSExpression> {
}
}
}
- o << "\")\n";
+ o << "\")" << maybeNewLine;
}
}
void visitModule(Module* curr) {
@@ -1020,20 +1056,19 @@ struct PrintSExpression : public Visitor<PrintSExpression> {
visitFunctionType(child.get());
o << ")" << maybeNewLine;
}
- for (auto& child : curr->imports) {
- doIndent(o, indent);
- visitImport(child.get());
- o << maybeNewLine;
- }
- for (auto& child : curr->globals) {
- doIndent(o, indent);
- visitGlobal(child.get());
- o << maybeNewLine;
- }
+ visitMemory(&curr->memory);
if (curr->table.exists) {
visitTable(&curr->table); // Prints its own newlines
}
- visitMemory(&curr->memory);
+ ModuleUtils::iterImportedGlobals(*curr, [&](Global* global) {
+ visitGlobal(global);
+ });
+ ModuleUtils::iterImportedFunctions(*curr, [&](Function* func) {
+ visitFunction(func);
+ });
+ ModuleUtils::iterDefinedGlobals(*curr, [&](Global* global) {
+ visitGlobal(global);
+ });
for (auto& child : curr->exports) {
doIndent(o, indent);
visitExport(child.get());
@@ -1045,11 +1080,9 @@ struct PrintSExpression : public Visitor<PrintSExpression> {
printMedium(o, "start") << ' ' << curr->start << ')';
o << maybeNewLine;
}
- for (auto& child : curr->functions) {
- doIndent(o, indent);
- visitFunction(child.get());
- o << maybeNewLine;
- }
+ ModuleUtils::iterDefinedFunctions(*curr, [&](Function* func) {
+ visitFunction(func);
+ });
for (auto& section : curr->userSections) {
doIndent(o, indent);
o << ";; custom section \"" << section.name << "\", size " << section.data.size();
diff --git a/src/passes/PrintCallGraph.cpp b/src/passes/PrintCallGraph.cpp
index fa58e3859..2a82b7aa1 100644
--- a/src/passes/PrintCallGraph.cpp
+++ b/src/passes/PrintCallGraph.cpp
@@ -24,6 +24,7 @@
#include "wasm.h"
#include "pass.h"
+#include "ir/module-utils.h"
#include "ir/utils.h"
namespace wasm {
@@ -46,19 +47,17 @@ struct PrintCallGraph : public Pass {
" }\n\n"
" node [shape=box, fontname=courier, fontsize=10];\n";
- // All Functions
- for (auto& func : module->functions) {
- std::cout << " \"" << func.get()->name << "\" [style=\"filled\", fillcolor=\"white\"];\n";
- }
+ // Defined functions
+ ModuleUtils::iterDefinedFunctions(*module, [&](Function* curr) {
+ std::cout << " \"" << curr->name << "\" [style=\"filled\", fillcolor=\"white\"];\n";
+ });
- // Imports Nodes
- for (auto& curr : module->imports) {
- if (curr->kind == ExternalKind::Function) {
- o << " \"" << curr->name << "\" [style=\"filled\", fillcolor=\"turquoise\"];\n";
- }
- }
+ // Imported functions
+ ModuleUtils::iterImportedFunctions(*module, [&](Function* curr) {
+ o << " \"" << curr->name << "\" [style=\"filled\", fillcolor=\"turquoise\"];\n";
+ });
- // Exports Nodes
+ // Exports
for (auto& curr : module->exports) {
if (curr->kind == ExternalKind::Function) {
Function* func = module->getFunction(curr->value);
@@ -73,11 +72,11 @@ struct PrintCallGraph : public Pass {
std::vector<Function*> allIndirectTargets;
CallPrinter(Module *module) : module(module) {
// Walk function bodies.
- for (auto& func : module->functions) {
- currFunction = func.get();
+ ModuleUtils::iterDefinedFunctions(*module, [&](Function* curr) {
+ currFunction = curr;
visitedTargets.clear();
- walk(func.get()->body);
- }
+ walk(curr->body);
+ });
}
void visitCall(Call *curr) {
auto* target = module->getFunction(curr->target);
@@ -85,12 +84,6 @@ struct PrintCallGraph : public Pass {
visitedTargets.insert(target->name);
std::cout << " \"" << currFunction->name << "\" -> \"" << target->name << "\"; // call\n";
}
- void visitCallImport(CallImport *curr) {
- auto name = curr->target;
- if (visitedTargets.count(name) > 0) return;
- visitedTargets.insert(name);
- std::cout << " \"" << currFunction->name << "\" -> \"" << name << "\"; // callImport\n";
- }
};
CallPrinter printer(module);
diff --git a/src/passes/RemoveImports.cpp b/src/passes/RemoveImports.cpp
index 116cd3296..e70cbb3ac 100644
--- a/src/passes/RemoveImports.cpp
+++ b/src/passes/RemoveImports.cpp
@@ -22,14 +22,19 @@
// look at all the rest of the code).
//
-#include <wasm.h>
-#include <pass.h>
+#include "wasm.h"
+#include "pass.h"
+#include "ir/module-utils.h"
namespace wasm {
struct RemoveImports : public WalkerPass<PostWalker<RemoveImports>> {
- void visitCallImport(CallImport *curr) {
- Type type = getModule()->getFunctionType(getModule()->getImport(curr->target)->functionType)->result;
+ void visitCall(Call *curr) {
+ auto* func = getModule()->getFunction(curr->target);
+ if (!func->imported()) {
+ return;
+ }
+ Type type = getModule()->getFunctionType(func->type)->result;
if (type == none) {
replaceCurrent(getModule()->allocator.alloc<Nop>());
} else {
@@ -41,13 +46,11 @@ struct RemoveImports : public WalkerPass<PostWalker<RemoveImports>> {
void visitModule(Module *curr) {
std::vector<Name> names;
- for (auto& import : curr->imports) {
- if (import->kind == ExternalKind::Function) {
- names.push_back(import->name);
- }
- }
+ ModuleUtils::iterImportedFunctions(*curr, [&](Function* func) {
+ names.push_back(func->name);
+ });
for (auto& name : names) {
- curr->removeImport(name);
+ curr->removeFunction(name);
}
}
};
diff --git a/src/passes/RemoveUnusedModuleElements.cpp b/src/passes/RemoveUnusedModuleElements.cpp
index 6cd050da9..069137ff6 100644
--- a/src/passes/RemoveUnusedModuleElements.cpp
+++ b/src/passes/RemoveUnusedModuleElements.cpp
@@ -25,6 +25,7 @@
#include "wasm.h"
#include "pass.h"
+#include "ir/module-utils.h"
#include "ir/utils.h"
#include "asm_v_wasm.h"
@@ -63,15 +64,15 @@ struct ReachabilityAnalyzer : public PostWalker<ReachabilityAnalyzer> {
reachable.insert(curr);
if (curr.first == ModuleElementKind::Function) {
// if not an import, walk it
- auto* func = module->getFunctionOrNull(curr.second);
- if (func) {
+ auto* func = module->getFunction(curr.second);
+ if (!func->imported()) {
walk(func->body);
}
} else {
// if not imported, it has an init expression we need to walk
- auto* glob = module->getGlobalOrNull(curr.second);
- if (glob) {
- walk(glob->init);
+ auto* global = module->getGlobal(curr.second);
+ if (!global->imported()) {
+ walk(global->init);
}
}
}
@@ -83,11 +84,6 @@ struct ReachabilityAnalyzer : public PostWalker<ReachabilityAnalyzer> {
queue.emplace_back(ModuleElementKind::Function, curr->target);
}
}
- void visitCallImport(CallImport* curr) {
- if (reachable.count(ModuleElement(ModuleElementKind::Function, curr->target)) == 0) {
- queue.emplace_back(ModuleElementKind::Function, curr->target);
- }
- }
void visitCallIndirect(CallIndirect* curr) {
usesTable = true;
}
@@ -131,19 +127,17 @@ struct ReachabilityAnalyzer : public PostWalker<ReachabilityAnalyzer> {
// Finds function type usage
struct FunctionTypeAnalyzer : public PostWalker<FunctionTypeAnalyzer> {
- std::vector<Import*> functionImports;
+ std::vector<Function*> functionImports;
std::vector<Function*> functions;
std::vector<CallIndirect*> indirectCalls;
- void visitImport(Import* curr) {
- if (curr->kind == ExternalKind::Function && curr->functionType.is()) {
- functionImports.push_back(curr);
- }
- }
-
void visitFunction(Function* curr) {
if (curr->type.is()) {
- functions.push_back(curr);
+ if (curr->imported()) {
+ functionImports.push_back(curr);
+ } else {
+ functions.push_back(curr);
+ }
}
}
@@ -176,9 +170,9 @@ struct RemoveUnusedModuleElements : public Pass {
}
// If told to, root all the functions
if (rootAllFunctions) {
- for (auto& func : module->functions) {
+ ModuleUtils::iterDefinedFunctions(*module, [&](Function* func) {
roots.emplace_back(ModuleElementKind::Function, func->name);
- }
+ });
}
// Exports are roots.
bool exportsMemory = false;
@@ -194,15 +188,14 @@ struct RemoveUnusedModuleElements : public Pass {
exportsTable = true;
}
}
- // Check for special imports are roots.
+ // Check for special imports, which are roots.
bool importsMemory = false;
bool importsTable = false;
- for (auto& curr : module->imports) {
- if (curr->kind == ExternalKind::Memory) {
- importsMemory = true;
- } else if (curr->kind == ExternalKind::Table) {
- importsTable = true;
- }
+ if (module->memory.imported()) {
+ importsMemory = true;
+ }
+ if (module->table.imported()) {
+ importsTable = true;
}
// For now, all functions that can be called indirectly are marked as roots.
for (auto& segment : module->table.segments) {
@@ -225,17 +218,6 @@ struct RemoveUnusedModuleElements : public Pass {
return analyzer.reachable.count(ModuleElement(ModuleElementKind::Global, curr->name)) == 0;
}), v.end());
}
- {
- auto& v = module->imports;
- v.erase(std::remove_if(v.begin(), v.end(), [&](const std::unique_ptr<Import>& curr) {
- if (curr->kind == ExternalKind::Function) {
- return analyzer.reachable.count(ModuleElement(ModuleElementKind::Function, curr->name)) == 0;
- } else if (curr->kind == ExternalKind::Global) {
- return analyzer.reachable.count(ModuleElement(ModuleElementKind::Global, curr->name)) == 0;
- }
- return false;
- }), v.end());
- }
module->updateMaps();
// Handle the memory and table
if (!exportsMemory && !analyzer.usesMemory) {
@@ -245,10 +227,9 @@ struct RemoveUnusedModuleElements : public Pass {
}
if (module->memory.segments.empty()) {
module->memory.exists = false;
- module->memory.imported = false;
+ module->memory.module = module->memory.base = Name();
module->memory.initial = 0;
module->memory.max = 0;
- removeImport(ExternalKind::Memory, module);
}
}
if (!exportsTable && !analyzer.usesTable) {
@@ -258,21 +239,13 @@ struct RemoveUnusedModuleElements : public Pass {
}
if (module->table.segments.empty()) {
module->table.exists = false;
- module->table.imported = false;
+ module->table.module = module->table.base = Name();
module->table.initial = 0;
module->table.max = 0;
- removeImport(ExternalKind::Table, module);
}
}
}
- void removeImport(ExternalKind kind, Module* module) {
- auto& v = module->imports;
- v.erase(std::remove_if(v.begin(), v.end(), [&](const std::unique_ptr<Import>& curr) {
- return curr->kind == kind;
- }), v.end());
- }
-
void optimizeFunctionTypes(Module* module) {
FunctionTypeAnalyzer analyzer;
analyzer.walkModule(module);
@@ -294,7 +267,7 @@ struct RemoveUnusedModuleElements : public Pass {
};
// canonicalize all uses of function types
for (auto* import : analyzer.functionImports) {
- import->functionType = canonicalize(import->functionType);
+ import->type = canonicalize(import->type);
}
for (auto* func : analyzer.functions) {
func->type = canonicalize(func->type);
diff --git a/src/passes/SafeHeap.cpp b/src/passes/SafeHeap.cpp
index 325516f4d..5c1980f28 100644
--- a/src/passes/SafeHeap.cpp
+++ b/src/passes/SafeHeap.cpp
@@ -26,6 +26,7 @@
#include "asmjs/shared-constants.h"
#include "wasm-builder.h"
#include "ir/bits.h"
+#include "ir/function-type-utils.h"
#include "ir/import-utils.h"
namespace wasm {
@@ -114,39 +115,40 @@ struct SafeHeap : public Pass {
Name dynamicTopPtr, segfault, alignfault;
void addImports(Module* module) {
- // imports
- if (auto* existing = ImportUtils::getImport(*module, ENV, DYNAMICTOP_PTR_IMPORT)) {
+ ImportInfo info(*module);
+ if (auto* existing = info.getImportedGlobal(ENV, DYNAMICTOP_PTR_IMPORT)) {
dynamicTopPtr = existing->name;
} else {
- auto* import = new Import;
+ auto* import = new Global;
import->name = dynamicTopPtr = DYNAMICTOP_PTR_IMPORT;
import->module = ENV;
import->base = DYNAMICTOP_PTR_IMPORT;
- import->kind = ExternalKind::Global;
- import->globalType = i32;
- module->addImport(import);
+ import->type = i32;
+ module->addGlobal(import);
}
- if (auto* existing = ImportUtils::getImport(*module, ENV, SEGFAULT_IMPORT)) {
+ if (auto* existing = info.getImportedFunction(ENV, SEGFAULT_IMPORT)) {
segfault = existing->name;
} else {
- auto* import = new Import;
+ auto* import = new Function;
import->name = segfault = SEGFAULT_IMPORT;
import->module = ENV;
import->base = SEGFAULT_IMPORT;
- import->kind = ExternalKind::Function;
- import->functionType = ensureFunctionType("v", module)->name;
- module->addImport(import);
+ auto* functionType = ensureFunctionType("v", module);
+ import->type = functionType->name;
+ FunctionTypeUtils::fillFunction(import, functionType);
+ module->addFunction(import);
}
- if (auto* existing = ImportUtils::getImport(*module, ENV, ALIGNFAULT_IMPORT)) {
+ if (auto* existing = info.getImportedFunction(ENV, ALIGNFAULT_IMPORT)) {
alignfault = existing->name;
} else {
- auto* import = new Import;
+ auto* import = new Function;
import->name = alignfault = ALIGNFAULT_IMPORT;
import->module = ENV;
import->base = ALIGNFAULT_IMPORT;
- import->kind = ExternalKind::Function;
- import->functionType = ensureFunctionType("v", module)->name;
- module->addImport(import);
+ auto* functionType = ensureFunctionType("v", module);
+ import->type = functionType->name;
+ FunctionTypeUtils::fillFunction(import, functionType);
+ module->addFunction(import);
}
}
@@ -291,7 +293,7 @@ struct SafeHeap : public Pass {
builder.makeGetLocal(local, i32),
builder.makeConst(Literal(int32_t(align - 1)))
),
- builder.makeCallImport(alignfault, {}, none)
+ builder.makeCall(alignfault, {}, none)
);
}
@@ -316,7 +318,7 @@ struct SafeHeap : public Pass {
)
)
),
- builder.makeCallImport(segfault, {}, none)
+ builder.makeCall(segfault, {}, none)
);
}
};
diff --git a/src/passes/SpillPointers.cpp b/src/passes/SpillPointers.cpp
index d65c89d3e..36c2ae948 100644
--- a/src/passes/SpillPointers.cpp
+++ b/src/passes/SpillPointers.cpp
@@ -60,9 +60,6 @@ struct SpillPointers : public WalkerPass<LivenessWalker<SpillPointers, Visitor<S
void visitCall(Call* curr) {
visitSpillable(curr);
}
- void visitCallImport(CallImport* curr) {
- visitSpillable(curr);
- }
void visitCallIndirect(CallIndirect* curr) {
visitSpillable(curr);
}
@@ -161,10 +158,6 @@ struct SpillPointers : public WalkerPass<LivenessWalker<SpillPointers, Visitor<S
for (auto*& operand : call->cast<Call>()->operands) {
handleOperand(operand);
}
- } else if (call->is<CallImport>()) {
- for (auto*& operand : call->cast<CallImport>()->operands) {
- handleOperand(operand);
- }
} else if (call->is<CallIndirect>()) {
for (auto*& operand : call->cast<CallIndirect>()->operands) {
handleOperand(operand);
diff --git a/src/passes/TrapMode.cpp b/src/passes/TrapMode.cpp
index 68d6aad4b..19301ee3a 100644
--- a/src/passes/TrapMode.cpp
+++ b/src/passes/TrapMode.cpp
@@ -22,6 +22,7 @@
#include "asm_v_wasm.h"
#include "asmjs/shared-constants.h"
+#include "ir/function-type-utils.h"
#include "ir/trapping.h"
#include "mixed_arena.h"
#include "pass.h"
@@ -222,12 +223,13 @@ void ensureF64ToI64JSImport(TrappingFunctionContainer &trappingFunctions) {
}
Module& wasm = trappingFunctions.getModule();
- auto import = new Import; // f64-to-int = asm2wasm.f64-to-int;
+ auto import = new Function; // f64-to-int = asm2wasm.f64-to-int;
import->name = F64_TO_INT;
import->module = ASM2WASM;
import->base = F64_TO_INT;
- import->functionType = ensureFunctionType("id", &wasm)->name;
- import->kind = ExternalKind::Function;
+ auto* functionType = ensureFunctionType("id", &wasm);
+ import->type = functionType->name;
+ FunctionTypeUtils::fillFunction(import, functionType);
trappingFunctions.addImport(import);
}
@@ -263,7 +265,7 @@ Expression* makeTrappingUnary(Unary* curr, TrappingFunctionContainer &trappingFu
// WebAssembly traps on float-to-int overflows, but asm.js wouldn't, so we must emulate that
ensureF64ToI64JSImport(trappingFunctions);
Expression* f64Value = ensureDouble(curr->value, wasm.allocator);
- return builder.makeCallImport(F64_TO_INT, {f64Value}, i32);
+ return builder.makeCall(F64_TO_INT, {f64Value}, i32);
}
ensureUnaryFunc(curr, wasm, trappingFunctions);
diff --git a/src/passes/Vacuum.cpp b/src/passes/Vacuum.cpp
index f24f76881..f59fb287a 100644
--- a/src/passes/Vacuum.cpp
+++ b/src/passes/Vacuum.cpp
@@ -63,7 +63,6 @@ struct Vacuum : public WalkerPass<PostWalker<Vacuum>> {
case Expression::Id::BreakId:
case Expression::Id::SwitchId:
case Expression::Id::CallId:
- case Expression::Id::CallImportId:
case Expression::Id::CallIndirectId:
case Expression::Id::SetLocalId:
case Expression::Id::StoreId:
diff --git a/src/passes/pass.cpp b/src/passes/pass.cpp
index 9215341e3..66ffb9b30 100644
--- a/src/passes/pass.cpp
+++ b/src/passes/pass.cpp
@@ -17,12 +17,13 @@
#include <chrono>
#include <sstream>
-#include <support/colors.h>
-#include <passes/passes.h>
-#include <pass.h>
-#include <wasm-validator.h>
-#include <wasm-io.h>
+#include "support/colors.h"
+#include "passes/passes.h"
+#include "pass.h"
+#include "wasm-validator.h"
+#include "wasm-io.h"
#include "ir/hashed.h"
+#include "ir/module-utils.h"
namespace wasm {
@@ -267,9 +268,9 @@ void PassRunner::run() {
auto before = std::chrono::steady_clock::now();
if (pass->isFunctionParallel()) {
// function-parallel passes should get a new instance per function
- for (auto& func : wasm->functions) {
- runPassOnFunction(pass, func.get());
- }
+ ModuleUtils::iterDefinedFunctions(*wasm, [&](Function* func) {
+ runPassOnFunction(pass, func);
+ });
} else {
runPass(pass);
}
@@ -320,9 +321,11 @@ void PassRunner::run() {
return ThreadWorkState::Finished; // nothing left
}
Function* func = this->wasm->functions[index].get();
- // do the current task: run all passes on this function
- for (auto* pass : stack) {
- runPassOnFunction(pass, func);
+ if (!func->imported()) {
+ // do the current task: run all passes on this function
+ for (auto* pass : stack) {
+ runPassOnFunction(pass, func);
+ }
}
if (index + 1 == numFunctions) {
return ThreadWorkState::Finished; // we did the last one