summaryrefslogtreecommitdiff
path: root/src/tools/wasm-reduce.cpp
diff options
context:
space:
mode:
authorAbbas Mashayekh <martianboy2005@gmail.com>2021-03-06 03:08:51 +0330
committerGitHub <noreply@github.com>2021-03-05 15:38:51 -0800
commit89b8af006bc56cb4bf68f12a80b1cfe8e7a353d4 (patch)
tree602bd8e24753b5e45c859a2c3672062ce07133fe /src/tools/wasm-reduce.cpp
parent57619b508d38677844cb482a4034dc985d2cecc6 (diff)
downloadbinaryen-89b8af006bc56cb4bf68f12a80b1cfe8e7a353d4.tar.gz
binaryen-89b8af006bc56cb4bf68f12a80b1cfe8e7a353d4.tar.bz2
binaryen-89b8af006bc56cb4bf68f12a80b1cfe8e7a353d4.zip
[reference-types] Support passive elem segments (#3572)
Passive element segments do not belong to any table, so the link between Table and elem needs to be weaker; i.e. an elem may have a table in case of active segments, or simply be a collection of function references in case of passive/declarative segments. This PR takes Table::Segment out and turns it into a first class module element just like tables and functions. It also implements early support for parsing, printing, encoding and decoding passive/declarative elem segments.
Diffstat (limited to 'src/tools/wasm-reduce.cpp')
-rw-r--r--src/tools/wasm-reduce.cpp157
1 files changed, 77 insertions, 80 deletions
diff --git a/src/tools/wasm-reduce.cpp b/src/tools/wasm-reduce.cpp
index 4bb4b6f9a..5cd58301e 100644
--- a/src/tools/wasm-reduce.cpp
+++ b/src/tools/wasm-reduce.cpp
@@ -741,47 +741,39 @@ struct Reducer
// TODO: bisection on segment shrinking?
- void visitTable(Table* curr) {
- std::cerr << "| try to simplify table\n";
- Name first;
- for (auto& segment : curr->segments) {
- for (auto item : segment.data) {
- first = item;
- break;
- }
- if (!first.isNull()) {
- break;
- }
- }
- visitSegmented(curr, first, 100);
- }
-
void visitMemory(Memory* curr) {
std::cerr << "| try to simplify memory\n";
- visitSegmented(curr, 0, 2);
+
+ // try to reduce to first function. first, shrink segment elements.
+ // while we are shrinking successfully, keep going exponentially.
+ bool shrank = false;
+ for (auto& segment : curr->segments) {
+ shrank = shrinkByReduction(&segment, 2);
+ }
+ // the "opposite" of shrinking: copy a 'zero' element
+ for (auto& segment : curr->segments) {
+ reduceByZeroing(&segment, 0, 2, shrank);
+ }
}
- template<typename T, typename U>
- void visitSegmented(T* curr, U zero, size_t bonus) {
+ template<typename T> bool shrinkByReduction(T* segment, size_t bonus) {
// try to reduce to first function. first, shrink segment elements.
// while we are shrinking successfully, keep going exponentially.
bool justShrank = false;
bool shrank = false;
- for (auto& segment : curr->segments) {
- auto& data = segment.data;
- // when we succeed, try to shrink by more and more, similar to bisection
- size_t skip = 1;
- for (size_t i = 0; i < data.size() && !data.empty(); i++) {
- if (!justShrank && !shouldTryToReduce(bonus)) {
- continue;
- }
+
+ auto& data = segment->data;
+ // when we succeed, try to shrink by more and more, similar to bisection
+ size_t skip = 1;
+ for (size_t i = 0; i < data.size() && !data.empty(); i++) {
+ if (justShrank || shouldTryToReduce(bonus)) {
auto save = data;
for (size_t j = 0; j < skip; j++) {
if (!data.empty()) {
data.pop_back();
}
}
- auto justShrank = writeAndTestReduction();
+ justShrank = writeAndTestReduction();
if (justShrank) {
std::cerr << "| shrank segment (skip: " << skip << ")\n";
shrank = true;
@@ -793,37 +785,67 @@ struct Reducer
}
}
}
- // the "opposite" of shrinking: copy a 'zero' element
- for (auto& segment : curr->segments) {
- if (segment.data.empty()) {
+
+ return shrank;
+ }
+
+ template<typename T, typename U>
+ void reduceByZeroing(T* segment, U zero, size_t bonus, bool shrank) {
+ if (segment->data.empty()) {
+ return;
+ }
+ for (auto& item : segment->data) {
+ if (!shouldTryToReduce(bonus)) {
continue;
}
- for (auto& item : segment.data) {
- if (!shouldTryToReduce(bonus)) {
- continue;
- }
- if (item == zero) {
- continue;
- }
- auto save = item;
- item = zero;
- if (writeAndTestReduction()) {
- std::cerr << "| zeroed segment\n";
- noteReduction();
- } else {
- item = save;
- }
- if (shrank) {
- // zeroing is fairly inefficient. if we are managing to shrink
- // (which we do exponentially), just zero one per segment at most
- break;
- }
+ if (item == zero) {
+ continue;
+ }
+ auto save = item;
+ item = zero;
+ if (writeAndTestReduction()) {
+ std::cerr << "| zeroed elem segment\n";
+ noteReduction();
+ } else {
+ item = save;
+ }
+ if (shrank) {
+ // zeroing is fairly inefficient. if we are managing to shrink
+ // (which we do exponentially), just zero one per segment at most
+ break;
}
}
}
+ void shrinkElementSegments(Module* module) {
+ std::cerr << "| try to simplify elem segments\n";
+ Name first;
+ auto it =
+ std::find_if_not(module->elementSegments.begin(),
+ module->elementSegments.end(),
+ [&](auto& segment) { return segment->data.empty(); });
+
+ if (it != module->elementSegments.end()) {
+ first = it->get()->data[0];
+ }
+
+ // try to reduce to first function. first, shrink segment elements.
+ // while we are shrinking successfully, keep going exponentially.
+ bool shrank = false;
+ for (auto& segment : module->elementSegments) {
+ shrank = shrinkByReduction(segment.get(), 100);
+ }
+ // the "opposite" of shrinking: copy a 'zero' element
+ for (auto& segment : module->elementSegments) {
+ reduceByZeroing(segment.get(), first, 100, shrank);
+ }
+ }
+
void visitModule(Module* curr) {
assert(curr == module.get());
+
+ shrinkElementSegments(curr);
+
// try to remove functions
std::cerr << "| try to remove functions\n";
std::vector<Name> functionNames;
@@ -898,12 +920,11 @@ struct Reducer
}
// If we are left with a single function that is not exported or used in
// a table, that is useful as then we can change the return type.
- bool allTablesEmpty = std::all_of(
- module->tables.begin(), module->tables.end(), [&](auto& table) {
- return std::all_of(table->segments.begin(),
- table->segments.end(),
- [&](auto& segment) { return segment.data.empty(); });
- });
+ bool allTablesEmpty =
+ std::all_of(module->elementSegments.begin(),
+ module->elementSegments.end(),
+ [&](auto& segment) { return segment->data.empty(); });
+
if (module->functions.size() == 1 && module->exports.empty() &&
allTablesEmpty) {
auto* func = module->functions[0].get();
@@ -964,30 +985,6 @@ struct Reducer
exportsToRemove.push_back(curr->name);
}
}
- void visitTable(Table* curr) {
- Name other;
- for (auto& segment : curr->segments) {
- for (auto name : segment.data) {
- if (!names.count(name)) {
- other = name;
- break;
- }
- }
- if (!other.isNull()) {
- break;
- }
- }
- if (other.isNull()) {
- return; // we failed to find a replacement
- }
- for (auto& segment : curr->segments) {
- for (auto& name : segment.data) {
- if (names.count(name)) {
- name = other;
- }
- }
- }
- }
void doWalkModule(Module* module) {
PostWalker<FunctionReferenceRemover>::doWalkModule(module);
for (auto name : exportsToRemove) {