rucc_target/regs.rs
1//! The register file: what registers a target has, and what classes they fall into.
2//!
3//! Design: `spec/10-backend.md` section 10.8.
4//!
5//! A register file is data rather than code, which is the same claim the rest of this crate
6//! makes and the one `M10` puts a number on. A class is a set of registers that an operand of
7//! that class may be assigned to, and a physical register is its number inside its class, so
8//! the allocator works in dense small integers and only the printer and the parser ever deal in
9//! names.
10//!
11//! The file lives here rather than in `rucc-mir` because more than one thing reads it. The
12//! machine IR needs it to print, the allocator needs the set it may assign from, and the ABI
13//! description needs to name the registers arguments arrive in. All three are above this crate,
14//! and the alternative is the register file living in whichever of them happens to be lowest,
15//! which is how a layering ends up describing itself as historical.
16//!
17//! Names are unique across the whole file, not merely inside a class. That is what lets a
18//! register be written `$rax` in a dump rather than `$gpr.0`, and it is a real constraint on a
19//! target that gives one register two classes: it has to say which class it is in, or use two
20//! names. [`RegFile::duplicate`] is what a target's own test asks to find out.
21
22use std::fmt;
23
24use rucc_abi::{AbiDescription, StackArgs};
25
26/// One class of registers, and the registers in it.
27#[derive(Debug, Clone, Copy, PartialEq, Eq)]
28pub struct ClassInfo {
29 /// What the class is called in a dump, such as `gpr`.
30 pub name: &'static str,
31 /// How wide one of its registers is, in bits.
32 pub bits: u32,
33 /// The registers, in the order their numbers run, without the sigil a dump writes.
34 pub regs: &'static [&'static str],
35 /// Whether the allocator may put a value in one of these.
36 ///
37 /// True for every class a target means the allocator to use, which is nearly all of them.
38 /// False says the registers exist and are named and are not somewhere a value may be told to
39 /// live, so a virtual register of this class is a mistake at the point it was made rather than
40 /// a value the allocator has nowhere to put.
41 ///
42 /// The x87 stack is the case this exists for, and it is worth the sentence because it is not
43 /// the usual reason a register is unavailable. `rsp` is unavailable because it has a job;
44 /// `st0` is unavailable because the machine addresses it as a stack, so which register a name
45 /// means depends on how many values are on the stack at the time, and an allocator that hands
46 /// out a name has no way to say that. So nothing allocates from it, an eighty bit value lives
47 /// in a stack slot between one operation and the next, and the stack is empty on both sides of
48 /// every group of instructions that uses it. See `spec/10-backend.md` section 10.8, which says
49 /// what a group is and why nothing the allocator inserts can get into the middle of one, and
50 /// tamnd/rucc#540.
51 ///
52 /// A register in such a class can still be named, which is the whole reason the class is
53 /// described at all: a `long double` comes back from a call in `st0` and the convention has to
54 /// be able to say so.
55 pub allocatable: bool,
56}
57
58/// Which class a register or an operand belongs to.
59///
60/// A number into the file's classes rather than a name, because it is on every operand of every
61/// instruction and it is compared far more often than it is printed.
62#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
63pub struct RegClass(u8);
64
65impl RegClass {
66 /// The class with that number.
67 #[must_use]
68 pub const fn new(number: u8) -> Self {
69 Self(number)
70 }
71
72 /// Its number, which is what indexes the file.
73 #[must_use]
74 pub const fn number(self) -> u8 {
75 self.0
76 }
77}
78
79/// One physical register, as its number inside its class.
80///
81/// The class is not in here. An operand carries its class already, and a fixed-register
82/// constraint is a constraint on an operand, so repeating the class would be a second copy of
83/// something that can disagree with the first.
84#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
85pub struct PhysReg(u8);
86
87impl PhysReg {
88 /// The register with that number in its class.
89 #[must_use]
90 pub const fn new(number: u8) -> Self {
91 Self(number)
92 }
93
94 /// Its number inside its class.
95 #[must_use]
96 pub const fn number(self) -> u8 {
97 self.0
98 }
99}
100
101/// Every register a target has.
102#[derive(Debug, Clone, Copy, PartialEq, Eq)]
103pub struct RegFile {
104 classes: &'static [ClassInfo],
105}
106
107impl RegFile {
108 /// The file of a target whose registers nothing has described yet.
109 ///
110 /// A target reaches 1.0 with a real one. Until it has one, the honest answer to what
111 /// registers it has is that nobody has written them down, and that is a file with no
112 /// classes in it rather than a panic or a plausible guess.
113 pub const EMPTY: Self = Self::new(&[]);
114
115 /// A file made of those classes, numbered in the order they are given.
116 #[must_use]
117 pub const fn new(classes: &'static [ClassInfo]) -> Self {
118 Self { classes }
119 }
120
121 /// Its classes, each with the number it is known by.
122 pub fn classes(&self) -> impl Iterator<Item = (RegClass, &'static ClassInfo)> + use<> {
123 self.classes.iter().enumerate().map(|(number, info)| (RegClass::new(number as u8), info))
124 }
125
126 /// What is in one class.
127 #[must_use]
128 pub fn class(&self, class: RegClass) -> Option<&'static ClassInfo> {
129 self.classes.get(usize::from(class.number()))
130 }
131
132 /// The class of that name, such as `gpr`.
133 #[must_use]
134 pub fn class_named(&self, name: &str) -> Option<RegClass> {
135 self.classes().find(|(_, info)| info.name == name).map(|(class, _)| class)
136 }
137
138 /// Whether the allocator may put a value in that class, which is [`ClassInfo::allocatable`].
139 ///
140 /// A class the file does not have is not one either, which is the same answer as a class
141 /// nothing allocates from and is the one that keeps a caller from having to say what it means
142 /// by a class number the target never gave out.
143 #[must_use]
144 pub fn allocatable(&self, class: RegClass) -> bool {
145 self.class(class).is_some_and(|info| info.allocatable)
146 }
147
148 /// How many registers are in a class, which is one past the largest number in it.
149 #[must_use]
150 pub fn len(&self, class: RegClass) -> usize {
151 self.class(class).map_or(0, |info| info.regs.len())
152 }
153
154 /// Whether the file has no classes at all, which is a target that has not described one.
155 #[must_use]
156 pub fn is_empty(&self) -> bool {
157 self.classes.is_empty()
158 }
159
160 /// What one register is called.
161 #[must_use]
162 pub fn name(&self, class: RegClass, reg: PhysReg) -> Option<&'static str> {
163 self.class(class)?.regs.get(usize::from(reg.number())).copied()
164 }
165
166 /// The register of that name, and the class it is in.
167 ///
168 /// The name is written without the sigil, so `rax` rather than `$rax`.
169 #[must_use]
170 pub fn reg_named(&self, name: &str) -> Option<(RegClass, PhysReg)> {
171 for (class, info) in self.classes() {
172 if let Some(number) = info.regs.iter().position(|®| reg == name) {
173 return Some((class, PhysReg::new(number as u8)));
174 }
175 }
176 None
177 }
178
179 /// A name this file gives to two registers, if it gives one to two.
180 ///
181 /// Reading a dump back needs every name to say which register it means, and a target that
182 /// breaks that produces text that cannot be parsed rather than an error at the point of the
183 /// mistake. So every target's own test asks this, which is why it is here and public.
184 #[must_use]
185 pub fn duplicate(&self) -> Option<&'static str> {
186 let mut seen: Vec<&'static str> = Vec::new();
187 for (_, info) in self.classes() {
188 for ® in info.regs {
189 if seen.contains(®) {
190 return Some(reg);
191 }
192 seen.push(reg);
193 }
194 }
195 None
196 }
197}
198
199/// The storage an address is counted from, on a machine that has more than one.
200///
201/// x86 keeps a thread's own block of words at a fixed place reached through a segment register,
202/// and that block is the only thing anything here uses one for. The stack protector's canary lives
203/// in it, which is why `%fs:40` is an address a compiler writes and `%fs` is not a register any
204/// program names. Every other address this compiler writes is in the flat segment and says nothing
205/// at all, which is what `None` is.
206#[derive(Debug, Clone, Copy, PartialEq, Eq)]
207pub enum Segment {
208 /// `%fs`, which is where a thread's own block is on x86-64 under System V.
209 Fs,
210 /// `%gs`, which is where it is on x86-64 under Windows and inside a kernel.
211 Gs,
212}
213
214/// Where a target keeps the word a stack protector's canary is a copy of.
215///
216/// Not a register and not a symbol either, on the conventions here. The word is in the block a
217/// thread has to itself, which is reached through a segment register and no other way, so the only
218/// way to name it is a distance into that block. That is why `%fs:40` appears in every protected
219/// function glibc has ever linked and why no object file carries a relocation for it.
220///
221/// A convention that answers `None` is one this compiler has no protector for, and a command line
222/// that asks for one on such a target is told so rather than quietly given an unprotected frame.
223#[derive(Debug, Clone, Copy, PartialEq, Eq)]
224pub struct Guard {
225 /// The storage the word is in.
226 pub segment: Segment,
227 /// How far into it the word is.
228 pub at: i32,
229 /// The function called when the copy in the frame no longer matches it, which does not come
230 /// back.
231 pub fail: &'static str,
232}
233
234/// What a profiler's hook at the top of every function is called on this platform.
235///
236/// A profiler wants to know which function called which and how often, and the only place a
237/// compiler can tell it that is the moment a function is entered. So `-pg` puts a call there, and
238/// what it calls is a routine the runtime provides rather than anything the program wrote.
239///
240/// Two of them, because there are two conventions for the same job and they disagree about where
241/// the call goes as well as what it is called. The older one runs once the frame is taken, so the
242/// hook can walk back through the frame pointer, which is why it needs one. The newer one runs
243/// before the prologue has done anything at all, which is what makes the return address the top
244/// thing on the stack and the arguments still in the registers they arrived in, and that is what
245/// lets a tracer replace the call with something else while the program runs. Linux's ftrace is
246/// built on exactly that, and it is why every kernel is built with the newer one.
247///
248/// A convention that answers `None` is one this compiler has no hook for, and a command line that
249/// asks for one on such a target is told so rather than quietly given an unprofiled program.
250#[derive(Debug, Clone, Copy, PartialEq, Eq)]
251pub struct Trace {
252 /// What is called in front of the prologue, which is what `-mfentry` asks for.
253 pub early: &'static str,
254 /// What is called once the frame is taken, which is what `-mno-fentry` asks for.
255 pub late: &'static str,
256 /// Which of the two a command line that named neither gets.
257 pub fentry: bool,
258}
259
260/// What a platform calls the routine that reaches the pages of a frame before the frame is taken.
261///
262/// Windows is the platform this is about. A thread there is given a stack of which only a little is
263/// committed, and one page below what is committed is a guard page whose whole job is to be touched:
264/// the fault it raises is what tells the kernel to commit another page and move the guard down. So a
265/// frame larger than a page has to be reached a page at a time or the guard is stepped over, and the
266/// program gets an access violation on an address that was never going to be mapped. That is the
267/// calling convention rather than a hardening flag, which is what makes this a field here and not
268/// something `-fstack-clash-protection` turns on.
269///
270/// Every Windows toolchain calls a routine for it rather than writing the walk out, and the routine
271/// is in the C runtime, so the name is the platform's. It reads the size in one register, touches
272/// each page down to there, and comes back having moved nothing, which is why the caller still has
273/// to take the frame afterwards.
274///
275/// A convention that answers `None` is one where reaching the pages is not the convention's
276/// business. That is every System V target, where a stack grows by faulting anywhere below it and
277/// the pages between are filled in by the kernel without being asked in order.
278#[derive(Debug, Clone, Copy, PartialEq, Eq)]
279pub struct Chkstk {
280 /// What the routine is called.
281 pub name: &'static str,
282 /// The register the size goes in, which is also the register it comes back in.
283 pub size: PhysReg,
284}
285
286/// Which registers a calling convention gives which job.
287///
288/// This is the second half of a target description and it is separate from [`RegFile`] because
289/// the two do not vary together. x86-64 has one register file and two conventions over it, and
290/// they disagree about nearly everything below: `rdi` is where the first argument arrives on
291/// SysV and a register a callee has to preserve on Windows, and a Windows caller reserves
292/// thirty two bytes below the call that a SysV caller does not.
293///
294/// The allocation order is here rather than on a class because it is a consequence of what a
295/// call clobbers. A value that does not live across a call belongs in a register the callee is
296/// free to destroy, because putting it in a preserved one costs a push and a pop in the
297/// prologue of whichever function ends up owning it.
298///
299/// Every register named here is a register of the file the same target describes, and each list
300/// is in the order the convention uses them, so the fourth integer argument is `int_args[3]` and
301/// nothing has to count.
302#[derive(Debug, Clone, Copy, PartialEq, Eq)]
303pub struct CallRegs {
304 /// The ABI these registers are the register half of.
305 ///
306 /// The two halves of one convention: this structure says which register a value goes in and
307 /// the description says what form it travels in on the way there, and a target that has one
308 /// has the other. It is a link rather than a copy of the fact anybody wants, because a back end
309 /// pass that writes a call to a runtime routine has to ask the same classification question a
310 /// call in the program is asked and there is one place that answers it. A target's registers and
311 /// a target's ABI are still chosen by two separate matches, one in [`crate::TargetInfo`] and one
312 /// in `rucc_abi::abis::for_target`, and the crate's test that walks every triple asking both is
313 /// what holds them together.
314 pub abi: &'static AbiDescription,
315 /// The class the general purpose registers named here are in.
316 ///
317 /// A register is a number inside its class, so a list of them says nothing about which
318 /// registers they are without this. Everything else could get the class from the operand it
319 /// came off, and a frame cannot, because a saved register is not an operand of anything.
320 pub int_class: RegClass,
321 /// The class the vector registers named here are in.
322 pub sse_class: RegClass,
323 /// The general purpose registers integer arguments arrive in, in order.
324 pub int_args: &'static [PhysReg],
325 /// The vector registers floating point arguments arrive in, in order.
326 ///
327 /// Whether an argument's position counts against both lists or only against its own is
328 /// [`CallRegs::shared_positions`].
329 pub sse_args: &'static [PhysReg],
330 /// Whether an argument's position counts against both argument lists or only against its own.
331 ///
332 /// False on SysV, which counts each separately, so a `double` after six integers is still in
333 /// `xmm0`. True on Windows, which counts one position for both, so a `double` in the third
334 /// position is in `xmm2` and `r8` is skipped.
335 pub shared_positions: bool,
336 /// The general purpose registers an integer return value comes back in.
337 pub int_returns: &'static [PhysReg],
338 /// The vector registers a floating point return value comes back in.
339 pub sse_returns: &'static [PhysReg],
340 /// The x87 registers a `long double` comes back in, which is empty on a target whose
341 /// `long double` is a `double`.
342 pub x87_returns: &'static [PhysReg],
343 /// The general purpose registers a call leaves alone, so a value in one survives it.
344 pub int_saved: &'static [PhysReg],
345 /// The vector registers a call leaves alone, which is none of them on SysV.
346 pub sse_saved: &'static [PhysReg],
347 /// The general purpose registers the allocator may hand out, in the order it prefers them.
348 ///
349 /// The stack pointer is never in this list, and neither is the frame pointer, which a
350 /// target could allocate when nothing needs a frame and which nothing here does yet.
351 pub int_order: &'static [PhysReg],
352 /// The vector registers the allocator may hand out, in the order it prefers them.
353 pub sse_order: &'static [PhysReg],
354 /// The stack pointer.
355 pub stack_pointer: PhysReg,
356 /// The frame pointer, which is the register a prologue puts the old stack pointer in.
357 pub frame_pointer: PhysReg,
358 /// Whether the prologue points the frame pointer at the frame after taking it rather than
359 /// before taking it.
360 ///
361 /// False everywhere but Windows, and there it is the unwind table asking rather than a
362 /// preference. The record a function carries on that platform counts every slot in it from
363 /// where the stack pointer ends the prologue, and it finds that place by taking a constant off
364 /// the frame pointer, so a register pushed after the pointer was established is below the place
365 /// the record counts from and has no row the format can write. The order that does work is the
366 /// pushes, then the frame, and only then the pointer, which is what Microsoft's compiler emits
367 /// and what gcc emits for this target in every function that saves anything besides the pointer
368 /// itself.
369 ///
370 /// What it costs is the chain: the frame pointer holds a copy of the body's stack pointer
371 /// rather than the address of the caller's copy of itself, so the words that used to lead from
372 /// one frame to the next no longer do. Nothing on this platform walks that chain. Unwinding
373 /// reads the table, there is no profiler's hook that reads the pointer, and gcc gives the chain
374 /// up on the same functions for the same reason.
375 pub late_frame_pointer: bool,
376 /// Where a variadic call says how many vector registers it passed arguments in, when the
377 /// convention makes it say.
378 ///
379 /// SysV puts the count in `al` and a variadic callee reads it to decide whether to save the
380 /// vector argument registers at all, which is what makes a call to `printf` with no
381 /// floating point argument cheap.
382 pub vector_count: Option<PhysReg>,
383 /// How many bytes below the stack pointer a leaf function may use without moving it.
384 ///
385 /// A hundred and twenty eight on SysV and nothing on Windows. It is nothing in kernel code
386 /// on either, because an interrupt handler runs on the interrupted stack and writes over
387 /// exactly this, which is what `-mno-red-zone` is for.
388 pub red_zone: u32,
389 /// How many bytes a caller reserves below the call for the callee to spill its register
390 /// arguments into, which is thirty two on Windows and nothing on SysV.
391 pub shadow: u32,
392 /// What the stack pointer has to be a multiple of at the instruction that makes a call.
393 ///
394 /// Sixteen on every convention here, and it is a real obligation rather than a preference,
395 /// because a callee is entitled to use an aligned vector store on its own frame and gets a
396 /// fault rather than a wrong answer when a caller got this wrong.
397 pub stack_align: u32,
398 /// How many bytes the call instruction itself pushes before the callee starts running.
399 ///
400 /// Eight on x86-64, where the return address is on the stack, and nothing on a machine that
401 /// leaves it in a register. It is what makes the stack pointer misaligned on entry by
402 /// exactly one word, which every frame layout has to undo.
403 pub return_address: u32,
404 /// How many bytes one general purpose register takes when it is saved on the stack.
405 pub word: u32,
406 /// Whether every plain load already orders like an acquire and every plain store like a
407 /// release, which is what total store order means.
408 ///
409 /// True on x86-64, where an ordered access below sequential consistency is the same `mov` as
410 /// an unordered one. False on AArch64, where a plain `ldr` and `str` may be reordered with the
411 /// accesses around them and an acquire or a release has an instruction of its own. Here beside
412 /// the word because the same pass asks both questions about the same access.
413 pub total_store_order: bool,
414 /// How far one push moves the stack pointer.
415 ///
416 /// The word on x86-64. Sixteen on AArch64, where the stack pointer has to stay a multiple of
417 /// sixteen whenever memory is reached through it, so a push of one register leaves eight bytes
418 /// of its slot unused and a push of two fills it.
419 pub push: u32,
420 /// The register a call leaves the return address in, or `None` on a machine whose call pushes
421 /// it.
422 ///
423 /// A function that calls anything has to put this register away first, since the call writes
424 /// over it. It goes with the frame pointer as one push, which is the pair AAPCS64 calls a frame
425 /// record, and so a function that calls keeps a frame pointer on such a machine whatever the
426 /// flags say. gcc does the same there.
427 pub link: Option<PhysReg>,
428 /// The register the address of a result returned through memory is passed in, or `None` on a
429 /// convention that passes it as the first integer argument.
430 ///
431 /// AAPCS64 gives it `x8`, which is not an argument register, so the arguments after it still
432 /// start at `x0`. SysV and Windows x64 pass it where the first argument would have gone and
433 /// move the rest along by one.
434 pub sret: Option<PhysReg>,
435 /// What a `va_list` is on this convention, which is what a variadic callee builds and walks.
436 ///
437 /// The same answer [`crate::TargetInfo::va_list`] gives the front end, kept here as well since
438 /// the walk is written after the front end is gone. It is not the same question as
439 /// [`CallRegs::shared_positions`]: Apple's AArch64 counts the files apart and still has a list
440 /// that is a pointer, because every argument a signature does not name goes on the stack.
441 pub list: crate::VaList,
442 /// What DWARF calls each register, one list per class in the order the file numbers the
443 /// classes, and inside a list in the order the class numbers its registers.
444 ///
445 /// The two numberings are a real difference and not a formality. On x86-64 the machine puts
446 /// `rcx` at one and DWARF puts `rdx` there, so a table written with the machine's numbers is
447 /// well formed and describes the wrong registers, which is a backtrace with plausible
448 /// nonsense in it rather than an error. Shorter than the file when the classes at the end are
449 /// ones DWARF has no column for, and empty on a target nobody has written this down for yet.
450 pub dwarf: &'static [&'static [u16]],
451 /// The column an unwind table files the return address under.
452 ///
453 /// Not a register on x86-64, where it is sixteen and `rip` is not a register anything can
454 /// name, and a real one on a machine that returns through a link register.
455 pub dwarf_return_address: u16,
456 /// Where the word a stack protector's canary is copied from lives, on a convention that has
457 /// somewhere to put one.
458 ///
459 /// Here rather than beside the frame instructions because it is a fact about the runtime the
460 /// code is linked against rather than about the machine. The two x86-64 conventions share
461 /// every instruction the check is made of and disagree about this.
462 pub guard: Option<Guard>,
463 /// What a profiler's hook is called on this platform, on one that has one.
464 ///
465 /// Here for the same reason [`CallRegs::guard`] is: the names are the runtime's rather than the
466 /// machine's, and the two x86-64 conventions write the same call instruction and disagree about
467 /// what goes in it.
468 pub trace: Option<Trace>,
469 /// What this platform calls the routine a prologue reaches the pages of a large frame with, on
470 /// one where reaching them is the convention.
471 ///
472 /// Here for the same reason the two above are, and it is the clearest case of the three: the
473 /// walk itself is written out of the machine's own instructions and both x86-64 conventions
474 /// have them, and what the two disagree about is whether a frame may be taken in one step at
475 /// all. A prologue that leaves this out on Windows writes a function that faults on its own
476 /// locals.
477 pub chkstk: Option<Chkstk>,
478}
479
480impl CallRegs {
481 /// The number DWARF gives that register, or `None` for one it has no column for.
482 ///
483 /// The x87 stack is the case that answers `None` on x86-64, and it is not an omission: a
484 /// register whose name means whichever one is on top of the stack is not one a table can have
485 /// a column for. Nothing saves one across a call either, so nothing ever asks.
486 #[must_use]
487 pub fn dwarf(&self, class: RegClass, reg: PhysReg) -> Option<u16> {
488 self.dwarf.get(usize::from(class.number()))?.get(usize::from(reg.number())).copied()
489 }
490
491 /// Which register of that class DWARF gave that number to, which is [`Self::dwarf`] the other
492 /// way round, and `None` for a number no register of the class holds.
493 ///
494 /// What asks is a table written in the machine's own numbering rather than DWARF's, which is
495 /// what Windows unwinds from. A row a prologue produces carries DWARF's number, because that is
496 /// what the format two of the three platforms want is written in, and the machine's number is
497 /// this register's place in its class. The two disagree over the first eight general purpose
498 /// registers on x86-64 and nowhere else, which is the worst shape a disagreement can have: every
499 /// number is a register either way, so the table comes out well formed and about the wrong
500 /// registers.
501 #[must_use]
502 pub fn machine(&self, class: RegClass, dwarf: u16) -> Option<PhysReg> {
503 let numbers = self.dwarf.get(usize::from(class.number()))?;
504 let at = numbers.iter().position(|&number| number == dwarf)?;
505 Some(PhysReg::new(u8::try_from(at).ok()?))
506 }
507
508 /// Whether a call preserves that general purpose register.
509 #[must_use]
510 pub fn preserves_int(&self, reg: PhysReg) -> bool {
511 self.int_saved.contains(®)
512 }
513
514 /// Whether a call preserves that vector register.
515 #[must_use]
516 pub fn preserves_sse(&self, reg: PhysReg) -> bool {
517 self.sse_saved.contains(®)
518 }
519}
520
521/// Where one of the values a call passes is.
522#[derive(Debug, Clone, Copy, PartialEq, Eq)]
523pub enum Where {
524 /// In that register.
525 Reg(PhysReg),
526 /// That many bytes up the argument area, which is where the stack pointer points at the
527 /// instruction that makes the call and is one word above the return address in the callee.
528 Stack(u32),
529}
530
531/// Where the values a call passes are, worked out one after another.
532///
533/// [`crate::abi::Call`] answers a different question: whether a value travels in registers at all
534/// and in how many, which is what decides the shape of a signature and is settled before the IR
535/// for a function exists. This answers the question after it. Given values in the order the
536/// signature holds them, it says which register each one is in and how far up the argument area
537/// the ones that got no register are. Both count registers, and they agree about how many fit
538/// because they read the same lists, but they run at opposite ends of the compiler and neither
539/// can be the other.
540///
541/// Ask about each value in the order the signature holds them. Asking out of order answers about
542/// a different signature, because where a value is depends on every value before it.
543#[derive(Debug, Clone)]
544pub struct Places<'a> {
545 regs: &'a CallRegs,
546 int: usize,
547 sse: usize,
548 stack: u32,
549}
550
551impl<'a> Places<'a> {
552 /// Where the first value is, for a call under that convention.
553 #[must_use]
554 pub fn new(regs: &'a CallRegs) -> Self {
555 Self { regs, int: 0, sse: 0, stack: regs.shadow }
556 }
557
558 /// Where the next value is, when it travels in a general purpose register.
559 ///
560 /// `bytes` is how wide the value is, which only matters once the registers have run out and
561 /// only on a convention that packs the argument area, for the reason `Places::scalar` gives.
562 pub fn integer(&mut self, bytes: u32) -> Where {
563 match self.regs.int_args.get(self.position(false)) {
564 Some(®) => {
565 self.int += 1;
566 Where::Reg(reg)
567 }
568 None => self.scalar(bytes),
569 }
570 }
571
572 /// Where the next value is, when it travels in a vector register.
573 ///
574 /// `bytes` is how wide the value is, and it is asked for because of what happens once the
575 /// vector registers have run out. A register holds whatever is put in it, so up to that point
576 /// the width changes nothing, and the argument area is a run of words, so a `float` or a
577 /// `double` that got no register takes one word wherever it starts. A `_Float128` is neither:
578 /// it is sixteen bytes aligned to sixteen, so its slot is two words and begins on an even one.
579 /// A slot of one word would leave the argument behind it sitting on the top half of the value,
580 /// and the load that reads it back is a `movaps`, which faults on an address that is not a
581 /// multiple of sixteen rather than being slow.
582 pub fn float(&mut self, bytes: u32) -> Where {
583 match self.regs.sse_args.get(self.position(true)) {
584 Some(®) => {
585 self.sse += 1;
586 Where::Reg(reg)
587 }
588 None => self.scalar(bytes),
589 }
590 }
591
592 /// Where a scalar that got no register is, which is its natural size and alignment on a
593 /// convention that packs the argument area and a whole number of words everywhere else.
594 ///
595 /// Apple's AArch64 is the one that packs, so a `char` in the ninth place there takes one byte
596 /// and the `short` after it starts at the second. That covers only the arguments a signature
597 /// names. One it does not is a word or more wherever it goes, and the caller asks for that
598 /// with [`Places::on_stack`] rather than here.
599 fn scalar(&mut self, bytes: u32) -> Where {
600 if self.regs.abi.stack_args == StackArgs::Packed {
601 let bytes = bytes.max(1);
602 let at = self.stack.next_multiple_of(bytes);
603 self.stack = at.saturating_add(bytes);
604 return Where::Stack(at);
605 }
606 // The alignment is the width, which [`Places::on_stack`] raises to a word for anything
607 // narrower, so this is the natural alignment of the value and not a rule of its own.
608 self.on_stack(bytes, bytes)
609 }
610
611 /// Where the next value is, when it travels in memory whatever is left.
612 ///
613 /// Every argument area is a run of whole words, so a value narrower than one still takes one
614 /// and a value that is not a whole number of them is rounded up. An alignment wider than a
615 /// word is respected, which is what a sixteen byte aligned structure passed by value needs.
616 pub fn on_stack(&mut self, size: u32, align: u32) -> Where {
617 let word = self.regs.word;
618 let at = self.stack.next_multiple_of(align.max(word));
619 self.stack = at.saturating_add(size.max(word).next_multiple_of(word));
620 Where::Stack(at)
621 }
622
623 /// Where an object a signature names and passes by value is.
624 ///
625 /// The same as [`Places::on_stack`] on every convention but one that packs the argument area.
626 /// There the alignment is the one the ABI gave the object, which is a word for most of them,
627 /// and the object takes its size rounded up to that, so a record of three `char`s is still a
628 /// word and three `float`s are twelve bytes.
629 pub fn object(&mut self, size: u32, align: u32) -> Where {
630 if self.regs.abi.stack_args != StackArgs::Packed {
631 return self.on_stack(size, align);
632 }
633 let align = align.max(1);
634 let at = self.stack.next_multiple_of(align);
635 self.stack = at.saturating_add(size.next_multiple_of(align));
636 Where::Stack(at)
637 }
638
639 /// Leaves no general purpose register for the values after this one.
640 ///
641 /// AAPCS64 asks for it after a record of sixteen bytes or less that found too few of them
642 /// left and went to memory, so an `int` after it goes to memory too rather than into the one
643 /// register the record could not use.
644 pub fn drain_integers(&mut self) {
645 self.int = self.regs.int_args.len();
646 }
647
648 /// Leaves no vector register for the values after this one, which AAPCS64 asks for after a
649 /// homogeneous floating point aggregate that found too few of them left.
650 pub fn drain_floats(&mut self) {
651 self.sse = self.regs.sse_args.len();
652 }
653
654 /// How many bytes of argument area the values so far need, shadow space included.
655 #[must_use]
656 pub fn size(&self) -> u32 {
657 self.stack
658 }
659
660 /// How many general purpose argument registers the values so far took.
661 ///
662 /// What a variadic callee needs and nothing else does. `va_start` has to record how far into
663 /// each of the two register sequences the arguments the signature names got, because the first
664 /// argument it does not name is the one after them, and asking here is the only way to know
665 /// that is the same count the caller worked from.
666 #[must_use]
667 pub fn integers(&self) -> usize {
668 self.int
669 }
670
671 /// How many vector argument registers the values so far took.
672 #[must_use]
673 pub fn floats(&self) -> usize {
674 self.sse
675 }
676
677 /// The position the next value of a kind is at.
678 fn position(&self, sse: bool) -> usize {
679 if self.regs.shared_positions {
680 self.int + self.sse
681 } else if sse {
682 self.sse
683 } else {
684 self.int
685 }
686 }
687}
688
689impl fmt::Display for RegFile {
690 /// The file as a dump reads it, one class to a line.
691 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
692 for (_, info) in self.classes() {
693 writeln!(f, "class {} : i{} = {}", info.name, info.bits, info.regs.join(", "))?;
694 }
695 Ok(())
696 }
697}
698
699#[cfg(test)]
700mod tests {
701 use super::*;
702
703 static GPR: [&str; 3] = ["rax", "rcx", "rdx"];
704 static XMM: [&str; 2] = ["xmm0", "xmm1"];
705 static CLASSES: [ClassInfo; 2] = [
706 ClassInfo { name: "gpr", bits: 64, regs: &GPR, allocatable: true },
707 ClassInfo { name: "xmm", bits: 128, regs: &XMM, allocatable: true },
708 ];
709 static FILE: RegFile = RegFile::new(&CLASSES);
710
711 #[test]
712 fn a_class_is_found_by_its_name() {
713 let gpr = FILE.class_named("gpr").expect("the file has a gpr class");
714 assert_eq!(FILE.len(gpr), 3);
715 assert_eq!(FILE.class(gpr).map(|info| info.bits), Some(64));
716 assert_eq!(FILE.class_named("vec"), None);
717 }
718
719 #[test]
720 fn a_register_is_found_by_its_name_and_names_itself_back() {
721 let (class, reg) = FILE.reg_named("xmm1").expect("the file has xmm1");
722 assert_eq!(FILE.class(class).map(|info| info.name), Some("xmm"));
723 assert_eq!(reg.number(), 1);
724 assert_eq!(FILE.name(class, reg), Some("xmm1"));
725 assert_eq!(FILE.reg_named("r15"), None);
726 }
727
728 #[test]
729 fn a_number_past_the_end_of_a_class_has_no_name() {
730 let gpr = FILE.class_named("gpr").expect("the file has a gpr class");
731 assert_eq!(FILE.name(gpr, PhysReg::new(3)), None);
732 assert_eq!(FILE.name(RegClass::new(7), PhysReg::new(0)), None);
733 }
734
735 #[test]
736 fn a_file_that_names_two_registers_alike_says_so() {
737 assert_eq!(FILE.duplicate(), None);
738 static BOTH: [ClassInfo; 2] = [
739 ClassInfo { name: "gpr", bits: 64, regs: &GPR, allocatable: true },
740 ClassInfo { name: "shadow", bits: 64, regs: &GPR, allocatable: true },
741 ];
742 assert_eq!(RegFile::new(&BOTH).duplicate(), Some("rax"));
743 }
744
745 #[test]
746 fn a_class_nothing_allocates_from_is_still_a_class_in_every_other_way() {
747 static WITH_STACK: [ClassInfo; 2] = [
748 ClassInfo { name: "gpr", bits: 64, regs: &GPR, allocatable: true },
749 ClassInfo { name: "x87", bits: 80, regs: &XMM, allocatable: false },
750 ];
751 let file = RegFile::new(&WITH_STACK);
752 let stack = file.class_named("x87").expect("the file has an x87 class");
753
754 assert!(!file.allocatable(stack));
755 assert!(file.allocatable(file.class_named("gpr").expect("the file has a gpr class")));
756
757 // Everything else about it works, which is the point of describing a class the allocator
758 // will not touch: the registers are counted, are named, and name themselves back.
759 assert_eq!(file.len(stack), 2);
760 assert_eq!(file.name(stack, PhysReg::new(1)), Some("xmm1"));
761 assert_eq!(file.reg_named("xmm1"), Some((stack, PhysReg::new(1))));
762 }
763
764 #[test]
765 fn a_class_the_file_does_not_have_is_not_one_to_allocate_from_either() {
766 assert!(!FILE.allocatable(RegClass::new(7)));
767 }
768
769 #[test]
770 fn the_file_prints_one_class_to_a_line() {
771 assert_eq!(
772 FILE.to_string(),
773 "class gpr : i64 = rax, rcx, rdx\nclass xmm : i128 = xmm0, xmm1\n"
774 );
775 }
776
777 /// Two integer registers, two vector registers and nothing else, so running out of them takes
778 /// three arguments rather than seven and the interesting case is the one being tested.
779 fn convention(shared: bool, shadow: u32) -> CallRegs {
780 static INT: [PhysReg; 2] = [PhysReg::new(0), PhysReg::new(1)];
781 static SSE: [PhysReg; 2] = [PhysReg::new(10), PhysReg::new(11)];
782 static NONE: [PhysReg; 0] = [];
783 // The registers are invented and the description is not, so it is picked by the one flag
784 // the two real conventions disagree about, which is the flag these tests vary.
785 let abi: &'static AbiDescription =
786 if shared { &rucc_abi::abis::WIN64 } else { &rucc_abi::abis::SYSV_AMD64 };
787 CallRegs {
788 abi,
789 int_class: RegClass::new(0),
790 sse_class: RegClass::new(1),
791 int_args: &INT,
792 sse_args: &SSE,
793 shared_positions: shared,
794 int_returns: &INT,
795 sse_returns: &SSE,
796 x87_returns: &NONE,
797 int_saved: &NONE,
798 sse_saved: &NONE,
799 int_order: &INT,
800 sse_order: &SSE,
801 stack_pointer: PhysReg::new(4),
802 frame_pointer: PhysReg::new(5),
803 late_frame_pointer: false,
804 vector_count: None,
805 red_zone: 0,
806 shadow,
807 stack_align: 16,
808 return_address: 8,
809 word: 8,
810 total_store_order: true,
811 push: 8,
812 link: None,
813 sret: None,
814 list: if shared { crate::VaList::CharPointer } else { crate::VaList::SysV },
815 // Empty, which is all a convention made up for a test of argument placement needs to
816 // say about a question it never asks.
817 dwarf: &[],
818 dwarf_return_address: 16,
819 guard: None,
820 trace: None,
821 chkstk: None,
822 }
823 }
824
825 #[test]
826 fn counting_each_kind_separately_leaves_the_first_vector_register_to_the_first_float() {
827 let regs = convention(false, 0);
828 let mut places = Places::new(®s);
829 assert_eq!(places.integer(8), Where::Reg(PhysReg::new(0)));
830 assert_eq!(places.integer(8), Where::Reg(PhysReg::new(1)));
831 // Two integers went past, and a convention that counts separately has not spent a vector
832 // register on either of them.
833 assert_eq!(places.float(8), Where::Reg(PhysReg::new(10)));
834 assert_eq!(places.size(), 0);
835 }
836
837 #[test]
838 fn counting_one_position_for_both_skips_the_register_the_other_kind_would_have_used() {
839 let regs = convention(true, 0);
840 let mut places = Places::new(®s);
841 assert_eq!(places.integer(8), Where::Reg(PhysReg::new(0)));
842 // The second position, so the second vector register, and the second integer register is
843 // spent whether anything is in it or not.
844 assert_eq!(places.float(8), Where::Reg(PhysReg::new(11)));
845 assert_eq!(places.integer(8), Where::Stack(0));
846 }
847
848 #[test]
849 fn running_out_of_one_kind_of_register_does_not_touch_the_other() {
850 let regs = convention(false, 0);
851 let mut places = Places::new(®s);
852 assert_eq!(places.integer(8), Where::Reg(PhysReg::new(0)));
853 assert_eq!(places.integer(8), Where::Reg(PhysReg::new(1)));
854 assert_eq!(places.integer(8), Where::Stack(0));
855 assert_eq!(places.float(8), Where::Reg(PhysReg::new(10)));
856 assert_eq!(places.size(), 8);
857 }
858
859 #[test]
860 fn the_argument_area_starts_above_the_shadow_space_and_keeps_every_value_aligned() {
861 let regs = convention(false, 32);
862 let mut places = Places::new(®s);
863 // A Windows caller reserves this whether it passes anything on the stack or not, which is
864 // why an empty area is thirty two bytes rather than none.
865 assert_eq!(places.size(), 32);
866 assert_eq!(places.on_stack(4, 4), Where::Stack(32));
867 // Sixteen byte alignment skips the word at 40, which is what a vector or an over-aligned
868 // structure passed by value asks for. The four byte value before it still took a whole
869 // word, which is why the skipped word is there to skip.
870 assert_eq!(places.on_stack(16, 16), Where::Stack(48));
871 assert_eq!(places.on_stack(8, 8), Where::Stack(64));
872 assert_eq!(places.size(), 72);
873 }
874
875 #[test]
876 fn a_float_wider_than_a_word_takes_two_of_them_once_the_registers_are_gone() {
877 let regs = convention(false, 0);
878 let mut places = Places::new(®s);
879 assert_eq!(places.float(16), Where::Reg(PhysReg::new(10)));
880 assert_eq!(places.float(16), Where::Reg(PhysReg::new(11)));
881 // The vector registers are gone, and so are the two general purpose ones, so the rest of
882 // this is in the area. The word the integer took is not where the first quad starts,
883 // because sixteen bytes aligned to sixteen skips the odd word above it, and the second
884 // quad is sixteen bytes above the first rather than eight.
885 assert_eq!(places.integer(8), Where::Reg(PhysReg::new(0)));
886 assert_eq!(places.integer(8), Where::Reg(PhysReg::new(1)));
887 assert_eq!(places.integer(8), Where::Stack(0));
888 assert_eq!(places.float(16), Where::Stack(16));
889 assert_eq!(places.float(16), Where::Stack(32));
890 assert_eq!(places.size(), 48);
891 // A float narrower than a word still takes one, which is what it took before any of this.
892 assert_eq!(places.float(4), Where::Stack(48));
893 assert_eq!(places.size(), 56);
894 }
895
896 #[test]
897 fn apple_packs_the_arguments_that_got_no_register_at_their_own_size() {
898 let mut regs = convention(false, 0);
899 regs.abi = &rucc_abi::abis::DARWIN_ARM64;
900 let mut places = Places::new(®s);
901 assert_eq!(places.integer(4), Where::Reg(PhysReg::new(0)));
902 assert_eq!(places.integer(4), Where::Reg(PhysReg::new(1)));
903 // A byte, a short and an int, each on its own alignment and nothing more, so the short
904 // skips the one byte after the char.
905 assert_eq!(places.integer(1), Where::Stack(0));
906 assert_eq!(places.integer(2), Where::Stack(2));
907 assert_eq!(places.integer(4), Where::Stack(4));
908 assert_eq!(places.float(8), Where::Reg(PhysReg::new(10)));
909 assert_eq!(places.float(4), Where::Reg(PhysReg::new(11)));
910 // The float goes straight after the int, and the long after it skips four bytes to get to
911 // its own alignment.
912 assert_eq!(places.float(4), Where::Stack(8));
913 assert_eq!(places.integer(8), Where::Stack(16));
914 assert_eq!(places.size(), 24);
915 // An object keeps the alignment it was given and takes its size up to it.
916 assert_eq!(places.object(12, 4), Where::Stack(24));
917 assert_eq!(places.object(3, 8), Where::Stack(40));
918 assert_eq!(places.size(), 48);
919 // Anything asked for as bytes is still a word or more, which is what an unnamed argument
920 // is there.
921 assert_eq!(places.on_stack(1, 1), Where::Stack(48));
922 assert_eq!(places.size(), 56);
923 }
924
925 #[test]
926 fn draining_one_kind_of_register_sends_the_rest_of_that_kind_to_memory_and_no_other() {
927 let regs = convention(false, 0);
928 let mut places = Places::new(®s);
929 assert_eq!(places.float(4), Where::Reg(PhysReg::new(10)));
930 places.drain_floats();
931 // The second vector register is still free and nothing may have it.
932 assert_eq!(places.float(4), Where::Stack(0));
933 assert_eq!(places.integer(8), Where::Reg(PhysReg::new(0)));
934 places.drain_integers();
935 assert_eq!(places.integer(8), Where::Stack(8));
936 assert_eq!((places.integers(), places.floats()), (2, 2));
937 }
938}