Improve documentation of the filetest run command (#1645)
* Improve output display of RunCommand The previous use of Debug for displaying `print` and `run` results was less than clear. * Avoid checking the types of vectors during trampoline construction Because DataValue only understands `V128` vectors, we avoid type-checking vector values when constructing the trampoline arguments. * Improve the documentation of the filetest `run` command Adds an up-to-date example of how to use the `run` and `print` directives and includes an actual use of the new directives in a SIMD arithmetic filetest.
This commit is contained in:
@@ -320,13 +320,21 @@ Cranelift IR right before binary machine code emission.
|
|||||||
|
|
||||||
Compile and execute a function.
|
Compile and execute a function.
|
||||||
|
|
||||||
Add a `; run` directive after each function that should be executed. These
|
This test command allows several directives:
|
||||||
functions must have the signature `() -> bNN` where `bNN` is some sort of
|
- to print the result of running a function to stdout, add a `print`
|
||||||
boolean, e.g. `b1` or `b32`. A `true` value is interpreted as a successful
|
directive and call the preceding function with arguments (see `%foo` in
|
||||||
test execution, whereas a `false` value is interpreted as a failed test.
|
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
|
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.
|
host platform's native target will be used to actually compile the test.
|
||||||
|
|
||||||
Example:
|
Example:
|
||||||
@@ -335,8 +343,25 @@ Example:
|
|||||||
test run
|
test run
|
||||||
target x86_64
|
target x86_64
|
||||||
|
|
||||||
function %trivial_test() -> b1 {
|
; how to print the results of a function
|
||||||
ebb0:
|
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
|
v0 = bconst.b1 true
|
||||||
return v0
|
return v0
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,37 +2,21 @@ test run
|
|||||||
set enable_simd
|
set enable_simd
|
||||||
target x86_64 skylake
|
target x86_64 skylake
|
||||||
|
|
||||||
function %iadd_i32x4() -> b1 {
|
function %iadd_i32x4(i32x4, i32x4) -> i32x4 {
|
||||||
block0:
|
block0(v0:i32x4, v1:i32x4):
|
||||||
v0 = vconst.i32x4 [1 1 1 1]
|
|
||||||
v1 = vconst.i32x4 [1 2 3 4]
|
|
||||||
v2 = iadd v0, v1
|
v2 = iadd v0, v1
|
||||||
|
return v2
|
||||||
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
|
|
||||||
}
|
}
|
||||||
; 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:
|
block0:
|
||||||
v0 = vconst.i8x16 [255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255]
|
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]
|
v1 = vconst.i8x16 [2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2]
|
||||||
v2 = iadd v0, v1
|
v2 = iadd v0, v1
|
||||||
|
return v2
|
||||||
v3 = extractlane v2, 0
|
|
||||||
v4 = icmp_imm eq v3, 1
|
|
||||||
; TODO replace extractlane with vector comparison
|
|
||||||
|
|
||||||
return v4
|
|
||||||
}
|
}
|
||||||
; 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 {
|
function %isub_i32x4_rex() -> b1 {
|
||||||
block0:
|
block0:
|
||||||
|
|||||||
@@ -189,9 +189,8 @@ impl UnboxedValues {
|
|||||||
|
|
||||||
// Store the argument values into `values_vec`.
|
// Store the argument values into `values_vec`.
|
||||||
for ((arg, slot), param) in arguments.iter().zip(&mut values_vec).zip(&signature.params) {
|
for ((arg, slot), param) in arguments.iter().zip(&mut values_vec).zip(&signature.params) {
|
||||||
assert_eq!(
|
assert!(
|
||||||
arg.ty(),
|
arg.ty() == param.value_type || arg.is_vector(),
|
||||||
param.value_type,
|
|
||||||
"argument type mismatch: {} != {}",
|
"argument type mismatch: {} != {}",
|
||||||
arg.ty(),
|
arg.ty(),
|
||||||
param.value_type
|
param.value_type
|
||||||
|
|||||||
@@ -34,7 +34,7 @@ impl RunCommand {
|
|||||||
match self {
|
match self {
|
||||||
RunCommand::Print(invoke) => {
|
RunCommand::Print(invoke) => {
|
||||||
let actual = invoke_fn(&invoke.args);
|
let actual = invoke_fn(&invoke.args);
|
||||||
println!("{:?} -> {:?}", invoke, actual)
|
println!("{} -> {}", invoke, DisplayDataValues(&actual))
|
||||||
}
|
}
|
||||||
RunCommand::Run(invoke, compare, expected) => {
|
RunCommand::Run(invoke, compare, expected) => {
|
||||||
let actual = invoke_fn(&invoke.args);
|
let actual = invoke_fn(&invoke.args);
|
||||||
@@ -43,7 +43,8 @@ impl RunCommand {
|
|||||||
Comparison::NotEquals => *expected != actual,
|
Comparison::NotEquals => *expected != actual,
|
||||||
};
|
};
|
||||||
if !matched {
|
if !matched {
|
||||||
return Err(format!("Failed test: {:?}, actual: {:?}", self, actual));
|
let actual = DisplayDataValues(&actual);
|
||||||
|
return Err(format!("Failed test: {}, actual: {}", self, actual));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -56,14 +57,8 @@ impl Display for RunCommand {
|
|||||||
match self {
|
match self {
|
||||||
RunCommand::Print(invocation) => write!(f, "print: {}", invocation),
|
RunCommand::Print(invocation) => write!(f, "print: {}", invocation),
|
||||||
RunCommand::Run(invocation, comparison, expected) => {
|
RunCommand::Run(invocation, comparison, expected) => {
|
||||||
write!(f, "run: {} {} ", invocation, comparison)?;
|
let expected = DisplayDataValues(expected);
|
||||||
if expected.len() == 1 {
|
write!(f, "run: {} {} {}", invocation, comparison, expected)
|
||||||
write!(f, "{}", expected[0])
|
|
||||||
} else {
|
|
||||||
write!(f, "[")?;
|
|
||||||
write_data_value_list(f, expected)?;
|
|
||||||
write!(f, "]")
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -125,6 +120,14 @@ impl DataValue {
|
|||||||
DataValue::V128(_) => ir::types::I8X16,
|
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]
|
/// Helper for creating [From] implementations for [DataValue]
|
||||||
@@ -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>`.
|
/// Helper function for displaying `Vec<DataValue>`.
|
||||||
fn write_data_value_list(f: &mut Formatter<'_>, list: &[DataValue]) -> fmt::Result {
|
fn write_data_value_list(f: &mut Formatter<'_>, list: &[DataValue]) -> fmt::Result {
|
||||||
match list.len() {
|
match list.len() {
|
||||||
|
|||||||
Reference in New Issue
Block a user