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
//! What a machine level pass has to ask before it may keep a rewrite.
//!
//! Design: `spec/optimizer/37-machine-level-optimization.md` sections 37.2 and 37.3.
//!
//! A machine level rewrite is speculative. Section 37.3 quotes `gcc/combine.cc` on the shape of
//! it: substitute the earlier instruction into the later one, ask the machine description whether
//! what came out is an instruction this target has, install it if it is and put everything back if
//! it is not. GCC's word for the asking is `recog`, the machine description is the `.md` file, and
//! the reason the arrangement is worth copying is in the same section: a target that adds a
//! pattern makes the optimizer smarter without anybody editing the optimizer.
//!
//! This is that question for this compiler. A pass proposes an instruction and asks whether the
//! target has one of that shape, and a target answers out of the description it already keeps for
//! the allocator and the encoder rather than out of a second list written for this. Two lists
//! would be two opinions about one machine and they would disagree eventually.
//!
//! # What it does not answer
//!
//! Whether the rewrite is worth making. That is the pass's own question and no target has an
//! opinion about it.
//!
//! Whether the values are right. An instruction of a shape this target has can still read the
//! wrong register, and what checks that is `rucc_regalloc::check` after allocation and the shape
//! of the pass before it. This says the instruction exists and nothing further.
use crateOperandDesc;
/// What a pass has to know about a machine to tell an instruction it has from one it does not.
///
/// Every question is of a name, for the reason [`crate::BitInsts`] takes names: 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 what any name means is the target's answer.
/// What an address constructor's arguments are.
///
/// An addressing mode is an argument to an instruction rather than an instruction, and a rule
/// file writes one as a term so that a rule can say which registers go where. The selector has
/// to turn that term into a machine IR memory operand, and what each constructor's arguments
/// mean is the same kind of target fact as an instruction's operands, so it is written here
/// rather than in the selector.
///
/// The names are shared. A rule file writes an address with whichever of these its machine has,
/// and a target with only some of them lists which, so a selector reads a constructor the same
/// way whichever machine it is selecting for.
///
/// The scale and the displacement are arguments rather than part of the name because each is a
/// number the rule matched and the machine encodes it as a number. There is none with a symbol
/// yet, because the rules that would need one are the ones about a global and those are not
/// written.
///
/// What the arguments mean is the whole of what tells these apart, and there is deliberately no
/// predicate here that answers half the question: the same register is a base in one of these
/// and an index in another, and the same constant is a scale in one and a displacement in
/// another, so anything building an address out of one has to look at which it is.