charon_lib/transform/simplify_output/
ops_to_function_calls.rs

1//! Desugar some unary/binary operations and the array repeats to function calls.
2//! For instance, we desugar ArrayToSlice from an unop to a function call.
3//! This allows a more uniform treatment later on.
4//! TODO: actually transform all the unops and binops to function calls?
5use crate::llbc_ast::*;
6use crate::transform::TransformCtx;
7
8use crate::transform::ctx::LlbcPass;
9
10fn transform_st(s: &mut Statement) {
11    match &s.kind {
12        // Transform the ArrayToSlice unop
13        StatementKind::Assign(
14            p,
15            Rvalue::UnaryOp(
16                UnOp::Cast(CastKind::Unsize(src_ty, tgt_ty, UnsizingMetadata::Length(_))),
17                op,
18            ),
19        ) => {
20            if let (
21                TyKind::Ref(_, deref!(TyKind::Array(arr_ty, len)), kind1),
22                TyKind::Ref(_, deref!(TyKind::Slice(_)), kind2),
23            ) = (src_ty.kind(), tgt_ty.kind())
24            {
25                // In MIR terminology, we go from &[T; l] to &[T] which means we
26                // effectively "unsize" the type, as `l` no longer appears in the
27                // destination type. At runtime, the converse happens: the length
28                // materializes into the fat pointer.
29                assert!(kind1 == kind2);
30                // We could avoid the clone operations below if we take the content of
31                // the statement. In practice, this shouldn't have much impact.
32                let id = match *kind1 {
33                    RefKind::Mut => BuiltinFunId::ArrayToSliceMut,
34                    RefKind::Shared => BuiltinFunId::ArrayToSliceShared,
35                };
36                let func = FnPtrKind::mk_builtin(id);
37                let generics = GenericArgs::new(
38                    [Region::Erased].into(),
39                    [arr_ty.clone()].into(),
40                    [*len.clone()].into(),
41                    [].into(),
42                );
43                s.kind = StatementKind::Call(Call {
44                    func: FnOperand::Regular(FnPtr::new(func, generics)),
45                    args: vec![op.clone()],
46                    dest: p.clone(),
47                });
48            }
49        }
50        // Transform the array aggregates to function calls
51        StatementKind::Assign(p, Rvalue::Repeat(op, ty, cg)) => {
52            // We could avoid the clone operations below if we take the content of
53            // the statement. In practice, this shouldn't have much impact.
54            let id = BuiltinFunId::ArrayRepeat;
55            let func = FnPtrKind::mk_builtin(id);
56            let generics = GenericArgs::new(
57                [].into(),
58                [ty.clone()].into(),
59                [*cg.clone()].into(),
60                [].into(),
61            );
62            s.kind = StatementKind::Call(Call {
63                func: FnOperand::Regular(FnPtr::new(func, generics)),
64                args: vec![op.clone()],
65                dest: p.clone(),
66            });
67        }
68        // Transform the raw pointer aggregate to a function call
69        StatementKind::Assign(p, Rvalue::Aggregate(AggregateKind::RawPtr(ty, is_mut), ops)) => {
70            let id = BuiltinFunId::PtrFromParts(is_mut.clone());
71            let func = FnPtrKind::mk_builtin(id);
72            let generics = GenericArgs::new(
73                [Region::Erased].into(),
74                [ty.clone()].into(),
75                [].into(),
76                [].into(),
77            );
78
79            s.kind = StatementKind::Call(Call {
80                func: FnOperand::Regular(FnPtr::new(func, generics)),
81                args: ops.clone(),
82                dest: p.clone(),
83            });
84        }
85        _ => {}
86    }
87}
88
89pub struct Transform;
90impl LlbcPass for Transform {
91    fn should_run(&self, options: &crate::options::TranslateOptions) -> bool {
92        options.ops_to_function_calls
93    }
94
95    fn transform_body(&self, _ctx: &mut TransformCtx, b: &mut ExprBody) {
96        b.body.visit_statements(&mut transform_st);
97    }
98}