One squashed history of three stacked PRs, onto main atb16816671: - #426 (wai/pack-efficiency): a title's whole AV1 ladder in one package over one integer base; several floor rungs (packaging §7.1), a re-pack from a parent (§11.5), a floor that is the ladder's own CMAF (§7.7), a floor-only profile (§7.8), a streaming pack (§11.4), and the independent verifier at scale (§9.4). - #438 (wai/cross-fabric): each pack and verify step on the fabric with the least measured energy (§11.6); the `fabrics` member of measurement claims (jwp-receipts §2.4.8, energy-measurement §6.3); the wai-pack-gpu crate; `wai-pack fabric`; `wai-pack floor-decode`. - #452 (wai/gpu-int-tier), its GPU-tier part only: claiming decode-equivalence on a GPU (determinism-tiers §5), the WGSL integer semantics suite, the rules check on naga's IR, and the kernels' shift masks and min(max()) clamps. Left out, by the review's split (EN-C takes it over): #452's platform decode in dispatch, its commits6ad92e2e8,8695bc75fandfed8694f4and its CHANGELOG entry: extensions/platform-decode.md, platform-decode-conformance/, wai::platform_decode, wai-web's platform_decode bundle and demo, and its two SPEC.md sentences. #438's research note is not carried as written: it is rewritten as wai/research/cross-fabric.md, with hardware named by architecture, PCI id and OS version, and every table marked as one run. floor_decode.rs and a wai_pack.rs comment name the platform's media engine and a full-length film the same way. wai/CHANGELOG.md is the union of both sides' entries, the stack's first. Co-Authored-By: Claude Opus 5.5 <[email protected]>
113 lines
5.4 KiB
Rust
113 lines
5.4 KiB
Rust
//! WGSL's integer semantics on every adapter (`src/semantics.rs`): the committed vectors
|
|
//! of `wai/wgsl-conformance/` are the WGSL text's results, and every adapter found gives
|
|
//! them, with SplitMix64 cases of every operation besides. A case the translators do not
|
|
//! guard (`semantics::UNGUARDED`) is run and reported, and does not fail the adapter: no
|
|
//! kernel depends on one (`tests/wgsl_rules.rs`). Then an edited kernel is shown to be
|
|
//! caught: discovery refuses every adapter.
|
|
//!
|
|
//! Each adapter's result is one line, `ops-gpu semantics: key=…`, appended to
|
|
//! `WAI_OPS_GPU_REPORT` when it is set. No adapter is not a pass: the test prints
|
|
//! SKIPPED, and fails under `WAI_OPS_GPU_REQUIRE`.
|
|
|
|
use std::io::Write;
|
|
use std::path::PathBuf;
|
|
|
|
use wai_ops_gpu::semantics::{self, Case};
|
|
use wai_ops_gpu::{blocking, kernels::Sources};
|
|
|
|
fn report(line: &str) {
|
|
println!("{line}");
|
|
if let Ok(p) = std::env::var("WAI_OPS_GPU_REPORT") {
|
|
let mut f = std::fs::OpenOptions::new().create(true).append(true).open(&p).unwrap_or_else(|e| panic!("{p}: {e}"));
|
|
writeln!(f, "{line}").unwrap();
|
|
}
|
|
}
|
|
|
|
fn committed() -> (PathBuf, String) {
|
|
let p = PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("../wgsl-conformance/integer.jsonl");
|
|
let text = std::fs::read_to_string(&p).unwrap_or_else(|e| panic!("{}: {e}", p.display()));
|
|
(p, text)
|
|
}
|
|
|
|
/// The committed file is what `wai-wgsl-vectors` writes, byte for byte, and each of its
|
|
/// results is the reference's.
|
|
#[test]
|
|
fn the_committed_vectors_are_the_wgsl_texts_results() {
|
|
let (p, text) = committed();
|
|
let want = semantics::vector_file(&semantics::edge_cases());
|
|
assert!(text == want, "{} is not what `cargo run --bin wai-wgsl-vectors -- {}` writes", p.display(), p.display());
|
|
let cases = semantics::parse_vector_file(&text).unwrap();
|
|
assert_eq!(cases.len(), semantics::edge_cases().len());
|
|
for (c, r) in &cases {
|
|
assert_eq!(*r, semantics::reference(c), "{c:?}");
|
|
}
|
|
let unguarded = cases.iter().filter(|(c, _)| !c.guarded()).count();
|
|
assert!(unguarded > 0 && unguarded < cases.len() / 4, "{unguarded} unguarded cases");
|
|
}
|
|
|
|
#[test]
|
|
fn every_adapter_gives_wgsls_integer_semantics() {
|
|
let d = blocking::discover();
|
|
for (a, why) in &d.refused {
|
|
report(&format!("ops-gpu semantics adapter refused: key={} {} reason={why:?}", a.key(), a.describe()));
|
|
}
|
|
if d.found.is_empty() {
|
|
report("ops-gpu semantics: SKIPPED: no adapter");
|
|
assert!(std::env::var_os("WAI_OPS_GPU_REQUIRE").is_none(), "WAI_OPS_GPU_REQUIRE is set and no adapter was found");
|
|
return;
|
|
}
|
|
let (_, text) = committed();
|
|
let mut cases: Vec<Case> = semantics::parse_vector_file(&text).unwrap().into_iter().map(|(c, _)| c).collect();
|
|
let n_committed = cases.len();
|
|
cases.extend(semantics::random_cases(4096, 0xA417_5E00));
|
|
let expect: Vec<u32> = cases.iter().map(semantics::reference).collect();
|
|
for g in &d.found {
|
|
let got = blocking::semantics(g, &cases).unwrap_or_else(|e| panic!("{}: {e}", g.adapter().key()));
|
|
let o = semantics::compare(&cases, &expect, &got);
|
|
for d in o.guarded_differ.iter().take(20) {
|
|
println!("MISMATCH {}: {d}", g.adapter().key());
|
|
}
|
|
let mut shown = std::collections::BTreeSet::new();
|
|
for d in &o.unguarded_differ {
|
|
if shown.insert(d.case.op) {
|
|
println!("ops-gpu semantics unguarded: key={} {d}", g.adapter().key());
|
|
}
|
|
}
|
|
report(&format!(
|
|
"ops-gpu semantics: key={} {} committed={n_committed} cases={} guarded={} differ={} unguarded={} unguarded_differ={} unguarded_ops={}",
|
|
g.adapter().key(),
|
|
g.adapter().describe(),
|
|
cases.len(),
|
|
o.guarded,
|
|
o.guarded_differ.len(),
|
|
o.unguarded,
|
|
o.unguarded_differ.len(),
|
|
if o.unguarded_ops().is_empty() { "none".to_string() } else { o.unguarded_ops().join(",") },
|
|
));
|
|
assert!(o.guarded_differ.is_empty(), "{}: {} guarded cases differ from WGSL, the first: {}", g.adapter().key(), o.guarded_differ.len(), o.guarded_differ[0]);
|
|
}
|
|
}
|
|
|
|
/// A remainder written out by hand, `a - (a / b) * b`, gives `a` where WGSL gives 0 (a
|
|
/// zero divisor): an adapter running that kernel must be refused at discovery, for the
|
|
/// semantics suite, on every adapter.
|
|
#[test]
|
|
fn an_edited_semantics_kernel_is_caught() {
|
|
let d = blocking::discover();
|
|
if d.found.is_empty() {
|
|
println!("ops-gpu semantics mutant: SKIPPED: no adapter");
|
|
assert!(std::env::var_os("WAI_OPS_GPU_REQUIRE").is_none(), "WAI_OPS_GPU_REQUIRE is set and no adapter was found");
|
|
return;
|
|
}
|
|
let mut src = Sources::shipped();
|
|
let from = "case 10u: { r = bitcast<u32>(ia % ib); }";
|
|
assert!(src.semantics.contains(from));
|
|
src.semantics = src.semantics.replace(from, "case 10u: { r = bitcast<u32>(ia - (ia / ib) * ib); }");
|
|
let m = blocking::discover_with(&src, "mutant: a remainder by hand");
|
|
assert!(m.found.is_empty(), "an adapter passed the semantics suite with a remainder written by hand");
|
|
for (a, why) in &m.refused {
|
|
assert!(why.contains("WGSL semantics suite") && why.contains("rem_i32"), "{}: refused for another reason: {why}", a.key());
|
|
report(&format!("ops-gpu semantics mutant: key={} refused: {why}", a.key()));
|
|
}
|
|
assert_eq!(m.refused.len(), d.found.len() + d.refused.len());
|
|
}
|