charon_lib/transform/simplify_output/
simplify_constants.rs1use itertools::Itertools;
14
15use crate::transform::TransformCtx;
16use crate::transform::ctx::{BodyTransformCtx, UllbcPass, UllbcStatementTransformCtx};
17use crate::ullbc_ast::*;
18
19fn new_promoted_global(
22 ctx: &mut UllbcStatementTransformCtx<'_>,
23 value: ConstantExpr,
24 ptr_metadata: ConstantExpr,
25) -> GlobalDeclRef {
26 let krate = &mut ctx.ctx.translated;
27 let id = ItemId::Fun(*ctx.def_id);
28 let mut name = krate.item_names.get(&id).unwrap().clone();
29 let promoted_count = krate
30 .item_names
31 .values()
32 .filter_map(|n| n.name.split_last())
33 .filter(|(last, prefix)| {
34 matches!(last, PathElem::Builtin(BuiltinPathElem::PromotedConst, _))
35 && *prefix == name.name.as_slice()
36 })
37 .count();
38 let disambiguator = Disambiguator::new(promoted_count);
39 name.name.push(PathElem::Builtin(
40 BuiltinPathElem::PromotedConst,
41 disambiguator,
42 ));
43 let ty = value.ty().clone();
44 let id = krate.global_decls.push_with(|def_id| GlobalDecl {
45 def_id,
46 item_meta: ItemMeta::dummy_public(ctx.span, name.clone(), true, ItemOpacity::Transparent),
47 generics: GenericParams::empty(),
48 ty: ty.clone(),
49 size: Size::from_expr(SizeExpr::size_of(&ty)),
50 align: Size::from_expr(SizeExpr::align_of(&ty)),
51 ptr_metadata: Operand::Const(ptr_metadata),
52 src: GlobalSource::Normal,
53 global_kind: GlobalKind::AnonConst,
54 value,
55 });
56 krate.item_names.insert(id.into(), name);
57 GlobalDeclRef {
58 id,
59 generics: Box::new(GenericArgs::empty()),
60 }
61}
62
63fn transform_constant_expr(
70 ctx: &mut UllbcStatementTransformCtx<'_>,
71 mut val: ConstantExpr,
72) -> Operand {
73 let rval = match val.kind() {
74 ConstantExprKind::Global(global_ref) => {
76 return Operand::Copy(Place::new_global(global_ref.clone(), val.ty().clone()));
77 }
78 ConstantExprKind::PtrNoProvenance(ptr) => {
79 let usize_ty = Ty::mk_usize();
80 let ptr_usize = ConstantExprKind::Integer(IntegerValue::Unsigned(UIntTy::Usize, *ptr));
81 let cast = UnOp::Cast(CastKind::RawPtr(usize_ty.clone(), val.ty().clone()));
82 Rvalue::UnaryOp(cast, Operand::Const(ConstantExpr::new(ptr_usize, usize_ty)))
83 }
84 cexpr @ (ConstantExprKind::Ref(bval, metadata)
85 | ConstantExprKind::Ptr(_, bval, metadata)) => {
86 let rk = cexpr.as_ptr().map(|(rk, _, _)| *rk);
87 let bval_is_sized = bval.ty().get_ptr_metadata(ctx.get_crate()).is_none();
88
89 let place = match bval.kind() {
90 ConstantExprKind::Global(global_ref) => {
91 Place::new_global(global_ref.clone(), bval.ty().clone())
92 }
93 _ if !bval_is_sized => {
95 let meta = match metadata.as_ref().unwrap() {
96 UnsizingMetadata::Length(meta) | UnsizingMetadata::VTable(_, meta) => meta,
97 UnsizingMetadata::VTableUpcast(..) | UnsizingMetadata::Unknown => {
98 unreachable!("unexpected const metadata")
99 }
100 };
101 let global_ref = new_promoted_global(ctx, bval.clone(), meta.clone());
102 Place::new_global(global_ref, bval.ty().clone())
103 }
104 _ => {
105 let bval = transform_constant_expr(ctx, bval.clone());
107
108 let bval_ty = bval.ty().clone();
110 ctx.rval_to_place(Rvalue::Use(bval, WithRetag::No), bval_ty)
111 }
112 };
113 let mut rval = match (rk, metadata.clone().filter(|_| bval_is_sized)) {
115 (None, None) => ctx.borrow(place, BorrowKind::Shared),
117 (Some(rk), None) => ctx.raw_borrow(place, rk),
118 (None, Some(metadata)) => {
120 let sized_ref = ctx.borrow_to_new_var(place, BorrowKind::Shared, None);
121 Rvalue::UnaryOp(
122 UnOp::Cast(CastKind::Unsize(
123 sized_ref.ty.clone(),
124 val.ty().clone(),
125 metadata,
126 )),
127 Operand::Move(sized_ref),
128 )
129 }
130 (Some(rk), Some(metadata)) => {
131 let sized_raw_ref = ctx.raw_borrow_to_new_var(place, rk, None);
132 Rvalue::UnaryOp(
133 UnOp::Cast(CastKind::Unsize(
134 sized_raw_ref.ty.clone(),
135 val.ty().clone(),
136 metadata,
137 )),
138 Operand::Move(sized_raw_ref),
139 )
140 }
141 };
142 if let Rvalue::Ref { ptr_metadata, .. } | Rvalue::RawPtr { ptr_metadata, .. } =
144 &mut rval
145 {
146 transform_operand(ctx, ptr_metadata);
147 }
148 rval
149 }
150 ConstantExprKind::Adt(..) if val.ty().is_unit() => {
151 return Operand::Const(val);
153 }
154 ConstantExprKind::Adt(variant, fields) => {
155 let fields = fields
156 .iter()
157 .cloned()
158 .map(|x| transform_constant_expr(ctx, x))
159 .collect();
160
161 let tref = val.ty().kind().as_adt().unwrap();
163 let aggregate_kind = AggregateKind::Adt(tref.clone(), *variant, None);
164 Rvalue::Aggregate(aggregate_kind, fields)
165 }
166 ConstantExprKind::Array(fields)
167 if let TyKind::Array(ty, _, ty_is_sized) = val.ty().kind() =>
168 {
169 let fields = fields
170 .iter()
171 .cloned()
172 .map(|x| transform_constant_expr(ctx, x))
173 .collect_vec();
174 let len = ConstantExpr::mk_usize(fields.len() as u128);
175 Rvalue::Aggregate(
176 AggregateKind::Array(ty.clone(), len, ty_is_sized.clone()),
177 fields,
178 )
179 }
180 ConstantExprKind::FnPtr(fptr) if let TyKind::FnPtr(sig) = val.ty().kind() => {
181 let from_ty =
182 TyKind::FnDef(sig.clone().map(|_| fptr.clone().move_under_binder())).into_ty();
183 let to_ty = TyKind::FnPtr(sig.clone()).into_ty();
184 Rvalue::UnaryOp(
185 UnOp::Cast(CastKind::FnPtr(from_ty.clone(), to_ty)),
186 Operand::Const(ConstantExpr::new(
187 ConstantExprKind::FnDef(fptr.clone()),
188 from_ty,
189 )),
190 )
191 }
192 ConstantExprKind::VTableRef(tref)
193 if let Some(vtable_ref) = tref.vtable_ref(&ctx.ctx.translated)
194 && let TyKind::Ref(_, vtable_ty, _) = val.ty().kind() =>
195 {
196 let inner = ConstantExpr::new(
197 ConstantExprKind::Global(vtable_ref.clone()),
198 vtable_ty.clone(),
199 );
200 val.with_contents_mut(|kind, _| *kind = ConstantExprKind::Ref(inner, None));
201 return transform_constant_expr(ctx, val);
203 }
204 _ => return Operand::Const(val),
205 };
206 Operand::Move(ctx.rval_to_place(rval, val.ty().clone()))
207}
208
209fn transform_operand(ctx: &mut UllbcStatementTransformCtx<'_>, op: &mut Operand) {
210 take_mut::take(op, |op| {
212 if let Operand::Const(val) = op {
213 transform_constant_expr(ctx, val)
214 } else {
215 op
216 }
217 })
218}
219
220pub struct Transform;
221impl UllbcPass for Transform {
222 fn should_run(&self, options: &crate::options::TranslateOptions) -> bool {
223 !options.raw_consts
224 }
225
226 fn transform_function(&self, ctx: &mut TransformCtx, fun_decl: &mut FunDecl) {
227 fun_decl.transform_ullbc_operands(ctx, transform_operand);
228 if let Some(body) = fun_decl.body.as_unstructured_mut() {
229 for block in body.body.iter_mut() {
230 block.dyn_visit_in_body_mut(|rvalue: &mut Rvalue| {
232 take_mut::take(rvalue, |rvalue| match rvalue {
233 Rvalue::Use(Operand::Const(e), _)
234 if e.kind().is_adt() && e.ty().is_unit() =>
235 {
236 Rvalue::unit_value()
237 }
238 _ => rvalue,
239 });
240 });
241 }
242 }
243 }
244}