From ffac06650507ac413d60d72aadc1e33fb1f91ccf Mon Sep 17 00:00:00 2001 From: Abbas Mashayekh Date: Wed, 24 Mar 2021 21:43:45 +0430 Subject: [RT] Support expressions in element segments (#3666) This PR adds support for `ref.null t` as a valid element segment item. The abbreviated format of `(elem ... func $f $g...)` is kept in both printing and binary emitting if all items are `ref.func`s. Public APIs aren't updated in this PR. --- src/tools/wasm-reduce.cpp | 79 ++++++++++++++++++++++++++++------------------- 1 file changed, 48 insertions(+), 31 deletions(-) (limited to 'src/tools/wasm-reduce.cpp') diff --git a/src/tools/wasm-reduce.cpp b/src/tools/wasm-reduce.cpp index efe5c1caa..19afc2032 100644 --- a/src/tools/wasm-reduce.cpp +++ b/src/tools/wasm-reduce.cpp @@ -766,7 +766,31 @@ struct Reducer } // the "opposite" of shrinking: copy a 'zero' element for (auto& segment : curr->segments) { - reduceByZeroing(&segment, 0, 2, shrank); + reduceByZeroing( + &segment, 0, [](char item) { return item == 0; }, 2, shrank); + } + } + + template + void + reduceByZeroing(T* segment, U zero, C isZero, size_t bonus, bool shrank) { + for (auto& item : segment->data) { + if (!shouldTryToReduce(bonus) || isZero(item)) { + 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; + } } } @@ -803,37 +827,9 @@ struct Reducer return shrank; } - template - 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; - } - 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; + Expression* first = nullptr; auto it = std::find_if_not(module->elementSegments.begin(), module->elementSegments.end(), @@ -842,6 +838,10 @@ struct Reducer if (it != module->elementSegments.end()) { first = it->get()->data[0]; } + if (first == nullptr) { + // The elements are all empty, nothing to shrink + return; + } // try to reduce to first function. first, shrink segment elements. // while we are shrinking successfully, keep going exponentially. @@ -851,7 +851,24 @@ struct Reducer } // the "opposite" of shrinking: copy a 'zero' element for (auto& segment : module->elementSegments) { - reduceByZeroing(segment.get(), first, 100, shrank); + reduceByZeroing( + segment.get(), + first, + [&](Expression* entry) { + if (entry->is()) { + // we don't need to replace a ref.null + return true; + } else if (first->is()) { + return false; + } else { + // Both are ref.func + auto* f = first->cast(); + auto* e = entry->cast(); + return f->func == e->func; + } + }, + 100, + shrank); } } -- cgit v1.2.3