Hoists external inputs (instructions not in the dependency chain between start_ins and end_ins) to before start_ins, while preserving topological order
| 1663 | // Hoists external inputs (instructions not in the dependency chain between start_ins and end_ins) |
| 1664 | // to before start_ins, while preserving topological order |
| 1665 | void module::hoist_external_inputs(instruction_ref start_ins, instruction_ref end_ins) |
| 1666 | { |
| 1667 | // get the chain of instructions between start_ins and end_ins, inclusive |
| 1668 | auto fusion_ins = find_instructions_between(start_ins, end_ins, this); |
| 1669 | |
| 1670 | // move all instructions between start_ins & end_ins that are not in the fusion chain |
| 1671 | // to the start_ins. In order, moving to the same destination, this will naturally preserve |
| 1672 | // the preexisting topological order of the module |
| 1673 | for(auto it = std::next(start_ins); it != end_ins;) |
| 1674 | { |
| 1675 | if(fusion_ins.count(it) == 0) |
| 1676 | { |
| 1677 | // only move if none of its inputs are after start_ins |
| 1678 | bool has_input_in_range = |
| 1679 | std::any_of(it->inputs().begin(), it->inputs().end(), [&](instruction_ref input) { |
| 1680 | if(not has_instruction(input)) |
| 1681 | return false; |
| 1682 | // verify: start_ins < input < it |
| 1683 | return std::find(std::next(start_ins), it, input) != it; |
| 1684 | }); |
| 1685 | |
| 1686 | if(has_input_in_range) |
| 1687 | { |
| 1688 | // input is after start_ins, meaning can't move this instruction |
| 1689 | ++it; |
| 1690 | } |
| 1691 | else |
| 1692 | { |
| 1693 | auto next = std::next(it); |
| 1694 | this->move_instruction(it, start_ins); |
| 1695 | it = next; |
| 1696 | } |
| 1697 | } |
| 1698 | else |
| 1699 | { |
| 1700 | ++it; |
| 1701 | } |
| 1702 | } |
| 1703 | assert(this->validate() == this->end()); |
| 1704 | } |
| 1705 | |
| 1706 | bool operator==(const module& x, const module& y) { return to_string(x) == to_string(y); } |
| 1707 |