|
| 1 | +# Top-Down Description of the Semantics of MIR Constructs |
| 2 | + |
| 3 | +## Executing a `Body` (function call) |
| 4 | +Every _rust function_ gets compiled into a `Body`. A function body is |
| 5 | +broken up into a number of _basic blocks_ (portions of code with |
| 6 | +straight-line control flow). |
| 7 | + |
| 8 | +A function _call_ is executed by setting up the arguments and local |
| 9 | +variables, and then executing its body. After the function call, the |
| 10 | +return value (result) needs to be written back to the _destination_ |
| 11 | +given in the call, and execution continues with the _target_ basic |
| 12 | +block. An _unwind_ property indicates how to proceed when the call |
| 13 | +unwinds (i.e., panics). |
| 14 | + |
| 15 | +The _args_, _destination_, _unwind_, and (optional!) _target_ are |
| 16 | +supplied by either the `Terminator` kind `Call` (within a program), or |
| 17 | +unnecessary (when calling `main`). |
| 18 | + |
| 19 | +The execution of a body consists of |
| 20 | +* setting up a stack frame for this call |
| 21 | + - with reserved space for all _locals_: return value, arg.s, and local |
| 22 | + variables |
| 23 | + - with the (caller's) function address to return to (as well as |
| 24 | + _destination_, _target_, _unwind_) |
| 25 | + - with all _basic blocks_ of the function body |
| 26 | +* and then executing block 0 of the _basic blocks_ |
| 27 | + |
| 28 | +## Blocks and Control Flow |
| 29 | + |
| 30 | +Executing a block means to execute its contained _statements_ in |
| 31 | +order, followed by the _terminator_ action. |
| 32 | + |
| 33 | +### Execution of Terminators (Control Flow) |
| 34 | + |
| 35 | +The _terminator_ can be one of a variety of terminator kinds, |
| 36 | +indicating different continuations to the basic block. |
| 37 | + |
| 38 | +Some of these `TerminatorKind`s are only relevant for MIR |
| 39 | +transformations while elaborating higher-level operations and |
| 40 | +checking, others directly affect the execution control flow. |
| 41 | + |
| 42 | + |
| 43 | +| Kind | Data | | Action | |
| 44 | +|-----------------|-------------|---------------------------|-------------------------------------------| |
| 45 | +| Goto | block | | continue with given block | |
| 46 | +|-----------------|-------------|---------------------------|-------------------------------------------| |
| 47 | +| SwitchInt | discr | value to switch over | evaluate value and follow | |
| 48 | +| | targets | alternative continuations | the selected alternative | |
| 49 | +|-----------------|-------------|---------------------------|-------------------------------------------| |
| 50 | +| ?UnwindResume | | | Continue unwinding after "landing pad"(?) | |
| 51 | +|-----------------|-------------|---------------------------|-------------------------------------------| |
| 52 | +| UnwindTerminate | Reason | | Terminate after "landing pad"(?) | |
| 53 | +|-----------------|-------------|---------------------------|-------------------------------------------| |
| 54 | +| Return | | assign _0 to destination | continue with _target_ from call | |
| 55 | +| | | | and maybe more, "exact semantics unclear" | |
| 56 | +|-----------------|-------------|---------------------------|-------------------------------------------| |
| 57 | +| Unreachable | | cannot be reached | undefined behaviour if executed | |
| 58 | +|-----------------|-------------|---------------------------|-------------------------------------------| |
| 59 | +| Call | func | function address to call | set up stack frame for, load, and call | |
| 60 | +| | args | arguments | given function | |
| 61 | +| | destination | to store returned value | (will store return value at _destination_ | |
| 62 | +| | target | next block to go to | and proceed with _target_ block) | |
| 63 | +| | unwind | | | |
| 64 | +|-----------------|-------------|---------------------------|-------------------------------------------| |
| 65 | +| TailCall | func | function address to call | special version of `Call` for tail calls | |
| 66 | +| | args | arguments | replaces the stack frame instead of an | |
| 67 | +| | | | duplicating destination and target | |
| 68 | +|-----------------|-------------|---------------------------|-------------------------------------------| |
| 69 | +| Assert | cond | operand to check (bool) | evaluates _cond_, compares to _expected_ | |
| 70 | +| | expected | expected result of check | if equal, continue with _target_ | |
| 71 | +| | msg | msg for panic! call | otherwise `panic!` with _msg_ | |
| 72 | +| | target | continuation if OK | | |
| 73 | +| | unwind | | | |
| 74 | +|-----------------|-------------|---------------------------|-------------------------------------------| |
| 75 | +| InlineAsm | (for asm) | | executes inline ASM and returns | |
| 76 | +| | targets | next blocks, default 1st | to the _targets[1]_ block, UNCLEAR | |
| 77 | +|-----------------|-------------|---------------------------|-------------------------------------------| |
| 78 | +| **Irrelevant** | | | | |
| 79 | +|-----------------|-------------|---------------------------|-------------------------------------------| |
| 80 | +| Drop | place | memory to drop | UNCLEAR: noop after "drop elaboration" | |
| 81 | +| | target | next block to go to | | |
| 82 | +| | unwind | | | |
| 83 | +| | replace | | | |
| 84 | +|-----------------|-------------|---------------------------|-------------------------------------------| |
| 85 | +| Yield | ... | for coroutine blocks only | return a value to caller, resume from | |
| 86 | +| | | | given block when called again. | |
| 87 | +|-----------------|-------------|---------------------------|-------------------------------------------| |
| 88 | +| CoroutineDrop | ... | ? | | |
| 89 | +|-----------------|-------------|---------------------------|-------------------------------------------| |
| 90 | +| FalseEdge | real target | for borrow checker only | behaves like `Goto` with _real target_ | |
| 91 | +| FalseUnwind | real target | for borrow checker only | behaves like `Goto` with _real target_ | |
| 92 | +|-----------------|-------------|---------------------------|-------------------------------------------| |
| 93 | + |
| 94 | +### Statements (within a Basic Block) |
| 95 | + |
| 96 | +The list of statements in a basic block is executed sequentially. Each |
| 97 | +`Statement` has a certain `StatementKind`. Some `StatementKind`s won't |
| 98 | +appear in the MIR that gets executed by the semantics, others do. |
| 99 | + |
| 100 | +| Kind | Data | Action | |
| 101 | +|------------------|-----------------------------------------|------------------------------------------| |
| 102 | +| Assign | (Place, RValue) | evaluates place and rvalue, assigns | |
| 103 | +| ?SetDiscriminant | place, variant_index | write variant discriminant to place | |
| 104 | +|------------------|-----------------------------------------|------------------------------------------| |
| 105 | +| Deinit | (Place) | writes `uninit` to the place | |
| 106 | +| StorageLive | (Local) | allocates memory for the local | |
| 107 | +| StorageDead | (Local) | deallocates memory for the local | |
| 108 | +|------------------|-----------------------------------------|------------------------------------------| |
| 109 | +| ?Retag | (RetagKind, Place) | only for `miri`, puts fresh tag on place | |
| 110 | +| Intrinsic | (NonDivergingIntrinsic) | optimised call to intrinsic, saves block | |
| 111 | +| PlaceMention | (Place) | (technical, records place access) | |
| 112 | +|------------------|-----------------------------------------|------------------------------------------| |
| 113 | +| FakeRead | (FakeReadCause, Place) | disallowed after drop elaboration | |
| 114 | +| AscribeUserType | ((Place, UserTypeProjection), Variance) | relates types in assign, NOOP at runtime | |
| 115 | +| Coverage | (CoverageKind) | CostCtr indication for coverage counters | |
| 116 | +| ConstEvalCounter | | counts const eval. cost, NOOP otherwise | |
| 117 | +| Nop | | NOOP | |
| 118 | + |
| 119 | +The [code of the constant |
| 120 | +interpreter](https://github.com/runtimeverification/rust/blob/9131ddf5faba14fab225a7bf8ef5ee5dafe12e3b/compiler/rustc_const_eval/src/interpret/step.rs#L57-L291) |
| 121 | +demonstrates the semantics outlined in the table further. For |
| 122 | +instance, `Retag` and `PlaceMention` evaluate the given `Place` |
| 123 | +(`FakeRead` does not!). |
| 124 | + |
| 125 | +## Memory |
| 126 | + |
| 127 | +Some of the above constructs (statements `Storage{Live,Dead}` and |
| 128 | +`Deinit`, terminators `Drop`) are only relevant if memory allocation |
| 129 | +is part of the semantic model. In the KMIR semantics (so far), memory |
| 130 | +is intended to be modeled at a more abstract level. |
| 131 | + |
| 132 | +The `Assign` statement is where memory is accessed for reading or |
| 133 | +writing. An `RValue` is computed, potentially reading some arguments, |
| 134 | +and then written to a `Place`. |
| 135 | + |
| 136 | +### `Place`s |
| 137 | +A `Place` is a `Local` variable (actually just its index), and |
| 138 | +potentially a vector of `ProjectionElem`ents. |
| 139 | +- `Deref`erencing references or pointers (or `Box`es allocated in the |
| 140 | + heap) |
| 141 | +- `Field` access in struct.s and tuples |
| 142 | +- `Index`ing into arrays (from front or back) |
| 143 | +- Casting values (`OpaqueCast` or `Downcast` - variant narrowing) |
| 144 | + |
| 145 | + |
| 146 | +### `RValue`s |
| 147 | + |
| 148 | +An `RValue` is an operation that produces a value which can then be assigned to a `Place`. |
| 149 | + |
| 150 | +| RValue | Arguments | Action | |
| 151 | +|----------------|-------------------------------------------------|--------------------------------------| |
| 152 | +| Use | Operand | use (i.e., copy) operand unmodified | |
| 153 | +| Repeat | Operand, Const | create array [Operand;Const] | |
| 154 | +| Ref | Region, BorrowKind, Place | create reference to place | |
| 155 | +| ThreadLocalRef | DefId | thread-local reference (?) | |
| 156 | +| AddressOf | Mutability, Place | creates pointer to place | |
| 157 | +| Len | Place | array or slice size | |
| 158 | +| Cast | CastKind, Operand, Ty | different kinds of type casts | |
| 159 | +|----------------|-------------------------------------------------|--------------------------------------| |
| 160 | +| BinaryOp | BinOp, Box<(Operand, Operand)> | different fixed operations | |
| 161 | +| NullaryOp | NullOp, Ty | on ints, bool, floats | |
| 162 | +| UnaryOp | UnOp, Operand | (see below) | |
| 163 | +|----------------|-------------------------------------------------|--------------------------------------| |
| 164 | +| Discriminant | Place | discriminant (of sums types) (?) | |
| 165 | +| Aggregate | Box<AggregateKind>, IndexVec<FieldIdx, Operand> | disallowed after lowering. DF helper | |
| 166 | +| ShallowInitBox | Operand, Ty | ? | |
| 167 | +| CopyForDeref | Place | use (copy) contents of `Place` | |
| 168 | + |
| 169 | +See https://github.com/runtimeverification/rust/blob/9131ddf5faba14fab225a7bf8ef5ee5dafe12e3b/compiler/rustc_const_eval/src/interpret/step.rs#L139-L291 |
| 170 | + |
| 171 | +### Operations |
| 172 | + |
| 173 | +Operations are described cursorily in the `RValue` descriptions and in |
| 174 | +the `BinOp` and `UnaryOp` descriptions. Their exact semantics, |
| 175 | +however, must sometimes be retrieved from the compiler code. |
| 176 | + |
| 177 | +The `Operand`s of operations are `Copy` or `Move` from `Place`s, or |
| 178 | +`ConstOperand`s allocated in a `Box`. |
| 179 | +Both `Copy` and `Move` _load_ the operand from a `Place`. |
| 180 | + |
| 181 | +#### Nullary Operations `NullOp` |
| 182 | + |
| 183 | +| SizeOf | size of a type | |
| 184 | +| AlignOf, | minimum alignment of a type | |
| 185 | +| OffsetOf(&'tcx List<(VariantIdx, FieldIdx)>), | offset of a field in a struct | |
| 186 | +| UbChecks | whether upper-bound checks should be performed | |
| 187 | + |
| 188 | +#### Unary Operations `UnOp` |
| 189 | + |
| 190 | +| Not | logical inversion | |
| 191 | +| Neg | arithmetic inversion | |
| 192 | +| PtrMetadata | get pointer metadata. Only allowed in MIR:Runtime phase (?) | |
| 193 | + |
| 194 | +#### Binary Operations `BinOp`, operands A and B |
| 195 | + |
| 196 | +| Add | (A + B truncated, bool overflow flag) | int, float | | |
| 197 | +| AddUnchecked | A + B | int, float | must have been wrapped in `unsafe` | |
| 198 | +| AddWithOverflow | (A + B truncated, bool overflow flag) | int, float | not present in stable MIR | |
| 199 | +| Sub | (A - B truncated, bool underflow flag) | int, float | | |
| 200 | +| SubUnchecked | A - B | int, float | | |
| 201 | +| SubWithOverflow | (A - B truncated, bool underflow flag) | int, float | not present in stable MIR | |
| 202 | +| Mul | (A * B truncated, bool overflow flag) | int, float | | |
| 203 | +| MulUnchecked | A * B | int, float | | |
| 204 | +| MulWithOverflow | (A * B truncated, bool overflow flag) | int, float | not present in stable MIR | |
| 205 | +| Div | A / B or A `div` B | int, float | | |
| 206 | +| Rem | A `mod` B, rounding towards zero | int | | |
| 207 | +| BitXor | A `xor` B | int | | |
| 208 | +| BitAnd | A & B | int | | |
| 209 | +| BitOr | A \| B | int | | |
| 210 | +| Shl | (A << B truncated, bool overflow flag) | int | | |
| 211 | +| ShlUnchecked | A << B | int | | |
| 212 | +| Shr | (A >> B truncated? | int | | |
| 213 | +| ShrUnchecked | A >> B | int | | |
| 214 | +| Eq | A == B | int,float,bool | | |
| 215 | +| Lt | A < B | int,float | | |
| 216 | +| Le | A <= B | int,float | | |
| 217 | +| Ne | A /= B | int,float | | |
| 218 | +| Ge | A >= B | int,float | | |
| 219 | +| Gt | A > B | int,float | | |
| 220 | +| Cmp | cmp A B (LT -1, EQ 0, GT 1) | int,float | | |
| 221 | +| Offset | offset from a pointer | pointers | | |
0 commit comments