From d8179532787f988972d6305e423d01123a24465c Mon Sep 17 00:00:00 2001 From: Yuki Okushi Date: Sat, 18 Apr 2020 01:03:28 +0900 Subject: [PATCH 1/6] Update docs related to const-eval --- src/const-eval.md | 32 +++++++++++++++++++------------- src/miri.md | 30 +++++++++++++++--------------- 2 files changed, 34 insertions(+), 28 deletions(-) diff --git a/src/const-eval.md b/src/const-eval.md index aaa2ed2d6..45a8345db 100644 --- a/src/const-eval.md +++ b/src/const-eval.md @@ -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 will trigger the computation of its MIR for the first time. -Prominent examples are +Prominent examples are: * The initializer of a `static` * Array length @@ -20,19 +20,25 @@ Additionally constant evaluation can be used to reduce the workload or binary size at runtime by precomputing complex operations at compiletime and only 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_*` queries of `TyCtxt`. -The `const_eval` query takes a [`ParamEnv`](./param_env.html) of environment in -which the constant is evaluated (e.g. the function within which the constant is -used) and a `GlobalId`. The `GlobalId` is made up of an -`Instance` referring to a constant or static or of an -`Instance` of a function and an index into the function's `Promoted` table. +The `const_eval_*` queries use a [`ParamEnv`](./param_env.html) of environment +in which the constant is evaluated (e.g. the function within which the constant is used) +and a [`GlobalId`]. The `GlobalId` is made up of an `Instance` referring to a constant +or static or of an `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 simplest representation of the constant. "simplest" meaning if it is representable as an -integer or fat pointer, it will directly yield the value (via `ConstValue::Scalar` or -`ConstValue::ScalarPair`), instead of referring to the [`miri`](./miri.html) virtual -memory allocation (via `ConstValue::ByRef`). This means that the `const_eval` -function cannot be used to create miri-pointers to the evaluated constant or +integer or fat pointer, it will directly yield the value (via [`ConstValue::Scalar`] +or [`ConstValue::Slice`]), instead of referring to the [`miri`](./miri.html) virtual +memory allocation (via [`ConstValue::ByRef`]). This means that the `const_eval_*` +functions cannot be used to create miri-pointers to the evaluated constant or static. If you need that, you need to directly work with the functions in -[src/librustc_mir/const_eval.rs](https://doc.rust-lang.org/nightly/nightly-rustc/rustc_mir/const_eval/index.html). +[`src/librustc_mir/const_eval.rs`]. + +[`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 +[`src/librustc_mir/const_eval.rs`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_mir/const_eval/index.html diff --git a/src/miri.md b/src/miri.md index 16f2a18f2..03421b3f0 100644 --- a/src/miri.md +++ b/src/miri.md @@ -1,9 +1,9 @@ # Miri 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_*` queries. -If you start out with a constant +If you start out with a constant: ```rust 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 placed into metadata. -Once you have a use-site like +Once you have a use-site like: ```rust,ignore 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: ```mir -const Foo::{{initializer}}: usize = { - let mut _0: usize; // return pointer +Foo::{{constant}}#0: usize = { + let mut _0: usize; let mut _1: (usize, bool); bb0: { - _1 = CheckedSub(const Unevaluated(FOO, Slice([])), const 42usize); - assert(!(_1.1: bool), "attempt to subtract with overflow") -> bb1; + _1 = CheckedSub(const FOO, const 42usize); + assert(!move (_1.1: bool), "attempt to subtract with overflow") -> bb1; } bb1: { - _0 = (_1.0: usize); + _0 = move (_1.0: usize); return; } } @@ -55,16 +55,16 @@ Before the evaluation, a virtual memory location (in this case essentially a `vec![u8; 4]` or `vec![u8; 8]`) is created for storing the evaluation result. At the start of the evaluation, `_0` and `_1` are -`Operand::Immediate(Immediate::Scalar(ScalarMaybeUndef::Undef))`. This is quite +`Operand::Immediate(Immediate::Scalar(ScalarMaybeUndef::Undef))`. This is quite a mouthful: [`Operand`] can represent either data stored somewhere in the [interpreter memory](#memory) (`Operand::Indirect`), or (as an optimization) immediate data stored in-line. And [`Immediate`] can either be a single (potentially uninitialized) [scalar value][`Scalar`] (integer or thin pointer), -or a pair of two of them. In our case, the single scalar value is *not* (yet) +or a pair of two of them. In our case, the single scalar value is *not* (yet) initialized. 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 value `4096` and the result stored in `_1` as `Operand::Immediate(Immediate::ScalarPair(Scalar::Raw { data: 4054, .. }, @@ -200,8 +200,8 @@ division on pointer values. ## Interpretation -Although the main entry point to constant evaluation is the `tcx.const_eval` -query, there are additional functions in +Although the main entry point to constant evaluation is the `tcx.const_eval_*` +queries, there are additional functions in [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 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 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 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. The frames are just a `Vec`, 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 statement will now initialize or modify the locals or the virtual memory 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_*`. From 852baf504063b8b4f522c2ebb5ca1fde2f1a105a Mon Sep 17 00:00:00 2001 From: Yuki Okushi Date: Mon, 25 May 2020 13:48:48 +0900 Subject: [PATCH 2/6] Apply reviews from RalfJung --- src/const-eval.md | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/const-eval.md b/src/const-eval.md index 45a8345db..32191ec5d 100644 --- a/src/const-eval.md +++ b/src/const-eval.md @@ -20,15 +20,16 @@ Additionally constant evaluation can be used to reduce the workload or binary size at runtime by precomputing complex operations at compiletime and only storing the result. -Constant evaluation can be done by calling the `const_eval_*` queries 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_*` queries use a [`ParamEnv`](./param_env.html) of environment +The `const_eval_*` functions use a [`ParamEnv`](./param_env.html) of environment in which the constant is evaluated (e.g. the function within which the constant is used) and a [`GlobalId`]. The `GlobalId` is made up of an `Instance` referring to a constant or static or of an `Instance` of a function and an index into the function's `Promoted` table. Constant evaluation returns a [`ConstEvalResult`] with either the error, or the simplest -representation of the constant. "simplest" meaning if it is representable as an +representation of the constant. "simplest" meaning if the `const` item is representable as an integer or fat pointer, it will directly yield the value (via [`ConstValue::Scalar`] or [`ConstValue::Slice`]), instead of referring to the [`miri`](./miri.html) virtual memory allocation (via [`ConstValue::ByRef`]). This means that the `const_eval_*` From 050d44a9c1190dfba2f5553a07911c3c9214f428 Mon Sep 17 00:00:00 2001 From: Yuki Okushi Date: Mon, 25 May 2020 13:52:41 +0900 Subject: [PATCH 3/6] Apply reviews from RalfJung --- src/const-eval.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/const-eval.md b/src/const-eval.md index 32191ec5d..ac18d52bb 100644 --- a/src/const-eval.md +++ b/src/const-eval.md @@ -34,12 +34,12 @@ integer or fat pointer, it will directly yield the value (via [`ConstValue::Scal or [`ConstValue::Slice`]), instead of referring to the [`miri`](./miri.html) virtual memory allocation (via [`ConstValue::ByRef`]). This means that the `const_eval_*` functions cannot be used to create miri-pointers to the evaluated constant or -static. If you need that, you need to directly work with the functions in -[`src/librustc_mir/const_eval.rs`]. +static. If you need the value of a constant inside Miri, you need to directly work with +[`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 -[`src/librustc_mir/const_eval.rs`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_mir/const_eval/index.html +[`eval_const_to_op`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_mir/interpret/struct.InterpCx.html#method.eval_const_to_op From f28cc50cfc73e1beaf1e3774a2efd126cbab7266 Mon Sep 17 00:00:00 2001 From: Yuki Okushi Date: Mon, 25 May 2020 16:39:51 +0900 Subject: [PATCH 4/6] Update src/const-eval.md Co-authored-by: Ralf Jung --- src/const-eval.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/const-eval.md b/src/const-eval.md index ac18d52bb..9d9e6caa5 100644 --- a/src/const-eval.md +++ b/src/const-eval.md @@ -33,8 +33,8 @@ representation of the constant. "simplest" meaning if the `const` item is repres integer or fat pointer, it will directly yield the value (via [`ConstValue::Scalar`] or [`ConstValue::Slice`]), instead of referring to the [`miri`](./miri.html) virtual memory allocation (via [`ConstValue::ByRef`]). This means that the `const_eval_*` -functions cannot be used to create miri-pointers to the evaluated constant or -static. If you need the value of a constant inside Miri, you need to directly work with +functions cannot be used to create miri-pointers to the evaluated constant. +If you need the value of a constant inside Miri, you need to directly work with [`eval_const_to_op`]. [`GlobalId`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/mir/interpret/struct.GlobalId.html From 5cb33615286ff7429a2fffc4280a2cd4fced1862 Mon Sep 17 00:00:00 2001 From: Yuki Okushi Date: Mon, 25 May 2020 17:04:42 +0900 Subject: [PATCH 5/6] Update src/const-eval.md Co-authored-by: Ralf Jung --- src/const-eval.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/const-eval.md b/src/const-eval.md index 9d9e6caa5..2a5c5d2f9 100644 --- a/src/const-eval.md +++ b/src/const-eval.md @@ -28,11 +28,11 @@ in which the constant is evaluated (e.g. the function within which the constant and a [`GlobalId`]. The `GlobalId` is made up of an `Instance` referring to a constant or static or of an `Instance` of a function and an index into the function's `Promoted` table. -Constant evaluation returns a [`ConstEvalResult`] with either the error, or the simplest -representation of the constant. "simplest" meaning if the `const` item is representable as an -integer or fat pointer, it will directly yield the value (via [`ConstValue::Scalar`] -or [`ConstValue::Slice`]), instead of referring to the [`miri`](./miri.html) virtual -memory allocation (via [`ConstValue::ByRef`]). This means that the `const_eval_*` +Constant evaluation returns a [`ConstEvalResult`] with either the error, or the a +representation of the constant. `static` initializers are always represented as +[`miri`](./miri.html) virtual memory allocations (via [`ConstValue::ByRef`]). +Other constants get represented as [`ConstValue::Scalar`] +or [`ConstValue::Slice`] if possible. This means that the `const_eval_*` functions cannot be used to create miri-pointers to the evaluated constant. If you need the value of a constant inside Miri, you need to directly work with [`eval_const_to_op`]. From 0aaee9e59a60c90c18bce034488d3f7c1e8014e6 Mon Sep 17 00:00:00 2001 From: Yuki Okushi Date: Mon, 25 May 2020 17:14:53 +0900 Subject: [PATCH 6/6] Tweak wording in miri.md --- src/miri.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/miri.md b/src/miri.md index 03421b3f0..76996271d 100644 --- a/src/miri.md +++ b/src/miri.md @@ -1,7 +1,7 @@ # Miri Miri (**MIR** **I**nterpreter) is a virtual machine for executing MIR without -compiling to machine code. It is usually invoked via `tcx.const_eval_*` queries. +compiling to machine code. It is usually invoked via `tcx.const_eval_*` functions. If you start out with a constant: @@ -201,7 +201,7 @@ division on pointer values. ## Interpretation Although the main entry point to constant evaluation is the `tcx.const_eval_*` -queries, 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) 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