Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
39 changes: 32 additions & 7 deletions cranelift/docs/testing.md
Original file line number Diff line number Diff line change
Expand Up @@ -320,13 +320,21 @@ Cranelift IR right before binary machine code emission.

Compile and execute a function.

Add a `; run` directive after each function that should be executed. These
functions must have the signature `() -> bNN` where `bNN` is some sort of
boolean, e.g. `b1` or `b32`. A `true` value is interpreted as a successful
test execution, whereas a `false` value is interpreted as a failed test.
This test command allows several directives:
- to print the result of running a function to stdout, add a `print`
directive and call the preceding function with arguments (see `%foo` in
the example below); remember to enable `--nocapture` if running these
tests through Cargo
- to check the result of a function, add a `run` directive and call the
preceding function with a comparison (`==` or `!=`) (see `%bar` below)
- for backwards compatibility, to check the result of a function with a
`() -> b*` signature, only the `run` directive is required, with no
invocation or comparison (see `%baz` below); a `true` value is
interpreted as a successful test execution, whereas a `false` value is
interpreted as a failed test.

Currently a `target` is required but is only used to indicate whether the host
platform can run the test, and currently only the architecture is filtered. The
platform can run the test and currently only the architecture is filtered. The
host platform's native target will be used to actually compile the test.

Example:
Expand All @@ -335,8 +343,25 @@ Example:
test run
target x86_64

function %trivial_test() -> b1 {
ebb0:
; how to print the results of a function
function %foo() -> i32 {
block0:
v0 = iconst.i32 42
return v0
}
; print: %foo()

; how to check the results of a function
function %bar(i32) -> i32 {
block0(v0:i32):
v1 = iadd_imm v0, 1
return v1
}
; run: %bar(1) == 2

; legacy method of checking the results of a function
function %baz() -> b1 {
block0:
v0 = bconst.b1 true
return v0
}
Expand Down
30 changes: 7 additions & 23 deletions cranelift/filetests/filetests/isa/x86/simd-arithmetic-run.clif
Original file line number Diff line number Diff line change
Expand Up @@ -2,37 +2,21 @@ test run
set enable_simd
target x86_64 skylake

function %iadd_i32x4() -> b1 {
block0:
v0 = vconst.i32x4 [1 1 1 1]
v1 = vconst.i32x4 [1 2 3 4]
function %iadd_i32x4(i32x4, i32x4) -> i32x4 {
block0(v0:i32x4, v1:i32x4):
v2 = iadd v0, v1

v3 = extractlane v2, 0
v4 = icmp_imm eq v3, 2

v5 = extractlane v2, 3
v6 = icmp_imm eq v5, 5
; TODO replace extractlanes with vector comparison

v7 = band v4, v6
return v7
return v2
}
; run
; run: %iadd_i32x4([1 1 1 1], [1 2 3 4]) == [2 3 4 5]

function %iadd_i8x16_with_overflow() -> b1 {
function %iadd_i8x16_with_overflow() -> i8x16 {
block0:
v0 = vconst.i8x16 [255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255]
v1 = vconst.i8x16 [2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2]
v2 = iadd v0, v1

v3 = extractlane v2, 0
v4 = icmp_imm eq v3, 1
; TODO replace extractlane with vector comparison

return v4
return v2
}
; run
; run: %iadd_i8x16_with_overflow() == [1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1]

function %isub_i32x4_rex() -> b1 {
block0:
Expand Down
5 changes: 2 additions & 3 deletions cranelift/filetests/src/function_runner.rs
Original file line number Diff line number Diff line change
Expand Up @@ -189,9 +189,8 @@ impl UnboxedValues {

// Store the argument values into `values_vec`.
for ((arg, slot), param) in arguments.iter().zip(&mut values_vec).zip(&signature.params) {
assert_eq!(
arg.ty(),
param.value_type,
assert!(
arg.ty() == param.value_type || arg.is_vector(),
"argument type mismatch: {} != {}",
arg.ty(),
param.value_type
Expand Down
41 changes: 31 additions & 10 deletions cranelift/reader/src/run_command.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ impl RunCommand {
match self {
RunCommand::Print(invoke) => {
let actual = invoke_fn(&invoke.args);
println!("{:?} -> {:?}", invoke, actual)
println!("{} -> {}", invoke, DisplayDataValues(&actual))
}
RunCommand::Run(invoke, compare, expected) => {
let actual = invoke_fn(&invoke.args);
Expand All @@ -43,7 +43,8 @@ impl RunCommand {
Comparison::NotEquals => *expected != actual,
};
if !matched {
return Err(format!("Failed test: {:?}, actual: {:?}", self, actual));
let actual = DisplayDataValues(&actual);
return Err(format!("Failed test: {}, actual: {}", self, actual));
}
}
}
Expand All @@ -56,14 +57,8 @@ impl Display for RunCommand {
match self {
RunCommand::Print(invocation) => write!(f, "print: {}", invocation),
RunCommand::Run(invocation, comparison, expected) => {
write!(f, "run: {} {} ", invocation, comparison)?;
if expected.len() == 1 {
write!(f, "{}", expected[0])
} else {
write!(f, "[")?;
write_data_value_list(f, expected)?;
write!(f, "]")
}
let expected = DisplayDataValues(expected);
write!(f, "run: {} {} {}", invocation, comparison, expected)
}
}
}
Expand Down Expand Up @@ -125,6 +120,14 @@ impl DataValue {
DataValue::V128(_) => ir::types::I8X16,
}
}

/// Return true if the value is a vector (i.e. `DataValue::V128`).
pub fn is_vector(&self) -> bool {
match self {
DataValue::V128(_) => true,
_ => false,
}
}
}

/// Helper for creating [From] implementations for [DataValue]
Expand Down Expand Up @@ -163,6 +166,24 @@ impl Display for DataValue {
}
}

/// Helper structure for printing bracket-enclosed vectors of [DataValue]s.
/// - for empty vectors, display `[]`
/// - for single item vectors, display `42`, e.g.
/// - for multiple item vectors, display `[42, 43, 44]`, e.g.
struct DisplayDataValues<'a>(&'a [DataValue]);

impl<'a> Display for DisplayDataValues<'a> {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
if self.0.len() == 1 {
write!(f, "{}", self.0[0])
} else {
write!(f, "[")?;
write_data_value_list(f, &self.0)?;
write!(f, "]")
}
}
}

/// Helper function for displaying `Vec<DataValue>`.
fn write_data_value_list(f: &mut Formatter<'_>, list: &[DataValue]) -> fmt::Result {
match list.len() {
Expand Down