diff options
Diffstat (limited to 'third_party/rust/cranelift-codegen/src/legalizer/call.rs')
-rw-r--r-- | third_party/rust/cranelift-codegen/src/legalizer/call.rs | 54 |
1 files changed, 54 insertions, 0 deletions
diff --git a/third_party/rust/cranelift-codegen/src/legalizer/call.rs b/third_party/rust/cranelift-codegen/src/legalizer/call.rs new file mode 100644 index 0000000000..4321dbb90b --- /dev/null +++ b/third_party/rust/cranelift-codegen/src/legalizer/call.rs @@ -0,0 +1,54 @@ +//! Legalization of calls. +//! +//! This module exports the `expand_call` function which transforms a `call` +//! instruction into `func_addr` and `call_indirect` instructions. + +use crate::cursor::{Cursor, FuncCursor}; +use crate::flowgraph::ControlFlowGraph; +use crate::ir::{self, InstBuilder}; +use crate::isa::TargetIsa; + +/// Expand a `call` instruction. This lowers it to a `call_indirect`, which +/// is only done if the ABI doesn't support direct calls. +pub fn expand_call( + inst: ir::Inst, + func: &mut ir::Function, + _cfg: &mut ControlFlowGraph, + isa: &dyn TargetIsa, +) { + // Unpack the instruction. + let (func_ref, old_args) = match func.dfg[inst] { + ir::InstructionData::Call { + opcode, + ref args, + func_ref, + } => { + debug_assert_eq!(opcode, ir::Opcode::Call); + (func_ref, args.clone()) + } + _ => panic!("Wanted call: {}", func.dfg.display_inst(inst, None)), + }; + + let ptr_ty = isa.pointer_type(); + + let sig = func.dfg.ext_funcs[func_ref].signature; + + let callee = { + let mut pos = FuncCursor::new(func).at_inst(inst); + pos.use_srcloc(inst); + pos.ins().func_addr(ptr_ty, func_ref) + }; + + let mut new_args = ir::ValueList::default(); + new_args.push(callee, &mut func.dfg.value_lists); + for i in 0..old_args.len(&func.dfg.value_lists) { + new_args.push( + old_args.as_slice(&func.dfg.value_lists)[i], + &mut func.dfg.value_lists, + ); + } + + func.dfg + .replace(inst) + .CallIndirect(ir::Opcode::CallIndirect, ptr_ty, sig, new_args); +} |