From 28f6b0368c3df72f40773f9377bca44807f88d03 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Wed, 11 Dec 2024 14:01:13 -0800 Subject: [PATCH] pulley: Support `runtests` in Cranelift filetests This'll help when adding unit tests for Pulley and/or might be useful when debugging various lowerings and such in the future. I hope to enable more tests in the future once more pulley lowerings are available. --- cranelift/filetests/Cargo.toml | 2 +- .../filetests/filetests/runtests/br.clif | 4 ++ .../filetests/filetests/runtests/brif.clif | 4 ++ cranelift/filetests/src/function_runner.rs | 42 ++++++++++++++++-- cranelift/filetests/src/test_run.rs | 44 ++++++++++++++++--- 5 files changed, 87 insertions(+), 9 deletions(-) diff --git a/cranelift/filetests/Cargo.toml b/cranelift/filetests/Cargo.toml index b6e0df9814f2..7736ff247903 100644 --- a/cranelift/filetests/Cargo.toml +++ b/cranelift/filetests/Cargo.toml @@ -37,4 +37,4 @@ serde = { workspace = true } serde_derive = { workspace = true } cranelift.workspace = true smallvec = { workspace = true } -pulley-interpreter = { workspace = true, features = ["disas", "std"] } +pulley-interpreter = { workspace = true, features = ["disas", "std", "interp"] } diff --git a/cranelift/filetests/filetests/runtests/br.clif b/cranelift/filetests/filetests/runtests/br.clif index 689682ebd594..7308c78bf66e 100644 --- a/cranelift/filetests/filetests/runtests/br.clif +++ b/cranelift/filetests/filetests/runtests/br.clif @@ -5,6 +5,10 @@ target s390x target x86_64 target riscv64 target riscv64 has_c has_zcb +target pulley32 +target pulley32be +target pulley64 +target pulley64be function %jump() -> i8 { block0: diff --git a/cranelift/filetests/filetests/runtests/brif.clif b/cranelift/filetests/filetests/runtests/brif.clif index 60648d569cb2..54dea5ee6f26 100644 --- a/cranelift/filetests/filetests/runtests/brif.clif +++ b/cranelift/filetests/filetests/runtests/brif.clif @@ -5,6 +5,10 @@ target s390x target x86_64 target riscv64 target riscv64 has_c has_zcb +target pulley32 +target pulley32be +target pulley64 +target pulley64be function %brif_value(i8) -> i64 { block0(v0: i8): diff --git a/cranelift/filetests/src/function_runner.rs b/cranelift/filetests/src/function_runner.rs index bc00b1be7dbc..4b9a43bf48a4 100644 --- a/cranelift/filetests/src/function_runner.rs +++ b/cranelift/filetests/src/function_runner.rs @@ -13,9 +13,12 @@ use cranelift_jit::{JITBuilder, JITModule}; use cranelift_module::{FuncId, Linkage, Module, ModuleError}; use cranelift_native::builder_with_options; use cranelift_reader::TestFile; +use pulley_interpreter::interp as pulley; use std::cmp::max; use std::collections::hash_map::Entry; use std::collections::HashMap; +use std::ptr::NonNull; +use target_lexicon::Architecture; use thiserror::Error; const TESTFILE_NAMESPACE: u32 = 0; @@ -370,12 +373,45 @@ impl<'a> Trampoline<'a> { let function_ptr = self.module.get_finalized_function(self.func_id); let trampoline_ptr = self.module.get_finalized_function(self.trampoline_id); - let callable_trampoline: fn(*const u8, *mut u128) -> () = - unsafe { mem::transmute(trampoline_ptr) }; - callable_trampoline(function_ptr, arguments_address); + unsafe { + self.call_raw(trampoline_ptr, function_ptr, arguments_address); + } values.collect_returns(&self.func_signature) } + + unsafe fn call_raw( + &self, + trampoline_ptr: *const u8, + function_ptr: *const u8, + arguments_address: *mut u128, + ) { + match self.module.isa().triple().architecture { + // For the pulley target this is pulley bytecode, not machine code, + // so run the interpreter. + Architecture::Pulley32 + | Architecture::Pulley64 + | Architecture::Pulley32be + | Architecture::Pulley64be => { + let mut state = pulley::Vm::new(); + state.call( + NonNull::new(trampoline_ptr.cast_mut()).unwrap(), + &[ + pulley::XRegVal::new_ptr(function_ptr.cast_mut()).into(), + pulley::XRegVal::new_ptr(arguments_address).into(), + ], + [], + ); + } + + // Other targets natively execute this machine code. + _ => { + let callable_trampoline: fn(*const u8, *mut u128) -> () = + unsafe { mem::transmute(trampoline_ptr) }; + callable_trampoline(function_ptr, arguments_address); + } + } + } } /// Compilation Error when compiling a function. diff --git a/cranelift/filetests/src/test_run.rs b/cranelift/filetests/src/test_run.rs index 1e7e977c2b24..aee78c164446 100644 --- a/cranelift/filetests/src/test_run.rs +++ b/cranelift/filetests/src/test_run.rs @@ -59,8 +59,23 @@ fn is_isa_compatible( let requested_arch = requested.triple().architecture; match (host_arch, requested_arch) { + // If the host matches the requested target, then that's all good. (host, requested) if host == requested => {} + + // Allow minor differences in risc-v targets. (Architecture::Riscv64(_), Architecture::Riscv64(_)) => {} + + // Any host can run pulley so long as the pointer width and endianness + // match. + ( + _, + Architecture::Pulley32 + | Architecture::Pulley64 + | Architecture::Pulley32be + | Architecture::Pulley64be, + ) if host.triple().pointer_width() == requested.triple().pointer_width() + && host.triple().endianness() == requested.triple().endianness() => {} + _ => { return Err(format!( "skipped {file_path}: host can't run {requested_arch:?} programs" @@ -72,6 +87,10 @@ fn is_isa_compatible( // we can't natively support on the host. let requested_flags = requested.isa_flags(); for req_value in requested_flags { + // pointer_width for pulley already validated above + if req_value.name == "pointer_width" { + continue; + } let requested = match req_value.as_bool() { Some(requested) => requested, None => unimplemented!("ISA flag {} of kind {:?}", req_value.name, req_value.kind()), @@ -116,11 +135,26 @@ fn compile_testfile( flags: &Flags, isa: &dyn TargetIsa, ) -> anyhow::Result { - // We can't use the requested ISA directly since it does not contain info - // about the operating system / calling convention / etc.. - // - // Copy the requested ISA flags into the host ISA and use that. - let isa = build_host_isa(false, flags.clone(), isa.isa_flags()); + let isa = match isa.triple().architecture { + // Convert `&dyn TargetIsa` to `OwnedTargetIsa` by re-making the ISA and + // applying pulley flags/etc. + Architecture::Pulley32 + | Architecture::Pulley64 + | Architecture::Pulley32be + | Architecture::Pulley64be => { + let mut builder = cranelift_codegen::isa::lookup(isa.triple().clone())?; + for value in isa.isa_flags() { + builder.set(value.name, &value.value_string()).unwrap(); + } + builder.finish(flags.clone())? + } + + // We can't use the requested ISA directly since it does not contain info + // about the operating system / calling convention / etc.. + // + // Copy the requested ISA flags into the host ISA and use that. + _ => build_host_isa(false, flags.clone(), isa.isa_flags()), + }; let mut tfc = TestFileCompiler::new(isa); tfc.add_testfile(testfile)?;