Skip to content

Commit 88d8e61

Browse files
committed
fix: liveness bug
1 parent ff6b821 commit 88d8e61

2 files changed

Lines changed: 115 additions & 0 deletions

File tree

core-rs/epass-ir/src/cg/liveness.rs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,12 @@ pub fn analyze(env: &mut Env, func: &mut Function, cg: &mut CgState) -> Result<(
6767
let users = func.insn(v).users.clone();
6868
let mut visited: HashSet<BbId> = HashSet::new();
6969
for s in users {
70+
if !cg.extra.contains_key(&s) {
71+
// Def-use chains can still contain users in unreachable blocks.
72+
// CG metadata is allocated only for reachable instructions, so
73+
// these uses are irrelevant to register allocation.
74+
continue;
75+
}
7076
if matches!(func.insn(s).kind, InsnKind::Phi) {
7177
// For a phi user, liveness propagates from the predecessor block
7278
// corresponding to each operand equal to `v`.
@@ -112,6 +118,9 @@ fn live_out_at_statement(
112118
s: InsnId,
113119
v: InsnId,
114120
) {
121+
if !cg.extra.contains_key(&s) {
122+
return;
123+
}
115124
push_unique(&mut cg.extra_mut(s).live_out, v);
116125
let dst = cg.extra(s).dst;
117126
match dst {
@@ -137,6 +146,9 @@ fn live_in_at_statement(
137146
s: InsnId,
138147
v: InsnId,
139148
) {
149+
if !cg.extra.contains_key(&s) {
150+
return;
151+
}
140152
push_unique(&mut cg.extra_mut(s).live_in, v);
141153
match func.prev_insn(s) {
142154
None => {

core-rs/epasstool/tests/falco.rs

Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,103 @@
1+
use std::collections::HashSet;
2+
use std::path::PathBuf;
3+
use std::process::Command;
4+
5+
const KNOWN_FALCO_FAILURES: &[&str] = &[
6+
// libbpf poison/dummy path leaves a dead def in these large programs
7+
"prog195.txt",
8+
"prog198.txt",
9+
// RA post-spill fallback currently hits convergence cap / repeated pre-spills
10+
"prog280.txt",
11+
"prog286.txt",
12+
];
13+
14+
fn have_timeout() -> bool {
15+
Command::new("sh")
16+
.arg("-c")
17+
.arg("command -v timeout >/dev/null 2>&1")
18+
.status()
19+
.map(|s| s.success())
20+
.unwrap_or(false)
21+
}
22+
23+
#[test]
24+
fn falco_dump_corpus_rewrites_except_known_failures() {
25+
let manifest = PathBuf::from(env!("CARGO_MANIFEST_DIR"));
26+
let falco = manifest.parent().unwrap().join("bpftests/falco");
27+
if !falco.exists() {
28+
eprintln!("skipping falco tests: {} does not exist", falco.display());
29+
return;
30+
}
31+
32+
let mut files: Vec<_> = std::fs::read_dir(&falco)
33+
.expect("read falco dir")
34+
.filter_map(|e| e.ok().map(|e| e.path()))
35+
.filter(|p| p.extension().and_then(|s| s.to_str()) == Some("txt"))
36+
.collect();
37+
files.sort();
38+
39+
if files.is_empty() {
40+
eprintln!("skipping falco tests: no .txt programs in {}", falco.display());
41+
return;
42+
}
43+
44+
let known: HashSet<&str> = KNOWN_FALCO_FAILURES.iter().copied().collect();
45+
let epasstool = env!("CARGO_BIN_EXE_epasstool");
46+
let out = std::env::temp_dir().join(format!("epass-falco-{}.dump", std::process::id()));
47+
let use_timeout = have_timeout();
48+
49+
let mut passed = 0usize;
50+
let mut known_failed = 0usize;
51+
let mut unexpected = Vec::new();
52+
53+
for file in files {
54+
let name = file.file_name().unwrap().to_string_lossy().to_string();
55+
let output = if use_timeout {
56+
Command::new("timeout")
57+
.arg("-k")
58+
.arg("2")
59+
.arg("10")
60+
.arg(epasstool)
61+
.arg("read")
62+
.arg("-F")
63+
.arg("log")
64+
.arg("-o")
65+
.arg(&out)
66+
.arg(&file)
67+
.output()
68+
.expect("run epasstool with timeout")
69+
} else {
70+
Command::new(epasstool)
71+
.arg("read")
72+
.arg("-F")
73+
.arg("log")
74+
.arg("-o")
75+
.arg(&out)
76+
.arg(&file)
77+
.output()
78+
.expect("run epasstool")
79+
};
80+
if output.status.success() {
81+
passed += 1;
82+
} else if known.contains(name.as_str()) {
83+
known_failed += 1;
84+
} else {
85+
unexpected.push(format!(
86+
"{}: rc={:?}\nstdout={}\nstderr={}",
87+
name,
88+
output.status.code(),
89+
String::from_utf8_lossy(&output.stdout),
90+
String::from_utf8_lossy(&output.stderr)
91+
));
92+
}
93+
}
94+
let _ = std::fs::remove_file(&out);
95+
96+
eprintln!(
97+
"falco corpus: passed={} known_failed={} unexpected_failed={}",
98+
passed,
99+
known_failed,
100+
unexpected.len()
101+
);
102+
assert!(unexpected.is_empty(), "unexpected Falco failures:\n{}", unexpected.join("\n\n"));
103+
}

0 commit comments

Comments
 (0)