charon_lib/transform/
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 super::ctx::LlbcPass;
9
10fn transform_st(s: &mut Statement) {
11    match &s.content {
12        // Transform the ArrayToSlice unop
13        RawStatement::Assign(p, Rvalue::UnaryOp(UnOp::ArrayToSlice(ref_kind, ty, cg), op)) => {
14            // We could avoid the clone operations below if we take the content of
15            // the statement. In practice, this shouldn't have much impact.
16            let id = match ref_kind {
17                RefKind::Mut => BuiltinFunId::ArrayToSliceMut,
18                RefKind::Shared => BuiltinFunId::ArrayToSliceShared,
19            };
20            let func = FunIdOrTraitMethodRef::mk_builtin(id);
21            let generics = GenericArgs::new(
22                [Region::Erased].into(),
23                [ty.clone()].into(),
24                [cg.clone()].into(),
25                [].into(),
26            );
27            let func = FnOperand::Regular(FnPtr {
28                func: Box::new(func),
29                generics: Box::new(generics),
30            });
31            s.content = RawStatement::Call(Call {
32                func,
33                args: vec![op.clone()],
34                dest: p.clone(),
35            });
36        }
37        // Transform the array aggregates to function calls
38        RawStatement::Assign(p, Rvalue::Repeat(op, ty, cg)) => {
39            // We could avoid the clone operations below if we take the content of
40            // the statement. In practice, this shouldn't have much impact.
41            let id = BuiltinFunId::ArrayRepeat;
42            let func = FunIdOrTraitMethodRef::mk_builtin(id);
43            let generics = GenericArgs::new(
44                [Region::Erased].into(),
45                [ty.clone()].into(),
46                [cg.clone()].into(),
47                [].into(),
48            );
49            let func = FnOperand::Regular(FnPtr {
50                func: Box::new(func),
51                generics: Box::new(generics),
52            });
53            s.content = RawStatement::Call(Call {
54                func,
55                args: vec![op.clone()],
56                dest: p.clone(),
57            });
58        }
59        // Transform the raw pointer aggregate to a function call
60        RawStatement::Assign(p, Rvalue::Aggregate(AggregateKind::RawPtr(ty, is_mut), ops)) => {
61            let id = BuiltinFunId::PtrFromParts(is_mut.clone());
62            let func = FunIdOrTraitMethodRef::mk_builtin(id);
63            let generics = GenericArgs::new(
64                [Region::Erased].into(),
65                [ty.clone()].into(),
66                [].into(),
67                [].into(),
68            );
69
70            let func = FnOperand::Regular(FnPtr {
71                func: Box::new(func),
72                generics: Box::new(generics),
73            });
74            s.content = RawStatement::Call(Call {
75                func,
76                args: ops.clone(),
77                dest: p.clone(),
78            });
79        }
80        _ => {}
81    }
82}
83
84pub struct Transform;
85impl LlbcPass for Transform {
86    fn transform_body(&self, ctx: &mut TransformCtx, b: &mut ExprBody) {
87        if ctx.options.no_ops_to_function_calls {
88            return;
89        }
90        b.body.visit_statements(&mut transform_st);
91    }
92}