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 global = match rvalue {
34 Rvalue::Use(Operand::Const(c), _)
36 if let ConstantExprKind::Ref(pointee, _)
37 | ConstantExprKind::Ptr(_, pointee, _) = c.kind() =>
38 {
39 pointee.kind().as_global()?
40 }
41 Rvalue::Ref { place, .. } | Rvalue::RawPtr { place, .. } => {
43 place.kind.as_global()?
44 }
45 _ => return None,
46 };
47 let decl = ctx.translated.global_decls.get(global.id)?;
48 if !matches!(decl.global_kind, GlobalKind::Static { .. }) {
49 return None;
50 }
51 let info = StaticInfo {
52 global: global.clone(),
53 assign_loc: loc,
54 uses: 0,
55 derefs: 0,
56 };
57 Some((dest.as_local()?, info))
58 })
59 .collect();
60 if statics.is_empty() {
61 return;
62 }
63
64 body.body.dyn_visit_in_body(|place: &Place| {
67 if let Some(local) = place.as_local()
68 && let Some(info) = statics.get_mut(&local)
69 {
70 info.uses += 1;
71 } else if let Some((sub, ProjectionElem::Deref)) = place.as_projection()
72 && let Some(local) = sub.as_local()
73 && let Some(info) = statics.get_mut(&local)
74 {
75 info.derefs += 1;
76 }
77 });
78 statics.retain(|_, info| info.uses == info.derefs + 1);
79 if statics.is_empty() {
80 return;
81 }
82
83 for info in statics.values() {
85 body[info.assign_loc].kind = StatementKind::Nop;
86 }
87 body.body.dyn_visit_in_body_mut(|place: &mut Place| {
89 if let Some((sub, ProjectionElem::Deref)) = place.as_projection()
90 && let Some(local) = sub.as_local()
91 && let Some(info) = statics.get(&local)
92 {
93 *place = Place::new_global(info.global.clone(), place.ty.clone());
94 }
95 });
96 }
97}