(fn: FuncIR, options: CompilerOptions)
| 36 | |
| 37 | |
| 38 | def do_flag_elimination(fn: FuncIR, options: CompilerOptions) -> None: |
| 39 | # Find registers that are used exactly once as source, and in a branch. |
| 40 | counts: dict[Register, int] = {} |
| 41 | branches: dict[Register, Branch] = {} |
| 42 | labels: dict[Register, BasicBlock] = {} |
| 43 | for block in fn.blocks: |
| 44 | for i, op in enumerate(block.ops): |
| 45 | for src in op.sources(): |
| 46 | if isinstance(src, Register): |
| 47 | counts[src] = counts.get(src, 0) + 1 |
| 48 | if i == 0 and isinstance(op, Branch) and isinstance(op.value, Register): |
| 49 | branches[op.value] = op |
| 50 | labels[op.value] = block |
| 51 | |
| 52 | # Based on these we can find the candidate registers. |
| 53 | candidates: set[Register] = { |
| 54 | r for r in branches if counts.get(r, 0) == 1 and r not in fn.arg_regs |
| 55 | } |
| 56 | |
| 57 | # Remove candidates with invalid assignments. |
| 58 | for block in fn.blocks: |
| 59 | for i, op in enumerate(block.ops): |
| 60 | if isinstance(op, Assign) and op.dest in candidates: |
| 61 | next_op = block.ops[i + 1] |
| 62 | if not (isinstance(next_op, Goto) and next_op.label is labels[op.dest]): |
| 63 | # Not right |
| 64 | candidates.remove(op.dest) |
| 65 | |
| 66 | builder = LowLevelIRBuilder(None, options) |
| 67 | transform = FlagEliminationTransform( |
| 68 | builder, {x: y for x, y in branches.items() if x in candidates} |
| 69 | ) |
| 70 | transform.transform_blocks(fn.blocks) |
| 71 | fn.blocks = builder.blocks |
| 72 | |
| 73 | |
| 74 | class FlagEliminationTransform(IRTransform): |
searching dependent graphs…