charon_lib/transform/resugar/
reconstruct_static_accesses.rs1use rustc_hash::FxHashMap as HashMap;
7
8use crate::transform::TransformCtx;
9use crate::transform::ctx::UllbcPass;
10use crate::ullbc_ast::*;
11
12struct StaticInfo {
14 global: GlobalDeclRef,
15 assign_loc: StmtLoc,
16 uses: usize,
17 derefs: usize,
18}
19
20pub struct Transform;
21impl UllbcPass for Transform {
22 fn transform_body(&self, ctx: &mut TransformCtx, body: &mut ExprBody) {
23 let mut statics: HashMap<LocalId, StaticInfo> = body
25 .body
26 .iter_enumerated()
27 .flat_map(|(block_id, block)| {
28 let locs = (0..).map(move |i| StmtLoc::new(block_id, i));
29 locs.zip(&block.statements)
30 })
31 .filter_map(|(loc, st)| {
32 let (dest, rvalue) = &st.kind.as_assign()?;
33 let local = dest
34 .as_local()
35 .filter(|l| !body.locals.is_return_or_arg(*l))?;
36 let global = match rvalue {
37 Rvalue::Use(Operand::Const(c), _)
39 if let ConstantExprKind::Ref(pointee, _)
40 | ConstantExprKind::Ptr(_, pointee, _) = c.kind()
41 && let GlobalPlaceKind::Global(GlobalProvenance::Global(global)) =
42 &pointee.kind =>
43 {
44 global
45 }
46 Rvalue::Ref { place, .. } | Rvalue::RawPtr { place, .. } => {
48 place.kind.as_global()?
49 }
50 _ => return None,
51 };
52 let decl = ctx.translated.global_decls.get(global.id)?;
53 if !matches!(decl.global_kind, GlobalKind::Static { .. }) {
54 return None;
55 }
56 let info = StaticInfo {
57 global: global.clone(),
58 assign_loc: loc,
59 uses: 0,
60 derefs: 0,
61 };
62 Some((local, info))
63 })
64 .collect();
65 if statics.is_empty() {
66 return;
67 }
68
69 body.body.dyn_visit_in_body(|place: &Place| {
72 if let Some(local) = place.as_local()
73 && let Some(info) = statics.get_mut(&local)
74 {
75 info.uses += 1;
76 } else if let Some((sub, ProjectionElem::Deref)) = place.as_projection()
77 && let Some(local) = sub.as_local()
78 && let Some(info) = statics.get_mut(&local)
79 {
80 info.derefs += 1;
81 }
82 });
83 statics.retain(|_, info| info.uses == info.derefs + 1);
84 if statics.is_empty() {
85 return;
86 }
87
88 for info in statics.values() {
90 body[info.assign_loc].kind = StatementKind::Nop;
91 }
92 body.body.dyn_visit_in_body_mut(|place: &mut Place| {
94 if let Some((sub, ProjectionElem::Deref)) = place.as_projection()
95 && let Some(local) = sub.as_local()
96 && let Some(info) = statics.get(&local)
97 {
98 *place = Place::new_global(info.global.clone(), place.ty.clone());
99 }
100 });
101 }
102}