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 
20b691770fSChris Fallin use crate::entity::SecondaryMap;
211d90751bSBenjamin Bouvier use crate::ir::{self, Block, SourceLoc};
22d8357426SChris Fallin use crate::machinst::*;
23d8357426SChris Fallin use crate::settings;
24d8357426SChris Fallin 
25d8357426SChris Fallin use regalloc::Function as RegallocFunction;
26d8357426SChris Fallin use regalloc::Set as RegallocSet;
27be6f060aSChris Fallin use regalloc::{
28be6f060aSChris Fallin     BlockIx, InstIx, Range, RegAllocResult, RegClass, RegUsageCollector, RegUsageMapper,
29be6f060aSChris Fallin };
30d8357426SChris Fallin 
31d8357426SChris Fallin use alloc::boxed::Box;
32*4f919c64SBenjamin Bouvier use alloc::{borrow::Cow, vec::Vec};
33d8357426SChris Fallin use log::debug;
34d8357426SChris Fallin use smallvec::SmallVec;
35d8357426SChris Fallin use std::fmt;
36d8357426SChris Fallin use std::iter;
37d8357426SChris Fallin use std::string::String;
38d8357426SChris Fallin 
39d8357426SChris Fallin /// Index referring to an instruction in VCode.
40d8357426SChris Fallin pub type InsnIndex = u32;
41d8357426SChris Fallin /// Index referring to a basic block in VCode.
42d8357426SChris Fallin pub type BlockIndex = u32;
43d8357426SChris Fallin 
44d8357426SChris Fallin /// VCodeInst wraps all requirements for a MachInst to be in VCode: it must be
45d8357426SChris Fallin /// a `MachInst` and it must be able to emit itself at least to a `SizeCodeSink`.
46d8357426SChris Fallin pub trait VCodeInst: MachInst + MachInstEmit<MachSection> + MachInstEmit<MachSectionSize> {}
47d8357426SChris Fallin impl<I: MachInst + MachInstEmit<MachSection> + MachInstEmit<MachSectionSize>> VCodeInst for I {}
48d8357426SChris Fallin 
49d8357426SChris Fallin /// A function in "VCode" (virtualized-register code) form, after lowering.
50d8357426SChris Fallin /// This is essentially a standard CFG of basic blocks, where each basic block
51d8357426SChris Fallin /// consists of lowered instructions produced by the machine-specific backend.
52d8357426SChris Fallin pub struct VCode<I: VCodeInst> {
53d8357426SChris Fallin     /// Function liveins.
54d8357426SChris Fallin     liveins: RegallocSet<RealReg>,
55d8357426SChris Fallin 
56d8357426SChris Fallin     /// Function liveouts.
57d8357426SChris Fallin     liveouts: RegallocSet<RealReg>,
58d8357426SChris Fallin 
59d8357426SChris Fallin     /// VReg IR-level types.
60d8357426SChris Fallin     vreg_types: Vec<Type>,
61d8357426SChris Fallin 
62d8357426SChris Fallin     /// Lowered machine instructions in order corresponding to the original IR.
6348cf2c2fSChris Fallin     insts: Vec<I>,
64d8357426SChris Fallin 
65b691770fSChris Fallin     /// Source locations for each instruction. (`SourceLoc` is a `u32`, so it is
66b691770fSChris Fallin     /// reasonable to keep one of these per instruction.)
67b691770fSChris Fallin     srclocs: Vec<SourceLoc>,
68b691770fSChris Fallin 
69d8357426SChris Fallin     /// Entry block.
70d8357426SChris Fallin     entry: BlockIndex,
71d8357426SChris Fallin 
72d8357426SChris Fallin     /// Block instruction indices.
7348cf2c2fSChris Fallin     block_ranges: Vec<(InsnIndex, InsnIndex)>,
74d8357426SChris Fallin 
75d8357426SChris Fallin     /// Block successors: index range in the successor-list below.
76d8357426SChris Fallin     block_succ_range: Vec<(usize, usize)>,
77d8357426SChris Fallin 
78d8357426SChris Fallin     /// Block successor lists, concatenated into one Vec. The `block_succ_range`
79d8357426SChris Fallin     /// list of tuples above gives (start, end) ranges within this list that
80d8357426SChris Fallin     /// correspond to each basic block's successors.
81*4f919c64SBenjamin Bouvier     block_succs: Vec<BlockIx>,
82d8357426SChris Fallin 
83d8357426SChris Fallin     /// Block indices by IR block.
84d8357426SChris Fallin     block_by_bb: SecondaryMap<ir::Block, BlockIndex>,
85d8357426SChris Fallin 
86d8357426SChris Fallin     /// IR block for each VCode Block. The length of this Vec will likely be
87d8357426SChris Fallin     /// less than the total number of Blocks, because new Blocks (for edge
88d8357426SChris Fallin     /// splits, for example) are appended during lowering.
89d8357426SChris Fallin     bb_by_block: Vec<ir::Block>,
90d8357426SChris Fallin 
91d8357426SChris Fallin     /// Order of block IDs in final generated code.
92d8357426SChris Fallin     final_block_order: Vec<BlockIndex>,
93d8357426SChris Fallin 
94d8357426SChris Fallin     /// Final block offsets. Computed during branch finalization and used
95d8357426SChris Fallin     /// during emission.
96d8357426SChris Fallin     final_block_offsets: Vec<CodeOffset>,
97d8357426SChris Fallin 
98d8357426SChris Fallin     /// Size of code, accounting for block layout / alignment.
99d8357426SChris Fallin     code_size: CodeOffset,
100d8357426SChris Fallin 
101d8357426SChris Fallin     /// ABI object.
10248cf2c2fSChris Fallin     abi: Box<dyn ABIBody<I = I>>,
1031d90751bSBenjamin Bouvier 
1041d90751bSBenjamin Bouvier     /// The block targeted by fallthrough_returns, if there's one.
1051d90751bSBenjamin Bouvier     pub fallthrough_return_block: Option<BlockIndex>,
106d8357426SChris Fallin }
107d8357426SChris Fallin 
108d8357426SChris Fallin /// A builder for a VCode function body. This builder is designed for the
109d8357426SChris Fallin /// lowering approach that we take: we traverse basic blocks in forward
110d8357426SChris Fallin /// (original IR) order, but within each basic block, we generate code from
111d8357426SChris Fallin /// bottom to top; and within each IR instruction that we visit in this reverse
112d8357426SChris Fallin /// order, we emit machine instructions in *forward* order again.
113d8357426SChris Fallin ///
114d8357426SChris Fallin /// Hence, to produce the final instructions in proper order, we perform two
115d8357426SChris Fallin /// swaps.  First, the machine instructions (`I` instances) are produced in
116d8357426SChris Fallin /// forward order for an individual IR instruction. Then these are *reversed*
117d8357426SChris Fallin /// and concatenated to `bb_insns` at the end of the IR instruction lowering.
118d8357426SChris Fallin /// The `bb_insns` vec will thus contain all machine instructions for a basic
119d8357426SChris Fallin /// block, in reverse order. Finally, when we're done with a basic block, we
120d8357426SChris Fallin /// reverse the whole block's vec of instructions again, and concatenate onto
121d8357426SChris Fallin /// the VCode's insts.
122d8357426SChris Fallin pub struct VCodeBuilder<I: VCodeInst> {
123d8357426SChris Fallin     /// In-progress VCode.
124d8357426SChris Fallin     vcode: VCode<I>,
125d8357426SChris Fallin 
126d8357426SChris Fallin     /// Current basic block instructions, in reverse order (because blocks are
127d8357426SChris Fallin     /// built bottom-to-top).
128b691770fSChris Fallin     bb_insns: SmallVec<[(I, SourceLoc); 32]>,
129d8357426SChris Fallin 
130d8357426SChris Fallin     /// Current IR-inst instructions, in forward order.
131b691770fSChris Fallin     ir_inst_insns: SmallVec<[(I, SourceLoc); 4]>,
132d8357426SChris Fallin 
133d8357426SChris Fallin     /// Start of succs for the current block in the concatenated succs list.
134d8357426SChris Fallin     succ_start: usize,
135b691770fSChris Fallin 
136b691770fSChris Fallin     /// Current source location.
137b691770fSChris Fallin     cur_srcloc: SourceLoc,
138d8357426SChris Fallin }
139d8357426SChris Fallin 
140d8357426SChris Fallin impl<I: VCodeInst> VCodeBuilder<I> {
141d8357426SChris Fallin     /// Create a new VCodeBuilder.
14248cf2c2fSChris Fallin     pub fn new(abi: Box<dyn ABIBody<I = I>>) -> VCodeBuilder<I> {
143d8357426SChris Fallin         let vcode = VCode::new(abi);
144d8357426SChris Fallin         VCodeBuilder {
145d8357426SChris Fallin             vcode,
146d8357426SChris Fallin             bb_insns: SmallVec::new(),
147d8357426SChris Fallin             ir_inst_insns: SmallVec::new(),
148d8357426SChris Fallin             succ_start: 0,
149b691770fSChris Fallin             cur_srcloc: SourceLoc::default(),
150d8357426SChris Fallin         }
151d8357426SChris Fallin     }
152d8357426SChris Fallin 
153d8357426SChris Fallin     /// Access the ABI object.
15448cf2c2fSChris Fallin     pub fn abi(&mut self) -> &mut dyn ABIBody<I = I> {
155d8357426SChris Fallin         &mut *self.vcode.abi
156d8357426SChris Fallin     }
157d8357426SChris Fallin 
1581d90751bSBenjamin Bouvier     /// Set the fallthrough_return target block for this function. There must be at most once per
1591d90751bSBenjamin Bouvier     /// function.
1601d90751bSBenjamin Bouvier     pub fn set_fallthrough_return_block(&mut self, bb: Block) {
1611d90751bSBenjamin Bouvier         debug_assert!(
1621d90751bSBenjamin Bouvier             self.vcode.fallthrough_return_block.is_none(),
1631d90751bSBenjamin Bouvier             "a function must have at most one fallthrough-return instruction"
1641d90751bSBenjamin Bouvier         );
1651d90751bSBenjamin Bouvier         self.vcode.fallthrough_return_block = Some(self.bb_to_bindex(bb));
1661d90751bSBenjamin Bouvier     }
1671d90751bSBenjamin Bouvier 
168d8357426SChris Fallin     /// Set the type of a VReg.
169d8357426SChris Fallin     pub fn set_vreg_type(&mut self, vreg: VirtualReg, ty: Type) {
170d8357426SChris Fallin         while self.vcode.vreg_types.len() <= vreg.get_index() {
171d8357426SChris Fallin             self.vcode.vreg_types.push(ir::types::I8); // Default type.
172d8357426SChris Fallin         }
173d8357426SChris Fallin         self.vcode.vreg_types[vreg.get_index()] = ty;
174d8357426SChris Fallin     }
175d8357426SChris Fallin 
176d8357426SChris Fallin     /// Return the underlying bb-to-BlockIndex map.
177d8357426SChris Fallin     pub fn blocks_by_bb(&self) -> &SecondaryMap<ir::Block, BlockIndex> {
178d8357426SChris Fallin         &self.vcode.block_by_bb
179d8357426SChris Fallin     }
180d8357426SChris Fallin 
181d8357426SChris Fallin     /// Initialize the bb-to-BlockIndex map. Returns the first free
182d8357426SChris Fallin     /// BlockIndex.
183d8357426SChris Fallin     pub fn init_bb_map(&mut self, blocks: &[ir::Block]) -> BlockIndex {
184d8357426SChris Fallin         let mut bindex: BlockIndex = 0;
185d8357426SChris Fallin         for bb in blocks.iter() {
186d8357426SChris Fallin             self.vcode.block_by_bb[*bb] = bindex;
187d8357426SChris Fallin             self.vcode.bb_by_block.push(*bb);
188d8357426SChris Fallin             bindex += 1;
189d8357426SChris Fallin         }
190d8357426SChris Fallin         bindex
191d8357426SChris Fallin     }
192d8357426SChris Fallin 
193d8357426SChris Fallin     /// Get the BlockIndex for an IR block.
194d8357426SChris Fallin     pub fn bb_to_bindex(&self, bb: ir::Block) -> BlockIndex {
195d8357426SChris Fallin         self.vcode.block_by_bb[bb]
196d8357426SChris Fallin     }
197d8357426SChris Fallin 
198d8357426SChris Fallin     /// Set the current block as the entry block.
199d8357426SChris Fallin     pub fn set_entry(&mut self, block: BlockIndex) {
200d8357426SChris Fallin         self.vcode.entry = block;
201d8357426SChris Fallin     }
202d8357426SChris Fallin 
203d8357426SChris Fallin     /// End the current IR instruction. Must be called after pushing any
204d8357426SChris Fallin     /// instructions and prior to ending the basic block.
205d8357426SChris Fallin     pub fn end_ir_inst(&mut self) {
206b691770fSChris Fallin         while let Some(pair) = self.ir_inst_insns.pop() {
207b691770fSChris Fallin             self.bb_insns.push(pair);
208d8357426SChris Fallin         }
209d8357426SChris Fallin     }
210d8357426SChris Fallin 
211d8357426SChris Fallin     /// End the current basic block. Must be called after emitting vcode insts
212d8357426SChris Fallin     /// for IR insts and prior to ending the function (building the VCode).
213d8357426SChris Fallin     pub fn end_bb(&mut self) -> BlockIndex {
214d8357426SChris Fallin         assert!(self.ir_inst_insns.is_empty());
215d8357426SChris Fallin         let block_num = self.vcode.block_ranges.len() as BlockIndex;
216d8357426SChris Fallin         // Push the instructions.
217d8357426SChris Fallin         let start_idx = self.vcode.insts.len() as InsnIndex;
218b691770fSChris Fallin         while let Some((i, loc)) = self.bb_insns.pop() {
219d8357426SChris Fallin             self.vcode.insts.push(i);
220b691770fSChris Fallin             self.vcode.srclocs.push(loc);
221d8357426SChris Fallin         }
222d8357426SChris Fallin         let end_idx = self.vcode.insts.len() as InsnIndex;
223d8357426SChris Fallin         // Add the instruction index range to the list of blocks.
224d8357426SChris Fallin         self.vcode.block_ranges.push((start_idx, end_idx));
225d8357426SChris Fallin         // End the successors list.
226d8357426SChris Fallin         let succ_end = self.vcode.block_succs.len();
227d8357426SChris Fallin         self.vcode
228d8357426SChris Fallin             .block_succ_range
229d8357426SChris Fallin             .push((self.succ_start, succ_end));
230d8357426SChris Fallin         self.succ_start = succ_end;
231d8357426SChris Fallin 
232d8357426SChris Fallin         block_num
233d8357426SChris Fallin     }
234d8357426SChris Fallin 
235d8357426SChris Fallin     /// Push an instruction for the current BB and current IR inst within the BB.
236d8357426SChris Fallin     pub fn push(&mut self, insn: I) {
237d8357426SChris Fallin         match insn.is_term() {
238d8357426SChris Fallin             MachTerminator::None | MachTerminator::Ret => {}
239d8357426SChris Fallin             MachTerminator::Uncond(target) => {
240*4f919c64SBenjamin Bouvier                 self.vcode.block_succs.push(BlockIx::new(target));
241d8357426SChris Fallin             }
242d8357426SChris Fallin             MachTerminator::Cond(true_branch, false_branch) => {
243*4f919c64SBenjamin Bouvier                 self.vcode.block_succs.push(BlockIx::new(true_branch));
244*4f919c64SBenjamin Bouvier                 self.vcode.block_succs.push(BlockIx::new(false_branch));
245d8357426SChris Fallin             }
246d8357426SChris Fallin             MachTerminator::Indirect(targets) => {
247d8357426SChris Fallin                 for target in targets {
248*4f919c64SBenjamin Bouvier                     self.vcode.block_succs.push(BlockIx::new(*target));
249d8357426SChris Fallin                 }
250d8357426SChris Fallin             }
251d8357426SChris Fallin         }
252b691770fSChris Fallin         self.ir_inst_insns.push((insn, self.cur_srcloc));
253b691770fSChris Fallin     }
254b691770fSChris Fallin 
255b691770fSChris Fallin     /// Set the current source location.
256b691770fSChris Fallin     pub fn set_srcloc(&mut self, srcloc: SourceLoc) {
257b691770fSChris Fallin         self.cur_srcloc = srcloc;
258d8357426SChris Fallin     }
259d8357426SChris Fallin 
260d8357426SChris Fallin     /// Build the final VCode.
261d8357426SChris Fallin     pub fn build(self) -> VCode<I> {
262d8357426SChris Fallin         assert!(self.ir_inst_insns.is_empty());
263d8357426SChris Fallin         assert!(self.bb_insns.is_empty());
264d8357426SChris Fallin         self.vcode
265d8357426SChris Fallin     }
266d8357426SChris Fallin }
267d8357426SChris Fallin 
268d8357426SChris Fallin fn block_ranges(indices: &[InstIx], len: usize) -> Vec<(usize, usize)> {
269d8357426SChris Fallin     let v = indices
270d8357426SChris Fallin         .iter()
271d8357426SChris Fallin         .map(|iix| iix.get() as usize)
272d8357426SChris Fallin         .chain(iter::once(len))
273d8357426SChris Fallin         .collect::<Vec<usize>>();
274d8357426SChris Fallin     v.windows(2).map(|p| (p[0], p[1])).collect()
275d8357426SChris Fallin }
276d8357426SChris Fallin 
277d8357426SChris Fallin fn is_redundant_move<I: VCodeInst>(insn: &I) -> bool {
278d8357426SChris Fallin     if let Some((to, from)) = insn.is_move() {
279d8357426SChris Fallin         to.to_reg() == from
280d8357426SChris Fallin     } else {
281d8357426SChris Fallin         false
282d8357426SChris Fallin     }
283d8357426SChris Fallin }
284d8357426SChris Fallin 
285d8357426SChris Fallin fn is_trivial_jump_block<I: VCodeInst>(vcode: &VCode<I>, block: BlockIndex) -> Option<BlockIndex> {
286d8357426SChris Fallin     let range = vcode.block_insns(BlockIx::new(block));
287d8357426SChris Fallin 
288d8357426SChris Fallin     debug!(
289d8357426SChris Fallin         "is_trivial_jump_block: block {} has len {}",
290d8357426SChris Fallin         block,
291d8357426SChris Fallin         range.len()
292d8357426SChris Fallin     );
293d8357426SChris Fallin 
294d8357426SChris Fallin     if range.len() != 1 {
295d8357426SChris Fallin         return None;
296d8357426SChris Fallin     }
297d8357426SChris Fallin     let insn = range.first();
298d8357426SChris Fallin 
299d8357426SChris Fallin     debug!(
300d8357426SChris Fallin         " -> only insn is: {:?} with terminator {:?}",
301d8357426SChris Fallin         vcode.get_insn(insn),
302d8357426SChris Fallin         vcode.get_insn(insn).is_term()
303d8357426SChris Fallin     );
304d8357426SChris Fallin 
305d8357426SChris Fallin     match vcode.get_insn(insn).is_term() {
306d8357426SChris Fallin         MachTerminator::Uncond(target) => Some(target),
307d8357426SChris Fallin         _ => None,
308d8357426SChris Fallin     }
309d8357426SChris Fallin }
310d8357426SChris Fallin 
311d8357426SChris Fallin impl<I: VCodeInst> VCode<I> {
312d8357426SChris Fallin     /// New empty VCode.
31348cf2c2fSChris Fallin     fn new(abi: Box<dyn ABIBody<I = I>>) -> VCode<I> {
314d8357426SChris Fallin         VCode {
315d8357426SChris Fallin             liveins: abi.liveins(),
316d8357426SChris Fallin             liveouts: abi.liveouts(),
317d8357426SChris Fallin             vreg_types: vec![],
318d8357426SChris Fallin             insts: vec![],
319b691770fSChris Fallin             srclocs: vec![],
320d8357426SChris Fallin             entry: 0,
321d8357426SChris Fallin             block_ranges: vec![],
322d8357426SChris Fallin             block_succ_range: vec![],
323d8357426SChris Fallin             block_succs: vec![],
324d8357426SChris Fallin             block_by_bb: SecondaryMap::with_default(0),
325d8357426SChris Fallin             bb_by_block: vec![],
326d8357426SChris Fallin             final_block_order: vec![],
327d8357426SChris Fallin             final_block_offsets: vec![],
328d8357426SChris Fallin             code_size: 0,
329d8357426SChris Fallin             abi,
3301d90751bSBenjamin Bouvier             fallthrough_return_block: None,
331d8357426SChris Fallin         }
332d8357426SChris Fallin     }
333d8357426SChris Fallin 
334d1b5df31SBenjamin Bouvier     /// Returns the flags controlling this function's compilation.
335d1b5df31SBenjamin Bouvier     pub fn flags(&self) -> &settings::Flags {
336d1b5df31SBenjamin Bouvier         self.abi.flags()
337d1b5df31SBenjamin Bouvier     }
338d1b5df31SBenjamin Bouvier 
339d8357426SChris Fallin     /// Get the IR-level type of a VReg.
340d8357426SChris Fallin     pub fn vreg_type(&self, vreg: VirtualReg) -> Type {
341d8357426SChris Fallin         self.vreg_types[vreg.get_index()]
342d8357426SChris Fallin     }
343d8357426SChris Fallin 
344d8357426SChris Fallin     /// Get the entry block.
345d8357426SChris Fallin     pub fn entry(&self) -> BlockIndex {
346d8357426SChris Fallin         self.entry
347d8357426SChris Fallin     }
348d8357426SChris Fallin 
349d8357426SChris Fallin     /// Get the number of blocks. Block indices will be in the range `0 ..
350d8357426SChris Fallin     /// (self.num_blocks() - 1)`.
351d8357426SChris Fallin     pub fn num_blocks(&self) -> usize {
352d8357426SChris Fallin         self.block_ranges.len()
353d8357426SChris Fallin     }
354d8357426SChris Fallin 
355d8357426SChris Fallin     /// Stack frame size for the full function's body.
356d8357426SChris Fallin     pub fn frame_size(&self) -> u32 {
357d8357426SChris Fallin         self.abi.frame_size()
358d8357426SChris Fallin     }
359d8357426SChris Fallin 
360d8357426SChris Fallin     /// Get the successors for a block.
361*4f919c64SBenjamin Bouvier     pub fn succs(&self, block: BlockIndex) -> &[BlockIx] {
362d8357426SChris Fallin         let (start, end) = self.block_succ_range[block as usize];
363d8357426SChris Fallin         &self.block_succs[start..end]
364d8357426SChris Fallin     }
365d8357426SChris Fallin 
366d8357426SChris Fallin     /// Take the results of register allocation, with a sequence of
367d8357426SChris Fallin     /// instructions including spliced fill/reload/move instructions, and replace
368d8357426SChris Fallin     /// the VCode with them.
369d1b5df31SBenjamin Bouvier     pub fn replace_insns_from_regalloc(&mut self, result: RegAllocResult<Self>) {
370d8357426SChris Fallin         self.final_block_order = compute_final_block_order(self);
371d8357426SChris Fallin 
372d8357426SChris Fallin         // Record the spillslot count and clobbered registers for the ABI/stack
373d8357426SChris Fallin         // setup code.
374d8357426SChris Fallin         self.abi.set_num_spillslots(result.num_spill_slots as usize);
375d8357426SChris Fallin         self.abi
376d8357426SChris Fallin             .set_clobbered(result.clobbered_registers.map(|r| Writable::from_reg(*r)));
377d8357426SChris Fallin 
378d8357426SChris Fallin         // We want to move instructions over in final block order, using the new
379d8357426SChris Fallin         // block-start map given by the regalloc.
380d8357426SChris Fallin         let block_ranges: Vec<(usize, usize)> =
381d8357426SChris Fallin             block_ranges(result.target_map.elems(), result.insns.len());
382d8357426SChris Fallin         let mut final_insns = vec![];
383d8357426SChris Fallin         let mut final_block_ranges = vec![(0, 0); self.num_blocks()];
384b691770fSChris Fallin         let mut final_srclocs = vec![];
385d8357426SChris Fallin 
386d8357426SChris Fallin         for block in &self.final_block_order {
387d8357426SChris Fallin             let (start, end) = block_ranges[*block as usize];
388d8357426SChris Fallin             let final_start = final_insns.len() as InsnIndex;
389d8357426SChris Fallin 
390d8357426SChris Fallin             if *block == self.entry {
391d8357426SChris Fallin                 // Start with the prologue.
392b691770fSChris Fallin                 let prologue = self.abi.gen_prologue();
393b691770fSChris Fallin                 let len = prologue.len();
394b691770fSChris Fallin                 final_insns.extend(prologue.into_iter());
395b691770fSChris Fallin                 final_srclocs.extend(iter::repeat(SourceLoc::default()).take(len));
396d8357426SChris Fallin             }
397d8357426SChris Fallin 
398d8357426SChris Fallin             for i in start..end {
399d8357426SChris Fallin                 let insn = &result.insns[i];
400d8357426SChris Fallin 
401d8357426SChris Fallin                 // Elide redundant moves at this point (we only know what is
402d8357426SChris Fallin                 // redundant once registers are allocated).
403d8357426SChris Fallin                 if is_redundant_move(insn) {
404d8357426SChris Fallin                     continue;
405d8357426SChris Fallin                 }
406d8357426SChris Fallin 
407b691770fSChris Fallin                 // Is there a srcloc associated with this insn? Look it up based on original
408b691770fSChris Fallin                 // instruction index (if new insn corresponds to some original insn, i.e., is not
409b691770fSChris Fallin                 // an inserted load/spill/move).
410b691770fSChris Fallin                 let orig_iix = result.orig_insn_map[InstIx::new(i as u32)];
411b691770fSChris Fallin                 let srcloc = if orig_iix.is_invalid() {
412b691770fSChris Fallin                     SourceLoc::default()
413b691770fSChris Fallin                 } else {
414b691770fSChris Fallin                     self.srclocs[orig_iix.get() as usize]
415b691770fSChris Fallin                 };
416b691770fSChris Fallin 
417d8357426SChris Fallin                 // Whenever encountering a return instruction, replace it
418d8357426SChris Fallin                 // with the epilogue.
419d8357426SChris Fallin                 let is_ret = insn.is_term() == MachTerminator::Ret;
420d8357426SChris Fallin                 if is_ret {
421b691770fSChris Fallin                     let epilogue = self.abi.gen_epilogue();
422b691770fSChris Fallin                     let len = epilogue.len();
423b691770fSChris Fallin                     final_insns.extend(epilogue.into_iter());
424b691770fSChris Fallin                     final_srclocs.extend(iter::repeat(srcloc).take(len));
425d8357426SChris Fallin                 } else {
426d8357426SChris Fallin                     final_insns.push(insn.clone());
427b691770fSChris Fallin                     final_srclocs.push(srcloc);
428d8357426SChris Fallin                 }
429d8357426SChris Fallin             }
430d8357426SChris Fallin 
431d8357426SChris Fallin             let final_end = final_insns.len() as InsnIndex;
432d8357426SChris Fallin             final_block_ranges[*block as usize] = (final_start, final_end);
433d8357426SChris Fallin         }
434d8357426SChris Fallin 
435b691770fSChris Fallin         debug_assert!(final_insns.len() == final_srclocs.len());
436b691770fSChris Fallin 
437d8357426SChris Fallin         self.insts = final_insns;
438b691770fSChris Fallin         self.srclocs = final_srclocs;
439d8357426SChris Fallin         self.block_ranges = final_block_ranges;
440d8357426SChris Fallin     }
441d8357426SChris Fallin 
442d8357426SChris Fallin     /// Removes redundant branches, rewriting targets to point directly to the
443d8357426SChris Fallin     /// ultimate block at the end of a chain of trivial one-target jumps.
444d8357426SChris Fallin     pub fn remove_redundant_branches(&mut self) {
445d8357426SChris Fallin         // For each block, compute the actual target block, looking through up to one
446d8357426SChris Fallin         // block with single-target jumps (this will remove empty edge blocks inserted
447d8357426SChris Fallin         // by phi-lowering).
448d8357426SChris Fallin         let block_rewrites: Vec<BlockIndex> = (0..self.num_blocks() as u32)
449d8357426SChris Fallin             .map(|bix| is_trivial_jump_block(self, bix).unwrap_or(bix))
450d8357426SChris Fallin             .collect();
451d8357426SChris Fallin         let mut refcounts: Vec<usize> = vec![0; self.num_blocks()];
452d8357426SChris Fallin 
453d8357426SChris Fallin         debug!(
454d8357426SChris Fallin             "remove_redundant_branches: block_rewrites = {:?}",
455d8357426SChris Fallin             block_rewrites
456d8357426SChris Fallin         );
457d8357426SChris Fallin 
458d8357426SChris Fallin         refcounts[self.entry as usize] = 1;
459d8357426SChris Fallin 
460d8357426SChris Fallin         for block in 0..self.num_blocks() as u32 {
461d8357426SChris Fallin             for insn in self.block_insns(BlockIx::new(block)) {
462d8357426SChris Fallin                 self.get_insn_mut(insn)
463d8357426SChris Fallin                     .with_block_rewrites(&block_rewrites[..]);
464d8357426SChris Fallin                 match self.get_insn(insn).is_term() {
465d8357426SChris Fallin                     MachTerminator::Uncond(bix) => {
466d8357426SChris Fallin                         refcounts[bix as usize] += 1;
467d8357426SChris Fallin                     }
468d8357426SChris Fallin                     MachTerminator::Cond(bix1, bix2) => {
469d8357426SChris Fallin                         refcounts[bix1 as usize] += 1;
470d8357426SChris Fallin                         refcounts[bix2 as usize] += 1;
471d8357426SChris Fallin                     }
472d8357426SChris Fallin                     MachTerminator::Indirect(blocks) => {
473d8357426SChris Fallin                         for block in blocks {
474d8357426SChris Fallin                             refcounts[*block as usize] += 1;
475d8357426SChris Fallin                         }
476d8357426SChris Fallin                     }
477d8357426SChris Fallin                     _ => {}
478d8357426SChris Fallin                 }
479d8357426SChris Fallin             }
480d8357426SChris Fallin         }
481d8357426SChris Fallin 
482d8357426SChris Fallin         let deleted: Vec<bool> = refcounts.iter().map(|r| *r == 0).collect();
483d8357426SChris Fallin 
484d8357426SChris Fallin         let block_order = std::mem::replace(&mut self.final_block_order, vec![]);
485d8357426SChris Fallin         self.final_block_order = block_order
486d8357426SChris Fallin             .into_iter()
487d8357426SChris Fallin             .filter(|b| !deleted[*b as usize])
488d8357426SChris Fallin             .collect();
489d8357426SChris Fallin 
490d8357426SChris Fallin         // Rewrite successor information based on the block-rewrite map.
491d8357426SChris Fallin         for succ in &mut self.block_succs {
492*4f919c64SBenjamin Bouvier             let new_succ = block_rewrites[succ.get() as usize];
493*4f919c64SBenjamin Bouvier             *succ = BlockIx::new(new_succ);
494d8357426SChris Fallin         }
495d8357426SChris Fallin     }
496d8357426SChris Fallin 
497d8357426SChris Fallin     /// Mutate branch instructions to (i) lower two-way condbrs to one-way,
498d8357426SChris Fallin     /// depending on fallthrough; and (ii) use concrete offsets.
499d8357426SChris Fallin     pub fn finalize_branches(&mut self)
500d8357426SChris Fallin     where
501d8357426SChris Fallin         I: MachInstEmit<MachSectionSize>,
502d8357426SChris Fallin     {
503d8357426SChris Fallin         // Compute fallthrough block, indexed by block.
504d8357426SChris Fallin         let num_final_blocks = self.final_block_order.len();
505d8357426SChris Fallin         let mut block_fallthrough: Vec<Option<BlockIndex>> = vec![None; self.num_blocks()];
506d8357426SChris Fallin         for i in 0..(num_final_blocks - 1) {
507d8357426SChris Fallin             let from = self.final_block_order[i];
508d8357426SChris Fallin             let to = self.final_block_order[i + 1];
509d8357426SChris Fallin             block_fallthrough[from as usize] = Some(to);
510d8357426SChris Fallin         }
511d8357426SChris Fallin 
512d8357426SChris Fallin         // Pass over VCode instructions and finalize two-way branches into
513d8357426SChris Fallin         // one-way branches with fallthrough.
514d8357426SChris Fallin         for block in 0..self.num_blocks() {
515d8357426SChris Fallin             let next_block = block_fallthrough[block];
516d8357426SChris Fallin             let (start, end) = self.block_ranges[block];
517d8357426SChris Fallin 
518d8357426SChris Fallin             for iix in start..end {
519d8357426SChris Fallin                 let insn = &mut self.insts[iix as usize];
520d8357426SChris Fallin                 insn.with_fallthrough_block(next_block);
521d8357426SChris Fallin             }
522d8357426SChris Fallin         }
523d8357426SChris Fallin 
524a7ca37e4SBenjamin Bouvier         let flags = self.abi.flags();
525a7ca37e4SBenjamin Bouvier 
526d8357426SChris Fallin         // Compute block offsets.
527d8357426SChris Fallin         let mut code_section = MachSectionSize::new(0);
528d8357426SChris Fallin         let mut block_offsets = vec![0; self.num_blocks()];
529a66724aaSChris Fallin         let mut state = Default::default();
53048cf2c2fSChris Fallin         for &block in &self.final_block_order {
531d8357426SChris Fallin             code_section.offset = I::align_basic_block(code_section.offset);
53248cf2c2fSChris Fallin             block_offsets[block as usize] = code_section.offset;
53348cf2c2fSChris Fallin             let (start, end) = self.block_ranges[block as usize];
534d8357426SChris Fallin             for iix in start..end {
535a66724aaSChris Fallin                 self.insts[iix as usize].emit(&mut code_section, flags, &mut state);
536d8357426SChris Fallin             }
537d8357426SChris Fallin         }
538d8357426SChris Fallin 
539d8357426SChris Fallin         // We now have the section layout.
540d8357426SChris Fallin         self.final_block_offsets = block_offsets;
541d8357426SChris Fallin         self.code_size = code_section.size();
542d8357426SChris Fallin 
543d8357426SChris Fallin         // Update branches with known block offsets. This looks like the
544d8357426SChris Fallin         // traversal above, but (i) does not update block_offsets, rather uses
545d8357426SChris Fallin         // it (so forward references are now possible), and (ii) mutates the
546d8357426SChris Fallin         // instructions.
547d8357426SChris Fallin         let mut code_section = MachSectionSize::new(0);
548a66724aaSChris Fallin         let mut state = Default::default();
54948cf2c2fSChris Fallin         for &block in &self.final_block_order {
550d8357426SChris Fallin             code_section.offset = I::align_basic_block(code_section.offset);
55148cf2c2fSChris Fallin             let (start, end) = self.block_ranges[block as usize];
552d8357426SChris Fallin             for iix in start..end {
553d8357426SChris Fallin                 self.insts[iix as usize]
554d8357426SChris Fallin                     .with_block_offsets(code_section.offset, &self.final_block_offsets[..]);
555a66724aaSChris Fallin                 self.insts[iix as usize].emit(&mut code_section, flags, &mut state);
556d8357426SChris Fallin             }
557d8357426SChris Fallin         }
558d8357426SChris Fallin     }
559d8357426SChris Fallin 
560d8357426SChris Fallin     /// Emit the instructions to a list of sections.
561d8357426SChris Fallin     pub fn emit(&self) -> MachSections
562d8357426SChris Fallin     where
563d8357426SChris Fallin         I: MachInstEmit<MachSection>,
564d8357426SChris Fallin     {
565d8357426SChris Fallin         let mut sections = MachSections::new();
566d8357426SChris Fallin         let code_idx = sections.add_section(0, self.code_size);
567d8357426SChris Fallin         let code_section = sections.get_section(code_idx);
568a66724aaSChris Fallin         let mut state = Default::default();
569d8357426SChris Fallin 
570a7ca37e4SBenjamin Bouvier         let flags = self.abi.flags();
571964c6087SChris Fallin         let mut cur_srcloc = None;
57248cf2c2fSChris Fallin         for &block in &self.final_block_order {
573d8357426SChris Fallin             let new_offset = I::align_basic_block(code_section.cur_offset_from_start());
574d8357426SChris Fallin             while new_offset > code_section.cur_offset_from_start() {
575d8357426SChris Fallin                 // Pad with NOPs up to the aligned block offset.
576d8357426SChris Fallin                 let nop = I::gen_nop((new_offset - code_section.cur_offset_from_start()) as usize);
577a66724aaSChris Fallin                 nop.emit(code_section, flags, &mut Default::default());
578d8357426SChris Fallin             }
579d8357426SChris Fallin             assert_eq!(code_section.cur_offset_from_start(), new_offset);
580d8357426SChris Fallin 
58148cf2c2fSChris Fallin             let (start, end) = self.block_ranges[block as usize];
582d8357426SChris Fallin             for iix in start..end {
583b691770fSChris Fallin                 let srcloc = self.srclocs[iix as usize];
584964c6087SChris Fallin                 if cur_srcloc != Some(srcloc) {
585964c6087SChris Fallin                     if cur_srcloc.is_some() {
586b691770fSChris Fallin                         code_section.end_srcloc();
587b691770fSChris Fallin                     }
588b691770fSChris Fallin                     code_section.start_srcloc(srcloc);
589964c6087SChris Fallin                     cur_srcloc = Some(srcloc);
590b691770fSChris Fallin                 }
591b691770fSChris Fallin 
592a66724aaSChris Fallin                 self.insts[iix as usize].emit(code_section, flags, &mut state);
593d8357426SChris Fallin             }
594b691770fSChris Fallin 
595964c6087SChris Fallin             if cur_srcloc.is_some() {
596b691770fSChris Fallin                 code_section.end_srcloc();
597964c6087SChris Fallin                 cur_srcloc = None;
598b691770fSChris Fallin             }
599d8357426SChris Fallin         }
600d8357426SChris Fallin 
601d8357426SChris Fallin         sections
602d8357426SChris Fallin     }
603d8357426SChris Fallin 
604d8357426SChris Fallin     /// Get the IR block for a BlockIndex, if one exists.
605d8357426SChris Fallin     pub fn bindex_to_bb(&self, block: BlockIndex) -> Option<ir::Block> {
606d8357426SChris Fallin         if (block as usize) < self.bb_by_block.len() {
607d8357426SChris Fallin             Some(self.bb_by_block[block as usize])
608d8357426SChris Fallin         } else {
609d8357426SChris Fallin             None
610d8357426SChris Fallin         }
611d8357426SChris Fallin     }
612d8357426SChris Fallin }
613d8357426SChris Fallin 
614d8357426SChris Fallin impl<I: VCodeInst> RegallocFunction for VCode<I> {
615d8357426SChris Fallin     type Inst = I;
616d8357426SChris Fallin 
617d8357426SChris Fallin     fn insns(&self) -> &[I] {
618d8357426SChris Fallin         &self.insts[..]
619d8357426SChris Fallin     }
620d8357426SChris Fallin 
621d8357426SChris Fallin     fn insns_mut(&mut self) -> &mut [I] {
622d8357426SChris Fallin         &mut self.insts[..]
623d8357426SChris Fallin     }
624d8357426SChris Fallin 
625d8357426SChris Fallin     fn get_insn(&self, insn: InstIx) -> &I {
626d8357426SChris Fallin         &self.insts[insn.get() as usize]
627d8357426SChris Fallin     }
628d8357426SChris Fallin 
629d8357426SChris Fallin     fn get_insn_mut(&mut self, insn: InstIx) -> &mut I {
630d8357426SChris Fallin         &mut self.insts[insn.get() as usize]
631d8357426SChris Fallin     }
632d8357426SChris Fallin 
633d8357426SChris Fallin     fn blocks(&self) -> Range<BlockIx> {
634d8357426SChris Fallin         Range::new(BlockIx::new(0), self.block_ranges.len())
635d8357426SChris Fallin     }
636d8357426SChris Fallin 
637d8357426SChris Fallin     fn entry_block(&self) -> BlockIx {
638d8357426SChris Fallin         BlockIx::new(self.entry)
639d8357426SChris Fallin     }
640d8357426SChris Fallin 
641d8357426SChris Fallin     fn block_insns(&self, block: BlockIx) -> Range<InstIx> {
642d8357426SChris Fallin         let (start, end) = self.block_ranges[block.get() as usize];
643d8357426SChris Fallin         Range::new(InstIx::new(start), (end - start) as usize)
644d8357426SChris Fallin     }
645d8357426SChris Fallin 
646*4f919c64SBenjamin Bouvier     fn block_succs(&self, block: BlockIx) -> Cow<[BlockIx]> {
647d8357426SChris Fallin         let (start, end) = self.block_succ_range[block.get() as usize];
648*4f919c64SBenjamin Bouvier         Cow::Borrowed(&self.block_succs[start..end])
649d8357426SChris Fallin     }
650d8357426SChris Fallin 
651d8357426SChris Fallin     fn is_ret(&self, insn: InstIx) -> bool {
652d8357426SChris Fallin         match self.insts[insn.get() as usize].is_term() {
653d8357426SChris Fallin             MachTerminator::Ret => true,
654d8357426SChris Fallin             _ => false,
655d8357426SChris Fallin         }
656d8357426SChris Fallin     }
657d8357426SChris Fallin 
658d8357426SChris Fallin     fn get_regs(insn: &I, collector: &mut RegUsageCollector) {
659d8357426SChris Fallin         insn.get_regs(collector)
660d8357426SChris Fallin     }
661d8357426SChris Fallin 
662be6f060aSChris Fallin     fn map_regs(insn: &mut I, mapper: &RegUsageMapper) {
663be6f060aSChris Fallin         insn.map_regs(mapper);
664d8357426SChris Fallin     }
665d8357426SChris Fallin 
666d8357426SChris Fallin     fn is_move(&self, insn: &I) -> Option<(Writable<Reg>, Reg)> {
667d8357426SChris Fallin         insn.is_move()
668d8357426SChris Fallin     }
669d8357426SChris Fallin 
670be6f060aSChris Fallin     fn get_vreg_count_estimate(&self) -> Option<usize> {
671be6f060aSChris Fallin         Some(self.vreg_types.len())
672be6f060aSChris Fallin     }
673be6f060aSChris Fallin 
674d8357426SChris Fallin     fn get_spillslot_size(&self, regclass: RegClass, vreg: VirtualReg) -> u32 {
675d8357426SChris Fallin         let ty = self.vreg_type(vreg);
676d8357426SChris Fallin         self.abi.get_spillslot_size(regclass, ty)
677d8357426SChris Fallin     }
678d8357426SChris Fallin 
679d8357426SChris Fallin     fn gen_spill(&self, to_slot: SpillSlot, from_reg: RealReg, vreg: VirtualReg) -> I {
680d8357426SChris Fallin         let ty = self.vreg_type(vreg);
681d8357426SChris Fallin         self.abi.gen_spill(to_slot, from_reg, ty)
682d8357426SChris Fallin     }
683d8357426SChris Fallin 
684d8357426SChris Fallin     fn gen_reload(&self, to_reg: Writable<RealReg>, from_slot: SpillSlot, vreg: VirtualReg) -> I {
685d8357426SChris Fallin         let ty = self.vreg_type(vreg);
686d8357426SChris Fallin         self.abi.gen_reload(to_reg, from_slot, ty)
687d8357426SChris Fallin     }
688d8357426SChris Fallin 
689d8357426SChris Fallin     fn gen_move(&self, to_reg: Writable<RealReg>, from_reg: RealReg, vreg: VirtualReg) -> I {
690d8357426SChris Fallin         let ty = self.vreg_type(vreg);
691d8357426SChris Fallin         I::gen_move(to_reg.map(|r| r.to_reg()), from_reg.to_reg(), ty)
692d8357426SChris Fallin     }
693d8357426SChris Fallin 
694d8357426SChris Fallin     fn gen_zero_len_nop(&self) -> I {
695d8357426SChris Fallin         I::gen_zero_len_nop()
696d8357426SChris Fallin     }
697d8357426SChris Fallin 
698d8357426SChris Fallin     fn maybe_direct_reload(&self, insn: &I, reg: VirtualReg, slot: SpillSlot) -> Option<I> {
699d8357426SChris Fallin         insn.maybe_direct_reload(reg, slot)
700d8357426SChris Fallin     }
701d8357426SChris Fallin 
702d8357426SChris Fallin     fn func_liveins(&self) -> RegallocSet<RealReg> {
703d8357426SChris Fallin         self.liveins.clone()
704d8357426SChris Fallin     }
705d8357426SChris Fallin 
706d8357426SChris Fallin     fn func_liveouts(&self) -> RegallocSet<RealReg> {
707d8357426SChris Fallin         self.liveouts.clone()
708d8357426SChris Fallin     }
709d8357426SChris Fallin }
710d8357426SChris Fallin 
711d8357426SChris Fallin impl<I: VCodeInst> fmt::Debug for VCode<I> {
712d8357426SChris Fallin     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
713d8357426SChris Fallin         writeln!(f, "VCode_Debug {{")?;
714d8357426SChris Fallin         writeln!(f, "  Entry block: {}", self.entry)?;
715d8357426SChris Fallin         writeln!(f, "  Final block order: {:?}", self.final_block_order)?;
716d8357426SChris Fallin 
717d8357426SChris Fallin         for block in 0..self.num_blocks() {
718d8357426SChris Fallin             writeln!(f, "Block {}:", block,)?;
719d8357426SChris Fallin             for succ in self.succs(block as BlockIndex) {
720*4f919c64SBenjamin Bouvier                 writeln!(f, "  (successor: Block {})", succ.get())?;
721d8357426SChris Fallin             }
722d8357426SChris Fallin             let (start, end) = self.block_ranges[block];
723d8357426SChris Fallin             writeln!(f, "  (instruction range: {} .. {})", start, end)?;
724d8357426SChris Fallin             for inst in start..end {
725d8357426SChris Fallin                 writeln!(f, "  Inst {}: {:?}", inst, self.insts[inst as usize])?;
726d8357426SChris Fallin             }
727d8357426SChris Fallin         }
728d8357426SChris Fallin 
729d8357426SChris Fallin         writeln!(f, "}}")?;
730d8357426SChris Fallin         Ok(())
731d8357426SChris Fallin     }
732d8357426SChris Fallin }
733d8357426SChris Fallin 
73448cf2c2fSChris Fallin /// Pretty-printing with `RealRegUniverse` context.
735d8357426SChris Fallin impl<I: VCodeInst + ShowWithRRU> ShowWithRRU for VCode<I> {
736d8357426SChris Fallin     fn show_rru(&self, mb_rru: Option<&RealRegUniverse>) -> String {
737d8357426SChris Fallin         use std::fmt::Write;
738d8357426SChris Fallin 
739d8357426SChris Fallin         // Calculate an order in which to display the blocks.  This is the same
740d8357426SChris Fallin         // as final_block_order, but also includes blocks which are in the
741d8357426SChris Fallin         // representation but not in final_block_order.
742d8357426SChris Fallin         let mut display_order = Vec::<usize>::new();
74348cf2c2fSChris Fallin         // First display blocks in `final_block_order`
744d8357426SChris Fallin         for bix in &self.final_block_order {
745d8357426SChris Fallin             assert!((*bix as usize) < self.num_blocks());
746d8357426SChris Fallin             display_order.push(*bix as usize);
747d8357426SChris Fallin         }
74848cf2c2fSChris Fallin         // Now also take care of those not listed in `final_block_order`.
749d8357426SChris Fallin         // This is quadratic, but it's also debug-only code.
750d8357426SChris Fallin         for bix in 0..self.num_blocks() {
751d8357426SChris Fallin             if display_order.contains(&bix) {
752d8357426SChris Fallin                 continue;
753d8357426SChris Fallin             }
754d8357426SChris Fallin             display_order.push(bix);
755d8357426SChris Fallin         }
756d8357426SChris Fallin 
757d8357426SChris Fallin         let mut s = String::new();
75848cf2c2fSChris Fallin         write!(&mut s, "VCode_ShowWithRRU {{{{\n").unwrap();
75948cf2c2fSChris Fallin         write!(&mut s, "  Entry block: {}\n", self.entry).unwrap();
76048cf2c2fSChris Fallin         write!(
76148cf2c2fSChris Fallin             &mut s,
76248cf2c2fSChris Fallin             "  Final block order: {:?}\n",
76348cf2c2fSChris Fallin             self.final_block_order
76448cf2c2fSChris Fallin         )
76548cf2c2fSChris Fallin         .unwrap();
766d8357426SChris Fallin 
767d8357426SChris Fallin         for i in 0..self.num_blocks() {
768d8357426SChris Fallin             let block = display_order[i];
769d8357426SChris Fallin 
77048cf2c2fSChris Fallin             let omitted = if !self.final_block_order.is_empty() && i >= self.final_block_order.len()
77148cf2c2fSChris Fallin             {
772d8357426SChris Fallin                 "** OMITTED **"
773d8357426SChris Fallin             } else {
774d8357426SChris Fallin                 ""
77548cf2c2fSChris Fallin             };
776d8357426SChris Fallin 
77748cf2c2fSChris Fallin             write!(&mut s, "Block {}: {}\n", block, omitted).unwrap();
778d8357426SChris Fallin             if let Some(bb) = self.bindex_to_bb(block as BlockIndex) {
77948cf2c2fSChris Fallin                 write!(&mut s, "  (original IR block: {})\n", bb).unwrap();
780d8357426SChris Fallin             }
781d8357426SChris Fallin             for succ in self.succs(block as BlockIndex) {
782*4f919c64SBenjamin Bouvier                 write!(&mut s, "  (successor: Block {})\n", succ.get()).unwrap();
783d8357426SChris Fallin             }
784d8357426SChris Fallin             let (start, end) = self.block_ranges[block];
78548cf2c2fSChris Fallin             write!(&mut s, "  (instruction range: {} .. {})\n", start, end).unwrap();
786d8357426SChris Fallin             for inst in start..end {
78748cf2c2fSChris Fallin                 write!(
78848cf2c2fSChris Fallin                     &mut s,
78948cf2c2fSChris Fallin                     "  Inst {}:   {}\n",
790d8357426SChris Fallin                     inst,
791d8357426SChris Fallin                     self.insts[inst as usize].show_rru(mb_rru)
79248cf2c2fSChris Fallin                 )
79348cf2c2fSChris Fallin                 .unwrap();
794d8357426SChris Fallin             }
795d8357426SChris Fallin         }
796d8357426SChris Fallin 
79748cf2c2fSChris Fallin         write!(&mut s, "}}}}\n").unwrap();
798d8357426SChris Fallin 
799d8357426SChris Fallin         s
800d8357426SChris Fallin     }
801d8357426SChris Fallin }
802