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(slice_ty)), 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!(arr_ty == slice_ty);
30                assert!(kind1 == kind2);
31                // We could avoid the clone operations below if we take the content of
32                // the statement. In practice, this shouldn't have much impact.
33                let id = match *kind1 {
34                    RefKind::Mut => BuiltinFunId::ArrayToSliceMut,
35                    RefKind::Shared => BuiltinFunId::ArrayToSliceShared,
36                };
37                let func = FnPtrKind::mk_builtin(id);
38                let generics = GenericArgs::new(
39                    [Region::Erased].into(),
40                    [arr_ty.clone()].into(),
41                    [len.clone()].into(),
42                    [].into(),
43                );
44                s.kind = StatementKind::Call(Call {
45                    func: FnOperand::Regular(FnPtr::new(func, generics)),
46                    args: vec![op.clone()],
47                    dest: p.clone(),
48                });
49            }
50        }
51        // Transform the array aggregates to function calls
52        StatementKind::Assign(p, Rvalue::Repeat(op, ty, cg)) => {
53            // We could avoid the clone operations below if we take the content of
54            // the statement. In practice, this shouldn't have much impact.
55            let id = BuiltinFunId::ArrayRepeat;
56            let func = FnPtrKind::mk_builtin(id);
57            let generics = GenericArgs::new(
58                [].into(),
59                [ty.clone()].into(),
60                [cg.clone()].into(),
61                [].into(),
62            );
63            s.kind = StatementKind::Call(Call {
64                func: FnOperand::Regular(FnPtr::new(func, generics)),
65                args: vec![op.clone()],
66                dest: p.clone(),
67            });
68        }
69        // Transform the raw pointer aggregate to a function call
70        StatementKind::Assign(p, Rvalue::Aggregate(AggregateKind::RawPtr(ty, is_mut), ops)) => {
71            let id = BuiltinFunId::PtrFromParts(is_mut.clone());
72            let func = FnPtrKind::mk_builtin(id);
73            let generics = GenericArgs::new(
74                [Region::Erased].into(),
75                [ty.clone()].into(),
76                [].into(),
77                [].into(),
78            );
79
80            s.kind = StatementKind::Call(Call {
81                func: FnOperand::Regular(FnPtr::new(func, generics)),
82                args: ops.clone(),
83                dest: p.clone(),
84            });
85        }
86        _ => {}
87    }
88}
89
90pub struct Transform;
91impl LlbcPass for Transform {
92    fn should_run(&self, options: &crate::options::TranslateOptions) -> bool {
93        options.ops_to_function_calls
94    }
95
96    fn transform_body(&self, _ctx: &mut TransformCtx, b: &mut ExprBody) {
97        b.body.visit_statements(&mut transform_st);
98    }
99}