Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Verify code generation of the AVX-512 rotates #74

Merged
merged 5 commits into from
Aug 12, 2018
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
13 changes: 9 additions & 4 deletions ci/run.sh
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,10 @@ if [[ ${TARGET} == "x86_64-apple-ios" ]] || [[ ${TARGET} == "i386-apple-ios" ]];
export CARGO_TARGET_I386_APPLE_IOS_RUNNER=$HOME/runtest
fi

# The source directory is read-only. Need to copy internal crates to the target
# directory for their Cargo.lock to be properly written.
mkdir target || true

rustc --version
cargo --version
echo "TARGET=${TARGET}"
Expand Down Expand Up @@ -61,10 +65,11 @@ cargo_test_impl() {
cargo_test_impl
cargo_test_impl --release --features=into_bits,coresimd

# Examples - the source directory is read-only.
# Need to copy them to the target directory for the Cargo.lock to be
# properly written.
mkdir target || true
# Verify code generation
if [[ "${NOVERIFY}" != "1" ]]; then
cp -r verify/verify target/verify
cargo_test --release --manifest-path=target/verify/Cargo.toml
fi

# FIXME: https://github.com/rust-lang-nursery/packed_simd/issues/55
# All examples fail to build for `armv7-apple-ios`.
Expand Down
8 changes: 8 additions & 0 deletions readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,14 @@ there are correctness bugs open in the issue tracker.
[**] it is currently not easily possible to run these platforms on CI.


# Machine code verification

The
[`verify/`](https://github.com/rust-lang-nursery/packed_simd/tree/master/verify)
crate tests disassembles the portable packed vector APIs at run-time and
compares the generated machine code against the desired one to make sure that
this crate remains efficient.

# License

This project is licensed under either of
Expand Down
8 changes: 8 additions & 0 deletions verify/verify/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
[package]
name = "verify"
version = "0.1.0"
authors = ["gnzlbg <gonzalobg88@gmail.com>"]

[dev-dependencies]
stdsimd-test = { git = "https://github.com/rust-lang-nursery/stdsimd.git" }
packed_simd = { path = "../.." }
53 changes: 53 additions & 0 deletions verify/verify/readme.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
# Machine code verification

## Quick start

To run the verification tests run:

```
cargo test --release
```

on this crate, eventually passing the required target features via `RUSTFLAGS`.
For example, `RUSTFLAGS="-C target-feature=+avx2"`.

This crate only contains tests, and the tests only run in `--release` mode.
Therefore, building this crate with anything different from `cargo test
--release` does not make much sense.

## How it works

This crates verifies the machine code generated for some of the portable packed
vector APIs by disassembling the API at run-time and comparing the machine code
generated against the desired one for a particular target and target features.

This is done by using the
[`stdsimd-test`](https://github.com/rust-lang-nursery/stdsimd/tree/master/crates/stdsimd-test)
crate, which exposes the `assert_instr` procedural macro. It is used like this:

```rust
// The verification functions must be #[inline]:
#[inline]
// Enable the target features required for the desired code generation
// on the different targets:
#[cfg_attr(
any(target_arch = "x86", target_arch = "x86_64"),
target_feature(enable = "avx512f,avx512vl")
)]
// Check that the disassembly contains a particular instruction:
#[cfg_attr(
any(target_arch = "x86", target_arch = "x86_64"),
assert_instr(vpro)
)]
unsafe fn rotate_right_variable(x: u64x8, v: u64x8) -> u64x8 {
x.rotate_right(v)
}
```

The `assert_instr` procedural macro creates a test that contains a
`#[inline(never)]` function that calls the API. It then gets a function pointer
to this function, and calls `stdsimd_test::assert` with it, the function name,
and the expected assembly instruction. `stdsimd_test` uses `objdump` or similar
to disassemble itself, it then looks for the function address and name in the
disassembly, and verifies that the machine code for the function contains the
instruction.
1 change: 1 addition & 0 deletions verify/verify/src/api.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
mod ops;
1 change: 1 addition & 0 deletions verify/verify/src/api/ops.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
mod vector_rotates;
70 changes: 70 additions & 0 deletions verify/verify/src/api/ops/vector_rotates.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
mod u64x8 {
use packed_simd::*;
use stdsimd_test::assert_instr;

#[inline]
#[cfg_attr(
any(target_arch = "x86", target_arch = "x86_64"),
target_feature(enable = "avx512f,avx512vl")
)]
#[cfg_attr(
any(target_arch = "x86", target_arch = "x86_64"),
assert_instr(vpro)
)]
unsafe fn rotate_right_variable(x: u64x8, v: u64x8) -> u64x8 {
x.rotate_right(v)
}

#[inline]
#[cfg_attr(
any(target_arch = "x86", target_arch = "x86_64"),
target_feature(enable = "avx512f,avx512vl")
)]
#[cfg_attr(
any(target_arch = "x86", target_arch = "x86_64"),
assert_instr(vpro)
)]
unsafe fn rotate_left_variable(x: u64x8, v: u64x8) -> u64x8 {
x.rotate_left(v)
}

#[inline]
#[cfg_attr(
any(target_arch = "x86", target_arch = "x86_64"),
target_feature(enable = "avx512f")
)]
#[cfg_attr(
any(target_arch = "x86", target_arch = "x86_64"),
assert_instr(vpro)
)]
unsafe fn rotate_right(x: u64x8) -> u64x8 {
x.rotate_right(u64x8::splat(12))
}

#[inline]
#[cfg_attr(
any(target_arch = "x86", target_arch = "x86_64"),
target_feature(enable = "avx512f")
)]
#[cfg_attr(
any(target_arch = "x86", target_arch = "x86_64"),
assert_instr(vpro)
)]
unsafe fn rotate_left(x: u64x8) -> u64x8 {
x.rotate_left(u64x8::splat(12))
}

#[inline]
#[cfg_attr(
any(target_arch = "x86", target_arch = "x86_64"),
target_feature(enable = "avx512f")
)]
#[cfg_attr(
any(target_arch = "x86", target_arch = "x86_64"),
assert_instr(vpro)
)]
unsafe fn rotate_left_x2(x: u64x2) -> u64x2 {
x.rotate_left(u64x2::splat(12))
}

}
10 changes: 10 additions & 0 deletions verify/verify/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
#![feature(rust_2018_preview, use_extern_macros, avx512_target_feature)]

#[cfg(test)]
extern crate packed_simd;

#[cfg(test)]
extern crate stdsimd_test;

#[cfg(test)]
mod api;