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 transform_constant_expr(
26 ctx: &mut UllbcStatementTransformCtx<'_>,
27 mut val: ConstantExpr,
28) -> Operand {
29 let rval = match val.kind() {
30 ConstantExprKind::Global(global_ref) => {
32 return Operand::Copy(Place::new_global(global_ref.clone(), val.ty().clone()));
33 }
34 ConstantExprKind::PtrNoProvenance(ptr) => {
35 let usize_ty = Ty::mk_usize();
36 let ptr_usize = ConstantExprKind::Integer(IntegerValue::Unsigned(UIntTy::Usize, *ptr));
37 let cast = UnOp::Cast(CastKind::RawPtr(usize_ty.clone(), val.ty().clone()));
38 Rvalue::UnaryOp(cast, Operand::Const(ConstantExpr::new(ptr_usize, usize_ty)))
39 }
40 cexpr @ (ConstantExprKind::Ref(..) | ConstantExprKind::Ptr(..)) => {
41 let (rk, bval, metadata) = match cexpr {
42 ConstantExprKind::Ref(bval, metadata) => (None, bval.clone(), metadata.clone()),
43 ConstantExprKind::Ptr(rk, bval, metadata) => {
44 (Some(*rk), bval.clone(), metadata.clone())
45 }
46 _ => unreachable!(),
47 };
48
49 let place = match bval.kind() {
51 ConstantExprKind::Global(global_ref) => {
52 Place::new_global(global_ref.clone(), bval.ty().clone())
53 }
54 _ => {
55 let bval = transform_constant_expr(ctx, bval);
57
58 let bval_ty = bval.ty().clone();
60 ctx.rval_to_place(Rvalue::Use(bval, WithRetag::No), bval_ty)
61 }
62 };
63 match (rk, metadata) {
64 (None, None) => ctx.borrow(place, BorrowKind::Shared),
66 (Some(rk), None) => ctx.raw_borrow(place, rk),
67 (None, Some(metadata)) => {
69 let sized_ref = ctx.borrow_to_new_var(place, BorrowKind::Shared, None);
70 Rvalue::UnaryOp(
71 UnOp::Cast(CastKind::Unsize(
72 sized_ref.ty.clone(),
73 val.ty().clone(),
74 metadata,
75 )),
76 Operand::Move(sized_ref),
77 )
78 }
79 (Some(rk), Some(metadata)) => {
80 let sized_raw_ref = ctx.raw_borrow_to_new_var(place, rk, None);
81 Rvalue::UnaryOp(
82 UnOp::Cast(CastKind::Unsize(
83 sized_raw_ref.ty.clone(),
84 val.ty().clone(),
85 metadata,
86 )),
87 Operand::Move(sized_raw_ref),
88 )
89 }
90 }
91 }
92 ConstantExprKind::Adt(..) if val.ty().is_unit() => {
93 return Operand::Const(val);
95 }
96 ConstantExprKind::Adt(variant, fields) => {
97 let fields = fields
98 .iter()
99 .cloned()
100 .map(|x| transform_constant_expr(ctx, x))
101 .collect();
102
103 let tref = val.ty().kind().as_adt().unwrap();
105 let aggregate_kind = AggregateKind::Adt(tref.clone(), *variant, None);
106 Rvalue::Aggregate(aggregate_kind, fields)
107 }
108 ConstantExprKind::Array(fields)
109 if let TyKind::Array(ty, _, ty_is_sized) = val.ty().kind() =>
110 {
111 let fields = fields
112 .iter()
113 .cloned()
114 .map(|x| transform_constant_expr(ctx, x))
115 .collect_vec();
116 let len = ConstantExpr::mk_usize(fields.len() as u128);
117 Rvalue::Aggregate(
118 AggregateKind::Array(ty.clone(), len, ty_is_sized.clone()),
119 fields,
120 )
121 }
122 ConstantExprKind::FnPtr(fptr) if let TyKind::FnPtr(sig) = val.ty().kind() => {
123 let from_ty =
124 TyKind::FnDef(sig.clone().map(|_| fptr.clone().move_under_binder())).into_ty();
125 let to_ty = TyKind::FnPtr(sig.clone()).into_ty();
126 Rvalue::UnaryOp(
127 UnOp::Cast(CastKind::FnPtr(from_ty.clone(), to_ty)),
128 Operand::Const(ConstantExpr::new(
129 ConstantExprKind::FnDef(fptr.clone()),
130 from_ty,
131 )),
132 )
133 }
134 ConstantExprKind::VTableRef(tref)
135 if let Some(vtable_ref) = tref.vtable_ref(&ctx.ctx.translated)
136 && let TyKind::Ref(_, vtable_ty, _) = val.ty().kind() =>
137 {
138 let inner = ConstantExpr::new(
139 ConstantExprKind::Global(vtable_ref.clone()),
140 vtable_ty.clone(),
141 );
142 val.with_contents_mut(|kind, _| *kind = ConstantExprKind::Ref(inner, None));
143 return transform_constant_expr(ctx, val);
145 }
146 _ => return Operand::Const(val),
147 };
148 Operand::Move(ctx.rval_to_place(rval, val.ty().clone()))
149}
150
151fn transform_operand(ctx: &mut UllbcStatementTransformCtx<'_>, op: &mut Operand) {
152 take_mut::take(op, |op| {
154 if let Operand::Const(val) = op {
155 transform_constant_expr(ctx, val)
156 } else {
157 op
158 }
159 })
160}
161
162pub struct Transform;
163impl UllbcPass for Transform {
164 fn should_run(&self, options: &crate::options::TranslateOptions) -> bool {
165 !options.raw_consts
166 }
167
168 fn transform_function(&self, ctx: &mut TransformCtx, fun_decl: &mut FunDecl) {
169 fun_decl.transform_ullbc_operands(ctx, transform_operand);
170 if let Some(body) = fun_decl.body.as_unstructured_mut() {
171 for block in body.body.iter_mut() {
172 block.dyn_visit_in_body_mut(|rvalue: &mut Rvalue| {
174 take_mut::take(rvalue, |rvalue| match rvalue {
175 Rvalue::Use(Operand::Const(e), _)
176 if e.kind().is_adt() && e.ty().is_unit() =>
177 {
178 Rvalue::unit_value()
179 }
180 _ => rvalue,
181 });
182 });
183 }
184 }
185 }
186}