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"]
|
||||
enable-peepmatic = ["cranelift-codegen/enable-peepmatic", "cranelift-filetests/enable-peepmatic"]
|
||||
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.
|
||||
all-arch = [
|
||||
"x86",
|
||||
"x64",
|
||||
"arm32",
|
||||
"arm64",
|
||||
"riscv"
|
||||
|
||||
@@ -26,7 +26,15 @@ fn main() {
|
||||
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");
|
||||
|
||||
// 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()
|
||||
.iter()
|
||||
.cloned()
|
||||
@@ -36,7 +44,7 @@ fn main() {
|
||||
})
|
||||
.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.
|
||||
let target_name = target_triple.split('-').next().unwrap();
|
||||
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()
|
||||
);
|
||||
|
||||
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);
|
||||
process::exit(1);
|
||||
}
|
||||
|
||||
if env::var("CRANELIFT_VERBOSE").is_ok() {
|
||||
for isa in &isas {
|
||||
println!("cargo:warning=Includes support for {} ISA", isa.to_string());
|
||||
for isa in &old_backend_isas {
|
||||
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!(
|
||||
"cargo:warning=Build step took {:?}.",
|
||||
|
||||
@@ -700,6 +700,7 @@ fn gen_isa(
|
||||
pub(crate) fn generate(
|
||||
isas: &[TargetIsa],
|
||||
transform_groups: &TransformGroups,
|
||||
extra_legalization_groups: &[&'static str],
|
||||
filename_prefix: &str,
|
||||
out_dir: &str,
|
||||
) -> Result<(), error::Error> {
|
||||
@@ -711,8 +712,14 @@ pub(crate) fn generate(
|
||||
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.
|
||||
let mut fmt = Formatter::new();
|
||||
// Generate shared legalize groups.
|
||||
let mut type_sets = UniqueTable::new();
|
||||
let mut sorted_shared_group_names = Vec::from_iter(shared_group_names);
|
||||
sorted_shared_group_names.sort();
|
||||
|
||||
@@ -6,10 +6,10 @@ use std::fmt;
|
||||
mod arm32;
|
||||
mod arm64;
|
||||
mod riscv;
|
||||
mod x86;
|
||||
pub(crate) mod x86;
|
||||
|
||||
/// Represents known ISA target.
|
||||
#[derive(Copy, Clone)]
|
||||
#[derive(PartialEq, Copy, Clone)]
|
||||
pub enum Isa {
|
||||
Riscv,
|
||||
X86,
|
||||
|
||||
@@ -14,7 +14,7 @@ mod legalize;
|
||||
mod opcodes;
|
||||
mod recipes;
|
||||
mod registers;
|
||||
mod settings;
|
||||
pub(crate) mod settings;
|
||||
|
||||
pub(crate) fn define(shared_defs: &mut SharedDefinitions) -> TargetIsa {
|
||||
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 {
|
||||
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
|
||||
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);
|
||||
|
||||
@@ -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.
|
||||
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:
|
||||
// - common definitions.
|
||||
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)?;
|
||||
|
||||
// - 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.
|
||||
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,
|
||||
)?;
|
||||
|
||||
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_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(())
|
||||
}
|
||||
|
||||
@@ -121,8 +121,12 @@ pub fn lookup(triple: Triple) -> Result<Builder, LookupError> {
|
||||
match triple.architecture {
|
||||
Architecture::Riscv32 | Architecture::Riscv64 => isa_builder!(riscv, "riscv", triple),
|
||||
Architecture::I386 | Architecture::I586 | Architecture::I686 | Architecture::X86_64 => {
|
||||
if cfg!(feature = "x64") {
|
||||
isa_builder!(x64, "x64", triple)
|
||||
} else {
|
||||
isa_builder!(x86, "x86", triple)
|
||||
}
|
||||
}
|
||||
Architecture::Arm { .. } => isa_builder!(arm32, "arm32", triple),
|
||||
Architecture::Aarch64 { .. } => isa_builder!(aarch64, "arm64", triple),
|
||||
_ => Err(LookupError::Unsupported),
|
||||
|
||||
@@ -11,28 +11,33 @@ use crate::isa::Builder as IsaBuilder;
|
||||
use crate::machinst::pretty_print::ShowWithRRU;
|
||||
use crate::machinst::{compile, MachBackend, MachCompileResult, TargetIsaAdapter, VCode};
|
||||
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 inst;
|
||||
mod lower;
|
||||
mod settings;
|
||||
|
||||
/// An X64 backend.
|
||||
pub(crate) struct X64Backend {
|
||||
triple: Triple,
|
||||
flags: Flags,
|
||||
_x64_flags: x64_settings::Flags,
|
||||
reg_universe: RealRegUniverse,
|
||||
}
|
||||
|
||||
impl X64Backend {
|
||||
/// 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);
|
||||
Self {
|
||||
triple,
|
||||
flags,
|
||||
_x64_flags: x64_flags,
|
||||
reg_universe,
|
||||
}
|
||||
}
|
||||
@@ -103,10 +108,17 @@ impl MachBackend for X64Backend {
|
||||
pub(crate) fn isa_builder(triple: Triple) -> IsaBuilder {
|
||||
IsaBuilder {
|
||||
triple,
|
||||
setup: settings::builder(),
|
||||
constructor: |triple: Triple, flags: Flags, _arch_flag_builder: settings::Builder| {
|
||||
let backend = X64Backend::new_with_flags(triple, flags);
|
||||
setup: x64_settings::builder(),
|
||||
constructor: isa_constructor,
|
||||
}
|
||||
}
|
||||
|
||||
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,13 +57,6 @@ fn isa_constructor(
|
||||
|
||||
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 {
|
||||
triple,
|
||||
isa_flags,
|
||||
@@ -71,7 +64,6 @@ fn isa_constructor(
|
||||
cpumode: level1,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl TargetIsa for Isa {
|
||||
fn name(&self) -> &'static str {
|
||||
|
||||
@@ -19,10 +19,24 @@ use crate::flowgraph::ControlFlowGraph;
|
||||
use crate::ir::types::{I32, I64};
|
||||
use crate::ir::{self, InstBuilder, MemFlags};
|
||||
use crate::isa::TargetIsa;
|
||||
|
||||
#[cfg(any(
|
||||
feature = "x86",
|
||||
feature = "arm32",
|
||||
feature = "arm64",
|
||||
feature = "riscv"
|
||||
))]
|
||||
use crate::predicates;
|
||||
#[cfg(any(
|
||||
feature = "x86",
|
||||
feature = "arm32",
|
||||
feature = "arm64",
|
||||
feature = "riscv"
|
||||
))]
|
||||
use alloc::vec::Vec;
|
||||
|
||||
use crate::timing;
|
||||
use alloc::collections::BTreeSet;
|
||||
use alloc::vec::Vec;
|
||||
|
||||
mod boundary;
|
||||
mod call;
|
||||
|
||||
@@ -98,12 +98,13 @@ fn apply_reloc(
|
||||
write_unaligned(reloc_address as *mut u32, reloc_delta_u32);
|
||||
},
|
||||
#[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_addend = r.addend() as isize;
|
||||
let reloc_delta_u64 = (target_func_address as u64)
|
||||
.wrapping_sub(reloc_address as u64)
|
||||
.wrapping_add(reloc_addend as u64);
|
||||
// TODO implement far calls mode in x64 new backend.
|
||||
assert!(
|
||||
reloc_delta_u64 as isize <= i32::max_value() as isize,
|
||||
"relocation too large to fit in i32"
|
||||
|
||||
Reference in New Issue
Block a user