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