Skip to content

Commit

Permalink
Basic 32-bit support for i686
Browse files Browse the repository at this point in the history
prtest:full
  • Loading branch information
alexcrichton committed Dec 5, 2024
1 parent 7db36ed commit a318d49
Show file tree
Hide file tree
Showing 25 changed files with 234 additions and 62 deletions.
11 changes: 9 additions & 2 deletions ci/build-test-matrix.js
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ function supports32Bit(pkg) {
if (pkg.indexOf("pulley") !== -1)
return true;

return pkg == 'wasmtime-fiber';
return pkg == 'wasmtime-fiber' || pkg == 'wasmtime';
}

// This is the full, unsharded, and unfiltered matrix of what we test on
Expand Down Expand Up @@ -231,7 +231,9 @@ async function shard(configs) {
for (const config of configs) {
// Special case 32-bit configs. Only some crates, according to
// `supports32Bit`, run on this target. At this time the set of supported
// crates is small enough that they're not sharded.
// crates is small enough that they're not sharded. A second shard, however,
// is included which runs `--test wast` to run the full `*.wast` test suite
// in CI on 32-bit platforms, at this time effectively testing Pulley.
if (config["32-bit"] === true) {
sharded.push(Object.assign(
{},
Expand All @@ -242,6 +244,11 @@ async function shard(configs) {
.join(" "),
}
));
sharded.push(Object.assign(
{},
config,
{ bucket: '--test wast' },
));
continue;
}

Expand Down
12 changes: 10 additions & 2 deletions cranelift/codegen/src/isa/pulley_shared/abi.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
//! Implementation of a standard Pulley ABI.
use super::{inst::*, PulleyFlags, PulleyTargetKind};
use crate::isa::pulley_shared::PulleyBackend;
use crate::isa::pulley_shared::{PointerWidth, PulleyBackend};
use crate::{
ir::{self, types::*, MemFlags, Signature},
isa::{self, unwind::UnwindInst},
Expand Down Expand Up @@ -533,7 +533,15 @@ where
_isa_flags: &PulleyFlags,
) -> u32 {
match rc {
RegClass::Int => 1,
// Spilling an integer register requires spilling 8 bytes, and spill
// slots are defined in terms of "word bytes" or the size of a
// pointer. That means on 32-bit pulley we need to take up two spill
// slots for integers where on 64-bit pulley we need to only take up
// one spill slot for integers.
RegClass::Int => match P::pointer_width() {
PointerWidth::PointerWidth32 => 2,
PointerWidth::PointerWidth64 => 1,
},
RegClass::Float => todo!(),
RegClass::Vector => unreachable!(),
}
Expand Down
1 change: 1 addition & 0 deletions cranelift/jit/src/compiled_blob.rs
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,7 @@ impl CompiledBlob {
let what_page = (what as usize) & !0xfff;
let at_page = (at as usize) & !0xfff;
let pcrel = (what_page as isize).checked_sub(at_page as isize).unwrap();
#[cfg(target_pointer_width = "64")]
assert!(
(-1 << 32) <= pcrel && pcrel < (1 << 32),
"can't reach GOT page with ±4GB `adrp` instruction"
Expand Down
8 changes: 5 additions & 3 deletions crates/wasi-nn/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -30,16 +30,18 @@ wasmtime = { workspace = true, features = [
# These dependencies are necessary for the wasi-nn implementation:
tracing = { workspace = true }
thiserror = { workspace = true }
openvino = { version = "0.8.0", features = [
"runtime-linking",
], optional = true }

ort = { version = "2.0.0-rc.2", default-features = false, features = [
"copy-dylibs",
"download-binaries",
], optional = true }
tch = { version = "0.17.0", default-features = false, optional = true}

[target.'cfg(target_pointer_width = "64")'.dependencies]
openvino = { version = "0.8.0", features = [
"runtime-linking",
], optional = true }

[target.'cfg(windows)'.dependencies.windows]
version = "0.52"
features = [
Expand Down
8 changes: 5 additions & 3 deletions crates/wasi-nn/src/backend/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
#[cfg(feature = "onnx")]
pub mod onnx;
#[cfg(feature = "openvino")]
#[cfg(all(feature = "openvino", target_pointer_width = "64"))]
pub mod openvino;
#[cfg(feature = "pytorch")]
pub mod pytorch;
Expand All @@ -13,7 +13,7 @@ pub mod winml;

#[cfg(feature = "onnx")]
use self::onnx::OnnxBackend;
#[cfg(feature = "openvino")]
#[cfg(all(feature = "openvino", target_pointer_width = "64"))]
use self::openvino::OpenvinoBackend;
#[cfg(feature = "pytorch")]
use self::pytorch::PytorchBackend;
Expand All @@ -31,7 +31,8 @@ use wiggle::GuestError;
/// Return a list of all available backend frameworks.
pub fn list() -> Vec<Backend> {
let mut backends = vec![];
#[cfg(feature = "openvino")]
let _ = &mut backends; // silence warnings if none are enabled
#[cfg(all(feature = "openvino", target_pointer_width = "64"))]
{
backends.push(Backend::from(OpenvinoBackend::default()));
}
Expand Down Expand Up @@ -120,6 +121,7 @@ pub enum BackendError {
}

/// Read a file into a byte vector.
#[allow(dead_code, reason = "not used on all platforms")]
fn read(path: &Path) -> anyhow::Result<Vec<u8>> {
let mut file = File::open(path)?;
let mut buffer = vec![];
Expand Down
5 changes: 5 additions & 0 deletions crates/wasmtime/src/engine/serialization.rs
Original file line number Diff line number Diff line change
Expand Up @@ -641,6 +641,8 @@ mod test {
}

#[test]
#[cfg(target_arch = "x86_64")] // test on a platform that is known to use
// Cranelift
fn test_os_mismatch() -> Result<()> {
let engine = Engine::default();
let mut metadata = Metadata::new(&engine);
Expand Down Expand Up @@ -712,6 +714,7 @@ Caused by:

#[test]
#[cfg_attr(miri, ignore)]
#[cfg(target_pointer_width = "64")] // different defaults on 32-bit platforms
fn test_tunables_int_mismatch() -> Result<()> {
let engine = Engine::default();
let mut metadata = Metadata::new(&engine);
Expand Down Expand Up @@ -762,6 +765,8 @@ Caused by:
}

#[test]
#[cfg(target_arch = "x86_64")] // test on a platform that is known to
// implement threads
fn test_feature_mismatch() -> Result<()> {
let mut config = Config::new();
config.wasm_threads(true);
Expand Down
16 changes: 15 additions & 1 deletion crates/wasmtime/src/runtime/externals/table.rs
Original file line number Diff line number Diff line change
Expand Up @@ -441,6 +441,7 @@ impl Table {
mod tests {
use super::*;
use crate::{Instance, Module, Store};
use wasmtime_environ::TripleExt;

#[test]
fn hash_key_is_stable_across_duplicate_store_data_entries() -> Result<()> {
Expand All @@ -452,7 +453,20 @@ mod tests {
(table (export "t") 1 1 externref)
)
"#,
)?;
);
// Expect this test to fail on pulley at this time. When pulley supports
// externref this should switch back to using `?` on the constructor
// above for all platforms.
let module = match module {
Ok(module) => {
assert!(!store.engine().target().is_pulley());
module
}
Err(e) => {
assert!(store.engine().target().is_pulley(), "bad error {e:?}");
return Ok(());
}
};
let instance = Instance::new(&mut store, &module, &[])?;

// Each time we `get_table`, we call `Table::from_wasmtime` which adds
Expand Down
17 changes: 16 additions & 1 deletion crates/wasmtime/src/runtime/module/registry.rs
Original file line number Diff line number Diff line change
Expand Up @@ -300,6 +300,8 @@ pub fn unregister_code(code: &Arc<CodeMemory>) {
#[cfg_attr(miri, ignore)]
fn test_frame_info() -> Result<(), anyhow::Error> {
use crate::*;
use wasmtime_environ::TripleExt;

let mut store = Store::<()>::default();
let module = Module::new(
store.engine(),
Expand All @@ -314,7 +316,20 @@ fn test_frame_info() -> Result<(), anyhow::Error> {
(func (export "rem_u") (param $x i32) (param $y i32) (result i32) (i32.rem_u (local.get $x) (local.get $y)))
)
"#,
)?;
);
// Expect this test to fail on pulley at this time. When pulley supports
// the instructions above this should switch back to using `?` on the
// constructor above for all platforms.
let module = match module {
Ok(module) => {
assert!(!store.engine().target().is_pulley());
module
}
Err(e) => {
assert!(store.engine().target().is_pulley(), "bad error {e:?}");
return Ok(());
}
};
// Create an instance to ensure the frame information is registered.
Instance::new(&mut store, &module, &[])?;

Expand Down
16 changes: 2 additions & 14 deletions crates/wasmtime/src/runtime/values.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1021,26 +1021,14 @@ mod tests {
fn size_of_val() {
// Try to keep tabs on the size of `Val` and make sure we don't grow its
// size.
assert_eq!(
std::mem::size_of::<Val>(),
if cfg!(any(
target_arch = "x86_64",
target_arch = "aarch64",
target_arch = "riscv64",
target_arch = "s390x"
)) {
24
} else {
panic!("unsupported architecture")
}
);
assert!(std::mem::size_of::<Val>() <= 24);
}

#[test]
fn size_of_ref() {
// Try to keep tabs on the size of `Ref` and make sure we don't grow its
// size.
assert_eq!(std::mem::size_of::<Ref>(), 24);
assert!(std::mem::size_of::<Ref>() <= 24);
}

#[test]
Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
//! x86_64-specific definitions of architecture-specific functions in Wasmtime.
//! arm-specific definitions of architecture-specific functions in Wasmtime.
#[inline]
#[allow(missing_docs)]
pub fn get_stack_pointer() -> usize {
let stack_pointer: usize;
unsafe {
core::arch::asm!(
"mov {}, rsp",
"mov {}, sp",
out(reg) stack_pointer,
options(nostack,nomem),
);
Expand All @@ -24,5 +24,5 @@ pub unsafe fn get_next_older_pc_from_fp(fp: usize) -> usize {
pub const NEXT_OLDER_FP_FROM_FP_OFFSET: usize = 0;

pub fn assert_fp_is_aligned(fp: usize) {
assert_eq!(fp % 16, 0, "stack should always be aligned to 16");
assert_eq!(fp % 8, 0, "stack should always be aligned to 8");
}
9 changes: 6 additions & 3 deletions crates/wasmtime/src/runtime/vm/arch/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,9 @@
//! crate.
cfg_if::cfg_if! {
if #[cfg(target_arch = "x86_64")] {
mod x86_64;
use x86_64 as imp;
if #[cfg(any(target_arch = "x86_64", target_arch = "x86"))] {
mod x86;
use x86 as imp;
} else if #[cfg(target_arch = "aarch64")] {
mod aarch64;
use aarch64 as imp;
Expand All @@ -20,6 +20,9 @@ cfg_if::cfg_if! {
} else if #[cfg(target_arch = "riscv64")] {
mod riscv64;
use riscv64 as imp;
} else if #[cfg(target_arch = "arm")] {
mod arm;
use arm as imp;
} else {
mod unsupported;
use unsupported as imp;
Expand Down
10 changes: 1 addition & 9 deletions crates/wasmtime/src/runtime/vm/arch/unsupported.rs
Original file line number Diff line number Diff line change
@@ -1,15 +1,7 @@
compile_error!("Wasmtime's runtime is being compiled for an architecture that it does not support");

cfg_if::cfg_if! {
if #[cfg(target_arch = "x86")] {
compile_error!("\
the tracking issue for i686 support is https://github.com/bytecodealliance/wasmtime/issues/1980 \
");
} else if #[cfg(target_arch = "arm")] {
compile_error!("\
the tracking issue for arm support is https://github.com/bytecodealliance/wasmtime/issues/1173 \
");
} else if #[cfg(target_arch = "riscv32")] {
if #[cfg(target_arch = "riscv32")] {
compile_error!("\
the tracking issue for riscv32 support is https://github.com/bytecodealliance/wasmtime/issues/8768 \
");
Expand Down
39 changes: 39 additions & 0 deletions crates/wasmtime/src/runtime/vm/arch/x86.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
//! x86-specific (also x86-64) definitions of architecture-specific functions in
//! Wasmtime.
#[inline]
#[allow(missing_docs)]
pub fn get_stack_pointer() -> usize {
let stack_pointer: usize;
unsafe {
#[cfg(target_pointer_width = "64")]
core::arch::asm!(
"mov {}, rsp",
out(reg) stack_pointer,
options(nostack,nomem),
);
#[cfg(target_pointer_width = "32")]
core::arch::asm!(
"mov {}, esp",
out(reg) stack_pointer,
options(nostack,nomem),
);
}
stack_pointer
}

pub unsafe fn get_next_older_pc_from_fp(fp: usize) -> usize {
// The calling convention always pushes the return pointer (aka the PC of
// the next older frame) just before this frame.
*(fp as *mut usize).offset(1)
}

// And the current frame pointer points to the next older frame pointer.
pub const NEXT_OLDER_FP_FROM_FP_OFFSET: usize = 0;

/// Frame pointers are aligned if they're aligned to twice the size of a
/// pointer.
pub fn assert_fp_is_aligned(fp: usize) {
let align = 2 * size_of::<usize>();
assert_eq!(fp % align, 0, "stack should always be aligned to {align}");
}
7 changes: 4 additions & 3 deletions crates/wasmtime/src/runtime/vm/gc/enabled/drc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -985,6 +985,7 @@ impl<T> DerefMut for DebugOnly<T> {
#[cfg(test)]
mod tests {
use super::*;
use wasmtime_environ::HostPtr;

#[test]
fn vm_drc_header_size_align() {
Expand Down Expand Up @@ -1019,7 +1020,7 @@ mod tests {
let actual_offset = (ref_count_ptr as usize) - (extern_data_ptr as usize);

let offsets = wasmtime_environ::VMOffsets::from(wasmtime_environ::VMOffsetsFields {
ptr: 8,
ptr: HostPtr,
num_imported_functions: 0,
num_imported_tables: 0,
num_imported_memories: 0,
Expand Down Expand Up @@ -1047,7 +1048,7 @@ mod tests {
let actual_offset = (next_ptr as usize) - (table_ptr as usize);

let offsets = wasmtime_environ::VMOffsets::from(wasmtime_environ::VMOffsetsFields {
ptr: 8,
ptr: HostPtr,
num_imported_functions: 0,
num_imported_tables: 0,
num_imported_memories: 0,
Expand All @@ -1074,7 +1075,7 @@ mod tests {
let actual_offset = (end_ptr as usize) - (table_ptr as usize);

let offsets = wasmtime_environ::VMOffsets::from(wasmtime_environ::VMOffsetsFields {
ptr: 8,
ptr: HostPtr,
num_imported_functions: 0,
num_imported_tables: 0,
num_imported_memories: 0,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -699,6 +699,7 @@ unsafe impl InstanceAllocatorImpl for PoolingInstanceAllocator {
}

#[cfg(test)]
#[cfg(target_pointer_width = "64")]
mod test {
use super::*;

Expand Down
Loading

0 comments on commit a318d49

Please sign in to comment.