Skip to main content

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}