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 2072e6be93SChris Fallin use crate::ir::{self, SourceLoc}; 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; 26be6f060aSChris Fallin use regalloc::{ 27be6f060aSChris Fallin BlockIx, InstIx, Range, RegAllocResult, RegClass, RegUsageCollector, RegUsageMapper, 28be6f060aSChris Fallin }; 29d8357426SChris Fallin 30d8357426SChris Fallin use alloc::boxed::Box; 314f919c64SBenjamin Bouvier use alloc::{borrow::Cow, vec::Vec}; 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`. 4372e6be93SChris Fallin pub trait VCodeInst: MachInst + MachInstEmit {} 4472e6be93SChris Fallin impl<I: MachInst + MachInstEmit> 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 62b691770fSChris Fallin /// Source locations for each instruction. (`SourceLoc` is a `u32`, so it is 63b691770fSChris Fallin /// reasonable to keep one of these per instruction.) 64b691770fSChris Fallin srclocs: Vec<SourceLoc>, 65b691770fSChris Fallin 66d8357426SChris Fallin /// Entry block. 67d8357426SChris Fallin entry: BlockIndex, 68d8357426SChris Fallin 69d8357426SChris Fallin /// Block instruction indices. 7048cf2c2fSChris Fallin block_ranges: Vec<(InsnIndex, InsnIndex)>, 71d8357426SChris Fallin 72d8357426SChris Fallin /// Block successors: index range in the successor-list below. 73d8357426SChris Fallin block_succ_range: Vec<(usize, usize)>, 74d8357426SChris Fallin 75d8357426SChris Fallin /// Block successor lists, concatenated into one Vec. The `block_succ_range` 76d8357426SChris Fallin /// list of tuples above gives (start, end) ranges within this list that 77d8357426SChris Fallin /// correspond to each basic block's successors. 784f919c64SBenjamin Bouvier block_succs: Vec<BlockIx>, 79d8357426SChris Fallin 8072e6be93SChris Fallin /// Block-order information. 8172e6be93SChris Fallin block_order: BlockLoweringOrder, 82d8357426SChris Fallin 83d8357426SChris Fallin /// ABI object. 8448cf2c2fSChris Fallin abi: Box<dyn ABIBody<I = I>>, 85d8357426SChris Fallin } 86d8357426SChris Fallin 87d8357426SChris Fallin /// A builder for a VCode function body. This builder is designed for the 88d8357426SChris Fallin /// lowering approach that we take: we traverse basic blocks in forward 89d8357426SChris Fallin /// (original IR) order, but within each basic block, we generate code from 90d8357426SChris Fallin /// bottom to top; and within each IR instruction that we visit in this reverse 91d8357426SChris Fallin /// order, we emit machine instructions in *forward* order again. 92d8357426SChris Fallin /// 93d8357426SChris Fallin /// Hence, to produce the final instructions in proper order, we perform two 94d8357426SChris Fallin /// swaps. First, the machine instructions (`I` instances) are produced in 95d8357426SChris Fallin /// forward order for an individual IR instruction. Then these are *reversed* 96d8357426SChris Fallin /// and concatenated to `bb_insns` at the end of the IR instruction lowering. 97d8357426SChris Fallin /// The `bb_insns` vec will thus contain all machine instructions for a basic 98d8357426SChris Fallin /// block, in reverse order. Finally, when we're done with a basic block, we 99d8357426SChris Fallin /// reverse the whole block's vec of instructions again, and concatenate onto 100d8357426SChris Fallin /// the VCode's insts. 101d8357426SChris Fallin pub struct VCodeBuilder<I: VCodeInst> { 102d8357426SChris Fallin /// In-progress VCode. 103d8357426SChris Fallin vcode: VCode<I>, 104d8357426SChris Fallin 10572e6be93SChris Fallin /// Index of the last block-start in the vcode. 10672e6be93SChris Fallin block_start: InsnIndex, 107d8357426SChris Fallin 108d8357426SChris Fallin /// Start of succs for the current block in the concatenated succs list. 109d8357426SChris Fallin succ_start: usize, 110b691770fSChris Fallin 111b691770fSChris Fallin /// Current source location. 112b691770fSChris Fallin cur_srcloc: SourceLoc, 113d8357426SChris Fallin } 114d8357426SChris Fallin 115d8357426SChris Fallin impl<I: VCodeInst> VCodeBuilder<I> { 116d8357426SChris Fallin /// Create a new VCodeBuilder. 11772e6be93SChris Fallin pub fn new(abi: Box<dyn ABIBody<I = I>>, block_order: BlockLoweringOrder) -> VCodeBuilder<I> { 11872e6be93SChris Fallin let vcode = VCode::new(abi, block_order); 119d8357426SChris Fallin VCodeBuilder { 120d8357426SChris Fallin vcode, 12172e6be93SChris Fallin block_start: 0, 122d8357426SChris Fallin succ_start: 0, 123b691770fSChris Fallin cur_srcloc: SourceLoc::default(), 124d8357426SChris Fallin } 125d8357426SChris Fallin } 126d8357426SChris Fallin 127d8357426SChris Fallin /// Access the ABI object. 12848cf2c2fSChris Fallin pub fn abi(&mut self) -> &mut dyn ABIBody<I = I> { 129d8357426SChris Fallin &mut *self.vcode.abi 130d8357426SChris Fallin } 131d8357426SChris Fallin 13272e6be93SChris Fallin /// Access to the BlockLoweringOrder object. 13372e6be93SChris Fallin pub fn block_order(&self) -> &BlockLoweringOrder { 13472e6be93SChris Fallin &self.vcode.block_order 1351d90751bSBenjamin Bouvier } 1361d90751bSBenjamin Bouvier 137d8357426SChris Fallin /// Set the type of a VReg. 138d8357426SChris Fallin pub fn set_vreg_type(&mut self, vreg: VirtualReg, ty: Type) { 139d8357426SChris Fallin while self.vcode.vreg_types.len() <= vreg.get_index() { 140d8357426SChris Fallin self.vcode.vreg_types.push(ir::types::I8); // Default type. 141d8357426SChris Fallin } 142d8357426SChris Fallin self.vcode.vreg_types[vreg.get_index()] = ty; 143d8357426SChris Fallin } 144d8357426SChris Fallin 145d8357426SChris Fallin /// Set the current block as the entry block. 146d8357426SChris Fallin pub fn set_entry(&mut self, block: BlockIndex) { 147d8357426SChris Fallin self.vcode.entry = block; 148d8357426SChris Fallin } 149d8357426SChris Fallin 150d8357426SChris Fallin /// End the current basic block. Must be called after emitting vcode insts 151d8357426SChris Fallin /// for IR insts and prior to ending the function (building the VCode). 15272e6be93SChris Fallin pub fn end_bb(&mut self) { 15372e6be93SChris Fallin let start_idx = self.block_start; 154d8357426SChris Fallin let end_idx = self.vcode.insts.len() as InsnIndex; 15572e6be93SChris Fallin self.block_start = end_idx; 156d8357426SChris Fallin // Add the instruction index range to the list of blocks. 157d8357426SChris Fallin self.vcode.block_ranges.push((start_idx, end_idx)); 158d8357426SChris Fallin // End the successors list. 159d8357426SChris Fallin let succ_end = self.vcode.block_succs.len(); 160d8357426SChris Fallin self.vcode 161d8357426SChris Fallin .block_succ_range 162d8357426SChris Fallin .push((self.succ_start, succ_end)); 163d8357426SChris Fallin self.succ_start = succ_end; 164d8357426SChris Fallin } 165d8357426SChris Fallin 166d8357426SChris Fallin /// Push an instruction for the current BB and current IR inst within the BB. 167d8357426SChris Fallin pub fn push(&mut self, insn: I) { 168d8357426SChris Fallin match insn.is_term() { 169d8357426SChris Fallin MachTerminator::None | MachTerminator::Ret => {} 170d8357426SChris Fallin MachTerminator::Uncond(target) => { 17172e6be93SChris Fallin self.vcode.block_succs.push(BlockIx::new(target.get())); 172d8357426SChris Fallin } 173d8357426SChris Fallin MachTerminator::Cond(true_branch, false_branch) => { 17472e6be93SChris Fallin self.vcode.block_succs.push(BlockIx::new(true_branch.get())); 17572e6be93SChris Fallin self.vcode 17672e6be93SChris Fallin .block_succs 17772e6be93SChris Fallin .push(BlockIx::new(false_branch.get())); 178d8357426SChris Fallin } 179d8357426SChris Fallin MachTerminator::Indirect(targets) => { 180d8357426SChris Fallin for target in targets { 18172e6be93SChris Fallin self.vcode.block_succs.push(BlockIx::new(target.get())); 182d8357426SChris Fallin } 183d8357426SChris Fallin } 184d8357426SChris Fallin } 18572e6be93SChris Fallin self.vcode.insts.push(insn); 18672e6be93SChris Fallin self.vcode.srclocs.push(self.cur_srcloc); 18772e6be93SChris Fallin } 18872e6be93SChris Fallin 18972e6be93SChris Fallin /// Get the current source location. 19072e6be93SChris Fallin pub fn get_srcloc(&self) -> SourceLoc { 19172e6be93SChris Fallin self.cur_srcloc 192b691770fSChris Fallin } 193b691770fSChris Fallin 194b691770fSChris Fallin /// Set the current source location. 195b691770fSChris Fallin pub fn set_srcloc(&mut self, srcloc: SourceLoc) { 196b691770fSChris Fallin self.cur_srcloc = srcloc; 197d8357426SChris Fallin } 198d8357426SChris Fallin 199d8357426SChris Fallin /// Build the final VCode. 200d8357426SChris Fallin pub fn build(self) -> VCode<I> { 201d8357426SChris Fallin self.vcode 202d8357426SChris Fallin } 203d8357426SChris Fallin } 204d8357426SChris Fallin 205d8357426SChris Fallin fn block_ranges(indices: &[InstIx], len: usize) -> Vec<(usize, usize)> { 206d8357426SChris Fallin let v = indices 207d8357426SChris Fallin .iter() 208d8357426SChris Fallin .map(|iix| iix.get() as usize) 209d8357426SChris Fallin .chain(iter::once(len)) 210d8357426SChris Fallin .collect::<Vec<usize>>(); 211d8357426SChris Fallin v.windows(2).map(|p| (p[0], p[1])).collect() 212d8357426SChris Fallin } 213d8357426SChris Fallin 214d8357426SChris Fallin fn is_redundant_move<I: VCodeInst>(insn: &I) -> bool { 215d8357426SChris Fallin if let Some((to, from)) = insn.is_move() { 216d8357426SChris Fallin to.to_reg() == from 217d8357426SChris Fallin } else { 218d8357426SChris Fallin false 219d8357426SChris Fallin } 220d8357426SChris Fallin } 221d8357426SChris Fallin 222d8357426SChris Fallin impl<I: VCodeInst> VCode<I> { 223d8357426SChris Fallin /// New empty VCode. 22472e6be93SChris Fallin fn new(abi: Box<dyn ABIBody<I = I>>, block_order: BlockLoweringOrder) -> VCode<I> { 225d8357426SChris Fallin VCode { 226d8357426SChris Fallin liveins: abi.liveins(), 227d8357426SChris Fallin liveouts: abi.liveouts(), 228d8357426SChris Fallin vreg_types: vec![], 229d8357426SChris Fallin insts: vec![], 230b691770fSChris Fallin srclocs: vec![], 231d8357426SChris Fallin entry: 0, 232d8357426SChris Fallin block_ranges: vec![], 233d8357426SChris Fallin block_succ_range: vec![], 234d8357426SChris Fallin block_succs: vec![], 23572e6be93SChris Fallin block_order, 236d8357426SChris Fallin abi, 237d8357426SChris Fallin } 238d8357426SChris Fallin } 239d8357426SChris Fallin 240d1b5df31SBenjamin Bouvier /// Returns the flags controlling this function's compilation. 241d1b5df31SBenjamin Bouvier pub fn flags(&self) -> &settings::Flags { 242d1b5df31SBenjamin Bouvier self.abi.flags() 243d1b5df31SBenjamin Bouvier } 244d1b5df31SBenjamin Bouvier 245d8357426SChris Fallin /// Get the IR-level type of a VReg. 246d8357426SChris Fallin pub fn vreg_type(&self, vreg: VirtualReg) -> Type { 247d8357426SChris Fallin self.vreg_types[vreg.get_index()] 248d8357426SChris Fallin } 249d8357426SChris Fallin 250d8357426SChris Fallin /// Get the entry block. 251d8357426SChris Fallin pub fn entry(&self) -> BlockIndex { 252d8357426SChris Fallin self.entry 253d8357426SChris Fallin } 254d8357426SChris Fallin 255d8357426SChris Fallin /// Get the number of blocks. Block indices will be in the range `0 .. 256d8357426SChris Fallin /// (self.num_blocks() - 1)`. 257d8357426SChris Fallin pub fn num_blocks(&self) -> usize { 258d8357426SChris Fallin self.block_ranges.len() 259d8357426SChris Fallin } 260d8357426SChris Fallin 261d8357426SChris Fallin /// Stack frame size for the full function's body. 262d8357426SChris Fallin pub fn frame_size(&self) -> u32 { 263d8357426SChris Fallin self.abi.frame_size() 264d8357426SChris Fallin } 265d8357426SChris Fallin 266d8357426SChris Fallin /// Get the successors for a block. 2674f919c64SBenjamin Bouvier pub fn succs(&self, block: BlockIndex) -> &[BlockIx] { 268d8357426SChris Fallin let (start, end) = self.block_succ_range[block as usize]; 269d8357426SChris Fallin &self.block_succs[start..end] 270d8357426SChris Fallin } 271d8357426SChris Fallin 272d8357426SChris Fallin /// Take the results of register allocation, with a sequence of 273d8357426SChris Fallin /// instructions including spliced fill/reload/move instructions, and replace 274d8357426SChris Fallin /// the VCode with them. 275d1b5df31SBenjamin Bouvier pub fn replace_insns_from_regalloc(&mut self, result: RegAllocResult<Self>) { 276d8357426SChris Fallin // Record the spillslot count and clobbered registers for the ABI/stack 277d8357426SChris Fallin // setup code. 278d8357426SChris Fallin self.abi.set_num_spillslots(result.num_spill_slots as usize); 279d8357426SChris Fallin self.abi 280d8357426SChris Fallin .set_clobbered(result.clobbered_registers.map(|r| Writable::from_reg(*r))); 281d8357426SChris Fallin 282d8357426SChris Fallin // We want to move instructions over in final block order, using the new 283d8357426SChris Fallin // block-start map given by the regalloc. 284d8357426SChris Fallin let block_ranges: Vec<(usize, usize)> = 285d8357426SChris Fallin block_ranges(result.target_map.elems(), result.insns.len()); 286d8357426SChris Fallin let mut final_insns = vec![]; 287d8357426SChris Fallin let mut final_block_ranges = vec![(0, 0); self.num_blocks()]; 288b691770fSChris Fallin let mut final_srclocs = vec![]; 289d8357426SChris Fallin 29072e6be93SChris Fallin for block in 0..self.num_blocks() { 29172e6be93SChris Fallin let block = block as BlockIndex; 29272e6be93SChris Fallin let (start, end) = block_ranges[block as usize]; 293d8357426SChris Fallin let final_start = final_insns.len() as InsnIndex; 294d8357426SChris Fallin 29572e6be93SChris Fallin if block == self.entry { 296d8357426SChris Fallin // Start with the prologue. 297b691770fSChris Fallin let prologue = self.abi.gen_prologue(); 298b691770fSChris Fallin let len = prologue.len(); 299b691770fSChris Fallin final_insns.extend(prologue.into_iter()); 300b691770fSChris Fallin final_srclocs.extend(iter::repeat(SourceLoc::default()).take(len)); 301d8357426SChris Fallin } 302d8357426SChris Fallin 303d8357426SChris Fallin for i in start..end { 304d8357426SChris Fallin let insn = &result.insns[i]; 305d8357426SChris Fallin 306d8357426SChris Fallin // Elide redundant moves at this point (we only know what is 307d8357426SChris Fallin // redundant once registers are allocated). 308d8357426SChris Fallin if is_redundant_move(insn) { 309d8357426SChris Fallin continue; 310d8357426SChris Fallin } 311d8357426SChris Fallin 312b691770fSChris Fallin // Is there a srcloc associated with this insn? Look it up based on original 313b691770fSChris Fallin // instruction index (if new insn corresponds to some original insn, i.e., is not 314b691770fSChris Fallin // an inserted load/spill/move). 315b691770fSChris Fallin let orig_iix = result.orig_insn_map[InstIx::new(i as u32)]; 316b691770fSChris Fallin let srcloc = if orig_iix.is_invalid() { 317b691770fSChris Fallin SourceLoc::default() 318b691770fSChris Fallin } else { 319b691770fSChris Fallin self.srclocs[orig_iix.get() as usize] 320b691770fSChris Fallin }; 321b691770fSChris Fallin 322d8357426SChris Fallin // Whenever encountering a return instruction, replace it 323d8357426SChris Fallin // with the epilogue. 324d8357426SChris Fallin let is_ret = insn.is_term() == MachTerminator::Ret; 325d8357426SChris Fallin if is_ret { 326b691770fSChris Fallin let epilogue = self.abi.gen_epilogue(); 327b691770fSChris Fallin let len = epilogue.len(); 328b691770fSChris Fallin final_insns.extend(epilogue.into_iter()); 329b691770fSChris Fallin final_srclocs.extend(iter::repeat(srcloc).take(len)); 330d8357426SChris Fallin } else { 331d8357426SChris Fallin final_insns.push(insn.clone()); 332b691770fSChris Fallin final_srclocs.push(srcloc); 333d8357426SChris Fallin } 334d8357426SChris Fallin } 335d8357426SChris Fallin 336d8357426SChris Fallin let final_end = final_insns.len() as InsnIndex; 33772e6be93SChris Fallin final_block_ranges[block as usize] = (final_start, final_end); 338d8357426SChris Fallin } 339d8357426SChris Fallin 340b691770fSChris Fallin debug_assert!(final_insns.len() == final_srclocs.len()); 341b691770fSChris Fallin 342d8357426SChris Fallin self.insts = final_insns; 343b691770fSChris Fallin self.srclocs = final_srclocs; 344d8357426SChris Fallin self.block_ranges = final_block_ranges; 345d8357426SChris Fallin } 346d8357426SChris Fallin 34772e6be93SChris Fallin /// Emit the instructions to a `MachBuffer`, containing fixed-up code and external 34872e6be93SChris Fallin /// reloc/trap/etc. records ready for use. 34972e6be93SChris Fallin pub fn emit(&self) -> MachBuffer<I> 350d8357426SChris Fallin where 35172e6be93SChris Fallin I: MachInstEmit, 352d8357426SChris Fallin { 35372e6be93SChris Fallin let mut buffer = MachBuffer::new(); 354a66724aaSChris Fallin let mut state = Default::default(); 355d8357426SChris Fallin 35672e6be93SChris Fallin buffer.reserve_labels_for_blocks(self.num_blocks() as BlockIndex); // first N MachLabels are simply block indices. 357d8357426SChris Fallin 358a7ca37e4SBenjamin Bouvier let flags = self.abi.flags(); 359964c6087SChris Fallin let mut cur_srcloc = None; 36072e6be93SChris Fallin for block in 0..self.num_blocks() { 36172e6be93SChris Fallin let block = block as BlockIndex; 36272e6be93SChris Fallin let new_offset = I::align_basic_block(buffer.cur_offset()); 36372e6be93SChris Fallin while new_offset > buffer.cur_offset() { 364d8357426SChris Fallin // Pad with NOPs up to the aligned block offset. 36572e6be93SChris Fallin let nop = I::gen_nop((new_offset - buffer.cur_offset()) as usize); 36672e6be93SChris Fallin nop.emit(&mut buffer, flags, &mut Default::default()); 367d8357426SChris Fallin } 36872e6be93SChris Fallin assert_eq!(buffer.cur_offset(), new_offset); 369d8357426SChris Fallin 37048cf2c2fSChris Fallin let (start, end) = self.block_ranges[block as usize]; 37172e6be93SChris Fallin buffer.bind_label(MachLabel::from_block(block)); 372d8357426SChris Fallin for iix in start..end { 373b691770fSChris Fallin let srcloc = self.srclocs[iix as usize]; 374964c6087SChris Fallin if cur_srcloc != Some(srcloc) { 375964c6087SChris Fallin if cur_srcloc.is_some() { 37672e6be93SChris Fallin buffer.end_srcloc(); 377b691770fSChris Fallin } 37872e6be93SChris Fallin buffer.start_srcloc(srcloc); 379964c6087SChris Fallin cur_srcloc = Some(srcloc); 380b691770fSChris Fallin } 381b691770fSChris Fallin 38272e6be93SChris Fallin self.insts[iix as usize].emit(&mut buffer, flags, &mut state); 383d8357426SChris Fallin } 384b691770fSChris Fallin 385964c6087SChris Fallin if cur_srcloc.is_some() { 38672e6be93SChris Fallin buffer.end_srcloc(); 387964c6087SChris Fallin cur_srcloc = None; 388b691770fSChris Fallin } 38972e6be93SChris Fallin 39072e6be93SChris Fallin // Do we need an island? Get the worst-case size of the next BB and see if, having 39172e6be93SChris Fallin // emitted that many bytes, we will be beyond the deadline. 39272e6be93SChris Fallin if block < (self.num_blocks() - 1) as BlockIndex { 39372e6be93SChris Fallin let next_block = block + 1; 39472e6be93SChris Fallin let next_block_range = self.block_ranges[next_block as usize]; 39572e6be93SChris Fallin let next_block_size = next_block_range.1 - next_block_range.0; 39672e6be93SChris Fallin let worst_case_next_bb = I::worst_case_size() * next_block_size; 39772e6be93SChris Fallin if buffer.island_needed(worst_case_next_bb) { 39872e6be93SChris Fallin buffer.emit_island(); 39972e6be93SChris Fallin } 40072e6be93SChris Fallin } 401d8357426SChris Fallin } 402d8357426SChris Fallin 40372e6be93SChris Fallin buffer 404d8357426SChris Fallin } 405d8357426SChris Fallin 406d8357426SChris Fallin /// Get the IR block for a BlockIndex, if one exists. 407d8357426SChris Fallin pub fn bindex_to_bb(&self, block: BlockIndex) -> Option<ir::Block> { 40872e6be93SChris Fallin self.block_order.lowered_order()[block as usize].orig_block() 409d8357426SChris Fallin } 410d8357426SChris Fallin } 411d8357426SChris Fallin 412d8357426SChris Fallin impl<I: VCodeInst> RegallocFunction for VCode<I> { 413d8357426SChris Fallin type Inst = I; 414d8357426SChris Fallin 415d8357426SChris Fallin fn insns(&self) -> &[I] { 416d8357426SChris Fallin &self.insts[..] 417d8357426SChris Fallin } 418d8357426SChris Fallin 419d8357426SChris Fallin fn insns_mut(&mut self) -> &mut [I] { 420d8357426SChris Fallin &mut self.insts[..] 421d8357426SChris Fallin } 422d8357426SChris Fallin 423d8357426SChris Fallin fn get_insn(&self, insn: InstIx) -> &I { 424d8357426SChris Fallin &self.insts[insn.get() as usize] 425d8357426SChris Fallin } 426d8357426SChris Fallin 427d8357426SChris Fallin fn get_insn_mut(&mut self, insn: InstIx) -> &mut I { 428d8357426SChris Fallin &mut self.insts[insn.get() as usize] 429d8357426SChris Fallin } 430d8357426SChris Fallin 431d8357426SChris Fallin fn blocks(&self) -> Range<BlockIx> { 432d8357426SChris Fallin Range::new(BlockIx::new(0), self.block_ranges.len()) 433d8357426SChris Fallin } 434d8357426SChris Fallin 435d8357426SChris Fallin fn entry_block(&self) -> BlockIx { 436d8357426SChris Fallin BlockIx::new(self.entry) 437d8357426SChris Fallin } 438d8357426SChris Fallin 439d8357426SChris Fallin fn block_insns(&self, block: BlockIx) -> Range<InstIx> { 440d8357426SChris Fallin let (start, end) = self.block_ranges[block.get() as usize]; 441d8357426SChris Fallin Range::new(InstIx::new(start), (end - start) as usize) 442d8357426SChris Fallin } 443d8357426SChris Fallin 4444f919c64SBenjamin Bouvier fn block_succs(&self, block: BlockIx) -> Cow<[BlockIx]> { 445d8357426SChris Fallin let (start, end) = self.block_succ_range[block.get() as usize]; 4464f919c64SBenjamin Bouvier Cow::Borrowed(&self.block_succs[start..end]) 447d8357426SChris Fallin } 448d8357426SChris Fallin 449d8357426SChris Fallin fn is_ret(&self, insn: InstIx) -> bool { 450d8357426SChris Fallin match self.insts[insn.get() as usize].is_term() { 451d8357426SChris Fallin MachTerminator::Ret => true, 452d8357426SChris Fallin _ => false, 453d8357426SChris Fallin } 454d8357426SChris Fallin } 455d8357426SChris Fallin 456d8357426SChris Fallin fn get_regs(insn: &I, collector: &mut RegUsageCollector) { 457d8357426SChris Fallin insn.get_regs(collector) 458d8357426SChris Fallin } 459d8357426SChris Fallin 460*1f620e1bSBenjamin Bouvier fn map_regs<RUM: RegUsageMapper>(insn: &mut I, mapper: &RUM) { 461be6f060aSChris Fallin insn.map_regs(mapper); 462d8357426SChris Fallin } 463d8357426SChris Fallin 464d8357426SChris Fallin fn is_move(&self, insn: &I) -> Option<(Writable<Reg>, Reg)> { 465d8357426SChris Fallin insn.is_move() 466d8357426SChris Fallin } 467d8357426SChris Fallin 468be6f060aSChris Fallin fn get_vreg_count_estimate(&self) -> Option<usize> { 469be6f060aSChris Fallin Some(self.vreg_types.len()) 470be6f060aSChris Fallin } 471be6f060aSChris Fallin 472d8357426SChris Fallin fn get_spillslot_size(&self, regclass: RegClass, vreg: VirtualReg) -> u32 { 473d8357426SChris Fallin let ty = self.vreg_type(vreg); 474d8357426SChris Fallin self.abi.get_spillslot_size(regclass, ty) 475d8357426SChris Fallin } 476d8357426SChris Fallin 477d8357426SChris Fallin fn gen_spill(&self, to_slot: SpillSlot, from_reg: RealReg, vreg: VirtualReg) -> I { 478d8357426SChris Fallin let ty = self.vreg_type(vreg); 479d8357426SChris Fallin self.abi.gen_spill(to_slot, from_reg, ty) 480d8357426SChris Fallin } 481d8357426SChris Fallin 482d8357426SChris Fallin fn gen_reload(&self, to_reg: Writable<RealReg>, from_slot: SpillSlot, vreg: VirtualReg) -> I { 483d8357426SChris Fallin let ty = self.vreg_type(vreg); 484d8357426SChris Fallin self.abi.gen_reload(to_reg, from_slot, ty) 485d8357426SChris Fallin } 486d8357426SChris Fallin 487d8357426SChris Fallin fn gen_move(&self, to_reg: Writable<RealReg>, from_reg: RealReg, vreg: VirtualReg) -> I { 488d8357426SChris Fallin let ty = self.vreg_type(vreg); 489d8357426SChris Fallin I::gen_move(to_reg.map(|r| r.to_reg()), from_reg.to_reg(), ty) 490d8357426SChris Fallin } 491d8357426SChris Fallin 492d8357426SChris Fallin fn gen_zero_len_nop(&self) -> I { 493d8357426SChris Fallin I::gen_zero_len_nop() 494d8357426SChris Fallin } 495d8357426SChris Fallin 496d8357426SChris Fallin fn maybe_direct_reload(&self, insn: &I, reg: VirtualReg, slot: SpillSlot) -> Option<I> { 497d8357426SChris Fallin insn.maybe_direct_reload(reg, slot) 498d8357426SChris Fallin } 499d8357426SChris Fallin 500d8357426SChris Fallin fn func_liveins(&self) -> RegallocSet<RealReg> { 501d8357426SChris Fallin self.liveins.clone() 502d8357426SChris Fallin } 503d8357426SChris Fallin 504d8357426SChris Fallin fn func_liveouts(&self) -> RegallocSet<RealReg> { 505d8357426SChris Fallin self.liveouts.clone() 506d8357426SChris Fallin } 507d8357426SChris Fallin } 508d8357426SChris Fallin 509d8357426SChris Fallin impl<I: VCodeInst> fmt::Debug for VCode<I> { 510d8357426SChris Fallin fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 511d8357426SChris Fallin writeln!(f, "VCode_Debug {{")?; 512d8357426SChris Fallin writeln!(f, " Entry block: {}", self.entry)?; 513d8357426SChris Fallin 514d8357426SChris Fallin for block in 0..self.num_blocks() { 515d8357426SChris Fallin writeln!(f, "Block {}:", block,)?; 516d8357426SChris Fallin for succ in self.succs(block as BlockIndex) { 5174f919c64SBenjamin Bouvier writeln!(f, " (successor: Block {})", succ.get())?; 518d8357426SChris Fallin } 519d8357426SChris Fallin let (start, end) = self.block_ranges[block]; 520d8357426SChris Fallin writeln!(f, " (instruction range: {} .. {})", start, end)?; 521d8357426SChris Fallin for inst in start..end { 522d8357426SChris Fallin writeln!(f, " Inst {}: {:?}", inst, self.insts[inst as usize])?; 523d8357426SChris Fallin } 524d8357426SChris Fallin } 525d8357426SChris Fallin 526d8357426SChris Fallin writeln!(f, "}}")?; 527d8357426SChris Fallin Ok(()) 528d8357426SChris Fallin } 529d8357426SChris Fallin } 530d8357426SChris Fallin 53148cf2c2fSChris Fallin /// Pretty-printing with `RealRegUniverse` context. 532d8357426SChris Fallin impl<I: VCodeInst + ShowWithRRU> ShowWithRRU for VCode<I> { 533d8357426SChris Fallin fn show_rru(&self, mb_rru: Option<&RealRegUniverse>) -> String { 534d8357426SChris Fallin use std::fmt::Write; 535d8357426SChris Fallin 536d8357426SChris Fallin let mut s = String::new(); 53748cf2c2fSChris Fallin write!(&mut s, "VCode_ShowWithRRU {{{{\n").unwrap(); 53848cf2c2fSChris Fallin write!(&mut s, " Entry block: {}\n", self.entry).unwrap(); 539d8357426SChris Fallin 540d8357426SChris Fallin for i in 0..self.num_blocks() { 54172e6be93SChris Fallin let block = i as BlockIndex; 542d8357426SChris Fallin 54372e6be93SChris Fallin write!(&mut s, "Block {}:\n", block).unwrap(); 54472e6be93SChris Fallin if let Some(bb) = self.bindex_to_bb(block) { 54548cf2c2fSChris Fallin write!(&mut s, " (original IR block: {})\n", bb).unwrap(); 546d8357426SChris Fallin } 54772e6be93SChris Fallin for succ in self.succs(block) { 5484f919c64SBenjamin Bouvier write!(&mut s, " (successor: Block {})\n", succ.get()).unwrap(); 549d8357426SChris Fallin } 55072e6be93SChris Fallin let (start, end) = self.block_ranges[block as usize]; 55148cf2c2fSChris Fallin write!(&mut s, " (instruction range: {} .. {})\n", start, end).unwrap(); 552d8357426SChris Fallin for inst in start..end { 55348cf2c2fSChris Fallin write!( 55448cf2c2fSChris Fallin &mut s, 55548cf2c2fSChris Fallin " Inst {}: {}\n", 556d8357426SChris Fallin inst, 557d8357426SChris Fallin self.insts[inst as usize].show_rru(mb_rru) 55848cf2c2fSChris Fallin ) 55948cf2c2fSChris Fallin .unwrap(); 560d8357426SChris Fallin } 561d8357426SChris Fallin } 562d8357426SChris Fallin 56348cf2c2fSChris Fallin write!(&mut s, "}}}}\n").unwrap(); 564d8357426SChris Fallin 565d8357426SChris Fallin s 566d8357426SChris Fallin } 567d8357426SChris Fallin } 568