Skip to content

Commit 5b696e0

Browse files
Optimize reachability with non-mutating global passes (#4177)
## Context When transforming MIR, we use both `TransformPass`-es that operate over a single body and `GlobalPass`-es that require further context thus and operate over the whole program. Since these global passes could potentially modify the bodies they operate over, we currently re-run reachability after them to ensure that any changes are reflected in our reachability output. However, our global passes are largely gated behind unstable features (e.g. `-Z uninit-checks` to check for uninitialized memory) or specific user actions (e.g. compiling w/ `RUSTFLAGS="--emit mir"`), so this extra reachability collection is often done unnecessarily. Furthermore, some global passes (like emitting the generated MIR) do not modify the bodies they interact with at all, so re-doing collection is unneeded even when they are enabled. ## Changes This PR modifies the `GlobalPass` trait to return a boolean representing if the pass modified the MIR in a way that could affect reachability. We then use the boolean flags for each result to redo reachability analysis _only if a `GlobalPass` could have affected its result._ By submitting this pull request, I confirm that my contribution is made under the terms of the Apache 2.0 and MIT licenses.
1 parent 7c2c4cb commit 5b696e0

File tree

4 files changed

+31
-13
lines changed

4 files changed

+31
-13
lines changed

kani-compiler/src/codegen_cprover_gotoc/compiler_interface.rs

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -87,7 +87,7 @@ impl GotocCodegenBackend {
8787
// disadvantage of not having a precomputed call graph for the global passes to use. The
8888
// call graph could be used, for example, in resolving function pointer or vtable calls for
8989
// global passes that need this.
90-
let (items, call_graph) = with_timer(
90+
let (mut items, call_graph) = with_timer(
9191
|| collect_reachable_items(tcx, &mut transformer, starting_items),
9292
"codegen reachability analysis",
9393
);
@@ -107,7 +107,7 @@ impl GotocCodegenBackend {
107107

108108
// Apply all transformation passes, including global passes.
109109
let mut global_passes = GlobalPasses::new(&self.queries.lock().unwrap(), tcx);
110-
global_passes.run_global_passes(
110+
let any_pass_modified = global_passes.run_global_passes(
111111
&mut transformer,
112112
tcx,
113113
starting_items,
@@ -117,10 +117,12 @@ impl GotocCodegenBackend {
117117

118118
// Re-collect reachable items after global transformations were applied. This is necessary
119119
// since global pass could add extra calls to instrumentation.
120-
let (items, _) = with_timer(
121-
|| collect_reachable_items(tcx, &mut transformer, starting_items),
122-
"codegen reachability analysis (second pass)",
123-
);
120+
if any_pass_modified {
121+
(items, _) = with_timer(
122+
|| collect_reachable_items(tcx, &mut transformer, starting_items),
123+
"codegen reachability analysis (second pass)",
124+
);
125+
}
124126

125127
// Follow rustc naming convention (cx is abbrev for context).
126128
// https://rustc-dev-guide.rust-lang.org/conventions.html#naming-conventions

kani-compiler/src/kani_middle/transform/check_uninit/delayed_ub/mod.rs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,8 @@ impl GlobalPass for DelayedUbPass {
6565
starting_items: &[MonoItem],
6666
instances: Vec<Instance>,
6767
transformer: &mut BodyTransformation,
68-
) {
68+
) -> bool {
69+
let mut modified = false;
6970
// Collect all analysis targets (pointers to places reading and writing from which should be
7071
// tracked).
7172
let targets: HashSet<_> = instances
@@ -138,11 +139,13 @@ impl GlobalPass for DelayedUbPass {
138139
);
139140
// If some instrumentation has been performed, update the cached body in the local transformer.
140141
if instrumentation_added {
142+
modified = true;
141143
transformer.cache.entry(instance).and_modify(|transformation_result| {
142144
*transformation_result = TransformationResult::Modified(body);
143145
});
144146
}
145147
}
146148
}
149+
modified
147150
}
148151
}

kani-compiler/src/kani_middle/transform/dump_mir_pass.rs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ impl GlobalPass for DumpMirPass {
4040
starting_items: &[MonoItem],
4141
instances: Vec<Instance>,
4242
transformer: &mut BodyTransformation,
43-
) {
43+
) -> bool {
4444
// Create output buffer.
4545
let file_path = {
4646
let base_path = tcx.output_filenames(()).path(OutputType::Object);
@@ -65,5 +65,8 @@ impl GlobalPass for DumpMirPass {
6565
writeln!(writer, "// Item: {} ({})", instance.name(), instance.mangled_name()).unwrap();
6666
let _ = transformer.body(tcx, *instance).dump(&mut writer, &instance.name());
6767
}
68+
69+
// This pass just reads the MIR and thus never modifies it.
70+
false
6871
}
6972
}

kani-compiler/src/kani_middle/transform/mod.rs

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -179,15 +179,16 @@ pub(crate) trait GlobalPass: Debug {
179179
where
180180
Self: Sized;
181181

182-
/// Run a transformation pass on the whole codegen unit.
182+
/// Run a transformation pass on the whole codegen unit, returning a bool
183+
/// for whether modifications were made to the MIR that could affect reachability.
183184
fn transform(
184185
&mut self,
185186
tcx: TyCtxt,
186187
call_graph: &CallGraph,
187188
starting_items: &[MonoItem],
188189
instances: Vec<Instance>,
189190
transformer: &mut BodyTransformation,
190-
);
191+
) -> bool;
191192
}
192193

193194
/// The transformation result.
@@ -226,16 +227,25 @@ impl GlobalPasses {
226227
}
227228

228229
/// Run all global passes and store the results in a cache that can later be queried by `body`.
230+
/// Returns a boolean for if a pass has modified the MIR bodies.
229231
pub fn run_global_passes(
230232
&mut self,
231233
transformer: &mut BodyTransformation,
232234
tcx: TyCtxt,
233235
starting_items: &[MonoItem],
234236
instances: Vec<Instance>,
235237
call_graph: CallGraph,
236-
) {
237-
for global_pass in self.global_passes.iter_mut() {
238-
global_pass.transform(tcx, &call_graph, starting_items, instances.clone(), transformer);
238+
) -> bool {
239+
let mut modified = false;
240+
for global_pass in &mut self.global_passes {
241+
modified |= global_pass.transform(
242+
tcx,
243+
&call_graph,
244+
starting_items,
245+
instances.clone(),
246+
transformer,
247+
);
239248
}
249+
modified
240250
}
241251
}

0 commit comments

Comments
 (0)