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
//! The instructions a laid out branch is made of.
//!
//! Design: `spec/10-backend.md` sections 10.6 and 10.8.
//!
//! A lowering rule for a conditional branch says one thing, which is what the branch is on. Where
//! its two arms go is on the block rather than in the instruction, and which of them the block
//! falls through to is not knowable until every block of the function has been put in an order.
//! So the instructions that actually branch are chosen by the block layout, after allocation, and
//! they are named here for the same reason [`crate::FrameInsts`] names a push: the crate that
//! writes them is a pipeline crate and `spec/10-backend.md` section 10.8 says a pipeline crate
//! holds no target-specific code.
//!
//! # What each one has to be
//!
//! The shapes are fixed, because the code that writes them writes one shape each. The test reads
//! one register and sets whatever the machine's condition state is. The three jumps read nothing
//! and write nothing, and where each goes is the first successor of the block it ends, which is
//! how every other arm is already carried.
//!
//! Two conditional jumps rather than one, because which one a block ends with depends on which
//! arm the layout put next. A block that falls into the arm taken when the condition does not
//! hold ends with the jump that is taken when it does, and a block that falls into the other arm
//! ends with the other jump. Neither is more natural than the other and a target that could only
//! name one would force the layout to lay every second branch out backwards.
//!
//! After the layout has run, a block that ends in a conditional jump has exactly two successors:
//! the first is where the jump goes, and the second is the block laid out next, which is where it
//! goes when the jump is not taken. There is never a second jump in the same block, because the
//! layout makes a block for one rather than writing it.
//!
//! # The jump the layout did not write
//!
//! An `asm` template may write one itself, which is how a loop a program spelled out by hand
//! reaches the machine IR: the lowering turns each label into a block and each jump into a block
//! with two arms whose last instruction is already the jump. [`BranchInsts::conditional`] is the
//! list the layout reads to tell one of those, and what it does then is nothing at all, beyond the
//! block on the second arm that every two-armed block needs when neither arm is laid out next.
//! The arms are in the order the jump means, taken first, so the shape is the one above already.
//!
//! # The condition state is not an operand
//!
//! Nothing here mentions the flags, on a machine that has them or on one that does not. What
//! makes that sound is that the test and the jump that reads it are written next to each other,
//! by one pass, after the allocator has finished, so there is nothing left in the compiler that
//! could put an instruction between them.
//!
//! # The test a comparison makes unnecessary
//!
//! Almost every branch in a C program is on a comparison, and a comparison already sets the
//! condition state. The byte a rule selects for it, the test of that byte against itself and the
//! jump on the answer are three instructions where the machine wanted two, and the two it wanted
//! are the comparison with nothing kept and a jump on the condition the comparison was asked
//! about.
//!
//! [`Fusion`] is that pair written down, one entry per comparison a rule can select. The layout
//! looks for one when the instruction in front of the branch is a comparison whose byte the
//! branch is the whole of what reads, and writes the two instructions in the entry instead of the
//! three it found. Which of the two jumps it writes is the same question as before and gets the
//! same answer, so an entry names both.
//!
//! # The select a comparison makes unnecessary
//!
//! A rule selects a choice between two values as a test of a condition byte and a conditional move
//! on the answer, because the byte is the only thing a rule can name. When the byte came from a
//! comparison that is the same three instructions a branch was, a comparison keeping a byte, a
//! test of it and an instruction that reads what the test left, and the same two do the work: the
//! comparison keeping nothing and a move on the condition the comparison was asked about.
//!
//! [`Move`] is that pair written down, one entry per select and condition. The condition is named
//! by the jump a [`Fusion`] takes when its comparison held, so a comparison has one name for what
//! it asked whether a branch or a select reads it.
//!
//! It stays a table rather than becoming an operation on the names. `cmp_set_ae_ri_64` and
//! `cmp_ri_64` and `jcc_ae` are strings a target chose and not a spelling anything here may
//! derive, and a target whose comparisons are shaped differently, or which has no condition state
//! at all, writes a shorter table or an empty one.
/// Every instruction a laid out branch is made of.
/// A comparison, and the two instructions a branch on its answer becomes.
/// A select, a condition, and the move that makes the choice straight off that condition.