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
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
//! How long each of a machine's instructions takes, and which part of the machine it takes it on.
//!
//! Design: `spec/optimizer/38-scheduling-and-layout.md` sections 38.1 and 38.6.
//!
//! A scheduler puts the instructions of a block in the order that finishes soonest, and the only
//! thing that makes one order finish sooner than another is that the machine does not answer every
//! instruction in one cycle. So a scheduler needs two numbers about each instruction: how long
//! after it starts what it wrote may be read, and what it was using while it ran, because two
//! instructions that want the same part of the machine cannot both start in the same cycle however
//! independent they are.
//!
//! Those two numbers are this. They are a target's answer, for the reason every other description
//! in this crate is: the pass is in a pipeline crate, `spec/10-backend.md` section 10.8 says a
//! pipeline crate holds no target specific code, so an opcode is a name to it and how long a name
//! takes is something it is told.
//!
//! # Why the numbers are allowed to be wrong
//!
//! They are measurements of a particular processor, taken from published tables, and a program
//! compiled with them runs on whatever processor the person who runs it has. Spec 10.5 settles
//! what to do about that: "an incorrect model produces slow code rather than wrong code, which is
//! the right failure mode". A schedule is a permutation of instructions that were already going to
//! run, so a model that is wrong about every number produces a program that computes the same
//! thing at a different speed.
//!
//! What a wrong model must not do is be wrong quietly. [`TimingInsts::accurate`] is how a model
//! says which kind it is, and it is here from the first model rather than added when the first
//! model turns out to be wrong. `gcc/params.opt:77` has the same flag, `cycle-accurate-model`,
//! `Init(1)`, and is unusually direct about what it is for: "Whether the scheduling description is
//! mostly a cycle-accurate model of the target processor and is likely to spill aggressively to
//! fill any pipeline bubbles."
//!
//! A model that says `false` is one whose latencies are worth believing and whose picture of the
//! machine's units is not, because the latencies come out of a table of measured numbers and the
//! units are a summary of a pipeline nobody wrote down here. `rucc_codegen::schedule` reads it
//! exactly that way: it orders by latency either way, and it only holds an instruction back for
//! want of a free unit when the model says it is worth believing about units.
//!
//! # What is not in here
//!
//! How many micro-operations an instruction decodes to, which port each of them goes to, and what
//! the machine does when the queue in front of one fills. That is what a cycle accurate model is
//! and it is what `gcc/config/*/*.md`'s automata are built out of. No target here has one, every
//! target here says so, and section 38.8 owes the measurement that says how much that costs.
/// What a scheduler has to know about a machine to put a block in an order.
/// What one instruction costs.
/// The parts of a machine a scheduler counts.
///
/// A summary of a real processor's ports rather than a description of them. What it has to get
/// right is which instructions compete with each other, and the ones that compete are the ones
/// that are scarce: there are several units that add and one that divides, so a block full of
/// divisions is limited by the divider and a block full of additions is limited by the width.