diff --git a/cranelift/codegen/src/settings.rs b/cranelift/codegen/src/settings.rs index e21eceda27..f94380ea66 100644 --- a/cranelift/codegen/src/settings.rs +++ b/cranelift/codegen/src/settings.rs @@ -113,6 +113,17 @@ impl Value { _ => None, } } + + /// Builds a string from the current value + pub fn value_string(&self) -> String { + match self.kind() { + SettingKind::Enum => self.as_enum().map(|b| b.to_string()), + SettingKind::Num => self.as_num().map(|b| b.to_string()), + SettingKind::Bool => self.as_bool().map(|b| b.to_string()), + SettingKind::Preset => unreachable!(), + } + .unwrap() + } } impl fmt::Display for Value { diff --git a/cranelift/filetests/filetests/runtests/atomic-rmw-little.clif b/cranelift/filetests/filetests/runtests/atomic-rmw-little.clif index 0ce931876a..2c201f902d 100644 --- a/cranelift/filetests/filetests/runtests/atomic-rmw-little.clif +++ b/cranelift/filetests/filetests/runtests/atomic-rmw-little.clif @@ -1,5 +1,6 @@ test run target s390x +target s390x has_mie2 target aarch64 target aarch64 has_lse target x86_64 diff --git a/cranelift/filetests/filetests/runtests/atomic-rmw-subword-big.clif b/cranelift/filetests/filetests/runtests/atomic-rmw-subword-big.clif index b6218d4d35..8e24b8e55d 100644 --- a/cranelift/filetests/filetests/runtests/atomic-rmw-subword-big.clif +++ b/cranelift/filetests/filetests/runtests/atomic-rmw-subword-big.clif @@ -1,5 +1,6 @@ test run target s390x +target s390x has_mie2 ; We can't test that these instructions are right regarding atomicity, but we can ; test if they perform their operation correctly @@ -457,4 +458,3 @@ block0(v0: i32, v1: i64, v2: i8): ; run: %atomic_rmw_xchg_big_i8(0x12345678, 2, 0xff) == 0x1234ff78 ; run: %atomic_rmw_xchg_big_i8(0x12345678, 3, 0x11) == 0x12345611 ; run: %atomic_rmw_xchg_big_i8(0x12345678, 3, 0xff) == 0x123456ff - diff --git a/cranelift/filetests/filetests/runtests/atomic-rmw-subword-little.clif b/cranelift/filetests/filetests/runtests/atomic-rmw-subword-little.clif index 7e597ecf1d..163a886448 100644 --- a/cranelift/filetests/filetests/runtests/atomic-rmw-subword-little.clif +++ b/cranelift/filetests/filetests/runtests/atomic-rmw-subword-little.clif @@ -1,5 +1,6 @@ test run target s390x +target s390x has_mie2 target aarch64 target aarch64 has_lse target x86_64 @@ -456,4 +457,3 @@ block0(v0: i32, v1: i64, v2: i8): ; run: %atomic_rmw_xchg_little_i8(0x12345678, 1, 0xff) == 0x1234ff78 ; run: %atomic_rmw_xchg_little_i8(0x12345678, 0, 0x11) == 0x12345611 ; run: %atomic_rmw_xchg_little_i8(0x12345678, 0, 0xff) == 0x123456ff - diff --git a/cranelift/filetests/filetests/runtests/bitops.clif b/cranelift/filetests/filetests/runtests/bitops.clif index 9120f62cdc..2e3f114274 100644 --- a/cranelift/filetests/filetests/runtests/bitops.clif +++ b/cranelift/filetests/filetests/runtests/bitops.clif @@ -1,6 +1,7 @@ test run target aarch64 target s390x +target s390x has_mie2 ; target x86_64 TODO: Not yet implemented on x86_64 function %bnot_band() -> b1 { diff --git a/cranelift/filetests/filetests/runtests/br.clif b/cranelift/filetests/filetests/runtests/br.clif index b6c1f1d282..8031f5735c 100644 --- a/cranelift/filetests/filetests/runtests/br.clif +++ b/cranelift/filetests/filetests/runtests/br.clif @@ -1,7 +1,6 @@ test interpret test run target aarch64 -target arm target s390x target x86_64 diff --git a/cranelift/filetests/filetests/runtests/clz.clif b/cranelift/filetests/filetests/runtests/clz.clif index d8ed24d0e6..a6f7dde54b 100644 --- a/cranelift/filetests/filetests/runtests/clz.clif +++ b/cranelift/filetests/filetests/runtests/clz.clif @@ -2,6 +2,7 @@ test interpret test run target aarch64 target x86_64 +target x86_64 has_lzcnt function %clz_i8(i8) -> i8 { block0(v0: i8): diff --git a/cranelift/filetests/filetests/runtests/const.clif b/cranelift/filetests/filetests/runtests/const.clif index ec91e171bb..579b936eec 100644 --- a/cranelift/filetests/filetests/runtests/const.clif +++ b/cranelift/filetests/filetests/runtests/const.clif @@ -1,6 +1,5 @@ test run target aarch64 -target arm target s390x target x86_64 diff --git a/cranelift/filetests/filetests/runtests/ctz.clif b/cranelift/filetests/filetests/runtests/ctz.clif index 6a75dd6b73..a7776d1897 100644 --- a/cranelift/filetests/filetests/runtests/ctz.clif +++ b/cranelift/filetests/filetests/runtests/ctz.clif @@ -2,6 +2,7 @@ test interpret test run target aarch64 target x86_64 +target x86_64 has_bmi1 function %ctz_i8(i8) -> i8 { block0(v0: i8): diff --git a/cranelift/filetests/filetests/runtests/div-checks.clif b/cranelift/filetests/filetests/runtests/div-checks.clif index beb1a077ff..32b5588528 100644 --- a/cranelift/filetests/filetests/runtests/div-checks.clif +++ b/cranelift/filetests/filetests/runtests/div-checks.clif @@ -1,6 +1,5 @@ test run target aarch64 -target arm target s390x set avoid_div_traps=false target x86_64 diff --git a/cranelift/filetests/filetests/runtests/popcnt.clif b/cranelift/filetests/filetests/runtests/popcnt.clif index 4f6f7aa9c4..1afcca329a 100644 --- a/cranelift/filetests/filetests/runtests/popcnt.clif +++ b/cranelift/filetests/filetests/runtests/popcnt.clif @@ -2,7 +2,7 @@ test interpret test run target aarch64 target x86_64 -target x86_64 has_popcnt=1 +target x86_64 has_popcnt function %popcnt_i8(i8) -> i8 { block0(v0: i8): diff --git a/cranelift/filetests/src/test_run.rs b/cranelift/filetests/src/test_run.rs index 504d3e0f2d..24d0a3452a 100644 --- a/cranelift/filetests/src/test_run.rs +++ b/cranelift/filetests/src/test_run.rs @@ -6,13 +6,14 @@ use crate::function_runner::SingleFunctionCompiler; use crate::runtest_environment::{HeapMemory, RuntestEnvironment}; use crate::subtest::{Context, SubTest}; use cranelift_codegen::data_value::DataValue; -use cranelift_codegen::ir; use cranelift_codegen::ir::Type; +use cranelift_codegen::isa::TargetIsa; +use cranelift_codegen::settings::Configurable; +use cranelift_codegen::{ir, settings}; use cranelift_reader::parse_run_command; use cranelift_reader::TestCommand; use log::trace; use std::borrow::Cow; -use target_lexicon::Architecture; struct TestRun; @@ -24,6 +25,68 @@ pub fn subtest(parsed: &TestCommand) -> anyhow::Result> { Ok(Box::new(TestRun)) } +/// Builds a [TargetIsa] for the current host. +/// +/// ISA Flags can be overridden by passing [Value]'s via `isa_flags`. +fn build_host_isa( + infer_native_flags: bool, + flags: settings::Flags, + isa_flags: Vec, +) -> Box { + let mut builder = cranelift_native::builder_with_options(infer_native_flags) + .expect("Unable to build a TargetIsa for the current host"); + + for value in isa_flags { + builder.set(value.name, &value.value_string()).unwrap(); + } + + builder.finish(flags).unwrap() +} + +/// Checks if the host's ISA is compatible with the one requested by the test. +fn is_isa_compatible( + context: &Context, + host: &dyn TargetIsa, + requested: &dyn TargetIsa, +) -> Result<(), String> { + // If this test requests to run on a completely different + // architecture than the host platform then we skip it entirely, + // since we won't be able to natively execute machine code. + let host_arch = host.triple().architecture; + let requested_arch = requested.triple().architecture; + if host_arch != requested_arch { + return Err(format!( + "skipped {}: host can't run {:?} programs", + context.file_path, requested_arch + )); + } + + // We need to check that the requested ISA does not have any flags that + // we can't natively support on the host. + let requested_flags = requested.isa_flags(); + for req_value in requested_flags { + if let Some(requested) = req_value.as_bool() { + let available_in_host = host + .isa_flags() + .iter() + .find(|val| val.name == req_value.name) + .and_then(|val| val.as_bool()) + .unwrap_or(false); + + if requested && !available_in_host { + return Err(format!( + "skipped {}: host does not support ISA flag {}", + context.file_path, req_value.name + )); + } + } else { + unimplemented!("ISA flag {} of kind {:?}", req_value.name, req_value.kind()); + } + } + + Ok(()) +} + impl SubTest for TestRun { fn name(&self) -> &'static str { "run" @@ -38,18 +101,6 @@ impl SubTest for TestRun { } fn run(&self, func: Cow, context: &Context) -> anyhow::Result<()> { - // If this test requests to run on a completely different - // architecture than the host platform then we skip it entirely, - // since we won't be able to natively execute machine code. - let requested_arch = context.isa.unwrap().triple().architecture; - if requested_arch != Architecture::host() { - println!( - "skipped {}: host can't run {:?} programs", - context.file_path, requested_arch - ); - return Ok(()); - } - // Disable runtests with pinned reg enabled. // We've had some abi issues that the trampoline isn't quite ready for. if context.flags.enable_pinned_reg() { @@ -60,18 +111,26 @@ impl SubTest for TestRun { .join("\n"))); } + let host_isa = build_host_isa(true, context.flags.clone(), vec![]); + let requested_isa = context.isa.unwrap(); + if let Err(e) = is_isa_compatible(context, host_isa.as_ref(), requested_isa) { + println!("{}", e); + return Ok(()); + } + + // 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, context.flags.clone(), requested_isa.isa_flags()); + let test_env = RuntestEnvironment::parse(&context.details.comments[..])?; - let mut compiler = SingleFunctionCompiler::with_host_isa(context.flags.clone())?; + let mut compiler = SingleFunctionCompiler::new(isa); for comment in context.details.comments.iter() { if let Some(command) = parse_run_command(comment.text, &func.signature)? { trace!("Parsed run command: {}", command); - // Note that here we're also explicitly ignoring `context.isa`, - // regardless of what's requested. We want to use the native - // host ISA no matter what here, so the ISA listed in the file - // is only used as a filter to not run into situations like - // running x86_64 code on aarch64 platforms. let compiled_fn = compiler.compile(func.clone().into_owned())?; command .run(|_, run_args| {