1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
//! The pass manager, the acyclic e-graph, the rewrite rules and the analyses.
//!
//! Design: `spec/09-optimizer.md`. Layer rank 9, see `spec/18-package-layout.md`.
//!
//! # What is here
//!
//! The pass manager and five passes. [`pipeline`] holds the six pipelines, one per optimization
//! level, written out rather than assembled from flags, along with the fuel, the dumps and the
//! verification that section 9.10 asks of every pass. [`gate`] is the other half of the
//! bisection interface, which is `-fdisable-<pass>` and `-fenable-<pass>` over a list of
//! functions, so that which pass and which function are two searches rather than one. [`fold`] is the first pass through it,
//! [`simplify`] is the peephole the e-graph will eventually absorb, [`narrow`] takes the width
//! back off arithmetic that C promoted, [`simplify_cfg`] turns a branch whose condition is known
//! into a jump and removes the blocks that leaves stranded, and [`dce`] is what clears up after
//! all four of them. [`uses`] is the one thing two of them share, which is a count of who reads
//! what.
//!
//! [`stats`] is what a pass has to return, and [`optinfo`] is that printed. A pass reports what
//! it did and what it gave up on, and there is no other way for it to tell the manager it changed
//! anything, so the instrumentation cannot be the thing nobody got round to. Section 42.2 of
//! `spec/optimizer/42-measurement.md` counted what happens otherwise.
//!
//! [`mod@cfg`], [`dom`], [`loops`], [`scev`], [`alias`], [`memssa`] and [`range`] are the analyses
//! so far, and everything in `spec/optimizer/07` through `spec/optimizer/11` is built on them.
//! [`mod@cfg`] is the shape of a function with the instructions taken out, [`dom`] answers what
//! every path has to go through, forwards and backwards, [`loops`] says what loops there are, how
//! they nest, and which cycles are not loops at all, [`scev`] says how a value changes across the
//! iterations of one and how many iterations there are, [`alias`] answers the one question every
//! memory optimization is gated on, which is whether two references can touch the same byte,
//! [`memssa`] puts memory on a chain so a load can walk back to the store it sees, and [`range`]
//! says what values an integer can hold at the place it is asked about, which is not the same
//! question as what it can hold where it was defined.
//!
//! [`profile`] is how likely an edge is taken and how often a block runs, along with the field
//! that says how much either is worth believing. The types come first because section 11.5 of
//! `spec/optimizer/11-profile-and-frequency.md` says what M4 owes the profile work that arrives
//! after it, which is the shape rather than the data: a quality on every number, arithmetic that
//! degrades it, and no way to build one without saying where it came from. Retrofitting that into
//! thirty passes once there is real profile data is the failure mode, and it is GCC's, whose
//! profile maintenance bugs are mostly in passes written before the quality field existed.
//!
//! [`predict`] is where the first of those numbers comes from, which is a guess: ten predictors
//! from section 11.2, first match, each one a syntactic situation somebody measured in the 1990s
//! and a rate it turned out right at. Nothing in here is a measurement and every probability out
//! of it says so.
//!
//! [`frequency`] turns those guesses into the number the consumers actually want, which is how
//! often a block runs compared with the function entry. Section 11.3's method: solve each loop
//! from the inside out, take the chance of going round again, and the header runs one over one
//! minus that many times, which is the sum of the series. A loop nothing predicted an exit for
//! gets a cap rather than a division by zero, an irreducible region gets an answer that is marked
//! as not meaning anything, and the check section 11.5 asks for, which is that what arrives at a
//! block adds up to the block, is in [`frequency::Frequencies::problems`].
//!
//! [`purity`] is the other question asked about a call, which is what it is allowed to do. Five
//! answers rather than a boolean, because whether a call reads memory and whether it comes back are
//! separate questions and GCC needs both, and the default is the one that permits everything, so a
//! call nobody has taught it about costs a missed optimization rather than a wrong program. The
//! declaration the user wrote and the answer an analysis works out are kept in separate fields and
//! combined where they are read, which is what makes it possible to check one against the other.
//!
//! [`analysis`] is where a pass gets one from. It computes on demand, caches per function, and
//! throws out what a pass broke, working from what the pass said it preserved rather than from a
//! list kept somewhere else. A pass that claims to preserve an analysis it broke is caught under
//! `--verify`, by recomputing the analysis and comparing.
//!
//! The e-graph and the rewrite rule set are still M4 work and are not here yet.
//!
//! # Stability
//!
//! Every crate in the workspace is published, and publishing implies a promise. This one is
//! tier 3: its Rust API is explicitly unstable and will change without a major version bump.
//! Depend on the `rucc` binary's behaviour, not on this.
// `alias::Options` is deliberately not re-exported: [`pipeline::Options`] already has that name
// here and two of them at the top of the crate would be one import mistake away from a flag going
// to the wrong place.
pub use ;
pub use ;
pub use Cfg;
pub use ;
pub use Frequencies;
pub use ;
pub use Fuel;
pub use Gates;
pub use ;
// `memssa::Counts` is deliberately not re-exported either, for the same reason: [`alias::Counts`]
// has that name here, the two count different things, and a pass reporting one under the other's
// name would be read as a much worse number than it is. `memssa::build` stays behind its module
// because a bare `build` at the top of an optimizer says nothing about what it builds.
pub use ;
pub use Wants;
pub use ;
pub use ;
pub use ;
pub use ;
// `purity::Callee` and `purity::Facts` stay behind their module. `Callee` is one letter away from
// [`predict::Callees`], which is a different thing about the same instructions, and `Facts` at the
// top of an optimizer says nothing about which facts. [`purity::Purity`] is the answer everything
// asks for and is worth having here.
pub use Purity;
// `range::query::Options` and `range::query::Counts` stay behind their module for the two reasons
// already given above, which is that both names are taken at the top of this crate and neither of
// the things holding them is the thing a caller would mean.
pub use Ranges;
pub use ;
pub use ;
pub use Stats;
/// The milestone in `spec/17-milestones.md` that fills this crate in.
pub const MILESTONE: &str = "M4";