Introduce a TargetFrontendConfig type. (#570)
* Introduce a `TargetFrontendConfig` type. `TargetFrontendConfig` is information specific to the target which is provided to frontends to allow them to produce Cranelift IR for the target. Currently this includes the pointer size and the default calling convention. The default calling convention is now inferred from the target, rather than being a setting. cranelift-native is now just a provider of target information, rather than also being a provider of settings, which gives it a clearer role. And instead of having cranelift-frontend routines require the whole `TargetIsa`, just require the `TargetFrontendConfig`, and add a way to get the `TargetFrontendConfig` from a `Module`. Fixes #529. Fixes #555.
This commit is contained in:
@@ -6,8 +6,7 @@
|
||||
//! This module declares the data types used to represent external functions and call signatures.
|
||||
|
||||
use ir::{ArgumentLoc, ExternalName, SigRef, Type};
|
||||
use isa::{RegInfo, RegUnit};
|
||||
use settings::CallConv;
|
||||
use isa::{CallConv, RegInfo, RegUnit};
|
||||
use std::fmt;
|
||||
use std::str::FromStr;
|
||||
use std::vec::Vec;
|
||||
|
||||
@@ -13,9 +13,8 @@ use ir::{
|
||||
};
|
||||
use ir::{EbbOffsets, InstEncodings, SourceLocs, StackSlots, ValueLocations};
|
||||
use ir::{JumpTableOffsets, JumpTables};
|
||||
use isa::{EncInfo, Encoding, Legalize, TargetIsa};
|
||||
use isa::{CallConv, EncInfo, Encoding, Legalize, TargetIsa};
|
||||
use regalloc::RegDiversions;
|
||||
use settings::CallConv;
|
||||
use std::fmt;
|
||||
use write::write_function;
|
||||
|
||||
|
||||
@@ -4,8 +4,7 @@ use ir::{
|
||||
types, AbiParam, ArgumentPurpose, ExtFuncData, ExternalName, FuncRef, Function, Inst, Opcode,
|
||||
Signature, Type,
|
||||
};
|
||||
use isa::{RegUnit, TargetIsa};
|
||||
use settings::CallConv;
|
||||
use isa::{CallConv, RegUnit, TargetIsa};
|
||||
use std::fmt;
|
||||
use std::str::FromStr;
|
||||
|
||||
@@ -166,8 +165,7 @@ fn make_funcref_for_inst(
|
||||
inst: Inst,
|
||||
isa: &TargetIsa,
|
||||
) -> FuncRef {
|
||||
// Start with a fast calling convention. We'll give the ISA a chance to change it.
|
||||
let mut sig = Signature::new(isa.flags().call_conv());
|
||||
let mut sig = Signature::new(isa.default_call_conv());
|
||||
for &v in func.dfg.inst_args(inst) {
|
||||
sig.params.push(AbiParam::new(func.dfg.value_type(v)));
|
||||
}
|
||||
|
||||
74
lib/codegen/src/isa/call_conv.rs
Normal file
74
lib/codegen/src/isa/call_conv.rs
Normal file
@@ -0,0 +1,74 @@
|
||||
use std::fmt;
|
||||
use std::str;
|
||||
use target_lexicon::{OperatingSystem, Triple};
|
||||
|
||||
/// Calling convention identifiers.
|
||||
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
|
||||
pub enum CallConv {
|
||||
/// Best performance, not ABI-stable
|
||||
Fast,
|
||||
/// Smallest caller code size, not ABI-stable
|
||||
Cold,
|
||||
/// System V-style convention used on many platforms
|
||||
SystemV,
|
||||
/// Windows "fastcall" convention, also used for x64 and ARM
|
||||
WindowsFastcall,
|
||||
/// SpiderMonkey WebAssembly convention
|
||||
Baldrdash,
|
||||
/// Specialized convention for the probestack function
|
||||
Probestack,
|
||||
}
|
||||
|
||||
impl CallConv {
|
||||
/// Return the default calling convention for the given target triple.
|
||||
pub fn default_for_triple(triple: &Triple) -> Self {
|
||||
match triple.operating_system {
|
||||
OperatingSystem::Unknown
|
||||
| OperatingSystem::Bitrig
|
||||
| OperatingSystem::Cloudabi
|
||||
| OperatingSystem::Darwin
|
||||
| OperatingSystem::Dragonfly
|
||||
| OperatingSystem::Freebsd
|
||||
| OperatingSystem::Fuchsia
|
||||
| OperatingSystem::Haiku
|
||||
| OperatingSystem::Ios
|
||||
| OperatingSystem::L4re
|
||||
| OperatingSystem::Linux
|
||||
| OperatingSystem::Nebulet
|
||||
| OperatingSystem::Netbsd
|
||||
| OperatingSystem::Openbsd
|
||||
| OperatingSystem::Redox
|
||||
| OperatingSystem::Solaris => CallConv::SystemV,
|
||||
OperatingSystem::Windows => CallConv::WindowsFastcall,
|
||||
os => panic!("unsupported operating system: {}", os),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for CallConv {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
f.write_str(match *self {
|
||||
CallConv::Fast => "fast",
|
||||
CallConv::Cold => "cold",
|
||||
CallConv::SystemV => "system_v",
|
||||
CallConv::WindowsFastcall => "windows_fastcall",
|
||||
CallConv::Baldrdash => "baldrdash",
|
||||
CallConv::Probestack => "probestack",
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl str::FromStr for CallConv {
|
||||
type Err = ();
|
||||
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||
match s {
|
||||
"fast" => Ok(CallConv::Fast),
|
||||
"cold" => Ok(CallConv::Cold),
|
||||
"system_v" => Ok(CallConv::SystemV),
|
||||
"windows_fastcall" => Ok(CallConv::WindowsFastcall),
|
||||
"baldrdash" => Ok(CallConv::Baldrdash),
|
||||
"probestack" => Ok(CallConv::Probestack),
|
||||
_ => Err(()),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -46,6 +46,7 @@
|
||||
//! The configured target ISA trait object is a `Box<TargetIsa>` which can be used for multiple
|
||||
//! concurrent function compilations.
|
||||
|
||||
pub use isa::call_conv::CallConv;
|
||||
pub use isa::constraints::{BranchRange, ConstraintKind, OperandConstraint, RecipeConstraints};
|
||||
pub use isa::encoding::{base_size, EncInfo, Encoding};
|
||||
pub use isa::registers::{regs_overlap, RegClass, RegClassIndex, RegInfo, RegUnit};
|
||||
@@ -58,10 +59,10 @@ use isa::enc_tables::Encodings;
|
||||
use regalloc;
|
||||
use result::CodegenResult;
|
||||
use settings;
|
||||
use settings::{CallConv, SetResult};
|
||||
use settings::SetResult;
|
||||
use std::boxed::Box;
|
||||
use std::fmt;
|
||||
use target_lexicon::{Architecture, Triple};
|
||||
use target_lexicon::{Architecture, PointerWidth, Triple};
|
||||
use timing;
|
||||
|
||||
#[cfg(build_riscv)]
|
||||
@@ -76,6 +77,7 @@ mod arm32;
|
||||
#[cfg(build_arm64)]
|
||||
mod arm64;
|
||||
|
||||
mod call_conv;
|
||||
mod constraints;
|
||||
mod enc_tables;
|
||||
mod encoding;
|
||||
@@ -164,6 +166,34 @@ impl settings::Configurable for Builder {
|
||||
pub type Legalize =
|
||||
fn(ir::Inst, &mut ir::Function, &mut flowgraph::ControlFlowGraph, &TargetIsa) -> bool;
|
||||
|
||||
/// This struct provides information that a frontend may need to know about a target to
|
||||
/// produce Cranelift IR for the target.
|
||||
#[derive(Clone, Copy)]
|
||||
pub struct TargetFrontendConfig {
|
||||
/// The default calling convention of the target.
|
||||
pub default_call_conv: CallConv,
|
||||
|
||||
/// The pointer width of the target.
|
||||
pub pointer_width: PointerWidth,
|
||||
}
|
||||
|
||||
impl TargetFrontendConfig {
|
||||
/// Get the pointer type of this target.
|
||||
pub fn pointer_type(&self) -> ir::Type {
|
||||
ir::Type::int(u16::from(self.pointer_bits())).unwrap()
|
||||
}
|
||||
|
||||
/// Get the width of pointers on this target, in units of bits.
|
||||
pub fn pointer_bits(&self) -> u8 {
|
||||
self.pointer_width.bits()
|
||||
}
|
||||
|
||||
/// Get the width of pointers on this target, in units of bytes.
|
||||
pub fn pointer_bytes(&self) -> u8 {
|
||||
self.pointer_width.bytes()
|
||||
}
|
||||
}
|
||||
|
||||
/// Methods that are specialized to a target ISA. Implies a Display trait that shows the
|
||||
/// shared flags, as well as any isa-specific flags.
|
||||
pub trait TargetIsa: fmt::Display {
|
||||
@@ -176,19 +206,37 @@ pub trait TargetIsa: fmt::Display {
|
||||
/// Get the ISA-independent flags that were used to make this trait object.
|
||||
fn flags(&self) -> &settings::Flags;
|
||||
|
||||
/// Get the default calling convention of this target.
|
||||
fn default_call_conv(&self) -> CallConv {
|
||||
CallConv::default_for_triple(self.triple())
|
||||
}
|
||||
|
||||
/// Get the pointer type of this ISA.
|
||||
fn pointer_type(&self) -> ir::Type {
|
||||
ir::Type::int(u16::from(self.pointer_bits())).unwrap()
|
||||
}
|
||||
|
||||
/// Get the width of pointers on this ISA.
|
||||
fn pointer_width(&self) -> PointerWidth {
|
||||
self.triple().pointer_width().unwrap()
|
||||
}
|
||||
|
||||
/// Get the width of pointers on this ISA, in units of bits.
|
||||
fn pointer_bits(&self) -> u8 {
|
||||
self.triple().pointer_width().unwrap().bits()
|
||||
self.pointer_width().bits()
|
||||
}
|
||||
|
||||
/// Get the width of pointers on this ISA, in units of bytes.
|
||||
fn pointer_bytes(&self) -> u8 {
|
||||
self.triple().pointer_width().unwrap().bytes()
|
||||
self.pointer_width().bytes()
|
||||
}
|
||||
|
||||
/// Get the information needed by frontends producing Cranelift IR.
|
||||
fn frontend_config(&self) -> TargetFrontendConfig {
|
||||
TargetFrontendConfig {
|
||||
default_call_conv: self.default_call_conv(),
|
||||
pointer_width: self.pointer_width(),
|
||||
}
|
||||
}
|
||||
|
||||
/// Does the CPU implement scalar comparisons using a CPU flags register?
|
||||
|
||||
@@ -10,10 +10,9 @@ use ir::{
|
||||
get_probestack_funcref, AbiParam, ArgumentExtension, ArgumentLoc, ArgumentPurpose, InstBuilder,
|
||||
ValueLoc,
|
||||
};
|
||||
use isa::{RegClass, RegUnit, TargetIsa};
|
||||
use isa::{CallConv, RegClass, RegUnit, TargetIsa};
|
||||
use regalloc::RegisterSet;
|
||||
use result::CodegenResult;
|
||||
use settings::CallConv;
|
||||
use stack_layout::layout_stack;
|
||||
use std::i32;
|
||||
use target_lexicon::{PointerWidth, Triple};
|
||||
@@ -189,12 +188,12 @@ pub fn allocatable_registers(_func: &ir::Function, triple: &Triple) -> RegisterS
|
||||
}
|
||||
|
||||
/// Get the set of callee-saved registers.
|
||||
fn callee_saved_gprs(isa: &TargetIsa) -> &'static [RU] {
|
||||
fn callee_saved_gprs(isa: &TargetIsa, call_conv: CallConv) -> &'static [RU] {
|
||||
match isa.triple().pointer_width().unwrap() {
|
||||
PointerWidth::U16 => panic!(),
|
||||
PointerWidth::U32 => &[RU::rbx, RU::rsi, RU::rdi],
|
||||
PointerWidth::U64 => {
|
||||
if isa.flags().call_conv() == CallConv::WindowsFastcall {
|
||||
if call_conv == CallConv::WindowsFastcall {
|
||||
// "registers RBX, RBP, RDI, RSI, RSP, R12, R13, R14, R15 are considered nonvolatile
|
||||
// and must be saved and restored by a function that uses them."
|
||||
// as per https://msdn.microsoft.com/en-us/library/6t169e9c.aspx
|
||||
@@ -219,7 +218,7 @@ fn callee_saved_gprs(isa: &TargetIsa) -> &'static [RU] {
|
||||
/// Get the set of callee-saved registers that are used.
|
||||
fn callee_saved_gprs_used(isa: &TargetIsa, func: &ir::Function) -> RegisterSet {
|
||||
let mut all_callee_saved = RegisterSet::empty();
|
||||
for reg in callee_saved_gprs(isa) {
|
||||
for reg in callee_saved_gprs(isa, func.signature.call_conv) {
|
||||
all_callee_saved.free(GPR, *reg as RegUnit);
|
||||
}
|
||||
|
||||
|
||||
@@ -372,7 +372,6 @@ mod tests {
|
||||
"[shared]\n\
|
||||
opt_level = \"default\"\n\
|
||||
enable_verifier = true\n\
|
||||
call_conv = \"fast\"\n\
|
||||
is_pic = false\n\
|
||||
colocated_libcalls = false\n\
|
||||
avoid_div_traps = false\n\
|
||||
|
||||
Reference in New Issue
Block a user