11//! A framework that can express both [gen-kill] and generic dataflow problems.
22//!
3- //! To use this framework, implement either the [`Analysis`] or the
4- //! [`GenKillAnalysis`] trait. If your transfer function can be expressed with only gen/kill
5- //! operations, prefer `GenKillAnalysis` since it will run faster while iterating to fixpoint. The
6- //! `impls` module contains several examples of gen/kill dataflow analyses.
3+ //! To use this framework, implement the [`Analysis`] trait. There used to be a `GenKillAnalysis`
4+ //! alternative trait for gen-kill analyses that would pre-compute the transfer function for each
5+ //! block. It was intended as an optimization, but it ended up not being any faster than
6+ //! `Analysis`.
7+ //!
8+ //! The `impls` module contains several examples of dataflow analyses.
79//!
810//! Create an `Engine` for your analysis using the `into_engine` method on the `Analysis` trait,
911//! then call `iterate_to_fixpoint`. From there, you can use a `ResultsCursor` to inspect the
@@ -122,9 +124,9 @@ pub trait AnalysisDomain<'tcx> {
122124///
123125/// # Convergence
124126///
125- /// When implementing this trait directly (not via [`GenKillAnalysis`]), it's possible to choose a
126- /// transfer function such that the analysis does not reach fixpoint. To guarantee convergence,
127- /// your transfer functions must maintain the following invariant:
127+ /// When implementing this trait it's possible to choose a transfer function such that the analysis
128+ /// does not reach fixpoint. To guarantee convergence, your transfer functions must maintain the
129+ /// following invariant:
128130///
129131/// > If the dataflow state **before** some point in the program changes to be greater
130132/// than the prior state **before** that point, the dataflow state **after** that point must
@@ -223,9 +225,7 @@ pub trait Analysis<'tcx>: AnalysisDomain<'tcx> {
223225
224226 /// Creates an `Engine` to find the fixpoint for this dataflow problem.
225227 ///
226- /// You shouldn't need to override this outside this module, since the combination of the
227- /// default impl and the one for all `A: GenKillAnalysis` will do the right thing.
228- /// Its purpose is to enable method chaining like so:
228+ /// You shouldn't need to override this. Its purpose is to enable method chaining like so:
229229 ///
230230 /// ```ignore (cross-crate-imports)
231231 /// let results = MyAnalysis::new(tcx, body)
@@ -246,146 +246,7 @@ pub trait Analysis<'tcx>: AnalysisDomain<'tcx> {
246246 }
247247}
248248
249- /// A gen/kill dataflow problem.
250- ///
251- /// Each method in this trait has a corresponding one in `Analysis`. However, the first two methods
252- /// here only allow modification of the dataflow state via "gen" and "kill" operations. By defining
253- /// transfer functions for each statement in this way, the transfer function for an entire basic
254- /// block can be computed efficiently. The remaining methods match up with `Analysis` exactly.
255- ///
256- /// `Analysis` is automatically implemented for all implementers of `GenKillAnalysis` via a blanket
257- /// impl below.
258- pub trait GenKillAnalysis < ' tcx > : Analysis < ' tcx > {
259- type Idx : Idx ;
260-
261- fn domain_size ( & self , body : & mir:: Body < ' tcx > ) -> usize ;
262-
263- /// See `Analysis::apply_statement_effect`.
264- fn statement_effect (
265- & mut self ,
266- trans : & mut Self :: Domain ,
267- statement : & mir:: Statement < ' tcx > ,
268- location : Location ,
269- ) ;
270-
271- /// See `Analysis::apply_before_statement_effect`.
272- fn before_statement_effect (
273- & mut self ,
274- _trans : & mut Self :: Domain ,
275- _statement : & mir:: Statement < ' tcx > ,
276- _location : Location ,
277- ) {
278- }
279-
280- /// See `Analysis::apply_terminator_effect`.
281- fn terminator_effect < ' mir > (
282- & mut self ,
283- trans : & mut Self :: Domain ,
284- terminator : & ' mir mir:: Terminator < ' tcx > ,
285- location : Location ,
286- ) -> TerminatorEdges < ' mir , ' tcx > ;
287-
288- /// See `Analysis::apply_before_terminator_effect`.
289- fn before_terminator_effect (
290- & mut self ,
291- _trans : & mut Self :: Domain ,
292- _terminator : & mir:: Terminator < ' tcx > ,
293- _location : Location ,
294- ) {
295- }
296-
297- /* Edge-specific effects */
298-
299- /// See `Analysis::apply_call_return_effect`.
300- fn call_return_effect (
301- & mut self ,
302- trans : & mut Self :: Domain ,
303- block : BasicBlock ,
304- return_places : CallReturnPlaces < ' _ , ' tcx > ,
305- ) ;
306-
307- /// See `Analysis::apply_switch_int_edge_effects`.
308- fn switch_int_edge_effects (
309- & mut self ,
310- _block : BasicBlock ,
311- _discr : & mir:: Operand < ' tcx > ,
312- _edge_effects : & mut impl SwitchIntEdgeEffects < Self :: Domain > ,
313- ) {
314- }
315- }
316-
317- // Blanket impl: any impl of `GenKillAnalysis` automatically impls `Analysis`.
318- impl < ' tcx , A > Analysis < ' tcx > for A
319- where
320- A : GenKillAnalysis < ' tcx > ,
321- A :: Domain : GenKill < A :: Idx > + BitSetExt < A :: Idx > ,
322- {
323- fn apply_statement_effect (
324- & mut self ,
325- state : & mut A :: Domain ,
326- statement : & mir:: Statement < ' tcx > ,
327- location : Location ,
328- ) {
329- self . statement_effect ( state, statement, location) ;
330- }
331-
332- fn apply_before_statement_effect (
333- & mut self ,
334- state : & mut A :: Domain ,
335- statement : & mir:: Statement < ' tcx > ,
336- location : Location ,
337- ) {
338- self . before_statement_effect ( state, statement, location) ;
339- }
340-
341- fn apply_terminator_effect < ' mir > (
342- & mut self ,
343- state : & mut A :: Domain ,
344- terminator : & ' mir mir:: Terminator < ' tcx > ,
345- location : Location ,
346- ) -> TerminatorEdges < ' mir , ' tcx > {
347- self . terminator_effect ( state, terminator, location)
348- }
349-
350- fn apply_before_terminator_effect (
351- & mut self ,
352- state : & mut A :: Domain ,
353- terminator : & mir:: Terminator < ' tcx > ,
354- location : Location ,
355- ) {
356- self . before_terminator_effect ( state, terminator, location) ;
357- }
358-
359- /* Edge-specific effects */
360-
361- fn apply_call_return_effect (
362- & mut self ,
363- state : & mut A :: Domain ,
364- block : BasicBlock ,
365- return_places : CallReturnPlaces < ' _ , ' tcx > ,
366- ) {
367- self . call_return_effect ( state, block, return_places) ;
368- }
369-
370- fn apply_switch_int_edge_effects (
371- & mut self ,
372- block : BasicBlock ,
373- discr : & mir:: Operand < ' tcx > ,
374- edge_effects : & mut impl SwitchIntEdgeEffects < A :: Domain > ,
375- ) {
376- self . switch_int_edge_effects ( block, discr, edge_effects) ;
377- }
378- }
379-
380249/// The legal operations for a transfer function in a gen/kill problem.
381- ///
382- /// This abstraction exists because there are two different contexts in which we call the methods in
383- /// `GenKillAnalysis`. Sometimes we need to store a single transfer function that can be efficiently
384- /// applied multiple times, such as when computing the cumulative transfer function for each block.
385- /// These cases require a `GenKillSet`, which in turn requires two `BitSet`s of storage. Oftentimes,
386- /// however, we only need to apply an effect once. In *these* cases, it is more efficient to pass the
387- /// `BitSet` representing the state vector directly into the `*_effect` methods as opposed to
388- /// building up a `GenKillSet` and then throwing it away.
389250pub trait GenKill < T > {
390251 /// Inserts `elem` into the state vector.
391252 fn gen_ ( & mut self , elem : T ) ;
0 commit comments