From eab57c0a408a2726f887a2aab2d4873b3c03e655 Mon Sep 17 00:00:00 2001 From: Dan Gohman Date: Mon, 9 Apr 2018 14:53:00 -0700 Subject: [PATCH] Use large-model addressing for calls when in non-PIC mode. The main use for non-PIC code at present is JIT code, and JIT code can live anywhere in memory and reference other symbols defined anywhere in memory, so it needs to use the "large" code model. func_addr and globalsym_addr instructions were already using `movabs` to support arbitrary 64-bit addresses, so this just makes calls be legalized to support arbitrary 64-bit addresses also. --- cranelift/filetests/isa/intel/binary64.cton | 7 ++- .../filetests/isa/intel/legalize-libcall.cton | 1 + .../isa/intel/prologue-epilogue.cton | 1 + lib/cretonne/meta/base/legalize.py | 3 + lib/cretonne/meta/isa/intel/encodings.py | 1 - lib/cretonne/src/legalizer/call.rs | 60 +++++++++++++++++++ lib/cretonne/src/legalizer/mod.rs | 2 + 7 files changed, 72 insertions(+), 3 deletions(-) create mode 100644 lib/cretonne/src/legalizer/call.rs 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`.