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: Box<ConstantExpr>,
28) -> Operand {
29 let rval = match val.kind {
30 ConstantExprKind::Literal(_)
31 | ConstantExprKind::Var(_)
32 | ConstantExprKind::RawMemory(..)
33 | ConstantExprKind::TraitConst(..)
34 | ConstantExprKind::FnDef(..)
35 | ConstantExprKind::Opaque(_) => {
36 return Operand::Const(val);
41 }
42 ConstantExprKind::Global(global_ref) => {
48 return Operand::Copy(Place::new_global(global_ref, val.ty));
49 }
50 ConstantExprKind::PtrNoProvenance(ptr) => {
51 let usize_ty = TyKind::Literal(LiteralTy::UInt(UIntTy::Usize)).into_ty();
52 let ptr_usize = ConstantExprKind::Literal(Literal::Scalar(ScalarValue::Unsigned(
53 UIntTy::Usize,
54 ptr,
55 )));
56 let cast = UnOp::Cast(CastKind::RawPtr(usize_ty.clone(), val.ty.clone()));
57 Rvalue::UnaryOp(
58 cast,
59 Operand::Const(Box::new(ConstantExpr {
60 kind: ptr_usize,
61 ty: usize_ty,
62 })),
63 )
64 }
65 cexpr @ (ConstantExprKind::Ref(..) | ConstantExprKind::Ptr(..)) => {
66 let (rk, bval, metadata) = match cexpr {
67 ConstantExprKind::Ref(bval, metadata) => (None, bval, metadata),
68 ConstantExprKind::Ptr(rk, bval, metadata) => (Some(rk), bval, metadata),
69 _ => unreachable!("Unexpected constant expr kind in ref/ptr"),
70 };
71
72 let place = match bval.kind {
74 ConstantExprKind::Global(global_ref) => Place::new_global(global_ref, bval.ty),
75 _ => {
76 let bval = transform_constant_expr(ctx, bval);
78
79 let bval_ty = bval.ty().clone();
81 ctx.rval_to_place(Rvalue::Use(bval), bval_ty)
82 }
83 };
84 match (rk, metadata) {
85 (None, None) => ctx.borrow(place, BorrowKind::Shared),
87 (Some(rk), None) => ctx.raw_borrow(place, rk),
88 (None, Some(metadata)) => {
90 let sized_ref = ctx.borrow_to_new_var(place, BorrowKind::Shared, None);
91 Rvalue::UnaryOp(
92 UnOp::Cast(CastKind::Unsize(
93 sized_ref.ty.clone(),
94 val.ty.clone(),
95 metadata,
96 )),
97 Operand::Move(sized_ref),
98 )
99 }
100 (Some(rk), Some(metadata)) => {
101 let sized_raw_ref = ctx.raw_borrow_to_new_var(place, rk, None);
102 Rvalue::UnaryOp(
103 UnOp::Cast(CastKind::Unsize(
104 sized_raw_ref.ty.clone(),
105 val.ty.clone(),
106 metadata,
107 )),
108 Operand::Move(sized_raw_ref),
109 )
110 }
111 }
112 }
113 ConstantExprKind::Adt(variant, fields) => {
114 let fields = fields
115 .into_iter()
116 .map(|x| transform_constant_expr(ctx, Box::new(x)))
117 .collect();
118
119 let tref = val.ty.kind().as_adt().unwrap();
121 let aggregate_kind = AggregateKind::Adt(tref.clone(), variant, None);
122 Rvalue::Aggregate(aggregate_kind, fields)
123 }
124 ConstantExprKind::Array(fields) => {
125 let fields = fields
126 .into_iter()
127 .map(|x| transform_constant_expr(ctx, Box::new(x)))
128 .collect_vec();
129
130 let len =
131 ConstantExpr::mk_usize(ScalarValue::Unsigned(UIntTy::Usize, fields.len() as u128));
132 let TyKind::Array(ty, _) = val.ty.kind() else {
133 unreachable!("Non array type in array constant");
134 };
135 Rvalue::Aggregate(AggregateKind::Array(ty.clone(), Box::new(len)), fields)
136 }
137 ConstantExprKind::FnPtr(fptr) => {
138 let TyKind::FnPtr(sig) = val.ty.kind() else {
139 unreachable!("FnPtr constant must have FnPtr type");
140 };
141 let from_ty =
142 TyKind::FnDef(sig.clone().map(|_| fptr.clone().move_under_binder())).into_ty();
143 let to_ty = TyKind::FnPtr(sig.clone()).into_ty();
144
145 Rvalue::UnaryOp(
146 UnOp::Cast(CastKind::FnPtr(from_ty.clone(), to_ty)),
147 Operand::Const(Box::new(ConstantExpr {
148 kind: ConstantExprKind::FnDef(fptr),
149 ty: from_ty,
150 })),
151 )
152 }
153 ConstantExprKind::VTableRef(tref)
154 if let TraitRefKind::TraitImpl(impl_ref) = &tref.kind
155 && let Some(timpl) = ctx.ctx.translated.trait_impls.get(impl_ref.id)
156 && let Some(vtable_ref) = &timpl.vtable
157 && let TyKind::Ref(_, vtable_ty, _) = val.ty.kind() =>
158 {
159 let inner = Box::new(ConstantExpr {
160 kind: ConstantExprKind::Global(vtable_ref.clone()),
161 ty: vtable_ty.clone(),
162 });
163 val.kind = ConstantExprKind::Ref(inner, None);
164 return transform_constant_expr(ctx, val);
166 }
167 ConstantExprKind::VTableRef(..) => return Operand::Const(val),
168 };
169 Operand::Move(ctx.rval_to_place(rval, val.ty.clone()))
170}
171
172fn transform_operand(ctx: &mut UllbcStatementTransformCtx<'_>, op: &mut Operand) {
173 take_mut::take(op, |op| {
175 if let Operand::Const(val) = op {
176 transform_constant_expr(ctx, val)
177 } else {
178 op
179 }
180 })
181}
182
183pub struct Transform;
184impl UllbcPass for Transform {
185 fn should_run(&self, options: &crate::options::TranslateOptions) -> bool {
186 !options.raw_consts
187 }
188
189 fn transform_function(&self, ctx: &mut TransformCtx, fun_decl: &mut FunDecl) {
190 fun_decl.transform_ullbc_operands(ctx, transform_operand);
191 if let Some(body) = fun_decl.body.as_unstructured_mut() {
192 for block in body.body.iter_mut() {
193 block.dyn_visit_in_body_mut(|rvalue: &mut Rvalue| {
195 take_mut::take(rvalue, |rvalue| match rvalue {
196 Rvalue::Aggregate(AggregateKind::Array(ty, len), ref fields)
197 if fields.len() >= 2
198 && fields.iter().all(|x| x.is_const())
199 && let Ok(op) = fields.iter().dedup().exactly_one() =>
200 {
201 Rvalue::Repeat(op.clone(), ty.clone(), len)
202 }
203 _ => rvalue,
204 });
205 });
206 }
207 }
208 }
209}