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,
40968952abSNick Fitzgerald     /// Inline the call, using this function as the body of the callee.
41968952abSNick Fitzgerald     ///
42968952abSNick Fitzgerald     /// It is the `Inline` implementor's responsibility to ensure that this
43968952abSNick Fitzgerald     /// function is the correct callee. Providing the wrong function may result
44968952abSNick Fitzgerald     /// in panics during compilation or incorrect runtime behavior.
45968952abSNick Fitzgerald     Inline(Cow<'a, ir::Function>),
46968952abSNick Fitzgerald }
47968952abSNick Fitzgerald 
48968952abSNick Fitzgerald /// A trait for directing Cranelift whether to inline a particular call or not.
49968952abSNick Fitzgerald ///
50968952abSNick Fitzgerald /// Used in combination with the [`Context::inline`][crate::Context::inline]
51968952abSNick Fitzgerald /// method.
52968952abSNick Fitzgerald pub trait Inline {
53968952abSNick Fitzgerald     /// A hook invoked for each direct call instruction in a function, whose
54968952abSNick Fitzgerald     /// result determines whether Cranelift should inline a given call.
55968952abSNick Fitzgerald     ///
56968952abSNick Fitzgerald     /// The Cranelift user is responsible for defining their own hueristics and
57968952abSNick Fitzgerald     /// deciding whether inlining the call is beneficial.
58968952abSNick Fitzgerald     ///
59968952abSNick Fitzgerald     /// When returning a function and directing Cranelift to inline its body
60968952abSNick Fitzgerald     /// into the call site, the `Inline` implementer must ensure the following:
61968952abSNick Fitzgerald     ///
62968952abSNick Fitzgerald     /// * The returned function's signature exactly matches the `callee`
63968952abSNick Fitzgerald     ///   `FuncRef`'s signature.
64968952abSNick Fitzgerald     ///
65968952abSNick Fitzgerald     /// * The returned function must be legalized.
66968952abSNick Fitzgerald     ///
67968952abSNick Fitzgerald     /// * The returned function must be valid (i.e. it must pass the CLIF
68968952abSNick Fitzgerald     ///   verifier).
69968952abSNick Fitzgerald     ///
70968952abSNick Fitzgerald     /// * The returned function is a correct and valid implementation of the
71968952abSNick Fitzgerald     ///   `callee` according to your language's semantics.
72968952abSNick Fitzgerald     ///
73968952abSNick Fitzgerald     /// Failure to uphold these invariants may result in panics during
74968952abSNick Fitzgerald     /// compilation or incorrect runtime behavior in the generated code.
75968952abSNick Fitzgerald     fn inline(
76*3ecb338eSNick Fitzgerald         &mut self,
77968952abSNick Fitzgerald         caller: &ir::Function,
78968952abSNick Fitzgerald         call_inst: ir::Inst,
79968952abSNick Fitzgerald         call_opcode: ir::Opcode,
80968952abSNick Fitzgerald         callee: ir::FuncRef,
81968952abSNick Fitzgerald         call_args: &[ir::Value],
82968952abSNick Fitzgerald     ) -> InlineCommand<'_>;
83968952abSNick Fitzgerald }
84968952abSNick Fitzgerald 
85*3ecb338eSNick Fitzgerald impl<'a, T> Inline for &'a mut T
86968952abSNick Fitzgerald where
87968952abSNick Fitzgerald     T: Inline,
88968952abSNick Fitzgerald {
89968952abSNick Fitzgerald     fn inline(
90*3ecb338eSNick Fitzgerald         &mut self,
91968952abSNick Fitzgerald         caller: &ir::Function,
92968952abSNick Fitzgerald         inst: ir::Inst,
93968952abSNick Fitzgerald         opcode: ir::Opcode,
94968952abSNick Fitzgerald         callee: ir::FuncRef,
95968952abSNick Fitzgerald         args: &[ir::Value],
96968952abSNick Fitzgerald     ) -> InlineCommand<'_> {
97968952abSNick Fitzgerald         (*self).inline(caller, inst, opcode, callee, args)
98968952abSNick Fitzgerald     }
99968952abSNick Fitzgerald }
100968952abSNick Fitzgerald 
101968952abSNick Fitzgerald /// Walk the given function, invoke the `Inline` implementation for each call
102968952abSNick Fitzgerald /// instruction, and inline the callee when directed to do so.
103968952abSNick Fitzgerald ///
104968952abSNick Fitzgerald /// Returns whether any call was inlined.
105*3ecb338eSNick Fitzgerald pub(crate) fn do_inlining(
106*3ecb338eSNick Fitzgerald     func: &mut ir::Function,
107*3ecb338eSNick Fitzgerald     mut inliner: impl Inline,
108*3ecb338eSNick Fitzgerald ) -> CodegenResult<bool> {
109*3ecb338eSNick Fitzgerald     trace!("function {} before inlining: {}", func.name, func);
110*3ecb338eSNick Fitzgerald 
111968952abSNick Fitzgerald     let mut inlined_any = false;
112968952abSNick Fitzgerald     let mut allocs = InliningAllocs::default();
113968952abSNick Fitzgerald 
114968952abSNick Fitzgerald     let mut cursor = FuncCursor::new(func);
115968952abSNick Fitzgerald     while let Some(block) = cursor.next_block() {
116968952abSNick Fitzgerald         // Always keep track of our previous cursor position. After we inline a
117968952abSNick Fitzgerald         // call, replacing the current position with an arbitrary sub-CFG, we
118968952abSNick Fitzgerald         // back up to this previous position. This makes sure our cursor is
119968952abSNick Fitzgerald         // always at a position that is inserted in the layout and also enables
120968952abSNick Fitzgerald         // multi-level inlining, if desired by the user, where we consider any
121968952abSNick Fitzgerald         // newly-inlined call instructions for further inlining.
122968952abSNick Fitzgerald         let mut prev_pos;
123968952abSNick Fitzgerald 
124968952abSNick Fitzgerald         while let Some(inst) = {
125968952abSNick Fitzgerald             prev_pos = cursor.position();
126968952abSNick Fitzgerald             cursor.next_inst()
127968952abSNick Fitzgerald         } {
128968952abSNick Fitzgerald             match cursor.func.dfg.insts[inst] {
129968952abSNick Fitzgerald                 ir::InstructionData::Call {
130968952abSNick Fitzgerald                     opcode: opcode @ ir::Opcode::Call | opcode @ ir::Opcode::ReturnCall,
131968952abSNick Fitzgerald                     args: _,
132968952abSNick Fitzgerald                     func_ref,
133968952abSNick Fitzgerald                 } => {
134968952abSNick Fitzgerald                     let args = cursor.func.dfg.inst_args(inst);
135968952abSNick Fitzgerald                     match inliner.inline(&cursor.func, inst, opcode, func_ref, args) {
136968952abSNick Fitzgerald                         InlineCommand::KeepCall => continue,
137968952abSNick Fitzgerald                         InlineCommand::Inline(callee) => {
138968952abSNick Fitzgerald                             inline_one(
139968952abSNick Fitzgerald                                 &mut allocs,
140968952abSNick Fitzgerald                                 cursor.func,
141968952abSNick Fitzgerald                                 func_ref,
142968952abSNick Fitzgerald                                 block,
143968952abSNick Fitzgerald                                 inst,
144968952abSNick Fitzgerald                                 opcode,
145968952abSNick Fitzgerald                                 &callee,
146968952abSNick Fitzgerald                                 None,
147968952abSNick Fitzgerald                             );
148968952abSNick Fitzgerald                             inlined_any = true;
149968952abSNick Fitzgerald                             cursor.set_position(prev_pos);
150968952abSNick Fitzgerald                         }
151968952abSNick Fitzgerald                     }
152968952abSNick Fitzgerald                 }
153968952abSNick Fitzgerald                 ir::InstructionData::TryCall {
154968952abSNick Fitzgerald                     opcode: opcode @ ir::Opcode::TryCall,
155968952abSNick Fitzgerald                     args: _,
156968952abSNick Fitzgerald                     func_ref,
157968952abSNick Fitzgerald                     exception,
158968952abSNick Fitzgerald                 } => {
159968952abSNick Fitzgerald                     let args = cursor.func.dfg.inst_args(inst);
160968952abSNick Fitzgerald                     match inliner.inline(&cursor.func, inst, opcode, func_ref, args) {
161968952abSNick Fitzgerald                         InlineCommand::KeepCall => continue,
162968952abSNick Fitzgerald                         InlineCommand::Inline(callee) => {
163968952abSNick Fitzgerald                             inline_one(
164968952abSNick Fitzgerald                                 &mut allocs,
165968952abSNick Fitzgerald                                 cursor.func,
166968952abSNick Fitzgerald                                 func_ref,
167968952abSNick Fitzgerald                                 block,
168968952abSNick Fitzgerald                                 inst,
169968952abSNick Fitzgerald                                 opcode,
170968952abSNick Fitzgerald                                 &callee,
171968952abSNick Fitzgerald                                 Some(exception),
172968952abSNick Fitzgerald                             );
173968952abSNick Fitzgerald                             inlined_any = true;
174968952abSNick Fitzgerald                             cursor.set_position(prev_pos);
175968952abSNick Fitzgerald                         }
176968952abSNick Fitzgerald                     }
177968952abSNick Fitzgerald                 }
178968952abSNick Fitzgerald                 _ => continue,
179968952abSNick Fitzgerald             }
180968952abSNick Fitzgerald         }
181968952abSNick Fitzgerald     }
182968952abSNick Fitzgerald 
183*3ecb338eSNick Fitzgerald     if inlined_any {
184*3ecb338eSNick Fitzgerald         trace!("function {} after inlining: {}", func.name, func);
185*3ecb338eSNick Fitzgerald     } else {
186*3ecb338eSNick Fitzgerald         trace!("function {} did not have any callees inlined", func.name);
187*3ecb338eSNick Fitzgerald     }
188*3ecb338eSNick Fitzgerald 
189968952abSNick Fitzgerald     Ok(inlined_any)
190968952abSNick Fitzgerald }
191968952abSNick Fitzgerald 
192968952abSNick Fitzgerald #[derive(Default)]
193968952abSNick Fitzgerald struct InliningAllocs {
194968952abSNick Fitzgerald     /// Map from callee value to inlined caller value.
195968952abSNick Fitzgerald     values: SecondaryMap<ir::Value, PackedOption<ir::Value>>,
196968952abSNick Fitzgerald 
197968952abSNick Fitzgerald     /// Map from callee constant to inlined caller constant.
198968952abSNick Fitzgerald     constants: SecondaryMap<ir::Constant, PackedOption<ir::Constant>>,
199968952abSNick Fitzgerald 
200968952abSNick Fitzgerald     /// The set of _caller_ inlined call instructions that need exception table
201968952abSNick Fitzgerald     /// fixups at the end of inlining.
202968952abSNick Fitzgerald     ///
203968952abSNick Fitzgerald     /// This includes all kinds of non-returning calls, not just the literal
204968952abSNick Fitzgerald     /// `call` instruction: `call_indirect`, `try_call`, `try_call_indirect`,
205968952abSNick Fitzgerald     /// etc... However, it does not include `return_call` and
206968952abSNick Fitzgerald     /// `return_call_indirect` instructions because the caller cannot catch
207968952abSNick Fitzgerald     /// exceptions that those calls throw because the caller is no longer on the
208968952abSNick Fitzgerald     /// stack as soon as they are executed.
209968952abSNick Fitzgerald     ///
210968952abSNick Fitzgerald     /// Note: this is a simple `Vec`, and not an `EntitySet`, because it is very
211968952abSNick Fitzgerald     /// sparse: most of the caller's instructions are not inlined call
212968952abSNick Fitzgerald     /// instructions. Additionally, we require deterministic iteration order and
213968952abSNick Fitzgerald     /// do not require set-membership testing, so a hash set is not a good
214968952abSNick Fitzgerald     /// choice either.
215968952abSNick Fitzgerald     calls_needing_exception_table_fixup: Vec<ir::Inst>,
216968952abSNick Fitzgerald }
217968952abSNick Fitzgerald 
218968952abSNick Fitzgerald impl InliningAllocs {
219968952abSNick Fitzgerald     fn reset(&mut self, callee: &ir::Function) {
220968952abSNick Fitzgerald         let InliningAllocs {
221968952abSNick Fitzgerald             values,
222968952abSNick Fitzgerald             constants,
223968952abSNick Fitzgerald             calls_needing_exception_table_fixup,
224968952abSNick Fitzgerald         } = self;
225968952abSNick Fitzgerald 
226968952abSNick Fitzgerald         values.clear();
227968952abSNick Fitzgerald         values.resize(callee.dfg.len_values());
228968952abSNick Fitzgerald 
229968952abSNick Fitzgerald         constants.clear();
230968952abSNick Fitzgerald         constants.resize(callee.dfg.constants.len());
231968952abSNick Fitzgerald 
232968952abSNick Fitzgerald         // Note: We do not reserve capacity for
233968952abSNick Fitzgerald         // `calls_needing_exception_table_fixup` because it is a sparse set and
234968952abSNick Fitzgerald         // we don't know how large it needs to be ahead of time.
235968952abSNick Fitzgerald         calls_needing_exception_table_fixup.clear();
236968952abSNick Fitzgerald     }
237968952abSNick Fitzgerald 
238968952abSNick Fitzgerald     fn set_inlined_value(
239968952abSNick Fitzgerald         &mut self,
240968952abSNick Fitzgerald         callee: &ir::Function,
241968952abSNick Fitzgerald         callee_val: ir::Value,
242968952abSNick Fitzgerald         inlined_val: ir::Value,
243968952abSNick Fitzgerald     ) {
244968952abSNick Fitzgerald         trace!("  --> callee {callee_val:?} = inlined {inlined_val:?}");
245968952abSNick Fitzgerald         debug_assert!(self.values[callee_val].is_none());
246968952abSNick Fitzgerald         let resolved_callee_val = callee.dfg.resolve_aliases(callee_val);
247968952abSNick Fitzgerald         debug_assert!(self.values[resolved_callee_val].is_none());
248968952abSNick Fitzgerald         self.values[resolved_callee_val] = Some(inlined_val).into();
249968952abSNick Fitzgerald     }
250968952abSNick Fitzgerald 
251968952abSNick Fitzgerald     fn get_inlined_value(&self, callee: &ir::Function, callee_val: ir::Value) -> Option<ir::Value> {
252968952abSNick Fitzgerald         let resolved_callee_val = callee.dfg.resolve_aliases(callee_val);
253968952abSNick Fitzgerald         self.values[resolved_callee_val].expand()
254968952abSNick Fitzgerald     }
255968952abSNick Fitzgerald }
256968952abSNick Fitzgerald 
257968952abSNick Fitzgerald /// Inline one particular function call.
258968952abSNick Fitzgerald fn inline_one(
259968952abSNick Fitzgerald     allocs: &mut InliningAllocs,
260968952abSNick Fitzgerald     func: &mut ir::Function,
261968952abSNick Fitzgerald     callee_func_ref: ir::FuncRef,
262968952abSNick Fitzgerald     call_block: ir::Block,
263968952abSNick Fitzgerald     call_inst: ir::Inst,
264968952abSNick Fitzgerald     call_opcode: ir::Opcode,
265968952abSNick Fitzgerald     callee: &ir::Function,
266968952abSNick Fitzgerald     call_exception_table: Option<ir::ExceptionTable>,
267968952abSNick Fitzgerald ) {
268968952abSNick Fitzgerald     trace!(
269968952abSNick Fitzgerald         "Inlining call {call_inst:?}: {}\n\
270968952abSNick Fitzgerald          with callee = {callee:?}",
271968952abSNick Fitzgerald         func.dfg.display_inst(call_inst)
272968952abSNick Fitzgerald     );
273968952abSNick Fitzgerald 
274968952abSNick Fitzgerald     // Type check callee signature.
275968952abSNick Fitzgerald     let expected_callee_sig = func.dfg.ext_funcs[callee_func_ref].signature;
276968952abSNick Fitzgerald     let expected_callee_sig = &func.dfg.signatures[expected_callee_sig];
277968952abSNick Fitzgerald     assert_eq!(expected_callee_sig, &callee.signature);
278968952abSNick Fitzgerald 
279968952abSNick Fitzgerald     allocs.reset(callee);
280968952abSNick Fitzgerald 
281968952abSNick Fitzgerald     // First, append various callee entity arenas to the end of the caller's
282968952abSNick Fitzgerald     // entity arenas.
283968952abSNick Fitzgerald     let entity_map = create_entities(allocs, func, callee);
284968952abSNick Fitzgerald 
285968952abSNick Fitzgerald     // Inlined prologue: split the call instruction's block at the point of the
286968952abSNick Fitzgerald     // call and replace the call with a jump.
287968952abSNick Fitzgerald     let return_block = split_off_return_block(func, call_inst, call_opcode, callee);
288968952abSNick Fitzgerald     let call_stack_map = replace_call_with_jump(allocs, func, call_inst, callee, &entity_map);
289968952abSNick Fitzgerald 
290968952abSNick Fitzgerald     // Prepare for translating the actual instructions by inserting the inlined
291968952abSNick Fitzgerald     // blocks into the caller's layout in the same order that they appear in the
292968952abSNick Fitzgerald     // callee.
293968952abSNick Fitzgerald     inline_block_layout(func, call_block, callee, &entity_map);
294968952abSNick Fitzgerald 
295968952abSNick Fitzgerald     // Translate each instruction from the callee into the caller,
296968952abSNick Fitzgerald     // appending them to their associated block in the caller.
297968952abSNick Fitzgerald     //
298968952abSNick Fitzgerald     // Note that we iterate over the callee with a pre-order traversal so that
299968952abSNick Fitzgerald     // we see value defs before uses.
300968952abSNick Fitzgerald     for callee_block in Dfs::new().pre_order_iter(callee) {
301968952abSNick Fitzgerald         let inlined_block = entity_map.inlined_block(callee_block);
302968952abSNick Fitzgerald         trace!(
303968952abSNick Fitzgerald             "Processing instructions in callee block {callee_block:?} (inlined block {inlined_block:?}"
304968952abSNick Fitzgerald         );
305968952abSNick Fitzgerald 
306968952abSNick Fitzgerald         let mut next_callee_inst = callee.layout.first_inst(callee_block);
307968952abSNick Fitzgerald         while let Some(callee_inst) = next_callee_inst {
308968952abSNick Fitzgerald             trace!(
309968952abSNick Fitzgerald                 "Processing callee instruction {callee_inst:?}: {}",
310968952abSNick Fitzgerald                 callee.dfg.display_inst(callee_inst)
311968952abSNick Fitzgerald             );
312968952abSNick Fitzgerald 
313968952abSNick Fitzgerald             assert_ne!(
314968952abSNick Fitzgerald                 callee.dfg.insts[callee_inst].opcode(),
315968952abSNick Fitzgerald                 ir::Opcode::GlobalValue,
316968952abSNick Fitzgerald                 "callee must already be legalized, we shouldn't see any `global_value` \
317968952abSNick Fitzgerald                  instructions when inlining; found {callee_inst:?}: {}",
318968952abSNick Fitzgerald                 callee.dfg.display_inst(callee_inst)
319968952abSNick Fitzgerald             );
320968952abSNick Fitzgerald 
321968952abSNick Fitzgerald             // Remap the callee instruction's entities and insert it into the
322968952abSNick Fitzgerald             // caller's DFG.
323968952abSNick Fitzgerald             let inlined_inst_data = callee.dfg.insts[callee_inst].map(InliningInstRemapper {
324968952abSNick Fitzgerald                 allocs: &allocs,
325968952abSNick Fitzgerald                 func,
326968952abSNick Fitzgerald                 callee,
327968952abSNick Fitzgerald                 entity_map: &entity_map,
328968952abSNick Fitzgerald             });
329968952abSNick Fitzgerald             let inlined_inst = func.dfg.make_inst(inlined_inst_data);
330968952abSNick Fitzgerald             func.layout.append_inst(inlined_inst, inlined_block);
331968952abSNick Fitzgerald 
332968952abSNick Fitzgerald             let opcode = callee.dfg.insts[callee_inst].opcode();
333968952abSNick Fitzgerald             if opcode.is_return() {
334968952abSNick Fitzgerald                 // Instructions that return do not define any values, so we
335968952abSNick Fitzgerald                 // don't need to worry about that, but we do need to fix them up
336968952abSNick Fitzgerald                 // so that they return by jumping to our control-flow join
337968952abSNick Fitzgerald                 // block, rather than returning from the caller.
338968952abSNick Fitzgerald                 if let Some(return_block) = return_block {
339968952abSNick Fitzgerald                     fixup_inst_that_returns(
340968952abSNick Fitzgerald                         allocs,
341968952abSNick Fitzgerald                         func,
342968952abSNick Fitzgerald                         callee,
343968952abSNick Fitzgerald                         &entity_map,
344968952abSNick Fitzgerald                         call_opcode,
345968952abSNick Fitzgerald                         inlined_inst,
346968952abSNick Fitzgerald                         callee_inst,
347968952abSNick Fitzgerald                         return_block,
348968952abSNick Fitzgerald                         call_stack_map.as_ref().map(|es| &**es),
349968952abSNick Fitzgerald                     );
350968952abSNick Fitzgerald                 } else {
351968952abSNick Fitzgerald                     // If we are inlining a callee that was invoked via
352968952abSNick Fitzgerald                     // `return_call`, we leave inlined return instructions
353968952abSNick Fitzgerald                     // as-is: there is no logical caller frame on the stack to
354968952abSNick Fitzgerald                     // continue to.
355968952abSNick Fitzgerald                     debug_assert_eq!(call_opcode, ir::Opcode::ReturnCall);
356968952abSNick Fitzgerald                 }
357968952abSNick Fitzgerald             } else {
358968952abSNick Fitzgerald                 // Make the instruction's result values.
359968952abSNick Fitzgerald                 let ctrl_typevar = callee.dfg.ctrl_typevar(callee_inst);
360968952abSNick Fitzgerald                 func.dfg.make_inst_results(inlined_inst, ctrl_typevar);
361968952abSNick Fitzgerald 
362968952abSNick Fitzgerald                 // Update the value map for this instruction's defs.
363968952abSNick Fitzgerald                 let callee_results = callee.dfg.inst_results(callee_inst);
364968952abSNick Fitzgerald                 let inlined_results = func.dfg.inst_results(inlined_inst);
365968952abSNick Fitzgerald                 debug_assert_eq!(callee_results.len(), inlined_results.len());
366968952abSNick Fitzgerald                 for (callee_val, inlined_val) in callee_results.iter().zip(inlined_results) {
367968952abSNick Fitzgerald                     allocs.set_inlined_value(callee, *callee_val, *inlined_val);
368968952abSNick Fitzgerald                 }
369968952abSNick Fitzgerald 
370968952abSNick Fitzgerald                 if opcode.is_call() {
371968952abSNick Fitzgerald                     append_stack_map_entries(
372968952abSNick Fitzgerald                         func,
373968952abSNick Fitzgerald                         callee,
374968952abSNick Fitzgerald                         &entity_map,
375968952abSNick Fitzgerald                         call_stack_map.as_deref(),
376968952abSNick Fitzgerald                         inlined_inst,
377968952abSNick Fitzgerald                         callee_inst,
378968952abSNick Fitzgerald                     );
379968952abSNick Fitzgerald 
380968952abSNick Fitzgerald                     // When we are inlining a `try_call` call site, we need to merge
381968952abSNick Fitzgerald                     // the call site's exception table into the inlined calls'
382968952abSNick Fitzgerald                     // exception tables. This can involve rewriting regular `call`s
383968952abSNick Fitzgerald                     // into `try_call`s, which requires mutating the CFG because
384968952abSNick Fitzgerald                     // `try_call` is a block terminator. However, we can't mutate
385968952abSNick Fitzgerald                     // the CFG in the middle of this traversal because we rely on
386968952abSNick Fitzgerald                     // the existence of a one-to-one mapping between the callee
387968952abSNick Fitzgerald                     // layout and the inlined layout. Instead, we record the set of
388968952abSNick Fitzgerald                     // inlined call instructions that will need fixing up, and
389968952abSNick Fitzgerald                     // perform that possibly-CFG-mutating exception table merging in
390968952abSNick Fitzgerald                     // a follow up pass, when we no longer rely on that one-to-one
391968952abSNick Fitzgerald                     // layout mapping.
392968952abSNick Fitzgerald                     debug_assert_eq!(
393968952abSNick Fitzgerald                         call_opcode == ir::Opcode::TryCall,
394968952abSNick Fitzgerald                         call_exception_table.is_some()
395968952abSNick Fitzgerald                     );
396968952abSNick Fitzgerald                     if call_opcode == ir::Opcode::TryCall {
397968952abSNick Fitzgerald                         allocs
398968952abSNick Fitzgerald                             .calls_needing_exception_table_fixup
399968952abSNick Fitzgerald                             .push(inlined_inst);
400968952abSNick Fitzgerald                     }
401968952abSNick Fitzgerald                 }
402968952abSNick Fitzgerald             }
403968952abSNick Fitzgerald 
404968952abSNick Fitzgerald             trace!(
405968952abSNick Fitzgerald                 "  --> inserted inlined instruction {inlined_inst:?}: {}",
406968952abSNick Fitzgerald                 func.dfg.display_inst(inlined_inst)
407968952abSNick Fitzgerald             );
408968952abSNick Fitzgerald 
409968952abSNick Fitzgerald             next_callee_inst = callee.layout.next_inst(callee_inst);
410968952abSNick Fitzgerald         }
411968952abSNick Fitzgerald     }
412968952abSNick Fitzgerald 
413e3a607eaSNick Fitzgerald     // We copied *all* callee blocks into the caller's layout, but only copied
414e3a607eaSNick Fitzgerald     // the callee instructions in *reachable* callee blocks into the caller's
415e3a607eaSNick Fitzgerald     // associated blocks. Therefore, any *unreachable* blocks are empty in the
416e3a607eaSNick Fitzgerald     // caller, which is invalid CLIF because all blocks must end in a
417e3a607eaSNick Fitzgerald     // terminator, so do a quick pass over the inlined blocks and remove any
418e3a607eaSNick Fitzgerald     // empty blocks from the caller's layout.
419e3a607eaSNick Fitzgerald     for block in entity_map.iter_inlined_blocks(func) {
420e3a607eaSNick Fitzgerald         if func.layout.first_inst(block).is_none() {
421e3a607eaSNick Fitzgerald             func.layout.remove_block(block);
422e3a607eaSNick Fitzgerald         }
423e3a607eaSNick Fitzgerald     }
424e3a607eaSNick Fitzgerald 
425968952abSNick Fitzgerald     // Final step: fixup the exception tables of any inlined calls when we are
426968952abSNick Fitzgerald     // inlining a `try_call` site.
427968952abSNick Fitzgerald     //
428968952abSNick Fitzgerald     // Subtly, this requires rewriting non-catching `call[_indirect]`
429968952abSNick Fitzgerald     // instructions into `try_call[_indirect]` instructions so that exceptions
430968952abSNick Fitzgerald     // that unwound through the original callee frame and were caught by the
431968952abSNick Fitzgerald     // caller's `try_call` do not unwind past this inlined frame. And turning a
432968952abSNick Fitzgerald     // `call` into a `try_call` mutates the CFG, breaking our one-to-one mapping
433968952abSNick Fitzgerald     // between callee blocks and inlined blocks, so we delay these fixups to
434968952abSNick Fitzgerald     // this final step, when we no longer rely on that mapping.
435968952abSNick Fitzgerald     debug_assert!(
436968952abSNick Fitzgerald         allocs.calls_needing_exception_table_fixup.is_empty() || call_exception_table.is_some()
437968952abSNick Fitzgerald     );
438968952abSNick Fitzgerald     debug_assert_eq!(
439968952abSNick Fitzgerald         call_opcode == ir::Opcode::TryCall,
440968952abSNick Fitzgerald         call_exception_table.is_some()
441968952abSNick Fitzgerald     );
442968952abSNick Fitzgerald     if let Some(call_exception_table) = call_exception_table {
443968952abSNick Fitzgerald         fixup_inlined_call_exception_tables(allocs, func, call_exception_table);
444968952abSNick Fitzgerald     }
445968952abSNick Fitzgerald }
446968952abSNick Fitzgerald 
447968952abSNick Fitzgerald /// Append stack map entries from the caller and callee to the given inlined
448968952abSNick Fitzgerald /// instruction.
449968952abSNick Fitzgerald fn append_stack_map_entries(
450968952abSNick Fitzgerald     func: &mut ir::Function,
451968952abSNick Fitzgerald     callee: &ir::Function,
452968952abSNick Fitzgerald     entity_map: &EntityMap,
453968952abSNick Fitzgerald     call_stack_map: Option<&[ir::UserStackMapEntry]>,
454968952abSNick Fitzgerald     inlined_inst: ir::Inst,
455968952abSNick Fitzgerald     callee_inst: ir::Inst,
456968952abSNick Fitzgerald ) {
457968952abSNick Fitzgerald     // Add the caller's stack map to this call. These entries
458968952abSNick Fitzgerald     // already refer to caller entities and do not need further
459968952abSNick Fitzgerald     // translation.
460968952abSNick Fitzgerald     func.dfg.append_user_stack_map_entries(
461968952abSNick Fitzgerald         inlined_inst,
462968952abSNick Fitzgerald         call_stack_map
463968952abSNick Fitzgerald             .iter()
464968952abSNick Fitzgerald             .flat_map(|entries| entries.iter().cloned()),
465968952abSNick Fitzgerald     );
466968952abSNick Fitzgerald 
467968952abSNick Fitzgerald     // Append the callee's stack map to this call. These entries
468968952abSNick Fitzgerald     // refer to callee entities and therefore do require
469968952abSNick Fitzgerald     // translation into the caller's index space.
470968952abSNick Fitzgerald     func.dfg.append_user_stack_map_entries(
471968952abSNick Fitzgerald         inlined_inst,
472968952abSNick Fitzgerald         callee
473968952abSNick Fitzgerald             .dfg
474968952abSNick Fitzgerald             .user_stack_map_entries(callee_inst)
475968952abSNick Fitzgerald             .iter()
476968952abSNick Fitzgerald             .flat_map(|entries| entries.iter())
477968952abSNick Fitzgerald             .map(|entry| ir::UserStackMapEntry {
478968952abSNick Fitzgerald                 ty: entry.ty,
479968952abSNick Fitzgerald                 slot: entity_map.inlined_stack_slot(entry.slot),
480968952abSNick Fitzgerald                 offset: entry.offset,
481968952abSNick Fitzgerald             }),
482968952abSNick Fitzgerald     );
483968952abSNick Fitzgerald }
484968952abSNick Fitzgerald 
485968952abSNick Fitzgerald /// Create or update the exception tables for any inlined call instructions:
486968952abSNick Fitzgerald /// when inlining at a `try_call` site, we must forward our exceptional edges
487968952abSNick Fitzgerald /// into each inlined call instruction.
488968952abSNick Fitzgerald fn fixup_inlined_call_exception_tables(
489968952abSNick Fitzgerald     allocs: &mut InliningAllocs,
490968952abSNick Fitzgerald     func: &mut ir::Function,
491968952abSNick Fitzgerald     call_exception_table: ir::ExceptionTable,
492968952abSNick Fitzgerald ) {
493968952abSNick Fitzgerald     // Split a block at a `call[_indirect]` instruction, detach the
494968952abSNick Fitzgerald     // instruction's results, and alias them to the new block's parameters.
495968952abSNick Fitzgerald     let split_block_for_new_try_call = |func: &mut ir::Function, inst: ir::Inst| -> ir::Block {
496968952abSNick Fitzgerald         debug_assert!(func.dfg.insts[inst].opcode().is_call());
497968952abSNick Fitzgerald         debug_assert!(!func.dfg.insts[inst].opcode().is_terminator());
498968952abSNick Fitzgerald 
499968952abSNick Fitzgerald         // Split the block.
500968952abSNick Fitzgerald         let next_inst = func
501968952abSNick Fitzgerald             .layout
502968952abSNick Fitzgerald             .next_inst(inst)
503968952abSNick Fitzgerald             .expect("inst is not a terminator, should have a successor");
504968952abSNick Fitzgerald         let new_block = func.dfg.blocks.add();
505968952abSNick Fitzgerald         func.layout.split_block(new_block, next_inst);
506968952abSNick Fitzgerald 
507968952abSNick Fitzgerald         // `try_call[_indirect]` instructions do not define values themselves;
508968952abSNick Fitzgerald         // the normal-return block has parameters for the results. So remove
509968952abSNick Fitzgerald         // this instruction's results, create an associated block parameter for
510968952abSNick Fitzgerald         // each of them, and alias them to the new block parameter.
511968952abSNick Fitzgerald         let old_results = SmallValueVec::from_iter(func.dfg.inst_results(inst).iter().copied());
512968952abSNick Fitzgerald         func.dfg.detach_inst_results(inst);
513968952abSNick Fitzgerald         for old_result in old_results {
514968952abSNick Fitzgerald             let ty = func.dfg.value_type(old_result);
515968952abSNick Fitzgerald             let new_block_param = func.dfg.append_block_param(new_block, ty);
516968952abSNick Fitzgerald             func.dfg.change_to_alias(old_result, new_block_param);
517968952abSNick Fitzgerald         }
518968952abSNick Fitzgerald 
519968952abSNick Fitzgerald         new_block
520968952abSNick Fitzgerald     };
521968952abSNick Fitzgerald 
522968952abSNick Fitzgerald     // Clone the caller's exception table, updating it for use in the current
523968952abSNick Fitzgerald     // `call[_indirect]` instruction as it becomes a `try_call[_indirect]`.
524968952abSNick Fitzgerald     let clone_exception_table_for_this_call = |func: &mut ir::Function,
525968952abSNick Fitzgerald                                                signature: ir::SigRef,
526968952abSNick Fitzgerald                                                new_block: ir::Block|
527968952abSNick Fitzgerald      -> ir::ExceptionTable {
528968952abSNick Fitzgerald         let mut exception = func.stencil.dfg.exception_tables[call_exception_table]
529968952abSNick Fitzgerald             .deep_clone(&mut func.stencil.dfg.value_lists);
530968952abSNick Fitzgerald 
531968952abSNick Fitzgerald         *exception.signature_mut() = signature;
532968952abSNick Fitzgerald 
533968952abSNick Fitzgerald         let returns_len = func.dfg.signatures[signature].returns.len();
534968952abSNick Fitzgerald         let returns_len = u32::try_from(returns_len).unwrap();
535968952abSNick Fitzgerald 
536968952abSNick Fitzgerald         *exception.normal_return_mut() = ir::BlockCall::new(
537968952abSNick Fitzgerald             new_block,
538968952abSNick Fitzgerald             (0..returns_len).map(|i| ir::BlockArg::TryCallRet(i)),
539968952abSNick Fitzgerald             &mut func.dfg.value_lists,
540968952abSNick Fitzgerald         );
541968952abSNick Fitzgerald 
542968952abSNick Fitzgerald         func.dfg.exception_tables.push(exception)
543968952abSNick Fitzgerald     };
544968952abSNick Fitzgerald 
545968952abSNick Fitzgerald     for inst in allocs.calls_needing_exception_table_fixup.drain(..) {
546968952abSNick Fitzgerald         debug_assert!(func.dfg.insts[inst].opcode().is_call());
547968952abSNick Fitzgerald         debug_assert!(!func.dfg.insts[inst].opcode().is_return());
548968952abSNick Fitzgerald         match func.dfg.insts[inst] {
549968952abSNick Fitzgerald             //     current_block:
550968952abSNick Fitzgerald             //         preds...
551968952abSNick Fitzgerald             //         rets... = call f(args...)
552968952abSNick Fitzgerald             //         succs...
553968952abSNick Fitzgerald             //
554968952abSNick Fitzgerald             // becomes
555968952abSNick Fitzgerald             //
556968952abSNick Fitzgerald             //     current_block:
557968952abSNick Fitzgerald             //         preds...
558968952abSNick Fitzgerald             //         try_call f(args...), new_block(rets...), [call_exception_table...]
559968952abSNick Fitzgerald             //     new_block(rets...):
560968952abSNick Fitzgerald             //         succs...
561968952abSNick Fitzgerald             ir::InstructionData::Call {
562968952abSNick Fitzgerald                 opcode: ir::Opcode::Call,
563968952abSNick Fitzgerald                 args,
564968952abSNick Fitzgerald                 func_ref,
565968952abSNick Fitzgerald             } => {
566968952abSNick Fitzgerald                 let new_block = split_block_for_new_try_call(func, inst);
567968952abSNick Fitzgerald                 let signature = func.dfg.ext_funcs[func_ref].signature;
568968952abSNick Fitzgerald                 let exception = clone_exception_table_for_this_call(func, signature, new_block);
569968952abSNick Fitzgerald                 func.dfg.insts[inst] = ir::InstructionData::TryCall {
570968952abSNick Fitzgerald                     opcode: ir::Opcode::TryCall,
571968952abSNick Fitzgerald                     args,
572968952abSNick Fitzgerald                     func_ref,
573968952abSNick Fitzgerald                     exception,
574968952abSNick Fitzgerald                 };
575968952abSNick Fitzgerald             }
576968952abSNick Fitzgerald 
577968952abSNick Fitzgerald             //     current_block:
578968952abSNick Fitzgerald             //         preds...
579968952abSNick Fitzgerald             //         rets... = call_indirect sig, val(args...)
580968952abSNick Fitzgerald             //         succs...
581968952abSNick Fitzgerald             //
582968952abSNick Fitzgerald             // becomes
583968952abSNick Fitzgerald             //
584968952abSNick Fitzgerald             //     current_block:
585968952abSNick Fitzgerald             //         preds...
586968952abSNick Fitzgerald             //         try_call_indirect sig, val(args...), new_block(rets...), [call_exception_table...]
587968952abSNick Fitzgerald             //     new_block(rets...):
588968952abSNick Fitzgerald             //         succs...
589968952abSNick Fitzgerald             ir::InstructionData::CallIndirect {
590968952abSNick Fitzgerald                 opcode: ir::Opcode::CallIndirect,
591968952abSNick Fitzgerald                 args,
592968952abSNick Fitzgerald                 sig_ref,
593968952abSNick Fitzgerald             } => {
594968952abSNick Fitzgerald                 let new_block = split_block_for_new_try_call(func, inst);
595968952abSNick Fitzgerald                 let exception = clone_exception_table_for_this_call(func, sig_ref, new_block);
596968952abSNick Fitzgerald                 func.dfg.insts[inst] = ir::InstructionData::TryCallIndirect {
597968952abSNick Fitzgerald                     opcode: ir::Opcode::TryCallIndirect,
598968952abSNick Fitzgerald                     args,
599968952abSNick Fitzgerald                     exception,
600968952abSNick Fitzgerald                 };
601968952abSNick Fitzgerald             }
602968952abSNick Fitzgerald 
603968952abSNick Fitzgerald             // For `try_call[_indirect]` instructions, we just need to merge the
604968952abSNick Fitzgerald             // exception tables.
605968952abSNick Fitzgerald             ir::InstructionData::TryCall {
606968952abSNick Fitzgerald                 opcode: ir::Opcode::TryCall,
607968952abSNick Fitzgerald                 exception,
608968952abSNick Fitzgerald                 ..
609968952abSNick Fitzgerald             }
610968952abSNick Fitzgerald             | ir::InstructionData::TryCallIndirect {
611968952abSNick Fitzgerald                 opcode: ir::Opcode::TryCallIndirect,
612968952abSNick Fitzgerald                 exception,
613968952abSNick Fitzgerald                 ..
614968952abSNick Fitzgerald             } => {
6154590076fSChris Fallin                 // Construct a new exception table that consists of
6164590076fSChris Fallin                 // the inlined instruction's exception table match
6174590076fSChris Fallin                 // sequence, with the inlining site's exception table
6184590076fSChris Fallin                 // appended. This will ensure that the first-match
6194590076fSChris Fallin                 // semantics emulates the original behavior of
6204590076fSChris Fallin                 // matching in the inner frame first.
6214590076fSChris Fallin                 let sig = func.dfg.exception_tables[exception].signature();
6224590076fSChris Fallin                 let normal_return = *func.dfg.exception_tables[exception].normal_return();
6234590076fSChris Fallin                 let exception_data = ExceptionTableData::new(
6244590076fSChris Fallin                     sig,
6254590076fSChris Fallin                     normal_return,
626968952abSNick Fitzgerald                     func.dfg.exception_tables[exception]
6274590076fSChris Fallin                         .items()
6284590076fSChris Fallin                         .chain(func.dfg.exception_tables[call_exception_table].items()),
6294590076fSChris Fallin                 )
6304590076fSChris Fallin                 .deep_clone(&mut func.dfg.value_lists);
631968952abSNick Fitzgerald 
6324590076fSChris Fallin                 func.dfg.exception_tables[exception] = exception_data;
633968952abSNick Fitzgerald             }
634968952abSNick Fitzgerald 
635968952abSNick Fitzgerald             otherwise => unreachable!("unknown non-return call instruction: {otherwise:?}"),
636968952abSNick Fitzgerald         }
637968952abSNick Fitzgerald     }
638968952abSNick Fitzgerald }
639968952abSNick Fitzgerald 
640968952abSNick Fitzgerald /// After having created an inlined version of a callee instruction that returns
641968952abSNick Fitzgerald /// in the caller, we need to fix it up so that it doesn't actually return
642968952abSNick Fitzgerald /// (since we are already in the caller's frame) and instead just jumps to the
643968952abSNick Fitzgerald /// control-flow join point.
644968952abSNick Fitzgerald fn fixup_inst_that_returns(
645968952abSNick Fitzgerald     allocs: &mut InliningAllocs,
646968952abSNick Fitzgerald     func: &mut ir::Function,
647968952abSNick Fitzgerald     callee: &ir::Function,
648968952abSNick Fitzgerald     entity_map: &EntityMap,
649968952abSNick Fitzgerald     call_opcode: ir::Opcode,
650968952abSNick Fitzgerald     inlined_inst: ir::Inst,
651968952abSNick Fitzgerald     callee_inst: ir::Inst,
652968952abSNick Fitzgerald     return_block: ir::Block,
653968952abSNick Fitzgerald     call_stack_map: Option<&[ir::UserStackMapEntry]>,
654968952abSNick Fitzgerald ) {
655968952abSNick Fitzgerald     debug_assert!(func.dfg.insts[inlined_inst].opcode().is_return());
656968952abSNick Fitzgerald     match func.dfg.insts[inlined_inst] {
657968952abSNick Fitzgerald         //     return rets...
658968952abSNick Fitzgerald         //
659968952abSNick Fitzgerald         // becomes
660968952abSNick Fitzgerald         //
661968952abSNick Fitzgerald         //     jump return_block(rets...)
662968952abSNick Fitzgerald         ir::InstructionData::MultiAry {
663968952abSNick Fitzgerald             opcode: ir::Opcode::Return,
664968952abSNick Fitzgerald             args,
665968952abSNick Fitzgerald         } => {
666968952abSNick Fitzgerald             let rets = SmallBlockArgVec::from_iter(
667968952abSNick Fitzgerald                 args.as_slice(&func.dfg.value_lists)
668968952abSNick Fitzgerald                     .iter()
669968952abSNick Fitzgerald                     .copied()
670968952abSNick Fitzgerald                     .map(|v| v.into()),
671968952abSNick Fitzgerald             );
672968952abSNick Fitzgerald             func.dfg.replace(inlined_inst).jump(return_block, &rets);
673968952abSNick Fitzgerald         }
674968952abSNick Fitzgerald 
675968952abSNick Fitzgerald         //     return_call f(args...)
676968952abSNick Fitzgerald         //
677968952abSNick Fitzgerald         // becomes
678968952abSNick Fitzgerald         //
679968952abSNick Fitzgerald         //     rets... = call f(args...)
680968952abSNick Fitzgerald         //     jump return_block(rets...)
681968952abSNick Fitzgerald         ir::InstructionData::Call {
682968952abSNick Fitzgerald             opcode: ir::Opcode::ReturnCall,
683968952abSNick Fitzgerald             args,
684968952abSNick Fitzgerald             func_ref,
685968952abSNick Fitzgerald         } => {
686968952abSNick Fitzgerald             func.dfg.insts[inlined_inst] = ir::InstructionData::Call {
687968952abSNick Fitzgerald                 opcode: ir::Opcode::Call,
688968952abSNick Fitzgerald                 args,
689968952abSNick Fitzgerald                 func_ref,
690968952abSNick Fitzgerald             };
691968952abSNick Fitzgerald             func.dfg.make_inst_results(inlined_inst, ir::types::INVALID);
692968952abSNick Fitzgerald 
693968952abSNick Fitzgerald             append_stack_map_entries(
694968952abSNick Fitzgerald                 func,
695968952abSNick Fitzgerald                 callee,
696968952abSNick Fitzgerald                 &entity_map,
697968952abSNick Fitzgerald                 call_stack_map,
698968952abSNick Fitzgerald                 inlined_inst,
699968952abSNick Fitzgerald                 callee_inst,
700968952abSNick Fitzgerald             );
701968952abSNick Fitzgerald 
702968952abSNick Fitzgerald             let rets = SmallBlockArgVec::from_iter(
703968952abSNick Fitzgerald                 func.dfg
704968952abSNick Fitzgerald                     .inst_results(inlined_inst)
705968952abSNick Fitzgerald                     .iter()
706968952abSNick Fitzgerald                     .copied()
707968952abSNick Fitzgerald                     .map(|v| v.into()),
708968952abSNick Fitzgerald             );
709968952abSNick Fitzgerald             let mut cursor = FuncCursor::new(func);
710968952abSNick Fitzgerald             cursor.goto_after_inst(inlined_inst);
711968952abSNick Fitzgerald             cursor.ins().jump(return_block, &rets);
712968952abSNick Fitzgerald 
713968952abSNick Fitzgerald             if call_opcode == ir::Opcode::TryCall {
714968952abSNick Fitzgerald                 allocs
715968952abSNick Fitzgerald                     .calls_needing_exception_table_fixup
716968952abSNick Fitzgerald                     .push(inlined_inst);
717968952abSNick Fitzgerald             }
718968952abSNick Fitzgerald         }
719968952abSNick Fitzgerald 
720968952abSNick Fitzgerald         //     return_call_indirect val(args...)
721968952abSNick Fitzgerald         //
722968952abSNick Fitzgerald         // becomes
723968952abSNick Fitzgerald         //
724968952abSNick Fitzgerald         //     rets... = call_indirect val(args...)
725968952abSNick Fitzgerald         //     jump return_block(rets...)
726968952abSNick Fitzgerald         ir::InstructionData::CallIndirect {
727968952abSNick Fitzgerald             opcode: ir::Opcode::ReturnCallIndirect,
728968952abSNick Fitzgerald             args,
729968952abSNick Fitzgerald             sig_ref,
730968952abSNick Fitzgerald         } => {
731968952abSNick Fitzgerald             func.dfg.insts[inlined_inst] = ir::InstructionData::CallIndirect {
732968952abSNick Fitzgerald                 opcode: ir::Opcode::CallIndirect,
733968952abSNick Fitzgerald                 args,
734968952abSNick Fitzgerald                 sig_ref,
735968952abSNick Fitzgerald             };
736968952abSNick Fitzgerald             func.dfg.make_inst_results(inlined_inst, ir::types::INVALID);
737968952abSNick Fitzgerald 
738968952abSNick Fitzgerald             append_stack_map_entries(
739968952abSNick Fitzgerald                 func,
740968952abSNick Fitzgerald                 callee,
741968952abSNick Fitzgerald                 &entity_map,
742968952abSNick Fitzgerald                 call_stack_map,
743968952abSNick Fitzgerald                 inlined_inst,
744968952abSNick Fitzgerald                 callee_inst,
745968952abSNick Fitzgerald             );
746968952abSNick Fitzgerald 
747968952abSNick Fitzgerald             let rets = SmallBlockArgVec::from_iter(
748968952abSNick Fitzgerald                 func.dfg
749968952abSNick Fitzgerald                     .inst_results(inlined_inst)
750968952abSNick Fitzgerald                     .iter()
751968952abSNick Fitzgerald                     .copied()
752968952abSNick Fitzgerald                     .map(|v| v.into()),
753968952abSNick Fitzgerald             );
754968952abSNick Fitzgerald             let mut cursor = FuncCursor::new(func);
755968952abSNick Fitzgerald             cursor.goto_after_inst(inlined_inst);
756968952abSNick Fitzgerald             cursor.ins().jump(return_block, &rets);
757968952abSNick Fitzgerald 
758968952abSNick Fitzgerald             if call_opcode == ir::Opcode::TryCall {
759968952abSNick Fitzgerald                 allocs
760968952abSNick Fitzgerald                     .calls_needing_exception_table_fixup
761968952abSNick Fitzgerald                     .push(inlined_inst);
762968952abSNick Fitzgerald             }
763968952abSNick Fitzgerald         }
764968952abSNick Fitzgerald 
765968952abSNick Fitzgerald         inst_data => unreachable!(
766968952abSNick Fitzgerald             "should have handled all `is_return() == true` instructions above; \
767968952abSNick Fitzgerald              got {inst_data:?}"
768968952abSNick Fitzgerald         ),
769968952abSNick Fitzgerald     }
770968952abSNick Fitzgerald }
771968952abSNick Fitzgerald 
772968952abSNick Fitzgerald /// An `InstructionMapper` implementation that remaps a callee instruction's
773968952abSNick Fitzgerald /// entity references to their new indices in the caller function.
774968952abSNick Fitzgerald struct InliningInstRemapper<'a> {
775968952abSNick Fitzgerald     allocs: &'a InliningAllocs,
776968952abSNick Fitzgerald     func: &'a mut ir::Function,
777968952abSNick Fitzgerald     callee: &'a ir::Function,
778968952abSNick Fitzgerald     entity_map: &'a EntityMap,
779968952abSNick Fitzgerald }
780968952abSNick Fitzgerald 
781968952abSNick Fitzgerald impl<'a> ir::instructions::InstructionMapper for InliningInstRemapper<'a> {
782968952abSNick Fitzgerald     fn map_value(&mut self, value: ir::Value) -> ir::Value {
783968952abSNick Fitzgerald         self.allocs.get_inlined_value(self.callee, value).expect(
784968952abSNick Fitzgerald             "defs come before uses; we should have already inlined all values \
785968952abSNick Fitzgerald              used by an instruction",
786968952abSNick Fitzgerald         )
787968952abSNick Fitzgerald     }
788968952abSNick Fitzgerald 
789968952abSNick Fitzgerald     fn map_value_list(&mut self, value_list: ir::ValueList) -> ir::ValueList {
790968952abSNick Fitzgerald         let mut inlined_list = ir::ValueList::new();
791968952abSNick Fitzgerald         for callee_val in value_list.as_slice(&self.callee.dfg.value_lists) {
792968952abSNick Fitzgerald             let inlined_val = self.map_value(*callee_val);
793968952abSNick Fitzgerald             inlined_list.push(inlined_val, &mut self.func.dfg.value_lists);
794968952abSNick Fitzgerald         }
795968952abSNick Fitzgerald         inlined_list
796968952abSNick Fitzgerald     }
797968952abSNick Fitzgerald 
798968952abSNick Fitzgerald     fn map_global_value(&mut self, global_value: ir::GlobalValue) -> ir::GlobalValue {
799968952abSNick Fitzgerald         self.entity_map.inlined_global_value(global_value)
800968952abSNick Fitzgerald     }
801968952abSNick Fitzgerald 
802968952abSNick Fitzgerald     fn map_jump_table(&mut self, jump_table: ir::JumpTable) -> ir::JumpTable {
803968952abSNick Fitzgerald         let inlined_default =
804968952abSNick Fitzgerald             self.map_block_call(self.callee.dfg.jump_tables[jump_table].default_block());
805968952abSNick Fitzgerald         let inlined_table = self.callee.dfg.jump_tables[jump_table]
806968952abSNick Fitzgerald             .as_slice()
807968952abSNick Fitzgerald             .iter()
808968952abSNick Fitzgerald             .map(|callee_block_call| self.map_block_call(*callee_block_call))
809968952abSNick Fitzgerald             .collect::<SmallBlockCallVec>();
810968952abSNick Fitzgerald         self.func
811968952abSNick Fitzgerald             .dfg
812968952abSNick Fitzgerald             .jump_tables
813968952abSNick Fitzgerald             .push(ir::JumpTableData::new(inlined_default, &inlined_table))
814968952abSNick Fitzgerald     }
815968952abSNick Fitzgerald 
816968952abSNick Fitzgerald     fn map_exception_table(&mut self, exception_table: ir::ExceptionTable) -> ir::ExceptionTable {
817968952abSNick Fitzgerald         let exception_table = &self.callee.dfg.exception_tables[exception_table];
818968952abSNick Fitzgerald         let inlined_sig_ref = self.map_sig_ref(exception_table.signature());
819968952abSNick Fitzgerald         let inlined_normal_return = self.map_block_call(*exception_table.normal_return());
820968952abSNick Fitzgerald         let inlined_table = exception_table
8214590076fSChris Fallin             .items()
8224590076fSChris Fallin             .map(|item| match item {
8234590076fSChris Fallin                 ExceptionTableItem::Tag(tag, block_call) => {
8244590076fSChris Fallin                     ExceptionTableItem::Tag(tag, self.map_block_call(block_call))
8254590076fSChris Fallin                 }
8264590076fSChris Fallin                 ExceptionTableItem::Default(block_call) => {
8274590076fSChris Fallin                     ExceptionTableItem::Default(self.map_block_call(block_call))
8284590076fSChris Fallin                 }
8294590076fSChris Fallin                 ExceptionTableItem::Context(value) => {
8304590076fSChris Fallin                     ExceptionTableItem::Context(self.map_value(value))
8314590076fSChris Fallin                 }
8324590076fSChris Fallin             })
833968952abSNick Fitzgerald             .collect::<SmallVec<[_; 8]>>();
834968952abSNick Fitzgerald         self.func
835968952abSNick Fitzgerald             .dfg
836968952abSNick Fitzgerald             .exception_tables
837968952abSNick Fitzgerald             .push(ir::ExceptionTableData::new(
838968952abSNick Fitzgerald                 inlined_sig_ref,
839968952abSNick Fitzgerald                 inlined_normal_return,
840968952abSNick Fitzgerald                 inlined_table,
841968952abSNick Fitzgerald             ))
842968952abSNick Fitzgerald     }
843968952abSNick Fitzgerald 
844968952abSNick Fitzgerald     fn map_block_call(&mut self, block_call: ir::BlockCall) -> ir::BlockCall {
845968952abSNick Fitzgerald         let callee_block = block_call.block(&self.callee.dfg.value_lists);
846968952abSNick Fitzgerald         let inlined_block = self.entity_map.inlined_block(callee_block);
847968952abSNick Fitzgerald         let args = block_call
848968952abSNick Fitzgerald             .args(&self.callee.dfg.value_lists)
849968952abSNick Fitzgerald             .map(|arg| match arg {
850968952abSNick Fitzgerald                 ir::BlockArg::Value(value) => self.map_value(value).into(),
851968952abSNick Fitzgerald                 ir::BlockArg::TryCallRet(_) | ir::BlockArg::TryCallExn(_) => arg,
852968952abSNick Fitzgerald             })
853968952abSNick Fitzgerald             .collect::<SmallBlockArgVec>();
854968952abSNick Fitzgerald         ir::BlockCall::new(inlined_block, args, &mut self.func.dfg.value_lists)
855968952abSNick Fitzgerald     }
856968952abSNick Fitzgerald 
857968952abSNick Fitzgerald     fn map_func_ref(&mut self, func_ref: ir::FuncRef) -> ir::FuncRef {
858968952abSNick Fitzgerald         self.entity_map.inlined_func_ref(func_ref)
859968952abSNick Fitzgerald     }
860968952abSNick Fitzgerald 
861968952abSNick Fitzgerald     fn map_sig_ref(&mut self, sig_ref: ir::SigRef) -> ir::SigRef {
862968952abSNick Fitzgerald         self.entity_map.inlined_sig_ref(sig_ref)
863968952abSNick Fitzgerald     }
864968952abSNick Fitzgerald 
865968952abSNick Fitzgerald     fn map_stack_slot(&mut self, stack_slot: ir::StackSlot) -> ir::StackSlot {
866968952abSNick Fitzgerald         self.entity_map.inlined_stack_slot(stack_slot)
867968952abSNick Fitzgerald     }
868968952abSNick Fitzgerald 
869968952abSNick Fitzgerald     fn map_dynamic_stack_slot(
870968952abSNick Fitzgerald         &mut self,
871968952abSNick Fitzgerald         dynamic_stack_slot: ir::DynamicStackSlot,
872968952abSNick Fitzgerald     ) -> ir::DynamicStackSlot {
873968952abSNick Fitzgerald         self.entity_map
874968952abSNick Fitzgerald             .inlined_dynamic_stack_slot(dynamic_stack_slot)
875968952abSNick Fitzgerald     }
876968952abSNick Fitzgerald 
877968952abSNick Fitzgerald     fn map_constant(&mut self, constant: ir::Constant) -> ir::Constant {
878968952abSNick Fitzgerald         self.allocs
879968952abSNick Fitzgerald             .constants
880968952abSNick Fitzgerald             .get(constant)
881968952abSNick Fitzgerald             .and_then(|o| o.expand())
882968952abSNick Fitzgerald             .expect("should have inlined all callee constants")
883968952abSNick Fitzgerald     }
884968952abSNick Fitzgerald 
885968952abSNick Fitzgerald     fn map_immediate(&mut self, immediate: ir::Immediate) -> ir::Immediate {
886968952abSNick Fitzgerald         self.entity_map.inlined_immediate(immediate)
887968952abSNick Fitzgerald     }
888968952abSNick Fitzgerald }
889968952abSNick Fitzgerald 
890968952abSNick Fitzgerald /// Inline the callee's layout into the caller's layout.
891968952abSNick Fitzgerald fn inline_block_layout(
892968952abSNick Fitzgerald     func: &mut ir::Function,
893968952abSNick Fitzgerald     call_block: ir::Block,
894968952abSNick Fitzgerald     callee: &ir::Function,
895968952abSNick Fitzgerald     entity_map: &EntityMap,
896968952abSNick Fitzgerald ) {
897968952abSNick Fitzgerald     // Iterate over callee blocks in layout order, inserting their associated
898968952abSNick Fitzgerald     // inlined block into the caller's layout.
899968952abSNick Fitzgerald     let mut prev_inlined_block = call_block;
900968952abSNick Fitzgerald     let mut next_callee_block = callee.layout.entry_block();
901968952abSNick Fitzgerald     while let Some(callee_block) = next_callee_block {
902968952abSNick Fitzgerald         let inlined_block = entity_map.inlined_block(callee_block);
903968952abSNick Fitzgerald         func.layout
904968952abSNick Fitzgerald             .insert_block_after(inlined_block, prev_inlined_block);
905968952abSNick Fitzgerald 
906968952abSNick Fitzgerald         prev_inlined_block = inlined_block;
907968952abSNick Fitzgerald         next_callee_block = callee.layout.next_block(callee_block);
908968952abSNick Fitzgerald     }
909968952abSNick Fitzgerald }
910968952abSNick Fitzgerald 
911968952abSNick Fitzgerald /// Split the call instruction's block just after the call instruction to create
912968952abSNick Fitzgerald /// the point where control-flow joins after the inlined callee "returns".
913968952abSNick Fitzgerald ///
914968952abSNick Fitzgerald /// Note that tail calls do not return to the caller and therefore do not have a
915968952abSNick Fitzgerald /// control-flow join point.
916968952abSNick Fitzgerald fn split_off_return_block(
917968952abSNick Fitzgerald     func: &mut ir::Function,
918968952abSNick Fitzgerald     call_inst: ir::Inst,
919968952abSNick Fitzgerald     opcode: ir::Opcode,
920968952abSNick Fitzgerald     callee: &ir::Function,
921968952abSNick Fitzgerald ) -> Option<ir::Block> {
922968952abSNick Fitzgerald     // When the `call_inst` is not a block terminator, we need to split the
923968952abSNick Fitzgerald     // block.
924968952abSNick Fitzgerald     let return_block = func.layout.next_inst(call_inst).map(|next_inst| {
925968952abSNick Fitzgerald         let return_block = func.dfg.blocks.add();
926968952abSNick Fitzgerald         func.layout.split_block(return_block, next_inst);
927968952abSNick Fitzgerald 
928968952abSNick Fitzgerald         // Add block parameters for each return value and alias the call
929968952abSNick Fitzgerald         // instruction's results to them.
930968952abSNick Fitzgerald         let old_results =
931968952abSNick Fitzgerald             SmallValueVec::from_iter(func.dfg.inst_results(call_inst).iter().copied());
932968952abSNick Fitzgerald         debug_assert_eq!(old_results.len(), callee.signature.returns.len());
933968952abSNick Fitzgerald         func.dfg.detach_inst_results(call_inst);
934968952abSNick Fitzgerald         for (abi, old_val) in callee.signature.returns.iter().zip(old_results) {
935968952abSNick Fitzgerald             debug_assert_eq!(abi.value_type, func.dfg.value_type(old_val));
936968952abSNick Fitzgerald             let ret_param = func.dfg.append_block_param(return_block, abi.value_type);
937968952abSNick Fitzgerald             func.dfg.change_to_alias(old_val, ret_param);
938968952abSNick Fitzgerald         }
939968952abSNick Fitzgerald 
940968952abSNick Fitzgerald         return_block
941968952abSNick Fitzgerald     });
942968952abSNick Fitzgerald 
943968952abSNick Fitzgerald     // When the `call_inst` is a block terminator, then it is either a
944968952abSNick Fitzgerald     // `return_call` or a `try_call`:
945968952abSNick Fitzgerald     //
946968952abSNick Fitzgerald     // * For `return_call`s, we don't have a control-flow join point, because
947968952abSNick Fitzgerald     //   the caller permanently transfers control to the callee.
948968952abSNick Fitzgerald     //
949968952abSNick Fitzgerald     // * For `try_call`s, we probably already have a block for the control-flow
950968952abSNick Fitzgerald     //   join point, but it isn't guaranteed: the `try_call` might ignore the
951968952abSNick Fitzgerald     //   call's returns and not forward them to the normal-return block or it
952968952abSNick Fitzgerald     //   might also pass additional arguments. We can only reuse the existing
953968952abSNick Fitzgerald     //   normal-return block when the `try_call` forwards exactly our callee's
954968952abSNick Fitzgerald     //   returns to that block (and therefore that block's parameter types also
955968952abSNick Fitzgerald     //   exactly match the callee's return types). Otherwise, we must create a new
956968952abSNick Fitzgerald     //   return block that forwards to the existing normal-return
957968952abSNick Fitzgerald     //   block. (Elsewhere, at the end of inlining, we will also update any inlined
958968952abSNick Fitzgerald     //   calls to forward any raised exceptions to the caller's exception table,
959968952abSNick Fitzgerald     //   as necessary.)
960968952abSNick Fitzgerald     //
961968952abSNick Fitzgerald     //   Finally, note that reusing the normal-return's target block is just an
962968952abSNick Fitzgerald     //   optimization to emit a simpler CFG when we can, and is not
963968952abSNick Fitzgerald     //   fundamentally required for correctness. We could always insert a
964968952abSNick Fitzgerald     //   temporary block as our control-flow join point that then forwards to
965968952abSNick Fitzgerald     //   the normal-return's target block. However, at the time of writing,
966968952abSNick Fitzgerald     //   Cranelift doesn't currently do any jump-threading or branch
967968952abSNick Fitzgerald     //   simplification in the mid-end, and removing unnecessary blocks in this
968968952abSNick Fitzgerald     //   way can help some subsequent mid-end optimizations. If, in the future,
969968952abSNick Fitzgerald     //   we gain support for jump-threading optimizations in the mid-end, we can
970968952abSNick Fitzgerald     //   come back and simplify the below code a bit to always generate the
971968952abSNick Fitzgerald     //   temporary block, and then rely on the subsequent optimizations to clean
972968952abSNick Fitzgerald     //   everything up.
973968952abSNick Fitzgerald     debug_assert_eq!(
974968952abSNick Fitzgerald         return_block.is_none(),
975968952abSNick Fitzgerald         opcode == ir::Opcode::ReturnCall || opcode == ir::Opcode::TryCall,
976968952abSNick Fitzgerald     );
977968952abSNick Fitzgerald     return_block.or_else(|| match func.dfg.insts[call_inst] {
978968952abSNick Fitzgerald         ir::InstructionData::TryCall {
979968952abSNick Fitzgerald             opcode: ir::Opcode::TryCall,
980968952abSNick Fitzgerald             args: _,
981968952abSNick Fitzgerald             func_ref: _,
982968952abSNick Fitzgerald             exception,
983968952abSNick Fitzgerald         } => {
984968952abSNick Fitzgerald             let normal_return = func.dfg.exception_tables[exception].normal_return();
985968952abSNick Fitzgerald             let normal_return_block = normal_return.block(&func.dfg.value_lists);
986968952abSNick Fitzgerald 
987968952abSNick Fitzgerald             // Check to see if we can reuse the existing normal-return block.
988968952abSNick Fitzgerald             {
989968952abSNick Fitzgerald                 let normal_return_args = normal_return.args(&func.dfg.value_lists);
990968952abSNick Fitzgerald                 if normal_return_args.len() == callee.signature.returns.len()
991968952abSNick Fitzgerald                     && normal_return_args.enumerate().all(|(i, arg)| {
992968952abSNick Fitzgerald                         let i = u32::try_from(i).unwrap();
993968952abSNick Fitzgerald                         arg == ir::BlockArg::TryCallRet(i)
994968952abSNick Fitzgerald                     })
995968952abSNick Fitzgerald                 {
996968952abSNick Fitzgerald                     return Some(normal_return_block);
997968952abSNick Fitzgerald                 }
998968952abSNick Fitzgerald             }
999968952abSNick Fitzgerald 
1000968952abSNick Fitzgerald             // Okay, we cannot reuse the normal-return block. Create a new block
1001968952abSNick Fitzgerald             // that has the expected block parameter types and have it jump to
1002968952abSNick Fitzgerald             // the normal-return block.
1003968952abSNick Fitzgerald             let return_block = func.dfg.blocks.add();
1004968952abSNick Fitzgerald             func.layout.insert_block(return_block, normal_return_block);
1005968952abSNick Fitzgerald 
1006968952abSNick Fitzgerald             let return_block_params = callee
1007968952abSNick Fitzgerald                 .signature
1008968952abSNick Fitzgerald                 .returns
1009968952abSNick Fitzgerald                 .iter()
1010968952abSNick Fitzgerald                 .map(|abi| func.dfg.append_block_param(return_block, abi.value_type))
1011968952abSNick Fitzgerald                 .collect::<SmallValueVec>();
1012968952abSNick Fitzgerald 
1013968952abSNick Fitzgerald             let normal_return_args = func.dfg.exception_tables[exception]
1014968952abSNick Fitzgerald                 .normal_return()
1015968952abSNick Fitzgerald                 .args(&func.dfg.value_lists)
1016968952abSNick Fitzgerald                 .collect::<SmallBlockArgVec>();
1017968952abSNick Fitzgerald             let jump_args = normal_return_args
1018968952abSNick Fitzgerald                 .into_iter()
1019968952abSNick Fitzgerald                 .map(|arg| match arg {
1020968952abSNick Fitzgerald                     ir::BlockArg::Value(value) => ir::BlockArg::Value(value),
1021968952abSNick Fitzgerald                     ir::BlockArg::TryCallRet(i) => {
1022968952abSNick Fitzgerald                         let i = usize::try_from(i).unwrap();
1023968952abSNick Fitzgerald                         ir::BlockArg::Value(return_block_params[i])
1024968952abSNick Fitzgerald                     }
1025968952abSNick Fitzgerald                     ir::BlockArg::TryCallExn(_) => {
1026968952abSNick Fitzgerald                         unreachable!("normal-return edges cannot use exceptional results")
1027968952abSNick Fitzgerald                     }
1028968952abSNick Fitzgerald                 })
1029968952abSNick Fitzgerald                 .collect::<SmallBlockArgVec>();
1030968952abSNick Fitzgerald 
1031968952abSNick Fitzgerald             let mut cursor = FuncCursor::new(func);
1032968952abSNick Fitzgerald             cursor.goto_first_insertion_point(return_block);
1033968952abSNick Fitzgerald             cursor.ins().jump(normal_return_block, &jump_args);
1034968952abSNick Fitzgerald 
1035968952abSNick Fitzgerald             Some(return_block)
1036968952abSNick Fitzgerald         }
1037968952abSNick Fitzgerald         _ => None,
1038968952abSNick Fitzgerald     })
1039968952abSNick Fitzgerald }
1040968952abSNick Fitzgerald 
1041968952abSNick Fitzgerald /// Replace the caller's call instruction with a jump to the caller's inlined
1042968952abSNick Fitzgerald /// copy of the callee's entry block.
1043968952abSNick Fitzgerald ///
1044968952abSNick Fitzgerald /// Also associates the callee's parameters with the caller's arguments in our
1045968952abSNick Fitzgerald /// value map.
1046968952abSNick Fitzgerald ///
1047968952abSNick Fitzgerald /// Returns the caller's stack map entries, if any.
1048968952abSNick Fitzgerald fn replace_call_with_jump(
1049968952abSNick Fitzgerald     allocs: &mut InliningAllocs,
1050968952abSNick Fitzgerald     func: &mut ir::Function,
1051968952abSNick Fitzgerald     call_inst: ir::Inst,
1052968952abSNick Fitzgerald     callee: &ir::Function,
1053968952abSNick Fitzgerald     entity_map: &EntityMap,
1054968952abSNick Fitzgerald ) -> Option<ir::UserStackMapEntryVec> {
1055968952abSNick Fitzgerald     trace!("Replacing `call` with `jump`");
1056968952abSNick Fitzgerald     trace!(
1057968952abSNick Fitzgerald         "  --> call instruction: {call_inst:?}: {}",
1058968952abSNick Fitzgerald         func.dfg.display_inst(call_inst)
1059968952abSNick Fitzgerald     );
1060968952abSNick Fitzgerald 
1061968952abSNick Fitzgerald     let callee_entry_block = callee
1062968952abSNick Fitzgerald         .layout
1063968952abSNick Fitzgerald         .entry_block()
1064968952abSNick Fitzgerald         .expect("callee function should have an entry block");
1065968952abSNick Fitzgerald     let callee_param_values = callee.dfg.block_params(callee_entry_block);
1066968952abSNick Fitzgerald     let caller_arg_values = SmallValueVec::from_iter(func.dfg.inst_args(call_inst).iter().copied());
1067968952abSNick Fitzgerald     debug_assert_eq!(callee_param_values.len(), caller_arg_values.len());
1068968952abSNick Fitzgerald     debug_assert_eq!(callee_param_values.len(), callee.signature.params.len());
1069968952abSNick Fitzgerald     for (abi, (callee_param_value, caller_arg_value)) in callee
1070968952abSNick Fitzgerald         .signature
1071968952abSNick Fitzgerald         .params
1072968952abSNick Fitzgerald         .iter()
1073968952abSNick Fitzgerald         .zip(callee_param_values.into_iter().zip(caller_arg_values))
1074968952abSNick Fitzgerald     {
1075968952abSNick Fitzgerald         debug_assert_eq!(abi.value_type, callee.dfg.value_type(*callee_param_value));
1076968952abSNick Fitzgerald         debug_assert_eq!(abi.value_type, func.dfg.value_type(caller_arg_value));
1077968952abSNick Fitzgerald         allocs.set_inlined_value(callee, *callee_param_value, caller_arg_value);
1078968952abSNick Fitzgerald     }
1079968952abSNick Fitzgerald 
1080968952abSNick Fitzgerald     // Replace the caller's call instruction with a jump to the caller's inlined
1081968952abSNick Fitzgerald     // copy of the callee's entry block.
1082968952abSNick Fitzgerald     //
1083968952abSNick Fitzgerald     // Note that the call block dominates the inlined entry block (and also all
1084968952abSNick Fitzgerald     // other inlined blocks) so we can reference the arguments directly, and do
1085968952abSNick Fitzgerald     // not need to add block parameters to the inlined entry block.
1086968952abSNick Fitzgerald     let inlined_entry_block = entity_map.inlined_block(callee_entry_block);
1087968952abSNick Fitzgerald     func.dfg.replace(call_inst).jump(inlined_entry_block, &[]);
1088968952abSNick Fitzgerald     trace!(
1089968952abSNick Fitzgerald         "  --> replaced with jump instruction: {call_inst:?}: {}",
1090968952abSNick Fitzgerald         func.dfg.display_inst(call_inst)
1091968952abSNick Fitzgerald     );
1092968952abSNick Fitzgerald 
1093968952abSNick Fitzgerald     let stack_map_entries = func.dfg.take_user_stack_map_entries(call_inst);
1094968952abSNick Fitzgerald     stack_map_entries
1095968952abSNick Fitzgerald }
1096968952abSNick Fitzgerald 
1097968952abSNick Fitzgerald /// Keeps track of mapping callee entities to their associated inlined caller
1098968952abSNick Fitzgerald /// entities.
1099968952abSNick Fitzgerald #[derive(Default)]
1100968952abSNick Fitzgerald struct EntityMap {
1101968952abSNick Fitzgerald     // Rather than doing an implicit, demand-based, DCE'ing translation of
1102968952abSNick Fitzgerald     // entities, which would require maps from each callee entity to its
1103968952abSNick Fitzgerald     // associated caller entity, we copy all entities into the caller, remember
1104968952abSNick Fitzgerald     // each entity's initial offset, and then mapping from the callee to the
1105968952abSNick Fitzgerald     // inlined caller entity is just adding that initial offset to the callee's
1106968952abSNick Fitzgerald     // index. This should be both faster and simpler than the alternative. Most
1107968952abSNick Fitzgerald     // of these sets are relatively small, and they rarely have too much dead
1108968952abSNick Fitzgerald     // code in practice, so this is a good trade off.
1109968952abSNick Fitzgerald     //
1110968952abSNick Fitzgerald     // Note that there are a few kinds of entities that are excluded from the
1111968952abSNick Fitzgerald     // `EntityMap`, and for which we do actually take the demand-based approach:
1112968952abSNick Fitzgerald     // values and value lists being the notable ones.
1113968952abSNick Fitzgerald     block_offset: Option<u32>,
1114968952abSNick Fitzgerald     global_value_offset: Option<u32>,
1115968952abSNick Fitzgerald     sig_ref_offset: Option<u32>,
1116968952abSNick Fitzgerald     func_ref_offset: Option<u32>,
1117968952abSNick Fitzgerald     stack_slot_offset: Option<u32>,
1118968952abSNick Fitzgerald     dynamic_type_offset: Option<u32>,
1119968952abSNick Fitzgerald     dynamic_stack_slot_offset: Option<u32>,
1120968952abSNick Fitzgerald     immediate_offset: Option<u32>,
1121968952abSNick Fitzgerald }
1122968952abSNick Fitzgerald 
1123968952abSNick Fitzgerald impl EntityMap {
1124968952abSNick Fitzgerald     fn inlined_block(&self, callee_block: ir::Block) -> ir::Block {
1125968952abSNick Fitzgerald         let offset = self
1126968952abSNick Fitzgerald             .block_offset
1127968952abSNick Fitzgerald             .expect("must create inlined `ir::Block`s before calling `EntityMap::inlined_block`");
1128968952abSNick Fitzgerald         ir::Block::from_u32(offset + callee_block.as_u32())
1129968952abSNick Fitzgerald     }
1130968952abSNick Fitzgerald 
1131e3a607eaSNick Fitzgerald     fn iter_inlined_blocks(&self, func: &ir::Function) -> impl Iterator<Item = ir::Block> + use<> {
1132e3a607eaSNick Fitzgerald         let start = self.block_offset.expect(
1133e3a607eaSNick Fitzgerald             "must create inlined `ir::Block`s before calling `EntityMap::iter_inlined_blocks`",
1134e3a607eaSNick Fitzgerald         );
1135e3a607eaSNick Fitzgerald 
1136e3a607eaSNick Fitzgerald         let end = func.dfg.blocks.len();
1137e3a607eaSNick Fitzgerald         let end = u32::try_from(end).unwrap();
1138e3a607eaSNick Fitzgerald 
1139e3a607eaSNick Fitzgerald         (start..end).map(|i| ir::Block::from_u32(i))
1140e3a607eaSNick Fitzgerald     }
1141e3a607eaSNick Fitzgerald 
1142968952abSNick Fitzgerald     fn inlined_global_value(&self, callee_global_value: ir::GlobalValue) -> ir::GlobalValue {
1143968952abSNick Fitzgerald         let offset = self
1144968952abSNick Fitzgerald             .global_value_offset
1145968952abSNick Fitzgerald             .expect("must create inlined `ir::GlobalValue`s before calling `EntityMap::inlined_global_value`");
1146968952abSNick Fitzgerald         ir::GlobalValue::from_u32(offset + callee_global_value.as_u32())
1147968952abSNick Fitzgerald     }
1148968952abSNick Fitzgerald 
1149968952abSNick Fitzgerald     fn inlined_sig_ref(&self, callee_sig_ref: ir::SigRef) -> ir::SigRef {
1150968952abSNick Fitzgerald         let offset = self.sig_ref_offset.expect(
1151968952abSNick Fitzgerald             "must create inlined `ir::SigRef`s before calling `EntityMap::inlined_sig_ref`",
1152968952abSNick Fitzgerald         );
1153968952abSNick Fitzgerald         ir::SigRef::from_u32(offset + callee_sig_ref.as_u32())
1154968952abSNick Fitzgerald     }
1155968952abSNick Fitzgerald 
1156968952abSNick Fitzgerald     fn inlined_func_ref(&self, callee_func_ref: ir::FuncRef) -> ir::FuncRef {
1157968952abSNick Fitzgerald         let offset = self.func_ref_offset.expect(
1158968952abSNick Fitzgerald             "must create inlined `ir::FuncRef`s before calling `EntityMap::inlined_func_ref`",
1159968952abSNick Fitzgerald         );
1160968952abSNick Fitzgerald         ir::FuncRef::from_u32(offset + callee_func_ref.as_u32())
1161968952abSNick Fitzgerald     }
1162968952abSNick Fitzgerald 
1163968952abSNick Fitzgerald     fn inlined_stack_slot(&self, callee_stack_slot: ir::StackSlot) -> ir::StackSlot {
1164968952abSNick Fitzgerald         let offset = self.stack_slot_offset.expect(
1165968952abSNick Fitzgerald             "must create inlined `ir::StackSlot`s before calling `EntityMap::inlined_stack_slot`",
1166968952abSNick Fitzgerald         );
1167968952abSNick Fitzgerald         ir::StackSlot::from_u32(offset + callee_stack_slot.as_u32())
1168968952abSNick Fitzgerald     }
1169968952abSNick Fitzgerald 
1170968952abSNick Fitzgerald     fn inlined_dynamic_type(&self, callee_dynamic_type: ir::DynamicType) -> ir::DynamicType {
1171968952abSNick Fitzgerald         let offset = self.dynamic_type_offset.expect(
1172968952abSNick Fitzgerald             "must create inlined `ir::DynamicType`s before calling `EntityMap::inlined_dynamic_type`",
1173968952abSNick Fitzgerald         );
1174968952abSNick Fitzgerald         ir::DynamicType::from_u32(offset + callee_dynamic_type.as_u32())
1175968952abSNick Fitzgerald     }
1176968952abSNick Fitzgerald 
1177968952abSNick Fitzgerald     fn inlined_dynamic_stack_slot(
1178968952abSNick Fitzgerald         &self,
1179968952abSNick Fitzgerald         callee_dynamic_stack_slot: ir::DynamicStackSlot,
1180968952abSNick Fitzgerald     ) -> ir::DynamicStackSlot {
1181968952abSNick Fitzgerald         let offset = self.dynamic_stack_slot_offset.expect(
1182968952abSNick Fitzgerald             "must create inlined `ir::DynamicStackSlot`s before calling `EntityMap::inlined_dynamic_stack_slot`",
1183968952abSNick Fitzgerald         );
1184968952abSNick Fitzgerald         ir::DynamicStackSlot::from_u32(offset + callee_dynamic_stack_slot.as_u32())
1185968952abSNick Fitzgerald     }
1186968952abSNick Fitzgerald 
1187968952abSNick Fitzgerald     fn inlined_immediate(&self, callee_immediate: ir::Immediate) -> ir::Immediate {
1188968952abSNick Fitzgerald         let offset = self.immediate_offset.expect(
1189968952abSNick Fitzgerald             "must create inlined `ir::Immediate`s before calling `EntityMap::inlined_immediate`",
1190968952abSNick Fitzgerald         );
1191968952abSNick Fitzgerald         ir::Immediate::from_u32(offset + callee_immediate.as_u32())
1192968952abSNick Fitzgerald     }
1193968952abSNick Fitzgerald }
1194968952abSNick Fitzgerald 
1195968952abSNick Fitzgerald /// Translate all of the callee's various entities into the caller, producing an
1196968952abSNick Fitzgerald /// `EntityMap` that can be used to translate callee entity references into
1197968952abSNick Fitzgerald /// inlined caller entity references.
1198968952abSNick Fitzgerald fn create_entities(
1199968952abSNick Fitzgerald     allocs: &mut InliningAllocs,
1200968952abSNick Fitzgerald     func: &mut ir::Function,
1201968952abSNick Fitzgerald     callee: &ir::Function,
1202968952abSNick Fitzgerald ) -> EntityMap {
1203968952abSNick Fitzgerald     let mut entity_map = EntityMap::default();
1204968952abSNick Fitzgerald 
1205968952abSNick Fitzgerald     entity_map.block_offset = Some(create_blocks(allocs, func, callee));
1206968952abSNick Fitzgerald     entity_map.global_value_offset = Some(create_global_values(func, callee));
1207968952abSNick Fitzgerald     entity_map.sig_ref_offset = Some(create_sig_refs(func, callee));
1208968952abSNick Fitzgerald     entity_map.func_ref_offset = Some(create_func_refs(func, callee, &entity_map));
1209968952abSNick Fitzgerald     entity_map.stack_slot_offset = Some(create_stack_slots(func, callee));
1210968952abSNick Fitzgerald     entity_map.dynamic_type_offset = Some(create_dynamic_types(func, callee, &entity_map));
1211968952abSNick Fitzgerald     entity_map.dynamic_stack_slot_offset =
1212968952abSNick Fitzgerald         Some(create_dynamic_stack_slots(func, callee, &entity_map));
1213968952abSNick Fitzgerald     entity_map.immediate_offset = Some(create_immediates(func, callee));
1214968952abSNick Fitzgerald 
1215968952abSNick Fitzgerald     // `ir::ConstantData` is deduplicated, so we cannot use our offset scheme
1216968952abSNick Fitzgerald     // for `ir::Constant`s. Nonetheless, we still insert them into the caller
1217968952abSNick Fitzgerald     // now, at the same time as the rest of our entities.
1218968952abSNick Fitzgerald     create_constants(allocs, func, callee);
1219968952abSNick Fitzgerald 
1220968952abSNick Fitzgerald     entity_map
1221968952abSNick Fitzgerald }
1222968952abSNick Fitzgerald 
1223968952abSNick Fitzgerald /// Create inlined blocks in the caller for every block in the callee.
1224968952abSNick Fitzgerald fn create_blocks(
1225968952abSNick Fitzgerald     allocs: &mut InliningAllocs,
1226968952abSNick Fitzgerald     func: &mut ir::Function,
1227968952abSNick Fitzgerald     callee: &ir::Function,
1228968952abSNick Fitzgerald ) -> u32 {
1229968952abSNick Fitzgerald     let offset = func.dfg.blocks.len();
1230968952abSNick Fitzgerald     let offset = u32::try_from(offset).unwrap();
1231968952abSNick Fitzgerald 
1232968952abSNick Fitzgerald     func.dfg.blocks.reserve(callee.dfg.blocks.len());
1233968952abSNick Fitzgerald     for callee_block in callee.dfg.blocks.iter() {
1234968952abSNick Fitzgerald         let caller_block = func.dfg.blocks.add();
1235968952abSNick Fitzgerald         trace!("Callee {callee_block:?} = inlined {caller_block:?}");
1236968952abSNick Fitzgerald 
1237968952abSNick Fitzgerald         if callee.layout.is_cold(callee_block) {
1238968952abSNick Fitzgerald             func.layout.set_cold(caller_block);
1239968952abSNick Fitzgerald         }
1240968952abSNick Fitzgerald 
1241968952abSNick Fitzgerald         // Note: the entry block does not need parameters because the only
1242968952abSNick Fitzgerald         // predecessor is the call block and we associate the callee's
1243968952abSNick Fitzgerald         // parameters with the caller's arguments directly.
1244968952abSNick Fitzgerald         if callee.layout.entry_block() != Some(callee_block) {
1245968952abSNick Fitzgerald             for callee_param in callee.dfg.blocks[callee_block].params(&callee.dfg.value_lists) {
1246968952abSNick Fitzgerald                 let ty = callee.dfg.value_type(*callee_param);
1247968952abSNick Fitzgerald                 let caller_param = func.dfg.append_block_param(caller_block, ty);
1248968952abSNick Fitzgerald 
1249968952abSNick Fitzgerald                 allocs.set_inlined_value(callee, *callee_param, caller_param);
1250968952abSNick Fitzgerald             }
1251968952abSNick Fitzgerald         }
1252968952abSNick Fitzgerald     }
1253968952abSNick Fitzgerald 
1254968952abSNick Fitzgerald     offset
1255968952abSNick Fitzgerald }
1256968952abSNick Fitzgerald 
1257968952abSNick Fitzgerald /// Copy and translate global values from the callee into the caller.
1258968952abSNick Fitzgerald fn create_global_values(func: &mut ir::Function, callee: &ir::Function) -> u32 {
1259968952abSNick Fitzgerald     let gv_offset = func.global_values.len();
1260968952abSNick Fitzgerald     let gv_offset = u32::try_from(gv_offset).unwrap();
1261968952abSNick Fitzgerald 
1262968952abSNick Fitzgerald     func.global_values.reserve(callee.global_values.len());
1263968952abSNick Fitzgerald     for gv in callee.global_values.values() {
1264968952abSNick Fitzgerald         func.global_values.push(match gv {
1265968952abSNick Fitzgerald             // These kinds of global values reference other global values, so we
1266968952abSNick Fitzgerald             // need to fixup that reference.
1267968952abSNick Fitzgerald             ir::GlobalValueData::Load {
1268968952abSNick Fitzgerald                 base,
1269968952abSNick Fitzgerald                 offset,
1270968952abSNick Fitzgerald                 global_type,
1271968952abSNick Fitzgerald                 flags,
1272968952abSNick Fitzgerald             } => ir::GlobalValueData::Load {
1273968952abSNick Fitzgerald                 base: ir::GlobalValue::from_u32(base.as_u32() + gv_offset),
1274968952abSNick Fitzgerald                 offset: *offset,
1275968952abSNick Fitzgerald                 global_type: *global_type,
1276968952abSNick Fitzgerald                 flags: *flags,
1277968952abSNick Fitzgerald             },
1278968952abSNick Fitzgerald             ir::GlobalValueData::IAddImm {
1279968952abSNick Fitzgerald                 base,
1280968952abSNick Fitzgerald                 offset,
1281968952abSNick Fitzgerald                 global_type,
1282968952abSNick Fitzgerald             } => ir::GlobalValueData::IAddImm {
1283968952abSNick Fitzgerald                 base: ir::GlobalValue::from_u32(base.as_u32() + gv_offset),
1284968952abSNick Fitzgerald                 offset: *offset,
1285968952abSNick Fitzgerald                 global_type: *global_type,
1286968952abSNick Fitzgerald             },
1287968952abSNick Fitzgerald 
1288968952abSNick Fitzgerald             // These kinds of global values do not reference other global
1289968952abSNick Fitzgerald             // values, so we can just clone them.
1290968952abSNick Fitzgerald             ir::GlobalValueData::VMContext
1291968952abSNick Fitzgerald             | ir::GlobalValueData::Symbol { .. }
1292968952abSNick Fitzgerald             | ir::GlobalValueData::DynScaleTargetConst { .. } => gv.clone(),
1293968952abSNick Fitzgerald         });
1294968952abSNick Fitzgerald     }
1295968952abSNick Fitzgerald 
1296968952abSNick Fitzgerald     gv_offset
1297968952abSNick Fitzgerald }
1298968952abSNick Fitzgerald 
1299968952abSNick Fitzgerald /// Copy `ir::SigRef`s from the callee into the caller.
1300968952abSNick Fitzgerald fn create_sig_refs(func: &mut ir::Function, callee: &ir::Function) -> u32 {
1301968952abSNick Fitzgerald     let offset = func.dfg.signatures.len();
1302968952abSNick Fitzgerald     let offset = u32::try_from(offset).unwrap();
1303968952abSNick Fitzgerald 
1304968952abSNick Fitzgerald     func.dfg.signatures.reserve(callee.dfg.signatures.len());
1305968952abSNick Fitzgerald     for sig in callee.dfg.signatures.values() {
1306968952abSNick Fitzgerald         func.dfg.signatures.push(sig.clone());
1307968952abSNick Fitzgerald     }
1308968952abSNick Fitzgerald 
1309968952abSNick Fitzgerald     offset
1310968952abSNick Fitzgerald }
1311968952abSNick Fitzgerald 
1312968952abSNick Fitzgerald /// Translate `ir::FuncRef`s from the callee into the caller.
1313968952abSNick Fitzgerald fn create_func_refs(func: &mut ir::Function, callee: &ir::Function, entity_map: &EntityMap) -> u32 {
1314968952abSNick Fitzgerald     let offset = func.dfg.ext_funcs.len();
1315968952abSNick Fitzgerald     let offset = u32::try_from(offset).unwrap();
1316968952abSNick Fitzgerald 
1317968952abSNick Fitzgerald     func.dfg.ext_funcs.reserve(callee.dfg.ext_funcs.len());
1318968952abSNick Fitzgerald     for ir::ExtFuncData {
1319968952abSNick Fitzgerald         name,
1320968952abSNick Fitzgerald         signature,
1321968952abSNick Fitzgerald         colocated,
1322968952abSNick Fitzgerald     } in callee.dfg.ext_funcs.values()
1323968952abSNick Fitzgerald     {
1324968952abSNick Fitzgerald         func.dfg.ext_funcs.push(ir::ExtFuncData {
1325968952abSNick Fitzgerald             name: name.clone(),
1326968952abSNick Fitzgerald             signature: entity_map.inlined_sig_ref(*signature),
1327968952abSNick Fitzgerald             colocated: *colocated,
1328968952abSNick Fitzgerald         });
1329968952abSNick Fitzgerald     }
1330968952abSNick Fitzgerald 
1331968952abSNick Fitzgerald     offset
1332968952abSNick Fitzgerald }
1333968952abSNick Fitzgerald 
1334968952abSNick Fitzgerald /// Copy stack slots from the callee into the caller.
1335968952abSNick Fitzgerald fn create_stack_slots(func: &mut ir::Function, callee: &ir::Function) -> u32 {
1336968952abSNick Fitzgerald     let offset = func.sized_stack_slots.len();
1337968952abSNick Fitzgerald     let offset = u32::try_from(offset).unwrap();
1338968952abSNick Fitzgerald 
1339968952abSNick Fitzgerald     func.sized_stack_slots
1340968952abSNick Fitzgerald         .reserve(callee.sized_stack_slots.len());
1341968952abSNick Fitzgerald     for slot in callee.sized_stack_slots.values() {
1342968952abSNick Fitzgerald         func.sized_stack_slots.push(slot.clone());
1343968952abSNick Fitzgerald     }
1344968952abSNick Fitzgerald 
1345968952abSNick Fitzgerald     offset
1346968952abSNick Fitzgerald }
1347968952abSNick Fitzgerald 
1348968952abSNick Fitzgerald /// Copy dynamic types from the callee into the caller.
1349968952abSNick Fitzgerald fn create_dynamic_types(
1350968952abSNick Fitzgerald     func: &mut ir::Function,
1351968952abSNick Fitzgerald     callee: &ir::Function,
1352968952abSNick Fitzgerald     entity_map: &EntityMap,
1353968952abSNick Fitzgerald ) -> u32 {
1354968952abSNick Fitzgerald     let offset = func.dynamic_stack_slots.len();
1355968952abSNick Fitzgerald     let offset = u32::try_from(offset).unwrap();
1356968952abSNick Fitzgerald 
1357968952abSNick Fitzgerald     func.dfg
1358968952abSNick Fitzgerald         .dynamic_types
1359968952abSNick Fitzgerald         .reserve(callee.dfg.dynamic_types.len());
1360968952abSNick Fitzgerald     for ir::DynamicTypeData {
1361968952abSNick Fitzgerald         base_vector_ty,
1362968952abSNick Fitzgerald         dynamic_scale,
1363968952abSNick Fitzgerald     } in callee.dfg.dynamic_types.values()
1364968952abSNick Fitzgerald     {
1365968952abSNick Fitzgerald         func.dfg.dynamic_types.push(ir::DynamicTypeData {
1366968952abSNick Fitzgerald             base_vector_ty: *base_vector_ty,
1367968952abSNick Fitzgerald             dynamic_scale: entity_map.inlined_global_value(*dynamic_scale),
1368968952abSNick Fitzgerald         });
1369968952abSNick Fitzgerald     }
1370968952abSNick Fitzgerald 
1371968952abSNick Fitzgerald     offset
1372968952abSNick Fitzgerald }
1373968952abSNick Fitzgerald 
1374968952abSNick Fitzgerald /// Copy dynamic stack slots from the callee into the caller.
1375968952abSNick Fitzgerald fn create_dynamic_stack_slots(
1376968952abSNick Fitzgerald     func: &mut ir::Function,
1377968952abSNick Fitzgerald     callee: &ir::Function,
1378968952abSNick Fitzgerald     entity_map: &EntityMap,
1379968952abSNick Fitzgerald ) -> u32 {
1380968952abSNick Fitzgerald     let offset = func.dynamic_stack_slots.len();
1381968952abSNick Fitzgerald     let offset = u32::try_from(offset).unwrap();
1382968952abSNick Fitzgerald 
1383968952abSNick Fitzgerald     func.dynamic_stack_slots
1384968952abSNick Fitzgerald         .reserve(callee.dynamic_stack_slots.len());
1385968952abSNick Fitzgerald     for ir::DynamicStackSlotData { kind, dyn_ty } in callee.dynamic_stack_slots.values() {
1386968952abSNick Fitzgerald         func.dynamic_stack_slots.push(ir::DynamicStackSlotData {
1387968952abSNick Fitzgerald             kind: *kind,
1388968952abSNick Fitzgerald             dyn_ty: entity_map.inlined_dynamic_type(*dyn_ty),
1389968952abSNick Fitzgerald         });
1390968952abSNick Fitzgerald     }
1391968952abSNick Fitzgerald 
1392968952abSNick Fitzgerald     offset
1393968952abSNick Fitzgerald }
1394968952abSNick Fitzgerald 
1395968952abSNick Fitzgerald /// Copy immediates from the callee into the caller.
1396968952abSNick Fitzgerald fn create_immediates(func: &mut ir::Function, callee: &ir::Function) -> u32 {
1397968952abSNick Fitzgerald     let offset = func.dfg.immediates.len();
1398968952abSNick Fitzgerald     let offset = u32::try_from(offset).unwrap();
1399968952abSNick Fitzgerald 
1400968952abSNick Fitzgerald     func.dfg.immediates.reserve(callee.dfg.immediates.len());
1401968952abSNick Fitzgerald     for imm in callee.dfg.immediates.values() {
1402968952abSNick Fitzgerald         func.dfg.immediates.push(imm.clone());
1403968952abSNick Fitzgerald     }
1404968952abSNick Fitzgerald 
1405968952abSNick Fitzgerald     offset
1406968952abSNick Fitzgerald }
1407968952abSNick Fitzgerald 
1408968952abSNick Fitzgerald /// Copy constants from the callee into the caller.
1409968952abSNick Fitzgerald fn create_constants(allocs: &mut InliningAllocs, func: &mut ir::Function, callee: &ir::Function) {
1410968952abSNick Fitzgerald     for (callee_constant, data) in callee.dfg.constants.iter() {
1411968952abSNick Fitzgerald         let inlined_constant = func.dfg.constants.insert(data.clone());
1412968952abSNick Fitzgerald         allocs.constants[*callee_constant] = Some(inlined_constant).into();
1413968952abSNick Fitzgerald     }
1414968952abSNick Fitzgerald }
1415