diff --git a/cranelift/Cargo.toml b/cranelift/Cargo.toml index 7c63bea275..d72bcc4d91 100644 --- a/cranelift/Cargo.toml +++ b/cranelift/Cargo.toml @@ -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"] diff --git a/cranelift/codegen/Cargo.toml b/cranelift/codegen/Cargo.toml index cdafe049e2..a78869265a 100644 --- a/cranelift/codegen/Cargo.toml +++ b/cranelift/codegen/Cargo.toml @@ -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" diff --git a/cranelift/codegen/build.rs b/cranelift/codegen/build.rs index b7352f37c3..2caf32609d 100644 --- a/cranelift/codegen/build.rs +++ b/cranelift/codegen/build.rs @@ -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::>(); - 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 {:?}.", diff --git a/cranelift/codegen/meta/src/gen_legalizer.rs b/cranelift/codegen/meta/src/gen_legalizer.rs index 759121894f..7b56b8db48 100644 --- a/cranelift/codegen/meta/src/gen_legalizer.rs +++ b/cranelift/codegen/meta/src/gen_legalizer.rs @@ -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(); diff --git a/cranelift/codegen/meta/src/isa/mod.rs b/cranelift/codegen/meta/src/isa/mod.rs index 39cd913300..ed8db85f0d 100644 --- a/cranelift/codegen/meta/src/isa/mod.rs +++ b/cranelift/codegen/meta/src/isa/mod.rs @@ -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, diff --git a/cranelift/codegen/meta/src/isa/x86/mod.rs b/cranelift/codegen/meta/src/isa/x86/mod.rs index 56f35770a8..a272e83900 100644 --- a/cranelift/codegen/meta/src/isa/x86/mod.rs +++ b/cranelift/codegen/meta/src/isa/x86/mod.rs @@ -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); diff --git a/cranelift/codegen/meta/src/isa/x86/settings.rs b/cranelift/codegen/meta/src/isa/x86/settings.rs index 0059bf0864..dddd69abb3 100644 --- a/cranelift/codegen/meta/src/isa/x86/settings.rs +++ b/cranelift/codegen/meta/src/isa/x86/settings.rs @@ -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); diff --git a/cranelift/codegen/meta/src/lib.rs b/cranelift/codegen/meta/src/lib.rs index 796e2a110d..ead2c4442f 100644 --- a/cranelift/codegen/meta/src/lib.rs +++ b/cranelift/codegen/meta/src/lib.rs @@ -25,7 +25,11 @@ pub fn isa_from_arch(arch: &str) -> Result { } /// 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(()) } diff --git a/cranelift/codegen/src/isa/mod.rs b/cranelift/codegen/src/isa/mod.rs index 3bd84fbc6e..4ac40c06a4 100644 --- a/cranelift/codegen/src/isa/mod.rs +++ b/cranelift/codegen/src/isa/mod.rs @@ -121,7 +121,11 @@ pub fn lookup(triple: Triple) -> Result { match triple.architecture { Architecture::Riscv32 | Architecture::Riscv64 => isa_builder!(riscv, "riscv", triple), Architecture::I386 | Architecture::I586 | Architecture::I686 | Architecture::X86_64 => { - isa_builder!(x86, "x86", triple) + 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), diff --git a/cranelift/codegen/src/isa/x64/mod.rs b/cranelift/codegen/src/isa/x64/mod.rs index 7666875a0e..271542378a 100644 --- a/cranelift/codegen/src/isa/x64/mod.rs +++ b/cranelift/codegen/src/isa/x64/mod.rs @@ -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); - Box::new(TargetIsaAdapter::new(backend)) - }, + setup: x64_settings::builder(), + constructor: isa_constructor, } } + +fn isa_constructor( + triple: Triple, + shared_flags: Flags, + builder: shared_settings::Builder, +) -> Box { + 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)) +} diff --git a/cranelift/codegen/src/isa/x64/settings.rs b/cranelift/codegen/src/isa/x64/settings.rs new file mode 100644 index 0000000000..c5371bb132 --- /dev/null +++ b/cranelift/codegen/src/isa/x64/settings.rs @@ -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")); diff --git a/cranelift/codegen/src/isa/x86/mod.rs b/cranelift/codegen/src/isa/x86/mod.rs index 4da21a879f..cbdeb3069d 100644 --- a/cranelift/codegen/src/isa/x86/mod.rs +++ b/cranelift/codegen/src/isa/x86/mod.rs @@ -57,20 +57,12 @@ 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, - shared_flags, - cpumode: level1, - }) - } + Box::new(Isa { + triple, + isa_flags, + shared_flags, + cpumode: level1, + }) } impl TargetIsa for Isa { diff --git a/cranelift/codegen/src/legalizer/mod.rs b/cranelift/codegen/src/legalizer/mod.rs index 5bd5ac8f5a..3b33e55b1e 100644 --- a/cranelift/codegen/src/legalizer/mod.rs +++ b/cranelift/codegen/src/legalizer/mod.rs @@ -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; diff --git a/crates/jit/src/link.rs b/crates/jit/src/link.rs index 68996f45ab..71284e8755 100644 --- a/crates/jit/src/link.rs +++ b/crates/jit/src/link.rs @@ -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"