diff --git a/cranelift/filetests/isa/intel/binary64.cton b/cranelift/filetests/isa/intel/binary64.cton index 859c7d0d12..d2fab8e19d 100644 --- a/cranelift/filetests/isa/intel/binary64.cton +++ b/cranelift/filetests/isa/intel/binary64.cton @@ -473,8 +473,11 @@ ebb0: ; asm: movzbq %dl, %rsi [-,%rsi] v351 = bint.i64 v301 ; bin: 0f b6 f2 - ; asm: call foo - call fn0() ; bin: e8 PCRel4(%foo-4) 00000000 + ; TODO: x86-64 can't encode a direct call to an arbitrary 64-bit address in + ; a single instruction. When we add a concept of colocated definitions, this + ; test can be re-enabled. + ; disabled: asm: call foo + ; disabled: call fn0() ; bin: e8 PCRel4(%foo-4) 00000000 ; asm: movabsq $0, %rcx [-,%rcx] v400 = func_addr.i64 fn0 ; bin: 48 b9 Abs8(%foo) 0000000000000000 diff --git a/cranelift/filetests/isa/intel/legalize-libcall.cton b/cranelift/filetests/isa/intel/legalize-libcall.cton index c15587fc7f..239b3e5a57 100644 --- a/cranelift/filetests/isa/intel/legalize-libcall.cton +++ b/cranelift/filetests/isa/intel/legalize-libcall.cton @@ -2,6 +2,7 @@ test legalizer ; Pre-SSE 4.1, we need to use runtime library calls for floating point rounding operations. set is_64bit +set is_pic isa intel function %floor(f32) -> f32 { diff --git a/cranelift/filetests/isa/intel/prologue-epilogue.cton b/cranelift/filetests/isa/intel/prologue-epilogue.cton index 416f90df63..0eadcd27d7 100644 --- a/cranelift/filetests/isa/intel/prologue-epilogue.cton +++ b/cranelift/filetests/isa/intel/prologue-epilogue.cton @@ -1,6 +1,7 @@ test compile set is_64bit set is_compressed +set is_pic isa intel haswell ; An empty function. diff --git a/lib/cretonne/meta/base/legalize.py b/lib/cretonne/meta/base/legalize.py index c2392269df..95a58987d3 100644 --- a/lib/cretonne/meta/base/legalize.py +++ b/lib/cretonne/meta/base/legalize.py @@ -65,6 +65,9 @@ expand_flags = XFormGroup('expand_flags', """ expand.custom_legalize(insts.global_addr, 'expand_global_addr') expand.custom_legalize(insts.heap_addr, 'expand_heap_addr') +# Custom expansions for calls. +expand.custom_legalize(insts.call, 'expand_call') + # Custom expansions that need to change the CFG. # TODO: Add sufficient XForm syntax that we don't need to hand-code these. expand.custom_legalize(insts.trapz, 'expand_cond_trap') diff --git a/lib/cretonne/meta/isa/intel/encodings.py b/lib/cretonne/meta/isa/intel/encodings.py index 4d4fa12ced..c7833d04bc 100644 --- a/lib/cretonne/meta/isa/intel/encodings.py +++ b/lib/cretonne/meta/isa/intel/encodings.py @@ -321,7 +321,6 @@ X86_64.enc(base.globalsym_addr.i64, *r.got_gvaddr8.rex(0x8b, w=1), # Call/return # X86_32.enc(base.call, *r.call_id(0xe8)) -X86_64.enc(base.call, *r.call_id(0xe8), isap=Not(is_pic)) X86_64.enc(base.call, *r.call_plt_id(0xe8), isap=is_pic) X86_32.enc(base.call_indirect.i32, *r.call_r(0xff, rrr=2)) diff --git a/lib/cretonne/src/legalizer/call.rs b/lib/cretonne/src/legalizer/call.rs new file mode 100644 index 0000000000..d1d8bcba08 --- /dev/null +++ b/lib/cretonne/src/legalizer/call.rs @@ -0,0 +1,60 @@ +//! Legalization of calls. +//! +//! This module exports the `expand_call` function which transforms a `call` +//! instruction into `func_addr` and `call_indirect` instructions. + +use cursor::{Cursor, FuncCursor}; +use flowgraph::ControlFlowGraph; +use ir::{self, InstBuilder}; +use isa::TargetIsa; + +/// Expand a `call` instruction. +pub fn expand_call( + inst: ir::Inst, + func: &mut ir::Function, + _cfg: &mut ControlFlowGraph, + isa: &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 = if isa.flags().is_64bit() { + ir::types::I64 + } else { + ir::types::I32 + }; + + 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).IndirectCall( + ir::Opcode::CallIndirect, + ptr_ty, + sig, + new_args, + ); +} diff --git a/lib/cretonne/src/legalizer/mod.rs b/lib/cretonne/src/legalizer/mod.rs index 23b3f56c89..4486d5df4e 100644 --- a/lib/cretonne/src/legalizer/mod.rs +++ b/lib/cretonne/src/legalizer/mod.rs @@ -21,6 +21,7 @@ use isa::TargetIsa; use timing; mod boundary; +mod call; mod globalvar; mod heap; mod libcall; @@ -28,6 +29,7 @@ mod split; use self::globalvar::expand_global_addr; use self::heap::expand_heap_addr; +use self::call::expand_call; use self::libcall::expand_as_libcall; /// Legalize `func` for `isa`.