blob: 1d5aaf4ec3675540da127e956e60763f197124ac [file] [log] [blame]
/*
* Copyright 2019 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.
*/
//
// Reorder blocks so there is a canonical ordering, which can help
// passes that look for identical code on multiple blocks.
//
#include <tuple>
#include <utility>
#include "ir/effects.h"
#include "ir/utils.h"
#include "pass.h"
#include "support/hash.h"
#include "wasm.h"
namespace wasm {
// Main pass class
struct SortBlocks : public WalkerPass<PostWalker<SortBlocks>> {
bool isFunctionParallel() override { return true; }
Pass* create() override { return new SortBlocks; }
void visitBlock(Block* curr) {
auto& list = curr->list;
if (list.empty()) return;
Index numSortable = list.size();
if (list.back()->type != none) {
numSortable--;
}
if (numSortable < 2) return;
// Compute all the effects (which may block some reordering) and
// all the hashes.
std::map<Expression*, EffectAnalyzer> effects;
std::map<Expression*, HashType> hashes;
for (Index i = 0; i < numSortable; i++) {
auto* curr = list[i];
effects.emplace(std::piecewise_construct,
std::forward_as_tuple(curr),
std::forward_as_tuple(getPassOptions(), curr));
hashes.emplace(curr, ExpressionAnalyzer::hash(curr));
}
// Do the sorting, by bubbling to the front and back (which is
// where optimizations typically look). We pick the order of
// lower hashes earlier.
bool more = true;
while (more) {
more = false;
for (Index i = 0; i < numSortable; i++) {
// Bubble forward.
Index j = i;
while (j < numSortable - 1 &&
hashes[list[j]] > hashes[list[j + 1]] &&
!effects.at(list[j]).invalidates(effects.at(list[j + 1]))) {
std::swap(list[j], list[j + 1]);
j++;
more = true;
}
// Bubble backward, if we didn't move forward (if we did, there
// is no possibility to reverse).
if (j == i) {
while (j > 0 &&
hashes[list[j]] < hashes[list[j - 1]] &&
!effects.at(list[j]).invalidates(effects.at(list[j - 1]))) {
std::swap(list[j], list[j - 1]);
j--;
more = true;
}
}
}
}
}
};
Pass* createSortBlocksPass() { return new SortBlocks(); }
} // namespace wasm