/src/regalloc2/src/ion/mod.rs
Line | Count | Source |
1 | | /* |
2 | | * This file was initially derived from the files |
3 | | * `js/src/jit/BacktrackingAllocator.h` and |
4 | | * `js/src/jit/BacktrackingAllocator.cpp` in Mozilla Firefox, and was |
5 | | * originally licensed under the Mozilla Public License 2.0. We |
6 | | * subsequently relicensed it to Apache-2.0 WITH LLVM-exception (see |
7 | | * https://github.com/bytecodealliance/regalloc2/issues/7). |
8 | | * |
9 | | * Since the initial port, the design has been substantially evolved |
10 | | * and optimized. |
11 | | */ |
12 | | |
13 | | //! Backtracking register allocator. See doc/DESIGN.md for details of |
14 | | //! its design. |
15 | | |
16 | | use crate::ssa::validate_ssa; |
17 | | use crate::{Function, MachineEnv, PReg, RegAllocError, RegClass, VecExt}; |
18 | | pub(crate) mod data_structures; |
19 | | pub use data_structures::Ctx; |
20 | | pub use data_structures::Stats; |
21 | | use data_structures::*; |
22 | | pub(crate) mod reg_traversal; |
23 | | use reg_traversal::*; |
24 | | pub(crate) mod requirement; |
25 | | use requirement::*; |
26 | | pub(crate) mod redundant_moves; |
27 | | use redundant_moves::*; |
28 | | pub(crate) mod liveranges; |
29 | | use liveranges::*; |
30 | | pub(crate) mod merge; |
31 | | pub(crate) mod process; |
32 | | use process::*; |
33 | | use smallvec::smallvec; |
34 | | pub(crate) mod dump; |
35 | | pub(crate) mod moves; |
36 | | pub(crate) mod spill; |
37 | | |
38 | | impl<'a, F: Function> Env<'a, F> { |
39 | 11.4k | pub(crate) fn new(func: &'a F, env: &'a MachineEnv, ctx: &'a mut Ctx) -> Self { |
40 | 11.4k | let ninstrs = func.num_insts(); |
41 | 11.4k | let nblocks = func.num_blocks(); |
42 | | |
43 | 11.4k | ctx.liveins.preallocate(nblocks); |
44 | 11.4k | ctx.liveouts.preallocate(nblocks); |
45 | 11.4k | ctx.blockparam_ins.clear(); |
46 | 11.4k | ctx.blockparam_outs.clear(); |
47 | 11.4k | ctx.ranges.preallocate(4 * ninstrs); |
48 | 11.4k | ctx.bundles.preallocate(ninstrs); |
49 | 11.4k | ctx.spillsets.preallocate(ninstrs); |
50 | 11.4k | ctx.vregs.preallocate(ninstrs); |
51 | 2.93M | for preg in ctx.pregs.iter_mut() { |
52 | 2.93M | preg.is_stack = false; |
53 | 2.93M | preg.allocations.btree.clear(); |
54 | 2.93M | } |
55 | 11.4k | ctx.allocation_queue.heap.clear(); |
56 | 11.4k | ctx.spilled_bundles.clear(); |
57 | 11.4k | ctx.scratch_spillset_pool |
58 | 298k | .extend(ctx.spillslots.drain(..).map(|mut s| { |
59 | 298k | s.ranges.btree.clear(); |
60 | 298k | s.ranges |
61 | 298k | })); |
62 | 34.3k | ctx.slots_by_class = core::array::from_fn(|_| SpillSlotList::default()); |
63 | 34.3k | ctx.extra_spillslots_by_class = core::array::from_fn(|_| smallvec![]); |
64 | 11.4k | ctx.preferred_victim_by_class = [PReg::invalid(); 3]; |
65 | 11.4k | ctx.multi_fixed_reg_fixups.clear(); |
66 | 11.4k | ctx.allocated_bundle_count = 0; |
67 | 11.4k | ctx.debug_annotations.clear(); |
68 | 11.4k | ctx.scratch_bump |
69 | 11.4k | .get_mut() |
70 | 11.4k | .expect("we dropped all refs to this") |
71 | 11.4k | .reset(); |
72 | | |
73 | 11.4k | ctx.output.allocs.preallocate(4 * ninstrs); |
74 | 11.4k | ctx.output.inst_alloc_offsets.clear(); |
75 | 11.4k | ctx.output.num_spillslots = 0; |
76 | 11.4k | ctx.output.debug_locations.clear(); |
77 | 11.4k | ctx.output.edits.clear(); |
78 | 11.4k | ctx.output.stats = Stats::default(); |
79 | | |
80 | 11.4k | Self { func, env, ctx } |
81 | 11.4k | } |
82 | | |
83 | 11.4k | pub(crate) fn init(&mut self) -> Result<(), RegAllocError> { |
84 | 11.4k | self.create_pregs_and_vregs(); |
85 | 11.4k | self.compute_liveness()?; |
86 | 11.4k | self.build_liveranges()?; |
87 | 11.4k | self.fixup_multi_fixed_vregs(); |
88 | 11.4k | self.merge_vreg_bundles(); |
89 | 11.4k | self.queue_bundles(); |
90 | 11.4k | if trace_enabled!() { |
91 | 0 | self.dump_state(); |
92 | 11.4k | } |
93 | 11.4k | Ok(()) |
94 | 11.4k | } |
95 | | |
96 | 11.4k | pub(crate) fn run(&mut self) -> Result<Edits, RegAllocError> { |
97 | 11.4k | self.process_bundles()?; |
98 | 11.4k | self.try_allocating_regs_for_spilled_bundles(); |
99 | 11.4k | self.allocate_spillslots(); |
100 | 11.4k | if trace_enabled!() { |
101 | 0 | self.dump_state(); |
102 | 11.4k | } |
103 | 11.4k | let moves = self.apply_allocations_and_insert_moves(); |
104 | 11.4k | Ok(self.resolve_inserted_moves(moves)) |
105 | 11.4k | } |
106 | | } |
107 | | |
108 | 11.4k | pub fn run<F: Function>( |
109 | 11.4k | func: &F, |
110 | 11.4k | mach_env: &MachineEnv, |
111 | 11.4k | ctx: &mut Ctx, |
112 | 11.4k | enable_annotations: bool, |
113 | 11.4k | enable_ssa_checker: bool, |
114 | 11.4k | ) -> Result<(), RegAllocError> { |
115 | 11.4k | ctx.cfginfo.init(func, &mut ctx.cfginfo_ctx)?; |
116 | | |
117 | 11.4k | if enable_ssa_checker { |
118 | 930 | validate_ssa(func, &ctx.cfginfo)?; |
119 | 10.5k | } |
120 | | |
121 | 11.4k | ctx.annotations_enabled = enable_annotations; |
122 | 11.4k | let mut env = Env::new(func, mach_env, ctx); |
123 | 11.4k | env.init()?; |
124 | | |
125 | 11.4k | let mut edits = env.run()?; |
126 | | |
127 | 11.4k | if enable_annotations { |
128 | 1.00k | env.dump_results(); |
129 | 10.4k | } |
130 | | |
131 | 11.4k | ctx.output.edits.extend(edits.drain_edits()); |
132 | | |
133 | 11.4k | Ok(()) |
134 | 11.4k | } |