Inline one particular function call. Returns the last inlined block in the layout.
(
allocs: &mut InliningAllocs,
func: &mut ir::Function,
callee_func_ref: ir::FuncRef,
call_block: ir::Block,
call_inst: ir::Inst,
call_opcode: ir::Opcode,
callee: &ir::Func
| 338 | /// |
| 339 | /// Returns the last inlined block in the layout. |
| 340 | fn inline_one( |
| 341 | allocs: &mut InliningAllocs, |
| 342 | func: &mut ir::Function, |
| 343 | callee_func_ref: ir::FuncRef, |
| 344 | call_block: ir::Block, |
| 345 | call_inst: ir::Inst, |
| 346 | call_opcode: ir::Opcode, |
| 347 | callee: &ir::Function, |
| 348 | call_exception_table: Option<ir::ExceptionTable>, |
| 349 | ) -> CodegenResult<ir::Block> { |
| 350 | trace!( |
| 351 | "Inlining call {call_inst:?}: {}\n\ |
| 352 | with callee = {callee:?}", |
| 353 | func.dfg.display_inst(call_inst) |
| 354 | ); |
| 355 | |
| 356 | // Type check callee signature. |
| 357 | let expected_callee_sig = func.dfg.ext_funcs[callee_func_ref].signature; |
| 358 | let expected_callee_sig = &func.dfg.signatures[expected_callee_sig]; |
| 359 | assert_eq!(expected_callee_sig, &callee.signature); |
| 360 | |
| 361 | allocs.reset(callee); |
| 362 | |
| 363 | // First, append various callee entity arenas to the end of the caller's |
| 364 | // entity arenas. |
| 365 | let entity_map = create_entities(allocs, func, callee)?; |
| 366 | |
| 367 | // Inlined prologue: split the call instruction's block at the point of the |
| 368 | // call and replace the call with a jump. |
| 369 | let return_block = split_off_return_block(func, call_inst, call_opcode, callee); |
| 370 | let call_stack_map = replace_call_with_jump(allocs, func, call_inst, callee, &entity_map); |
| 371 | |
| 372 | // Prepare for translating the actual instructions by inserting the inlined |
| 373 | // blocks into the caller's layout in the same order that they appear in the |
| 374 | // callee. |
| 375 | let mut last_inlined_block = inline_block_layout(func, call_block, callee, &entity_map); |
| 376 | |
| 377 | // Get a copy of debug tags on the call instruction; these are |
| 378 | // prepended to debug tags on inlined instructions. Remove them |
| 379 | // from the call itself as it will be rewritten to a jump (which |
| 380 | // cannot have tags). |
| 381 | let call_debug_tags = func.debug_tags.get(call_inst).to_vec(); |
| 382 | func.debug_tags.set(call_inst, []); |
| 383 | |
| 384 | // Translate each instruction from the callee into the caller, |
| 385 | // appending them to their associated block in the caller. |
| 386 | // |
| 387 | // Note that we iterate over the callee with a pre-order traversal so that |
| 388 | // we see value defs before uses. |
| 389 | for callee_block in Dfs::new().pre_order_iter(callee) { |
| 390 | let inlined_block = entity_map.inlined_block(callee_block); |
| 391 | trace!( |
| 392 | "Processing instructions in callee block {callee_block:?} (inlined block {inlined_block:?}" |
| 393 | ); |
| 394 | |
| 395 | let mut next_callee_inst = callee.layout.first_inst(callee_block); |
| 396 | while let Some(callee_inst) = next_callee_inst { |
| 397 | trace!( |
no test coverage detected