diff --git a/Cargo.lock b/Cargo.lock index ff424b79ac..94d046acc8 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3592,6 +3592,20 @@ dependencies = [ "target-lexicon", "thiserror", "wasmparser", + "wasmtime-cranelift-shared", + "wasmtime-environ", +] + +[[package]] +name = "wasmtime-cranelift-shared" +version = "8.0.0" +dependencies = [ + "anyhow", + "cranelift-codegen", + "cranelift-native", + "gimli", + "object", + "target-lexicon", "wasmtime-environ", ] @@ -3836,8 +3850,11 @@ version = "8.0.0" dependencies = [ "anyhow", "cranelift-codegen", + "gimli", "object", "target-lexicon", + "wasmparser", + "wasmtime-cranelift-shared", "wasmtime-environ", "winch-codegen", ] @@ -3993,6 +4010,7 @@ version = "0.6.0" dependencies = [ "anyhow", "cranelift-codegen", + "gimli", "regalloc2", "smallvec", "target-lexicon", diff --git a/Cargo.toml b/Cargo.toml index 5868c414a0..908bbb0849 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -118,6 +118,7 @@ wasmtime = { path = "crates/wasmtime", version = "8.0.0", default-features = fal wasmtime-cache = { path = "crates/cache", version = "=8.0.0" } wasmtime-cli-flags = { path = "crates/cli-flags", version = "=8.0.0" } wasmtime-cranelift = { path = "crates/cranelift", version = "=8.0.0" } +wasmtime-cranelift-shared = { path = "crates/cranelift-shared", version = "=8.0.0" } wasmtime-environ = { path = "crates/environ", version = "=8.0.0" } wasmtime-fiber = { path = "crates/fiber", version = "=8.0.0" } wasmtime-types = { path = "crates/types", version = "8.0.0" } diff --git a/cranelift/codegen/meta/src/gen_settings.rs b/cranelift/codegen/meta/src/gen_settings.rs index 01a4f731a7..d81781ef62 100644 --- a/cranelift/codegen/meta/src/gen_settings.rs +++ b/cranelift/codegen/meta/src/gen_settings.rs @@ -21,7 +21,7 @@ pub(crate) enum ParentGroup { fn gen_constructor(group: &SettingGroup, parent: ParentGroup, fmt: &mut Formatter) { let args = match parent { ParentGroup::None => "builder: Builder", - ParentGroup::Shared => "shared: &settings::Flags, builder: Builder", + ParentGroup::Shared => "shared: &settings::Flags, builder: &Builder", }; fmtln!(fmt, "impl Flags {"); fmt.indent(|fmt| { diff --git a/cranelift/codegen/src/isa/mod.rs b/cranelift/codegen/src/isa/mod.rs index 539bdb4317..3baf230f7a 100644 --- a/cranelift/codegen/src/isa/mod.rs +++ b/cranelift/codegen/src/isa/mod.rs @@ -146,16 +146,34 @@ impl fmt::Display for LookupError { /// The type of a polymorphic TargetISA object which is 'static. pub type OwnedTargetIsa = Arc; +/// Type alias of `IsaBuilder` used for building Cranelift's ISAs. +pub type Builder = IsaBuilder>; + /// Builder for a `TargetIsa`. /// Modify the ISA-specific settings before creating the `TargetIsa` trait object with `finish`. #[derive(Clone)] -pub struct Builder { +pub struct IsaBuilder { triple: Triple, setup: settings::Builder, - constructor: fn(Triple, settings::Flags, settings::Builder) -> CodegenResult, + constructor: fn(Triple, settings::Flags, &settings::Builder) -> T, } -impl Builder { +impl IsaBuilder { + /// Creates a new ISA-builder from its components, namely the `triple` for + /// the ISA, the ISA-specific settings builder, and a final constructor + /// function to generate the ISA from its components. + pub fn new( + triple: Triple, + setup: settings::Builder, + constructor: fn(Triple, settings::Flags, &settings::Builder) -> T, + ) -> Self { + IsaBuilder { + triple, + setup, + constructor, + } + } + /// Gets the triple for the builder. pub fn triple(&self) -> &Triple { &self.triple @@ -172,12 +190,12 @@ impl Builder { /// flags are inconsistent or incompatible: for example, some /// platform-independent features, like general SIMD support, may /// need certain ISA extensions to be enabled. - pub fn finish(self, shared_flags: settings::Flags) -> CodegenResult { - (self.constructor)(self.triple, shared_flags, self.setup) + pub fn finish(&self, shared_flags: settings::Flags) -> T { + (self.constructor)(self.triple.clone(), shared_flags, &self.setup) } } -impl settings::Configurable for Builder { +impl settings::Configurable for IsaBuilder { fn set(&mut self, name: &str, value: &str) -> SetResult<()> { self.setup.set(name, value) } @@ -339,24 +357,6 @@ impl<'a> dyn TargetIsa + 'a { } } - /// Returns the code (text) section alignment for this ISA. - pub fn code_section_alignment(&self) -> u64 { - use target_lexicon::*; - match (self.triple().operating_system, self.triple().architecture) { - ( - OperatingSystem::MacOSX { .. } - | OperatingSystem::Darwin - | OperatingSystem::Ios - | OperatingSystem::Tvos, - Architecture::Aarch64(..), - ) => 0x4000, - // 64 KB is the maximal page size (i.e. memory translation granule size) - // supported by the architecture and is used on some platforms. - (_, Architecture::Aarch64(..)) => 0x10000, - _ => 0x1000, - } - } - /// Returns the minimum symbol alignment for this ISA. pub fn symbol_alignment(&self) -> u64 { match self.triple().architecture { diff --git a/cranelift/codegen/src/isa/riscv64/inst/emit_tests.rs b/cranelift/codegen/src/isa/riscv64/inst/emit_tests.rs index ebe67af792..f919990d82 100644 --- a/cranelift/codegen/src/isa/riscv64/inst/emit_tests.rs +++ b/cranelift/codegen/src/isa/riscv64/inst/emit_tests.rs @@ -2095,7 +2095,7 @@ fn make_test_flags() -> (settings::Flags, super::super::riscv_settings::Flags) { let b = settings::builder(); let flags = settings::Flags::new(b.clone()); let b2 = super::super::riscv_settings::builder(); - let isa_flags = super::super::riscv_settings::Flags::new(&flags, b2); + let isa_flags = super::super::riscv_settings::Flags::new(&flags, &b2); (flags, isa_flags) } diff --git a/cranelift/codegen/src/isa/s390x/inst/emit_tests.rs b/cranelift/codegen/src/isa/s390x/inst/emit_tests.rs index 943762540e..003365cc08 100644 --- a/cranelift/codegen/src/isa/s390x/inst/emit_tests.rs +++ b/cranelift/codegen/src/isa/s390x/inst/emit_tests.rs @@ -13362,7 +13362,7 @@ fn test_s390x_binemit() { use crate::settings::Configurable; let mut isa_flag_builder = s390x_settings::builder(); isa_flag_builder.enable("arch13").unwrap(); - let isa_flags = s390x_settings::Flags::new(&flags, isa_flag_builder); + let isa_flags = s390x_settings::Flags::new(&flags, &isa_flag_builder); let emit_info = EmitInfo::new(isa_flags); for (insn, expected_encoding, expected_printing) in insns { diff --git a/cranelift/codegen/src/isa/x64/inst/emit_tests.rs b/cranelift/codegen/src/isa/x64/inst/emit_tests.rs index 1ccaf6c7de..717e0fc391 100644 --- a/cranelift/codegen/src/isa/x64/inst/emit_tests.rs +++ b/cranelift/codegen/src/isa/x64/inst/emit_tests.rs @@ -5155,7 +5155,7 @@ fn test_x64_emit() { isa_flag_builder.enable("has_avx512f").unwrap(); isa_flag_builder.enable("has_avx512vbmi").unwrap(); isa_flag_builder.enable("has_avx512vl").unwrap(); - let isa_flags = x64::settings::Flags::new(&flags, isa_flag_builder); + let isa_flags = x64::settings::Flags::new(&flags, &isa_flag_builder); let emit_info = EmitInfo::new(flags, isa_flags); for (insn, expected_encoding, expected_printing) in insns { diff --git a/cranelift/codegen/src/isa/x64/mod.rs b/cranelift/codegen/src/isa/x64/mod.rs index 68f218fae4..79f79c7e2d 100644 --- a/cranelift/codegen/src/isa/x64/mod.rs +++ b/cranelift/codegen/src/isa/x64/mod.rs @@ -212,7 +212,7 @@ pub(crate) fn isa_builder(triple: Triple) -> IsaBuilder { fn isa_constructor( triple: Triple, shared_flags: Flags, - builder: shared_settings::Builder, + builder: &shared_settings::Builder, ) -> CodegenResult { let isa_flags = x64_settings::Flags::new(&shared_flags, builder); diff --git a/cranelift/codegen/src/lib.rs b/cranelift/codegen/src/lib.rs index e8687114c3..a5c82c7619 100644 --- a/cranelift/codegen/src/lib.rs +++ b/cranelift/codegen/src/lib.rs @@ -88,7 +88,9 @@ pub mod verifier; pub mod write; pub use crate::entity::packed_option; -pub use crate::machinst::buffer::{MachCallSite, MachReloc, MachSrcLoc, MachStackMap, MachTrap}; +pub use crate::machinst::buffer::{ + MachCallSite, MachReloc, MachSrcLoc, MachStackMap, MachTextSectionBuilder, MachTrap, +}; pub use crate::machinst::{ CompiledCode, Final, MachBuffer, MachBufferFinalized, MachInst, MachInstEmit, Reg, TextSectionBuilder, Writable, diff --git a/cranelift/codegen/src/machinst/buffer.rs b/cranelift/codegen/src/machinst/buffer.rs index 316e916db3..6dc2518456 100644 --- a/cranelift/codegen/src/machinst/buffer.rs +++ b/cranelift/codegen/src/machinst/buffer.rs @@ -1610,6 +1610,8 @@ pub struct MachTextSectionBuilder { } impl MachTextSectionBuilder { + /// Creates a new text section builder which will have `num_funcs` functions + /// pushed into it. pub fn new(num_funcs: usize) -> MachTextSectionBuilder { let mut buf = MachBuffer::new(); buf.reserve_labels_for_blocks(num_funcs); diff --git a/cranelift/codegen/src/settings.rs b/cranelift/codegen/src/settings.rs index 6836646e2a..5485779de8 100644 --- a/cranelift/codegen/src/settings.rs +++ b/cranelift/codegen/src/settings.rs @@ -161,9 +161,9 @@ impl Builder { } /// Extract contents of builder once everything is configured. - pub fn state_for(self, name: &str) -> Box<[u8]> { + pub fn state_for(&self, name: &str) -> &[u8] { assert_eq!(name, self.template.name); - self.bytes + &self.bytes } /// Iterates the available settings in the builder. diff --git a/cranelift/native/src/lib.rs b/cranelift/native/src/lib.rs index 3becbeb1e6..993fb35e09 100644 --- a/cranelift/native/src/lib.rs +++ b/cranelift/native/src/lib.rs @@ -24,6 +24,7 @@ )] use cranelift_codegen::isa; +use cranelift_codegen::settings::Configurable; use target_lexicon::Triple; /// Return an `isa` builder configured for the current host @@ -45,19 +46,26 @@ pub fn builder_with_options(infer_native_flags: bool) -> Result "support for architecture disabled at compile time", isa::LookupError::Unsupported => "unsupported architecture", })?; + if infer_native_flags { + self::infer_native_flags(&mut isa_builder)?; + } + Ok(isa_builder) +} +/// Return an `isa` builder configured for the current host +/// machine, or `Err(())` if the host machine is not supported +/// in the current configuration. +/// +/// Selects the given backend variant specifically; this is +/// useful when more than oen backend exists for a given target +/// (e.g., on x86-64). +pub fn infer_native_flags(isa_builder: &mut dyn Configurable) -> Result<(), &'static str> { #[cfg(target_arch = "x86_64")] { - use cranelift_codegen::settings::Configurable; - if !std::is_x86_feature_detected!("sse2") { return Err("x86 support requires SSE2"); } - if !infer_native_flags { - return Ok(isa_builder); - } - // These are temporarily enabled by default (see #3810 for // more) so that a default-constructed `Flags` can work with // default Wasmtime features. Otherwise, the user must @@ -123,12 +131,6 @@ pub fn builder_with_options(infer_native_flags: bool) -> Result Result Result Result { + /// The shared flags that all targets share. + shared_flags: settings::Builder, + /// The internal ISA builder for the current target. + inner: Builder, + /// A callback to lookup a new ISA builder for a target. + pub lookup: fn(Triple) -> Result>, +} + +impl IsaBuilder { + /// Create a new ISA builder with the given lookup function. + pub fn new(lookup: fn(Triple) -> Result>) -> Self { + let mut flags = settings::builder(); + + // There are two possible traps for division, and this way + // we get the proper one if code traps. + flags + .enable("avoid_div_traps") + .expect("should be valid flag"); + + // We don't use probestack as a stack limit mechanism + flags + .set("enable_probestack", "false") + .expect("should be valid flag"); + + let mut isa_flags = lookup(Triple::host()).expect("host machine is not a supported target"); + cranelift_native::infer_native_flags(&mut isa_flags).unwrap(); + + Self { + shared_flags: flags, + inner: isa_flags, + lookup, + } + } + + pub fn triple(&self) -> &target_lexicon::Triple { + self.inner.triple() + } + + pub fn target(&mut self, target: target_lexicon::Triple) -> Result<()> { + self.inner = (self.lookup)(target)?; + Ok(()) + } + + pub fn settings(&self) -> Vec { + self.inner + .iter() + .map(|s| Setting { + description: s.description, + name: s.name, + values: s.values, + kind: match s.kind { + settings::SettingKind::Preset => SettingKind::Preset, + settings::SettingKind::Enum => SettingKind::Enum, + settings::SettingKind::Num => SettingKind::Num, + settings::SettingKind::Bool => SettingKind::Bool, + }, + }) + .collect() + } + + pub fn set(&mut self, name: &str, value: &str) -> Result<()> { + if let Err(err) = self.shared_flags.set(name, value) { + match err { + SetError::BadName(_) => { + self.inner.set(name, value)?; + } + _ => return Err(err.into()), + } + } + Ok(()) + } + + pub fn enable(&mut self, name: &str) -> Result<()> { + if let Err(err) = self.shared_flags.enable(name) { + match err { + SetError::BadName(_) => { + // Try the target-specific flags. + self.inner.enable(name)?; + } + _ => return Err(err.into()), + } + } + Ok(()) + } + + pub fn build(&self) -> T { + self.inner + .finish(settings::Flags::new(self.shared_flags.clone())) + } + + pub fn shared_flags(&self) -> Flags { + settings::Flags::new(self.shared_flags.clone()) + } +} diff --git a/crates/cranelift-shared/src/lib.rs b/crates/cranelift-shared/src/lib.rs new file mode 100644 index 0000000000..6b0d4586d7 --- /dev/null +++ b/crates/cranelift-shared/src/lib.rs @@ -0,0 +1,49 @@ +use cranelift_codegen::binemit; +use cranelift_codegen::ir; +use cranelift_codegen::settings; +use std::collections::BTreeMap; +use wasmtime_environ::{FlagValue, FuncIndex}; + +pub mod isa_builder; +pub mod obj; + +/// A record of a relocation to perform. +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct Relocation { + /// The relocation code. + pub reloc: binemit::Reloc, + /// Relocation target. + pub reloc_target: RelocationTarget, + /// The offset where to apply the relocation. + pub offset: binemit::CodeOffset, + /// The addend to add to the relocation value. + pub addend: binemit::Addend, +} + +/// Destination function. Can be either user function or some special one, like `memory.grow`. +#[derive(Debug, Copy, Clone, PartialEq, Eq)] +pub enum RelocationTarget { + /// The user function index. + UserFunc(FuncIndex), + /// A compiler-generated libcall. + LibCall(ir::LibCall), +} + +/// Converts cranelift_codegen settings to the wasmtime_environ equivalent. +pub fn clif_flags_to_wasmtime( + flags: impl IntoIterator, +) -> BTreeMap { + flags + .into_iter() + .map(|val| (val.name.to_string(), to_flag_value(&val))) + .collect() +} + +fn to_flag_value(v: &settings::Value) -> FlagValue { + match v.kind() { + settings::SettingKind::Enum => FlagValue::Enum(v.as_enum().unwrap().into()), + settings::SettingKind::Num => FlagValue::Num(v.as_num().unwrap()), + settings::SettingKind::Bool => FlagValue::Bool(v.as_bool().unwrap()), + settings::SettingKind::Preset => unreachable!(), + } +} diff --git a/crates/cranelift/src/obj.rs b/crates/cranelift-shared/src/obj.rs similarity index 94% rename from crates/cranelift/src/obj.rs rename to crates/cranelift-shared/src/obj.rs index d5983598aa..44901f8456 100644 --- a/crates/cranelift/src/obj.rs +++ b/crates/cranelift-shared/src/obj.rs @@ -13,14 +13,11 @@ //! function body, the imported wasm function do not. The trampolines symbol //! names have format "_trampoline_N", where N is `SignatureIndex`. -use crate::{CompiledFunction, RelocationTarget}; +use crate::{Relocation, RelocationTarget}; use anyhow::Result; use cranelift_codegen::binemit::Reloc; use cranelift_codegen::ir::LibCall; -use cranelift_codegen::isa::{ - unwind::{systemv, UnwindInfo}, - TargetIsa, -}; +use cranelift_codegen::isa::unwind::{systemv, UnwindInfo}; use cranelift_codegen::TextSectionBuilder; use gimli::write::{Address, EhFrame, EndianVec, FrameTable, Writer}; use gimli::RunTimeEndian; @@ -29,7 +26,7 @@ use object::{Architecture, SectionKind, SymbolFlags, SymbolKind, SymbolScope}; use std::collections::HashMap; use std::convert::TryFrom; use std::ops::Range; -use wasmtime_environ::FuncIndex; +use wasmtime_environ::{Compiler, FuncIndex}; const TEXT_SECTION_NAME: &[u8] = b".text"; @@ -42,7 +39,7 @@ const TEXT_SECTION_NAME: &[u8] = b".text"; pub struct ModuleTextBuilder<'a> { /// The target that we're compiling for, used to query target-specific /// information as necessary. - isa: &'a dyn TargetIsa, + compiler: &'a dyn Compiler, /// The object file that we're generating code into. obj: &'a mut Object<'static>, @@ -71,7 +68,11 @@ impl<'a> ModuleTextBuilder<'a> { /// any unwinding or such information as necessary. The `num_funcs` /// parameter indicates the number of times the `append_func` function will /// be called. The `finish` function will panic if this contract is not met. - pub fn new(obj: &'a mut Object<'static>, isa: &'a dyn TargetIsa, num_funcs: usize) -> Self { + pub fn new( + obj: &'a mut Object<'static>, + compiler: &'a dyn Compiler, + text: Box, + ) -> Self { // Entire code (functions and trampolines) will be placed // in the ".text" section. let text_section = obj.add_section( @@ -81,11 +82,11 @@ impl<'a> ModuleTextBuilder<'a> { ); Self { - isa, + compiler, obj, text_section, unwind_info: Default::default(), - text: isa.text_section_builder(num_funcs), + text, libcall_symbols: HashMap::default(), } } @@ -103,14 +104,17 @@ impl<'a> ModuleTextBuilder<'a> { pub fn append_func( &mut self, name: &str, - func: &'a CompiledFunction, + body: &[u8], + alignment: u32, + unwind_info: Option<&'a UnwindInfo>, + relocations: &[Relocation], resolve_reloc_target: impl Fn(FuncIndex) -> usize, ) -> (SymbolId, Range) { - let body_len = func.body.len() as u64; + let body_len = body.len() as u64; let off = self.text.append( true, - &func.body, - self.isa.function_alignment().max(func.alignment), + &body, + self.compiler.function_alignment().max(alignment), ); let symbol_id = self.obj.add_symbol(Symbol { @@ -124,11 +128,11 @@ impl<'a> ModuleTextBuilder<'a> { flags: SymbolFlags::None, }); - if let Some(info) = &func.unwind_info { + if let Some(info) = unwind_info { self.unwind_info.push(off, body_len, info); } - for r in func.relocations.iter() { + for r in relocations { match r.reloc_target { // Relocations against user-defined functions means that this is // a relocation against a module-local function, typically a @@ -236,11 +240,11 @@ impl<'a> ModuleTextBuilder<'a> { let text = self.text.finish(); self.obj .section_mut(self.text_section) - .set_data(text, self.isa.code_section_alignment()); + .set_data(text, self.compiler.page_size_align()); // Append the unwind information for all our functions, if necessary. self.unwind_info - .append_section(self.isa, self.obj, self.text_section); + .append_section(self.compiler, self.obj, self.text_section); } } @@ -333,12 +337,17 @@ impl<'a> UnwindInfoBuilder<'a> { /// section immediately. /// /// The `text_section`'s section identifier is passed into this function. - fn append_section(&self, isa: &dyn TargetIsa, obj: &mut Object<'_>, text_section: SectionId) { + fn append_section( + &self, + compiler: &dyn Compiler, + obj: &mut Object<'_>, + text_section: SectionId, + ) { // This write will align the text section to a page boundary and then // return the offset at that point. This gives us the full size of the // text section at that point, after alignment. let text_section_size = - obj.append_section_data(text_section, &[], isa.code_section_alignment()); + obj.append_section_data(text_section, &[], compiler.page_size_align()); if self.windows_xdata.len() > 0 { assert!(self.systemv_unwind_info.len() == 0); @@ -356,7 +365,7 @@ impl<'a> UnwindInfoBuilder<'a> { let segment = obj.segment_name(StandardSegment::Data).to_vec(); let section_id = obj.add_section(segment, b".eh_frame".to_vec(), SectionKind::ReadOnlyData); - self.write_systemv_unwind_info(isa, obj, section_id, text_section_size) + self.write_systemv_unwind_info(compiler, obj, section_id, text_section_size) } } @@ -451,12 +460,12 @@ impl<'a> UnwindInfoBuilder<'a> { /// bits. fn write_systemv_unwind_info( &self, - isa: &dyn TargetIsa, + compiler: &dyn Compiler, obj: &mut Object<'_>, section_id: SectionId, text_section_size: u64, ) { - let mut cie = isa + let mut cie = compiler .create_systemv_cie() .expect("must be able to create a CIE for system-v unwind info"); let mut table = FrameTable::default(); @@ -473,7 +482,7 @@ impl<'a> UnwindInfoBuilder<'a> { let fde = unwind_info.to_fde(Address::Constant(actual_offset as u64)); table.add_fde(cie_id, fde); } - let endian = match isa.triple().endianness().unwrap() { + let endian = match compiler.triple().endianness().unwrap() { target_lexicon::Endianness::Little => RunTimeEndian::Little, target_lexicon::Endianness::Big => RunTimeEndian::Big, }; diff --git a/crates/cranelift/Cargo.toml b/crates/cranelift/Cargo.toml index 10455b4b5a..7c31add30a 100644 --- a/crates/cranelift/Cargo.toml +++ b/crates/cranelift/Cargo.toml @@ -19,6 +19,7 @@ cranelift-codegen = { workspace = true } cranelift-frontend = { workspace = true } cranelift-entity = { workspace = true } cranelift-native = { workspace = true } +wasmtime-cranelift-shared = { workspace = true } wasmparser = { workspace = true } target-lexicon = { workspace = true } gimli = { workspace = true } diff --git a/crates/cranelift/src/builder.rs b/crates/cranelift/src/builder.rs index 4fb2b6369a..1e32eed6fe 100644 --- a/crates/cranelift/src/builder.rs +++ b/crates/cranelift/src/builder.rs @@ -4,15 +4,17 @@ //! well as providing a function to return the default configuration to build. use anyhow::Result; -use cranelift_codegen::isa; -use cranelift_codegen::settings::{self, Configurable, SetError}; +use cranelift_codegen::{ + isa::{self, OwnedTargetIsa}, + CodegenResult, +}; use std::fmt; use std::sync::Arc; -use wasmtime_environ::{CacheStore, CompilerBuilder, Setting, SettingKind}; +use wasmtime_cranelift_shared::isa_builder::IsaBuilder; +use wasmtime_environ::{CacheStore, CompilerBuilder, Setting}; struct Builder { - flags: settings::Builder, - isa_flags: isa::Builder, + inner: IsaBuilder>, linkopts: LinkOptions, cache_store: Option>, } @@ -31,22 +33,8 @@ pub struct LinkOptions { } pub fn builder() -> Box { - let mut flags = settings::builder(); - - // There are two possible traps for division, and this way - // we get the proper one if code traps. - flags - .enable("avoid_div_traps") - .expect("should be valid flag"); - - // We don't use probestack as a stack limit mechanism - flags - .set("enable_probestack", "false") - .expect("should be valid flag"); - Box::new(Builder { - flags, - isa_flags: cranelift_native::builder().expect("host machine is not a supported target"), + inner: IsaBuilder::new(|triple| isa::lookup(triple).map_err(|e| e.into())), linkopts: LinkOptions::default(), cache_store: None, }) @@ -54,11 +42,11 @@ pub fn builder() -> Box { impl CompilerBuilder for Builder { fn triple(&self) -> &target_lexicon::Triple { - self.isa_flags.triple() + self.inner.triple() } fn target(&mut self, target: target_lexicon::Triple) -> Result<()> { - self.isa_flags = isa::lookup(target)?; + self.inner.target(target)?; Ok(()) } @@ -73,37 +61,15 @@ impl CompilerBuilder for Builder { return Ok(()); } - // ... then forward this to Cranelift - if let Err(err) = self.flags.set(name, value) { - match err { - SetError::BadName(_) => { - // Try the target-specific flags. - self.isa_flags.set(name, value)?; - } - _ => return Err(err.into()), - } - } - Ok(()) + self.inner.set(name, value) } fn enable(&mut self, name: &str) -> Result<()> { - if let Err(err) = self.flags.enable(name) { - match err { - SetError::BadName(_) => { - // Try the target-specific flags. - self.isa_flags.enable(name)?; - } - _ => return Err(err.into()), - } - } - Ok(()) + self.inner.enable(name) } fn build(&self) -> Result> { - let isa = self - .isa_flags - .clone() - .finish(settings::Flags::new(self.flags.clone()))?; + let isa = self.inner.build()?; Ok(Box::new(crate::compiler::Compiler::new( isa, self.cache_store.clone(), @@ -112,37 +78,22 @@ impl CompilerBuilder for Builder { } fn settings(&self) -> Vec { - self.isa_flags - .iter() - .map(|s| Setting { - description: s.description, - name: s.name, - values: s.values, - kind: match s.kind { - settings::SettingKind::Preset => SettingKind::Preset, - settings::SettingKind::Enum => SettingKind::Enum, - settings::SettingKind::Num => SettingKind::Num, - settings::SettingKind::Bool => SettingKind::Bool, - }, - }) - .collect() + self.inner.settings() } fn enable_incremental_compilation( &mut self, cache_store: Arc, - ) { + ) -> Result<()> { self.cache_store = Some(cache_store); + Ok(()) } } impl fmt::Debug for Builder { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { f.debug_struct("Builder") - .field( - "flags", - &settings::Flags::new(self.flags.clone()).to_string(), - ) + .field("shared_flags", &self.inner.shared_flags().to_string()) .finish() } } diff --git a/crates/cranelift/src/compiler.rs b/crates/cranelift/src/compiler.rs index 512a837d69..5733a998ed 100644 --- a/crates/cranelift/src/compiler.rs +++ b/crates/cranelift/src/compiler.rs @@ -1,10 +1,8 @@ -use crate::builder::LinkOptions; use crate::debug::{DwarfSectionRelocTarget, ModuleMemoryOffset}; use crate::func_environ::FuncEnvironment; -use crate::obj::ModuleTextBuilder; use crate::{ - blank_sig, func_signature, indirect_signature, value_type, wasmtime_call_conv, - CompiledFunction, FunctionAddressMap, Relocation, RelocationTarget, + blank_sig, builder::LinkOptions, func_signature, indirect_signature, value_type, + wasmtime_call_conv, CompiledFunction, FunctionAddressMap, }; use anyhow::{Context as _, Result}; use cranelift_codegen::ir::{ @@ -13,8 +11,8 @@ use cranelift_codegen::ir::{ use cranelift_codegen::isa::{OwnedTargetIsa, TargetIsa}; use cranelift_codegen::print_errors::pretty_error; use cranelift_codegen::Context; -use cranelift_codegen::{settings, MachReloc, MachTrap}; use cranelift_codegen::{CompiledCode, MachSrcLoc, MachStackMap}; +use cranelift_codegen::{MachReloc, MachTrap}; use cranelift_entity::{EntityRef, PrimaryMap}; use cranelift_frontend::FunctionBuilder; use cranelift_wasm::{ @@ -30,6 +28,8 @@ use std::convert::TryFrom; use std::mem; use std::sync::{Arc, Mutex}; use wasmparser::{FuncValidatorAllocations, FunctionBody}; +use wasmtime_cranelift_shared::obj::ModuleTextBuilder; +use wasmtime_cranelift_shared::{Relocation, RelocationTarget}; use wasmtime_environ::{ AddressMapSection, CacheStore, CompileError, FilePos, FlagValue, FunctionBodyData, FunctionLoc, InstructionAddressMap, ModuleTranslation, ModuleTypes, PtrSize, StackMapInformation, Trap, @@ -360,7 +360,8 @@ impl wasmtime_environ::Compiler for Compiler { tunables: &Tunables, resolve_reloc: &dyn Fn(usize, FuncIndex) -> usize, ) -> Result> { - let mut builder = ModuleTextBuilder::new(obj, &*self.isa, funcs.len()); + let mut builder = + ModuleTextBuilder::new(obj, self, self.isa.text_section_builder(funcs.len())); if self.linkopts.force_jump_veneers { builder.force_veneers(); } @@ -369,8 +370,15 @@ impl wasmtime_environ::Compiler for Compiler { let mut ret = Vec::with_capacity(funcs.len()); for (i, (sym, func)) in funcs.iter().enumerate() { - let func = func.downcast_ref().unwrap(); - let (sym, range) = builder.append_func(&sym, func, |idx| resolve_reloc(i, idx)); + let func = func.downcast_ref::().unwrap(); + let (sym, range) = builder.append_func( + &sym, + &func.body, + func.alignment, + func.unwind_info.as_ref(), + &func.relocations, + |idx| resolve_reloc(i, idx), + ); if tunables.generate_address_map { addrs.push(range.clone(), &func.address_map.instructions); } @@ -401,9 +409,23 @@ impl wasmtime_environ::Compiler for Compiler { ) -> Result<(FunctionLoc, FunctionLoc)> { let host_to_wasm = self.host_to_wasm_trampoline(ty)?; let wasm_to_host = self.wasm_to_host_trampoline(ty, host_fn)?; - let mut builder = ModuleTextBuilder::new(obj, &*self.isa, 2); - let (_, a) = builder.append_func("host_to_wasm", &host_to_wasm, |_| unreachable!()); - let (_, b) = builder.append_func("wasm_to_host", &wasm_to_host, |_| unreachable!()); + let mut builder = ModuleTextBuilder::new(obj, self, self.isa.text_section_builder(2)); + let (_, a) = builder.append_func( + "host_to_wasm", + &host_to_wasm.body, + host_to_wasm.alignment, + host_to_wasm.unwind_info.as_ref(), + &host_to_wasm.relocations, + |_| unreachable!(), + ); + let (_, b) = builder.append_func( + "wasm_to_host", + &wasm_to_host.body, + wasm_to_host.alignment, + wasm_to_host.unwind_info.as_ref(), + &wasm_to_host.relocations, + |_| unreachable!(), + ); let a = FunctionLoc { start: u32::try_from(a.start).unwrap(), length: u32::try_from(a.end - a.start).unwrap(), @@ -420,24 +442,12 @@ impl wasmtime_environ::Compiler for Compiler { self.isa.triple() } - fn page_size_align(&self) -> u64 { - self.isa.code_section_alignment() - } - fn flags(&self) -> BTreeMap { - self.isa - .flags() - .iter() - .map(|val| (val.name.to_string(), to_flag_value(&val))) - .collect() + wasmtime_cranelift_shared::clif_flags_to_wasmtime(self.isa.flags().iter()) } fn isa_flags(&self) -> BTreeMap { - self.isa - .isa_flags() - .iter() - .map(|val| (val.name.to_string(), to_flag_value(val))) - .collect() + wasmtime_cranelift_shared::clif_flags_to_wasmtime(self.isa.isa_flags()) } fn is_branch_protection_enabled(&self) -> bool { @@ -534,6 +544,14 @@ impl wasmtime_environ::Compiler for Compiler { Ok(()) } + + fn function_alignment(&self) -> u32 { + self.isa.function_alignment() + } + + fn create_systemv_cie(&self) -> Option { + self.isa.create_systemv_cie() + } } #[cfg(feature = "incremental-cache")] @@ -599,15 +617,6 @@ fn compile_uncached<'a>( Ok((compiled_code, code_buf)) } -fn to_flag_value(v: &settings::Value) -> FlagValue { - match v.kind() { - settings::SettingKind::Enum => FlagValue::Enum(v.as_enum().unwrap().into()), - settings::SettingKind::Num => FlagValue::Num(v.as_num().unwrap()), - settings::SettingKind::Bool => FlagValue::Bool(v.as_bool().unwrap()), - settings::SettingKind::Preset => unreachable!(), - } -} - impl Compiler { fn host_to_wasm_trampoline(&self, ty: &WasmFuncType) -> Result { let isa = &*self.isa; diff --git a/crates/cranelift/src/lib.rs b/crates/cranelift/src/lib.rs index ddefe3cfdd..d9c9d8c956 100644 --- a/crates/cranelift/src/lib.rs +++ b/crates/cranelift/src/lib.rs @@ -3,12 +3,12 @@ //! This crate provides an implementation of the `wasmtime_environ::Compiler` //! and `wasmtime_environ::CompilerBuilder` traits. -use cranelift_codegen::binemit; use cranelift_codegen::ir; use cranelift_codegen::isa::{unwind::UnwindInfo, CallConv, TargetIsa}; use cranelift_entity::PrimaryMap; use cranelift_wasm::{DefinedFuncIndex, FuncIndex, WasmFuncType, WasmType}; use target_lexicon::{Architecture, CallingConvention}; +use wasmtime_cranelift_shared::Relocation; use wasmtime_environ::{ FilePos, InstructionAddressMap, ModuleTranslation, ModuleTypes, TrapInformation, }; @@ -19,7 +19,6 @@ mod builder; mod compiler; mod debug; mod func_environ; -mod obj; type CompiledFunctions<'a> = PrimaryMap; @@ -72,28 +71,6 @@ struct FunctionAddressMap { body_len: u32, } -/// A record of a relocation to perform. -#[derive(Debug, Clone, PartialEq, Eq)] -struct Relocation { - /// The relocation code. - reloc: binemit::Reloc, - /// Relocation target. - reloc_target: RelocationTarget, - /// The offset where to apply the relocation. - offset: binemit::CodeOffset, - /// The addend to add to the relocation value. - addend: binemit::Addend, -} - -/// Destination function. Can be either user function or some special one, like `memory.grow`. -#[derive(Debug, Copy, Clone, PartialEq, Eq)] -enum RelocationTarget { - /// The user function index. - UserFunc(FuncIndex), - /// A compiler-generated libcall. - LibCall(ir::LibCall), -} - /// Creates a new cranelift `Signature` with no wasm params/results for the /// given calling convention. /// diff --git a/crates/environ/Cargo.toml b/crates/environ/Cargo.toml index 0a15d82797..2f29881d10 100644 --- a/crates/environ/Cargo.toml +++ b/crates/environ/Cargo.toml @@ -19,7 +19,7 @@ indexmap = { version = "1.0.2", features = ["serde-1"] } thiserror = { workspace = true } serde = { version = "1.0.94", features = ["derive"] } log = { workspace = true } -gimli = { workspace = true } +gimli = { workspace = true, features = ["write"] } object = { workspace = true, features = ['write_core'] } target-lexicon = { workspace = true } wasm-encoder = { workspace = true, optional = true } diff --git a/crates/environ/src/compilation.rs b/crates/environ/src/compilation.rs index 73b752bce6..0b27e92d33 100644 --- a/crates/environ/src/compilation.rs +++ b/crates/environ/src/compilation.rs @@ -112,7 +112,9 @@ pub trait CompilerBuilder: Send + Sync + fmt::Debug { /// Enables Cranelift's incremental compilation cache, using the given `CacheStore` /// implementation. - fn enable_incremental_compilation(&mut self, cache_store: Arc); + /// + /// This will return an error if the compiler does not support incremental compilation. + fn enable_incremental_compilation(&mut self, cache_store: Arc) -> Result<()>; /// Builds a new [`Compiler`] object from this configuration. fn build(&self) -> Result>; @@ -267,7 +269,22 @@ pub trait Compiler: Send + Sync { /// compilation target. Note that this may be an upper-bound where the /// alignment is larger than necessary for some platforms since it may /// depend on the platform's runtime configuration. - fn page_size_align(&self) -> u64; + fn page_size_align(&self) -> u64 { + use target_lexicon::*; + match (self.triple().operating_system, self.triple().architecture) { + ( + OperatingSystem::MacOSX { .. } + | OperatingSystem::Darwin + | OperatingSystem::Ios + | OperatingSystem::Tvos, + Architecture::Aarch64(..), + ) => 0x4000, + // 64 KB is the maximal page size (i.e. memory translation granule size) + // supported by the architecture and is used on some platforms. + (_, Architecture::Aarch64(..)) => 0x10000, + _ => 0x1000, + } + } /// Returns a list of configured settings for this compiler. fn flags(&self) -> BTreeMap; @@ -293,6 +310,17 @@ pub trait Compiler: Send + Sync { translation: &ModuleTranslation<'_>, funcs: &PrimaryMap, ) -> Result<()>; + + /// The function alignment required by this ISA. + fn function_alignment(&self) -> u32; + + /// Creates a new System V Common Information Entry for the ISA. + /// + /// Returns `None` if the ISA does not support System V unwind information. + fn create_systemv_cie(&self) -> Option { + // By default, an ISA cannot create a System V CIE. + None + } } /// Value of a configured setting for a [`Compiler`] diff --git a/crates/wasmtime/src/config.rs b/crates/wasmtime/src/config.rs index 9690daeb6d..2095281e07 100644 --- a/crates/wasmtime/src/config.rs +++ b/crates/wasmtime/src/config.rs @@ -1623,7 +1623,7 @@ impl Config { } if let Some(cache_store) = &self.compiler_config.cache_store { - compiler.enable_incremental_compilation(cache_store.clone()); + compiler.enable_incremental_compilation(cache_store.clone())?; } compiler.build() diff --git a/crates/winch/Cargo.toml b/crates/winch/Cargo.toml index a8d618d741..8c006624ea 100644 --- a/crates/winch/Cargo.toml +++ b/crates/winch/Cargo.toml @@ -14,8 +14,11 @@ wasmtime-environ = { workspace = true } anyhow = { workspace = true } object = { workspace = true } cranelift-codegen = { workspace = true } +wasmtime-cranelift-shared = { workspace = true } +wasmparser = { workspace = true } +gimli = { workspace = true } [features] -default = ["all-arch", "component-model"] +default = ["component-model"] component-model = ["wasmtime-environ/component-model"] all-arch = ["winch-codegen/all-arch"] diff --git a/crates/winch/src/builder.rs b/crates/winch/src/builder.rs index 1d9a0a645b..d8f17d5bae 100644 --- a/crates/winch/src/builder.rs +++ b/crates/winch/src/builder.rs @@ -1,67 +1,54 @@ use crate::compiler::Compiler; -use anyhow::Result; -use cranelift_codegen::settings; +use anyhow::{bail, Result}; use std::sync::Arc; -use target_lexicon::Triple; +use wasmtime_cranelift_shared::isa_builder::IsaBuilder; use wasmtime_environ::{CompilerBuilder, Setting}; -use winch_codegen::isa; +use winch_codegen::{isa, TargetIsa}; /// Compiler builder. struct Builder { - /// Target triple. - triple: Triple, - /// Shared flags builder. - shared_flags: settings::Builder, - /// ISA builder. - isa_builder: isa::Builder, + inner: IsaBuilder>>, } pub fn builder() -> Box { - let triple = Triple::host(); Box::new(Builder { - triple: triple.clone(), - shared_flags: settings::builder(), - // TODO: - // Either refactor and re-use `cranelift-native::builder()` or come up with a similar - // mechanism to lookup the host's architecture ISA and infer native flags. - isa_builder: isa::lookup(triple).expect("host architecture is not supported"), + inner: IsaBuilder::new(|triple| isa::lookup(triple).map_err(|e| e.into())), }) } impl CompilerBuilder for Builder { fn triple(&self) -> &target_lexicon::Triple { - &self.triple + self.inner.triple() } fn target(&mut self, target: target_lexicon::Triple) -> Result<()> { - self.triple = target; + self.inner.target(target)?; Ok(()) } - fn set(&mut self, _name: &str, _val: &str) -> Result<()> { - Ok(()) + fn set(&mut self, name: &str, value: &str) -> Result<()> { + self.inner.set(name, value) } - fn enable(&mut self, _name: &str) -> Result<()> { - Ok(()) + fn enable(&mut self, name: &str) -> Result<()> { + self.inner.enable(name) } fn settings(&self) -> Vec { - vec![] + self.inner.settings() } fn build(&self) -> Result> { - let flags = settings::Flags::new(self.shared_flags.clone()); - Ok(Box::new(Compiler::new( - self.isa_builder.clone().build(flags)?, - ))) + let isa = self.inner.build()?; + + Ok(Box::new(Compiler::new(isa))) } fn enable_incremental_compilation( &mut self, _cache_store: Arc, - ) { - todo!() + ) -> Result<()> { + bail!("incremental compilation is not supported on this platform"); } } diff --git a/crates/winch/src/compiler.rs b/crates/winch/src/compiler.rs index c975d084a8..3a0f55bd75 100644 --- a/crates/winch/src/compiler.rs +++ b/crates/winch/src/compiler.rs @@ -43,7 +43,8 @@ impl wasmtime_environ::Compiler for Compiler { _tunables: &Tunables, _resolve_reloc: &dyn Fn(usize, FuncIndex) -> usize, ) -> Result> { - todo!() + assert!(_funcs.is_empty()); + Ok(Vec::new()) } fn emit_trampoline_obj( @@ -59,20 +60,16 @@ impl wasmtime_environ::Compiler for Compiler { self.isa.triple() } - fn page_size_align(&self) -> u64 { - todo!() - } - fn flags(&self) -> std::collections::BTreeMap { - todo!() + wasmtime_cranelift_shared::clif_flags_to_wasmtime(self.isa.flags().iter()) } fn isa_flags(&self) -> std::collections::BTreeMap { - todo!() + wasmtime_cranelift_shared::clif_flags_to_wasmtime(self.isa.isa_flags()) } fn is_branch_protection_enabled(&self) -> bool { - todo!() + self.isa.is_branch_protection_enabled() } #[cfg(feature = "component-model")] @@ -88,4 +85,12 @@ impl wasmtime_environ::Compiler for Compiler { ) -> Result<()> { todo!() } + + fn function_alignment(&self) -> u32 { + self.isa.function_alignment() + } + + fn create_systemv_cie(&self) -> Option { + self.isa.create_systemv_cie() + } } diff --git a/crates/winch/src/lib.rs b/crates/winch/src/lib.rs index 96a6c25206..962019d878 100644 --- a/crates/winch/src/lib.rs +++ b/crates/winch/src/lib.rs @@ -1,3 +1,4 @@ +pub use builder::builder; + mod builder; mod compiler; -pub use builder::builder; diff --git a/scripts/publish.rs b/scripts/publish.rs index df377254c2..964f75bb0f 100644 --- a/scripts/publish.rs +++ b/scripts/publish.rs @@ -52,6 +52,7 @@ const CRATES_TO_PUBLISH: &[&str] = &[ "wasmtime-fiber", "wasmtime-environ", "wasmtime-runtime", + "wasmtime-cranelift-shared", "wasmtime-cranelift", "wasmtime-jit", "wasmtime-cache", diff --git a/winch/codegen/Cargo.toml b/winch/codegen/Cargo.toml index e5ebcf9e45..bf3bdab98e 100644 --- a/winch/codegen/Cargo.toml +++ b/winch/codegen/Cargo.toml @@ -18,6 +18,7 @@ target-lexicon = { workspace = true, features = ["std"] } # by Cranelift and Winch. cranelift-codegen = { workspace = true } regalloc2 = "0.6.0" +gimli = { workspace = true } [features] x64 = ["cranelift-codegen/x86"] diff --git a/winch/codegen/build.rs b/winch/codegen/build.rs new file mode 100644 index 0000000000..9f18db48a0 --- /dev/null +++ b/winch/codegen/build.rs @@ -0,0 +1,12 @@ +fn main() { + if cfg!(feature = "x64") || cfg!(feature = "arm64") || cfg!(feature = "all-arch") { + return; + } + + if cfg!(target_arch = "x86_64") { + println!("cargo:rustc-cfg=feature=\"x64\""); + } else if cfg!(target_arch = "aarch64") { + println!("cargo:rustc-cfg=feature=\"arm64\""); + } + println!("cargo:rerun-if-changed=build.rs"); +} diff --git a/winch/codegen/src/isa/aarch64/mod.rs b/winch/codegen/src/isa/aarch64/mod.rs index 4f8d3048c7..ff56cdb999 100644 --- a/winch/codegen/src/isa/aarch64/mod.rs +++ b/winch/codegen/src/isa/aarch64/mod.rs @@ -10,9 +10,9 @@ use crate::{ stack::Stack, }; use anyhow::Result; -use cranelift_codegen::{ - isa::aarch64::settings as aarch64_settings, settings::Flags, Final, MachBufferFinalized, -}; +use cranelift_codegen::settings::{self, Flags}; +use cranelift_codegen::{isa::aarch64::settings as aarch64_settings, Final, MachBufferFinalized}; +use cranelift_codegen::{MachTextSectionBuilder, TextSectionBuilder}; use masm::MacroAssembler as Aarch64Masm; use target_lexicon::Triple; use wasmparser::{FuncType, FuncValidator, FunctionBody, ValidatorResources}; @@ -25,15 +25,15 @@ mod regs; /// Create an ISA from the given triple. pub(crate) fn isa_builder(triple: Triple) -> Builder { - Builder { + Builder::new( triple, - settings: aarch64_settings::builder(), - constructor: |triple, shared_flags, settings| { + aarch64_settings::builder(), + |triple, shared_flags, settings| { let isa_flags = aarch64_settings::Flags::new(&shared_flags, settings); let isa = Aarch64::new(triple, shared_flags, isa_flags); Ok(Box::new(isa)) }, - } + ) } /// Aarch64 ISA. @@ -68,6 +68,18 @@ impl TargetIsa for Aarch64 { &self.triple } + fn flags(&self) -> &settings::Flags { + &self.shared_flags + } + + fn isa_flags(&self) -> Vec { + self.isa_flags.iter().collect() + } + + fn is_branch_protection_enabled(&self) -> bool { + self.isa_flags.use_bti() + } + fn compile_function( &self, sig: &FuncType, @@ -88,4 +100,15 @@ impl TargetIsa for Aarch64 { codegen.emit(&mut body, validator)?; Ok(masm.finalize()) } + + fn text_section_builder(&self, num_funcs: usize) -> Box { + Box::new(MachTextSectionBuilder::< + cranelift_codegen::isa::aarch64::inst::Inst, + >::new(num_funcs)) + } + + fn function_alignment(&self) -> u32 { + // See `cranelift_codegen::isa::TargetIsa::function_alignment`. + 32 + } } diff --git a/winch/codegen/src/isa/mod.rs b/winch/codegen/src/isa/mod.rs index ea0f93828e..37fcb76f0d 100644 --- a/winch/codegen/src/isa/mod.rs +++ b/winch/codegen/src/isa/mod.rs @@ -1,6 +1,8 @@ use anyhow::{anyhow, Result}; use core::fmt::Formatter; -use cranelift_codegen::{isa::CallConv, settings, Final, MachBufferFinalized}; +use cranelift_codegen::isa::{CallConv, IsaBuilder}; +use cranelift_codegen::settings; +use cranelift_codegen::{Final, MachBufferFinalized, TextSectionBuilder}; use std::{ error, fmt::{self, Debug, Display}, @@ -29,24 +31,7 @@ macro_rules! isa_builder { }}; } -/// The target ISA builder. -#[derive(Clone)] -pub struct Builder { - /// The target triple. - triple: Triple, - /// The ISA settings builder. - settings: settings::Builder, - /// The Target ISA constructor. - constructor: fn(Triple, settings::Flags, settings::Builder) -> Result>, -} - -impl Builder { - /// Create a TargetIsa by combining ISA-specific settings with the provided - /// shared flags. - pub fn build(self, shared_flags: settings::Flags) -> Result> { - (self.constructor)(self.triple, shared_flags, self.settings) - } -} +pub type Builder = IsaBuilder>>; /// Look for an ISA builder for the given target triple. pub fn lookup(triple: Triple) -> Result { @@ -92,6 +77,17 @@ pub trait TargetIsa: Send + Sync { /// Get the target triple of the ISA. fn triple(&self) -> &Triple; + /// Get the ISA-independent flags that were used to make this trait object. + fn flags(&self) -> &settings::Flags; + + /// Get the ISA-dependent flag values that were used to make this trait object. + fn isa_flags(&self) -> Vec; + + /// Get a flag indicating whether branch protection is enabled. + fn is_branch_protection_enabled(&self) -> bool { + false + } + fn compile_function( &self, sig: &FuncType, @@ -108,6 +104,18 @@ pub trait TargetIsa: Send + Sync { fn endianness(&self) -> target_lexicon::Endianness { self.triple().endianness().unwrap() } + + /// See `cranelift_codegen::isa::TargetIsa::create_systemv_cie`. + fn create_systemv_cie(&self) -> Option { + // By default, an ISA cannot create a System V CIE. + None + } + + /// See `cranelift_codegen::isa::TargetIsa::text_section_builder`. + fn text_section_builder(&self, num_labeled_funcs: usize) -> Box; + + /// See `cranelift_codegen::isa::TargetIsa::function_alignment`. + fn function_alignment(&self) -> u32; } impl Debug for &dyn TargetIsa { diff --git a/winch/codegen/src/isa/x64/mod.rs b/winch/codegen/src/isa/x64/mod.rs index e44f3470f3..dc31055409 100644 --- a/winch/codegen/src/isa/x64/mod.rs +++ b/winch/codegen/src/isa/x64/mod.rs @@ -10,9 +10,9 @@ use crate::{ regset::RegSet, }; use anyhow::Result; -use cranelift_codegen::{ - isa::x64::settings as x64_settings, settings::Flags, Final, MachBufferFinalized, -}; +use cranelift_codegen::settings::{self, Flags}; +use cranelift_codegen::{isa::x64::settings as x64_settings, Final, MachBufferFinalized}; +use cranelift_codegen::{MachTextSectionBuilder, TextSectionBuilder}; use target_lexicon::Triple; use wasmparser::{FuncType, FuncValidator, FunctionBody, ValidatorResources}; @@ -30,17 +30,17 @@ mod regs; /// Create an ISA builder. pub(crate) fn isa_builder(triple: Triple) -> Builder { - Builder { + Builder::new( triple, - settings: x64_settings::builder(), - constructor: |triple, shared_flags, settings| { + x64_settings::builder(), + |triple, shared_flags, settings| { // TODO: Once enabling/disabling flags is allowed, and once features like SIMD are supported // ensure compatibility between shared flags and ISA flags. let isa_flags = x64_settings::Flags::new(&shared_flags, settings); let isa = X64::new(triple, shared_flags, isa_flags); Ok(Box::new(isa)) }, - } + ) } /// x64 ISA. @@ -73,6 +73,14 @@ impl TargetIsa for X64 { &self.triple } + fn flags(&self) -> &settings::Flags { + &self.shared_flags + } + + fn isa_flags(&self) -> Vec { + self.isa_flags.iter().collect() + } + fn compile_function( &self, sig: &FuncType, @@ -94,4 +102,13 @@ impl TargetIsa for X64 { Ok(masm.finalize()) } + + fn text_section_builder(&self, num_funcs: usize) -> Box { + Box::new(MachTextSectionBuilder::::new(num_funcs)) + } + + fn function_alignment(&self) -> u32 { + // See `cranelift_codegen`'s value of this for more information. + 16 + } } diff --git a/winch/filetests/src/lib.rs b/winch/filetests/src/lib.rs index 4400bf0652..3f49abddc7 100644 --- a/winch/filetests/src/lib.rs +++ b/winch/filetests/src/lib.rs @@ -94,7 +94,7 @@ mod test { let shared_flags = settings::Flags::new(settings::builder()); let isa_builder = lookup(triple).unwrap(); - let isa = isa_builder.build(shared_flags).unwrap(); + let isa = isa_builder.finish(shared_flags).unwrap(); let mut validator = Validator::new(); let parser = WasmParser::new(0); diff --git a/winch/src/compile.rs b/winch/src/compile.rs index 6573801044..508fa56c78 100644 --- a/winch/src/compile.rs +++ b/winch/src/compile.rs @@ -27,7 +27,7 @@ pub fn run(opt: &Options) -> Result<()> { let triple = Triple::from_str(&opt.target)?; let shared_flags = settings::Flags::new(settings::builder()); let isa_builder = lookup(triple)?; - let isa = isa_builder.build(shared_flags)?; + let isa = isa_builder.finish(shared_flags)?; let mut validator = Validator::new(); let parser = WasmParser::new(0); let mut types = Default::default();