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: 37 additions & 2 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ exclude = [
"sdk/.cargo",
"tests/",
"examples",
"tools/fuzza-agent",
]

[workspace.package]
Expand Down
94 changes: 94 additions & 0 deletions Makefile.toml
Original file line number Diff line number Diff line change
Expand Up @@ -541,3 +541,97 @@ args = [
"publish",
"--dry-run",
]

[tasks.install-cargo-llvm-cov]
private = true
install_crate = { crate_name = "cargo-llvm-cov", binary = "cargo", test_arg = [
"llvm-cov",
"--version",
] }

[tasks.install-rustfilt]
private = true
install_crate = { crate_name = "rustfilt", binary = "rustfilt", test_arg = "--version" }

[tasks.fuzza-cov]
category = "Test"
description = "Run the differential tests under cargo-llvm-cov (clean slate) and emit a fuzza-oriented Markdown coverage report"
dependencies = ["install-cargo-llvm-cov", "install-rustfilt"]
script = ['''
#!/usr/bin/env bash
set -euo pipefail
WORKSPACE="${CARGO_MAKE_WORKSPACE_WORKING_DIRECTORY}"
OUT="${WORKSPACE}/target/fuzza-coverage"
mkdir -p "${OUT}"

cargo llvm-cov clean --workspace
if [[ -f "${OUT}/report.json" ]]; then
mv "${OUT}/report.json" "${OUT}/report.prev.json"
fi

cargo llvm-cov --package midenc-integration-tests --no-report -- differential --test-threads=1
cargo llvm-cov report --json --output-path "${OUT}/report.json"
cargo llvm-cov report --html --output-dir "${OUT}/html"

python3 "${WORKSPACE}/tools/fuzza-agent/cov.py" \
"${OUT}/report.json" "${WORKSPACE}" \
--prev "${OUT}/report.prev.json" \
> "${OUT}/report.md"

echo ""
echo "Coverage report written to:"
echo " ${OUT}/report.md (agent-consumable summary, includes delta if a prev snapshot existed)"
echo " ${OUT}/html/ (human-readable browser view)"
echo " ${OUT}/report.json (raw llvm-cov JSON)"
''']

[tasks.fuzza-cov-step]
category = "Test"
description = "Incremental fuzza coverage run — reuses previous profile data and reports the delta against the last report"
dependencies = ["install-cargo-llvm-cov", "install-rustfilt"]
script = ['''
#!/usr/bin/env bash
set -euo pipefail
WORKSPACE="${CARGO_MAKE_WORKSPACE_WORKING_DIRECTORY}"
OUT="${WORKSPACE}/target/fuzza-coverage"

if [[ ! -f "${OUT}/report.json" ]]; then
echo "no baseline report at ${OUT}/report.json — run \`cargo make fuzza-cov\` first" >&2
exit 1
fi

mv "${OUT}/report.json" "${OUT}/report.prev.json"

# `cargo llvm-cov` rejects `--no-report` together with `--no-clean`; we need
# `--no-clean` to preserve accumulated profile data across iterations, so we
# let it emit its default stdout report and then regenerate JSON/HTML from
# the merged profdata in the steps below. Tolerate test failures — a failed
# case still contributes coverage and the agent needs the delta even then.
test_status=0
cargo llvm-cov --no-clean --package midenc-integration-tests -- differential --test-threads=1 || test_status=$?
cargo llvm-cov report --json --output-path "${OUT}/report.json"
cargo llvm-cov report --html --output-dir "${OUT}/html"

python3 "${WORKSPACE}/tools/fuzza-agent/cov.py" \
"${OUT}/report.json" "${WORKSPACE}" \
--prev "${OUT}/report.prev.json" \
> "${OUT}/report.md"

echo ""
if [[ "${test_status}" -ne 0 ]]; then
echo "NOTE: one or more differential tests failed; report reflects coverage up to the failures." >&2
fi
echo "Incremental coverage report with delta written to ${OUT}/report.md"
''']

[tasks.fuzza-cov-clean]
category = "Test"
description = "Clear accumulated fuzza coverage profile data and snapshot"
dependencies = ["install-cargo-llvm-cov"]
script = ['''
#!/usr/bin/env bash
set -euo pipefail
WORKSPACE="${CARGO_MAKE_WORKSPACE_WORKING_DIRECTORY}"
cargo llvm-cov clean --workspace
rm -rf "${WORKSPACE}/target/fuzza-coverage"
''']
2 changes: 2 additions & 0 deletions tests/integration/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -41,4 +41,6 @@ sha2 = "0.11"
[dev-dependencies]
# NOTE: Use local paths for dev-only dependency to avoid relying on crates.io during packaging
blake3 = "1.5"
cargo_metadata = "0.19"
concat-idents = "1.1"
libloading = "0.8"
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
#[unsafe(no_mangle)]
pub extern "C" fn entrypoint(input1: u32, input2: u32) -> u32 {
input1.wrapping_add(input2)
}
36 changes: 36 additions & 0 deletions tests/integration/src/end_to_end/differential/cases/case_bitops.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
// Exercises u32 bitwise / shift / rotate / comparison HIR ops that lower to
// the per-type arms in `codegen/masm/src/emit/binary.rs` —
// `OpEmitter::{bor, shl, shr, rotl, rotr, eq, neq, lt, gt, lte, gte}`.
//
// All comparisons use the two runtime `u32` inputs (no immediates) so the
// non-`_imm` emitter variants are taken. The shift counts are masked to
// avoid panicking shifts on `u32`.
#[unsafe(no_mangle)]
pub extern "C" fn entrypoint(input1: u32, input2: u32) -> u32 {
// Mask shift/rotate amounts so native shifts do not panic on values >= 32.
let amt: u32 = input2 & 31;

// Bitwise OR + shifts.
let mixed: u32 = (input1 | input2).wrapping_add(input1 << amt).wrapping_add(input1 >> amt);

// Rotates (no panic risk for any u32).
let rot: u32 = input1.rotate_left(amt).wrapping_add(input1.rotate_right(amt));

// Six comparisons — each takes two runtime u32s, so the emitter's
// non-immediate `eq/neq/lt/lte/gt/gte` arms are exercised.
let eq = (input1 == input2) as u32;
let ne = (input1 != input2) as u32;
let lt = (input1 < input2) as u32;
let le = (input1 <= input2) as u32;
let gt = (input1 > input2) as u32;
let ge = (input1 >= input2) as u32;

mixed
.wrapping_add(rot)
.wrapping_add(eq)
.wrapping_add(ne)
.wrapping_add(lt)
.wrapping_add(le)
.wrapping_add(gt)
.wrapping_add(ge)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
// Small branchy case — exercises comparisons, if/else, and u32 div/rem
// paths in the compiler pipeline.
#[unsafe(no_mangle)]
pub extern "C" fn entrypoint(input1: u32, input2: u32) -> u32 {
if input2 == 0 {
return input1.wrapping_mul(3).wrapping_add(1);
}
let q = input1 / input2;
let r = input1 % input2;
if q > r { q.wrapping_sub(r) } else { r.wrapping_sub(q) }
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
// Dense integer match intended to lower through wasm `br_table`.
#[unsafe(no_mangle)]
pub extern "C" fn entrypoint(input1: u32, input2: u32) -> u32 {
match input1 & 7 {
0 => arm0(input1, input2),
1 => arm1(input1, input2),
2 => arm2(input1, input2),
3 => arm3(input1, input2),
4 => arm4(input1, input2),
5 => arm5(input1, input2),
6 => arm6(input1, input2),
_ => arm7(input1, input2),
}
}

#[inline(never)]
fn arm0(a: u32, b: u32) -> u32 {
a.wrapping_add(b ^ 0x1357_2468)
}

#[inline(never)]
fn arm1(a: u32, b: u32) -> u32 {
b.wrapping_sub(a ^ 0x2468_1357)
}

#[inline(never)]
fn arm2(a: u32, b: u32) -> u32 {
a.wrapping_add(17).wrapping_sub(b & 0x00ff_00ff)
}

#[inline(never)]
fn arm3(a: u32, b: u32) -> u32 {
(a | 0x0f0f_0f0f).wrapping_add(b ^ 31)
}

#[inline(never)]
fn arm4(a: u32, b: u32) -> u32 {
(b | 0xf0f0_f0f0).wrapping_sub(a ^ 47)
}

#[inline(never)]
fn arm5(a: u32, b: u32) -> u32 {
(a & b).wrapping_add(0x55aa_aa55)
}

#[inline(never)]
fn arm6(a: u32, b: u32) -> u32 {
(a ^ b).wrapping_sub(0xaa55_55aa)
}

#[inline(never)]
fn arm7(a: u32, b: u32) -> u32 {
a.wrapping_sub(b).wrapping_add(0x1020_3040)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
#[unsafe(no_mangle)]
pub extern "C" fn entrypoint(input1: u32, input2: u32) -> u32 {
input1
.wrapping_mul(input2)
.wrapping_add(input1)
.wrapping_add(input2)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
// Nested labelled loops with local and non-local exits.
#[unsafe(no_mangle)]
pub extern "C" fn entrypoint(input1: u32, input2: u32) -> u32 {
let outer_limit = (input1 & 3).wrapping_add(2);
let inner_limit = (input2 & 3).wrapping_add(1);
let mut outer = 0;
let mut acc = input1.wrapping_add(input2 ^ 0x3141_5926);

let result = 'outer: loop {
if outer >= outer_limit {
break acc ^ outer;
}

let mut inner = 0;
loop {
if inner >= inner_limit {
break;
}

let mix = acc ^ inner ^ outer;
if (mix & 7) == 3 {
break 'outer acc.wrapping_add(inner).wrapping_add(outer);
}

if (mix & 1) == 0 {
acc = acc.wrapping_add(input1 ^ inner);
} else {
acc = acc.wrapping_sub(input2 ^ outer);
}

inner = inner.wrapping_add(1);
}

outer = outer.wrapping_add(1);
acc = acc.wrapping_add(outer ^ inner_limit);
};

result.wrapping_add(acc & 0x0000_ffff)
}
Loading
Loading