1d8357426SChris Fallin //! This implements the VCode container: a CFG of Insts that have been lowered.
2d8357426SChris Fallin //!
3d8357426SChris Fallin //! VCode is virtual-register code. An instruction in VCode is almost a machine
4d8357426SChris Fallin //! instruction; however, its register slots can refer to virtual registers in
5d8357426SChris Fallin //! addition to real machine registers.
6d8357426SChris Fallin //!
7d8357426SChris Fallin //! VCode is structured with traditional basic blocks, and
8d8357426SChris Fallin //! each block must be terminated by an unconditional branch (one target), a
9d8357426SChris Fallin //! conditional branch (two targets), or a return (no targets). Note that this
10d8357426SChris Fallin //! slightly differs from the machine code of most ISAs: in most ISAs, a
11d8357426SChris Fallin //! conditional branch has one target (and the not-taken case falls through).
12d8357426SChris Fallin //! However, we expect that machine backends will elide branches to the following
13d8357426SChris Fallin //! block (i.e., zero-offset jumps), and will be able to codegen a branch-cond /
14d8357426SChris Fallin //! branch-uncond pair if *both* targets are not fallthrough. This allows us to
15d8357426SChris Fallin //! play with layout prior to final binary emission, as well, if we want.
16d8357426SChris Fallin //!
17d8357426SChris Fallin //! See the main module comment in `mod.rs` for more details on the VCode-based
18d8357426SChris Fallin //! backend pipeline.
19d8357426SChris Fallin 
20d8357426SChris Fallin use crate::ir;
21d8357426SChris Fallin use crate::machinst::*;
22d8357426SChris Fallin use crate::settings;
23d8357426SChris Fallin 
24d8357426SChris Fallin use regalloc::Function as RegallocFunction;
25d8357426SChris Fallin use regalloc::Set as RegallocSet;
26d8357426SChris Fallin use regalloc::{BlockIx, InstIx, Range, RegAllocResult, RegClass, RegUsageCollector};
27d8357426SChris Fallin 
28d8357426SChris Fallin use alloc::boxed::Box;
29d8357426SChris Fallin use alloc::vec::Vec;
30d8357426SChris Fallin use log::debug;
31d8357426SChris Fallin use smallvec::SmallVec;
32d8357426SChris Fallin use std::fmt;
33d8357426SChris Fallin use std::iter;
34d8357426SChris Fallin use std::string::String;
35d8357426SChris Fallin 
36d8357426SChris Fallin /// Index referring to an instruction in VCode.
37d8357426SChris Fallin pub type InsnIndex = u32;
38d8357426SChris Fallin /// Index referring to a basic block in VCode.
39d8357426SChris Fallin pub type BlockIndex = u32;
40d8357426SChris Fallin 
41d8357426SChris Fallin /// VCodeInst wraps all requirements for a MachInst to be in VCode: it must be
42d8357426SChris Fallin /// a `MachInst` and it must be able to emit itself at least to a `SizeCodeSink`.
43d8357426SChris Fallin pub trait VCodeInst: MachInst + MachInstEmit<MachSection> + MachInstEmit<MachSectionSize> {}
44d8357426SChris Fallin impl<I: MachInst + MachInstEmit<MachSection> + MachInstEmit<MachSectionSize>> VCodeInst for I {}
45d8357426SChris Fallin 
46d8357426SChris Fallin /// A function in "VCode" (virtualized-register code) form, after lowering.
47d8357426SChris Fallin /// This is essentially a standard CFG of basic blocks, where each basic block
48d8357426SChris Fallin /// consists of lowered instructions produced by the machine-specific backend.
49d8357426SChris Fallin pub struct VCode<I: VCodeInst> {
50d8357426SChris Fallin     /// Function liveins.
51d8357426SChris Fallin     liveins: RegallocSet<RealReg>,
52d8357426SChris Fallin 
53d8357426SChris Fallin     /// Function liveouts.
54d8357426SChris Fallin     liveouts: RegallocSet<RealReg>,
55d8357426SChris Fallin 
56d8357426SChris Fallin     /// VReg IR-level types.
57d8357426SChris Fallin     vreg_types: Vec<Type>,
58d8357426SChris Fallin 
59d8357426SChris Fallin     /// Lowered machine instructions in order corresponding to the original IR.
6048cf2c2fSChris Fallin     insts: Vec<I>,
61d8357426SChris Fallin 
62d8357426SChris Fallin     /// Entry block.
63d8357426SChris Fallin     entry: BlockIndex,
64d8357426SChris Fallin 
65d8357426SChris Fallin     /// Block instruction indices.
6648cf2c2fSChris Fallin     block_ranges: Vec<(InsnIndex, InsnIndex)>,
67d8357426SChris Fallin 
68d8357426SChris Fallin     /// Block successors: index range in the successor-list below.
69d8357426SChris Fallin     block_succ_range: Vec<(usize, usize)>,
70d8357426SChris Fallin 
71d8357426SChris Fallin     /// Block successor lists, concatenated into one Vec. The `block_succ_range`
72d8357426SChris Fallin     /// list of tuples above gives (start, end) ranges within this list that
73d8357426SChris Fallin     /// correspond to each basic block's successors.
74d8357426SChris Fallin     block_succs: Vec<BlockIndex>,
75d8357426SChris Fallin 
76d8357426SChris Fallin     /// Block indices by IR block.
77d8357426SChris Fallin     block_by_bb: SecondaryMap<ir::Block, BlockIndex>,
78d8357426SChris Fallin 
79d8357426SChris Fallin     /// IR block for each VCode Block. The length of this Vec will likely be
80d8357426SChris Fallin     /// less than the total number of Blocks, because new Blocks (for edge
81d8357426SChris Fallin     /// splits, for example) are appended during lowering.
82d8357426SChris Fallin     bb_by_block: Vec<ir::Block>,
83d8357426SChris Fallin 
84d8357426SChris Fallin     /// Order of block IDs in final generated code.
85d8357426SChris Fallin     final_block_order: Vec<BlockIndex>,
86d8357426SChris Fallin 
87d8357426SChris Fallin     /// Final block offsets. Computed during branch finalization and used
88d8357426SChris Fallin     /// during emission.
89d8357426SChris Fallin     final_block_offsets: Vec<CodeOffset>,
90d8357426SChris Fallin 
91d8357426SChris Fallin     /// Size of code, accounting for block layout / alignment.
92d8357426SChris Fallin     code_size: CodeOffset,
93d8357426SChris Fallin 
94d8357426SChris Fallin     /// ABI object.
9548cf2c2fSChris Fallin     abi: Box<dyn ABIBody<I = I>>,
96d8357426SChris Fallin }
97d8357426SChris Fallin 
98d8357426SChris Fallin /// A builder for a VCode function body. This builder is designed for the
99d8357426SChris Fallin /// lowering approach that we take: we traverse basic blocks in forward
100d8357426SChris Fallin /// (original IR) order, but within each basic block, we generate code from
101d8357426SChris Fallin /// bottom to top; and within each IR instruction that we visit in this reverse
102d8357426SChris Fallin /// order, we emit machine instructions in *forward* order again.
103d8357426SChris Fallin ///
104d8357426SChris Fallin /// Hence, to produce the final instructions in proper order, we perform two
105d8357426SChris Fallin /// swaps.  First, the machine instructions (`I` instances) are produced in
106d8357426SChris Fallin /// forward order for an individual IR instruction. Then these are *reversed*
107d8357426SChris Fallin /// and concatenated to `bb_insns` at the end of the IR instruction lowering.
108d8357426SChris Fallin /// The `bb_insns` vec will thus contain all machine instructions for a basic
109d8357426SChris Fallin /// block, in reverse order. Finally, when we're done with a basic block, we
110d8357426SChris Fallin /// reverse the whole block's vec of instructions again, and concatenate onto
111d8357426SChris Fallin /// the VCode's insts.
112d8357426SChris Fallin pub struct VCodeBuilder<I: VCodeInst> {
113d8357426SChris Fallin     /// In-progress VCode.
114d8357426SChris Fallin     vcode: VCode<I>,
115d8357426SChris Fallin 
116d8357426SChris Fallin     /// Current basic block instructions, in reverse order (because blocks are
117d8357426SChris Fallin     /// built bottom-to-top).
118d8357426SChris Fallin     bb_insns: SmallVec<[I; 32]>,
119d8357426SChris Fallin 
120d8357426SChris Fallin     /// Current IR-inst instructions, in forward order.
121d8357426SChris Fallin     ir_inst_insns: SmallVec<[I; 4]>,
122d8357426SChris Fallin 
123d8357426SChris Fallin     /// Start of succs for the current block in the concatenated succs list.
124d8357426SChris Fallin     succ_start: usize,
125d8357426SChris Fallin }
126d8357426SChris Fallin 
127d8357426SChris Fallin impl<I: VCodeInst> VCodeBuilder<I> {
128d8357426SChris Fallin     /// Create a new VCodeBuilder.
12948cf2c2fSChris Fallin     pub fn new(abi: Box<dyn ABIBody<I = I>>) -> VCodeBuilder<I> {
130d8357426SChris Fallin         let vcode = VCode::new(abi);
131d8357426SChris Fallin         VCodeBuilder {
132d8357426SChris Fallin             vcode,
133d8357426SChris Fallin             bb_insns: SmallVec::new(),
134d8357426SChris Fallin             ir_inst_insns: SmallVec::new(),
135d8357426SChris Fallin             succ_start: 0,
136d8357426SChris Fallin         }
137d8357426SChris Fallin     }
138d8357426SChris Fallin 
139d8357426SChris Fallin     /// Access the ABI object.
14048cf2c2fSChris Fallin     pub fn abi(&mut self) -> &mut dyn ABIBody<I = I> {
141d8357426SChris Fallin         &mut *self.vcode.abi
142d8357426SChris Fallin     }
143d8357426SChris Fallin 
144d8357426SChris Fallin     /// Set the type of a VReg.
145d8357426SChris Fallin     pub fn set_vreg_type(&mut self, vreg: VirtualReg, ty: Type) {
146d8357426SChris Fallin         while self.vcode.vreg_types.len() <= vreg.get_index() {
147d8357426SChris Fallin             self.vcode.vreg_types.push(ir::types::I8); // Default type.
148d8357426SChris Fallin         }
149d8357426SChris Fallin         self.vcode.vreg_types[vreg.get_index()] = ty;
150d8357426SChris Fallin     }
151d8357426SChris Fallin 
152d8357426SChris Fallin     /// Return the underlying bb-to-BlockIndex map.
153d8357426SChris Fallin     pub fn blocks_by_bb(&self) -> &SecondaryMap<ir::Block, BlockIndex> {
154d8357426SChris Fallin         &self.vcode.block_by_bb
155d8357426SChris Fallin     }
156d8357426SChris Fallin 
157d8357426SChris Fallin     /// Initialize the bb-to-BlockIndex map. Returns the first free
158d8357426SChris Fallin     /// BlockIndex.
159d8357426SChris Fallin     pub fn init_bb_map(&mut self, blocks: &[ir::Block]) -> BlockIndex {
160d8357426SChris Fallin         let mut bindex: BlockIndex = 0;
161d8357426SChris Fallin         for bb in blocks.iter() {
162d8357426SChris Fallin             self.vcode.block_by_bb[*bb] = bindex;
163d8357426SChris Fallin             self.vcode.bb_by_block.push(*bb);
164d8357426SChris Fallin             bindex += 1;
165d8357426SChris Fallin         }
166d8357426SChris Fallin         bindex
167d8357426SChris Fallin     }
168d8357426SChris Fallin 
169d8357426SChris Fallin     /// Get the BlockIndex for an IR block.
170d8357426SChris Fallin     pub fn bb_to_bindex(&self, bb: ir::Block) -> BlockIndex {
171d8357426SChris Fallin         self.vcode.block_by_bb[bb]
172d8357426SChris Fallin     }
173d8357426SChris Fallin 
174d8357426SChris Fallin     /// Set the current block as the entry block.
175d8357426SChris Fallin     pub fn set_entry(&mut self, block: BlockIndex) {
176d8357426SChris Fallin         self.vcode.entry = block;
177d8357426SChris Fallin     }
178d8357426SChris Fallin 
179d8357426SChris Fallin     /// End the current IR instruction. Must be called after pushing any
180d8357426SChris Fallin     /// instructions and prior to ending the basic block.
181d8357426SChris Fallin     pub fn end_ir_inst(&mut self) {
182d8357426SChris Fallin         while let Some(i) = self.ir_inst_insns.pop() {
183d8357426SChris Fallin             self.bb_insns.push(i);
184d8357426SChris Fallin         }
185d8357426SChris Fallin     }
186d8357426SChris Fallin 
187d8357426SChris Fallin     /// End the current basic block. Must be called after emitting vcode insts
188d8357426SChris Fallin     /// for IR insts and prior to ending the function (building the VCode).
189d8357426SChris Fallin     pub fn end_bb(&mut self) -> BlockIndex {
190d8357426SChris Fallin         assert!(self.ir_inst_insns.is_empty());
191d8357426SChris Fallin         let block_num = self.vcode.block_ranges.len() as BlockIndex;
192d8357426SChris Fallin         // Push the instructions.
193d8357426SChris Fallin         let start_idx = self.vcode.insts.len() as InsnIndex;
194d8357426SChris Fallin         while let Some(i) = self.bb_insns.pop() {
195d8357426SChris Fallin             self.vcode.insts.push(i);
196d8357426SChris Fallin         }
197d8357426SChris Fallin         let end_idx = self.vcode.insts.len() as InsnIndex;
198d8357426SChris Fallin         // Add the instruction index range to the list of blocks.
199d8357426SChris Fallin         self.vcode.block_ranges.push((start_idx, end_idx));
200d8357426SChris Fallin         // End the successors list.
201d8357426SChris Fallin         let succ_end = self.vcode.block_succs.len();
202d8357426SChris Fallin         self.vcode
203d8357426SChris Fallin             .block_succ_range
204d8357426SChris Fallin             .push((self.succ_start, succ_end));
205d8357426SChris Fallin         self.succ_start = succ_end;
206d8357426SChris Fallin 
207d8357426SChris Fallin         block_num
208d8357426SChris Fallin     }
209d8357426SChris Fallin 
210d8357426SChris Fallin     /// Push an instruction for the current BB and current IR inst within the BB.
211d8357426SChris Fallin     pub fn push(&mut self, insn: I) {
212d8357426SChris Fallin         match insn.is_term() {
213d8357426SChris Fallin             MachTerminator::None | MachTerminator::Ret => {}
214d8357426SChris Fallin             MachTerminator::Uncond(target) => {
215d8357426SChris Fallin                 self.vcode.block_succs.push(target);
216d8357426SChris Fallin             }
217d8357426SChris Fallin             MachTerminator::Cond(true_branch, false_branch) => {
218d8357426SChris Fallin                 self.vcode.block_succs.push(true_branch);
219d8357426SChris Fallin                 self.vcode.block_succs.push(false_branch);
220d8357426SChris Fallin             }
221d8357426SChris Fallin             MachTerminator::Indirect(targets) => {
222d8357426SChris Fallin                 for target in targets {
223d8357426SChris Fallin                     self.vcode.block_succs.push(*target);
224d8357426SChris Fallin                 }
225d8357426SChris Fallin             }
226d8357426SChris Fallin         }
227d8357426SChris Fallin         self.ir_inst_insns.push(insn);
228d8357426SChris Fallin     }
229d8357426SChris Fallin 
230d8357426SChris Fallin     /// Build the final VCode.
231d8357426SChris Fallin     pub fn build(self) -> VCode<I> {
232d8357426SChris Fallin         assert!(self.ir_inst_insns.is_empty());
233d8357426SChris Fallin         assert!(self.bb_insns.is_empty());
234d8357426SChris Fallin         self.vcode
235d8357426SChris Fallin     }
236d8357426SChris Fallin }
237d8357426SChris Fallin 
238d8357426SChris Fallin fn block_ranges(indices: &[InstIx], len: usize) -> Vec<(usize, usize)> {
239d8357426SChris Fallin     let v = indices
240d8357426SChris Fallin         .iter()
241d8357426SChris Fallin         .map(|iix| iix.get() as usize)
242d8357426SChris Fallin         .chain(iter::once(len))
243d8357426SChris Fallin         .collect::<Vec<usize>>();
244d8357426SChris Fallin     v.windows(2).map(|p| (p[0], p[1])).collect()
245d8357426SChris Fallin }
246d8357426SChris Fallin 
247d8357426SChris Fallin fn is_redundant_move<I: VCodeInst>(insn: &I) -> bool {
248d8357426SChris Fallin     if let Some((to, from)) = insn.is_move() {
249d8357426SChris Fallin         to.to_reg() == from
250d8357426SChris Fallin     } else {
251d8357426SChris Fallin         false
252d8357426SChris Fallin     }
253d8357426SChris Fallin }
254d8357426SChris Fallin 
255d8357426SChris Fallin fn is_trivial_jump_block<I: VCodeInst>(vcode: &VCode<I>, block: BlockIndex) -> Option<BlockIndex> {
256d8357426SChris Fallin     let range = vcode.block_insns(BlockIx::new(block));
257d8357426SChris Fallin 
258d8357426SChris Fallin     debug!(
259d8357426SChris Fallin         "is_trivial_jump_block: block {} has len {}",
260d8357426SChris Fallin         block,
261d8357426SChris Fallin         range.len()
262d8357426SChris Fallin     );
263d8357426SChris Fallin 
264d8357426SChris Fallin     if range.len() != 1 {
265d8357426SChris Fallin         return None;
266d8357426SChris Fallin     }
267d8357426SChris Fallin     let insn = range.first();
268d8357426SChris Fallin 
269d8357426SChris Fallin     debug!(
270d8357426SChris Fallin         " -> only insn is: {:?} with terminator {:?}",
271d8357426SChris Fallin         vcode.get_insn(insn),
272d8357426SChris Fallin         vcode.get_insn(insn).is_term()
273d8357426SChris Fallin     );
274d8357426SChris Fallin 
275d8357426SChris Fallin     match vcode.get_insn(insn).is_term() {
276d8357426SChris Fallin         MachTerminator::Uncond(target) => Some(target),
277d8357426SChris Fallin         _ => None,
278d8357426SChris Fallin     }
279d8357426SChris Fallin }
280d8357426SChris Fallin 
281d8357426SChris Fallin impl<I: VCodeInst> VCode<I> {
282d8357426SChris Fallin     /// New empty VCode.
28348cf2c2fSChris Fallin     fn new(abi: Box<dyn ABIBody<I = I>>) -> VCode<I> {
284d8357426SChris Fallin         VCode {
285d8357426SChris Fallin             liveins: abi.liveins(),
286d8357426SChris Fallin             liveouts: abi.liveouts(),
287d8357426SChris Fallin             vreg_types: vec![],
288d8357426SChris Fallin             insts: vec![],
289d8357426SChris Fallin             entry: 0,
290d8357426SChris Fallin             block_ranges: vec![],
291d8357426SChris Fallin             block_succ_range: vec![],
292d8357426SChris Fallin             block_succs: vec![],
293d8357426SChris Fallin             block_by_bb: SecondaryMap::with_default(0),
294d8357426SChris Fallin             bb_by_block: vec![],
295d8357426SChris Fallin             final_block_order: vec![],
296d8357426SChris Fallin             final_block_offsets: vec![],
297d8357426SChris Fallin             code_size: 0,
298d8357426SChris Fallin             abi,
299d8357426SChris Fallin         }
300d8357426SChris Fallin     }
301d8357426SChris Fallin 
302*d1b5df31SBenjamin Bouvier     /// Returns the flags controlling this function's compilation.
303*d1b5df31SBenjamin Bouvier     pub fn flags(&self) -> &settings::Flags {
304*d1b5df31SBenjamin Bouvier         self.abi.flags()
305*d1b5df31SBenjamin Bouvier     }
306*d1b5df31SBenjamin Bouvier 
307d8357426SChris Fallin     /// Get the IR-level type of a VReg.
308d8357426SChris Fallin     pub fn vreg_type(&self, vreg: VirtualReg) -> Type {
309d8357426SChris Fallin         self.vreg_types[vreg.get_index()]
310d8357426SChris Fallin     }
311d8357426SChris Fallin 
312d8357426SChris Fallin     /// Get the entry block.
313d8357426SChris Fallin     pub fn entry(&self) -> BlockIndex {
314d8357426SChris Fallin         self.entry
315d8357426SChris Fallin     }
316d8357426SChris Fallin 
317d8357426SChris Fallin     /// Get the number of blocks. Block indices will be in the range `0 ..
318d8357426SChris Fallin     /// (self.num_blocks() - 1)`.
319d8357426SChris Fallin     pub fn num_blocks(&self) -> usize {
320d8357426SChris Fallin         self.block_ranges.len()
321d8357426SChris Fallin     }
322d8357426SChris Fallin 
323d8357426SChris Fallin     /// Stack frame size for the full function's body.
324d8357426SChris Fallin     pub fn frame_size(&self) -> u32 {
325d8357426SChris Fallin         self.abi.frame_size()
326d8357426SChris Fallin     }
327d8357426SChris Fallin 
328d8357426SChris Fallin     /// Get the successors for a block.
329d8357426SChris Fallin     pub fn succs(&self, block: BlockIndex) -> &[BlockIndex] {
330d8357426SChris Fallin         let (start, end) = self.block_succ_range[block as usize];
331d8357426SChris Fallin         &self.block_succs[start..end]
332d8357426SChris Fallin     }
333d8357426SChris Fallin 
334d8357426SChris Fallin     /// Take the results of register allocation, with a sequence of
335d8357426SChris Fallin     /// instructions including spliced fill/reload/move instructions, and replace
336d8357426SChris Fallin     /// the VCode with them.
337*d1b5df31SBenjamin Bouvier     pub fn replace_insns_from_regalloc(&mut self, result: RegAllocResult<Self>) {
338d8357426SChris Fallin         self.final_block_order = compute_final_block_order(self);
339d8357426SChris Fallin 
340d8357426SChris Fallin         // Record the spillslot count and clobbered registers for the ABI/stack
341d8357426SChris Fallin         // setup code.
342d8357426SChris Fallin         self.abi.set_num_spillslots(result.num_spill_slots as usize);
343d8357426SChris Fallin         self.abi
344d8357426SChris Fallin             .set_clobbered(result.clobbered_registers.map(|r| Writable::from_reg(*r)));
345d8357426SChris Fallin 
346d8357426SChris Fallin         // We want to move instructions over in final block order, using the new
347d8357426SChris Fallin         // block-start map given by the regalloc.
348d8357426SChris Fallin         let block_ranges: Vec<(usize, usize)> =
349d8357426SChris Fallin             block_ranges(result.target_map.elems(), result.insns.len());
350d8357426SChris Fallin         let mut final_insns = vec![];
351d8357426SChris Fallin         let mut final_block_ranges = vec![(0, 0); self.num_blocks()];
352d8357426SChris Fallin 
353d8357426SChris Fallin         for block in &self.final_block_order {
354d8357426SChris Fallin             let (start, end) = block_ranges[*block as usize];
355d8357426SChris Fallin             let final_start = final_insns.len() as InsnIndex;
356d8357426SChris Fallin 
357d8357426SChris Fallin             if *block == self.entry {
358d8357426SChris Fallin                 // Start with the prologue.
359*d1b5df31SBenjamin Bouvier                 final_insns.extend(self.abi.gen_prologue().into_iter());
360d8357426SChris Fallin             }
361d8357426SChris Fallin 
362d8357426SChris Fallin             for i in start..end {
363d8357426SChris Fallin                 let insn = &result.insns[i];
364d8357426SChris Fallin 
365d8357426SChris Fallin                 // Elide redundant moves at this point (we only know what is
366d8357426SChris Fallin                 // redundant once registers are allocated).
367d8357426SChris Fallin                 if is_redundant_move(insn) {
368d8357426SChris Fallin                     continue;
369d8357426SChris Fallin                 }
370d8357426SChris Fallin 
371d8357426SChris Fallin                 // Whenever encountering a return instruction, replace it
372d8357426SChris Fallin                 // with the epilogue.
373d8357426SChris Fallin                 let is_ret = insn.is_term() == MachTerminator::Ret;
374d8357426SChris Fallin                 if is_ret {
375*d1b5df31SBenjamin Bouvier                     final_insns.extend(self.abi.gen_epilogue().into_iter());
376d8357426SChris Fallin                 } else {
377d8357426SChris Fallin                     final_insns.push(insn.clone());
378d8357426SChris Fallin                 }
379d8357426SChris Fallin             }
380d8357426SChris Fallin 
381d8357426SChris Fallin             let final_end = final_insns.len() as InsnIndex;
382d8357426SChris Fallin             final_block_ranges[*block as usize] = (final_start, final_end);
383d8357426SChris Fallin         }
384d8357426SChris Fallin 
385d8357426SChris Fallin         self.insts = final_insns;
386d8357426SChris Fallin         self.block_ranges = final_block_ranges;
387d8357426SChris Fallin     }
388d8357426SChris Fallin 
389d8357426SChris Fallin     /// Removes redundant branches, rewriting targets to point directly to the
390d8357426SChris Fallin     /// ultimate block at the end of a chain of trivial one-target jumps.
391d8357426SChris Fallin     pub fn remove_redundant_branches(&mut self) {
392d8357426SChris Fallin         // For each block, compute the actual target block, looking through up to one
393d8357426SChris Fallin         // block with single-target jumps (this will remove empty edge blocks inserted
394d8357426SChris Fallin         // by phi-lowering).
395d8357426SChris Fallin         let block_rewrites: Vec<BlockIndex> = (0..self.num_blocks() as u32)
396d8357426SChris Fallin             .map(|bix| is_trivial_jump_block(self, bix).unwrap_or(bix))
397d8357426SChris Fallin             .collect();
398d8357426SChris Fallin         let mut refcounts: Vec<usize> = vec![0; self.num_blocks()];
399d8357426SChris Fallin 
400d8357426SChris Fallin         debug!(
401d8357426SChris Fallin             "remove_redundant_branches: block_rewrites = {:?}",
402d8357426SChris Fallin             block_rewrites
403d8357426SChris Fallin         );
404d8357426SChris Fallin 
405d8357426SChris Fallin         refcounts[self.entry as usize] = 1;
406d8357426SChris Fallin 
407d8357426SChris Fallin         for block in 0..self.num_blocks() as u32 {
408d8357426SChris Fallin             for insn in self.block_insns(BlockIx::new(block)) {
409d8357426SChris Fallin                 self.get_insn_mut(insn)
410d8357426SChris Fallin                     .with_block_rewrites(&block_rewrites[..]);
411d8357426SChris Fallin                 match self.get_insn(insn).is_term() {
412d8357426SChris Fallin                     MachTerminator::Uncond(bix) => {
413d8357426SChris Fallin                         refcounts[bix as usize] += 1;
414d8357426SChris Fallin                     }
415d8357426SChris Fallin                     MachTerminator::Cond(bix1, bix2) => {
416d8357426SChris Fallin                         refcounts[bix1 as usize] += 1;
417d8357426SChris Fallin                         refcounts[bix2 as usize] += 1;
418d8357426SChris Fallin                     }
419d8357426SChris Fallin                     MachTerminator::Indirect(blocks) => {
420d8357426SChris Fallin                         for block in blocks {
421d8357426SChris Fallin                             refcounts[*block as usize] += 1;
422d8357426SChris Fallin                         }
423d8357426SChris Fallin                     }
424d8357426SChris Fallin                     _ => {}
425d8357426SChris Fallin                 }
426d8357426SChris Fallin             }
427d8357426SChris Fallin         }
428d8357426SChris Fallin 
429d8357426SChris Fallin         let deleted: Vec<bool> = refcounts.iter().map(|r| *r == 0).collect();
430d8357426SChris Fallin 
431d8357426SChris Fallin         let block_order = std::mem::replace(&mut self.final_block_order, vec![]);
432d8357426SChris Fallin         self.final_block_order = block_order
433d8357426SChris Fallin             .into_iter()
434d8357426SChris Fallin             .filter(|b| !deleted[*b as usize])
435d8357426SChris Fallin             .collect();
436d8357426SChris Fallin 
437d8357426SChris Fallin         // Rewrite successor information based on the block-rewrite map.
438d8357426SChris Fallin         for succ in &mut self.block_succs {
439d8357426SChris Fallin             let new_succ = block_rewrites[*succ as usize];
440d8357426SChris Fallin             *succ = new_succ;
441d8357426SChris Fallin         }
442d8357426SChris Fallin     }
443d8357426SChris Fallin 
444d8357426SChris Fallin     /// Mutate branch instructions to (i) lower two-way condbrs to one-way,
445d8357426SChris Fallin     /// depending on fallthrough; and (ii) use concrete offsets.
446d8357426SChris Fallin     pub fn finalize_branches(&mut self)
447d8357426SChris Fallin     where
448d8357426SChris Fallin         I: MachInstEmit<MachSectionSize>,
449d8357426SChris Fallin     {
450d8357426SChris Fallin         // Compute fallthrough block, indexed by block.
451d8357426SChris Fallin         let num_final_blocks = self.final_block_order.len();
452d8357426SChris Fallin         let mut block_fallthrough: Vec<Option<BlockIndex>> = vec![None; self.num_blocks()];
453d8357426SChris Fallin         for i in 0..(num_final_blocks - 1) {
454d8357426SChris Fallin             let from = self.final_block_order[i];
455d8357426SChris Fallin             let to = self.final_block_order[i + 1];
456d8357426SChris Fallin             block_fallthrough[from as usize] = Some(to);
457d8357426SChris Fallin         }
458d8357426SChris Fallin 
459d8357426SChris Fallin         // Pass over VCode instructions and finalize two-way branches into
460d8357426SChris Fallin         // one-way branches with fallthrough.
461d8357426SChris Fallin         for block in 0..self.num_blocks() {
462d8357426SChris Fallin             let next_block = block_fallthrough[block];
463d8357426SChris Fallin             let (start, end) = self.block_ranges[block];
464d8357426SChris Fallin 
465d8357426SChris Fallin             for iix in start..end {
466d8357426SChris Fallin                 let insn = &mut self.insts[iix as usize];
467d8357426SChris Fallin                 insn.with_fallthrough_block(next_block);
468d8357426SChris Fallin             }
469d8357426SChris Fallin         }
470d8357426SChris Fallin 
471d8357426SChris Fallin         // Compute block offsets.
472d8357426SChris Fallin         let mut code_section = MachSectionSize::new(0);
473d8357426SChris Fallin         let mut block_offsets = vec![0; self.num_blocks()];
47448cf2c2fSChris Fallin         for &block in &self.final_block_order {
475d8357426SChris Fallin             code_section.offset = I::align_basic_block(code_section.offset);
47648cf2c2fSChris Fallin             block_offsets[block as usize] = code_section.offset;
47748cf2c2fSChris Fallin             let (start, end) = self.block_ranges[block as usize];
478d8357426SChris Fallin             for iix in start..end {
479d8357426SChris Fallin                 self.insts[iix as usize].emit(&mut code_section);
480d8357426SChris Fallin             }
481d8357426SChris Fallin         }
482d8357426SChris Fallin 
483d8357426SChris Fallin         // We now have the section layout.
484d8357426SChris Fallin         self.final_block_offsets = block_offsets;
485d8357426SChris Fallin         self.code_size = code_section.size();
486d8357426SChris Fallin 
487d8357426SChris Fallin         // Update branches with known block offsets. This looks like the
488d8357426SChris Fallin         // traversal above, but (i) does not update block_offsets, rather uses
489d8357426SChris Fallin         // it (so forward references are now possible), and (ii) mutates the
490d8357426SChris Fallin         // instructions.
491d8357426SChris Fallin         let mut code_section = MachSectionSize::new(0);
49248cf2c2fSChris Fallin         for &block in &self.final_block_order {
493d8357426SChris Fallin             code_section.offset = I::align_basic_block(code_section.offset);
49448cf2c2fSChris Fallin             let (start, end) = self.block_ranges[block as usize];
495d8357426SChris Fallin             for iix in start..end {
496d8357426SChris Fallin                 self.insts[iix as usize]
497d8357426SChris Fallin                     .with_block_offsets(code_section.offset, &self.final_block_offsets[..]);
498d8357426SChris Fallin                 self.insts[iix as usize].emit(&mut code_section);
499d8357426SChris Fallin             }
500d8357426SChris Fallin         }
501d8357426SChris Fallin     }
502d8357426SChris Fallin 
503d8357426SChris Fallin     /// Emit the instructions to a list of sections.
504d8357426SChris Fallin     pub fn emit(&self) -> MachSections
505d8357426SChris Fallin     where
506d8357426SChris Fallin         I: MachInstEmit<MachSection>,
507d8357426SChris Fallin     {
508d8357426SChris Fallin         let mut sections = MachSections::new();
509d8357426SChris Fallin         let code_idx = sections.add_section(0, self.code_size);
510d8357426SChris Fallin         let code_section = sections.get_section(code_idx);
511d8357426SChris Fallin 
51248cf2c2fSChris Fallin         for &block in &self.final_block_order {
513d8357426SChris Fallin             let new_offset = I::align_basic_block(code_section.cur_offset_from_start());
514d8357426SChris Fallin             while new_offset > code_section.cur_offset_from_start() {
515d8357426SChris Fallin                 // Pad with NOPs up to the aligned block offset.
516d8357426SChris Fallin                 let nop = I::gen_nop((new_offset - code_section.cur_offset_from_start()) as usize);
517d8357426SChris Fallin                 nop.emit(code_section);
518d8357426SChris Fallin             }
519d8357426SChris Fallin             assert_eq!(code_section.cur_offset_from_start(), new_offset);
520d8357426SChris Fallin 
52148cf2c2fSChris Fallin             let (start, end) = self.block_ranges[block as usize];
522d8357426SChris Fallin             for iix in start..end {
523d8357426SChris Fallin                 self.insts[iix as usize].emit(code_section);
524d8357426SChris Fallin             }
525d8357426SChris Fallin         }
526d8357426SChris Fallin 
527d8357426SChris Fallin         sections
528d8357426SChris Fallin     }
529d8357426SChris Fallin 
530d8357426SChris Fallin     /// Get the IR block for a BlockIndex, if one exists.
531d8357426SChris Fallin     pub fn bindex_to_bb(&self, block: BlockIndex) -> Option<ir::Block> {
532d8357426SChris Fallin         if (block as usize) < self.bb_by_block.len() {
533d8357426SChris Fallin             Some(self.bb_by_block[block as usize])
534d8357426SChris Fallin         } else {
535d8357426SChris Fallin             None
536d8357426SChris Fallin         }
537d8357426SChris Fallin     }
538d8357426SChris Fallin }
539d8357426SChris Fallin 
540d8357426SChris Fallin impl<I: VCodeInst> RegallocFunction for VCode<I> {
541d8357426SChris Fallin     type Inst = I;
542d8357426SChris Fallin 
543d8357426SChris Fallin     fn insns(&self) -> &[I] {
544d8357426SChris Fallin         &self.insts[..]
545d8357426SChris Fallin     }
546d8357426SChris Fallin 
547d8357426SChris Fallin     fn insns_mut(&mut self) -> &mut [I] {
548d8357426SChris Fallin         &mut self.insts[..]
549d8357426SChris Fallin     }
550d8357426SChris Fallin 
551d8357426SChris Fallin     fn get_insn(&self, insn: InstIx) -> &I {
552d8357426SChris Fallin         &self.insts[insn.get() as usize]
553d8357426SChris Fallin     }
554d8357426SChris Fallin 
555d8357426SChris Fallin     fn get_insn_mut(&mut self, insn: InstIx) -> &mut I {
556d8357426SChris Fallin         &mut self.insts[insn.get() as usize]
557d8357426SChris Fallin     }
558d8357426SChris Fallin 
559d8357426SChris Fallin     fn blocks(&self) -> Range<BlockIx> {
560d8357426SChris Fallin         Range::new(BlockIx::new(0), self.block_ranges.len())
561d8357426SChris Fallin     }
562d8357426SChris Fallin 
563d8357426SChris Fallin     fn entry_block(&self) -> BlockIx {
564d8357426SChris Fallin         BlockIx::new(self.entry)
565d8357426SChris Fallin     }
566d8357426SChris Fallin 
567d8357426SChris Fallin     fn block_insns(&self, block: BlockIx) -> Range<InstIx> {
568d8357426SChris Fallin         let (start, end) = self.block_ranges[block.get() as usize];
569d8357426SChris Fallin         Range::new(InstIx::new(start), (end - start) as usize)
570d8357426SChris Fallin     }
571d8357426SChris Fallin 
572d8357426SChris Fallin     fn block_succs(&self, block: BlockIx) -> Vec<BlockIx> {
573d8357426SChris Fallin         let (start, end) = self.block_succ_range[block.get() as usize];
574d8357426SChris Fallin         self.block_succs[start..end]
575d8357426SChris Fallin             .iter()
576d8357426SChris Fallin             .cloned()
577d8357426SChris Fallin             .map(BlockIx::new)
578d8357426SChris Fallin             .collect()
579d8357426SChris Fallin     }
580d8357426SChris Fallin 
581d8357426SChris Fallin     fn is_ret(&self, insn: InstIx) -> bool {
582d8357426SChris Fallin         match self.insts[insn.get() as usize].is_term() {
583d8357426SChris Fallin             MachTerminator::Ret => true,
584d8357426SChris Fallin             _ => false,
585d8357426SChris Fallin         }
586d8357426SChris Fallin     }
587d8357426SChris Fallin 
588d8357426SChris Fallin     fn get_regs(insn: &I, collector: &mut RegUsageCollector) {
589d8357426SChris Fallin         insn.get_regs(collector)
590d8357426SChris Fallin     }
591d8357426SChris Fallin 
592d8357426SChris Fallin     fn map_regs(
593d8357426SChris Fallin         insn: &mut I,
594d8357426SChris Fallin         pre_map: &RegallocMap<VirtualReg, RealReg>,
595d8357426SChris Fallin         post_map: &RegallocMap<VirtualReg, RealReg>,
596d8357426SChris Fallin     ) {
597d8357426SChris Fallin         insn.map_regs(pre_map, post_map);
598d8357426SChris Fallin     }
599d8357426SChris Fallin 
600d8357426SChris Fallin     fn is_move(&self, insn: &I) -> Option<(Writable<Reg>, Reg)> {
601d8357426SChris Fallin         insn.is_move()
602d8357426SChris Fallin     }
603d8357426SChris Fallin 
604d8357426SChris Fallin     fn get_spillslot_size(&self, regclass: RegClass, vreg: VirtualReg) -> u32 {
605d8357426SChris Fallin         let ty = self.vreg_type(vreg);
606d8357426SChris Fallin         self.abi.get_spillslot_size(regclass, ty)
607d8357426SChris Fallin     }
608d8357426SChris Fallin 
609d8357426SChris Fallin     fn gen_spill(&self, to_slot: SpillSlot, from_reg: RealReg, vreg: VirtualReg) -> I {
610d8357426SChris Fallin         let ty = self.vreg_type(vreg);
611d8357426SChris Fallin         self.abi.gen_spill(to_slot, from_reg, ty)
612d8357426SChris Fallin     }
613d8357426SChris Fallin 
614d8357426SChris Fallin     fn gen_reload(&self, to_reg: Writable<RealReg>, from_slot: SpillSlot, vreg: VirtualReg) -> I {
615d8357426SChris Fallin         let ty = self.vreg_type(vreg);
616d8357426SChris Fallin         self.abi.gen_reload(to_reg, from_slot, ty)
617d8357426SChris Fallin     }
618d8357426SChris Fallin 
619d8357426SChris Fallin     fn gen_move(&self, to_reg: Writable<RealReg>, from_reg: RealReg, vreg: VirtualReg) -> I {
620d8357426SChris Fallin         let ty = self.vreg_type(vreg);
621d8357426SChris Fallin         I::gen_move(to_reg.map(|r| r.to_reg()), from_reg.to_reg(), ty)
622d8357426SChris Fallin     }
623d8357426SChris Fallin 
624d8357426SChris Fallin     fn gen_zero_len_nop(&self) -> I {
625d8357426SChris Fallin         I::gen_zero_len_nop()
626d8357426SChris Fallin     }
627d8357426SChris Fallin 
628d8357426SChris Fallin     fn maybe_direct_reload(&self, insn: &I, reg: VirtualReg, slot: SpillSlot) -> Option<I> {
629d8357426SChris Fallin         insn.maybe_direct_reload(reg, slot)
630d8357426SChris Fallin     }
631d8357426SChris Fallin 
632d8357426SChris Fallin     fn func_liveins(&self) -> RegallocSet<RealReg> {
633d8357426SChris Fallin         self.liveins.clone()
634d8357426SChris Fallin     }
635d8357426SChris Fallin 
636d8357426SChris Fallin     fn func_liveouts(&self) -> RegallocSet<RealReg> {
637d8357426SChris Fallin         self.liveouts.clone()
638d8357426SChris Fallin     }
639d8357426SChris Fallin }
640d8357426SChris Fallin 
641d8357426SChris Fallin impl<I: VCodeInst> fmt::Debug for VCode<I> {
642d8357426SChris Fallin     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
643d8357426SChris Fallin         writeln!(f, "VCode_Debug {{")?;
644d8357426SChris Fallin         writeln!(f, "  Entry block: {}", self.entry)?;
645d8357426SChris Fallin         writeln!(f, "  Final block order: {:?}", self.final_block_order)?;
646d8357426SChris Fallin 
647d8357426SChris Fallin         for block in 0..self.num_blocks() {
648d8357426SChris Fallin             writeln!(f, "Block {}:", block,)?;
649d8357426SChris Fallin             for succ in self.succs(block as BlockIndex) {
650d8357426SChris Fallin                 writeln!(f, "  (successor: Block {})", succ)?;
651d8357426SChris Fallin             }
652d8357426SChris Fallin             let (start, end) = self.block_ranges[block];
653d8357426SChris Fallin             writeln!(f, "  (instruction range: {} .. {})", start, end)?;
654d8357426SChris Fallin             for inst in start..end {
655d8357426SChris Fallin                 writeln!(f, "  Inst {}: {:?}", inst, self.insts[inst as usize])?;
656d8357426SChris Fallin             }
657d8357426SChris Fallin         }
658d8357426SChris Fallin 
659d8357426SChris Fallin         writeln!(f, "}}")?;
660d8357426SChris Fallin         Ok(())
661d8357426SChris Fallin     }
662d8357426SChris Fallin }
663d8357426SChris Fallin 
66448cf2c2fSChris Fallin /// Pretty-printing with `RealRegUniverse` context.
665d8357426SChris Fallin impl<I: VCodeInst + ShowWithRRU> ShowWithRRU for VCode<I> {
666d8357426SChris Fallin     fn show_rru(&self, mb_rru: Option<&RealRegUniverse>) -> String {
667d8357426SChris Fallin         use std::fmt::Write;
668d8357426SChris Fallin 
669d8357426SChris Fallin         // Calculate an order in which to display the blocks.  This is the same
670d8357426SChris Fallin         // as final_block_order, but also includes blocks which are in the
671d8357426SChris Fallin         // representation but not in final_block_order.
672d8357426SChris Fallin         let mut display_order = Vec::<usize>::new();
67348cf2c2fSChris Fallin         // First display blocks in `final_block_order`
674d8357426SChris Fallin         for bix in &self.final_block_order {
675d8357426SChris Fallin             assert!((*bix as usize) < self.num_blocks());
676d8357426SChris Fallin             display_order.push(*bix as usize);
677d8357426SChris Fallin         }
67848cf2c2fSChris Fallin         // Now also take care of those not listed in `final_block_order`.
679d8357426SChris Fallin         // This is quadratic, but it's also debug-only code.
680d8357426SChris Fallin         for bix in 0..self.num_blocks() {
681d8357426SChris Fallin             if display_order.contains(&bix) {
682d8357426SChris Fallin                 continue;
683d8357426SChris Fallin             }
684d8357426SChris Fallin             display_order.push(bix);
685d8357426SChris Fallin         }
686d8357426SChris Fallin 
687d8357426SChris Fallin         let mut s = String::new();
68848cf2c2fSChris Fallin         write!(&mut s, "VCode_ShowWithRRU {{{{\n").unwrap();
68948cf2c2fSChris Fallin         write!(&mut s, "  Entry block: {}\n", self.entry).unwrap();
69048cf2c2fSChris Fallin         write!(
69148cf2c2fSChris Fallin             &mut s,
69248cf2c2fSChris Fallin             "  Final block order: {:?}\n",
69348cf2c2fSChris Fallin             self.final_block_order
69448cf2c2fSChris Fallin         )
69548cf2c2fSChris Fallin         .unwrap();
696d8357426SChris Fallin 
697d8357426SChris Fallin         for i in 0..self.num_blocks() {
698d8357426SChris Fallin             let block = display_order[i];
699d8357426SChris Fallin 
70048cf2c2fSChris Fallin             let omitted = if !self.final_block_order.is_empty() && i >= self.final_block_order.len()
70148cf2c2fSChris Fallin             {
702d8357426SChris Fallin                 "** OMITTED **"
703d8357426SChris Fallin             } else {
704d8357426SChris Fallin                 ""
70548cf2c2fSChris Fallin             };
706d8357426SChris Fallin 
70748cf2c2fSChris Fallin             write!(&mut s, "Block {}: {}\n", block, omitted).unwrap();
708d8357426SChris Fallin             if let Some(bb) = self.bindex_to_bb(block as BlockIndex) {
70948cf2c2fSChris Fallin                 write!(&mut s, "  (original IR block: {})\n", bb).unwrap();
710d8357426SChris Fallin             }
711d8357426SChris Fallin             for succ in self.succs(block as BlockIndex) {
71248cf2c2fSChris Fallin                 write!(&mut s, "  (successor: Block {})\n", succ).unwrap();
713d8357426SChris Fallin             }
714d8357426SChris Fallin             let (start, end) = self.block_ranges[block];
71548cf2c2fSChris Fallin             write!(&mut s, "  (instruction range: {} .. {})\n", start, end).unwrap();
716d8357426SChris Fallin             for inst in start..end {
71748cf2c2fSChris Fallin                 write!(
71848cf2c2fSChris Fallin                     &mut s,
71948cf2c2fSChris Fallin                     "  Inst {}:   {}\n",
720d8357426SChris Fallin                     inst,
721d8357426SChris Fallin                     self.insts[inst as usize].show_rru(mb_rru)
72248cf2c2fSChris Fallin                 )
72348cf2c2fSChris Fallin                 .unwrap();
724d8357426SChris Fallin             }
725d8357426SChris Fallin         }
726d8357426SChris Fallin 
72748cf2c2fSChris Fallin         write!(&mut s, "}}}}\n").unwrap();
728d8357426SChris Fallin 
729d8357426SChris Fallin         s
730d8357426SChris Fallin     }
731d8357426SChris Fallin }
732