diff options
Diffstat (limited to 'Userland/Libraries/LibJS/Bytecode/Pass/UnifySameBlocks.cpp')
-rw-r--r-- | Userland/Libraries/LibJS/Bytecode/Pass/UnifySameBlocks.cpp | 62 |
1 files changed, 62 insertions, 0 deletions
diff --git a/Userland/Libraries/LibJS/Bytecode/Pass/UnifySameBlocks.cpp b/Userland/Libraries/LibJS/Bytecode/Pass/UnifySameBlocks.cpp new file mode 100644 index 0000000000..70be9244e2 --- /dev/null +++ b/Userland/Libraries/LibJS/Bytecode/Pass/UnifySameBlocks.cpp @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2021, Ali Mohammad Pur <mpfard@serenityos.org> + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#include <LibJS/Bytecode/PassManager.h> +#include <string.h> + +namespace JS::Bytecode::Passes { + +void UnifySameBlocks::perform(PassPipelineExecutable& executable) +{ + started(); + + VERIFY(executable.cfg.has_value()); + VERIFY(executable.inverted_cfg.has_value()); + auto cfg = executable.cfg.release_value(); + auto inverted_cfg = executable.inverted_cfg.release_value(); + + HashMap<BasicBlock const*, BasicBlock const*> equal_blocks; + + for (size_t i = 0; i < executable.executable.basic_blocks.size(); ++i) { + auto& block = executable.executable.basic_blocks[i]; + auto block_bytes = block.instruction_stream(); + for (auto& candidate_block : executable.executable.basic_blocks.span().slice(i + 1)) { + // FIXME: This can probably be relaxed a bit... + if (candidate_block->size() != block.size()) + continue; + + auto candidate_bytes = candidate_block->instruction_stream(); + if (memcmp(candidate_bytes.data(), block_bytes.data(), candidate_block->size()) == 0) + equal_blocks.set(&*candidate_block, &block); + } + } + + auto replace_blocks = [&](auto& match, auto& replacement) { + Optional<size_t> first_successor_position; + auto it = executable.executable.basic_blocks.find_if([match](auto& block) { return match == block; }); + VERIFY(!it.is_end()); + executable.executable.basic_blocks.remove(it.index()); + if (!first_successor_position.has_value()) + first_successor_position = it.index(); + + for (auto& block : executable.executable.basic_blocks) { + InstructionStreamIterator it { block.instruction_stream() }; + while (!it.at_end()) { + auto& instruction = *it; + ++it; + const_cast<Instruction&>(instruction).replace_references(*match, replacement); + } + } + return first_successor_position; + }; + + for (auto& entry : equal_blocks) + (void)replace_blocks(entry.key, *entry.value); + + finished(); +} + +} |