Skip to content

Commit 48b0882

Browse files
committed
[WIP] Codegen tests
gherrit-pr-id: G5964d13c9ffb7a47ed4662892ef92c90ddc51e12
1 parent 4fe6388 commit 48b0882

File tree

8 files changed

+288
-3
lines changed

8 files changed

+288
-3
lines changed

.github/workflows/ci.yml

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -379,7 +379,8 @@ jobs:
379379
$FEATURES \
380380
--verbose \
381381
-- \
382-
--skip ui
382+
--skip ui \
383+
--skip codegen
383384
384385
# Only run tests when targetting Linux x86 (32- or 64-bit) - we're
385386
# executing on Linux x86_64, so we can't run tests for any non-x86 target.
@@ -388,6 +389,23 @@ jobs:
388389
# Run compile tests when building for other targets.
389390
if: contains(matrix.target, 'linux') && (contains(matrix.target, 'x86_64') || contains(matrix.target, 'i686'))
390391

392+
- name: Run codegen tests
393+
env:
394+
TOOLCHAIN: ${{ matrix.toolchain }}
395+
CRATE: ${{ matrix.crate }}
396+
TARGET: ${{ matrix.target }}
397+
FEATURES: ${{ matrix.features }}
398+
run: |
399+
sudo apt install llvm > /dev/null
400+
./cargo.sh +nightly install cargo-show-asm > /dev/null
401+
./cargo.sh +$TOOLCHAIN test \
402+
--package $CRATE \
403+
--target $TARGET \
404+
$FEATURES \
405+
--verbose \
406+
--test codegen
407+
if: matrix.crate == 'zerocopy' && matrix.toolchain == 'nightly' && matrix.target == 'x86_64-unknown-linux-gnu' && matrix.features == '--all-features'
408+
391409
- name: Run UI tests
392410
env:
393411
TOOLCHAIN: ${{ matrix.toolchain }}
@@ -631,7 +649,9 @@ jobs:
631649
--lcov \
632650
--output-path lcov.info \
633651
--verbose \
634-
-- --skip ui
652+
-- \
653+
--skip ui \
654+
--skip codegen
635655
- name: Upload coverage to Codecov
636656
uses: codecov/codecov-action@671740ac38dd9b0130fbe1cec585b89eea48d3de # v5.5.2
637657
with:

benches/formats/coco.rs

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
use zerocopy_derive::*;
2+
3+
// The only valid value of this type is the byte `0xC0`
4+
#[derive(TryFromBytes, KnownLayout, Immutable)]
5+
#[repr(u8)]
6+
enum C0 {
7+
_XC0 = 0xC0,
8+
}
9+
10+
// The only valid value of this type is the bytes `0xC0C0`.
11+
#[derive(TryFromBytes, KnownLayout, Immutable)]
12+
#[repr(C)]
13+
struct C0C0(C0, C0);
14+
15+
#[derive(TryFromBytes, KnownLayout, Immutable)]
16+
#[repr(C)]
17+
pub struct Packet {
18+
magic_number: C0C0,
19+
mug_size: u8,
20+
temperature: u8,
21+
marshmallows: [[u8; 2]],
22+
}
Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
Iterations: 100
2+
Instructions: 1900
3+
Total Cycles: 512
4+
Total uOps: 2500
5+
6+
Dispatch Width: 6
7+
uOps Per Cycle: 4.88
8+
IPC: 3.71
9+
Block RThroughput: 4.2
10+
11+
12+
Instruction Info:
13+
[1]: #uOps
14+
[2]: Latency
15+
[3]: RThroughput
16+
[4]: MayLoad
17+
[5]: MayStore
18+
[6]: HasSideEffects (U)
19+
20+
[1] [2] [3] [4] [5] [6] Instructions:
21+
1 1 0.25 mov rdx, rsi
22+
1 1 0.25 cmp rsi, 4
23+
1 1 0.50 jb .LBB5_5
24+
1 1 0.50 lea rcx, [rdx - 4]
25+
1 1 0.25 mov rsi, rcx
26+
1 1 0.25 and rsi, -2
27+
1 1 0.25 add rsi, 4
28+
1 1 0.25 cmp rdx, rsi
29+
1 1 0.50 jne .LBB5_5
30+
1 1 0.25 mov rax, rdi
31+
2 6 0.50 * cmp byte ptr [rdi], -64
32+
1 1 0.50 jne .LBB5_5
33+
2 6 0.50 * cmp byte ptr [rax + 1], -64
34+
1 1 0.50 jne .LBB5_5
35+
1 1 0.50 shr rcx
36+
1 1 0.25 mov rdx, rcx
37+
3 7 1.00 U ret
38+
1 0 0.17 xor eax, eax
39+
3 7 1.00 U ret
40+
41+
42+
Resources:
43+
[0] - ICXDivider
44+
[1] - ICXFPDivider
45+
[2] - ICXPort0
46+
[3] - ICXPort1
47+
[4] - ICXPort2
48+
[5] - ICXPort3
49+
[6] - ICXPort4
50+
[7] - ICXPort5
51+
[8] - ICXPort6
52+
[9] - ICXPort7
53+
[10] - ICXPort8
54+
[11] - ICXPort9
55+
56+
57+
Resource pressure per iteration:
58+
[0] [1] [2] [3] [4] [5] [6] [7] [8] [9] [10] [11]
59+
- - 5.01 4.98 2.00 2.00 - 5.00 5.01 - - -
60+
61+
Resource pressure by instruction:
62+
[0] [1] [2] [3] [4] [5] [6] [7] [8] [9] [10] [11] Instructions:
63+
- - 0.03 0.95 - - - 0.01 0.01 - - - mov rdx, rsi
64+
- - - 0.02 - - - 0.64 0.34 - - - cmp rsi, 4
65+
- - 0.36 - - - - - 0.64 - - - jb .LBB5_5
66+
- - - 0.98 - - - 0.02 - - - - lea rcx, [rdx - 4]
67+
- - - 0.01 - - - 0.98 0.01 - - - mov rsi, rcx
68+
- - - 0.01 - - - 0.98 0.01 - - - and rsi, -2
69+
- - - - - - - 1.00 - - - - add rsi, 4
70+
- - 0.01 - - - - 0.98 0.01 - - - cmp rdx, rsi
71+
- - 1.00 - - - - - - - - - jne .LBB5_5
72+
- - - 0.35 - - - - 0.65 - - - mov rax, rdi
73+
- - 0.32 0.33 0.32 0.68 - 0.02 0.33 - - - cmp byte ptr [rdi], -64
74+
- - 1.00 - - - - - - - - - jne .LBB5_5
75+
- - 0.01 0.66 1.00 - - - 0.33 - - - cmp byte ptr [rax + 1], -64
76+
- - 0.98 - - - - - 0.02 - - - jne .LBB5_5
77+
- - 0.34 - - - - - 0.66 - - - shr rcx
78+
- - - 0.99 - - - 0.01 - - - - mov rdx, rcx
79+
- - 0.33 0.67 0.32 0.68 - - 1.00 - - - ret
80+
- - - - - - - - - - - - xor eax, eax
81+
- - 0.63 0.01 0.36 0.64 - 0.36 1.00 - - - ret

benches/try_ref_from_bytes.rs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
use zerocopy::TryFromBytes;
2+
3+
#[path = "formats/coco.rs"]
4+
mod coco;
5+
6+
#[unsafe(no_mangle)]
7+
fn codegen_test(source: &[u8]) -> Option<&coco::Packet> {
8+
TryFromBytes::try_ref_from_bytes(source).ok()
9+
}
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
Iterations: 100
2+
Instructions: 900
3+
Total Cycles: 214
4+
Total uOps: 1100
5+
6+
Dispatch Width: 6
7+
uOps Per Cycle: 5.14
8+
IPC: 4.21
9+
Block RThroughput: 1.8
10+
11+
12+
Instruction Info:
13+
[1]: #uOps
14+
[2]: Latency
15+
[3]: RThroughput
16+
[4]: MayLoad
17+
[5]: MayStore
18+
[6]: HasSideEffects (U)
19+
20+
[1] [2] [3] [4] [5] [6] Instructions:
21+
1 1 0.25 mov rdx, rsi
22+
1 5 0.50 * movzx ecx, byte ptr [rdi]
23+
1 5 0.50 * movzx esi, byte ptr [rdi + 1]
24+
1 1 0.25 xor cl, -64
25+
1 1 0.25 xor sil, -64
26+
1 0 0.17 xor eax, eax
27+
1 1 0.25 or sil, cl
28+
1 1 0.50 cmove rax, rdi
29+
3 7 1.00 U ret
30+
31+
32+
Resources:
33+
[0] - ICXDivider
34+
[1] - ICXFPDivider
35+
[2] - ICXPort0
36+
[3] - ICXPort1
37+
[4] - ICXPort2
38+
[5] - ICXPort3
39+
[6] - ICXPort4
40+
[7] - ICXPort5
41+
[8] - ICXPort6
42+
[9] - ICXPort7
43+
[10] - ICXPort8
44+
[11] - ICXPort9
45+
46+
47+
Resource pressure per iteration:
48+
[0] [1] [2] [3] [4] [5] [6] [7] [8] [9] [10] [11]
49+
- - 1.75 1.74 1.50 1.50 - 1.75 1.76 - - -
50+
51+
Resource pressure by instruction:
52+
[0] [1] [2] [3] [4] [5] [6] [7] [8] [9] [10] [11] Instructions:
53+
- - - 0.49 - - - 0.27 0.24 - - - mov rdx, rsi
54+
- - - - 0.49 0.51 - - - - - - movzx ecx, byte ptr [rdi]
55+
- - - - 0.74 0.26 - - - - - - movzx esi, byte ptr [rdi + 1]
56+
- - 0.26 0.26 - - - 0.48 - - - - xor cl, -64
57+
- - 0.01 0.49 - - - 0.24 0.26 - - - xor sil, -64
58+
- - - - - - - - - - - - xor eax, eax
59+
- - 0.25 0.24 - - - 0.26 0.25 - - - or sil, cl
60+
- - 0.99 - - - - - 0.01 - - - cmove rax, rdi
61+
- - 0.24 0.26 0.27 0.73 - 0.50 1.00 - - - ret

benches/try_transmute_ref.rs

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
use zerocopy::try_transmute_ref;
2+
use zerocopy_derive::*;
3+
4+
#[path = "formats/coco.rs"]
5+
mod coco;
6+
7+
#[derive(IntoBytes, Unaligned, KnownLayout, Immutable)]
8+
#[repr(C)]
9+
struct MinimalViableSource {
10+
header: [u8; 4],
11+
trailer: [[u8; 2]],
12+
}
13+
14+
#[unsafe(no_mangle)]
15+
fn codegen_test(source: &MinimalViableSource) -> Option<&coco::Packet> {
16+
try_transmute_ref!(source).ok()
17+
}

tests/codegen.rs

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
// Copyright 2026 The Fuchsia Authors
2+
//
3+
// Licensed under a BSD-style license <LICENSE-BSD>, Apache License, Version 2.0
4+
// <LICENSE-APACHE or https://www.apache.org/licenses/LICENSE-2.0>, or the MIT
5+
// license <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your option.
6+
// This file may not be copied, modified, or distributed except according to
7+
// those terms.
8+
9+
#![cfg(__ZEROCOPY_INTERNAL_USE_ONLY_NIGHTLY_FEATURES_IN_TESTS)]
10+
11+
use std::{path::PathBuf, process::Command};
12+
13+
fn run_codegen_test(bench_name: &str, target_cpu: &str, bless: bool) {
14+
let manifest_path = env!("CARGO_MANIFEST_PATH");
15+
let target_dir = env!("CARGO_TARGET_DIR");
16+
17+
let output = Command::new("cargo")
18+
.args([
19+
"asm",
20+
"-p",
21+
"zerocopy",
22+
"--manifest-path",
23+
manifest_path,
24+
"--target-dir",
25+
target_dir,
26+
"--bench",
27+
bench_name,
28+
/*"--target-cpu",
29+
target_cpu,*/
30+
"--mca",
31+
"codegen_test",
32+
])
33+
.output()
34+
.expect("failed to execute process");
35+
36+
let actual_result = output.stdout;
37+
38+
if !(output.status.success()) {
39+
panic!("{}", String::from_utf8_lossy(&output.stderr));
40+
}
41+
42+
let expected_file_path = {
43+
let mut path: PathBuf = env!("CARGO_MANIFEST_DIR").into();
44+
path.push("benches");
45+
let file_name = format!("{bench_name}.{target_cpu}.mca");
46+
path.push(file_name);
47+
path
48+
};
49+
50+
if bless {
51+
std::fs::write(expected_file_path, &actual_result).unwrap();
52+
} else {
53+
let expected_result = std::fs::read(expected_file_path).unwrap_or_default();
54+
if actual_result != expected_result {
55+
let expected = String::from_utf8_lossy(&expected_result[..]);
56+
panic!("Bless codegen tests with BLESS=1\nGot unexpected output:\n{}", expected);
57+
}
58+
}
59+
}
60+
61+
#[test]
62+
#[cfg_attr(miri, ignore)]
63+
fn codegen() {
64+
let bless = std::env::var("BLESS").ok().filter(|s| s == "1").is_some();
65+
let paths = std::fs::read_dir("benches").unwrap();
66+
for path in paths {
67+
let path = path.unwrap().path();
68+
if !path.extension().map(|s| s == "rs").unwrap_or(false) {
69+
continue;
70+
}
71+
let path = path.file_stem().unwrap().to_str().unwrap();
72+
run_codegen_test(path, "icelake-server", bless);
73+
}
74+
}

tools/update-expected-test-output.sh

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,8 @@
1010

1111
set -eo pipefail
1212

13-
# Update the `.stderr` reference files used to validate our UI tests.
13+
# Update the `.stderr` reference files used to validate our UI and codegen tests.
14+
BLESS=1 ./cargo.sh +nightly test --test codegen -p zerocopy --all-features
1415
BLESS=1 ./cargo.sh +nightly test --test ui -p zerocopy --all-features
1516
BLESS=1 ./cargo.sh +stable test --test ui -p zerocopy --features=__internal_use_only_features_that_work_on_stable
1617
BLESS=1 ./cargo.sh +msrv test --test ui -p zerocopy --features=__internal_use_only_features_that_work_on_stable

0 commit comments

Comments
 (0)