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
//! What each instruction leaves in the condition state, and which comparisons ask the same thing.
//!
//! Design: `spec/optimizer/37-machine-level-optimization.md` section 37.4.
//!
//! A comparison on this kind of machine computes nothing. What it does is set a few bits nobody
//! named, and the instruction behind it reads them. So a comparison whose bits are already the
//! bits that are there is an instruction that could not be observed to have run, and taking it out
//! is the whole of this. There are two ways for the bits to already be there. The same comparison
//! was made a few instructions ago and nothing has disturbed it since, which is what a program
//! that asks whether something is zero and then whether it is not comes out as. Or the comparison
//! is against zero and the value it is about was worked out by arithmetic, which set the same bits
//! on its way past.
//!
//! It is here rather than in the pass for the reason [`crate::FrameInsts`] and
//! [`crate::BranchInsts`] are here. The pass is in a pipeline crate and `spec/10-backend.md`
//! section 10.8 says a pipeline crate holds no target-specific code, so what the pass knows about
//! a machine arrives as a description rather than as a name it says out loud.
//!
//! # Why the second case is not every condition
//!
//! A comparison against zero leaves more than the answer to it. `cmpl $0, %eax` says whether the
//! register is zero, and it says the register's sign, and it says that nothing carried and nothing
//! overflowed, because subtracting zero from a number cannot do either. An instruction that merely
//! happens to have written the register agrees about some of that and not all of it. `andl` agrees
//! about all of it: the machine clears carry and overflow after one, and sets the zero and sign
//! bits from what it wrote, which is what the comparison would have set them from. `subl` agrees
//! about the zero bit and about nothing else, because a subtraction that overflowed says so and
//! the comparison would have said it did not, and a condition built out of the sign and the
//! overflow together then reads two bits that no longer belong to each other.
//!
//! So a [`Zeroing`] says which of the three groups of conditions it is good for, [`Reads`] is
//! which group a condition belongs to, and a [`Reader`] is an instruction that names one. The zero
//! group is the one every entry is good for, since every instruction here that writes the
//! condition state at all sets the zero bit from what it wrote.
//!
//! The first case needs none of that. Two instructions that made the same comparison of the same
//! values left the same bits, all of them, so what may read them is not a question.
//!
//! # What is not a [`Zeroing`]
//!
//! A shift, because a shift by zero leaves the condition state exactly as it found it, and the
//! count is in a register often enough that the compiler cannot tell. A multiply, because the
//! machine leaves the zero bit undefined after one. An increment and a decrement, because they
//! leave carry alone rather than clearing it. None of those is a shape a program runs into often,
//! and each of them is a way to be quietly wrong, so the table says nothing about them and the
//! pass believes the table.
/// What a pass has to know about a machine to find a comparison the machine has already made.
/// One comparison, and what is left of it when the machine has already made it.
/// One instruction that reads the condition state, and which part of it it reads.
/// Which part of what a comparison against zero left a condition is about.
/// One instruction that leaves behind the comparison of what it wrote against zero.