machinst x64: Only use the feature flag to enable the x64 new backend;
Before this patch, running the x64 new backend would require both
compiling with --features experimental_x64 and running with
`use_new_backend`.
This patches changes this behavior so that the runtime flag is not
needed anymore: using the feature flag will enforce usage of the new
backend everywhere, making using and testing it much simpler:
cargo run --features experimental_x64 ;; other CLI options/flags
This also gives a hint at what the meta language generation would look
like after switching to the new backend.
Compiling only with the x64 codegen flag gives a nice compile time speedup.
This commit is contained in:
@@ -48,3 +48,4 @@ default = ["disas", "wasm", "cranelift-codegen/all-arch"]
|
|||||||
disas = ["capstone"]
|
disas = ["capstone"]
|
||||||
enable-peepmatic = ["cranelift-codegen/enable-peepmatic", "cranelift-filetests/enable-peepmatic"]
|
enable-peepmatic = ["cranelift-codegen/enable-peepmatic", "cranelift-filetests/enable-peepmatic"]
|
||||||
wasm = ["wat", "cranelift-wasm"]
|
wasm = ["wat", "cranelift-wasm"]
|
||||||
|
experimental_x64 = ["cranelift-codegen/x64"]
|
||||||
|
|||||||
@@ -66,7 +66,6 @@ x64 = [] # New work-in-progress codegen backend for x86_64 based on the new isel
|
|||||||
# Option to enable all architectures.
|
# Option to enable all architectures.
|
||||||
all-arch = [
|
all-arch = [
|
||||||
"x86",
|
"x86",
|
||||||
"x64",
|
|
||||||
"arm32",
|
"arm32",
|
||||||
"arm64",
|
"arm64",
|
||||||
"riscv"
|
"riscv"
|
||||||
|
|||||||
@@ -26,7 +26,15 @@ fn main() {
|
|||||||
let out_dir = env::var("OUT_DIR").expect("The OUT_DIR environment variable must be set");
|
let out_dir = env::var("OUT_DIR").expect("The OUT_DIR environment variable must be set");
|
||||||
let target_triple = env::var("TARGET").expect("The TARGET environment variable must be set");
|
let target_triple = env::var("TARGET").expect("The TARGET environment variable must be set");
|
||||||
|
|
||||||
// Configure isa targets cfg.
|
let new_backend_isas = if env::var("CARGO_FEATURE_X64").is_ok() {
|
||||||
|
// The x64 (new backend for x86_64) is a bit particular: it only requires generating
|
||||||
|
// the shared meta code; the only ISA-specific code is for settings.
|
||||||
|
vec![meta::isa::Isa::X86]
|
||||||
|
} else {
|
||||||
|
Vec::new()
|
||||||
|
};
|
||||||
|
|
||||||
|
// Configure isa targets using the old backend.
|
||||||
let isa_targets = meta::isa::Isa::all()
|
let isa_targets = meta::isa::Isa::all()
|
||||||
.iter()
|
.iter()
|
||||||
.cloned()
|
.cloned()
|
||||||
@@ -36,7 +44,7 @@ fn main() {
|
|||||||
})
|
})
|
||||||
.collect::<Vec<_>>();
|
.collect::<Vec<_>>();
|
||||||
|
|
||||||
let isas = if isa_targets.is_empty() {
|
let old_backend_isas = if new_backend_isas.is_empty() && isa_targets.is_empty() {
|
||||||
// Try to match native target.
|
// Try to match native target.
|
||||||
let target_name = target_triple.split('-').next().unwrap();
|
let target_name = target_triple.split('-').next().unwrap();
|
||||||
let isa = meta::isa_from_arch(&target_name).expect("error when identifying target");
|
let isa = meta::isa_from_arch(&target_name).expect("error when identifying target");
|
||||||
@@ -56,14 +64,23 @@ fn main() {
|
|||||||
crate_dir.join("build.rs").to_str().unwrap()
|
crate_dir.join("build.rs").to_str().unwrap()
|
||||||
);
|
);
|
||||||
|
|
||||||
if let Err(err) = meta::generate(&isas, &out_dir) {
|
if let Err(err) = meta::generate(&old_backend_isas, &new_backend_isas, &out_dir) {
|
||||||
eprintln!("Error: {}", err);
|
eprintln!("Error: {}", err);
|
||||||
process::exit(1);
|
process::exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
if env::var("CRANELIFT_VERBOSE").is_ok() {
|
if env::var("CRANELIFT_VERBOSE").is_ok() {
|
||||||
for isa in &isas {
|
for isa in &old_backend_isas {
|
||||||
println!("cargo:warning=Includes support for {} ISA", isa.to_string());
|
println!(
|
||||||
|
"cargo:warning=Includes old-backend support for {} ISA",
|
||||||
|
isa.to_string()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
for isa in &new_backend_isas {
|
||||||
|
println!(
|
||||||
|
"cargo:warning=Includes new-backend support for {} ISA",
|
||||||
|
isa.to_string()
|
||||||
|
);
|
||||||
}
|
}
|
||||||
println!(
|
println!(
|
||||||
"cargo:warning=Build step took {:?}.",
|
"cargo:warning=Build step took {:?}.",
|
||||||
|
|||||||
@@ -700,6 +700,7 @@ fn gen_isa(
|
|||||||
pub(crate) fn generate(
|
pub(crate) fn generate(
|
||||||
isas: &[TargetIsa],
|
isas: &[TargetIsa],
|
||||||
transform_groups: &TransformGroups,
|
transform_groups: &TransformGroups,
|
||||||
|
extra_legalization_groups: &[&'static str],
|
||||||
filename_prefix: &str,
|
filename_prefix: &str,
|
||||||
out_dir: &str,
|
out_dir: &str,
|
||||||
) -> Result<(), error::Error> {
|
) -> Result<(), error::Error> {
|
||||||
@@ -711,8 +712,14 @@ pub(crate) fn generate(
|
|||||||
fmt.update_file(format!("{}-{}.rs", filename_prefix, isa.name), out_dir)?;
|
fmt.update_file(format!("{}-{}.rs", filename_prefix, isa.name), out_dir)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Add extra legalization groups that were explicitly requested.
|
||||||
|
for group in extra_legalization_groups {
|
||||||
|
shared_group_names.insert(group);
|
||||||
|
}
|
||||||
|
|
||||||
// Generate shared legalize groups.
|
// Generate shared legalize groups.
|
||||||
let mut fmt = Formatter::new();
|
let mut fmt = Formatter::new();
|
||||||
|
// Generate shared legalize groups.
|
||||||
let mut type_sets = UniqueTable::new();
|
let mut type_sets = UniqueTable::new();
|
||||||
let mut sorted_shared_group_names = Vec::from_iter(shared_group_names);
|
let mut sorted_shared_group_names = Vec::from_iter(shared_group_names);
|
||||||
sorted_shared_group_names.sort();
|
sorted_shared_group_names.sort();
|
||||||
|
|||||||
@@ -6,10 +6,10 @@ use std::fmt;
|
|||||||
mod arm32;
|
mod arm32;
|
||||||
mod arm64;
|
mod arm64;
|
||||||
mod riscv;
|
mod riscv;
|
||||||
mod x86;
|
pub(crate) mod x86;
|
||||||
|
|
||||||
/// Represents known ISA target.
|
/// Represents known ISA target.
|
||||||
#[derive(Copy, Clone)]
|
#[derive(PartialEq, Copy, Clone)]
|
||||||
pub enum Isa {
|
pub enum Isa {
|
||||||
Riscv,
|
Riscv,
|
||||||
X86,
|
X86,
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ mod legalize;
|
|||||||
mod opcodes;
|
mod opcodes;
|
||||||
mod recipes;
|
mod recipes;
|
||||||
mod registers;
|
mod registers;
|
||||||
mod settings;
|
pub(crate) mod settings;
|
||||||
|
|
||||||
pub(crate) fn define(shared_defs: &mut SharedDefinitions) -> TargetIsa {
|
pub(crate) fn define(shared_defs: &mut SharedDefinitions) -> TargetIsa {
|
||||||
let settings = settings::define(&shared_defs.settings);
|
let settings = settings::define(&shared_defs.settings);
|
||||||
|
|||||||
@@ -3,12 +3,6 @@ use crate::cdsl::settings::{PredicateNode, SettingGroup, SettingGroupBuilder};
|
|||||||
pub(crate) fn define(shared: &SettingGroup) -> SettingGroup {
|
pub(crate) fn define(shared: &SettingGroup) -> SettingGroup {
|
||||||
let mut settings = SettingGroupBuilder::new("x86");
|
let mut settings = SettingGroupBuilder::new("x86");
|
||||||
|
|
||||||
settings.add_bool(
|
|
||||||
"use_new_backend",
|
|
||||||
"Whether to use the new codegen backend using the new isel",
|
|
||||||
false,
|
|
||||||
);
|
|
||||||
|
|
||||||
// CPUID.01H:ECX
|
// CPUID.01H:ECX
|
||||||
let has_sse3 = settings.add_bool("has_sse3", "SSE3: CPUID.01H:ECX.SSE3[bit 0]", false);
|
let has_sse3 = settings.add_bool("has_sse3", "SSE3: CPUID.01H:ECX.SSE3[bit 0]", false);
|
||||||
let has_ssse3 = settings.add_bool("has_ssse3", "SSSE3: CPUID.01H:ECX.SSSE3[bit 9]", false);
|
let has_ssse3 = settings.add_bool("has_ssse3", "SSSE3: CPUID.01H:ECX.SSSE3[bit 9]", false);
|
||||||
|
|||||||
@@ -25,7 +25,11 @@ pub fn isa_from_arch(arch: &str) -> Result<isa::Isa, String> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Generates all the Rust source files used in Cranelift from the meta-language.
|
/// Generates all the Rust source files used in Cranelift from the meta-language.
|
||||||
pub fn generate(isas: &[isa::Isa], out_dir: &str) -> Result<(), error::Error> {
|
pub fn generate(
|
||||||
|
old_backend_isas: &[isa::Isa],
|
||||||
|
new_backend_isas: &[isa::Isa],
|
||||||
|
out_dir: &str,
|
||||||
|
) -> Result<(), error::Error> {
|
||||||
// Create all the definitions:
|
// Create all the definitions:
|
||||||
// - common definitions.
|
// - common definitions.
|
||||||
let mut shared_defs = shared::define();
|
let mut shared_defs = shared::define();
|
||||||
@@ -39,7 +43,7 @@ pub fn generate(isas: &[isa::Isa], out_dir: &str) -> Result<(), error::Error> {
|
|||||||
gen_types::generate("types.rs", &out_dir)?;
|
gen_types::generate("types.rs", &out_dir)?;
|
||||||
|
|
||||||
// - per ISA definitions.
|
// - per ISA definitions.
|
||||||
let isas = isa::define(isas, &mut shared_defs);
|
let target_isas = isa::define(old_backend_isas, &mut shared_defs);
|
||||||
|
|
||||||
// At this point, all definitions are done.
|
// At this point, all definitions are done.
|
||||||
let all_formats = shared_defs.verify_instruction_formats();
|
let all_formats = shared_defs.verify_instruction_formats();
|
||||||
@@ -53,9 +57,22 @@ pub fn generate(isas: &[isa::Isa], out_dir: &str) -> Result<(), error::Error> {
|
|||||||
&out_dir,
|
&out_dir,
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
gen_legalizer::generate(&isas, &shared_defs.transform_groups, "legalize", &out_dir)?;
|
let extra_legalization_groups: &[&'static str] = if !new_backend_isas.is_empty() {
|
||||||
|
// The new backend only requires the "expand" legalization group.
|
||||||
|
&["expand"]
|
||||||
|
} else {
|
||||||
|
&[]
|
||||||
|
};
|
||||||
|
|
||||||
for isa in isas {
|
gen_legalizer::generate(
|
||||||
|
&target_isas,
|
||||||
|
&shared_defs.transform_groups,
|
||||||
|
extra_legalization_groups,
|
||||||
|
"legalize",
|
||||||
|
&out_dir,
|
||||||
|
)?;
|
||||||
|
|
||||||
|
for isa in target_isas {
|
||||||
gen_registers::generate(&isa, &format!("registers-{}.rs", isa.name), &out_dir)?;
|
gen_registers::generate(&isa, &format!("registers-{}.rs", isa.name), &out_dir)?;
|
||||||
|
|
||||||
gen_settings::generate(
|
gen_settings::generate(
|
||||||
@@ -80,5 +97,28 @@ pub fn generate(isas: &[isa::Isa], out_dir: &str) -> Result<(), error::Error> {
|
|||||||
)?;
|
)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for isa in new_backend_isas {
|
||||||
|
match isa {
|
||||||
|
isa::Isa::X86 => {
|
||||||
|
// If the old backend ISAs contained x86, this file has already been generated.
|
||||||
|
if old_backend_isas.iter().any(|isa| *isa == isa::Isa::X86) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
let settings = crate::isa::x86::settings::define(&shared_defs.settings);
|
||||||
|
gen_settings::generate(
|
||||||
|
&settings,
|
||||||
|
gen_settings::ParentGroup::Shared,
|
||||||
|
"settings-x86.rs",
|
||||||
|
&out_dir,
|
||||||
|
)?;
|
||||||
|
}
|
||||||
|
isa::Isa::Arm64 => {
|
||||||
|
// aarch64 doesn't have platform-specific settings.
|
||||||
|
}
|
||||||
|
isa::Isa::Arm32 | isa::Isa::Riscv => todo!(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -121,8 +121,12 @@ pub fn lookup(triple: Triple) -> Result<Builder, LookupError> {
|
|||||||
match triple.architecture {
|
match triple.architecture {
|
||||||
Architecture::Riscv32 | Architecture::Riscv64 => isa_builder!(riscv, "riscv", triple),
|
Architecture::Riscv32 | Architecture::Riscv64 => isa_builder!(riscv, "riscv", triple),
|
||||||
Architecture::I386 | Architecture::I586 | Architecture::I686 | Architecture::X86_64 => {
|
Architecture::I386 | Architecture::I586 | Architecture::I686 | Architecture::X86_64 => {
|
||||||
|
if cfg!(feature = "x64") {
|
||||||
|
isa_builder!(x64, "x64", triple)
|
||||||
|
} else {
|
||||||
isa_builder!(x86, "x86", triple)
|
isa_builder!(x86, "x86", triple)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
Architecture::Arm { .. } => isa_builder!(arm32, "arm32", triple),
|
Architecture::Arm { .. } => isa_builder!(arm32, "arm32", triple),
|
||||||
Architecture::Aarch64 { .. } => isa_builder!(aarch64, "arm64", triple),
|
Architecture::Aarch64 { .. } => isa_builder!(aarch64, "arm64", triple),
|
||||||
_ => Err(LookupError::Unsupported),
|
_ => Err(LookupError::Unsupported),
|
||||||
|
|||||||
@@ -11,28 +11,33 @@ use crate::isa::Builder as IsaBuilder;
|
|||||||
use crate::machinst::pretty_print::ShowWithRRU;
|
use crate::machinst::pretty_print::ShowWithRRU;
|
||||||
use crate::machinst::{compile, MachBackend, MachCompileResult, TargetIsaAdapter, VCode};
|
use crate::machinst::{compile, MachBackend, MachCompileResult, TargetIsaAdapter, VCode};
|
||||||
use crate::result::CodegenResult;
|
use crate::result::CodegenResult;
|
||||||
use crate::settings::{self, Flags};
|
use crate::settings::{self as shared_settings, Flags};
|
||||||
|
|
||||||
use crate::isa::x64::inst::regs::create_reg_universe_systemv;
|
use crate::isa::x64::{inst::regs::create_reg_universe_systemv, settings as x64_settings};
|
||||||
|
|
||||||
|
use super::TargetIsa;
|
||||||
|
|
||||||
mod abi;
|
mod abi;
|
||||||
mod inst;
|
mod inst;
|
||||||
mod lower;
|
mod lower;
|
||||||
|
mod settings;
|
||||||
|
|
||||||
/// An X64 backend.
|
/// An X64 backend.
|
||||||
pub(crate) struct X64Backend {
|
pub(crate) struct X64Backend {
|
||||||
triple: Triple,
|
triple: Triple,
|
||||||
flags: Flags,
|
flags: Flags,
|
||||||
|
_x64_flags: x64_settings::Flags,
|
||||||
reg_universe: RealRegUniverse,
|
reg_universe: RealRegUniverse,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl X64Backend {
|
impl X64Backend {
|
||||||
/// Create a new X64 backend with the given (shared) flags.
|
/// Create a new X64 backend with the given (shared) flags.
|
||||||
fn new_with_flags(triple: Triple, flags: Flags) -> Self {
|
fn new_with_flags(triple: Triple, flags: Flags, x64_flags: x64_settings::Flags) -> Self {
|
||||||
let reg_universe = create_reg_universe_systemv(&flags);
|
let reg_universe = create_reg_universe_systemv(&flags);
|
||||||
Self {
|
Self {
|
||||||
triple,
|
triple,
|
||||||
flags,
|
flags,
|
||||||
|
_x64_flags: x64_flags,
|
||||||
reg_universe,
|
reg_universe,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -103,10 +108,17 @@ impl MachBackend for X64Backend {
|
|||||||
pub(crate) fn isa_builder(triple: Triple) -> IsaBuilder {
|
pub(crate) fn isa_builder(triple: Triple) -> IsaBuilder {
|
||||||
IsaBuilder {
|
IsaBuilder {
|
||||||
triple,
|
triple,
|
||||||
setup: settings::builder(),
|
setup: x64_settings::builder(),
|
||||||
constructor: |triple: Triple, flags: Flags, _arch_flag_builder: settings::Builder| {
|
constructor: isa_constructor,
|
||||||
let backend = X64Backend::new_with_flags(triple, flags);
|
|
||||||
Box::new(TargetIsaAdapter::new(backend))
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn isa_constructor(
|
||||||
|
triple: Triple,
|
||||||
|
shared_flags: Flags,
|
||||||
|
builder: shared_settings::Builder,
|
||||||
|
) -> Box<dyn TargetIsa> {
|
||||||
|
let isa_flags = x64_settings::Flags::new(&shared_flags, builder);
|
||||||
|
let backend = X64Backend::new_with_flags(triple, shared_flags, isa_flags);
|
||||||
|
Box::new(TargetIsaAdapter::new(backend))
|
||||||
|
}
|
||||||
|
|||||||
9
cranelift/codegen/src/isa/x64/settings.rs
Normal file
9
cranelift/codegen/src/isa/x64/settings.rs
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
//! x86 Settings.
|
||||||
|
|
||||||
|
use crate::settings::{self, detail, Builder};
|
||||||
|
use core::fmt;
|
||||||
|
|
||||||
|
// Include code generated by `cranelift-codegen/meta/src/gen_settings.rs:`. This file contains a
|
||||||
|
// public `Flags` struct with an impl for all of the settings defined in
|
||||||
|
// `cranelift-codegen/meta/src/isa/x86/settings.rs`.
|
||||||
|
include!(concat!(env!("OUT_DIR"), "/settings-x86.rs"));
|
||||||
@@ -57,20 +57,12 @@ fn isa_constructor(
|
|||||||
|
|
||||||
let isa_flags = settings::Flags::new(&shared_flags, builder);
|
let isa_flags = settings::Flags::new(&shared_flags, builder);
|
||||||
|
|
||||||
if isa_flags.use_new_backend() {
|
|
||||||
#[cfg(not(feature = "x64"))]
|
|
||||||
panic!("new backend x86 support not included by cargo features!");
|
|
||||||
|
|
||||||
#[cfg(feature = "x64")]
|
|
||||||
super::x64::isa_builder(triple).finish(shared_flags)
|
|
||||||
} else {
|
|
||||||
Box::new(Isa {
|
Box::new(Isa {
|
||||||
triple,
|
triple,
|
||||||
isa_flags,
|
isa_flags,
|
||||||
shared_flags,
|
shared_flags,
|
||||||
cpumode: level1,
|
cpumode: level1,
|
||||||
})
|
})
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TargetIsa for Isa {
|
impl TargetIsa for Isa {
|
||||||
|
|||||||
@@ -19,10 +19,24 @@ use crate::flowgraph::ControlFlowGraph;
|
|||||||
use crate::ir::types::{I32, I64};
|
use crate::ir::types::{I32, I64};
|
||||||
use crate::ir::{self, InstBuilder, MemFlags};
|
use crate::ir::{self, InstBuilder, MemFlags};
|
||||||
use crate::isa::TargetIsa;
|
use crate::isa::TargetIsa;
|
||||||
|
|
||||||
|
#[cfg(any(
|
||||||
|
feature = "x86",
|
||||||
|
feature = "arm32",
|
||||||
|
feature = "arm64",
|
||||||
|
feature = "riscv"
|
||||||
|
))]
|
||||||
use crate::predicates;
|
use crate::predicates;
|
||||||
|
#[cfg(any(
|
||||||
|
feature = "x86",
|
||||||
|
feature = "arm32",
|
||||||
|
feature = "arm64",
|
||||||
|
feature = "riscv"
|
||||||
|
))]
|
||||||
|
use alloc::vec::Vec;
|
||||||
|
|
||||||
use crate::timing;
|
use crate::timing;
|
||||||
use alloc::collections::BTreeSet;
|
use alloc::collections::BTreeSet;
|
||||||
use alloc::vec::Vec;
|
|
||||||
|
|
||||||
mod boundary;
|
mod boundary;
|
||||||
mod call;
|
mod call;
|
||||||
|
|||||||
@@ -98,12 +98,13 @@ fn apply_reloc(
|
|||||||
write_unaligned(reloc_address as *mut u32, reloc_delta_u32);
|
write_unaligned(reloc_address as *mut u32, reloc_delta_u32);
|
||||||
},
|
},
|
||||||
#[cfg(target_pointer_width = "64")]
|
#[cfg(target_pointer_width = "64")]
|
||||||
(RelocationKind::Relative, RelocationEncoding::X86Branch, 32) => unsafe {
|
(RelocationKind::Relative, RelocationEncoding::Generic, 32) => unsafe {
|
||||||
let reloc_address = body.add(offset as usize) as usize;
|
let reloc_address = body.add(offset as usize) as usize;
|
||||||
let reloc_addend = r.addend() as isize;
|
let reloc_addend = r.addend() as isize;
|
||||||
let reloc_delta_u64 = (target_func_address as u64)
|
let reloc_delta_u64 = (target_func_address as u64)
|
||||||
.wrapping_sub(reloc_address as u64)
|
.wrapping_sub(reloc_address as u64)
|
||||||
.wrapping_add(reloc_addend as u64);
|
.wrapping_add(reloc_addend as u64);
|
||||||
|
// TODO implement far calls mode in x64 new backend.
|
||||||
assert!(
|
assert!(
|
||||||
reloc_delta_u64 as isize <= i32::max_value() as isize,
|
reloc_delta_u64 as isize <= i32::max_value() as isize,
|
||||||
"relocation too large to fit in i32"
|
"relocation too large to fit in i32"
|
||||||
|
|||||||
Reference in New Issue
Block a user