1968952abSNick Fitzgerald //! Function inlining infrastructure. 2968952abSNick Fitzgerald //! 3968952abSNick Fitzgerald //! This module provides "inlining as a library" to Cranelift users; it does 4968952abSNick Fitzgerald //! _not_ provide a complete, off-the-shelf inlining solution. Cranelift's 5968952abSNick Fitzgerald //! compilation context is per-function and does not encompass the full call 6968952abSNick Fitzgerald //! graph. It does not know which functions are hot and which are cold, which 7968952abSNick Fitzgerald //! have been marked the equivalent of `#[inline(never)]`, etc... Only the 8968952abSNick Fitzgerald //! Cranelift user can understand these aspects of the full compilation 9968952abSNick Fitzgerald //! pipeline, and these things can be very different between (say) Wasmtime and 10968952abSNick Fitzgerald //! `cg_clif`. Therefore, this module does not attempt to define hueristics for 11968952abSNick Fitzgerald //! when inlining a particular call is likely beneficial. This module only 12968952abSNick Fitzgerald //! provides hooks for the Cranelift user to define whether a given call should 13968952abSNick Fitzgerald //! be inlined or not, and the mechanics to inline a callee into a particular 14968952abSNick Fitzgerald //! call site when directed to do so by the Cranelift user. 15968952abSNick Fitzgerald //! 16968952abSNick Fitzgerald //! The top-level inlining entry point during Cranelift compilation is 17968952abSNick Fitzgerald //! [`Context::inline`][crate::Context::inline]. It takes an [`Inline`] trait 18968952abSNick Fitzgerald //! implementation, which is authored by the Cranelift user and directs 19968952abSNick Fitzgerald //! Cranelift whether to inline a particular call, and, when inlining, gives 20968952abSNick Fitzgerald //! Cranelift the body of the callee that is to be inlined. 21968952abSNick Fitzgerald 22968952abSNick Fitzgerald use crate::cursor::{Cursor as _, FuncCursor}; 234590076fSChris Fallin use crate::ir::{self, ExceptionTableData, ExceptionTableItem, InstBuilder as _}; 24968952abSNick Fitzgerald use crate::result::CodegenResult; 25968952abSNick Fitzgerald use crate::trace; 26968952abSNick Fitzgerald use crate::traversals::Dfs; 27968952abSNick Fitzgerald use alloc::borrow::Cow; 28968952abSNick Fitzgerald use alloc::vec::Vec; 29968952abSNick Fitzgerald use cranelift_entity::{SecondaryMap, packed_option::PackedOption}; 30968952abSNick Fitzgerald use smallvec::SmallVec; 31968952abSNick Fitzgerald 32968952abSNick Fitzgerald type SmallValueVec = SmallVec<[ir::Value; 8]>; 33968952abSNick Fitzgerald type SmallBlockArgVec = SmallVec<[ir::BlockArg; 8]>; 34968952abSNick Fitzgerald type SmallBlockCallVec = SmallVec<[ir::BlockCall; 8]>; 35968952abSNick Fitzgerald 36968952abSNick Fitzgerald /// A command directing Cranelift whether or not to inline a particular call. 37968952abSNick Fitzgerald pub enum InlineCommand<'a> { 38968952abSNick Fitzgerald /// Keep the call as-is, out-of-line, and do not inline the callee. 39968952abSNick Fitzgerald KeepCall, 40*dcedcbf5SNick Fitzgerald 41968952abSNick Fitzgerald /// Inline the call, using this function as the body of the callee. 42968952abSNick Fitzgerald /// 43968952abSNick Fitzgerald /// It is the `Inline` implementor's responsibility to ensure that this 44968952abSNick Fitzgerald /// function is the correct callee. Providing the wrong function may result 45968952abSNick Fitzgerald /// in panics during compilation or incorrect runtime behavior. 46*dcedcbf5SNick Fitzgerald Inline { 47*dcedcbf5SNick Fitzgerald /// The callee function's body. 48*dcedcbf5SNick Fitzgerald callee: Cow<'a, ir::Function>, 49*dcedcbf5SNick Fitzgerald /// Whether to visit any function calls within the callee body after 50*dcedcbf5SNick Fitzgerald /// inlining and consider them for further inlining. 51*dcedcbf5SNick Fitzgerald visit_callee: bool, 52*dcedcbf5SNick Fitzgerald }, 53968952abSNick Fitzgerald } 54968952abSNick Fitzgerald 55968952abSNick Fitzgerald /// A trait for directing Cranelift whether to inline a particular call or not. 56968952abSNick Fitzgerald /// 57968952abSNick Fitzgerald /// Used in combination with the [`Context::inline`][crate::Context::inline] 58968952abSNick Fitzgerald /// method. 59968952abSNick Fitzgerald pub trait Inline { 60968952abSNick Fitzgerald /// A hook invoked for each direct call instruction in a function, whose 61968952abSNick Fitzgerald /// result determines whether Cranelift should inline a given call. 62968952abSNick Fitzgerald /// 63968952abSNick Fitzgerald /// The Cranelift user is responsible for defining their own hueristics and 64968952abSNick Fitzgerald /// deciding whether inlining the call is beneficial. 65968952abSNick Fitzgerald /// 66968952abSNick Fitzgerald /// When returning a function and directing Cranelift to inline its body 67968952abSNick Fitzgerald /// into the call site, the `Inline` implementer must ensure the following: 68968952abSNick Fitzgerald /// 69968952abSNick Fitzgerald /// * The returned function's signature exactly matches the `callee` 70968952abSNick Fitzgerald /// `FuncRef`'s signature. 71968952abSNick Fitzgerald /// 72968952abSNick Fitzgerald /// * The returned function must be legalized. 73968952abSNick Fitzgerald /// 74968952abSNick Fitzgerald /// * The returned function must be valid (i.e. it must pass the CLIF 75968952abSNick Fitzgerald /// verifier). 76968952abSNick Fitzgerald /// 77968952abSNick Fitzgerald /// * The returned function is a correct and valid implementation of the 78968952abSNick Fitzgerald /// `callee` according to your language's semantics. 79968952abSNick Fitzgerald /// 80968952abSNick Fitzgerald /// Failure to uphold these invariants may result in panics during 81968952abSNick Fitzgerald /// compilation or incorrect runtime behavior in the generated code. 82968952abSNick Fitzgerald fn inline( 833ecb338eSNick Fitzgerald &mut self, 84968952abSNick Fitzgerald caller: &ir::Function, 85968952abSNick Fitzgerald call_inst: ir::Inst, 86968952abSNick Fitzgerald call_opcode: ir::Opcode, 87968952abSNick Fitzgerald callee: ir::FuncRef, 88968952abSNick Fitzgerald call_args: &[ir::Value], 89968952abSNick Fitzgerald ) -> InlineCommand<'_>; 90968952abSNick Fitzgerald } 91968952abSNick Fitzgerald 923ecb338eSNick Fitzgerald impl<'a, T> Inline for &'a mut T 93968952abSNick Fitzgerald where 94968952abSNick Fitzgerald T: Inline, 95968952abSNick Fitzgerald { 96968952abSNick Fitzgerald fn inline( 973ecb338eSNick Fitzgerald &mut self, 98968952abSNick Fitzgerald caller: &ir::Function, 99968952abSNick Fitzgerald inst: ir::Inst, 100968952abSNick Fitzgerald opcode: ir::Opcode, 101968952abSNick Fitzgerald callee: ir::FuncRef, 102968952abSNick Fitzgerald args: &[ir::Value], 103968952abSNick Fitzgerald ) -> InlineCommand<'_> { 104968952abSNick Fitzgerald (*self).inline(caller, inst, opcode, callee, args) 105968952abSNick Fitzgerald } 106968952abSNick Fitzgerald } 107968952abSNick Fitzgerald 108968952abSNick Fitzgerald /// Walk the given function, invoke the `Inline` implementation for each call 109968952abSNick Fitzgerald /// instruction, and inline the callee when directed to do so. 110968952abSNick Fitzgerald /// 111968952abSNick Fitzgerald /// Returns whether any call was inlined. 1123ecb338eSNick Fitzgerald pub(crate) fn do_inlining( 1133ecb338eSNick Fitzgerald func: &mut ir::Function, 1143ecb338eSNick Fitzgerald mut inliner: impl Inline, 1153ecb338eSNick Fitzgerald ) -> CodegenResult<bool> { 1163ecb338eSNick Fitzgerald trace!("function {} before inlining: {}", func.name, func); 1173ecb338eSNick Fitzgerald 118968952abSNick Fitzgerald let mut inlined_any = false; 119968952abSNick Fitzgerald let mut allocs = InliningAllocs::default(); 120968952abSNick Fitzgerald 121968952abSNick Fitzgerald let mut cursor = FuncCursor::new(func); 122*dcedcbf5SNick Fitzgerald 'block_loop: while let Some(block) = cursor.next_block() { 123*dcedcbf5SNick Fitzgerald // Always keep track of our previous cursor position. Assuming that the 124*dcedcbf5SNick Fitzgerald // current position is a function call that we will inline, then the 125*dcedcbf5SNick Fitzgerald // previous position is just before the inlined callee function. After 126*dcedcbf5SNick Fitzgerald // inlining a call, the Cranelift user can decide whether to consider 127*dcedcbf5SNick Fitzgerald // any function calls in the inlined callee for further inlining or 128*dcedcbf5SNick Fitzgerald // not. When they do, then we back up to this previous cursor position 129*dcedcbf5SNick Fitzgerald // so that our traversal will then continue over the inlined body. 130968952abSNick Fitzgerald let mut prev_pos; 131968952abSNick Fitzgerald 132968952abSNick Fitzgerald while let Some(inst) = { 133968952abSNick Fitzgerald prev_pos = cursor.position(); 134968952abSNick Fitzgerald cursor.next_inst() 135968952abSNick Fitzgerald } { 136*dcedcbf5SNick Fitzgerald // Make sure that `block` is always `inst`'s block, even with all of 137*dcedcbf5SNick Fitzgerald // our cursor-position-updating and block-splitting-during-inlining 138*dcedcbf5SNick Fitzgerald // shenanigans below. 139*dcedcbf5SNick Fitzgerald debug_assert_eq!(Some(block), cursor.func.layout.inst_block(inst)); 140*dcedcbf5SNick Fitzgerald 141968952abSNick Fitzgerald match cursor.func.dfg.insts[inst] { 142968952abSNick Fitzgerald ir::InstructionData::Call { 143968952abSNick Fitzgerald opcode: opcode @ ir::Opcode::Call | opcode @ ir::Opcode::ReturnCall, 144968952abSNick Fitzgerald args: _, 145968952abSNick Fitzgerald func_ref, 146968952abSNick Fitzgerald } => { 1474cbea5e8SNick Fitzgerald trace!( 1484cbea5e8SNick Fitzgerald "considering call site for inlining: {inst}: {}", 1494cbea5e8SNick Fitzgerald cursor.func.dfg.display_inst(inst), 1504cbea5e8SNick Fitzgerald ); 151*dcedcbf5SNick Fitzgerald let args = cursor.func.dfg.inst_args(inst); 152968952abSNick Fitzgerald match inliner.inline(&cursor.func, inst, opcode, func_ref, args) { 1534cbea5e8SNick Fitzgerald InlineCommand::KeepCall => { 1544cbea5e8SNick Fitzgerald trace!(" --> keeping call"); 1554cbea5e8SNick Fitzgerald } 156*dcedcbf5SNick Fitzgerald InlineCommand::Inline { 157*dcedcbf5SNick Fitzgerald callee, 158*dcedcbf5SNick Fitzgerald visit_callee, 159*dcedcbf5SNick Fitzgerald } => { 160*dcedcbf5SNick Fitzgerald let last_inlined_block = inline_one( 161968952abSNick Fitzgerald &mut allocs, 162968952abSNick Fitzgerald cursor.func, 163968952abSNick Fitzgerald func_ref, 164968952abSNick Fitzgerald block, 165968952abSNick Fitzgerald inst, 166968952abSNick Fitzgerald opcode, 167968952abSNick Fitzgerald &callee, 168968952abSNick Fitzgerald None, 169968952abSNick Fitzgerald ); 170968952abSNick Fitzgerald inlined_any = true; 171*dcedcbf5SNick Fitzgerald if visit_callee { 172968952abSNick Fitzgerald cursor.set_position(prev_pos); 173*dcedcbf5SNick Fitzgerald } else { 174*dcedcbf5SNick Fitzgerald // Arrange it so that the `next_block()` loop 175*dcedcbf5SNick Fitzgerald // will continue to the next block that is not 176*dcedcbf5SNick Fitzgerald // associated with the just-inlined callee. 177*dcedcbf5SNick Fitzgerald cursor.goto_bottom(last_inlined_block); 178*dcedcbf5SNick Fitzgerald continue 'block_loop; 179*dcedcbf5SNick Fitzgerald } 180968952abSNick Fitzgerald } 181968952abSNick Fitzgerald } 182968952abSNick Fitzgerald } 183968952abSNick Fitzgerald ir::InstructionData::TryCall { 184968952abSNick Fitzgerald opcode: opcode @ ir::Opcode::TryCall, 185968952abSNick Fitzgerald args: _, 186968952abSNick Fitzgerald func_ref, 187968952abSNick Fitzgerald exception, 188968952abSNick Fitzgerald } => { 1894cbea5e8SNick Fitzgerald trace!( 1904cbea5e8SNick Fitzgerald "considering call site for inlining: {inst}: {}", 1914cbea5e8SNick Fitzgerald cursor.func.dfg.display_inst(inst), 1924cbea5e8SNick Fitzgerald ); 193*dcedcbf5SNick Fitzgerald let args = cursor.func.dfg.inst_args(inst); 194968952abSNick Fitzgerald match inliner.inline(&cursor.func, inst, opcode, func_ref, args) { 1954cbea5e8SNick Fitzgerald InlineCommand::KeepCall => { 1964cbea5e8SNick Fitzgerald trace!(" --> keeping call"); 1974cbea5e8SNick Fitzgerald } 198*dcedcbf5SNick Fitzgerald InlineCommand::Inline { 199*dcedcbf5SNick Fitzgerald callee, 200*dcedcbf5SNick Fitzgerald visit_callee, 201*dcedcbf5SNick Fitzgerald } => { 202*dcedcbf5SNick Fitzgerald let last_inlined_block = inline_one( 203968952abSNick Fitzgerald &mut allocs, 204968952abSNick Fitzgerald cursor.func, 205968952abSNick Fitzgerald func_ref, 206968952abSNick Fitzgerald block, 207968952abSNick Fitzgerald inst, 208968952abSNick Fitzgerald opcode, 209968952abSNick Fitzgerald &callee, 210968952abSNick Fitzgerald Some(exception), 211968952abSNick Fitzgerald ); 212968952abSNick Fitzgerald inlined_any = true; 213*dcedcbf5SNick Fitzgerald if visit_callee { 214968952abSNick Fitzgerald cursor.set_position(prev_pos); 215*dcedcbf5SNick Fitzgerald } else { 216*dcedcbf5SNick Fitzgerald // Arrange it so that the `next_block()` loop 217*dcedcbf5SNick Fitzgerald // will continue to the next block that is not 218*dcedcbf5SNick Fitzgerald // associated with the just-inlined callee. 219*dcedcbf5SNick Fitzgerald cursor.goto_bottom(last_inlined_block); 220*dcedcbf5SNick Fitzgerald continue 'block_loop; 221968952abSNick Fitzgerald } 222968952abSNick Fitzgerald } 223968952abSNick Fitzgerald } 224*dcedcbf5SNick Fitzgerald } 225*dcedcbf5SNick Fitzgerald ir::InstructionData::CallIndirect { .. } 226*dcedcbf5SNick Fitzgerald | ir::InstructionData::TryCallIndirect { .. } => { 227*dcedcbf5SNick Fitzgerald // Can't inline indirect calls; need to have some earlier 228*dcedcbf5SNick Fitzgerald // pass rewrite them into direct calls first, when possible. 229*dcedcbf5SNick Fitzgerald } 230*dcedcbf5SNick Fitzgerald _ => { 231*dcedcbf5SNick Fitzgerald debug_assert!( 232*dcedcbf5SNick Fitzgerald !cursor.func.dfg.insts[inst].opcode().is_call(), 233*dcedcbf5SNick Fitzgerald "should have matched all call instructions, but found: {inst}: {}", 234*dcedcbf5SNick Fitzgerald cursor.func.dfg.display_inst(inst), 235*dcedcbf5SNick Fitzgerald ); 236*dcedcbf5SNick Fitzgerald } 237968952abSNick Fitzgerald } 238968952abSNick Fitzgerald } 239968952abSNick Fitzgerald } 240968952abSNick Fitzgerald 2413ecb338eSNick Fitzgerald if inlined_any { 2423ecb338eSNick Fitzgerald trace!("function {} after inlining: {}", func.name, func); 2433ecb338eSNick Fitzgerald } else { 2443ecb338eSNick Fitzgerald trace!("function {} did not have any callees inlined", func.name); 2453ecb338eSNick Fitzgerald } 2463ecb338eSNick Fitzgerald 247968952abSNick Fitzgerald Ok(inlined_any) 248968952abSNick Fitzgerald } 249968952abSNick Fitzgerald 250968952abSNick Fitzgerald #[derive(Default)] 251968952abSNick Fitzgerald struct InliningAllocs { 252968952abSNick Fitzgerald /// Map from callee value to inlined caller value. 253968952abSNick Fitzgerald values: SecondaryMap<ir::Value, PackedOption<ir::Value>>, 254968952abSNick Fitzgerald 255968952abSNick Fitzgerald /// Map from callee constant to inlined caller constant. 2564cbea5e8SNick Fitzgerald /// 2574cbea5e8SNick Fitzgerald /// Not in `EntityMap` because these are hash-consed inside the 2584cbea5e8SNick Fitzgerald /// `ir::Function`. 259968952abSNick Fitzgerald constants: SecondaryMap<ir::Constant, PackedOption<ir::Constant>>, 260968952abSNick Fitzgerald 2614cbea5e8SNick Fitzgerald /// Map from callee to inlined caller external name refs. 2624cbea5e8SNick Fitzgerald /// 2634cbea5e8SNick Fitzgerald /// Not in `EntityMap` because these are hash-consed inside the 2644cbea5e8SNick Fitzgerald /// `ir::Function`. 2654cbea5e8SNick Fitzgerald user_external_name_refs: 2664cbea5e8SNick Fitzgerald SecondaryMap<ir::UserExternalNameRef, PackedOption<ir::UserExternalNameRef>>, 2674cbea5e8SNick Fitzgerald 268968952abSNick Fitzgerald /// The set of _caller_ inlined call instructions that need exception table 269968952abSNick Fitzgerald /// fixups at the end of inlining. 270968952abSNick Fitzgerald /// 271968952abSNick Fitzgerald /// This includes all kinds of non-returning calls, not just the literal 272968952abSNick Fitzgerald /// `call` instruction: `call_indirect`, `try_call`, `try_call_indirect`, 273968952abSNick Fitzgerald /// etc... However, it does not include `return_call` and 274968952abSNick Fitzgerald /// `return_call_indirect` instructions because the caller cannot catch 275968952abSNick Fitzgerald /// exceptions that those calls throw because the caller is no longer on the 276968952abSNick Fitzgerald /// stack as soon as they are executed. 277968952abSNick Fitzgerald /// 278968952abSNick Fitzgerald /// Note: this is a simple `Vec`, and not an `EntitySet`, because it is very 279968952abSNick Fitzgerald /// sparse: most of the caller's instructions are not inlined call 280968952abSNick Fitzgerald /// instructions. Additionally, we require deterministic iteration order and 281968952abSNick Fitzgerald /// do not require set-membership testing, so a hash set is not a good 282968952abSNick Fitzgerald /// choice either. 283968952abSNick Fitzgerald calls_needing_exception_table_fixup: Vec<ir::Inst>, 284968952abSNick Fitzgerald } 285968952abSNick Fitzgerald 286968952abSNick Fitzgerald impl InliningAllocs { 287968952abSNick Fitzgerald fn reset(&mut self, callee: &ir::Function) { 288968952abSNick Fitzgerald let InliningAllocs { 289968952abSNick Fitzgerald values, 290968952abSNick Fitzgerald constants, 2914cbea5e8SNick Fitzgerald user_external_name_refs, 292968952abSNick Fitzgerald calls_needing_exception_table_fixup, 293968952abSNick Fitzgerald } = self; 294968952abSNick Fitzgerald 295968952abSNick Fitzgerald values.clear(); 296968952abSNick Fitzgerald values.resize(callee.dfg.len_values()); 297968952abSNick Fitzgerald 298968952abSNick Fitzgerald constants.clear(); 299968952abSNick Fitzgerald constants.resize(callee.dfg.constants.len()); 300968952abSNick Fitzgerald 3014cbea5e8SNick Fitzgerald user_external_name_refs.clear(); 3024cbea5e8SNick Fitzgerald user_external_name_refs.resize(callee.params.user_named_funcs().len()); 3034cbea5e8SNick Fitzgerald 304968952abSNick Fitzgerald // Note: We do not reserve capacity for 305968952abSNick Fitzgerald // `calls_needing_exception_table_fixup` because it is a sparse set and 306968952abSNick Fitzgerald // we don't know how large it needs to be ahead of time. 307968952abSNick Fitzgerald calls_needing_exception_table_fixup.clear(); 308968952abSNick Fitzgerald } 309968952abSNick Fitzgerald 310968952abSNick Fitzgerald fn set_inlined_value( 311968952abSNick Fitzgerald &mut self, 312968952abSNick Fitzgerald callee: &ir::Function, 313968952abSNick Fitzgerald callee_val: ir::Value, 314968952abSNick Fitzgerald inlined_val: ir::Value, 315968952abSNick Fitzgerald ) { 316968952abSNick Fitzgerald trace!(" --> callee {callee_val:?} = inlined {inlined_val:?}"); 317968952abSNick Fitzgerald debug_assert!(self.values[callee_val].is_none()); 318968952abSNick Fitzgerald let resolved_callee_val = callee.dfg.resolve_aliases(callee_val); 319968952abSNick Fitzgerald debug_assert!(self.values[resolved_callee_val].is_none()); 320968952abSNick Fitzgerald self.values[resolved_callee_val] = Some(inlined_val).into(); 321968952abSNick Fitzgerald } 322968952abSNick Fitzgerald 323968952abSNick Fitzgerald fn get_inlined_value(&self, callee: &ir::Function, callee_val: ir::Value) -> Option<ir::Value> { 324968952abSNick Fitzgerald let resolved_callee_val = callee.dfg.resolve_aliases(callee_val); 325968952abSNick Fitzgerald self.values[resolved_callee_val].expand() 326968952abSNick Fitzgerald } 327968952abSNick Fitzgerald } 328968952abSNick Fitzgerald 329968952abSNick Fitzgerald /// Inline one particular function call. 330*dcedcbf5SNick Fitzgerald /// 331*dcedcbf5SNick Fitzgerald /// Returns the last inlined block in the layout. 332968952abSNick Fitzgerald fn inline_one( 333968952abSNick Fitzgerald allocs: &mut InliningAllocs, 334968952abSNick Fitzgerald func: &mut ir::Function, 335968952abSNick Fitzgerald callee_func_ref: ir::FuncRef, 336968952abSNick Fitzgerald call_block: ir::Block, 337968952abSNick Fitzgerald call_inst: ir::Inst, 338968952abSNick Fitzgerald call_opcode: ir::Opcode, 339968952abSNick Fitzgerald callee: &ir::Function, 340968952abSNick Fitzgerald call_exception_table: Option<ir::ExceptionTable>, 341*dcedcbf5SNick Fitzgerald ) -> ir::Block { 342968952abSNick Fitzgerald trace!( 343968952abSNick Fitzgerald "Inlining call {call_inst:?}: {}\n\ 344968952abSNick Fitzgerald with callee = {callee:?}", 345968952abSNick Fitzgerald func.dfg.display_inst(call_inst) 346968952abSNick Fitzgerald ); 347968952abSNick Fitzgerald 348968952abSNick Fitzgerald // Type check callee signature. 349968952abSNick Fitzgerald let expected_callee_sig = func.dfg.ext_funcs[callee_func_ref].signature; 350968952abSNick Fitzgerald let expected_callee_sig = &func.dfg.signatures[expected_callee_sig]; 351968952abSNick Fitzgerald assert_eq!(expected_callee_sig, &callee.signature); 352968952abSNick Fitzgerald 353968952abSNick Fitzgerald allocs.reset(callee); 354968952abSNick Fitzgerald 355968952abSNick Fitzgerald // First, append various callee entity arenas to the end of the caller's 356968952abSNick Fitzgerald // entity arenas. 357968952abSNick Fitzgerald let entity_map = create_entities(allocs, func, callee); 358968952abSNick Fitzgerald 359968952abSNick Fitzgerald // Inlined prologue: split the call instruction's block at the point of the 360968952abSNick Fitzgerald // call and replace the call with a jump. 361968952abSNick Fitzgerald let return_block = split_off_return_block(func, call_inst, call_opcode, callee); 362968952abSNick Fitzgerald let call_stack_map = replace_call_with_jump(allocs, func, call_inst, callee, &entity_map); 363968952abSNick Fitzgerald 364968952abSNick Fitzgerald // Prepare for translating the actual instructions by inserting the inlined 365968952abSNick Fitzgerald // blocks into the caller's layout in the same order that they appear in the 366968952abSNick Fitzgerald // callee. 367*dcedcbf5SNick Fitzgerald let last_inlined_block = inline_block_layout(func, call_block, callee, &entity_map); 368968952abSNick Fitzgerald 369968952abSNick Fitzgerald // Translate each instruction from the callee into the caller, 370968952abSNick Fitzgerald // appending them to their associated block in the caller. 371968952abSNick Fitzgerald // 372968952abSNick Fitzgerald // Note that we iterate over the callee with a pre-order traversal so that 373968952abSNick Fitzgerald // we see value defs before uses. 374968952abSNick Fitzgerald for callee_block in Dfs::new().pre_order_iter(callee) { 375968952abSNick Fitzgerald let inlined_block = entity_map.inlined_block(callee_block); 376968952abSNick Fitzgerald trace!( 377968952abSNick Fitzgerald "Processing instructions in callee block {callee_block:?} (inlined block {inlined_block:?}" 378968952abSNick Fitzgerald ); 379968952abSNick Fitzgerald 380968952abSNick Fitzgerald let mut next_callee_inst = callee.layout.first_inst(callee_block); 381968952abSNick Fitzgerald while let Some(callee_inst) = next_callee_inst { 382968952abSNick Fitzgerald trace!( 383968952abSNick Fitzgerald "Processing callee instruction {callee_inst:?}: {}", 384968952abSNick Fitzgerald callee.dfg.display_inst(callee_inst) 385968952abSNick Fitzgerald ); 386968952abSNick Fitzgerald 387968952abSNick Fitzgerald assert_ne!( 388968952abSNick Fitzgerald callee.dfg.insts[callee_inst].opcode(), 389968952abSNick Fitzgerald ir::Opcode::GlobalValue, 390968952abSNick Fitzgerald "callee must already be legalized, we shouldn't see any `global_value` \ 391968952abSNick Fitzgerald instructions when inlining; found {callee_inst:?}: {}", 392968952abSNick Fitzgerald callee.dfg.display_inst(callee_inst) 393968952abSNick Fitzgerald ); 394968952abSNick Fitzgerald 395968952abSNick Fitzgerald // Remap the callee instruction's entities and insert it into the 396968952abSNick Fitzgerald // caller's DFG. 397968952abSNick Fitzgerald let inlined_inst_data = callee.dfg.insts[callee_inst].map(InliningInstRemapper { 398968952abSNick Fitzgerald allocs: &allocs, 399968952abSNick Fitzgerald func, 400968952abSNick Fitzgerald callee, 401968952abSNick Fitzgerald entity_map: &entity_map, 402968952abSNick Fitzgerald }); 403968952abSNick Fitzgerald let inlined_inst = func.dfg.make_inst(inlined_inst_data); 404968952abSNick Fitzgerald func.layout.append_inst(inlined_inst, inlined_block); 405968952abSNick Fitzgerald 406968952abSNick Fitzgerald let opcode = callee.dfg.insts[callee_inst].opcode(); 407968952abSNick Fitzgerald if opcode.is_return() { 408968952abSNick Fitzgerald // Instructions that return do not define any values, so we 409968952abSNick Fitzgerald // don't need to worry about that, but we do need to fix them up 410968952abSNick Fitzgerald // so that they return by jumping to our control-flow join 411968952abSNick Fitzgerald // block, rather than returning from the caller. 412968952abSNick Fitzgerald if let Some(return_block) = return_block { 413968952abSNick Fitzgerald fixup_inst_that_returns( 414968952abSNick Fitzgerald allocs, 415968952abSNick Fitzgerald func, 416968952abSNick Fitzgerald callee, 417968952abSNick Fitzgerald &entity_map, 418968952abSNick Fitzgerald call_opcode, 419968952abSNick Fitzgerald inlined_inst, 420968952abSNick Fitzgerald callee_inst, 421968952abSNick Fitzgerald return_block, 422968952abSNick Fitzgerald call_stack_map.as_ref().map(|es| &**es), 423968952abSNick Fitzgerald ); 424968952abSNick Fitzgerald } else { 425968952abSNick Fitzgerald // If we are inlining a callee that was invoked via 426968952abSNick Fitzgerald // `return_call`, we leave inlined return instructions 427968952abSNick Fitzgerald // as-is: there is no logical caller frame on the stack to 428968952abSNick Fitzgerald // continue to. 429968952abSNick Fitzgerald debug_assert_eq!(call_opcode, ir::Opcode::ReturnCall); 430968952abSNick Fitzgerald } 431968952abSNick Fitzgerald } else { 432968952abSNick Fitzgerald // Make the instruction's result values. 433968952abSNick Fitzgerald let ctrl_typevar = callee.dfg.ctrl_typevar(callee_inst); 434968952abSNick Fitzgerald func.dfg.make_inst_results(inlined_inst, ctrl_typevar); 435968952abSNick Fitzgerald 436968952abSNick Fitzgerald // Update the value map for this instruction's defs. 437968952abSNick Fitzgerald let callee_results = callee.dfg.inst_results(callee_inst); 438968952abSNick Fitzgerald let inlined_results = func.dfg.inst_results(inlined_inst); 439968952abSNick Fitzgerald debug_assert_eq!(callee_results.len(), inlined_results.len()); 440968952abSNick Fitzgerald for (callee_val, inlined_val) in callee_results.iter().zip(inlined_results) { 441968952abSNick Fitzgerald allocs.set_inlined_value(callee, *callee_val, *inlined_val); 442968952abSNick Fitzgerald } 443968952abSNick Fitzgerald 444968952abSNick Fitzgerald if opcode.is_call() { 445968952abSNick Fitzgerald append_stack_map_entries( 446968952abSNick Fitzgerald func, 447968952abSNick Fitzgerald callee, 448968952abSNick Fitzgerald &entity_map, 449968952abSNick Fitzgerald call_stack_map.as_deref(), 450968952abSNick Fitzgerald inlined_inst, 451968952abSNick Fitzgerald callee_inst, 452968952abSNick Fitzgerald ); 453968952abSNick Fitzgerald 454968952abSNick Fitzgerald // When we are inlining a `try_call` call site, we need to merge 455968952abSNick Fitzgerald // the call site's exception table into the inlined calls' 456968952abSNick Fitzgerald // exception tables. This can involve rewriting regular `call`s 457968952abSNick Fitzgerald // into `try_call`s, which requires mutating the CFG because 458968952abSNick Fitzgerald // `try_call` is a block terminator. However, we can't mutate 459968952abSNick Fitzgerald // the CFG in the middle of this traversal because we rely on 460968952abSNick Fitzgerald // the existence of a one-to-one mapping between the callee 461968952abSNick Fitzgerald // layout and the inlined layout. Instead, we record the set of 462968952abSNick Fitzgerald // inlined call instructions that will need fixing up, and 463968952abSNick Fitzgerald // perform that possibly-CFG-mutating exception table merging in 464968952abSNick Fitzgerald // a follow up pass, when we no longer rely on that one-to-one 465968952abSNick Fitzgerald // layout mapping. 466968952abSNick Fitzgerald debug_assert_eq!( 467968952abSNick Fitzgerald call_opcode == ir::Opcode::TryCall, 468968952abSNick Fitzgerald call_exception_table.is_some() 469968952abSNick Fitzgerald ); 470968952abSNick Fitzgerald if call_opcode == ir::Opcode::TryCall { 471968952abSNick Fitzgerald allocs 472968952abSNick Fitzgerald .calls_needing_exception_table_fixup 473968952abSNick Fitzgerald .push(inlined_inst); 474968952abSNick Fitzgerald } 475968952abSNick Fitzgerald } 476968952abSNick Fitzgerald } 477968952abSNick Fitzgerald 478968952abSNick Fitzgerald trace!( 479968952abSNick Fitzgerald " --> inserted inlined instruction {inlined_inst:?}: {}", 480968952abSNick Fitzgerald func.dfg.display_inst(inlined_inst) 481968952abSNick Fitzgerald ); 482968952abSNick Fitzgerald 483968952abSNick Fitzgerald next_callee_inst = callee.layout.next_inst(callee_inst); 484968952abSNick Fitzgerald } 485968952abSNick Fitzgerald } 486968952abSNick Fitzgerald 487e3a607eaSNick Fitzgerald // We copied *all* callee blocks into the caller's layout, but only copied 488e3a607eaSNick Fitzgerald // the callee instructions in *reachable* callee blocks into the caller's 489e3a607eaSNick Fitzgerald // associated blocks. Therefore, any *unreachable* blocks are empty in the 490e3a607eaSNick Fitzgerald // caller, which is invalid CLIF because all blocks must end in a 491e3a607eaSNick Fitzgerald // terminator, so do a quick pass over the inlined blocks and remove any 492e3a607eaSNick Fitzgerald // empty blocks from the caller's layout. 493e3a607eaSNick Fitzgerald for block in entity_map.iter_inlined_blocks(func) { 494cfc05638SNick Fitzgerald if func.layout.is_block_inserted(block) && func.layout.first_inst(block).is_none() { 495e3a607eaSNick Fitzgerald func.layout.remove_block(block); 496e3a607eaSNick Fitzgerald } 497e3a607eaSNick Fitzgerald } 498e3a607eaSNick Fitzgerald 499968952abSNick Fitzgerald // Final step: fixup the exception tables of any inlined calls when we are 500968952abSNick Fitzgerald // inlining a `try_call` site. 501968952abSNick Fitzgerald // 502968952abSNick Fitzgerald // Subtly, this requires rewriting non-catching `call[_indirect]` 503968952abSNick Fitzgerald // instructions into `try_call[_indirect]` instructions so that exceptions 504968952abSNick Fitzgerald // that unwound through the original callee frame and were caught by the 505968952abSNick Fitzgerald // caller's `try_call` do not unwind past this inlined frame. And turning a 506968952abSNick Fitzgerald // `call` into a `try_call` mutates the CFG, breaking our one-to-one mapping 507968952abSNick Fitzgerald // between callee blocks and inlined blocks, so we delay these fixups to 508968952abSNick Fitzgerald // this final step, when we no longer rely on that mapping. 509968952abSNick Fitzgerald debug_assert!( 510968952abSNick Fitzgerald allocs.calls_needing_exception_table_fixup.is_empty() || call_exception_table.is_some() 511968952abSNick Fitzgerald ); 512968952abSNick Fitzgerald debug_assert_eq!( 513968952abSNick Fitzgerald call_opcode == ir::Opcode::TryCall, 514968952abSNick Fitzgerald call_exception_table.is_some() 515968952abSNick Fitzgerald ); 516968952abSNick Fitzgerald if let Some(call_exception_table) = call_exception_table { 517968952abSNick Fitzgerald fixup_inlined_call_exception_tables(allocs, func, call_exception_table); 518968952abSNick Fitzgerald } 519*dcedcbf5SNick Fitzgerald 520*dcedcbf5SNick Fitzgerald last_inlined_block 521968952abSNick Fitzgerald } 522968952abSNick Fitzgerald 523968952abSNick Fitzgerald /// Append stack map entries from the caller and callee to the given inlined 524968952abSNick Fitzgerald /// instruction. 525968952abSNick Fitzgerald fn append_stack_map_entries( 526968952abSNick Fitzgerald func: &mut ir::Function, 527968952abSNick Fitzgerald callee: &ir::Function, 528968952abSNick Fitzgerald entity_map: &EntityMap, 529968952abSNick Fitzgerald call_stack_map: Option<&[ir::UserStackMapEntry]>, 530968952abSNick Fitzgerald inlined_inst: ir::Inst, 531968952abSNick Fitzgerald callee_inst: ir::Inst, 532968952abSNick Fitzgerald ) { 533968952abSNick Fitzgerald // Add the caller's stack map to this call. These entries 534968952abSNick Fitzgerald // already refer to caller entities and do not need further 535968952abSNick Fitzgerald // translation. 536968952abSNick Fitzgerald func.dfg.append_user_stack_map_entries( 537968952abSNick Fitzgerald inlined_inst, 538968952abSNick Fitzgerald call_stack_map 539968952abSNick Fitzgerald .iter() 540968952abSNick Fitzgerald .flat_map(|entries| entries.iter().cloned()), 541968952abSNick Fitzgerald ); 542968952abSNick Fitzgerald 543968952abSNick Fitzgerald // Append the callee's stack map to this call. These entries 544968952abSNick Fitzgerald // refer to callee entities and therefore do require 545968952abSNick Fitzgerald // translation into the caller's index space. 546968952abSNick Fitzgerald func.dfg.append_user_stack_map_entries( 547968952abSNick Fitzgerald inlined_inst, 548968952abSNick Fitzgerald callee 549968952abSNick Fitzgerald .dfg 550968952abSNick Fitzgerald .user_stack_map_entries(callee_inst) 551968952abSNick Fitzgerald .iter() 552968952abSNick Fitzgerald .flat_map(|entries| entries.iter()) 553968952abSNick Fitzgerald .map(|entry| ir::UserStackMapEntry { 554968952abSNick Fitzgerald ty: entry.ty, 555968952abSNick Fitzgerald slot: entity_map.inlined_stack_slot(entry.slot), 556968952abSNick Fitzgerald offset: entry.offset, 557968952abSNick Fitzgerald }), 558968952abSNick Fitzgerald ); 559968952abSNick Fitzgerald } 560968952abSNick Fitzgerald 561968952abSNick Fitzgerald /// Create or update the exception tables for any inlined call instructions: 562968952abSNick Fitzgerald /// when inlining at a `try_call` site, we must forward our exceptional edges 563968952abSNick Fitzgerald /// into each inlined call instruction. 564968952abSNick Fitzgerald fn fixup_inlined_call_exception_tables( 565968952abSNick Fitzgerald allocs: &mut InliningAllocs, 566968952abSNick Fitzgerald func: &mut ir::Function, 567968952abSNick Fitzgerald call_exception_table: ir::ExceptionTable, 568968952abSNick Fitzgerald ) { 569968952abSNick Fitzgerald // Split a block at a `call[_indirect]` instruction, detach the 570968952abSNick Fitzgerald // instruction's results, and alias them to the new block's parameters. 571968952abSNick Fitzgerald let split_block_for_new_try_call = |func: &mut ir::Function, inst: ir::Inst| -> ir::Block { 572968952abSNick Fitzgerald debug_assert!(func.dfg.insts[inst].opcode().is_call()); 573968952abSNick Fitzgerald debug_assert!(!func.dfg.insts[inst].opcode().is_terminator()); 574968952abSNick Fitzgerald 575968952abSNick Fitzgerald // Split the block. 576968952abSNick Fitzgerald let next_inst = func 577968952abSNick Fitzgerald .layout 578968952abSNick Fitzgerald .next_inst(inst) 579968952abSNick Fitzgerald .expect("inst is not a terminator, should have a successor"); 580968952abSNick Fitzgerald let new_block = func.dfg.blocks.add(); 581968952abSNick Fitzgerald func.layout.split_block(new_block, next_inst); 582968952abSNick Fitzgerald 583968952abSNick Fitzgerald // `try_call[_indirect]` instructions do not define values themselves; 584968952abSNick Fitzgerald // the normal-return block has parameters for the results. So remove 585968952abSNick Fitzgerald // this instruction's results, create an associated block parameter for 586968952abSNick Fitzgerald // each of them, and alias them to the new block parameter. 587968952abSNick Fitzgerald let old_results = SmallValueVec::from_iter(func.dfg.inst_results(inst).iter().copied()); 588968952abSNick Fitzgerald func.dfg.detach_inst_results(inst); 589968952abSNick Fitzgerald for old_result in old_results { 590968952abSNick Fitzgerald let ty = func.dfg.value_type(old_result); 591968952abSNick Fitzgerald let new_block_param = func.dfg.append_block_param(new_block, ty); 592968952abSNick Fitzgerald func.dfg.change_to_alias(old_result, new_block_param); 593968952abSNick Fitzgerald } 594968952abSNick Fitzgerald 595968952abSNick Fitzgerald new_block 596968952abSNick Fitzgerald }; 597968952abSNick Fitzgerald 598968952abSNick Fitzgerald // Clone the caller's exception table, updating it for use in the current 599968952abSNick Fitzgerald // `call[_indirect]` instruction as it becomes a `try_call[_indirect]`. 600968952abSNick Fitzgerald let clone_exception_table_for_this_call = |func: &mut ir::Function, 601968952abSNick Fitzgerald signature: ir::SigRef, 602968952abSNick Fitzgerald new_block: ir::Block| 603968952abSNick Fitzgerald -> ir::ExceptionTable { 604968952abSNick Fitzgerald let mut exception = func.stencil.dfg.exception_tables[call_exception_table] 605968952abSNick Fitzgerald .deep_clone(&mut func.stencil.dfg.value_lists); 606968952abSNick Fitzgerald 607968952abSNick Fitzgerald *exception.signature_mut() = signature; 608968952abSNick Fitzgerald 609968952abSNick Fitzgerald let returns_len = func.dfg.signatures[signature].returns.len(); 610968952abSNick Fitzgerald let returns_len = u32::try_from(returns_len).unwrap(); 611968952abSNick Fitzgerald 612968952abSNick Fitzgerald *exception.normal_return_mut() = ir::BlockCall::new( 613968952abSNick Fitzgerald new_block, 614968952abSNick Fitzgerald (0..returns_len).map(|i| ir::BlockArg::TryCallRet(i)), 615968952abSNick Fitzgerald &mut func.dfg.value_lists, 616968952abSNick Fitzgerald ); 617968952abSNick Fitzgerald 618968952abSNick Fitzgerald func.dfg.exception_tables.push(exception) 619968952abSNick Fitzgerald }; 620968952abSNick Fitzgerald 621968952abSNick Fitzgerald for inst in allocs.calls_needing_exception_table_fixup.drain(..) { 622968952abSNick Fitzgerald debug_assert!(func.dfg.insts[inst].opcode().is_call()); 623968952abSNick Fitzgerald debug_assert!(!func.dfg.insts[inst].opcode().is_return()); 624968952abSNick Fitzgerald match func.dfg.insts[inst] { 625968952abSNick Fitzgerald // current_block: 626968952abSNick Fitzgerald // preds... 627968952abSNick Fitzgerald // rets... = call f(args...) 628968952abSNick Fitzgerald // succs... 629968952abSNick Fitzgerald // 630968952abSNick Fitzgerald // becomes 631968952abSNick Fitzgerald // 632968952abSNick Fitzgerald // current_block: 633968952abSNick Fitzgerald // preds... 634968952abSNick Fitzgerald // try_call f(args...), new_block(rets...), [call_exception_table...] 635968952abSNick Fitzgerald // new_block(rets...): 636968952abSNick Fitzgerald // succs... 637968952abSNick Fitzgerald ir::InstructionData::Call { 638968952abSNick Fitzgerald opcode: ir::Opcode::Call, 639968952abSNick Fitzgerald args, 640968952abSNick Fitzgerald func_ref, 641968952abSNick Fitzgerald } => { 642968952abSNick Fitzgerald let new_block = split_block_for_new_try_call(func, inst); 643968952abSNick Fitzgerald let signature = func.dfg.ext_funcs[func_ref].signature; 644968952abSNick Fitzgerald let exception = clone_exception_table_for_this_call(func, signature, new_block); 645968952abSNick Fitzgerald func.dfg.insts[inst] = ir::InstructionData::TryCall { 646968952abSNick Fitzgerald opcode: ir::Opcode::TryCall, 647968952abSNick Fitzgerald args, 648968952abSNick Fitzgerald func_ref, 649968952abSNick Fitzgerald exception, 650968952abSNick Fitzgerald }; 651968952abSNick Fitzgerald } 652968952abSNick Fitzgerald 653968952abSNick Fitzgerald // current_block: 654968952abSNick Fitzgerald // preds... 655968952abSNick Fitzgerald // rets... = call_indirect sig, val(args...) 656968952abSNick Fitzgerald // succs... 657968952abSNick Fitzgerald // 658968952abSNick Fitzgerald // becomes 659968952abSNick Fitzgerald // 660968952abSNick Fitzgerald // current_block: 661968952abSNick Fitzgerald // preds... 662968952abSNick Fitzgerald // try_call_indirect sig, val(args...), new_block(rets...), [call_exception_table...] 663968952abSNick Fitzgerald // new_block(rets...): 664968952abSNick Fitzgerald // succs... 665968952abSNick Fitzgerald ir::InstructionData::CallIndirect { 666968952abSNick Fitzgerald opcode: ir::Opcode::CallIndirect, 667968952abSNick Fitzgerald args, 668968952abSNick Fitzgerald sig_ref, 669968952abSNick Fitzgerald } => { 670968952abSNick Fitzgerald let new_block = split_block_for_new_try_call(func, inst); 671968952abSNick Fitzgerald let exception = clone_exception_table_for_this_call(func, sig_ref, new_block); 672968952abSNick Fitzgerald func.dfg.insts[inst] = ir::InstructionData::TryCallIndirect { 673968952abSNick Fitzgerald opcode: ir::Opcode::TryCallIndirect, 674968952abSNick Fitzgerald args, 675968952abSNick Fitzgerald exception, 676968952abSNick Fitzgerald }; 677968952abSNick Fitzgerald } 678968952abSNick Fitzgerald 679968952abSNick Fitzgerald // For `try_call[_indirect]` instructions, we just need to merge the 680968952abSNick Fitzgerald // exception tables. 681968952abSNick Fitzgerald ir::InstructionData::TryCall { 682968952abSNick Fitzgerald opcode: ir::Opcode::TryCall, 683968952abSNick Fitzgerald exception, 684968952abSNick Fitzgerald .. 685968952abSNick Fitzgerald } 686968952abSNick Fitzgerald | ir::InstructionData::TryCallIndirect { 687968952abSNick Fitzgerald opcode: ir::Opcode::TryCallIndirect, 688968952abSNick Fitzgerald exception, 689968952abSNick Fitzgerald .. 690968952abSNick Fitzgerald } => { 6914590076fSChris Fallin // Construct a new exception table that consists of 6924590076fSChris Fallin // the inlined instruction's exception table match 6934590076fSChris Fallin // sequence, with the inlining site's exception table 6944590076fSChris Fallin // appended. This will ensure that the first-match 6954590076fSChris Fallin // semantics emulates the original behavior of 6964590076fSChris Fallin // matching in the inner frame first. 6974590076fSChris Fallin let sig = func.dfg.exception_tables[exception].signature(); 6984590076fSChris Fallin let normal_return = *func.dfg.exception_tables[exception].normal_return(); 6994590076fSChris Fallin let exception_data = ExceptionTableData::new( 7004590076fSChris Fallin sig, 7014590076fSChris Fallin normal_return, 702968952abSNick Fitzgerald func.dfg.exception_tables[exception] 7034590076fSChris Fallin .items() 7044590076fSChris Fallin .chain(func.dfg.exception_tables[call_exception_table].items()), 7054590076fSChris Fallin ) 7064590076fSChris Fallin .deep_clone(&mut func.dfg.value_lists); 707968952abSNick Fitzgerald 7084590076fSChris Fallin func.dfg.exception_tables[exception] = exception_data; 709968952abSNick Fitzgerald } 710968952abSNick Fitzgerald 711968952abSNick Fitzgerald otherwise => unreachable!("unknown non-return call instruction: {otherwise:?}"), 712968952abSNick Fitzgerald } 713968952abSNick Fitzgerald } 714968952abSNick Fitzgerald } 715968952abSNick Fitzgerald 716968952abSNick Fitzgerald /// After having created an inlined version of a callee instruction that returns 717968952abSNick Fitzgerald /// in the caller, we need to fix it up so that it doesn't actually return 718968952abSNick Fitzgerald /// (since we are already in the caller's frame) and instead just jumps to the 719968952abSNick Fitzgerald /// control-flow join point. 720968952abSNick Fitzgerald fn fixup_inst_that_returns( 721968952abSNick Fitzgerald allocs: &mut InliningAllocs, 722968952abSNick Fitzgerald func: &mut ir::Function, 723968952abSNick Fitzgerald callee: &ir::Function, 724968952abSNick Fitzgerald entity_map: &EntityMap, 725968952abSNick Fitzgerald call_opcode: ir::Opcode, 726968952abSNick Fitzgerald inlined_inst: ir::Inst, 727968952abSNick Fitzgerald callee_inst: ir::Inst, 728968952abSNick Fitzgerald return_block: ir::Block, 729968952abSNick Fitzgerald call_stack_map: Option<&[ir::UserStackMapEntry]>, 730968952abSNick Fitzgerald ) { 731968952abSNick Fitzgerald debug_assert!(func.dfg.insts[inlined_inst].opcode().is_return()); 732968952abSNick Fitzgerald match func.dfg.insts[inlined_inst] { 733968952abSNick Fitzgerald // return rets... 734968952abSNick Fitzgerald // 735968952abSNick Fitzgerald // becomes 736968952abSNick Fitzgerald // 737968952abSNick Fitzgerald // jump return_block(rets...) 738968952abSNick Fitzgerald ir::InstructionData::MultiAry { 739968952abSNick Fitzgerald opcode: ir::Opcode::Return, 740968952abSNick Fitzgerald args, 741968952abSNick Fitzgerald } => { 742968952abSNick Fitzgerald let rets = SmallBlockArgVec::from_iter( 743968952abSNick Fitzgerald args.as_slice(&func.dfg.value_lists) 744968952abSNick Fitzgerald .iter() 745968952abSNick Fitzgerald .copied() 746968952abSNick Fitzgerald .map(|v| v.into()), 747968952abSNick Fitzgerald ); 748968952abSNick Fitzgerald func.dfg.replace(inlined_inst).jump(return_block, &rets); 749968952abSNick Fitzgerald } 750968952abSNick Fitzgerald 751968952abSNick Fitzgerald // return_call f(args...) 752968952abSNick Fitzgerald // 753968952abSNick Fitzgerald // becomes 754968952abSNick Fitzgerald // 755968952abSNick Fitzgerald // rets... = call f(args...) 756968952abSNick Fitzgerald // jump return_block(rets...) 757968952abSNick Fitzgerald ir::InstructionData::Call { 758968952abSNick Fitzgerald opcode: ir::Opcode::ReturnCall, 759968952abSNick Fitzgerald args, 760968952abSNick Fitzgerald func_ref, 761968952abSNick Fitzgerald } => { 762968952abSNick Fitzgerald func.dfg.insts[inlined_inst] = ir::InstructionData::Call { 763968952abSNick Fitzgerald opcode: ir::Opcode::Call, 764968952abSNick Fitzgerald args, 765968952abSNick Fitzgerald func_ref, 766968952abSNick Fitzgerald }; 767968952abSNick Fitzgerald func.dfg.make_inst_results(inlined_inst, ir::types::INVALID); 768968952abSNick Fitzgerald 769968952abSNick Fitzgerald append_stack_map_entries( 770968952abSNick Fitzgerald func, 771968952abSNick Fitzgerald callee, 772968952abSNick Fitzgerald &entity_map, 773968952abSNick Fitzgerald call_stack_map, 774968952abSNick Fitzgerald inlined_inst, 775968952abSNick Fitzgerald callee_inst, 776968952abSNick Fitzgerald ); 777968952abSNick Fitzgerald 778968952abSNick Fitzgerald let rets = SmallBlockArgVec::from_iter( 779968952abSNick Fitzgerald func.dfg 780968952abSNick Fitzgerald .inst_results(inlined_inst) 781968952abSNick Fitzgerald .iter() 782968952abSNick Fitzgerald .copied() 783968952abSNick Fitzgerald .map(|v| v.into()), 784968952abSNick Fitzgerald ); 785968952abSNick Fitzgerald let mut cursor = FuncCursor::new(func); 786968952abSNick Fitzgerald cursor.goto_after_inst(inlined_inst); 787968952abSNick Fitzgerald cursor.ins().jump(return_block, &rets); 788968952abSNick Fitzgerald 789968952abSNick Fitzgerald if call_opcode == ir::Opcode::TryCall { 790968952abSNick Fitzgerald allocs 791968952abSNick Fitzgerald .calls_needing_exception_table_fixup 792968952abSNick Fitzgerald .push(inlined_inst); 793968952abSNick Fitzgerald } 794968952abSNick Fitzgerald } 795968952abSNick Fitzgerald 796968952abSNick Fitzgerald // return_call_indirect val(args...) 797968952abSNick Fitzgerald // 798968952abSNick Fitzgerald // becomes 799968952abSNick Fitzgerald // 800968952abSNick Fitzgerald // rets... = call_indirect val(args...) 801968952abSNick Fitzgerald // jump return_block(rets...) 802968952abSNick Fitzgerald ir::InstructionData::CallIndirect { 803968952abSNick Fitzgerald opcode: ir::Opcode::ReturnCallIndirect, 804968952abSNick Fitzgerald args, 805968952abSNick Fitzgerald sig_ref, 806968952abSNick Fitzgerald } => { 807968952abSNick Fitzgerald func.dfg.insts[inlined_inst] = ir::InstructionData::CallIndirect { 808968952abSNick Fitzgerald opcode: ir::Opcode::CallIndirect, 809968952abSNick Fitzgerald args, 810968952abSNick Fitzgerald sig_ref, 811968952abSNick Fitzgerald }; 812968952abSNick Fitzgerald func.dfg.make_inst_results(inlined_inst, ir::types::INVALID); 813968952abSNick Fitzgerald 814968952abSNick Fitzgerald append_stack_map_entries( 815968952abSNick Fitzgerald func, 816968952abSNick Fitzgerald callee, 817968952abSNick Fitzgerald &entity_map, 818968952abSNick Fitzgerald call_stack_map, 819968952abSNick Fitzgerald inlined_inst, 820968952abSNick Fitzgerald callee_inst, 821968952abSNick Fitzgerald ); 822968952abSNick Fitzgerald 823968952abSNick Fitzgerald let rets = SmallBlockArgVec::from_iter( 824968952abSNick Fitzgerald func.dfg 825968952abSNick Fitzgerald .inst_results(inlined_inst) 826968952abSNick Fitzgerald .iter() 827968952abSNick Fitzgerald .copied() 828968952abSNick Fitzgerald .map(|v| v.into()), 829968952abSNick Fitzgerald ); 830968952abSNick Fitzgerald let mut cursor = FuncCursor::new(func); 831968952abSNick Fitzgerald cursor.goto_after_inst(inlined_inst); 832968952abSNick Fitzgerald cursor.ins().jump(return_block, &rets); 833968952abSNick Fitzgerald 834968952abSNick Fitzgerald if call_opcode == ir::Opcode::TryCall { 835968952abSNick Fitzgerald allocs 836968952abSNick Fitzgerald .calls_needing_exception_table_fixup 837968952abSNick Fitzgerald .push(inlined_inst); 838968952abSNick Fitzgerald } 839968952abSNick Fitzgerald } 840968952abSNick Fitzgerald 841968952abSNick Fitzgerald inst_data => unreachable!( 842968952abSNick Fitzgerald "should have handled all `is_return() == true` instructions above; \ 843968952abSNick Fitzgerald got {inst_data:?}" 844968952abSNick Fitzgerald ), 845968952abSNick Fitzgerald } 846968952abSNick Fitzgerald } 847968952abSNick Fitzgerald 848968952abSNick Fitzgerald /// An `InstructionMapper` implementation that remaps a callee instruction's 849968952abSNick Fitzgerald /// entity references to their new indices in the caller function. 850968952abSNick Fitzgerald struct InliningInstRemapper<'a> { 851968952abSNick Fitzgerald allocs: &'a InliningAllocs, 852968952abSNick Fitzgerald func: &'a mut ir::Function, 853968952abSNick Fitzgerald callee: &'a ir::Function, 854968952abSNick Fitzgerald entity_map: &'a EntityMap, 855968952abSNick Fitzgerald } 856968952abSNick Fitzgerald 857968952abSNick Fitzgerald impl<'a> ir::instructions::InstructionMapper for InliningInstRemapper<'a> { 858968952abSNick Fitzgerald fn map_value(&mut self, value: ir::Value) -> ir::Value { 859968952abSNick Fitzgerald self.allocs.get_inlined_value(self.callee, value).expect( 860968952abSNick Fitzgerald "defs come before uses; we should have already inlined all values \ 861968952abSNick Fitzgerald used by an instruction", 862968952abSNick Fitzgerald ) 863968952abSNick Fitzgerald } 864968952abSNick Fitzgerald 865968952abSNick Fitzgerald fn map_value_list(&mut self, value_list: ir::ValueList) -> ir::ValueList { 866968952abSNick Fitzgerald let mut inlined_list = ir::ValueList::new(); 867968952abSNick Fitzgerald for callee_val in value_list.as_slice(&self.callee.dfg.value_lists) { 868968952abSNick Fitzgerald let inlined_val = self.map_value(*callee_val); 869968952abSNick Fitzgerald inlined_list.push(inlined_val, &mut self.func.dfg.value_lists); 870968952abSNick Fitzgerald } 871968952abSNick Fitzgerald inlined_list 872968952abSNick Fitzgerald } 873968952abSNick Fitzgerald 874968952abSNick Fitzgerald fn map_global_value(&mut self, global_value: ir::GlobalValue) -> ir::GlobalValue { 875968952abSNick Fitzgerald self.entity_map.inlined_global_value(global_value) 876968952abSNick Fitzgerald } 877968952abSNick Fitzgerald 878968952abSNick Fitzgerald fn map_jump_table(&mut self, jump_table: ir::JumpTable) -> ir::JumpTable { 879968952abSNick Fitzgerald let inlined_default = 880968952abSNick Fitzgerald self.map_block_call(self.callee.dfg.jump_tables[jump_table].default_block()); 881968952abSNick Fitzgerald let inlined_table = self.callee.dfg.jump_tables[jump_table] 882968952abSNick Fitzgerald .as_slice() 883968952abSNick Fitzgerald .iter() 884968952abSNick Fitzgerald .map(|callee_block_call| self.map_block_call(*callee_block_call)) 885968952abSNick Fitzgerald .collect::<SmallBlockCallVec>(); 886968952abSNick Fitzgerald self.func 887968952abSNick Fitzgerald .dfg 888968952abSNick Fitzgerald .jump_tables 889968952abSNick Fitzgerald .push(ir::JumpTableData::new(inlined_default, &inlined_table)) 890968952abSNick Fitzgerald } 891968952abSNick Fitzgerald 892968952abSNick Fitzgerald fn map_exception_table(&mut self, exception_table: ir::ExceptionTable) -> ir::ExceptionTable { 893968952abSNick Fitzgerald let exception_table = &self.callee.dfg.exception_tables[exception_table]; 894968952abSNick Fitzgerald let inlined_sig_ref = self.map_sig_ref(exception_table.signature()); 895968952abSNick Fitzgerald let inlined_normal_return = self.map_block_call(*exception_table.normal_return()); 896968952abSNick Fitzgerald let inlined_table = exception_table 8974590076fSChris Fallin .items() 8984590076fSChris Fallin .map(|item| match item { 8994590076fSChris Fallin ExceptionTableItem::Tag(tag, block_call) => { 9004590076fSChris Fallin ExceptionTableItem::Tag(tag, self.map_block_call(block_call)) 9014590076fSChris Fallin } 9024590076fSChris Fallin ExceptionTableItem::Default(block_call) => { 9034590076fSChris Fallin ExceptionTableItem::Default(self.map_block_call(block_call)) 9044590076fSChris Fallin } 9054590076fSChris Fallin ExceptionTableItem::Context(value) => { 9064590076fSChris Fallin ExceptionTableItem::Context(self.map_value(value)) 9074590076fSChris Fallin } 9084590076fSChris Fallin }) 909968952abSNick Fitzgerald .collect::<SmallVec<[_; 8]>>(); 910968952abSNick Fitzgerald self.func 911968952abSNick Fitzgerald .dfg 912968952abSNick Fitzgerald .exception_tables 913968952abSNick Fitzgerald .push(ir::ExceptionTableData::new( 914968952abSNick Fitzgerald inlined_sig_ref, 915968952abSNick Fitzgerald inlined_normal_return, 916968952abSNick Fitzgerald inlined_table, 917968952abSNick Fitzgerald )) 918968952abSNick Fitzgerald } 919968952abSNick Fitzgerald 920968952abSNick Fitzgerald fn map_block_call(&mut self, block_call: ir::BlockCall) -> ir::BlockCall { 921968952abSNick Fitzgerald let callee_block = block_call.block(&self.callee.dfg.value_lists); 922968952abSNick Fitzgerald let inlined_block = self.entity_map.inlined_block(callee_block); 923968952abSNick Fitzgerald let args = block_call 924968952abSNick Fitzgerald .args(&self.callee.dfg.value_lists) 925968952abSNick Fitzgerald .map(|arg| match arg { 926968952abSNick Fitzgerald ir::BlockArg::Value(value) => self.map_value(value).into(), 927968952abSNick Fitzgerald ir::BlockArg::TryCallRet(_) | ir::BlockArg::TryCallExn(_) => arg, 928968952abSNick Fitzgerald }) 929968952abSNick Fitzgerald .collect::<SmallBlockArgVec>(); 930968952abSNick Fitzgerald ir::BlockCall::new(inlined_block, args, &mut self.func.dfg.value_lists) 931968952abSNick Fitzgerald } 932968952abSNick Fitzgerald 933968952abSNick Fitzgerald fn map_func_ref(&mut self, func_ref: ir::FuncRef) -> ir::FuncRef { 934968952abSNick Fitzgerald self.entity_map.inlined_func_ref(func_ref) 935968952abSNick Fitzgerald } 936968952abSNick Fitzgerald 937968952abSNick Fitzgerald fn map_sig_ref(&mut self, sig_ref: ir::SigRef) -> ir::SigRef { 938968952abSNick Fitzgerald self.entity_map.inlined_sig_ref(sig_ref) 939968952abSNick Fitzgerald } 940968952abSNick Fitzgerald 941968952abSNick Fitzgerald fn map_stack_slot(&mut self, stack_slot: ir::StackSlot) -> ir::StackSlot { 942968952abSNick Fitzgerald self.entity_map.inlined_stack_slot(stack_slot) 943968952abSNick Fitzgerald } 944968952abSNick Fitzgerald 945968952abSNick Fitzgerald fn map_dynamic_stack_slot( 946968952abSNick Fitzgerald &mut self, 947968952abSNick Fitzgerald dynamic_stack_slot: ir::DynamicStackSlot, 948968952abSNick Fitzgerald ) -> ir::DynamicStackSlot { 949968952abSNick Fitzgerald self.entity_map 950968952abSNick Fitzgerald .inlined_dynamic_stack_slot(dynamic_stack_slot) 951968952abSNick Fitzgerald } 952968952abSNick Fitzgerald 953968952abSNick Fitzgerald fn map_constant(&mut self, constant: ir::Constant) -> ir::Constant { 954968952abSNick Fitzgerald self.allocs 955968952abSNick Fitzgerald .constants 956968952abSNick Fitzgerald .get(constant) 957968952abSNick Fitzgerald .and_then(|o| o.expand()) 958968952abSNick Fitzgerald .expect("should have inlined all callee constants") 959968952abSNick Fitzgerald } 960968952abSNick Fitzgerald 961968952abSNick Fitzgerald fn map_immediate(&mut self, immediate: ir::Immediate) -> ir::Immediate { 962968952abSNick Fitzgerald self.entity_map.inlined_immediate(immediate) 963968952abSNick Fitzgerald } 964968952abSNick Fitzgerald } 965968952abSNick Fitzgerald 966968952abSNick Fitzgerald /// Inline the callee's layout into the caller's layout. 967*dcedcbf5SNick Fitzgerald /// 968*dcedcbf5SNick Fitzgerald /// Returns the last inlined block in the layout. 969968952abSNick Fitzgerald fn inline_block_layout( 970968952abSNick Fitzgerald func: &mut ir::Function, 971968952abSNick Fitzgerald call_block: ir::Block, 972968952abSNick Fitzgerald callee: &ir::Function, 973968952abSNick Fitzgerald entity_map: &EntityMap, 974*dcedcbf5SNick Fitzgerald ) -> ir::Block { 975968952abSNick Fitzgerald // Iterate over callee blocks in layout order, inserting their associated 976968952abSNick Fitzgerald // inlined block into the caller's layout. 977968952abSNick Fitzgerald let mut prev_inlined_block = call_block; 978968952abSNick Fitzgerald let mut next_callee_block = callee.layout.entry_block(); 979968952abSNick Fitzgerald while let Some(callee_block) = next_callee_block { 980968952abSNick Fitzgerald let inlined_block = entity_map.inlined_block(callee_block); 981968952abSNick Fitzgerald func.layout 982968952abSNick Fitzgerald .insert_block_after(inlined_block, prev_inlined_block); 983968952abSNick Fitzgerald 984968952abSNick Fitzgerald prev_inlined_block = inlined_block; 985968952abSNick Fitzgerald next_callee_block = callee.layout.next_block(callee_block); 986968952abSNick Fitzgerald } 987*dcedcbf5SNick Fitzgerald prev_inlined_block 988968952abSNick Fitzgerald } 989968952abSNick Fitzgerald 990968952abSNick Fitzgerald /// Split the call instruction's block just after the call instruction to create 991968952abSNick Fitzgerald /// the point where control-flow joins after the inlined callee "returns". 992968952abSNick Fitzgerald /// 993968952abSNick Fitzgerald /// Note that tail calls do not return to the caller and therefore do not have a 994968952abSNick Fitzgerald /// control-flow join point. 995968952abSNick Fitzgerald fn split_off_return_block( 996968952abSNick Fitzgerald func: &mut ir::Function, 997968952abSNick Fitzgerald call_inst: ir::Inst, 998968952abSNick Fitzgerald opcode: ir::Opcode, 999968952abSNick Fitzgerald callee: &ir::Function, 1000968952abSNick Fitzgerald ) -> Option<ir::Block> { 1001968952abSNick Fitzgerald // When the `call_inst` is not a block terminator, we need to split the 1002968952abSNick Fitzgerald // block. 1003968952abSNick Fitzgerald let return_block = func.layout.next_inst(call_inst).map(|next_inst| { 1004968952abSNick Fitzgerald let return_block = func.dfg.blocks.add(); 1005968952abSNick Fitzgerald func.layout.split_block(return_block, next_inst); 1006968952abSNick Fitzgerald 1007968952abSNick Fitzgerald // Add block parameters for each return value and alias the call 1008968952abSNick Fitzgerald // instruction's results to them. 1009968952abSNick Fitzgerald let old_results = 1010968952abSNick Fitzgerald SmallValueVec::from_iter(func.dfg.inst_results(call_inst).iter().copied()); 1011968952abSNick Fitzgerald debug_assert_eq!(old_results.len(), callee.signature.returns.len()); 1012968952abSNick Fitzgerald func.dfg.detach_inst_results(call_inst); 1013968952abSNick Fitzgerald for (abi, old_val) in callee.signature.returns.iter().zip(old_results) { 1014968952abSNick Fitzgerald debug_assert_eq!(abi.value_type, func.dfg.value_type(old_val)); 1015968952abSNick Fitzgerald let ret_param = func.dfg.append_block_param(return_block, abi.value_type); 1016968952abSNick Fitzgerald func.dfg.change_to_alias(old_val, ret_param); 1017968952abSNick Fitzgerald } 1018968952abSNick Fitzgerald 1019968952abSNick Fitzgerald return_block 1020968952abSNick Fitzgerald }); 1021968952abSNick Fitzgerald 1022968952abSNick Fitzgerald // When the `call_inst` is a block terminator, then it is either a 1023968952abSNick Fitzgerald // `return_call` or a `try_call`: 1024968952abSNick Fitzgerald // 1025968952abSNick Fitzgerald // * For `return_call`s, we don't have a control-flow join point, because 1026968952abSNick Fitzgerald // the caller permanently transfers control to the callee. 1027968952abSNick Fitzgerald // 1028968952abSNick Fitzgerald // * For `try_call`s, we probably already have a block for the control-flow 1029968952abSNick Fitzgerald // join point, but it isn't guaranteed: the `try_call` might ignore the 1030968952abSNick Fitzgerald // call's returns and not forward them to the normal-return block or it 1031968952abSNick Fitzgerald // might also pass additional arguments. We can only reuse the existing 1032968952abSNick Fitzgerald // normal-return block when the `try_call` forwards exactly our callee's 1033968952abSNick Fitzgerald // returns to that block (and therefore that block's parameter types also 1034968952abSNick Fitzgerald // exactly match the callee's return types). Otherwise, we must create a new 1035968952abSNick Fitzgerald // return block that forwards to the existing normal-return 1036968952abSNick Fitzgerald // block. (Elsewhere, at the end of inlining, we will also update any inlined 1037968952abSNick Fitzgerald // calls to forward any raised exceptions to the caller's exception table, 1038968952abSNick Fitzgerald // as necessary.) 1039968952abSNick Fitzgerald // 1040968952abSNick Fitzgerald // Finally, note that reusing the normal-return's target block is just an 1041968952abSNick Fitzgerald // optimization to emit a simpler CFG when we can, and is not 1042968952abSNick Fitzgerald // fundamentally required for correctness. We could always insert a 1043968952abSNick Fitzgerald // temporary block as our control-flow join point that then forwards to 1044968952abSNick Fitzgerald // the normal-return's target block. However, at the time of writing, 1045968952abSNick Fitzgerald // Cranelift doesn't currently do any jump-threading or branch 1046968952abSNick Fitzgerald // simplification in the mid-end, and removing unnecessary blocks in this 1047968952abSNick Fitzgerald // way can help some subsequent mid-end optimizations. If, in the future, 1048968952abSNick Fitzgerald // we gain support for jump-threading optimizations in the mid-end, we can 1049968952abSNick Fitzgerald // come back and simplify the below code a bit to always generate the 1050968952abSNick Fitzgerald // temporary block, and then rely on the subsequent optimizations to clean 1051968952abSNick Fitzgerald // everything up. 1052968952abSNick Fitzgerald debug_assert_eq!( 1053968952abSNick Fitzgerald return_block.is_none(), 1054968952abSNick Fitzgerald opcode == ir::Opcode::ReturnCall || opcode == ir::Opcode::TryCall, 1055968952abSNick Fitzgerald ); 1056968952abSNick Fitzgerald return_block.or_else(|| match func.dfg.insts[call_inst] { 1057968952abSNick Fitzgerald ir::InstructionData::TryCall { 1058968952abSNick Fitzgerald opcode: ir::Opcode::TryCall, 1059968952abSNick Fitzgerald args: _, 1060968952abSNick Fitzgerald func_ref: _, 1061968952abSNick Fitzgerald exception, 1062968952abSNick Fitzgerald } => { 1063968952abSNick Fitzgerald let normal_return = func.dfg.exception_tables[exception].normal_return(); 1064968952abSNick Fitzgerald let normal_return_block = normal_return.block(&func.dfg.value_lists); 1065968952abSNick Fitzgerald 1066968952abSNick Fitzgerald // Check to see if we can reuse the existing normal-return block. 1067968952abSNick Fitzgerald { 1068968952abSNick Fitzgerald let normal_return_args = normal_return.args(&func.dfg.value_lists); 1069968952abSNick Fitzgerald if normal_return_args.len() == callee.signature.returns.len() 1070968952abSNick Fitzgerald && normal_return_args.enumerate().all(|(i, arg)| { 1071968952abSNick Fitzgerald let i = u32::try_from(i).unwrap(); 1072968952abSNick Fitzgerald arg == ir::BlockArg::TryCallRet(i) 1073968952abSNick Fitzgerald }) 1074968952abSNick Fitzgerald { 1075968952abSNick Fitzgerald return Some(normal_return_block); 1076968952abSNick Fitzgerald } 1077968952abSNick Fitzgerald } 1078968952abSNick Fitzgerald 1079968952abSNick Fitzgerald // Okay, we cannot reuse the normal-return block. Create a new block 1080968952abSNick Fitzgerald // that has the expected block parameter types and have it jump to 1081968952abSNick Fitzgerald // the normal-return block. 1082968952abSNick Fitzgerald let return_block = func.dfg.blocks.add(); 1083968952abSNick Fitzgerald func.layout.insert_block(return_block, normal_return_block); 1084968952abSNick Fitzgerald 1085968952abSNick Fitzgerald let return_block_params = callee 1086968952abSNick Fitzgerald .signature 1087968952abSNick Fitzgerald .returns 1088968952abSNick Fitzgerald .iter() 1089968952abSNick Fitzgerald .map(|abi| func.dfg.append_block_param(return_block, abi.value_type)) 1090968952abSNick Fitzgerald .collect::<SmallValueVec>(); 1091968952abSNick Fitzgerald 1092968952abSNick Fitzgerald let normal_return_args = func.dfg.exception_tables[exception] 1093968952abSNick Fitzgerald .normal_return() 1094968952abSNick Fitzgerald .args(&func.dfg.value_lists) 1095968952abSNick Fitzgerald .collect::<SmallBlockArgVec>(); 1096968952abSNick Fitzgerald let jump_args = normal_return_args 1097968952abSNick Fitzgerald .into_iter() 1098968952abSNick Fitzgerald .map(|arg| match arg { 1099968952abSNick Fitzgerald ir::BlockArg::Value(value) => ir::BlockArg::Value(value), 1100968952abSNick Fitzgerald ir::BlockArg::TryCallRet(i) => { 1101968952abSNick Fitzgerald let i = usize::try_from(i).unwrap(); 1102968952abSNick Fitzgerald ir::BlockArg::Value(return_block_params[i]) 1103968952abSNick Fitzgerald } 1104968952abSNick Fitzgerald ir::BlockArg::TryCallExn(_) => { 1105968952abSNick Fitzgerald unreachable!("normal-return edges cannot use exceptional results") 1106968952abSNick Fitzgerald } 1107968952abSNick Fitzgerald }) 1108968952abSNick Fitzgerald .collect::<SmallBlockArgVec>(); 1109968952abSNick Fitzgerald 1110968952abSNick Fitzgerald let mut cursor = FuncCursor::new(func); 1111968952abSNick Fitzgerald cursor.goto_first_insertion_point(return_block); 1112968952abSNick Fitzgerald cursor.ins().jump(normal_return_block, &jump_args); 1113968952abSNick Fitzgerald 1114968952abSNick Fitzgerald Some(return_block) 1115968952abSNick Fitzgerald } 1116968952abSNick Fitzgerald _ => None, 1117968952abSNick Fitzgerald }) 1118968952abSNick Fitzgerald } 1119968952abSNick Fitzgerald 1120968952abSNick Fitzgerald /// Replace the caller's call instruction with a jump to the caller's inlined 1121968952abSNick Fitzgerald /// copy of the callee's entry block. 1122968952abSNick Fitzgerald /// 1123968952abSNick Fitzgerald /// Also associates the callee's parameters with the caller's arguments in our 1124968952abSNick Fitzgerald /// value map. 1125968952abSNick Fitzgerald /// 1126968952abSNick Fitzgerald /// Returns the caller's stack map entries, if any. 1127968952abSNick Fitzgerald fn replace_call_with_jump( 1128968952abSNick Fitzgerald allocs: &mut InliningAllocs, 1129968952abSNick Fitzgerald func: &mut ir::Function, 1130968952abSNick Fitzgerald call_inst: ir::Inst, 1131968952abSNick Fitzgerald callee: &ir::Function, 1132968952abSNick Fitzgerald entity_map: &EntityMap, 1133968952abSNick Fitzgerald ) -> Option<ir::UserStackMapEntryVec> { 1134968952abSNick Fitzgerald trace!("Replacing `call` with `jump`"); 1135968952abSNick Fitzgerald trace!( 1136968952abSNick Fitzgerald " --> call instruction: {call_inst:?}: {}", 1137968952abSNick Fitzgerald func.dfg.display_inst(call_inst) 1138968952abSNick Fitzgerald ); 1139968952abSNick Fitzgerald 1140968952abSNick Fitzgerald let callee_entry_block = callee 1141968952abSNick Fitzgerald .layout 1142968952abSNick Fitzgerald .entry_block() 1143968952abSNick Fitzgerald .expect("callee function should have an entry block"); 1144968952abSNick Fitzgerald let callee_param_values = callee.dfg.block_params(callee_entry_block); 1145968952abSNick Fitzgerald let caller_arg_values = SmallValueVec::from_iter(func.dfg.inst_args(call_inst).iter().copied()); 1146968952abSNick Fitzgerald debug_assert_eq!(callee_param_values.len(), caller_arg_values.len()); 1147968952abSNick Fitzgerald debug_assert_eq!(callee_param_values.len(), callee.signature.params.len()); 1148968952abSNick Fitzgerald for (abi, (callee_param_value, caller_arg_value)) in callee 1149968952abSNick Fitzgerald .signature 1150968952abSNick Fitzgerald .params 1151968952abSNick Fitzgerald .iter() 1152968952abSNick Fitzgerald .zip(callee_param_values.into_iter().zip(caller_arg_values)) 1153968952abSNick Fitzgerald { 1154968952abSNick Fitzgerald debug_assert_eq!(abi.value_type, callee.dfg.value_type(*callee_param_value)); 1155968952abSNick Fitzgerald debug_assert_eq!(abi.value_type, func.dfg.value_type(caller_arg_value)); 1156968952abSNick Fitzgerald allocs.set_inlined_value(callee, *callee_param_value, caller_arg_value); 1157968952abSNick Fitzgerald } 1158968952abSNick Fitzgerald 1159968952abSNick Fitzgerald // Replace the caller's call instruction with a jump to the caller's inlined 1160968952abSNick Fitzgerald // copy of the callee's entry block. 1161968952abSNick Fitzgerald // 1162968952abSNick Fitzgerald // Note that the call block dominates the inlined entry block (and also all 1163968952abSNick Fitzgerald // other inlined blocks) so we can reference the arguments directly, and do 1164968952abSNick Fitzgerald // not need to add block parameters to the inlined entry block. 1165968952abSNick Fitzgerald let inlined_entry_block = entity_map.inlined_block(callee_entry_block); 1166968952abSNick Fitzgerald func.dfg.replace(call_inst).jump(inlined_entry_block, &[]); 1167968952abSNick Fitzgerald trace!( 1168968952abSNick Fitzgerald " --> replaced with jump instruction: {call_inst:?}: {}", 1169968952abSNick Fitzgerald func.dfg.display_inst(call_inst) 1170968952abSNick Fitzgerald ); 1171968952abSNick Fitzgerald 1172968952abSNick Fitzgerald let stack_map_entries = func.dfg.take_user_stack_map_entries(call_inst); 1173968952abSNick Fitzgerald stack_map_entries 1174968952abSNick Fitzgerald } 1175968952abSNick Fitzgerald 1176968952abSNick Fitzgerald /// Keeps track of mapping callee entities to their associated inlined caller 1177968952abSNick Fitzgerald /// entities. 1178968952abSNick Fitzgerald #[derive(Default)] 1179968952abSNick Fitzgerald struct EntityMap { 1180968952abSNick Fitzgerald // Rather than doing an implicit, demand-based, DCE'ing translation of 1181968952abSNick Fitzgerald // entities, which would require maps from each callee entity to its 1182968952abSNick Fitzgerald // associated caller entity, we copy all entities into the caller, remember 1183968952abSNick Fitzgerald // each entity's initial offset, and then mapping from the callee to the 1184968952abSNick Fitzgerald // inlined caller entity is just adding that initial offset to the callee's 1185968952abSNick Fitzgerald // index. This should be both faster and simpler than the alternative. Most 1186968952abSNick Fitzgerald // of these sets are relatively small, and they rarely have too much dead 1187968952abSNick Fitzgerald // code in practice, so this is a good trade off. 1188968952abSNick Fitzgerald // 1189968952abSNick Fitzgerald // Note that there are a few kinds of entities that are excluded from the 1190968952abSNick Fitzgerald // `EntityMap`, and for which we do actually take the demand-based approach: 1191968952abSNick Fitzgerald // values and value lists being the notable ones. 1192968952abSNick Fitzgerald block_offset: Option<u32>, 1193968952abSNick Fitzgerald global_value_offset: Option<u32>, 1194968952abSNick Fitzgerald sig_ref_offset: Option<u32>, 1195968952abSNick Fitzgerald func_ref_offset: Option<u32>, 1196968952abSNick Fitzgerald stack_slot_offset: Option<u32>, 1197968952abSNick Fitzgerald dynamic_type_offset: Option<u32>, 1198968952abSNick Fitzgerald dynamic_stack_slot_offset: Option<u32>, 1199968952abSNick Fitzgerald immediate_offset: Option<u32>, 1200968952abSNick Fitzgerald } 1201968952abSNick Fitzgerald 1202968952abSNick Fitzgerald impl EntityMap { 1203968952abSNick Fitzgerald fn inlined_block(&self, callee_block: ir::Block) -> ir::Block { 1204968952abSNick Fitzgerald let offset = self 1205968952abSNick Fitzgerald .block_offset 1206968952abSNick Fitzgerald .expect("must create inlined `ir::Block`s before calling `EntityMap::inlined_block`"); 1207968952abSNick Fitzgerald ir::Block::from_u32(offset + callee_block.as_u32()) 1208968952abSNick Fitzgerald } 1209968952abSNick Fitzgerald 1210e3a607eaSNick Fitzgerald fn iter_inlined_blocks(&self, func: &ir::Function) -> impl Iterator<Item = ir::Block> + use<> { 1211e3a607eaSNick Fitzgerald let start = self.block_offset.expect( 1212e3a607eaSNick Fitzgerald "must create inlined `ir::Block`s before calling `EntityMap::iter_inlined_blocks`", 1213e3a607eaSNick Fitzgerald ); 1214e3a607eaSNick Fitzgerald 1215e3a607eaSNick Fitzgerald let end = func.dfg.blocks.len(); 1216e3a607eaSNick Fitzgerald let end = u32::try_from(end).unwrap(); 1217e3a607eaSNick Fitzgerald 1218e3a607eaSNick Fitzgerald (start..end).map(|i| ir::Block::from_u32(i)) 1219e3a607eaSNick Fitzgerald } 1220e3a607eaSNick Fitzgerald 1221968952abSNick Fitzgerald fn inlined_global_value(&self, callee_global_value: ir::GlobalValue) -> ir::GlobalValue { 1222968952abSNick Fitzgerald let offset = self 1223968952abSNick Fitzgerald .global_value_offset 1224968952abSNick Fitzgerald .expect("must create inlined `ir::GlobalValue`s before calling `EntityMap::inlined_global_value`"); 1225968952abSNick Fitzgerald ir::GlobalValue::from_u32(offset + callee_global_value.as_u32()) 1226968952abSNick Fitzgerald } 1227968952abSNick Fitzgerald 1228968952abSNick Fitzgerald fn inlined_sig_ref(&self, callee_sig_ref: ir::SigRef) -> ir::SigRef { 1229968952abSNick Fitzgerald let offset = self.sig_ref_offset.expect( 1230968952abSNick Fitzgerald "must create inlined `ir::SigRef`s before calling `EntityMap::inlined_sig_ref`", 1231968952abSNick Fitzgerald ); 1232968952abSNick Fitzgerald ir::SigRef::from_u32(offset + callee_sig_ref.as_u32()) 1233968952abSNick Fitzgerald } 1234968952abSNick Fitzgerald 1235968952abSNick Fitzgerald fn inlined_func_ref(&self, callee_func_ref: ir::FuncRef) -> ir::FuncRef { 1236968952abSNick Fitzgerald let offset = self.func_ref_offset.expect( 1237968952abSNick Fitzgerald "must create inlined `ir::FuncRef`s before calling `EntityMap::inlined_func_ref`", 1238968952abSNick Fitzgerald ); 1239968952abSNick Fitzgerald ir::FuncRef::from_u32(offset + callee_func_ref.as_u32()) 1240968952abSNick Fitzgerald } 1241968952abSNick Fitzgerald 1242968952abSNick Fitzgerald fn inlined_stack_slot(&self, callee_stack_slot: ir::StackSlot) -> ir::StackSlot { 1243968952abSNick Fitzgerald let offset = self.stack_slot_offset.expect( 1244968952abSNick Fitzgerald "must create inlined `ir::StackSlot`s before calling `EntityMap::inlined_stack_slot`", 1245968952abSNick Fitzgerald ); 1246968952abSNick Fitzgerald ir::StackSlot::from_u32(offset + callee_stack_slot.as_u32()) 1247968952abSNick Fitzgerald } 1248968952abSNick Fitzgerald 1249968952abSNick Fitzgerald fn inlined_dynamic_type(&self, callee_dynamic_type: ir::DynamicType) -> ir::DynamicType { 1250968952abSNick Fitzgerald let offset = self.dynamic_type_offset.expect( 1251968952abSNick Fitzgerald "must create inlined `ir::DynamicType`s before calling `EntityMap::inlined_dynamic_type`", 1252968952abSNick Fitzgerald ); 1253968952abSNick Fitzgerald ir::DynamicType::from_u32(offset + callee_dynamic_type.as_u32()) 1254968952abSNick Fitzgerald } 1255968952abSNick Fitzgerald 1256968952abSNick Fitzgerald fn inlined_dynamic_stack_slot( 1257968952abSNick Fitzgerald &self, 1258968952abSNick Fitzgerald callee_dynamic_stack_slot: ir::DynamicStackSlot, 1259968952abSNick Fitzgerald ) -> ir::DynamicStackSlot { 1260968952abSNick Fitzgerald let offset = self.dynamic_stack_slot_offset.expect( 1261968952abSNick Fitzgerald "must create inlined `ir::DynamicStackSlot`s before calling `EntityMap::inlined_dynamic_stack_slot`", 1262968952abSNick Fitzgerald ); 1263968952abSNick Fitzgerald ir::DynamicStackSlot::from_u32(offset + callee_dynamic_stack_slot.as_u32()) 1264968952abSNick Fitzgerald } 1265968952abSNick Fitzgerald 1266968952abSNick Fitzgerald fn inlined_immediate(&self, callee_immediate: ir::Immediate) -> ir::Immediate { 1267968952abSNick Fitzgerald let offset = self.immediate_offset.expect( 1268968952abSNick Fitzgerald "must create inlined `ir::Immediate`s before calling `EntityMap::inlined_immediate`", 1269968952abSNick Fitzgerald ); 1270968952abSNick Fitzgerald ir::Immediate::from_u32(offset + callee_immediate.as_u32()) 1271968952abSNick Fitzgerald } 1272968952abSNick Fitzgerald } 1273968952abSNick Fitzgerald 1274968952abSNick Fitzgerald /// Translate all of the callee's various entities into the caller, producing an 1275968952abSNick Fitzgerald /// `EntityMap` that can be used to translate callee entity references into 1276968952abSNick Fitzgerald /// inlined caller entity references. 1277968952abSNick Fitzgerald fn create_entities( 1278968952abSNick Fitzgerald allocs: &mut InliningAllocs, 1279968952abSNick Fitzgerald func: &mut ir::Function, 1280968952abSNick Fitzgerald callee: &ir::Function, 1281968952abSNick Fitzgerald ) -> EntityMap { 1282968952abSNick Fitzgerald let mut entity_map = EntityMap::default(); 1283968952abSNick Fitzgerald 1284968952abSNick Fitzgerald entity_map.block_offset = Some(create_blocks(allocs, func, callee)); 1285968952abSNick Fitzgerald entity_map.global_value_offset = Some(create_global_values(func, callee)); 1286968952abSNick Fitzgerald entity_map.sig_ref_offset = Some(create_sig_refs(func, callee)); 12874cbea5e8SNick Fitzgerald create_user_external_name_refs(allocs, func, callee); 12884cbea5e8SNick Fitzgerald entity_map.func_ref_offset = Some(create_func_refs(allocs, func, callee, &entity_map)); 1289968952abSNick Fitzgerald entity_map.stack_slot_offset = Some(create_stack_slots(func, callee)); 1290968952abSNick Fitzgerald entity_map.dynamic_type_offset = Some(create_dynamic_types(func, callee, &entity_map)); 1291968952abSNick Fitzgerald entity_map.dynamic_stack_slot_offset = 1292968952abSNick Fitzgerald Some(create_dynamic_stack_slots(func, callee, &entity_map)); 1293968952abSNick Fitzgerald entity_map.immediate_offset = Some(create_immediates(func, callee)); 1294968952abSNick Fitzgerald 1295968952abSNick Fitzgerald // `ir::ConstantData` is deduplicated, so we cannot use our offset scheme 1296968952abSNick Fitzgerald // for `ir::Constant`s. Nonetheless, we still insert them into the caller 1297968952abSNick Fitzgerald // now, at the same time as the rest of our entities. 1298968952abSNick Fitzgerald create_constants(allocs, func, callee); 1299968952abSNick Fitzgerald 1300968952abSNick Fitzgerald entity_map 1301968952abSNick Fitzgerald } 1302968952abSNick Fitzgerald 1303968952abSNick Fitzgerald /// Create inlined blocks in the caller for every block in the callee. 1304968952abSNick Fitzgerald fn create_blocks( 1305968952abSNick Fitzgerald allocs: &mut InliningAllocs, 1306968952abSNick Fitzgerald func: &mut ir::Function, 1307968952abSNick Fitzgerald callee: &ir::Function, 1308968952abSNick Fitzgerald ) -> u32 { 1309968952abSNick Fitzgerald let offset = func.dfg.blocks.len(); 1310968952abSNick Fitzgerald let offset = u32::try_from(offset).unwrap(); 1311968952abSNick Fitzgerald 1312968952abSNick Fitzgerald func.dfg.blocks.reserve(callee.dfg.blocks.len()); 1313968952abSNick Fitzgerald for callee_block in callee.dfg.blocks.iter() { 1314968952abSNick Fitzgerald let caller_block = func.dfg.blocks.add(); 1315968952abSNick Fitzgerald trace!("Callee {callee_block:?} = inlined {caller_block:?}"); 1316968952abSNick Fitzgerald 1317968952abSNick Fitzgerald if callee.layout.is_cold(callee_block) { 1318968952abSNick Fitzgerald func.layout.set_cold(caller_block); 1319968952abSNick Fitzgerald } 1320968952abSNick Fitzgerald 1321968952abSNick Fitzgerald // Note: the entry block does not need parameters because the only 1322968952abSNick Fitzgerald // predecessor is the call block and we associate the callee's 1323968952abSNick Fitzgerald // parameters with the caller's arguments directly. 1324968952abSNick Fitzgerald if callee.layout.entry_block() != Some(callee_block) { 1325968952abSNick Fitzgerald for callee_param in callee.dfg.blocks[callee_block].params(&callee.dfg.value_lists) { 1326968952abSNick Fitzgerald let ty = callee.dfg.value_type(*callee_param); 1327968952abSNick Fitzgerald let caller_param = func.dfg.append_block_param(caller_block, ty); 1328968952abSNick Fitzgerald 1329968952abSNick Fitzgerald allocs.set_inlined_value(callee, *callee_param, caller_param); 1330968952abSNick Fitzgerald } 1331968952abSNick Fitzgerald } 1332968952abSNick Fitzgerald } 1333968952abSNick Fitzgerald 1334968952abSNick Fitzgerald offset 1335968952abSNick Fitzgerald } 1336968952abSNick Fitzgerald 1337968952abSNick Fitzgerald /// Copy and translate global values from the callee into the caller. 1338968952abSNick Fitzgerald fn create_global_values(func: &mut ir::Function, callee: &ir::Function) -> u32 { 1339968952abSNick Fitzgerald let gv_offset = func.global_values.len(); 1340968952abSNick Fitzgerald let gv_offset = u32::try_from(gv_offset).unwrap(); 1341968952abSNick Fitzgerald 1342968952abSNick Fitzgerald func.global_values.reserve(callee.global_values.len()); 1343968952abSNick Fitzgerald for gv in callee.global_values.values() { 1344968952abSNick Fitzgerald func.global_values.push(match gv { 1345968952abSNick Fitzgerald // These kinds of global values reference other global values, so we 1346968952abSNick Fitzgerald // need to fixup that reference. 1347968952abSNick Fitzgerald ir::GlobalValueData::Load { 1348968952abSNick Fitzgerald base, 1349968952abSNick Fitzgerald offset, 1350968952abSNick Fitzgerald global_type, 1351968952abSNick Fitzgerald flags, 1352968952abSNick Fitzgerald } => ir::GlobalValueData::Load { 1353968952abSNick Fitzgerald base: ir::GlobalValue::from_u32(base.as_u32() + gv_offset), 1354968952abSNick Fitzgerald offset: *offset, 1355968952abSNick Fitzgerald global_type: *global_type, 1356968952abSNick Fitzgerald flags: *flags, 1357968952abSNick Fitzgerald }, 1358968952abSNick Fitzgerald ir::GlobalValueData::IAddImm { 1359968952abSNick Fitzgerald base, 1360968952abSNick Fitzgerald offset, 1361968952abSNick Fitzgerald global_type, 1362968952abSNick Fitzgerald } => ir::GlobalValueData::IAddImm { 1363968952abSNick Fitzgerald base: ir::GlobalValue::from_u32(base.as_u32() + gv_offset), 1364968952abSNick Fitzgerald offset: *offset, 1365968952abSNick Fitzgerald global_type: *global_type, 1366968952abSNick Fitzgerald }, 1367968952abSNick Fitzgerald 1368968952abSNick Fitzgerald // These kinds of global values do not reference other global 1369968952abSNick Fitzgerald // values, so we can just clone them. 1370968952abSNick Fitzgerald ir::GlobalValueData::VMContext 1371968952abSNick Fitzgerald | ir::GlobalValueData::Symbol { .. } 1372968952abSNick Fitzgerald | ir::GlobalValueData::DynScaleTargetConst { .. } => gv.clone(), 1373968952abSNick Fitzgerald }); 1374968952abSNick Fitzgerald } 1375968952abSNick Fitzgerald 1376968952abSNick Fitzgerald gv_offset 1377968952abSNick Fitzgerald } 1378968952abSNick Fitzgerald 1379968952abSNick Fitzgerald /// Copy `ir::SigRef`s from the callee into the caller. 1380968952abSNick Fitzgerald fn create_sig_refs(func: &mut ir::Function, callee: &ir::Function) -> u32 { 1381968952abSNick Fitzgerald let offset = func.dfg.signatures.len(); 1382968952abSNick Fitzgerald let offset = u32::try_from(offset).unwrap(); 1383968952abSNick Fitzgerald 1384968952abSNick Fitzgerald func.dfg.signatures.reserve(callee.dfg.signatures.len()); 1385968952abSNick Fitzgerald for sig in callee.dfg.signatures.values() { 1386968952abSNick Fitzgerald func.dfg.signatures.push(sig.clone()); 1387968952abSNick Fitzgerald } 1388968952abSNick Fitzgerald 1389968952abSNick Fitzgerald offset 1390968952abSNick Fitzgerald } 1391968952abSNick Fitzgerald 13924cbea5e8SNick Fitzgerald fn create_user_external_name_refs( 13934cbea5e8SNick Fitzgerald allocs: &mut InliningAllocs, 13944cbea5e8SNick Fitzgerald func: &mut ir::Function, 13954cbea5e8SNick Fitzgerald callee: &ir::Function, 13964cbea5e8SNick Fitzgerald ) { 13974cbea5e8SNick Fitzgerald for (callee_named_func_ref, name) in callee.params.user_named_funcs().iter() { 13984cbea5e8SNick Fitzgerald let caller_named_func_ref = func.declare_imported_user_function(name.clone()); 13994cbea5e8SNick Fitzgerald allocs.user_external_name_refs[callee_named_func_ref] = Some(caller_named_func_ref).into(); 14004cbea5e8SNick Fitzgerald } 14014cbea5e8SNick Fitzgerald } 14024cbea5e8SNick Fitzgerald 1403968952abSNick Fitzgerald /// Translate `ir::FuncRef`s from the callee into the caller. 14044cbea5e8SNick Fitzgerald fn create_func_refs( 14054cbea5e8SNick Fitzgerald allocs: &InliningAllocs, 14064cbea5e8SNick Fitzgerald func: &mut ir::Function, 14074cbea5e8SNick Fitzgerald callee: &ir::Function, 14084cbea5e8SNick Fitzgerald entity_map: &EntityMap, 14094cbea5e8SNick Fitzgerald ) -> u32 { 1410968952abSNick Fitzgerald let offset = func.dfg.ext_funcs.len(); 1411968952abSNick Fitzgerald let offset = u32::try_from(offset).unwrap(); 1412968952abSNick Fitzgerald 1413968952abSNick Fitzgerald func.dfg.ext_funcs.reserve(callee.dfg.ext_funcs.len()); 1414968952abSNick Fitzgerald for ir::ExtFuncData { 1415968952abSNick Fitzgerald name, 1416968952abSNick Fitzgerald signature, 1417968952abSNick Fitzgerald colocated, 1418968952abSNick Fitzgerald } in callee.dfg.ext_funcs.values() 1419968952abSNick Fitzgerald { 1420968952abSNick Fitzgerald func.dfg.ext_funcs.push(ir::ExtFuncData { 14214cbea5e8SNick Fitzgerald name: match name { 14224cbea5e8SNick Fitzgerald ir::ExternalName::User(name_ref) => { 14234cbea5e8SNick Fitzgerald ir::ExternalName::User(allocs.user_external_name_refs[*name_ref].expect( 14244cbea5e8SNick Fitzgerald "should have translated all `ir::UserExternalNameRef`s before translating \ 14254cbea5e8SNick Fitzgerald `ir::FuncRef`s", 14264cbea5e8SNick Fitzgerald )) 14274cbea5e8SNick Fitzgerald } 14284cbea5e8SNick Fitzgerald ir::ExternalName::TestCase(_) 14294cbea5e8SNick Fitzgerald | ir::ExternalName::LibCall(_) 14304cbea5e8SNick Fitzgerald | ir::ExternalName::KnownSymbol(_) => name.clone(), 14314cbea5e8SNick Fitzgerald }, 1432968952abSNick Fitzgerald signature: entity_map.inlined_sig_ref(*signature), 1433968952abSNick Fitzgerald colocated: *colocated, 1434968952abSNick Fitzgerald }); 1435968952abSNick Fitzgerald } 1436968952abSNick Fitzgerald 1437968952abSNick Fitzgerald offset 1438968952abSNick Fitzgerald } 1439968952abSNick Fitzgerald 1440968952abSNick Fitzgerald /// Copy stack slots from the callee into the caller. 1441968952abSNick Fitzgerald fn create_stack_slots(func: &mut ir::Function, callee: &ir::Function) -> u32 { 1442968952abSNick Fitzgerald let offset = func.sized_stack_slots.len(); 1443968952abSNick Fitzgerald let offset = u32::try_from(offset).unwrap(); 1444968952abSNick Fitzgerald 1445968952abSNick Fitzgerald func.sized_stack_slots 1446968952abSNick Fitzgerald .reserve(callee.sized_stack_slots.len()); 1447968952abSNick Fitzgerald for slot in callee.sized_stack_slots.values() { 1448968952abSNick Fitzgerald func.sized_stack_slots.push(slot.clone()); 1449968952abSNick Fitzgerald } 1450968952abSNick Fitzgerald 1451968952abSNick Fitzgerald offset 1452968952abSNick Fitzgerald } 1453968952abSNick Fitzgerald 1454968952abSNick Fitzgerald /// Copy dynamic types from the callee into the caller. 1455968952abSNick Fitzgerald fn create_dynamic_types( 1456968952abSNick Fitzgerald func: &mut ir::Function, 1457968952abSNick Fitzgerald callee: &ir::Function, 1458968952abSNick Fitzgerald entity_map: &EntityMap, 1459968952abSNick Fitzgerald ) -> u32 { 1460968952abSNick Fitzgerald let offset = func.dynamic_stack_slots.len(); 1461968952abSNick Fitzgerald let offset = u32::try_from(offset).unwrap(); 1462968952abSNick Fitzgerald 1463968952abSNick Fitzgerald func.dfg 1464968952abSNick Fitzgerald .dynamic_types 1465968952abSNick Fitzgerald .reserve(callee.dfg.dynamic_types.len()); 1466968952abSNick Fitzgerald for ir::DynamicTypeData { 1467968952abSNick Fitzgerald base_vector_ty, 1468968952abSNick Fitzgerald dynamic_scale, 1469968952abSNick Fitzgerald } in callee.dfg.dynamic_types.values() 1470968952abSNick Fitzgerald { 1471968952abSNick Fitzgerald func.dfg.dynamic_types.push(ir::DynamicTypeData { 1472968952abSNick Fitzgerald base_vector_ty: *base_vector_ty, 1473968952abSNick Fitzgerald dynamic_scale: entity_map.inlined_global_value(*dynamic_scale), 1474968952abSNick Fitzgerald }); 1475968952abSNick Fitzgerald } 1476968952abSNick Fitzgerald 1477968952abSNick Fitzgerald offset 1478968952abSNick Fitzgerald } 1479968952abSNick Fitzgerald 1480968952abSNick Fitzgerald /// Copy dynamic stack slots from the callee into the caller. 1481968952abSNick Fitzgerald fn create_dynamic_stack_slots( 1482968952abSNick Fitzgerald func: &mut ir::Function, 1483968952abSNick Fitzgerald callee: &ir::Function, 1484968952abSNick Fitzgerald entity_map: &EntityMap, 1485968952abSNick Fitzgerald ) -> u32 { 1486968952abSNick Fitzgerald let offset = func.dynamic_stack_slots.len(); 1487968952abSNick Fitzgerald let offset = u32::try_from(offset).unwrap(); 1488968952abSNick Fitzgerald 1489968952abSNick Fitzgerald func.dynamic_stack_slots 1490968952abSNick Fitzgerald .reserve(callee.dynamic_stack_slots.len()); 1491968952abSNick Fitzgerald for ir::DynamicStackSlotData { kind, dyn_ty } in callee.dynamic_stack_slots.values() { 1492968952abSNick Fitzgerald func.dynamic_stack_slots.push(ir::DynamicStackSlotData { 1493968952abSNick Fitzgerald kind: *kind, 1494968952abSNick Fitzgerald dyn_ty: entity_map.inlined_dynamic_type(*dyn_ty), 1495968952abSNick Fitzgerald }); 1496968952abSNick Fitzgerald } 1497968952abSNick Fitzgerald 1498968952abSNick Fitzgerald offset 1499968952abSNick Fitzgerald } 1500968952abSNick Fitzgerald 1501968952abSNick Fitzgerald /// Copy immediates from the callee into the caller. 1502968952abSNick Fitzgerald fn create_immediates(func: &mut ir::Function, callee: &ir::Function) -> u32 { 1503968952abSNick Fitzgerald let offset = func.dfg.immediates.len(); 1504968952abSNick Fitzgerald let offset = u32::try_from(offset).unwrap(); 1505968952abSNick Fitzgerald 1506968952abSNick Fitzgerald func.dfg.immediates.reserve(callee.dfg.immediates.len()); 1507968952abSNick Fitzgerald for imm in callee.dfg.immediates.values() { 1508968952abSNick Fitzgerald func.dfg.immediates.push(imm.clone()); 1509968952abSNick Fitzgerald } 1510968952abSNick Fitzgerald 1511968952abSNick Fitzgerald offset 1512968952abSNick Fitzgerald } 1513968952abSNick Fitzgerald 1514968952abSNick Fitzgerald /// Copy constants from the callee into the caller. 1515968952abSNick Fitzgerald fn create_constants(allocs: &mut InliningAllocs, func: &mut ir::Function, callee: &ir::Function) { 1516968952abSNick Fitzgerald for (callee_constant, data) in callee.dfg.constants.iter() { 1517968952abSNick Fitzgerald let inlined_constant = func.dfg.constants.insert(data.clone()); 1518968952abSNick Fitzgerald allocs.constants[*callee_constant] = Some(inlined_constant).into(); 1519968952abSNick Fitzgerald } 1520968952abSNick Fitzgerald } 1521