Use the target-lexicon crate.

This switches from a custom list of architectures to use the
target-lexicon crate.

 - "set is_64bit=1; isa x86" is replaced with "target x86_64", and
   similar for other architectures, and the `is_64bit` flag is removed
   entirely.

 - The `is_compressed` flag is removed too; it's no longer being used to
   control REX prefixes on x86-64, ARM and Thumb are separate
   architectures in target-lexicon, and we can figure out how to
   select RISC-V compressed encodings when we're ready.
This commit is contained in:
Dan Gohman
2018-05-25 11:41:14 -07:00
parent 2f3008aa40
commit 4e67e08efd
131 changed files with 487 additions and 499 deletions

View File

@@ -15,6 +15,7 @@ cretonne-entity = { path = "../entity", version = "0.8.0", default-features = fa
failure = { version = "0.1.1", default-features = false, features = ["derive"] }
failure_derive = { version = "0.1.1", default-features = false }
hashmap_core = { version = "0.1.4", optional = true }
target-lexicon = { version = "0.0.0", default-features = false }
# It is a goal of the cretonne-codegen crate to have minimal external dependencies.
# Please don't add any unless they are essential to the task of creating binary
# machine code. Integration tests that need external dependencies can be

View File

@@ -27,8 +27,6 @@ enable_verifier = BoolSetting(
""",
default=True)
is_64bit = BoolSetting("Enable 64-bit code generation")
call_conv = EnumSetting(
"""
Default calling convention:
@@ -89,8 +87,6 @@ avoid_div_traps = BoolSetting(
this setting has no effect - explicit checks are always inserted.
""")
is_compressed = BoolSetting("Enable compressed instructions")
enable_float = BoolSetting(
"""
Enable the use of floating-point instructions

View File

@@ -15,32 +15,43 @@ use isa::{EncInfo, RegClass, RegInfo, TargetIsa};
use regalloc;
use std::boxed::Box;
use std::fmt;
use target_lexicon::{Architecture, Triple};
#[allow(dead_code)]
struct Isa {
triple: Triple,
shared_flags: shared_settings::Flags,
isa_flags: settings::Flags,
cpumode: &'static [shared_enc_tables::Level1Entry<u16>],
}
/// Get an ISA builder for creating ARM32 targets.
pub fn isa_builder() -> IsaBuilder {
pub fn isa_builder(triple: Triple) -> IsaBuilder {
IsaBuilder {
triple,
setup: settings::builder(),
constructor: isa_constructor,
}
}
fn isa_constructor(
triple: Triple,
shared_flags: shared_settings::Flags,
builder: shared_settings::Builder,
) -> Box<TargetIsa> {
let level1 = if shared_flags.is_compressed() {
&enc_tables::LEVEL1_T32[..]
} else {
&enc_tables::LEVEL1_A32[..]
let level1 = match triple.architecture {
Architecture::Thumbv6m | Architecture::Thumbv7em | Architecture::Thumbv7m => {
&enc_tables::LEVEL1_T32[..]
}
Architecture::Arm
| Architecture::Armv4t
| Architecture::Armv5te
| Architecture::Armv7
| Architecture::Armv7s => &enc_tables::LEVEL1_A32[..],
_ => panic!(),
};
Box::new(Isa {
triple,
isa_flags: settings::Flags::new(&shared_flags, builder),
shared_flags,
cpumode: level1,
@@ -52,6 +63,10 @@ impl TargetIsa for Isa {
"arm32"
}
fn triple(&self) -> &Triple {
&self.triple
}
fn flags(&self) -> &shared_settings::Flags {
&self.shared_flags
}

View File

@@ -15,26 +15,31 @@ use isa::{EncInfo, RegClass, RegInfo, TargetIsa};
use regalloc;
use std::boxed::Box;
use std::fmt;
use target_lexicon::Triple;
#[allow(dead_code)]
struct Isa {
triple: Triple,
shared_flags: shared_settings::Flags,
isa_flags: settings::Flags,
}
/// Get an ISA builder for creating ARM64 targets.
pub fn isa_builder() -> IsaBuilder {
pub fn isa_builder(triple: Triple) -> IsaBuilder {
IsaBuilder {
triple,
setup: settings::builder(),
constructor: isa_constructor,
}
}
fn isa_constructor(
triple: Triple,
shared_flags: shared_settings::Flags,
builder: shared_settings::Builder,
) -> Box<TargetIsa> {
Box::new(Isa {
triple,
isa_flags: settings::Flags::new(&shared_flags, builder),
shared_flags,
})
@@ -45,6 +50,10 @@ impl TargetIsa for Isa {
"arm64"
}
fn triple(&self) -> &Triple {
&self.triple
}
fn flags(&self) -> &shared_settings::Flags {
&self.shared_flags
}

View File

@@ -20,13 +20,18 @@
//! appropriate for the requested ISA:
//!
//! ```
//! # extern crate cretonne_codegen;
//! # #[macro_use] extern crate target_lexicon;
//! # fn main() {
//! use cretonne_codegen::settings::{self, Configurable};
//! use cretonne_codegen::isa;
//! use std::str::FromStr;
//! use target_lexicon::Triple;
//!
//! let shared_builder = settings::builder();
//! let shared_flags = settings::Flags::new(shared_builder);
//!
//! match isa::lookup("riscv") {
//! match isa::lookup(triple!("riscv32")) {
//! Err(_) => {
//! // The RISC-V target ISA is not available.
//! }
@@ -35,6 +40,7 @@
//! let isa = isa_builder.finish(shared_flags);
//! }
//! }
//! # }
//! ```
//!
//! The configured target ISA trait object is a `Box<TargetIsa>` which can be used for multiple
@@ -55,6 +61,7 @@ use settings;
use settings::CallConv;
use std::boxed::Box;
use std::fmt;
use target_lexicon::{Architecture, Triple};
use timing;
#[cfg(build_riscv)]
@@ -80,51 +87,61 @@ mod stack;
macro_rules! isa_builder {
($module:ident, $name:ident) => {{
#[cfg($name)]
fn $name() -> Result<Builder, LookupError> {
Ok($module::isa_builder())
fn $name(triple: Triple) -> Result<Builder, LookupError> {
Ok($module::isa_builder(triple))
};
#[cfg(not($name))]
fn $name() -> Result<Builder, LookupError> {
fn $name(_triple: Triple) -> Result<Builder, LookupError> {
Err(LookupError::Unsupported)
}
$name()
$name
}};
}
/// Look for a supported ISA with the given `name`.
/// Return a builder that can create a corresponding `TargetIsa`.
pub fn lookup(name: &str) -> Result<Builder, LookupError> {
match name {
"riscv" => isa_builder!(riscv, build_riscv),
"x86" => isa_builder!(x86, build_x86),
"arm32" => isa_builder!(arm32, build_arm32),
"arm64" => isa_builder!(arm64, build_arm64),
_ => Err(LookupError::Unknown),
pub fn lookup(triple: Triple) -> Result<Builder, LookupError> {
match triple.architecture {
Architecture::Riscv32 | Architecture::Riscv64 => isa_builder!(riscv, build_riscv)(triple),
Architecture::I386 | Architecture::I586 | Architecture::I686 | Architecture::X86_64 => {
isa_builder!(x86, build_x86)(triple)
}
Architecture::Thumbv6m
| Architecture::Thumbv7em
| Architecture::Thumbv7m
| Architecture::Arm
| Architecture::Armv4t
| Architecture::Armv5te
| Architecture::Armv7
| Architecture::Armv7s => isa_builder!(arm32, build_arm32)(triple),
Architecture::Aarch64 => isa_builder!(arm64, build_arm64)(triple),
_ => Err(LookupError::Unsupported),
}
}
/// Describes reason for target lookup failure
#[derive(PartialEq, Eq, Copy, Clone, Debug)]
pub enum LookupError {
/// Unknown Target
Unknown,
/// Support for this target was disabled in the current build.
SupportDisabled,
/// Target known but not built and thus not supported
/// Support for this target has not yet been implemented.
Unsupported,
}
/// Builder for a `TargetIsa`.
/// Modify the ISA-specific settings before creating the `TargetIsa` trait object with `finish`.
pub struct Builder {
triple: Triple,
setup: settings::Builder,
constructor: fn(settings::Flags, settings::Builder) -> Box<TargetIsa>,
constructor: fn(Triple, settings::Flags, settings::Builder) -> Box<TargetIsa>,
}
impl Builder {
/// Combine the ISA-specific settings with the provided ISA-independent settings and allocate a
/// fully configured `TargetIsa` trait object.
pub fn finish(self, shared_flags: settings::Flags) -> Box<TargetIsa> {
(self.constructor)(shared_flags, self.setup)
(self.constructor)(self.triple, shared_flags, self.setup)
}
}
@@ -151,9 +168,17 @@ pub trait TargetIsa: fmt::Display {
/// Get the name of this ISA.
fn name(&self) -> &'static str;
/// Get the target triple that was used to make this trait object.
fn triple(&self) -> &Triple;
/// Get the ISA-independent flags that were used to make this trait object.
fn flags(&self) -> &settings::Flags;
/// Get the pointer type of this ISA.
fn pointer_type(&self) -> ir::Type {
ir::Type::int(u16::from(self.triple().pointer_width().unwrap().bits())).unwrap()
}
/// Does the CPU implement scalar comparisons using a CPU flags register?
fn uses_cpu_flags(&self) -> bool {
false
@@ -252,7 +277,7 @@ pub trait TargetIsa: fmt::Display {
use ir::stackslot::{StackOffset, StackSize};
use stack_layout::layout_stack;
let word_size = if self.flags().is_64bit() { 8 } else { 4 };
let word_size = StackSize::from(self.triple().pointer_width().unwrap().bytes());
// Account for the SpiderMonkey standard prologue pushes.
if func.signature.call_conv == CallConv::Baldrdash {

View File

@@ -11,12 +11,12 @@ use abi::{legalize_args, ArgAction, ArgAssigner, ValueConversion};
use ir::{self, AbiParam, ArgumentExtension, ArgumentLoc, ArgumentPurpose, Type};
use isa::RegClass;
use regalloc::RegisterSet;
use settings as shared_settings;
use std::i32;
use target_lexicon::Triple;
struct Args {
pointer_bits: u16,
pointer_bytes: u32,
pointer_bits: u8,
pointer_bytes: u8,
pointer_type: Type,
regs: u32,
reg_limit: u32,
@@ -24,11 +24,11 @@ struct Args {
}
impl Args {
fn new(bits: u16, enable_e: bool) -> Self {
fn new(bits: u8, enable_e: bool) -> Self {
Self {
pointer_bits: bits,
pointer_bytes: u32::from(bits) / 8,
pointer_type: Type::int(bits).unwrap(),
pointer_bytes: bits / 8,
pointer_type: Type::int(u16::from(bits)).unwrap(),
regs: 0,
reg_limit: if enable_e { 6 } else { 8 },
offset: 0,
@@ -51,15 +51,15 @@ impl ArgAssigner for Args {
}
// Large integers and booleans are broken down to fit in a register.
if !ty.is_float() && ty.bits() > self.pointer_bits {
if !ty.is_float() && ty.bits() > u16::from(self.pointer_bits) {
// Align registers and stack to a multiple of two pointers.
self.regs = align(self.regs, 2);
self.offset = align(self.offset, 2 * self.pointer_bytes);
self.offset = align(self.offset, 2 * u32::from(self.pointer_bytes));
return ValueConversion::IntSplit.into();
}
// Small integers are extended to the size of a pointer register.
if ty.is_int() && ty.bits() < self.pointer_bits {
if ty.is_int() && ty.bits() < u16::from(self.pointer_bits) {
match arg.extension {
ArgumentExtension::None => {}
ArgumentExtension::Uext => return ValueConversion::Uext(self.pointer_type).into(),
@@ -79,7 +79,7 @@ impl ArgAssigner for Args {
} else {
// Assign a stack location.
let loc = ArgumentLoc::Stack(self.offset as i32);
self.offset += self.pointer_bytes;
self.offset += u32::from(self.pointer_bytes);
debug_assert!(self.offset <= i32::MAX as u32);
loc.into()
}
@@ -89,11 +89,11 @@ impl ArgAssigner for Args {
/// Legalize `sig` for RISC-V.
pub fn legalize_signature(
sig: &mut ir::Signature,
flags: &shared_settings::Flags,
triple: &Triple,
isa_flags: &settings::Flags,
current: bool,
) {
let bits = if flags.is_64bit() { 64 } else { 32 };
let bits = triple.pointer_width().unwrap().bits();
let mut args = Args::new(bits, isa_flags.enable_e());
legalize_args(&mut sig.params, &mut args);
@@ -102,7 +102,7 @@ pub fn legalize_signature(
legalize_args(&mut sig.returns, &mut rets);
if current {
let ptr = Type::int(bits).unwrap();
let ptr = Type::int(u16::from(bits)).unwrap();
// Add the link register as an argument and return value.
//

View File

@@ -15,32 +15,37 @@ use isa::{EncInfo, RegClass, RegInfo, TargetIsa};
use regalloc;
use std::boxed::Box;
use std::fmt;
use target_lexicon::{PointerWidth, Triple};
#[allow(dead_code)]
struct Isa {
triple: Triple,
shared_flags: shared_settings::Flags,
isa_flags: settings::Flags,
cpumode: &'static [shared_enc_tables::Level1Entry<u16>],
}
/// Get an ISA builder for creating RISC-V targets.
pub fn isa_builder() -> IsaBuilder {
pub fn isa_builder(triple: Triple) -> IsaBuilder {
IsaBuilder {
triple,
setup: settings::builder(),
constructor: isa_constructor,
}
}
fn isa_constructor(
triple: Triple,
shared_flags: shared_settings::Flags,
builder: shared_settings::Builder,
) -> Box<TargetIsa> {
let level1 = if shared_flags.is_64bit() {
&enc_tables::LEVEL1_RV64[..]
} else {
&enc_tables::LEVEL1_RV32[..]
let level1 = match triple.pointer_width().unwrap() {
PointerWidth::U16 => panic!("16-bit RISC-V unrecognized"),
PointerWidth::U32 => &enc_tables::LEVEL1_RV32[..],
PointerWidth::U64 => &enc_tables::LEVEL1_RV64[..],
};
Box::new(Isa {
triple,
isa_flags: settings::Flags::new(&shared_flags, builder),
shared_flags,
cpumode: level1,
@@ -52,6 +57,10 @@ impl TargetIsa for Isa {
"riscv"
}
fn triple(&self) -> &Triple {
&self.triple
}
fn flags(&self) -> &shared_settings::Flags {
&self.shared_flags
}
@@ -85,7 +94,7 @@ impl TargetIsa for Isa {
}
fn legalize_signature(&self, sig: &mut ir::Signature, current: bool) {
abi::legalize_signature(sig, &self.shared_flags, &self.isa_flags, current)
abi::legalize_signature(sig, &self.triple, &self.isa_flags, current)
}
fn regclass_for_abi_type(&self, ty: ir::Type) -> RegClass {
@@ -117,7 +126,9 @@ mod tests {
use ir::{Function, InstructionData, Opcode};
use isa;
use settings::{self, Configurable};
use std::str::FromStr;
use std::string::{String, ToString};
use target_lexicon;
fn encstr(isa: &isa::TargetIsa, enc: Result<isa::Encoding, isa::Legalize>) -> String {
match enc {
@@ -128,10 +139,11 @@ mod tests {
#[test]
fn test_64bitenc() {
let mut shared_builder = settings::builder();
shared_builder.enable("is_64bit").unwrap();
let shared_builder = settings::builder();
let shared_flags = settings::Flags::new(shared_builder);
let isa = isa::lookup("riscv").unwrap().finish(shared_flags);
let isa = isa::lookup(triple!("riscv64"))
.unwrap()
.finish(shared_flags);
let mut func = Function::new();
let ebb = func.dfg.make_ebb();
@@ -178,10 +190,11 @@ mod tests {
// Same as above, but for RV32.
#[test]
fn test_32bitenc() {
let mut shared_builder = settings::builder();
shared_builder.set("is_64bit", "false").unwrap();
let shared_builder = settings::builder();
let shared_flags = settings::Flags::new(shared_builder);
let isa = isa::lookup("riscv").unwrap().finish(shared_flags);
let isa = isa::lookup(triple!("riscv32"))
.unwrap()
.finish(shared_flags);
let mut func = Function::new();
let ebb = func.dfg.make_ebb();
@@ -232,13 +245,12 @@ mod tests {
#[test]
fn test_rv32m() {
let mut shared_builder = settings::builder();
shared_builder.set("is_64bit", "false").unwrap();
let shared_builder = settings::builder();
let shared_flags = settings::Flags::new(shared_builder);
// Set the supports_m stting which in turn enables the use_m predicate that unlocks
// encodings for imul.
let mut isa_builder = isa::lookup("riscv").unwrap();
let mut isa_builder = isa::lookup(triple!("riscv32")).unwrap();
isa_builder.enable("supports_m").unwrap();
let isa = isa_builder.finish(shared_flags);

View File

@@ -11,10 +11,10 @@ use ir::{get_probestack_funcref, AbiParam, ArgumentExtension, ArgumentLoc, Argum
use isa::{RegClass, RegUnit, TargetIsa};
use regalloc::RegisterSet;
use result;
use settings as shared_settings;
use settings::CallConv;
use stack_layout::layout_stack;
use std::i32;
use target_lexicon::{PointerWidth, Triple};
/// Argument registers for x86-64
static ARG_GPRS: [RU; 6] = [RU::rdi, RU::rsi, RU::rdx, RU::rcx, RU::r8, RU::r9];
@@ -29,8 +29,8 @@ static ARG_GPRS_WIN_FASTCALL_X64: [RU; 4] = [RU::rcx, RU::rdx, RU::r8, RU::r9];
static RET_GPRS_WIN_FASTCALL_X64: [RU; 1] = [RU::rax];
struct Args {
pointer_bytes: u32,
pointer_bits: u16,
pointer_bytes: u8,
pointer_bits: u8,
pointer_type: ir::Type,
gpr: &'static [RU],
gpr_used: usize,
@@ -41,7 +41,7 @@ struct Args {
}
impl Args {
fn new(bits: u16, gpr: &'static [RU], fpr_limit: usize, call_conv: CallConv) -> Self {
fn new(bits: u8, gpr: &'static [RU], fpr_limit: usize, call_conv: CallConv) -> Self {
let offset = if let CallConv::WindowsFastcall = call_conv {
// [1] "The caller is responsible for allocating space for parameters to the callee,
// and must always allocate sufficient space to store four register parameters"
@@ -51,9 +51,9 @@ impl Args {
};
Self {
pointer_bytes: u32::from(bits) / 8,
pointer_bytes: bits / 8,
pointer_bits: bits,
pointer_type: ir::Type::int(bits).unwrap(),
pointer_type: ir::Type::int(u16::from(bits)).unwrap(),
gpr,
gpr_used: 0,
fpr_limit,
@@ -75,12 +75,12 @@ impl ArgAssigner for Args {
}
// Large integers and booleans are broken down to fit in a register.
if !ty.is_float() && ty.bits() > self.pointer_bits {
if !ty.is_float() && ty.bits() > u16::from(self.pointer_bits) {
return ValueConversion::IntSplit.into();
}
// Small integers are extended to the size of a pointer register.
if ty.is_int() && ty.bits() < self.pointer_bits {
if ty.is_int() && ty.bits() < u16::from(self.pointer_bits) {
match arg.extension {
ArgumentExtension::None => {}
ArgumentExtension::Uext => return ValueConversion::Uext(self.pointer_type).into(),
@@ -122,27 +122,31 @@ impl ArgAssigner for Args {
// Assign a stack location.
let loc = ArgumentLoc::Stack(self.offset as i32);
self.offset += self.pointer_bytes;
self.offset += u32::from(self.pointer_bytes);
debug_assert!(self.offset <= i32::MAX as u32);
loc.into()
}
}
/// Legalize `sig`.
pub fn legalize_signature(sig: &mut ir::Signature, flags: &shared_settings::Flags, _current: bool) {
pub fn legalize_signature(sig: &mut ir::Signature, triple: &Triple, _current: bool) {
let bits;
let mut args;
if flags.is_64bit() {
bits = 64;
args = if sig.call_conv == CallConv::WindowsFastcall {
Args::new(bits, &ARG_GPRS_WIN_FASTCALL_X64[..], 4, sig.call_conv)
} else {
Args::new(bits, &ARG_GPRS[..], 8, sig.call_conv)
};
} else {
bits = 32;
args = Args::new(bits, &[], 0, sig.call_conv);
match triple.pointer_width().unwrap() {
PointerWidth::U16 => panic!(),
PointerWidth::U32 => {
bits = 32;
args = Args::new(bits, &[], 0, sig.call_conv);
}
PointerWidth::U64 => {
bits = 64;
args = if sig.call_conv == CallConv::WindowsFastcall {
Args::new(bits, &ARG_GPRS_WIN_FASTCALL_X64[..], 4, sig.call_conv)
} else {
Args::new(bits, &ARG_GPRS[..], 8, sig.call_conv)
};
}
}
legalize_args(&mut sig.params, &mut args);
@@ -167,13 +171,13 @@ pub fn regclass_for_abi_type(ty: ir::Type) -> RegClass {
}
/// Get the set of allocatable registers for `func`.
pub fn allocatable_registers(_func: &ir::Function, flags: &shared_settings::Flags) -> RegisterSet {
pub fn allocatable_registers(_func: &ir::Function, triple: &Triple) -> RegisterSet {
let mut regs = RegisterSet::new();
regs.take(GPR, RU::rsp as RegUnit);
regs.take(GPR, RU::rbp as RegUnit);
// 32-bit arch only has 8 registers.
if !flags.is_64bit() {
if triple.pointer_width().unwrap() != PointerWidth::U64 {
for i in 8..16 {
regs.take(GPR, GPR.unit(i));
regs.take(FPR, FPR.unit(i));
@@ -184,34 +188,36 @@ pub fn allocatable_registers(_func: &ir::Function, flags: &shared_settings::Flag
}
/// Get the set of callee-saved registers.
fn callee_saved_gprs(flags: &shared_settings::Flags) -> &'static [RU] {
if flags.is_64bit() {
if flags.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
// RSP & RSB are not listed below, since they are restored automatically during
// a function call. If that wasn't the case, function calls (RET) would not work.
&[
RU::rbx,
RU::rdi,
RU::rsi,
RU::r12,
RU::r13,
RU::r14,
RU::r15,
]
} else {
&[RU::rbx, RU::r12, RU::r13, RU::r14, RU::r15]
fn callee_saved_gprs(isa: &TargetIsa) -> &'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 {
// "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
// RSP & RSB are not listed below, since they are restored automatically during
// a function call. If that wasn't the case, function calls (RET) would not work.
&[
RU::rbx,
RU::rdi,
RU::rsi,
RU::r12,
RU::r13,
RU::r14,
RU::r15,
]
} else {
&[RU::rbx, RU::r12, RU::r13, RU::r14, RU::r15]
}
}
} else {
&[RU::rbx, RU::rsi, RU::rdi]
}
}
fn callee_saved_gprs_used(flags: &shared_settings::Flags, func: &ir::Function) -> RegisterSet {
fn callee_saved_gprs_used(isa: &TargetIsa, func: &ir::Function) -> RegisterSet {
let mut all_callee_saved = RegisterSet::empty();
for reg in callee_saved_gprs(flags) {
for reg in callee_saved_gprs(isa) {
all_callee_saved.free(GPR, *reg as RegUnit);
}
@@ -271,7 +277,7 @@ pub fn baldrdash_prologue_epilogue(func: &mut ir::Function, isa: &TargetIsa) ->
// Baldrdash on 32-bit x86 always aligns its stack pointer to 16 bytes.
let stack_align = 16;
let word_size = if isa.flags().is_64bit() { 8 } else { 4 };
let word_size = StackSize::from(isa.triple().pointer_width().unwrap().bytes());
let bytes = StackSize::from(isa.flags().baldrdash_prologue_words()) * word_size;
let mut ss = ir::StackSlotData::new(ir::StackSlotKind::IncomingArg, bytes);
@@ -285,7 +291,7 @@ pub fn baldrdash_prologue_epilogue(func: &mut ir::Function, isa: &TargetIsa) ->
/// Implementation of the fastcall-based Win64 calling convention described at [1]
/// [1] https://msdn.microsoft.com/en-us/library/ms235286.aspx
pub fn fastcall_prologue_epilogue(func: &mut ir::Function, isa: &TargetIsa) -> result::CtonResult {
if !isa.flags().is_64bit() {
if isa.triple().pointer_width().unwrap() != PointerWidth::U64 {
panic!("TODO: windows-fastcall: x86-32 not implemented yet");
}
@@ -293,14 +299,10 @@ pub fn fastcall_prologue_epilogue(func: &mut ir::Function, isa: &TargetIsa) -> r
// which are aligned to 16 bytes in order to aid performance"
let stack_align = 16;
let word_size = if isa.flags().is_64bit() { 8 } else { 4 };
let reg_type = if isa.flags().is_64bit() {
ir::types::I64
} else {
ir::types::I32
};
let word_size = isa.triple().pointer_width().unwrap().bytes() as usize;
let reg_type = isa.pointer_type();
let csrs = callee_saved_gprs_used(isa.flags(), func);
let csrs = callee_saved_gprs_used(isa, func);
// [1] "Space is allocated on the call stack as a shadow store for callees to save"
// This shadow store contains the parameters which are passed through registers (ARG_GPRS)
@@ -364,14 +366,11 @@ pub fn system_v_prologue_epilogue(func: &mut ir::Function, isa: &TargetIsa) -> r
// The original 32-bit x86 ELF ABI had a 4-byte aligned stack pointer, but
// newer versions use a 16-byte aligned stack pointer.
let stack_align = 16;
let word_size = if isa.flags().is_64bit() { 8 } else { 4 };
let reg_type = if isa.flags().is_64bit() {
ir::types::I64
} else {
ir::types::I32
};
let pointer_width = isa.triple().pointer_width().unwrap();
let word_size = pointer_width.bytes() as usize;
let reg_type = ir::Type::int(u16::from(pointer_width.bits())).unwrap();
let csrs = callee_saved_gprs_used(isa.flags(), func);
let csrs = callee_saved_gprs_used(isa, func);
// The reserved stack area is composed of:
// return address + frame pointer + all callee-saved registers
@@ -463,7 +462,8 @@ fn insert_common_prologue(
let callee = get_probestack_funcref(pos.func, reg_type, rax, isa);
// Make the call.
let call = if !isa.flags().is_pic() && isa.flags().is_64bit()
let call = if !isa.flags().is_pic()
&& isa.triple().pointer_width().unwrap() == PointerWidth::U64
&& !pos.func.dfg.ext_funcs[callee].colocated
{
// 64-bit non-PIC non-colocated calls need to be legalized to call_indirect.

View File

@@ -16,33 +16,38 @@ use regalloc;
use result;
use std::boxed::Box;
use std::fmt;
use target_lexicon::{PointerWidth, Triple};
use timing;
#[allow(dead_code)]
struct Isa {
triple: Triple,
shared_flags: shared_settings::Flags,
isa_flags: settings::Flags,
cpumode: &'static [shared_enc_tables::Level1Entry<u16>],
}
/// Get an ISA builder for creating x86 targets.
pub fn isa_builder() -> IsaBuilder {
pub fn isa_builder(triple: Triple) -> IsaBuilder {
IsaBuilder {
triple,
setup: settings::builder(),
constructor: isa_constructor,
}
}
fn isa_constructor(
triple: Triple,
shared_flags: shared_settings::Flags,
builder: shared_settings::Builder,
) -> Box<TargetIsa> {
let level1 = if shared_flags.is_64bit() {
&enc_tables::LEVEL1_I64[..]
} else {
&enc_tables::LEVEL1_I32[..]
let level1 = match triple.pointer_width().unwrap() {
PointerWidth::U16 => unimplemented!("x86-16"),
PointerWidth::U32 => &enc_tables::LEVEL1_I32[..],
PointerWidth::U64 => &enc_tables::LEVEL1_I64[..],
};
Box::new(Isa {
triple,
isa_flags: settings::Flags::new(&shared_flags, builder),
shared_flags,
cpumode: level1,
@@ -54,6 +59,10 @@ impl TargetIsa for Isa {
"x86"
}
fn triple(&self) -> &Triple {
&self.triple
}
fn flags(&self) -> &shared_settings::Flags {
&self.shared_flags
}
@@ -95,7 +104,7 @@ impl TargetIsa for Isa {
}
fn legalize_signature(&self, sig: &mut ir::Signature, current: bool) {
abi::legalize_signature(sig, &self.shared_flags, current)
abi::legalize_signature(sig, &self.triple, current)
}
fn regclass_for_abi_type(&self, ty: ir::Type) -> RegClass {
@@ -103,7 +112,7 @@ impl TargetIsa for Isa {
}
fn allocatable_registers(&self, func: &ir::Function) -> regalloc::RegisterSet {
abi::allocatable_registers(func, &self.shared_flags)
abi::allocatable_registers(func, &self.triple)
}
fn emit_inst(

View File

@@ -28,11 +28,7 @@ pub fn expand_call(
_ => 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 ptr_ty = isa.pointer_type();
let sig = func.dfg.ext_funcs[func_ref].signature;

View File

@@ -283,11 +283,7 @@ pub fn expand_stack_check(
ir::InstructionData::UnaryGlobalVar { global_var, .. } => global_var,
_ => panic!("Want stack_check: {}", func.dfg.display_inst(inst, isa)),
};
let ptr_ty = if isa.flags().is_64bit() {
ir::types::I64
} else {
ir::types::I32
};
let ptr_ty = isa.pointer_type();
let mut pos = FuncCursor::new(func).at_inst(inst);
pos.use_srcloc(inst);

View File

@@ -52,6 +52,11 @@ extern crate alloc;
extern crate failure;
#[macro_use]
extern crate failure_derive;
#[cfg(test)]
#[macro_use]
extern crate target_lexicon;
#[cfg(not(test))]
extern crate target_lexicon;
pub use context::Context;
pub use legalizer::legalize_function;

View File

@@ -275,6 +275,8 @@ mod tests {
use regalloc::RegisterSet;
use std::borrow::Borrow;
use std::boxed::Box;
use std::str::FromStr;
use target_lexicon;
// Make an arm32 `TargetIsa`, if possible.
fn arm32() -> Option<Box<TargetIsa>> {
@@ -284,7 +286,9 @@ mod tests {
let shared_builder = settings::builder();
let shared_flags = settings::Flags::new(shared_builder);
isa::lookup("arm32").ok().map(|b| b.finish(shared_flags))
isa::lookup(triple!("arm"))
.ok()
.map(|b| b.finish(shared_flags))
}
// Get a register class by name.

View File

@@ -1134,6 +1134,8 @@ mod tests {
use isa::{RegClass, RegInfo, RegUnit, TargetIsa};
use regalloc::RegisterSet;
use std::boxed::Box;
use std::str::FromStr;
use target_lexicon;
// Make an arm32 `TargetIsa`, if possible.
fn arm32() -> Option<Box<TargetIsa>> {
@@ -1143,7 +1145,9 @@ mod tests {
let shared_builder = settings::builder();
let shared_flags = settings::Flags::new(shared_builder);
isa::lookup("arm32").ok().map(|b| b.finish(shared_flags))
isa::lookup(triple!("arm"))
.ok()
.map(|b| b.finish(shared_flags))
}
// Get a register class by name.

View File

@@ -361,13 +361,11 @@ mod tests {
"[shared]\n\
opt_level = \"default\"\n\
enable_verifier = true\n\
is_64bit = false\n\
call_conv = \"fast\"\n\
is_pic = false\n\
colocated_libcalls = false\n\
return_at_end = false\n\
avoid_div_traps = false\n\
is_compressed = false\n\
enable_float = true\n\
enable_nan_canonicalization = false\n\
enable_simd = true\n\