rucc_target/x86_64/insts.rs
1//! What each x86-64 machine instruction does with its operands.
2//!
3//! Design: `spec/10-backend.md` sections 10.1 and 10.2.
4//!
5//! The lowering rules say which machine instruction computes an IR term and `rucc-verify`
6//! proves that it does. Neither says where the operands may live, and that is the other half of
7//! what the backend needs: a two-address instruction destroys its first source, a shift by a
8//! variable count wants the count in `cl`, and a division has its dividend and its quotient in
9//! registers the program did not choose. The allocator has to be told all of it, and the rule
10//! set is the wrong place to write it, because it is a fact about the instruction rather than
11//! about the rewrite, and the same instruction is reached by many rules.
12//!
13//! So each opcode has a [`Form`] here, and a form is the operand vector of every instruction with
14//! it. The name is the one the rule set writes without the `x64.` in front, because a machine
15//! opcode in the machine IR is a name and this is where the name is given a meaning that is not
16//! the encoder's.
17//!
18//! Every opcode, and not only the ones a rule selects. A prologue pushes and a spill stores, and
19//! neither is anything a pattern could match, so [`crate::FrameInsts`] names them and the block
20//! layout's jumps are named by [`crate::BranchInsts`]. All of them end up in the same function and
21//! everything downstream reads them the same way, so a second table for the ones a rule cannot
22//! reach would be a second place for an opcode to be missing from.
23//!
24//! # What a form is not
25//!
26//! It is not a promise that the opcode is one instruction. `imul_rr_8` is the form of a
27//! two-address multiply and there is no two-operand `imul` on eight bit registers, so the
28//! encoder writes more than one instruction for it, and the same is true of every division and
29//! of the compare and set pairs. What a form promises is what the allocator has to know, which
30//! is what each operand is read or written as and where it is allowed to be, and that is the
31//! same whether the opcode becomes one instruction or four.
32//!
33//! Nothing here mentions flags. A comparison and the set that reads it are one opcode, and a
34//! shift reads the flags of nothing, so no instruction in this description has a flag operand
35//! and the allocator never sees one. That is a deliberate constraint on the rule set rather
36//! than a simplification of the machine.
37
38use crate::operand::{Constraint, OperandDesc};
39use crate::x86_64::{GPR, RAX, RCX, RDX, XMM, xmm};
40
41use Form::{
42 AluRi, AluRr, AluVec, ArgVal, ArgValVec, BrCond, Call, CmpSet, CmpSetVec, CmpSetVecBoth,
43 Convert, ConvertFromVec, ConvertToVec, ConvertVec, DivQuo, DivRem, Jcc, Jmp, Lea, Load,
44 LoadImm, LoadVec, Move, MoveVec, Pop, Push, Ret, RetVal, RetVal2, RetVal2Vec, RetValVec,
45 ShiftCl, ShiftRi, Store, StoreVec, Test, UnaryR,
46};
47
48/// The operand vector one machine instruction has.
49///
50/// A form rather than a list per opcode, because a hundred and fifty six opcodes have eleven
51/// answers between them and writing the eleven once is what makes a mistake in one of them a
52/// mistake a test can find.
53#[derive(Debug, Clone, Copy, PartialEq, Eq)]
54pub enum Form {
55 /// A destination and an immediate, which is `mov r, imm`.
56 LoadImm,
57 /// Two-address arithmetic on two registers: the destination is the first source, which the
58 /// allocator is the one that has to arrange.
59 AluRr,
60 /// Two-address arithmetic on a register and an immediate.
61 AluRi,
62 /// Two-address arithmetic on one register, which is negation and complement.
63 UnaryR,
64 /// A two-address shift by a constant.
65 ShiftRi,
66 /// A two-address shift by a count, which this machine reads from `cl` and nowhere else.
67 ShiftCl,
68 /// A comparison and the byte it sets, which writes a destination unrelated to either
69 /// source rather than destroying one of them.
70 CmpSet,
71 /// A move between widths, which reads one register and writes another.
72 Convert,
73 /// The quotient of a division, which comes back in `rax` and destroys `rdx` on the way.
74 DivQuo,
75 /// The remainder of a division, which comes back in `rdx` and destroys `rax` on the way.
76 DivRem,
77 /// An address computation, whose registers are in an addressing mode rather than in the
78 /// operand vector, and which the builder puts there.
79 Lea,
80 /// A load: a destination register, and an addressing mode the value comes from.
81 Load,
82 /// A store: an addressing mode the value goes to, and the register it comes out of. It
83 /// writes no register at all, which makes it the first form here with no definition in it.
84 Store,
85 /// The value a function gives back, in the register it is given back in.
86 ///
87 /// It is not the `ret` instruction and it encodes to nothing. What the selector can do about
88 /// a return is put the value where the caller will look for it, and what it cannot do is
89 /// leave, because the epilogue has to give the frame back first and the epilogue is written
90 /// long after selection has finished. So this is the whole of the return that a lowering rule
91 /// gets to decide, and `rucc_codegen::finish` appends the rest to the same block.
92 ///
93 /// The point of it surviving as an instruction rather than being nothing at all is the
94 /// operand: a read constrained to the return register is how the allocator is told to get
95 /// the value there, and it is what keeps the value alive that far.
96 RetVal,
97 /// The second register a value comes back in, when it takes two of them.
98 ///
99 /// [`Form::RetVal`] one place further along the convention's list of return registers. A
100 /// structure of at most sixteen bytes comes back in up to two registers, and which register
101 /// each half goes in is the classification's answer, so a return of two values is built from
102 /// the convention the way a call is rather than matched by a rule. There is no third of these
103 /// because no convention this target has returns in three registers.
104 RetVal2,
105 /// A value the caller already passed, in the register it arrived in.
106 ///
107 /// The mirror of [`Form::RetVal`] and the same kind of thing: it encodes to nothing, and what
108 /// it is for is telling the allocator where a value already is. A function's arguments are
109 /// there before its first instruction runs, so something has to define them, and a block
110 /// parameter cannot, because there is no edge into the entry block for a move to go on.
111 ///
112 /// Which register is not written here, unlike the return, because the answer depends on the
113 /// argument's position and on every argument before it. `rucc_codegen::abi` works that out
114 /// from the convention and puts it on the operand.
115 ArgVal,
116 /// The condition a block leaves on, in a register.
117 ///
118 /// The third form here that encodes to nothing, and the smallest. Where the two arms go is on
119 /// the block rather than on the instruction, so this says nothing about either of them: it
120 /// reads the condition, which keeps the value alive to the end of the block and gets it into
121 /// a register. What turns it into a test and a jump is the block layout, which is the only
122 /// thing that knows which of the two arms falls through and therefore which way round the
123 /// jump goes. What takes the test back out again, where the condition came from a comparison
124 /// that already set the flags, is the peephole pass `spec/10-backend.md` section 10.9
125 /// describes, and it is a rule like any other rule.
126 ///
127 /// An unconditional jump is not a form at all, because there is nothing left of one once the
128 /// edge is on the block.
129 BrCond,
130 /// A comparison of a register against itself, which is what asks whether it is zero.
131 ///
132 /// The first instruction here that sets the flags and says nothing about them, which is the
133 /// same arrangement every instruction here has: the flags are not an operand and the
134 /// allocator never sees one. What makes that sound is that this and the jump that reads it
135 /// are put in by the block layout, next to each other, after allocation has finished, so
136 /// there is nothing left that could put an instruction between them.
137 Test,
138 /// A jump taken when the flags say so, whose target is on the block.
139 ///
140 /// Where it goes is the block's first successor, for the reason every other arm is on the
141 /// block: an instruction is twenty four bytes and a block reference would not fit in one, and
142 /// the successors of a block are the thing every pass over the CFG already reads. The second
143 /// successor is where the block goes when the jump is not taken, and after the layout has run
144 /// that is always the block laid out next, which is why nothing is written for it.
145 Jcc,
146 /// A jump always taken, whose target is on the block.
147 ///
148 /// The one this becomes when the block it goes to is not the next block in the layout. A
149 /// block that falls into the next one has no jump at all, which is what laying blocks out in
150 /// a good order is worth.
151 Jmp,
152 /// A call, whose operand vector is not a fact about the instruction.
153 ///
154 /// Empty for a different reason than the jumps are. A jump has no operands because there is
155 /// nothing for it to read, and this has none because there is nothing true of
156 /// every call: how many values it passes, which registers they are in, whether anything comes
157 /// back and where, are all facts about the signature and the convention. So the operands of a
158 /// call are built where it is built, by `rucc_codegen::abi`, the same way an argument's
159 /// register is.
160 ///
161 /// What is the same about every call is the rest of it, and none of that is an operand
162 /// either. The registers the convention does not preserve are gone across it, which is said
163 /// with a definition per register that nothing reads, and that is what stops the allocator
164 /// from leaving a value in one. The bytes below the stack pointer the arguments that did not
165 /// fit in registers occupy are the frame's, which is why the selector reports how many a
166 /// function's widest call needs rather than writing anything about them here.
167 ///
168 /// A call through an address is the same form. The address is an operand and is a fact about
169 /// the instruction rather than about the signature, so it is the one operand of a call that
170 /// could have been written here, and it is not: an index into the operand vector is what a
171 /// row of this table names an operand by, and how many registers a call writes before it
172 /// reads anything is a different number for every call. What names it instead is
173 /// [`Arg::Through`](crate::x86_64::Arg::Through), which is the first operand read rather than
174 /// the operand at a place.
175 Call,
176 /// A copy from one general purpose register to another.
177 ///
178 /// The first form here no rule reaches. A copy is what the allocator writes when the two ends
179 /// of a value could not be given the same register, and what a prologue writes when it puts
180 /// the stack pointer in the frame pointer, and neither of those is a term a pattern could
181 /// match. It is a whole register at a time whatever the value in it is worth, because a copy
182 /// of half a register is a copy that has to know what the other half was for.
183 Move,
184 /// A register put on the stack, which is how a prologue saves one the convention preserves.
185 Push,
186 /// A register taken off it, which is how the epilogue gives it back.
187 Pop,
188 /// Leaving, which is the instruction a lowering rule cannot select for the reason
189 /// [`Form::RetVal`] gives: the frame has to be given back first and the frame is worked out
190 /// long after selection has finished.
191 Ret,
192 /// A copy from one vector register to another.
193 ///
194 /// The same thing as [`Form::Move`] and a separate form rather than the same one, because a
195 /// form is the class each of its operands is drawn from and these two are drawn from
196 /// different classes. That is also why there are three of these rather than one: a spill and
197 /// a reload of a vector register are a different instruction from a spill and a reload of a
198 /// general purpose one, and the allocator picks between them by asking the register file
199 /// which class the value is in.
200 MoveVec,
201 /// A vector register read back from the stack.
202 LoadVec,
203 /// A vector register written to it.
204 StoreVec,
205 /// Two-address arithmetic on two vector registers, which is every scalar floating point
206 /// operation this machine has.
207 ///
208 /// [`Form::AluRr`] in the other class and a separate form for the same reason the three moves
209 /// above are separate: a form is which class each of its operands comes from, and an allocator
210 /// handed the wrong one would put a float in a register that cannot hold one. The destination
211 /// reuses the first source here too, because `addsd` writes its answer over one of the two it
212 /// was given, exactly as `addq` does.
213 AluVec,
214 /// The value a function gives back, when it goes back in a vector register.
215 ///
216 /// [`Form::RetVal`] in the other class. It encodes to nothing for the same reason and exists
217 /// for the same reason: a read constrained to the register the convention returns in is how
218 /// the allocator is told where the value has to end up.
219 RetValVec,
220 /// [`Form::RetVal2`] in the other file.
221 RetVal2Vec,
222 /// A value the caller already passed, when it arrived in a vector register.
223 ///
224 /// [`Form::ArgVal`] in the other class, unconstrained here and constrained where it is built,
225 /// for the reason that one gives.
226 ArgValVec,
227 /// A conversion from one float format to the other, which reads a vector register and writes
228 /// one.
229 ///
230 /// [`Form::Convert`] in the other class, and the reason there are three of these is the reason
231 /// there are two of that: a form is which file each of its operands is drawn from, and a
232 /// conversion is the one kind of instruction here whose answer is not the same for both of
233 /// them. What the destination is not is a reuse of the source, which every other vector
234 /// instruction here is: `cvtss2sd` writes a register it did not read.
235 ConvertVec,
236 /// A conversion that reads a general purpose register and writes a vector one, which is an
237 /// integer becoming a float.
238 ConvertToVec,
239 /// A conversion that reads a vector register and writes a general purpose one, which is a
240 /// float becoming an integer.
241 ConvertFromVec,
242 /// A comparison of two floats and the byte it sets, which reads two vector registers and
243 /// writes a general purpose one.
244 ///
245 /// [`Form::CmpSet`] with the two sources in the other file. The destination is in this one
246 /// because a truth value is a byte and a byte is not a thing the vector registers hold: what
247 /// `ucomisd` writes is the flags, and reading the flags is `setcc` and nothing else.
248 CmpSetVec,
249 /// The same, when the condition takes two of those bytes and a boolean operation to spell.
250 ///
251 /// Two of the sixteen float comparisons are not one condition on this machine. `ucomisd` says
252 /// less, greater, equal or unordered in three flag bits, and every predicate but two is one of
253 /// those bits: equal on its own is the flag that means equal or unordered, so an ordered
254 /// equality is that flag and the one that says the operands were ordered, put together with an
255 /// `and`. Its negation is the other one, with an `or`.
256 ///
257 /// So the instruction writes a second byte it then reads back, and that byte is written here
258 /// as a second definition, the way `idiv` writes down the register it destroys on the way. It
259 /// is a register the allocator picks and nothing else can be in it, because a definition that
260 /// is live where the first one is live is a definition that cannot share with it.
261 CmpSetVecBoth,
262}
263
264// The destination of a two-address instruction is the operand after it, which is the first
265// source. Writing it as a reuse rather than as a copy is what lets the allocator put the two in
266// one register when the source dies here and insert the copy when it does not.
267static TWO_ADDRESS_RR: [OperandDesc; 3] = [
268 OperandDesc::write(GPR).with(Constraint::Reuse(1)),
269 OperandDesc::read(GPR),
270 OperandDesc::read(GPR),
271];
272static TWO_ADDRESS_RI: [OperandDesc; 2] =
273 [OperandDesc::write(GPR).with(Constraint::Reuse(1)), OperandDesc::read(GPR)];
274// The count is in `cl` because that is the only register this machine shifts by. It is the
275// whole of `rcx` as far as the allocator is concerned, since `cl` is part of `rcx` and nothing
276// else may be using the rest of it.
277static SHIFT_CL: [OperandDesc; 3] = [
278 OperandDesc::write(GPR).with(Constraint::Reuse(1)),
279 OperandDesc::read(GPR),
280 OperandDesc::read(GPR).with(Constraint::Fixed(RCX)),
281];
282static LOAD_IMM: [OperandDesc; 1] = [OperandDesc::write(GPR)];
283static ONE_TO_ONE: [OperandDesc; 2] = [OperandDesc::write(GPR), OperandDesc::read(GPR)];
284static TWO_TO_ONE: [OperandDesc; 3] =
285 [OperandDesc::write(GPR), OperandDesc::read(GPR), OperandDesc::read(GPR)];
286// The dividend is in `rax` and the divisor is anywhere else. A division produces both answers
287// and this opcode is one of them, so the register the other one lands in is written here as
288// well, and it is written early: the sign extension that fills it runs before the division
289// reads its divisor, so the divisor may not be sitting in it, and an early definition is how a
290// target says exactly that.
291static DIV_QUO: [OperandDesc; 4] = [
292 OperandDesc::write(GPR).with(Constraint::Fixed(RAX)),
293 OperandDesc::write_early(GPR).with(Constraint::Fixed(RDX)),
294 OperandDesc::read(GPR).with(Constraint::Fixed(RAX)),
295 OperandDesc::read(GPR),
296];
297static DIV_REM: [OperandDesc; 4] = [
298 OperandDesc::write(GPR).with(Constraint::Fixed(RDX)),
299 OperandDesc::write_early(GPR).with(Constraint::Fixed(RAX)),
300 OperandDesc::read(GPR).with(Constraint::Fixed(RAX)),
301 OperandDesc::read(GPR),
302];
303static ADDRESS: [OperandDesc; 1] = [OperandDesc::write(GPR)];
304// A load writes one register and reads none, because the registers it reads are the ones in
305// the addressing mode and the builder is what puts those in the vector.
306static LOAD: [OperandDesc; 1] = [OperandDesc::write(GPR)];
307// A store writes nothing. It is the first instruction here that produces no value, which is
308// what having an effect means, and the allocator needs no more than that: an instruction with
309// no definition keeps nothing alive past it.
310static STORE: [OperandDesc; 1] = [OperandDesc::read(GPR)];
311// An integer comes back in `rax` on every convention this machine has, which is why the register
312// is written here rather than read out of the convention the session was given. A test checks it
313// against `SYSV` and `WIN64` rather than leaving it as something a reader has to take on trust,
314// and a convention that ever disagrees is one that will fail that test rather than compile.
315static RET_VAL: [OperandDesc; 1] = [OperandDesc::read(GPR).with(Constraint::Fixed(RAX))];
316// The second half of a structure that comes back in two registers, which is `rdx` on the one
317// convention that has a second register to come back in. Written here for the reason above and
318// held against the convention by the same test.
319static RET_VAL_2: [OperandDesc; 1] = [OperandDesc::read(GPR).with(Constraint::Fixed(RDX))];
320// An argument is unconstrained here and constrained where it is built, because which register the
321// third argument is in is a fact about the convention and about the two arguments before it, and
322// none of that is available to a table of shapes. The class is the same reason: an argument in a
323// vector register is one of these too, with the class the convention names for it.
324static ARG_VAL: [OperandDesc; 1] = [OperandDesc::write(GPR)];
325// A condition is in any register at all, since the instruction this becomes is a `test` of a
326// register against itself and every general purpose register can be tested.
327static BR_COND: [OperandDesc; 1] = [OperandDesc::read(GPR)];
328// A call names no operand here at all, because none of them is a fact about the instruction. What
329// it passes and what comes back are facts about the signature it is made against.
330static CALL: [OperandDesc; 0] = [];
331// A test of a register against itself reads the same register twice. It is written once here,
332// because the two operands of the instruction are the same register and the allocator would
333// otherwise be free to put two different ones there.
334static TEST: [OperandDesc; 1] = [OperandDesc::read(GPR)];
335// A jump reads nothing and writes nothing. Where it goes is on the block, not in an operand.
336static JUMP: [OperandDesc; 0] = [];
337// A push reads a whole register and a pop writes one. Neither says anything about the stack
338// pointer, which every one of them moves: it is not an operand because nothing may be allocated
339// to it, and a frame that has one of these in it is a frame that has already accounted for the
340// eight bytes it costs.
341static PUSH: [OperandDesc; 1] = [OperandDesc::read(GPR)];
342static POP: [OperandDesc; 1] = [OperandDesc::write(GPR)];
343// Leaving reads the return address and writes the instruction pointer, and neither of those is a
344// register anything here can name, so it has no operands at all. What keeps the returned value
345// alive as far as this is the `ret_val` in front of it.
346static LEAVE: [OperandDesc; 0] = [];
347static VEC_TO_VEC: [OperandDesc; 2] = [OperandDesc::write(XMM), OperandDesc::read(XMM)];
348static LOAD_VEC: [OperandDesc; 1] = [OperandDesc::write(XMM)];
349static STORE_VEC: [OperandDesc; 1] = [OperandDesc::read(XMM)];
350// The same shape as `TWO_ADDRESS_RR` in the other class, and separate for the same reason the
351// three moves above are separate from the ones over them.
352static TWO_ADDRESS_VEC: [OperandDesc; 3] = [
353 OperandDesc::write(XMM).with(Constraint::Reuse(1)),
354 OperandDesc::read(XMM),
355 OperandDesc::read(XMM),
356];
357// A float comes back in `xmm0` on both of this machine's conventions, so the register is written
358// here for the reason `RET_VAL` gives, and the same test holds it against both of them.
359static RET_VAL_VEC: [OperandDesc; 1] = [OperandDesc::read(XMM).with(Constraint::Fixed(xmm(0)))];
360// [`RET_VAL_2`] in the other file, and `xmm1` for the same reason `rdx` is.
361static RET_VAL_2_VEC: [OperandDesc; 1] = [OperandDesc::read(XMM).with(Constraint::Fixed(xmm(1)))];
362static ARG_VAL_VEC: [OperandDesc; 1] = [OperandDesc::write(XMM)];
363// The two shapes that cross the files, which are the first operand lists here whose two entries
364// are not drawn from the same one. Nothing else about them is new: a conversion writes a register
365// it did not read, the same way `movzbq` does.
366static GPR_TO_VEC: [OperandDesc; 2] = [OperandDesc::write(XMM), OperandDesc::read(GPR)];
367static VEC_TO_GPR: [OperandDesc; 2] = [OperandDesc::write(GPR), OperandDesc::read(XMM)];
368// `TWO_TO_ONE` with the two sources in the other file, which is what comparing two floats and
369// setting a byte on the answer is.
370static VEC_TO_ONE: [OperandDesc; 3] =
371 [OperandDesc::write(GPR), OperandDesc::read(XMM), OperandDesc::read(XMM)];
372// The same with the spare byte the two conditions that take two `setcc` need. It is a definition
373// rather than a fixed register so that the allocator places it, and it is a definition at all so
374// that the allocator knows the instruction lands a value there: two definitions of one instruction
375// are live at the same point, so the register this gets is never the register the answer gets.
376static VEC_TO_ONE_BOTH: [OperandDesc; 4] = [
377 OperandDesc::write(GPR),
378 OperandDesc::write(GPR),
379 OperandDesc::read(XMM),
380 OperandDesc::read(XMM),
381];
382
383impl Form {
384 /// The operands of an instruction of this form, the ones it writes before the ones it
385 /// reads.
386 ///
387 /// The registers an addressing mode names are not here. They are operands and the allocator
388 /// rewrites them like any other, and `rucc_mir::InstBuilder::mem` is what puts them in the
389 /// vector, because the addressing mode holds their positions and a caller that had to keep
390 /// those positions right by hand would eventually not.
391 #[must_use]
392 pub fn operands(self) -> &'static [OperandDesc] {
393 match self {
394 LoadImm => &LOAD_IMM,
395 AluRr => &TWO_ADDRESS_RR,
396 AluRi | UnaryR | ShiftRi => &TWO_ADDRESS_RI,
397 ShiftCl => &SHIFT_CL,
398 CmpSet => &TWO_TO_ONE,
399 Convert => &ONE_TO_ONE,
400 DivQuo => &DIV_QUO,
401 DivRem => &DIV_REM,
402 Lea => &ADDRESS,
403 Load => &LOAD,
404 Store => &STORE,
405 RetVal => &RET_VAL,
406 RetVal2 => &RET_VAL_2,
407 ArgVal => &ARG_VAL,
408 BrCond => &BR_COND,
409 Call => &CALL,
410 Test => &TEST,
411 Jcc | Jmp => &JUMP,
412 Move => &ONE_TO_ONE,
413 Push => &PUSH,
414 Pop => &POP,
415 Ret => &LEAVE,
416 MoveVec => &VEC_TO_VEC,
417 LoadVec => &LOAD_VEC,
418 StoreVec => &STORE_VEC,
419 AluVec => &TWO_ADDRESS_VEC,
420 RetValVec => &RET_VAL_VEC,
421 RetVal2Vec => &RET_VAL_2_VEC,
422 ArgValVec => &ARG_VAL_VEC,
423 ConvertVec => &VEC_TO_VEC,
424 ConvertToVec => &GPR_TO_VEC,
425 ConvertFromVec => &VEC_TO_GPR,
426 CmpSetVec => &VEC_TO_ONE,
427 CmpSetVecBoth => &VEC_TO_ONE_BOTH,
428 }
429 }
430
431 /// Whether an instruction of this form carries an immediate.
432 #[must_use]
433 pub fn takes_imm(self) -> bool {
434 matches!(self, LoadImm | AluRi | ShiftRi)
435 }
436
437 /// Whether an instruction of this form carries an addressing mode.
438 #[must_use]
439 pub fn takes_mem(self) -> bool {
440 matches!(self, Lea | Load | Store | LoadVec | StoreVec)
441 }
442}
443
444/// Every opcode the x86-64 rule set can produce, and the form of each.
445///
446/// Grouped by family and by width rather than sorted, because this is a list a person checks
447/// against a manual and the manual is organized the same way. A lookup is a scan, which is what
448/// a selector does once per instruction it emits.
449pub static INSTS: &[(&str, Form)] = &[
450 // Constants.
451 ("mov_ri_8", LoadImm),
452 ("mov_ri_16", LoadImm),
453 ("mov_ri_32", LoadImm),
454 ("mov_ri_64", LoadImm),
455 // Arithmetic, register with register.
456 ("add_rr_8", AluRr),
457 ("add_rr_16", AluRr),
458 ("add_rr_32", AluRr),
459 ("add_rr_64", AluRr),
460 ("sub_rr_8", AluRr),
461 ("sub_rr_16", AluRr),
462 ("sub_rr_32", AluRr),
463 ("sub_rr_64", AluRr),
464 ("and_rr_8", AluRr),
465 ("and_rr_16", AluRr),
466 ("and_rr_32", AluRr),
467 ("and_rr_64", AluRr),
468 ("or_rr_8", AluRr),
469 ("or_rr_16", AluRr),
470 ("or_rr_32", AluRr),
471 ("or_rr_64", AluRr),
472 ("xor_rr_8", AluRr),
473 ("xor_rr_16", AluRr),
474 ("xor_rr_32", AluRr),
475 ("xor_rr_64", AluRr),
476 ("imul_rr_8", AluRr),
477 ("imul_rr_16", AluRr),
478 ("imul_rr_32", AluRr),
479 ("imul_rr_64", AluRr),
480 // Arithmetic, register with immediate.
481 ("add_ri_8", AluRi),
482 ("add_ri_16", AluRi),
483 ("add_ri_32", AluRi),
484 ("add_ri_64", AluRi),
485 ("sub_ri_8", AluRi),
486 ("sub_ri_16", AluRi),
487 ("sub_ri_32", AluRi),
488 ("sub_ri_64", AluRi),
489 ("and_ri_8", AluRi),
490 ("and_ri_16", AluRi),
491 ("and_ri_32", AluRi),
492 ("and_ri_64", AluRi),
493 ("or_ri_8", AluRi),
494 ("or_ri_16", AluRi),
495 ("or_ri_32", AluRi),
496 ("or_ri_64", AluRi),
497 ("xor_ri_8", AluRi),
498 ("xor_ri_16", AluRi),
499 ("xor_ri_32", AluRi),
500 ("xor_ri_64", AluRi),
501 ("imul_ri_8", AluRi),
502 ("imul_ri_16", AluRi),
503 ("imul_ri_32", AluRi),
504 ("imul_ri_64", AluRi),
505 // Negation and complement.
506 ("neg_r_8", UnaryR),
507 ("neg_r_16", UnaryR),
508 ("neg_r_32", UnaryR),
509 ("neg_r_64", UnaryR),
510 ("not_r_8", UnaryR),
511 ("not_r_16", UnaryR),
512 ("not_r_32", UnaryR),
513 ("not_r_64", UnaryR),
514 // Division and remainder, signed and unsigned.
515 ("idiv_quo_8", DivQuo),
516 ("idiv_quo_16", DivQuo),
517 ("idiv_quo_32", DivQuo),
518 ("idiv_quo_64", DivQuo),
519 ("idiv_rem_8", DivRem),
520 ("idiv_rem_16", DivRem),
521 ("idiv_rem_32", DivRem),
522 ("idiv_rem_64", DivRem),
523 ("div_quo_8", DivQuo),
524 ("div_quo_16", DivQuo),
525 ("div_quo_32", DivQuo),
526 ("div_quo_64", DivQuo),
527 ("div_rem_8", DivRem),
528 ("div_rem_16", DivRem),
529 ("div_rem_32", DivRem),
530 ("div_rem_64", DivRem),
531 // Shifts by a constant.
532 ("shl_ri_8", ShiftRi),
533 ("shl_ri_16", ShiftRi),
534 ("shl_ri_32", ShiftRi),
535 ("shl_ri_64", ShiftRi),
536 ("shr_ri_8", ShiftRi),
537 ("shr_ri_16", ShiftRi),
538 ("shr_ri_32", ShiftRi),
539 ("shr_ri_64", ShiftRi),
540 ("sar_ri_8", ShiftRi),
541 ("sar_ri_16", ShiftRi),
542 ("sar_ri_32", ShiftRi),
543 ("sar_ri_64", ShiftRi),
544 // Shifts by a register, which is `cl` and nothing else.
545 ("shl_rcl_8", ShiftCl),
546 ("shl_rcl_16", ShiftCl),
547 ("shl_rcl_32", ShiftCl),
548 ("shl_rcl_64", ShiftCl),
549 ("shr_rcl_8", ShiftCl),
550 ("shr_rcl_16", ShiftCl),
551 ("shr_rcl_32", ShiftCl),
552 ("shr_rcl_64", ShiftCl),
553 ("sar_rcl_8", ShiftCl),
554 ("sar_rcl_16", ShiftCl),
555 ("sar_rcl_32", ShiftCl),
556 ("sar_rcl_64", ShiftCl),
557 // The comparisons, ten conditions at four widths.
558 ("cmp_set_e_8", CmpSet),
559 ("cmp_set_e_16", CmpSet),
560 ("cmp_set_e_32", CmpSet),
561 ("cmp_set_e_64", CmpSet),
562 ("cmp_set_ne_8", CmpSet),
563 ("cmp_set_ne_16", CmpSet),
564 ("cmp_set_ne_32", CmpSet),
565 ("cmp_set_ne_64", CmpSet),
566 ("cmp_set_l_8", CmpSet),
567 ("cmp_set_l_16", CmpSet),
568 ("cmp_set_l_32", CmpSet),
569 ("cmp_set_l_64", CmpSet),
570 ("cmp_set_le_8", CmpSet),
571 ("cmp_set_le_16", CmpSet),
572 ("cmp_set_le_32", CmpSet),
573 ("cmp_set_le_64", CmpSet),
574 ("cmp_set_g_8", CmpSet),
575 ("cmp_set_g_16", CmpSet),
576 ("cmp_set_g_32", CmpSet),
577 ("cmp_set_g_64", CmpSet),
578 ("cmp_set_ge_8", CmpSet),
579 ("cmp_set_ge_16", CmpSet),
580 ("cmp_set_ge_32", CmpSet),
581 ("cmp_set_ge_64", CmpSet),
582 ("cmp_set_b_8", CmpSet),
583 ("cmp_set_b_16", CmpSet),
584 ("cmp_set_b_32", CmpSet),
585 ("cmp_set_b_64", CmpSet),
586 ("cmp_set_be_8", CmpSet),
587 ("cmp_set_be_16", CmpSet),
588 ("cmp_set_be_32", CmpSet),
589 ("cmp_set_be_64", CmpSet),
590 ("cmp_set_a_8", CmpSet),
591 ("cmp_set_a_16", CmpSet),
592 ("cmp_set_a_32", CmpSet),
593 ("cmp_set_a_64", CmpSet),
594 ("cmp_set_ae_8", CmpSet),
595 ("cmp_set_ae_16", CmpSet),
596 ("cmp_set_ae_32", CmpSet),
597 ("cmp_set_ae_64", CmpSet),
598 // The conversions between widths.
599 ("movzx_8_16", Convert),
600 ("movzx_8_32", Convert),
601 ("movzx_8_64", Convert),
602 ("movzx_16_32", Convert),
603 ("movzx_16_64", Convert),
604 ("mov_32_to_64", Convert),
605 ("movsx_8_16", Convert),
606 ("movsx_8_32", Convert),
607 ("movsx_8_64", Convert),
608 ("movsx_16_32", Convert),
609 ("movsx_16_64", Convert),
610 ("movsxd_32_64", Convert),
611 // Widening a truth value, which the machine does with the byte widenings above because it
612 // has no narrower register than a byte. Separate names, because what these mean is what the
613 // instruction does to the one bit rather than to the byte holding it.
614 ("bit_to_8", Convert),
615 ("bit_to_16", Convert),
616 ("bit_to_32", Convert),
617 ("bit_to_64", Convert),
618 ("low_8", Convert),
619 ("low_16", Convert),
620 ("low_32", Convert),
621 // The address computation the addressing modes are reached through.
622 ("lea_64", Lea),
623 // Reading and writing memory, at each width the machine has a `mov` for.
624 ("mov_rm_8", Load),
625 ("mov_rm_16", Load),
626 ("mov_rm_32", Load),
627 ("mov_rm_64", Load),
628 ("mov_mr_8", Store),
629 ("mov_mr_16", Store),
630 ("mov_mr_32", Store),
631 ("mov_mr_64", Store),
632 // Putting the value a function gives back where the caller looks for it, which is as much of
633 // a return as a lowering rule decides.
634 ("ret_val_8", RetVal),
635 ("ret_val_16", RetVal),
636 ("ret_val_32", RetVal),
637 ("ret_val_64", RetVal),
638 // The same job for a float, which is a separate opcode rather than a wider one because the
639 // register it names is in the other file. A `float` and a `double` are both `xmm0` and are
640 // still two opcodes, so that the type a function returns survives as far as the machine IR
641 // and a listing says which of the two the program meant.
642 ("ret_val_f32", RetValVec),
643 ("ret_val_f64", RetValVec),
644 // The second half of a structure that comes back in two registers, at every width a half can
645 // be. The narrow ones are not a rounding of the wide one: the second eightbyte of a nine byte
646 // structure is one byte, and saying so is what keeps a listing honest about how much of the
647 // register the program meant.
648 ("ret_val2_8", RetVal2),
649 ("ret_val2_16", RetVal2),
650 ("ret_val2_32", RetVal2),
651 ("ret_val2_64", RetVal2),
652 ("ret_val2_f32", RetVal2Vec),
653 ("ret_val2_f64", RetVal2Vec),
654 // Naming the register an argument arrived in, which is the other half of the same job and is
655 // the one thing here no lowering rule reaches: where an argument is depends on its position
656 // and a rule pattern cannot see one.
657 ("arg_val_8", ArgVal),
658 ("arg_val_16", ArgVal),
659 ("arg_val_32", ArgVal),
660 ("arg_val_64", ArgVal),
661 ("arg_val_f32", ArgValVec),
662 ("arg_val_f64", ArgValVec),
663 // The condition a block leaves on, which is as much of a conditional branch as a lowering
664 // rule decides, since which arm falls through is the block layout's answer.
665 ("br_cond_8", BrCond),
666 // A call, which names nothing here because nothing about its operands is the same from one
667 // call to the next. Through an address it is the same instruction to the machine and a
668 // different one to the assembler, which writes the register with a star in front of it, and
669 // that is the whole of why there are two names here rather than one.
670 ("call", Call),
671 ("call_reg", Call),
672 // What a condition and the block layout come to. The test asks whether the byte a comparison
673 // wrote is zero, and the jump that follows it goes to the block's first successor when the
674 // answer is the one it names. `jcc_e` is the one written when the block falls through to the
675 // arm the condition is true for, and `jcc_ne` the one written when it falls through to the
676 // other, which is why both are here and neither is more natural than the other.
677 ("test_rr_8", Test),
678 ("jcc_e", Jcc),
679 ("jcc_ne", Jcc),
680 ("jmp", Jmp),
681 // What a copy, a prologue, an epilogue, a spill and a reload are made of, which is the other
682 // set of instructions no rule reaches. The arithmetic and the address computation a frame
683 // needs are already above, because a prologue taking its frame is the same instruction as a
684 // subtraction the program wrote and the encoder should not have two answers for it.
685 ("mov_rr_64", Move),
686 ("push_64", Push),
687 ("pop_64", Pop),
688 ("ret", Ret),
689 ("movaps_rr", MoveVec),
690 ("movaps_rm", LoadVec),
691 ("movaps_mr", StoreVec),
692 // Reading one value out of memory and writing one back, which is the same two shapes as the
693 // spill and the reload above and a different instruction: those move a whole register because
694 // a spill slot holds whatever was in it, and these move exactly the width of the value because
695 // that is all the program asked for.
696 ("movss_rm", LoadVec),
697 ("movsd_rm", LoadVec),
698 ("movss_mr", StoreVec),
699 ("movsd_mr", StoreVec),
700 ("addss_rr", AluVec),
701 ("addsd_rr", AluVec),
702 ("subss_rr", AluVec),
703 ("subsd_rr", AluVec),
704 ("mulss_rr", AluVec),
705 ("mulsd_rr", AluVec),
706 ("divss_rr", AluVec),
707 ("divsd_rr", AluVec),
708 // The conversions, which are the instructions that cross between the two register files and
709 // the two float formats. Ten of them, which is one for each pair of things a C program is
710 // allowed to convert between here: the two formats in both directions, and each format with a
711 // thirty two and a sixty four bit integer in both directions.
712 ("cvtss2sd", ConvertVec),
713 ("cvtsd2ss", ConvertVec),
714 ("cvttss2si_32", ConvertFromVec),
715 ("cvttss2si_64", ConvertFromVec),
716 ("cvttsd2si_32", ConvertFromVec),
717 ("cvttsd2si_64", ConvertFromVec),
718 ("cvtsi2ss_32", ConvertToVec),
719 ("cvtsi2ss_64", ConvertToVec),
720 ("cvtsi2sd_32", ConvertToVec),
721 ("cvtsi2sd_64", ConvertToVec),
722 // The same bits in the other file, which is not a conversion at all: it is where the value is
723 // kept and nothing about what it is worth. That is what a `bitcast` between an integer and a
724 // float of the same width is, and it is the same instruction each way with the two arguments
725 // swapped.
726 ("movd_to_xmm", ConvertToVec),
727 ("movq_to_xmm", ConvertToVec),
728 ("movd_from_xmm", ConvertFromVec),
729 ("movq_from_xmm", ConvertFromVec),
730 // Comparing two floats, which is one instruction that writes flags and one that reads them,
731 // the same pair the integer comparisons above are. Ten per format rather than one per
732 // predicate, because the machine has four answers and a C program has sixteen questions: the
733 // eight here are the eight the flags answer directly, and the two after them are the two
734 // that take both a flag and the bit that says whether the comparison meant anything.
735 //
736 // The predicates that are not here are the ones that are one of these with the operands the
737 // other way round, which is a fact about the rule rather than about the instruction.
738 ("ucomiss_set_a", CmpSetVec),
739 ("ucomiss_set_ae", CmpSetVec),
740 ("ucomiss_set_b", CmpSetVec),
741 ("ucomiss_set_be", CmpSetVec),
742 ("ucomiss_set_e", CmpSetVec),
743 ("ucomiss_set_ne", CmpSetVec),
744 ("ucomiss_set_p", CmpSetVec),
745 ("ucomiss_set_np", CmpSetVec),
746 ("ucomiss_set_e_and_np", CmpSetVecBoth),
747 ("ucomiss_set_ne_or_p", CmpSetVecBoth),
748 ("ucomisd_set_a", CmpSetVec),
749 ("ucomisd_set_ae", CmpSetVec),
750 ("ucomisd_set_b", CmpSetVec),
751 ("ucomisd_set_be", CmpSetVec),
752 ("ucomisd_set_e", CmpSetVec),
753 ("ucomisd_set_ne", CmpSetVec),
754 ("ucomisd_set_p", CmpSetVec),
755 ("ucomisd_set_np", CmpSetVec),
756 ("ucomisd_set_e_and_np", CmpSetVecBoth),
757 ("ucomisd_set_ne_or_p", CmpSetVecBoth),
758];
759
760/// The form of the opcode of that name, or `None` for a name this target does not have.
761///
762/// The name is written the way the machine IR holds it, so `add_rr_32` rather than
763/// `x64.add_rr_32`. The prefix is how a rule file says which target a term belongs to and it is
764/// not part of the opcode.
765#[must_use]
766pub fn form(name: &str) -> Option<Form> {
767 INSTS.iter().find(|(known, _)| *known == name).map(|&(_, form)| form)
768}
769
770/// What an address constructor's arguments are.
771///
772/// An addressing mode is an argument to an instruction rather than an instruction, and a rule
773/// file writes one as a term so that a rule can say which registers go where. The selector has
774/// to turn that term into a machine IR memory operand, and what each constructor's arguments
775/// mean is the same kind of target fact as [`Form`], so it is written here rather than in the
776/// selector.
777///
778/// The scale and the displacement are arguments rather than part of the name because each is a
779/// number the rule matched and the machine encodes it as a number. There is none with a symbol
780/// yet, because the rules that would need one are the ones about a global and those are not
781/// written.
782///
783/// What the arguments mean is the whole of what tells these apart, and there is deliberately no
784/// predicate here that answers half the question: the same register is a base in one of these
785/// and an index in another, and the same constant is a scale in one and a displacement in
786/// another, so anything building an address out of one has to look at which it is.
787#[derive(Debug, Clone, Copy, PartialEq, Eq)]
788pub enum Address {
789 /// A base register, an index register and a scale, in that order.
790 BaseIndexScale,
791 /// An index register and a scale, which is an address with nothing to add it to.
792 IndexScale,
793 /// A base register on its own, which is what a pointer already in a register is.
794 Base,
795 /// A base register and a constant added to it, which is every field of a structure and
796 /// every local reached through a frame pointer.
797 BaseOffset,
798}
799
800/// Every address constructor the x86-64 rule set can write, and what its arguments are.
801pub static ADDRESSES: &[(&str, Address)] = &[
802 ("amode_base_index_scale", Address::BaseIndexScale),
803 ("amode_index_scale", Address::IndexScale),
804 ("amode_base", Address::Base),
805 ("amode_base_offset", Address::BaseOffset),
806];
807
808/// The address constructor of that name, or `None` for a name that is not one.
809///
810/// This is what tells an instruction head from an address head, so a selector asks it before it
811/// decides that a term it does not recognize is an error.
812#[must_use]
813pub fn address(name: &str) -> Option<Address> {
814 ADDRESSES.iter().find(|(known, _)| *known == name).map(|&(_, kind)| kind)
815}
816
817#[cfg(test)]
818mod tests {
819 use super::*;
820 use crate::operand::Role;
821 use crate::x86_64::{FRAME, SYSV, WIN64};
822
823 #[test]
824 fn every_opcode_is_described_once() {
825 let mut names: Vec<&str> = INSTS.iter().map(|&(name, _)| name).collect();
826 let described = names.len();
827 names.sort_unstable();
828 names.dedup();
829 assert_eq!(names.len(), described, "an opcode is described twice");
830 // Every head in the model file, which is what the rule set may write and what
831 // `rucc-verify` has an answer for. The two lists are checked against each other by
832 // `rucc-codegen`, which is the crate that can read the rule set.
833 assert_eq!(described, 246);
834 }
835
836 #[test]
837 fn a_shape_writes_before_it_reads() {
838 for &(name, form) in INSTS {
839 let operands = form.operands();
840 let defs = operands.iter().filter(|operand| operand.role.is_def()).count();
841 assert!(
842 operands[..defs].iter().all(|operand| operand.role.is_def()),
843 "{name} writes an operand after one it reads"
844 );
845 // An instruction that writes no register at all is one whose whole purpose is what it
846 // does rather than what it computes. A store writes memory, a return puts a value
847 // where the caller will look, a branch puts a condition where the jump that the
848 // layout writes can read it, a test sets the flags, a jump goes somewhere, a push
849 // puts a register on the stack and leaving leaves. Everything else here computes
850 // something, and an opcode that computes nothing and does nothing either would be an
851 // opcode nothing has any reason to select.
852 assert!(
853 defs > 0
854 || matches!(
855 form,
856 Store
857 | RetVal
858 | RetVal2
859 | RetValVec
860 | RetVal2Vec
861 | BrCond
862 | Call
863 | Test
864 | Jcc
865 | Jmp
866 | Push
867 | Ret
868 | StoreVec
869 ),
870 "{name} writes nothing and does nothing"
871 );
872 }
873 }
874
875 #[test]
876 fn a_two_address_form_ties_its_destination_to_its_first_source() {
877 for form in [AluRr, AluRi, UnaryR, ShiftRi, ShiftCl, AluVec] {
878 assert_eq!(form.operands()[0].constraint, Constraint::Reuse(1));
879 }
880 // The float arithmetic is in the other class throughout, which is the whole reason it is a
881 // separate form from the integer arithmetic it is otherwise shaped exactly like.
882 assert!(AluVec.operands().iter().all(|operand| operand.class == XMM));
883 assert!(AluRr.operands().iter().all(|operand| operand.class == GPR));
884 // A comparison writes a byte that has nothing to do with either operand, and a
885 // conversion reads one width and writes another, so neither destroys its source.
886 for form in [CmpSet, CmpSetVec, CmpSetVecBoth, Convert, LoadImm, Lea] {
887 assert_eq!(form.operands()[0].constraint, Constraint::Reg);
888 }
889 }
890
891 #[test]
892 fn a_division_names_the_registers_the_machine_insists_on() {
893 let quo = DivQuo.operands();
894 assert_eq!(quo[0].constraint, Constraint::Fixed(RAX));
895 assert_eq!(quo[1].constraint, Constraint::Fixed(RDX));
896 assert_eq!(quo[1].role, Role::EarlyDef, "the divisor may not be where the rest goes");
897 assert_eq!(quo[2].constraint, Constraint::Fixed(RAX));
898 assert_eq!(quo[3].constraint, Constraint::Reg);
899 let rem = DivRem.operands();
900 assert_eq!(rem[0].constraint, Constraint::Fixed(RDX));
901 assert_eq!(rem[1].constraint, Constraint::Fixed(RAX));
902 }
903
904 #[test]
905 fn a_return_leaves_the_value_where_both_conventions_look_for_it() {
906 // The register in the form is written down rather than read out of a convention, so this
907 // is where the two are checked against each other. Both conventions this target has agree
908 // about it, and one that did not would fail here rather than compile a function whose
909 // caller reads a register nothing was put in.
910 assert_eq!(RetVal.operands()[0].constraint, Constraint::Fixed(RAX));
911 assert_eq!(SYSV.int_returns.first(), Some(&RAX));
912 assert_eq!(WIN64.int_returns.first(), Some(&RAX));
913 // It writes nothing, because the value is the caller's and this function has finished
914 // with it.
915 assert_eq!(RetVal.operands().len(), 1);
916 assert!(!RetVal.takes_imm() && !RetVal.takes_mem());
917
918 // The same claim about a float, which comes back in the first vector register on both.
919 assert_eq!(RetValVec.operands()[0].constraint, Constraint::Fixed(xmm(0)));
920 assert_eq!(SYSV.sse_returns.first(), Some(&xmm(0)));
921 assert_eq!(WIN64.sse_returns.first(), Some(&xmm(0)));
922 assert_eq!(RetValVec.operands()[0].class, XMM);
923 }
924
925 /// The second register, which only one of the two conventions has. Written down here the way
926 /// the first one is, and held against the convention the same way, so that a convention which
927 /// grew a different second register would fail here rather than compile a function whose
928 /// caller reads the wrong half of a structure.
929 #[test]
930 fn the_second_half_of_a_structure_comes_back_where_sysv_says_it_does() {
931 assert_eq!(RetVal2.operands()[0].constraint, Constraint::Fixed(RDX));
932 assert_eq!(SYSV.int_returns.get(1), Some(&RDX));
933 assert_eq!(RetVal2Vec.operands()[0].constraint, Constraint::Fixed(xmm(1)));
934 assert_eq!(SYSV.sse_returns.get(1), Some(&xmm(1)));
935 assert_eq!(RetVal2Vec.operands()[0].class, XMM);
936
937 // Windows returns a structure of more than eight bytes through a hidden pointer instead,
938 // so it has no second register and nothing here should ever select one of these for it.
939 assert_eq!(WIN64.int_returns.get(1), None);
940 assert_eq!(WIN64.sse_returns.get(1), None);
941 }
942
943 #[test]
944 fn an_argument_names_no_register_because_its_position_is_what_says_which_one() {
945 // The opposite of the return above, and deliberately so. Writing `rdi` here would be
946 // writing down where the first SysV integer argument is and then being wrong about every
947 // other argument and about Windows, so the register is put on the operand by the code
948 // that knows the position.
949 assert_eq!(ArgVal.operands()[0].constraint, Constraint::Reg);
950 assert_eq!(ArgVal.operands()[0].role, Role::Def);
951 assert_eq!(ArgVal.operands().len(), 1);
952 assert!(!ArgVal.takes_imm() && !ArgVal.takes_mem());
953
954 assert_eq!(ArgValVec.operands()[0].constraint, Constraint::Reg);
955 assert_eq!(ArgValVec.operands()[0].role, Role::Def);
956 assert_eq!(ArgValVec.operands()[0].class, XMM);
957 }
958
959 #[test]
960 fn a_shift_by_a_register_wants_it_in_cl() {
961 assert_eq!(ShiftCl.operands()[2].constraint, Constraint::Fixed(RCX));
962 assert!(!ShiftCl.takes_imm());
963 assert!(ShiftRi.takes_imm());
964 }
965
966 #[test]
967 fn only_the_shapes_that_carry_one_carry_an_immediate_or_an_address() {
968 assert!(LoadImm.takes_imm() && AluRi.takes_imm() && ShiftRi.takes_imm());
969 assert!(!AluRr.takes_imm() && !CmpSet.takes_imm() && !DivQuo.takes_imm());
970 assert!(Lea.takes_mem());
971 assert!(!AluRr.takes_mem() && !LoadImm.takes_mem());
972 }
973
974 #[test]
975 fn an_address_constructor_is_not_an_instruction() {
976 assert_eq!(address("amode_base_index_scale"), Some(Address::BaseIndexScale));
977 assert_eq!(address("amode_base_offset"), Some(Address::BaseOffset));
978 assert_eq!(address("amode_base"), Some(Address::Base));
979 assert_eq!(address("lea_64"), None);
980 assert_eq!(form("amode_index_scale"), None);
981 }
982
983 /// The block layout reads the four names out of [`crate::x86_64::BRANCH`] and writes them
984 /// into the machine IR without ever asking what any of them is, so a name there that is not
985 /// an opcode here would come out as an instruction nothing further along could describe. The
986 /// forms are pinned too, because the layout writes one shape each and a name that turned out
987 /// to be an ordinary two-address instruction would be written with no operands at all.
988 #[test]
989 fn every_instruction_the_block_layout_writes_is_described_here() {
990 use crate::x86_64::BRANCH;
991
992 assert_eq!(BRANCH.prefix, FRAME.prefix, "one target, one prefix");
993 assert_eq!(form(BRANCH.cond), Some(BrCond));
994 assert_eq!(form(BRANCH.test), Some(Test));
995 assert_eq!(form(BRANCH.if_true), Some(Jcc));
996 assert_eq!(form(BRANCH.if_false), Some(Jcc));
997 assert_eq!(form(BRANCH.jump), Some(Jmp));
998 assert_ne!(BRANCH.if_true, BRANCH.if_false, "the two arms are not the same jump");
999 }
1000
1001 /// The same claim about the other set of instructions nothing selects.
1002 ///
1003 /// `rucc_codegen::finish` reads these names out of [`crate::x86_64::FRAME`] and writes them
1004 /// into the machine IR, and until this table covered them there was nothing that could say
1005 /// what a push does with its operand. Six of the twelve names are shared with the rules, since
1006 /// a prologue taking its frame is a subtraction and a spill is a store, and the test says so
1007 /// by asking about the form rather than about which list the name came from.
1008 #[test]
1009 fn every_instruction_a_frame_is_made_of_is_described_here() {
1010 assert_eq!(form(FRAME.push), Some(Push));
1011 assert_eq!(form(FRAME.pop), Some(Pop));
1012 assert_eq!(form(FRAME.ret), Some(Ret));
1013 assert_eq!(form(FRAME.add), Some(AluRi));
1014 assert_eq!(form(FRAME.sub), Some(AluRi));
1015 assert_eq!(form(FRAME.align), Some(AluRi));
1016 assert_eq!(form(FRAME.lea), Some(Lea));
1017
1018 // One set of moves per class the allocator may spill, and the class each of them is
1019 // written for is the class the form draws its operands from.
1020 let gpr = FRAME.classes[GPR.number() as usize];
1021 assert_eq!(form(gpr.mov), Some(Move));
1022 assert_eq!(form(gpr.load), Some(Load));
1023 assert_eq!(form(gpr.store), Some(Store));
1024 let xmm = FRAME.classes[XMM.number() as usize];
1025 assert_eq!(form(xmm.mov), Some(MoveVec));
1026 assert_eq!(form(xmm.load), Some(LoadVec));
1027 assert_eq!(form(xmm.store), Some(StoreVec));
1028 assert_eq!(MoveVec.operands()[0].class, XMM);
1029 assert_eq!(Move.operands()[0].class, GPR);
1030 }
1031
1032 #[test]
1033 fn an_opcode_is_found_by_the_name_the_machine_ir_holds() {
1034 assert_eq!(form("add_rr_32"), Some(AluRr));
1035 assert_eq!(form("shl_rcl_64"), Some(ShiftCl));
1036 assert_eq!(form("lea_64"), Some(Lea));
1037 assert_eq!(form("x64.add_rr_32"), None, "the prefix is not part of the opcode");
1038 assert_eq!(form("add_rr_128"), None);
1039 }
1040}