charon_lib/ast/ullbc_ast.rs
1//! "Unstructured LLBC" ast (ULLBC). This is LLBC before the control-flow
2//! reconstruction. In effect, this is a cleaned up version of MIR.
3pub use crate::ast::*;
4use derive_generic_visitor::{Drive, DriveMut};
5use macros::{EnumAsGetters, EnumIsA, VariantIndexArity, VariantName};
6use serde::{Deserialize, Serialize};
7
8// Block identifier. Similar to rust's `BasicBlock`.
9generate_index_type!(BlockId, "Block");
10
11// The entry block of a function is always the block with id 0
12pub static START_BLOCK_ID: BlockId = BlockId::ZERO;
13
14#[charon::rename("Blocks")]
15pub type BodyContents = Vector<BlockId, BlockData>;
16pub type ExprBody = GExprBody<BodyContents>;
17
18/// A raw statement: a statement without meta data.
19#[derive(
20 Debug, Clone, EnumIsA, EnumAsGetters, VariantName, Serialize, Deserialize, Drive, DriveMut,
21)]
22pub enum StatementKind {
23 Assign(Place, Rvalue),
24 /// A call. For now, we don't support dynamic calls (i.e. to a function pointer in memory).
25 SetDiscriminant(Place, VariantId),
26 /// Equivalent to std::intrinsics::copy_nonoverlapping; this is not modelled as a function
27 /// call as it cannot diverge
28 CopyNonOverlapping(Box<CopyNonOverlapping>),
29 /// Indicates that this local should be allocated; if it is already allocated, this frees
30 /// the local and re-allocates it. The return value and arguments do not receive a
31 /// `StorageLive`. We ensure in the micro-pass `insert_storage_lives` that all other locals
32 /// have a `StorageLive` associated with them.
33 StorageLive(LocalId),
34 /// Indicates that this local should be deallocated; if it is already deallocated, this is
35 /// a no-op. A local may not have a `StorageDead` in the function's body, in which case it
36 /// is implicitly deallocated at the end of the function.
37 StorageDead(LocalId),
38 Deinit(Place),
39 /// Drop the value at the given place.
40 ///
41 /// This calls `<T as Drop>::drop_in_place(&raw mut place)` and marks the place as
42 /// moved-out-of. The `drop_in_place` method is added by Charon, it contains the same code as
43 /// the `core::ptr::drop_in_place<T>` builtin).
44 Drop(Place, TraitRef),
45 /// A built-in assert, which corresponds to runtime checks that we remove, namely: bounds
46 /// checks, over/underflow checks, div/rem by zero checks, pointer alignement check.
47 Assert(Assert),
48 /// Does nothing. Useful for passes.
49 Nop,
50 #[charon::opaque]
51 #[drive(skip)]
52 Error(String),
53}
54
55#[derive(Debug, Clone, Serialize, Deserialize, Drive, DriveMut)]
56pub struct Statement {
57 pub span: Span,
58 pub kind: StatementKind,
59 /// Comments that precede this statement.
60 // This is filled in a late pass after all the control-flow manipulation.
61 #[drive(skip)]
62 pub comments_before: Vec<String>,
63}
64
65#[derive(
66 Debug,
67 Clone,
68 EnumIsA,
69 EnumAsGetters,
70 VariantName,
71 VariantIndexArity,
72 Serialize,
73 Deserialize,
74 Drive,
75 DriveMut,
76)]
77#[charon::rename("Switch")]
78pub enum SwitchTargets {
79 /// Gives the `if` block and the `else` block
80 If(BlockId, BlockId),
81 /// Gives the integer type, a map linking values to switch branches, and the
82 /// otherwise block. Note that matches over enumerations are performed by
83 /// switching over the discriminant, which is an integer.
84 SwitchInt(LiteralTy, Vec<(Literal, BlockId)>, BlockId),
85}
86
87/// A raw terminator: a terminator without meta data.
88#[derive(Debug, Clone, EnumIsA, EnumAsGetters, Serialize, Deserialize, Drive, DriveMut)]
89pub enum TerminatorKind {
90 Goto {
91 target: BlockId,
92 },
93 Switch {
94 discr: Operand,
95 targets: SwitchTargets,
96 },
97 Call {
98 call: Call,
99 target: BlockId,
100 on_unwind: BlockId,
101 },
102 /// Handles panics and impossible cases.
103 Abort(AbortKind),
104 Return,
105 UnwindResume,
106}
107
108#[derive(Debug, Clone, Serialize, Deserialize, Drive, DriveMut)]
109pub struct Terminator {
110 pub span: Span,
111 pub kind: TerminatorKind,
112 /// Comments that precede this terminator.
113 // This is filled in a late pass after all the control-flow manipulation.
114 #[drive(skip)]
115 pub comments_before: Vec<String>,
116}
117
118#[derive(Debug, Clone, Serialize, Deserialize, Drive, DriveMut)]
119#[charon::rename("Block")]
120pub struct BlockData {
121 pub statements: Vec<Statement>,
122 pub terminator: Terminator,
123}