rapx/analysis/core/alias_analysis/mfp/
transfer.rs1use rustc_middle::mir::{Operand, Place, ProjectionElem};
3
4use super::intraproc::{AliasDomain, PlaceId, PlaceInfo};
5
6pub fn mir_place_to_place_id<'tcx>(place: Place<'tcx>) -> PlaceId {
8 let mut place_id = PlaceId::Local(place.local.as_usize());
9
10 for proj in place.projection {
12 match proj {
13 ProjectionElem::Field(field, _) => {
14 place_id = place_id.project_field(field.as_usize());
15 }
16 ProjectionElem::Deref => {
17 }
20 _ => {
21 }
23 }
24 }
25
26 place_id
27}
28
29pub fn operand_to_place_id<'tcx>(operand: &Operand<'tcx>) -> Option<PlaceId> {
31 match operand {
32 Operand::Copy(place) | Operand::Move(place) => Some(mir_place_to_place_id(*place)),
33 Operand::Constant(_) => None,
34 }
35}
36
37pub fn transfer_assign<'tcx>(
39 state: &mut AliasDomain,
40 lv: Place<'tcx>,
41 rv: &Operand<'tcx>,
42 place_info: &PlaceInfo<'tcx>,
43) {
44 let lv_id = mir_place_to_place_id(lv);
45
46 let lv_idx = match place_info.get_index(&lv_id) {
48 Some(idx) => idx,
49 None => return, };
51
52 if !place_info.may_drop(lv_idx) {
54 return;
55 }
56
57 state.remove_aliases_with_prefix(&lv_id, place_info);
59
60 if let Some(rv_id) = operand_to_place_id(rv) {
62 if let Some(rv_idx) = place_info.get_index(&rv_id) {
63 if place_info.may_drop(rv_idx) {
64 state.union(lv_idx, rv_idx);
65
66 sync_fields(state, &lv_id, &rv_id, place_info);
68 }
69 }
70 }
71}
72
73pub fn transfer_ref<'tcx>(
75 state: &mut AliasDomain,
76 lv: Place<'tcx>,
77 rv: Place<'tcx>,
78 place_info: &PlaceInfo<'tcx>,
79) {
80 let lv_id = mir_place_to_place_id(lv);
82 let rv_id = mir_place_to_place_id(rv);
83
84 let lv_idx = match place_info.get_index(&lv_id) {
85 Some(idx) => idx,
86 None => return,
87 };
88
89 let rv_idx = match place_info.get_index(&rv_id) {
90 Some(idx) => idx,
91 None => return,
92 };
93
94 if !place_info.may_drop(lv_idx) || !place_info.may_drop(rv_idx) {
95 return;
96 }
97
98 state.remove_aliases_with_prefix(&lv_id, place_info);
100
101 state.union(lv_idx, rv_idx);
103
104 sync_fields(state, &lv_id, &rv_id, place_info);
106}
107
108pub fn transfer_field_assign<'tcx>(
110 state: &mut AliasDomain,
111 lv: Place<'tcx>,
112 rv_base: Place<'tcx>,
113 field_idx: usize,
114 place_info: &PlaceInfo<'tcx>,
115) {
116 let lv_id = mir_place_to_place_id(lv);
117 let rv_base_id = mir_place_to_place_id(rv_base);
118 let rv_field_id = rv_base_id.project_field(field_idx);
119
120 let lv_idx = match place_info.get_index(&lv_id) {
121 Some(idx) => idx,
122 None => return,
123 };
124
125 let rv_field_idx = match place_info.get_index(&rv_field_id) {
126 Some(idx) => idx,
127 None => return,
128 };
129
130 if !place_info.may_drop(lv_idx) || !place_info.may_drop(rv_field_idx) {
131 return;
132 }
133
134 state.remove_aliases_with_prefix(&lv_id, place_info);
136
137 state.union(lv_idx, rv_field_idx);
139
140 sync_fields(state, &lv_id, &rv_field_id, place_info);
142}
143
144pub fn transfer_aggregate<'tcx>(
146 state: &mut AliasDomain,
147 lv: Place<'tcx>,
148 operands: &[Operand<'tcx>],
149 place_info: &PlaceInfo<'tcx>,
150) {
151 let lv_id = mir_place_to_place_id(lv);
152
153 state.remove_aliases_with_prefix(&lv_id, place_info);
155
156 for (field_idx, operand) in operands.iter().enumerate() {
158 if let Some(rv_id) = operand_to_place_id(operand) {
159 let lv_field_id = lv_id.project_field(field_idx);
160
161 if let Some(lv_field_idx) = place_info.get_index(&lv_field_id) {
162 if let Some(rv_idx) = place_info.get_index(&rv_id) {
163 if place_info.may_drop(lv_field_idx) && place_info.may_drop(rv_idx) {
164 state.union(lv_field_idx, rv_idx);
165
166 sync_fields(state, &lv_field_id, &rv_id, place_info);
168 }
169 }
170 }
171 }
172 }
173}
174
175pub fn transfer_call<'tcx>(
177 state: &mut AliasDomain,
178 ret: Place<'tcx>,
179 _args: &[Operand<'tcx>],
180 place_info: &PlaceInfo<'tcx>,
181) {
182 let ret_id = mir_place_to_place_id(ret);
183
184 state.remove_aliases_with_prefix(&ret_id, place_info);
186
187 }
191
192pub fn sync_fields<'tcx>(
195 state: &mut AliasDomain,
196 lv: &PlaceId,
197 rv: &PlaceId,
198 place_info: &PlaceInfo<'tcx>,
199) {
200 const MAX_SYNC_DEPTH: usize = 3;
202 sync_fields_recursive(state, lv, rv, place_info, 0, MAX_SYNC_DEPTH);
203}
204
205fn sync_fields_recursive<'tcx>(
207 state: &mut AliasDomain,
208 lv: &PlaceId,
209 rv: &PlaceId,
210 place_info: &PlaceInfo<'tcx>,
211 depth: usize,
212 max_depth: usize,
213) {
214 if depth >= max_depth {
215 return;
216 }
217
218 for field_idx in 0..16 {
221 let lv_field = lv.project_field(field_idx);
222 let rv_field = rv.project_field(field_idx);
223
224 if let (Some(lv_field_idx), Some(rv_field_idx)) = (
226 place_info.get_index(&lv_field),
227 place_info.get_index(&rv_field),
228 ) {
229 if place_info.may_drop(lv_field_idx) && place_info.may_drop(rv_field_idx) {
231 if state.union(lv_field_idx, rv_field_idx) {
232 sync_fields_recursive(
234 state,
235 &lv_field,
236 &rv_field,
237 place_info,
238 depth + 1,
239 max_depth,
240 );
241 }
242 }
243 } else {
244 break;
246 }
247 }
248}