Update docs related to const-eval/Miri (#676)

* Update docs related to const-eval

Co-authored-by: Ralf Jung <post@ralfj.de>
This commit is contained in:
Yuki Okushi 2020-05-25 17:23:15 +09:00 committed by GitHub
parent c777d434f5
commit 85d815d11d
2 changed files with 37 additions and 30 deletions

View File

@ -5,7 +5,7 @@ specific item (constant/static/array length) this happens after the MIR for the
item is borrow-checked and optimized. In many cases trying to const evaluate an item is borrow-checked and optimized. In many cases trying to const evaluate an
item will trigger the computation of its MIR for the first time. item will trigger the computation of its MIR for the first time.
Prominent examples are Prominent examples are:
* The initializer of a `static` * The initializer of a `static`
* Array length * Array length
@ -20,19 +20,26 @@ Additionally constant evaluation can be used to reduce the workload or binary
size at runtime by precomputing complex operations at compiletime and only size at runtime by precomputing complex operations at compiletime and only
storing the result. storing the result.
Constant evaluation can be done by calling the `const_eval` query of `TyCtxt`. Constant evaluation can be done by calling the `const_eval_*` functions of `TyCtxt`.
They're the wrappers of the `const_eval` query.
The `const_eval` query takes a [`ParamEnv`](./param_env.html) of environment in The `const_eval_*` functions use a [`ParamEnv`](./param_env.html) of environment
which the constant is evaluated (e.g. the function within which the constant is in which the constant is evaluated (e.g. the function within which the constant is used)
used) and a `GlobalId`. The `GlobalId` is made up of an and a [`GlobalId`]. The `GlobalId` is made up of an `Instance` referring to a constant
`Instance` referring to a constant or static or of an or static or of an `Instance` of a function and an index into the function's `Promoted` table.
`Instance` of a function and an index into the function's `Promoted` table.
Constant evaluation returns a `Result` with either the error, or the simplest Constant evaluation returns a [`ConstEvalResult`] with either the error, or the a
representation of the constant. "simplest" meaning if it is representable as an representation of the constant. `static` initializers are always represented as
integer or fat pointer, it will directly yield the value (via `ConstValue::Scalar` or [`miri`](./miri.html) virtual memory allocations (via [`ConstValue::ByRef`]).
`ConstValue::ScalarPair`), instead of referring to the [`miri`](./miri.html) virtual Other constants get represented as [`ConstValue::Scalar`]
memory allocation (via `ConstValue::ByRef`). This means that the `const_eval` or [`ConstValue::Slice`] if possible. This means that the `const_eval_*`
function cannot be used to create miri-pointers to the evaluated constant or functions cannot be used to create miri-pointers to the evaluated constant.
static. If you need that, you need to directly work with the functions in If you need the value of a constant inside Miri, you need to directly work with
[src/librustc_mir/const_eval.rs](https://doc.rust-lang.org/nightly/nightly-rustc/rustc_mir/const_eval/index.html). [`eval_const_to_op`].
[`GlobalId`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/mir/interpret/struct.GlobalId.html
[`ConstValue::Scalar`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/mir/interpret/value/enum.ConstValue.html#variant.Scalar
[`ConstValue::Slice`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/mir/interpret/value/enum.ConstValue.html#variant.Slice
[`ConstValue::ByRef`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/mir/interpret/value/enum.ConstValue.html#variant.ByRef
[`ConstEvalResult`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/mir/interpret/error/type.ConstEvalResult.html
[`eval_const_to_op`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_mir/interpret/struct.InterpCx.html#method.eval_const_to_op

View File

@ -1,9 +1,9 @@
# Miri # Miri
Miri (**MIR** **I**nterpreter) is a virtual machine for executing MIR without Miri (**MIR** **I**nterpreter) is a virtual machine for executing MIR without
compiling to machine code. It is usually invoked via `tcx.const_eval`. compiling to machine code. It is usually invoked via `tcx.const_eval_*` functions.
If you start out with a constant If you start out with a constant:
```rust ```rust
const FOO: usize = 1 << 12; const FOO: usize = 1 << 12;
@ -12,7 +12,7 @@ const FOO: usize = 1 << 12;
rustc doesn't actually invoke anything until the constant is either used or rustc doesn't actually invoke anything until the constant is either used or
placed into metadata. placed into metadata.
Once you have a use-site like Once you have a use-site like:
```rust,ignore ```rust,ignore
type Foo = [u8; FOO - 42]; type Foo = [u8; FOO - 42];
@ -35,17 +35,17 @@ Invoking `tcx.const_eval(param_env.and(gid))` will now trigger the creation of
the MIR of the array length expression. The MIR will look something like this: the MIR of the array length expression. The MIR will look something like this:
```mir ```mir
const Foo::{{initializer}}: usize = { Foo::{{constant}}#0: usize = {
let mut _0: usize; // return pointer let mut _0: usize;
let mut _1: (usize, bool); let mut _1: (usize, bool);
bb0: { bb0: {
_1 = CheckedSub(const Unevaluated(FOO, Slice([])), const 42usize); _1 = CheckedSub(const FOO, const 42usize);
assert(!(_1.1: bool), "attempt to subtract with overflow") -> bb1; assert(!move (_1.1: bool), "attempt to subtract with overflow") -> bb1;
} }
bb1: { bb1: {
_0 = (_1.0: usize); _0 = move (_1.0: usize);
return; return;
} }
} }
@ -64,7 +64,7 @@ or a pair of two of them. In our case, the single scalar value is *not* (yet)
initialized. initialized.
When the initialization of `_1` is invoked, the value of the `FOO` constant is When the initialization of `_1` is invoked, the value of the `FOO` constant is
required, and triggers another call to `tcx.const_eval`, which will not be shown required, and triggers another call to `tcx.const_eval_*`, which will not be shown
here. If the evaluation of FOO is successful, `42` will be subtracted from its here. If the evaluation of FOO is successful, `42` will be subtracted from its
value `4096` and the result stored in `_1` as value `4096` and the result stored in `_1` as
`Operand::Immediate(Immediate::ScalarPair(Scalar::Raw { data: 4054, .. }, `Operand::Immediate(Immediate::ScalarPair(Scalar::Raw { data: 4054, .. },
@ -200,8 +200,8 @@ division on pointer values.
## Interpretation ## Interpretation
Although the main entry point to constant evaluation is the `tcx.const_eval` Although the main entry point to constant evaluation is the `tcx.const_eval_*`
query, there are additional functions in functions, there are additional functions in
[librustc_mir/const_eval.rs](https://doc.rust-lang.org/nightly/nightly-rustc/rustc_mir/const_eval/index.html) [librustc_mir/const_eval.rs](https://doc.rust-lang.org/nightly/nightly-rustc/rustc_mir/const_eval/index.html)
that allow accessing the fields of a `ConstValue` (`ByRef` or otherwise). You should that allow accessing the fields of a `ConstValue` (`ByRef` or otherwise). You should
never have to access an `Allocation` directly except for translating it to the never have to access an `Allocation` directly except for translating it to the
@ -217,7 +217,7 @@ A stack frame is defined by the `Frame` type in
and contains all the local and contains all the local
variables memory (`None` at the start of evaluation). Each frame refers to the variables memory (`None` at the start of evaluation). Each frame refers to the
evaluation of either the root constant or subsequent calls to `const fn`. The evaluation of either the root constant or subsequent calls to `const fn`. The
evaluation of another constant simply calls `tcx.const_eval`, which produces an evaluation of another constant simply calls `tcx.const_eval_*`, which produce an
entirely new and independent stack frame. entirely new and independent stack frame.
The frames are just a `Vec<Frame>`, there's no way to actually refer to a The frames are just a `Vec<Frame>`, there's no way to actually refer to a
@ -229,4 +229,4 @@ Miri now calls the `step` method (in
) until it either returns an error or has no further statements to execute. Each ) until it either returns an error or has no further statements to execute. Each
statement will now initialize or modify the locals or the virtual memory statement will now initialize or modify the locals or the virtual memory
referred to by a local. This might require evaluating other constants or referred to by a local. This might require evaluating other constants or
statics, which just recursively invokes `tcx.const_eval`. statics, which just recursively invokes `tcx.const_eval_*`.