1 | // Copyright 2019 The Rust Project Developers. See the COPYRIGHT |
2 | // file at the top-level directory of this distribution and at |
3 | // http://rust-lang.org/COPYRIGHT. |
4 | // |
5 | // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or |
6 | // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license |
7 | // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your |
8 | // option. This file may not be copied, modified, or distributed |
9 | // except according to those terms. |
10 | |
11 | //! An implementation of the origin liveness calculation logic |
12 | |
13 | use std::collections::BTreeSet; |
14 | use std::time::Instant; |
15 | |
16 | use crate::facts::FactTypes; |
17 | use crate::output::{LivenessContext, Output}; |
18 | |
19 | use datafrog::{Iteration, Relation, RelationLeaper}; |
20 | |
21 | pub(super) fn compute_live_origins<T: FactTypes>( |
22 | ctx: LivenessContext<T>, |
23 | cfg_edge: &Relation<(T::Point, T::Point)>, |
24 | var_maybe_partly_initialized_on_exit: Relation<(T::Variable, T::Point)>, |
25 | output: &mut Output<T>, |
26 | ) -> Vec<(T::Origin, T::Point)> { |
27 | let timer = Instant::now(); |
28 | let mut iteration = Iteration::new(); |
29 | |
30 | // Relations |
31 | let var_defined_at: Relation<(T::Variable, T::Point)> = ctx.var_defined_at.into(); |
32 | let cfg_edge_reverse: Relation<(T::Point, T::Point)> = cfg_edge |
33 | .iter() |
34 | .map(|&(point1, point2)| (point2, point1)) |
35 | .collect(); |
36 | let use_of_var_derefs_origin: Relation<(T::Variable, T::Origin)> = |
37 | ctx.use_of_var_derefs_origin.into(); |
38 | let drop_of_var_derefs_origin: Relation<(T::Variable, T::Origin)> = |
39 | ctx.drop_of_var_derefs_origin.into(); |
40 | let var_dropped_at: Relation<((T::Variable, T::Point), ())> = ctx |
41 | .var_dropped_at |
42 | .into_iter() |
43 | .map(|(var, point)| ((var, point), ())) |
44 | .collect(); |
45 | |
46 | // Variables |
47 | |
48 | // `var_live_on_entry`: variable `var` is live upon entry at `point` |
49 | let var_live_on_entry = iteration.variable::<(T::Variable, T::Point)>("var_live_on_entry" ); |
50 | // `var_drop_live_on_entry`: variable `var` is drop-live (will be used for a drop) upon entry in `point` |
51 | let var_drop_live_on_entry = |
52 | iteration.variable::<(T::Variable, T::Point)>("var_drop_live_on_entry" ); |
53 | |
54 | // This is what we are actually calculating: |
55 | let origin_live_on_entry = iteration.variable::<(T::Origin, T::Point)>("origin_live_on_entry" ); |
56 | |
57 | // This propagates the relation `var_live_on_entry(var, point) :- var_used_at(var, point)`: |
58 | var_live_on_entry.insert(ctx.var_used_at.into()); |
59 | |
60 | // var_maybe_partly_initialized_on_entry(var, point2) :- |
61 | // var_maybe_partly_initialized_on_exit(var, point1), |
62 | // cfg_edge(point1, point2). |
63 | let var_maybe_partly_initialized_on_entry = Relation::from_leapjoin( |
64 | &var_maybe_partly_initialized_on_exit, |
65 | cfg_edge.extend_with(|&(_var, point1)| point1), |
66 | |&(var, _point1), &point2| ((var, point2), ()), |
67 | ); |
68 | |
69 | // var_drop_live_on_entry(var, point) :- |
70 | // var_dropped_at(var, point), |
71 | // var_maybe_partly_initialized_on_entry(var, point). |
72 | var_drop_live_on_entry.insert(Relation::from_join( |
73 | &var_dropped_at, |
74 | &var_maybe_partly_initialized_on_entry, |
75 | |&(var, point), _, _| (var, point), |
76 | )); |
77 | |
78 | while iteration.changed() { |
79 | // origin_live_on_entry(origin, point) :- |
80 | // var_drop_live_on_entry(var, point), |
81 | // drop_of_var_derefs_origin(var, origin). |
82 | origin_live_on_entry.from_join( |
83 | &var_drop_live_on_entry, |
84 | &drop_of_var_derefs_origin, |
85 | |_var, &point, &origin| (origin, point), |
86 | ); |
87 | |
88 | // origin_live_on_entry(origin, point) :- |
89 | // var_live_on_entry(var, point), |
90 | // use_of_var_derefs_origin(var, origin). |
91 | origin_live_on_entry.from_join( |
92 | &var_live_on_entry, |
93 | &use_of_var_derefs_origin, |
94 | |_var, &point, &origin| (origin, point), |
95 | ); |
96 | |
97 | // var_live_on_entry(var, point1) :- |
98 | // var_live_on_entry(var, point2), |
99 | // cfg_edge(point1, point2), |
100 | // !var_defined(var, point1). |
101 | var_live_on_entry.from_leapjoin( |
102 | &var_live_on_entry, |
103 | ( |
104 | var_defined_at.extend_anti(|&(var, _point2)| var), |
105 | cfg_edge_reverse.extend_with(|&(_var, point2)| point2), |
106 | ), |
107 | |&(var, _point2), &point1| (var, point1), |
108 | ); |
109 | |
110 | // var_drop_live_on_entry(Var, SourceNode) :- |
111 | // var_drop_live_on_entry(Var, TargetNode), |
112 | // cfg_edge(SourceNode, TargetNode), |
113 | // !var_defined_at(Var, SourceNode), |
114 | // var_maybe_partly_initialized_on_exit(Var, SourceNode). |
115 | var_drop_live_on_entry.from_leapjoin( |
116 | &var_drop_live_on_entry, |
117 | ( |
118 | var_defined_at.extend_anti(|&(var, _target_node)| var), |
119 | cfg_edge_reverse.extend_with(|&(_var, target_node)| target_node), |
120 | var_maybe_partly_initialized_on_exit.extend_with(|&(var, _target_node)| var), |
121 | ), |
122 | |&(var, _targetnode), &source_node| (var, source_node), |
123 | ); |
124 | } |
125 | |
126 | let origin_live_on_entry = origin_live_on_entry.complete(); |
127 | |
128 | info!( |
129 | "compute_live_origins() completed: {} tuples, {:?}" , |
130 | origin_live_on_entry.len(), |
131 | timer.elapsed(), |
132 | ); |
133 | |
134 | if output.dump_enabled { |
135 | let var_drop_live_on_entry = var_drop_live_on_entry.complete(); |
136 | for &(var, location) in var_drop_live_on_entry.iter() { |
137 | output |
138 | .var_drop_live_on_entry |
139 | .entry(location) |
140 | .or_default() |
141 | .push(var); |
142 | } |
143 | |
144 | let var_live_on_entry = var_live_on_entry.complete(); |
145 | for &(var, location) in var_live_on_entry.iter() { |
146 | output |
147 | .var_live_on_entry |
148 | .entry(location) |
149 | .or_default() |
150 | .push(var); |
151 | } |
152 | } |
153 | |
154 | origin_live_on_entry.elements |
155 | } |
156 | |
157 | pub(super) fn make_universal_regions_live<T: FactTypes>( |
158 | origin_live_on_entry: &mut Vec<(T::Origin, T::Point)>, |
159 | cfg_node: &BTreeSet<T::Point>, |
160 | universal_regions: &[T::Origin], |
161 | ) { |
162 | debug!("make_universal_regions_live()" ); |
163 | |
164 | origin_live_on_entry.reserve(additional:universal_regions.len() * cfg_node.len()); |
165 | for &origin: ::Origin in universal_regions.iter() { |
166 | for &point: ::Point in cfg_node.iter() { |
167 | origin_live_on_entry.push((origin, point)); |
168 | } |
169 | } |
170 | } |
171 | |