rapx/analysis/core/alias/
mop.rs1pub mod alias;
2pub mod graph;
3pub mod mop;
4pub mod types;
5
6use super::{AAFact, AAResult, AliasAnalysis};
7use crate::{
8 analysis::{
9 utils::intrinsic_id::{
10 COPY_FROM, COPY_FROM_NONOVERLAPPING, COPY_TO, COPY_TO_NONOVERLAPPING,
11 },
12 Analysis,
13 },
14 rap_debug, rap_trace,
15 utils::source::*,
16};
17use graph::MopGraph;
18use rustc_data_structures::fx::FxHashMap;
19use rustc_hir::def_id::DefId;
20use rustc_middle::ty::TyCtxt;
21use std::{collections::HashSet, convert::From, fmt};
22
23pub const VISIT_LIMIT: usize = 1000;
24
25#[derive(Debug, Clone, Hash, PartialEq, Eq)]
26pub struct MopAAFact {
27 pub fact: AAFact,
28 pub lhs_may_drop: bool,
29 pub lhs_need_drop: bool,
30 pub rhs_may_drop: bool,
31 pub rhs_need_drop: bool,
32}
33
34impl MopAAFact {
35 pub fn new(
36 lhs_no: usize,
37 lhs_may_drop: bool,
38 lhs_need_drop: bool,
39 rhs_no: usize,
40 rhs_may_drop: bool,
41 rhs_need_drop: bool,
42 ) -> MopAAFact {
43 MopAAFact {
44 fact: AAFact::new(lhs_no, rhs_no),
45 lhs_may_drop,
46 lhs_need_drop,
47 rhs_may_drop,
48 rhs_need_drop,
49 }
50 }
51
52 pub fn valuable(&self) -> bool {
53 return self.lhs_may_drop && self.rhs_may_drop;
54 }
55
56 pub fn swap(&mut self) {
57 self.fact.swap();
58 std::mem::swap(&mut self.lhs_may_drop, &mut self.rhs_may_drop);
59 std::mem::swap(&mut self.lhs_need_drop, &mut self.rhs_need_drop);
60 }
61
62 pub fn lhs_no(&self) -> usize {
63 self.fact.lhs_no
64 }
65
66 pub fn rhs_no(&self) -> usize {
67 self.fact.rhs_no
68 }
69
70 pub fn lhs_fields(&self) -> &[usize] {
71 &self.fact.lhs_fields
72 }
73
74 pub fn rhs_fields(&self) -> &[usize] {
75 &self.fact.rhs_fields
76 }
77}
78
79#[derive(Debug, Clone)]
80pub struct MopAAResult {
81 arg_size: usize,
82 alias_set: HashSet<MopAAFact>,
83}
84
85impl fmt::Display for MopAAResult {
86 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
87 write!(
88 f,
89 "{{{}}}",
90 self.aliases()
91 .iter()
92 .map(|alias| format!("{}", alias.fact))
93 .collect::<Vec<String>>()
94 .join(",")
95 )
96 }
97}
98
99impl MopAAResult {
100 pub fn new(arg_size: usize) -> MopAAResult {
101 Self {
102 arg_size,
103 alias_set: HashSet::new(),
104 }
105 }
106
107 pub fn arg_size(&self) -> usize {
108 self.arg_size
109 }
110
111 pub fn aliases(&self) -> &HashSet<MopAAFact> {
112 &self.alias_set
113 }
114
115 pub fn add_alias(&mut self, alias: MopAAFact) {
116 self.alias_set.insert(alias);
117 }
118
119 pub fn len(&self) -> usize {
120 self.alias_set.len()
121 }
122
123 pub fn sort_alias_index(&mut self) {
124 let alias_set = std::mem::take(&mut self.alias_set);
125 let mut new_alias_set = HashSet::with_capacity(alias_set.len());
126
127 for mut ra in alias_set.into_iter() {
128 if ra.lhs_no() >= ra.rhs_no() {
129 ra.swap();
130 }
131 new_alias_set.insert(ra);
132 }
133 self.alias_set = new_alias_set;
134 }
135}
136
137impl Into<AAResult> for MopAAResult {
138 fn into(self) -> AAResult {
139 AAResult {
140 arg_size: self.arg_size,
141 alias_set: self.alias_set.into_iter().map(|alias| alias.fact).collect(),
142 }
143 }
144}
145
146pub type FnMap = FxHashMap<DefId, MopAAResult>;
148
149pub struct MopAlias<'tcx> {
150 pub tcx: TyCtxt<'tcx>,
151 pub fn_map: FxHashMap<DefId, MopAAResult>,
152}
153
154impl<'tcx> Analysis for MopAlias<'tcx> {
155 fn name(&self) -> &'static str {
156 "Alias Analysis (MoP)"
157 }
158
159 fn run(&mut self) {
160 rap_debug!("Start alias analysis via MoP.");
161 let mir_keys = self.tcx.mir_keys(());
162 for local_def_id in mir_keys {
163 self.query_mop(local_def_id.to_def_id());
164 }
165 for (fn_id, fn_alias) in &mut self.fn_map {
167 let fn_name = get_fn_name(self.tcx, *fn_id);
168 fn_alias.sort_alias_index();
169 if fn_alias.len() > 0 {
170 rap_debug!("Alias found in {:?}: {}", fn_name, fn_alias);
171 }
172 }
173 self.handle_conor_cases();
174 }
175
176 fn reset(&mut self) {
177 todo!();
178 }
179}
180
181impl<'tcx, T> AliasAnalysis<T> for MopAlias<'tcx>
182where
183 T: From<MopAAResult> + Clone,
184{
185 fn get_fn_alias(&mut self, def_id: DefId) -> T {
186 self.fn_map
187 .get(&def_id)
188 .expect(&format!("cannot find alias analysis result for {def_id:?}"))
189 .clone()
190 .into()
191 }
192
193 fn get_all_fn_alias(&mut self) -> FxHashMap<DefId, T> {
194 self.fn_map
195 .iter()
196 .map(|(k, v)| (*k, T::from(v.clone())))
197 .collect::<FxHashMap<DefId, T>>()
198 }
199}
200
201impl<'tcx> MopAlias<'tcx> {
202 pub fn new(tcx: TyCtxt<'tcx>) -> Self {
203 Self {
204 tcx,
205 fn_map: FxHashMap::default(),
206 }
207 }
208
209 fn handle_conor_cases(&mut self) {
210 let cases = [
211 COPY_FROM_NONOVERLAPPING,
212 COPY_TO_NONOVERLAPPING,
213 COPY_TO,
214 COPY_FROM,
215 ];
216 let alias = MopAAFact::new(1, true, true, 2, true, true);
217 for (key, value) in self.fn_map.iter_mut() {
218 if cases.contains(&key.index.as_usize()) {
219 value.alias_set.clear();
220 value.alias_set.insert(alias.clone());
221 }
222 }
223 }
224
225 fn query_mop(&mut self, def_id: DefId) {
226 let fn_name = get_fn_name(self.tcx, def_id);
227 rap_trace!("query_mop: {:?}", fn_name);
228 if let Some(_other) = self.tcx.hir_body_const_context(def_id.expect_local()) {
230 return;
231 }
232
233 if self.tcx.is_mir_available(def_id) {
234 let mut mop_graph = MopGraph::new(self.tcx, def_id);
235 mop_graph.solve_scc();
236 let mut recursion_set = HashSet::default();
237 mop_graph.check(0, &mut self.fn_map, &mut recursion_set);
238 if mop_graph.visit_times > VISIT_LIMIT {
239 rap_trace!("Over visited: {:?}", def_id);
240 }
241 self.fn_map.insert(def_id, mop_graph.ret_alias);
242 } else {
243 rap_trace!("Mir is not available at {}", self.tcx.def_path_str(def_id));
244 }
245 }
246}