From 851a880f52e3d026f4329303df26095f4e42f8f7 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Mon, 1 May 2017 17:17:44 -0400 Subject: [PATCH] remove irrelevant comments --- src/librustc/mir/README.md | 132 +++++++++++-------------------------- 1 file changed, 40 insertions(+), 92 deletions(-) diff --git a/src/librustc/mir/README.md b/src/librustc/mir/README.md index 143e6e70a82..e8ed8bf104c 100644 --- a/src/librustc/mir/README.md +++ b/src/librustc/mir/README.md @@ -32,111 +32,59 @@ MIR and then iteratively optimize it by putting it through various pipeline stages. This section describes those pipeline stages and how you can extend them. -Here is a diagram showing the various MIR queries involved in producing -the final `optimized_mir()` for a single def-id `D`. The arrows here -indicate how data flows from query to query. +To produce the `optimized_mir(D)` for a given def-id `D`, the MIR +passes through several suites of optimizations, each represented by a +query. Each suite consists of multiple optimizations and +transformations. These suites represent useful intermediate points +where we want to access the MIR for type checking or other purposes: -``` -mir_build(D) - -> mir_pass((0,0,D)) ---+ each suite consists of many passes - -> ... | - -> mir_pass((0,N,D)) | - -> mir_suite((0,D)) ---+ ---+ there are several suites - -> ... | - -> mir_suite((M,D)) ---+ - -> mir_optimized(D) -``` - -The MIR transformation pipeline is organized into **suites**. When -you ask for `mir_optimized(D)`, it will turn around and request the -result from the final **suite** of MIR passes -(`mir_suite((M,D))`). This will in turn (eventually) trigger the MIR -to be build and then passes through each of the optimization suites. -Each suite internally triggers one query for each of its passes -(`mir_pass(...)`). - -The reason for the suites is that they represent points in the MIR -transformation pipeline where other bits of code are interested in -observing. For example, the `MIR_CONST` suite defines the point where -analysis for constant rvalues and expressions can take -place. `MIR_OPTIMIZED` naturally represents the point where we -actually generate machine code. Nobody should ever request the result -of an individual *pass*, at least outside of the transformation -pipeline: this allows us to add passes into the appropriate suite -without having to modify anything else in the compiler. +- `mir_build(D)` -- not a query, but this constructs the initial MIR +- `mir_const(D)` -- applies some simple transformations to make MIR ready for constant evaluation; +- `mir_validated(D)` -- applies some more transformations, making MIR ready for borrow checking; +- `optimized_mir(D)` -- the final state, after all optimizations have been performed. ### Stealing -Each of these intermediate queries yields up a `&'tcx -Steal>`, allocated using `tcx.alloc_steal_mir()`. This -indicates that the result may be **stolen** by the next pass -- this -is an optimization to avoid cloning the MIR. Attempting to use a -stolen result will cause a panic in the compiler. Therefore, it is -important that you not read directly from these intermediate queries -except as part of the MIR processing pipeline. +The intermediate queries `mir_const()` and `mir_validated()` yield up +a `&'tcx Steal>`, allocated using +`tcx.alloc_steal_mir()`. This indicates that the result may be +**stolen** by the next suite of optimizations -- this is an +optimization to avoid cloning the MIR. Attempting to use a stolen +result will cause a panic in the compiler. Therefore, it is important +that you not read directly from these intermediate queries except as +part of the MIR processing pipeline. Because of this stealing mechanism, some care must also be taken to ensure that, before the MIR at a particular phase in the processing pipeline is stolen, anyone who may want to read from it has already -done so. Sometimes this requires **forcing** queries -(`ty::queries::foo::force(...)`) during an optimization pass -- this -will force a query to execute even though you don't directly require -its result. The query can then read the MIR it needs, and -- once it -is complete -- you can steal it. +done so. Concretely, this means that if you have some query `foo(D)` +that wants to access the result of `mir_const(D)` or +`mir_validated(D)`, you need to have the successor pass either "force" +`foo(D)` using `ty::queries::foo::force(...)`. This will force a query +to execute even though you don't directly require its result. As an example, consider MIR const qualification. It wants to read the -result produced by the `MIR_CONST` suite. However, that result will be -**stolen** by the first pass in the next suite (that pass performs -const promotion): +result produced by the `mir_const()` suite. However, that result will +be **stolen** by the `mir_validated()` suite. If nothing was done, +then `mir_const_qualif(D)` would succeed if it came before +`mir_validated(D)`, but fail otherwise. Therefore, `mir_validated(D)` +will **force** `mir_const_qualif` before it actually steals, thus +ensuring that the reads have already happened: ``` -mir_suite((MIR_CONST,D)) --read-by--> mir_const_qualif(D) - | - stolen-by - | - v -mir_pass((MIR_VALIDATED,0,D)) +mir_const(D) --read-by--> mir_const_qualif(D) + | ^ + stolen-by | + | (forces) + v | +mir_validated(D) ------------+ ``` -Therefore, the const promotion pass (the `mir_pass()` in the diagram) -will **force** `mir_const_qualif` before it actually steals, thus -ensuring that the reads have already happened (and the final result is -cached). - ### Implementing and registering a pass -To create a new MIR pass, you have to implement one of the MIR pass -traits. There are several traits, and you want to pick the most -specific one that applies to your pass. They are described here in -order of preference. Once you have implemented a trait for your type -`Foo`, you then have to insert `Foo` into one of the suites; this is -done in `librustc_driver/driver.rs` by invoking `push_pass()` with the -appropriate suite. - -**The `MirPass` trait.** For the most part, a MIR pass works by taking -as input the MIR for a single function and mutating it imperatively to -perform an optimization. To write such a pass, you can implement the -`MirPass` trait, which has a single callback that takes an `&mut Mir`. - -**The `DefIdPass` trait.** When a `MirPass` trait is executed, the -system will automatically steal the result of the previous pass and -supply it to you. (See the section on queries and stealing below.) -Sometimes you don't want to steal the result of the previous pass -right away. In such cases, you can define a `DefIdPass`, which simply -gets a callback and lets you decide when to steal the previous result. - -**The `Pass` trait.** The most primitive but flexible trait is `Pass`. -Unlike the other pass types, it returns a `Multi` result, which means -it scan be used for interprocedural passes which mutate more than one -MIR at a time (e.g., `inline`). - -### The MIR Context - -All of the passes when invoked take a `MirCtxt` object. This contains -various methods to find out (e.g.) the current pass suite and pass -index, the def-id you are operating on, and so forth. You can also -access the MIR for the current def-id using `read_previous_mir()`; the -"previous" refers to the fact that this will be the MIR that was -output by the previous pass. Finally, you can `steal_previous_mir()` -to steal the output of the current pass (in which case you get -ownership of the MIR). +To create a new MIR pass, you simply implement the `MirPass` trait for +some fresh singleton type `Foo`. Once you have implemented a trait for +your type `Foo`, you then have to insert `Foo` into one of the suites; +this is done in `librustc_driver/driver.rs` by invoking `push_pass(S, +Foo)` with the appropriate suite substituted for `S`. + -- 2.44.0