backend_lang/regs.rs
1//! Registers: physical registers of a target, virtual registers of a
2//! function, the classes that type them, and sets of physical registers.
3//!
4//! All four are dense numbers. A [`PReg`] indexes the target's register file
5//! ([`Target::regs`](crate::target::Target::regs)), a [`RegClass`] indexes its
6//! class table, and a [`VReg`] indexes a function's virtual-register table,
7//! which records each virtual register's class. [`Reg`] is either kind,
8//! packed into one `u32`, so an operand that names a register is the same
9//! size before and after register allocation.
10
11use core::fmt;
12
13/// The most physical registers a target may describe.
14///
15/// [`RegSet`] is a fixed 128-bit set, so every target's register file fits
16/// in one, with room for x86-64's 16 general-purpose and 16 vector registers
17/// and AArch64's 31 + 32.
18pub const MAX_PREGS: usize = 128;
19
20/// A physical register: an index into the target's register file.
21///
22/// What the number means (its name, hardware encoding, and class) is the
23/// target's business; see [`Target::reg`](crate::target::Target::reg). The
24/// x86-64 target names its registers as constants, such as
25/// [`x86_64::RAX`](crate::x86_64::RAX).
26///
27/// # Examples
28///
29/// ```
30/// use backend_lang::x86_64::{self, RAX, RDI};
31///
32/// assert_eq!(x86_64::TARGET.reg(RAX).name(), "rax");
33/// assert!(RAX.index() < RDI.index());
34/// ```
35#[derive(Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
36pub struct PReg(u8);
37
38impl PReg {
39 /// The physical register with index `index`, or `None` past
40 /// [`MAX_PREGS`].
41 ///
42 /// # Examples
43 ///
44 /// ```
45 /// use backend_lang::PReg;
46 ///
47 /// assert_eq!(PReg::new(3).map(PReg::index), Some(3));
48 /// assert_eq!(PReg::new(128), None);
49 /// ```
50 #[inline]
51 #[must_use]
52 pub const fn new(index: usize) -> Option<PReg> {
53 if index < MAX_PREGS {
54 Some(PReg(index as u8))
55 } else {
56 None
57 }
58 }
59
60 /// Builds a register from an index the caller knows is in range (target
61 /// tables are checked by tests to stay below [`MAX_PREGS`]).
62 pub(crate) const fn from_index(index: u8) -> PReg {
63 PReg(index & (MAX_PREGS as u8 - 1))
64 }
65
66 /// The register's index in the target's register file.
67 ///
68 /// # Examples
69 ///
70 /// ```
71 /// use backend_lang::x86_64::RCX;
72 ///
73 /// assert_eq!(RCX.index(), 1);
74 /// ```
75 #[inline]
76 #[must_use]
77 pub const fn index(self) -> usize {
78 self.0 as usize
79 }
80}
81
82impl fmt::Debug for PReg {
83 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
84 write!(f, "p{}", self.0)
85 }
86}
87
88/// A virtual register: an index into a function's virtual-register table.
89///
90/// Virtual registers are created by
91/// [`Function::vreg`](crate::mir::Function::vreg), each with a
92/// [`RegClass`], and printed as `%N`.
93///
94/// # Examples
95///
96/// ```
97/// use backend_lang::mir::Function;
98/// use backend_lang::x86_64::{GPR, SYSV};
99///
100/// let mut f = Function::new("f", &SYSV);
101/// let v = f.vreg(GPR).unwrap();
102/// assert_eq!(v.as_virt().map(|v| v.index()), Some(0));
103/// assert_eq!(f.vreg_class(v.as_virt().unwrap()), Some(GPR));
104/// ```
105#[derive(Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
106pub struct VReg(u32);
107
108impl VReg {
109 /// The most virtual registers one function may have: indexes use 31
110 /// bits, because [`Reg`] keeps the top bit to tell the two kinds apart.
111 pub const MAX: usize = (1 << 31) - 1;
112
113 pub(crate) const fn from_index(index: u32) -> VReg {
114 VReg(index & VIRT_MASK)
115 }
116
117 /// The register's index in its function's virtual-register table.
118 ///
119 /// # Examples
120 ///
121 /// ```
122 /// use backend_lang::mir::Function;
123 /// use backend_lang::x86_64::{GPR, SYSV};
124 ///
125 /// let mut f = Function::new("f", &SYSV);
126 /// let _ = f.vreg(GPR).unwrap();
127 /// let second = f.vreg(GPR).unwrap().as_virt().unwrap();
128 /// assert_eq!(second.index(), 1);
129 /// ```
130 #[inline]
131 #[must_use]
132 pub const fn index(self) -> usize {
133 self.0 as usize
134 }
135}
136
137impl fmt::Debug for VReg {
138 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
139 write!(f, "%{}", self.0)
140 }
141}
142
143const VIRT_BIT: u32 = 1 << 31;
144const VIRT_MASK: u32 = VIRT_BIT - 1;
145
146/// A register operand: physical or virtual.
147///
148/// Before register allocation, instructions name virtual registers (and the
149/// physical registers an ABI or an instruction fixes); after it, only
150/// physical ones. Emission requires the latter.
151///
152/// # Examples
153///
154/// ```
155/// use backend_lang::Reg;
156/// use backend_lang::x86_64::RAX;
157///
158/// let r = Reg::from(RAX);
159/// assert_eq!(r.as_phys(), Some(RAX));
160/// assert!(r.as_virt().is_none());
161/// ```
162#[derive(Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
163pub struct Reg(u32);
164
165impl Reg {
166 /// The register as a physical register, if it is one.
167 ///
168 /// # Examples
169 ///
170 /// ```
171 /// use backend_lang::Reg;
172 /// use backend_lang::x86_64::RSI;
173 ///
174 /// assert_eq!(Reg::from(RSI).as_phys(), Some(RSI));
175 /// ```
176 #[inline]
177 #[must_use]
178 pub const fn as_phys(self) -> Option<PReg> {
179 if self.0 & VIRT_BIT == 0 {
180 Some(PReg::from_index(self.0 as u8))
181 } else {
182 None
183 }
184 }
185
186 /// The register as a virtual register, if it is one.
187 ///
188 /// # Examples
189 ///
190 /// ```
191 /// use backend_lang::mir::Function;
192 /// use backend_lang::x86_64::{GPR, SYSV};
193 ///
194 /// let mut f = Function::new("f", &SYSV);
195 /// let r = f.vreg(GPR).unwrap();
196 /// assert!(r.as_virt().is_some());
197 /// assert!(r.as_phys().is_none());
198 /// ```
199 #[inline]
200 #[must_use]
201 pub const fn as_virt(self) -> Option<VReg> {
202 if self.0 & VIRT_BIT != 0 {
203 Some(VReg(self.0 & VIRT_MASK))
204 } else {
205 None
206 }
207 }
208
209 /// Whether this is a virtual register.
210 ///
211 /// # Examples
212 ///
213 /// ```
214 /// use backend_lang::Reg;
215 /// use backend_lang::x86_64::RAX;
216 ///
217 /// assert!(!Reg::from(RAX).is_virtual());
218 /// ```
219 #[inline]
220 #[must_use]
221 pub const fn is_virtual(self) -> bool {
222 self.0 & VIRT_BIT != 0
223 }
224}
225
226impl From<PReg> for Reg {
227 #[inline]
228 fn from(p: PReg) -> Reg {
229 Reg(u32::from(p.0))
230 }
231}
232
233impl From<VReg> for Reg {
234 #[inline]
235 fn from(v: VReg) -> Reg {
236 Reg(v.0 | VIRT_BIT)
237 }
238}
239
240impl fmt::Debug for Reg {
241 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
242 match (self.as_phys(), self.as_virt()) {
243 (Some(p), _) => fmt::Debug::fmt(&p, f),
244 (_, Some(v)) => fmt::Debug::fmt(&v, f),
245 _ => Ok(()),
246 }
247 }
248}
249
250/// A register class: the set of physical registers a value may live in, and
251/// the type of a virtual register. An index into the target's class table.
252///
253/// # Examples
254///
255/// ```
256/// use backend_lang::x86_64::{self, GPR, RAX, XMM0};
257///
258/// let gpr = x86_64::TARGET.class(GPR);
259/// assert_eq!(gpr.name(), "gpr");
260/// assert!(gpr.regs().contains(RAX));
261/// assert!(!gpr.regs().contains(XMM0));
262/// ```
263#[derive(Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
264pub struct RegClass(u8);
265
266impl RegClass {
267 /// The class with index `index` (whether the target has it is checked
268 /// where it is used).
269 ///
270 /// # Examples
271 ///
272 /// ```
273 /// use backend_lang::RegClass;
274 /// use backend_lang::x86_64::GPR;
275 ///
276 /// assert_eq!(RegClass::new(0), GPR);
277 /// ```
278 #[inline]
279 #[must_use]
280 pub const fn new(index: u8) -> RegClass {
281 RegClass(index)
282 }
283
284 /// The class's index in the target's class table.
285 ///
286 /// # Examples
287 ///
288 /// ```
289 /// use backend_lang::x86_64::VEC;
290 ///
291 /// assert_eq!(VEC.index(), 1);
292 /// ```
293 #[inline]
294 #[must_use]
295 pub const fn index(self) -> usize {
296 self.0 as usize
297 }
298}
299
300impl fmt::Debug for RegClass {
301 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
302 write!(f, "class{}", self.0)
303 }
304}
305
306/// A set of physical registers: 128 bits, one per [`PReg`] index.
307///
308/// Used for class membership, allocatable sets, callee- and caller-saved
309/// sets, and per-instruction clobbers. Every operation is a few word
310/// operations; iteration yields registers in index order.
311///
312/// # Examples
313///
314/// ```
315/// use backend_lang::RegSet;
316/// use backend_lang::x86_64::{RAX, RCX, RDX};
317///
318/// let set = RegSet::EMPTY.with(RAX).with(RDX);
319/// assert!(set.contains(RDX));
320/// assert!(!set.contains(RCX));
321/// assert_eq!(set.iter().collect::<Vec<_>>(), [RAX, RDX]);
322/// assert_eq!(set.len(), 2);
323/// ```
324#[derive(Clone, Copy, PartialEq, Eq, Hash, Default)]
325pub struct RegSet([u64; 2]);
326
327impl RegSet {
328 /// The empty set.
329 pub const EMPTY: RegSet = RegSet([0, 0]);
330
331 /// The set holding exactly the registers in `regs`.
332 ///
333 /// # Examples
334 ///
335 /// ```
336 /// use backend_lang::RegSet;
337 /// use backend_lang::x86_64::{R11, RCX};
338 ///
339 /// let set = RegSet::of(&[RCX, R11]);
340 /// assert!(set.contains(R11));
341 /// ```
342 #[must_use]
343 pub const fn of(regs: &[PReg]) -> RegSet {
344 let mut set = RegSet::EMPTY;
345 let mut i = 0;
346 while i < regs.len() {
347 set = set.with(regs[i]);
348 i += 1;
349 }
350 set
351 }
352
353 /// The set with `reg` added.
354 ///
355 /// # Examples
356 ///
357 /// ```
358 /// use backend_lang::RegSet;
359 /// use backend_lang::x86_64::RBX;
360 ///
361 /// assert!(RegSet::EMPTY.with(RBX).contains(RBX));
362 /// ```
363 #[inline]
364 #[must_use]
365 pub const fn with(self, reg: PReg) -> RegSet {
366 let i = reg.index();
367 let mut words = self.0;
368 words[i >> 6] |= 1 << (i & 63);
369 RegSet(words)
370 }
371
372 /// The set with `reg` removed.
373 ///
374 /// # Examples
375 ///
376 /// ```
377 /// use backend_lang::RegSet;
378 /// use backend_lang::x86_64::RBX;
379 ///
380 /// assert!(RegSet::of(&[RBX]).without(RBX).is_empty());
381 /// ```
382 #[inline]
383 #[must_use]
384 pub const fn without(self, reg: PReg) -> RegSet {
385 let i = reg.index();
386 let mut words = self.0;
387 words[i >> 6] &= !(1 << (i & 63));
388 RegSet(words)
389 }
390
391 /// Whether `reg` is in the set.
392 ///
393 /// # Examples
394 ///
395 /// ```
396 /// use backend_lang::RegSet;
397 /// use backend_lang::x86_64::{RAX, RBX};
398 ///
399 /// assert!(RegSet::of(&[RAX]).contains(RAX));
400 /// assert!(!RegSet::of(&[RAX]).contains(RBX));
401 /// ```
402 #[inline]
403 #[must_use]
404 pub const fn contains(self, reg: PReg) -> bool {
405 let i = reg.index();
406 self.0[i >> 6] & (1 << (i & 63)) != 0
407 }
408
409 /// The registers in either set.
410 ///
411 /// # Examples
412 ///
413 /// ```
414 /// use backend_lang::RegSet;
415 /// use backend_lang::x86_64::{RAX, RBX};
416 ///
417 /// assert_eq!(RegSet::of(&[RAX]).union(RegSet::of(&[RBX])).len(), 2);
418 /// ```
419 #[inline]
420 #[must_use]
421 pub const fn union(self, other: RegSet) -> RegSet {
422 RegSet([self.0[0] | other.0[0], self.0[1] | other.0[1]])
423 }
424
425 /// The registers in both sets.
426 ///
427 /// # Examples
428 ///
429 /// ```
430 /// use backend_lang::RegSet;
431 /// use backend_lang::x86_64::{RAX, RBX};
432 ///
433 /// let a = RegSet::of(&[RAX, RBX]);
434 /// assert_eq!(a.intersect(RegSet::of(&[RBX])), RegSet::of(&[RBX]));
435 /// ```
436 #[inline]
437 #[must_use]
438 pub const fn intersect(self, other: RegSet) -> RegSet {
439 RegSet([self.0[0] & other.0[0], self.0[1] & other.0[1]])
440 }
441
442 /// The registers in `self` but not in `other`.
443 ///
444 /// # Examples
445 ///
446 /// ```
447 /// use backend_lang::RegSet;
448 /// use backend_lang::x86_64::{RAX, RBX};
449 ///
450 /// let a = RegSet::of(&[RAX, RBX]);
451 /// assert_eq!(a.difference(RegSet::of(&[RAX])), RegSet::of(&[RBX]));
452 /// ```
453 #[inline]
454 #[must_use]
455 pub const fn difference(self, other: RegSet) -> RegSet {
456 RegSet([self.0[0] & !other.0[0], self.0[1] & !other.0[1]])
457 }
458
459 /// Whether the set is empty.
460 ///
461 /// # Examples
462 ///
463 /// ```
464 /// use backend_lang::RegSet;
465 ///
466 /// assert!(RegSet::EMPTY.is_empty());
467 /// ```
468 #[inline]
469 #[must_use]
470 pub const fn is_empty(self) -> bool {
471 self.0[0] == 0 && self.0[1] == 0
472 }
473
474 /// The number of registers in the set.
475 ///
476 /// # Examples
477 ///
478 /// ```
479 /// use backend_lang::x86_64::{self, GPR};
480 ///
481 /// assert_eq!(x86_64::TARGET.class(GPR).regs().len(), 16);
482 /// ```
483 #[inline]
484 #[must_use]
485 pub const fn len(self) -> usize {
486 (self.0[0].count_ones() + self.0[1].count_ones()) as usize
487 }
488
489 /// The lowest-numbered register in the set.
490 ///
491 /// # Examples
492 ///
493 /// ```
494 /// use backend_lang::RegSet;
495 /// use backend_lang::x86_64::{RCX, R9};
496 ///
497 /// assert_eq!(RegSet::of(&[R9, RCX]).first(), Some(RCX));
498 /// assert_eq!(RegSet::EMPTY.first(), None);
499 /// ```
500 #[inline]
501 #[must_use]
502 pub const fn first(self) -> Option<PReg> {
503 if self.0[0] != 0 {
504 Some(PReg::from_index(self.0[0].trailing_zeros() as u8))
505 } else if self.0[1] != 0 {
506 Some(PReg::from_index(64 + self.0[1].trailing_zeros() as u8))
507 } else {
508 None
509 }
510 }
511
512 /// The registers in the set, in index order.
513 ///
514 /// # Examples
515 ///
516 /// ```
517 /// use backend_lang::RegSet;
518 /// use backend_lang::x86_64::{RAX, R15};
519 ///
520 /// let v: Vec<_> = RegSet::of(&[R15, RAX]).iter().collect();
521 /// assert_eq!(v, [RAX, R15]);
522 /// ```
523 #[must_use]
524 pub fn iter(self) -> RegSetIter {
525 RegSetIter(self)
526 }
527}
528
529impl fmt::Debug for RegSet {
530 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
531 f.debug_set().entries(self.iter()).finish()
532 }
533}
534
535impl FromIterator<PReg> for RegSet {
536 fn from_iter<I: IntoIterator<Item = PReg>>(iter: I) -> RegSet {
537 iter.into_iter().fold(RegSet::EMPTY, RegSet::with)
538 }
539}
540
541/// The registers of a [`RegSet`], in index order. Made by [`RegSet::iter`].
542///
543/// # Examples
544///
545/// ```
546/// use backend_lang::RegSet;
547/// use backend_lang::x86_64::RDX;
548///
549/// let mut it = RegSet::of(&[RDX]).iter();
550/// assert_eq!(it.next(), Some(RDX));
551/// assert_eq!(it.next(), None);
552/// ```
553#[derive(Clone, Debug)]
554pub struct RegSetIter(RegSet);
555
556impl Iterator for RegSetIter {
557 type Item = PReg;
558
559 #[inline]
560 fn next(&mut self) -> Option<PReg> {
561 let first = self.0.first()?;
562 self.0 = self.0.without(first);
563 Some(first)
564 }
565
566 fn size_hint(&self) -> (usize, Option<usize>) {
567 let n = self.0.len();
568 (n, Some(n))
569 }
570}
571
572impl ExactSizeIterator for RegSetIter {}
573
574#[cfg(test)]
575mod tests {
576 use alloc::vec::Vec;
577
578 use super::*;
579
580 #[test]
581 fn test_reg_packing_round_trips_both_kinds() {
582 for i in [0u8, 1, 15, 127] {
583 let p = PReg::from_index(i);
584 assert_eq!(Reg::from(p).as_phys(), Some(p));
585 assert_eq!(Reg::from(p).as_virt(), None);
586 }
587 for i in [0u32, 1, 1 << 20, VIRT_MASK] {
588 let v = VReg::from_index(i);
589 assert_eq!(Reg::from(v).as_virt(), Some(v));
590 assert_eq!(Reg::from(v).as_phys(), None);
591 assert!(Reg::from(v).is_virtual());
592 }
593 }
594
595 #[test]
596 fn test_regset_high_word_and_iteration_order() {
597 let regs: Vec<PReg> = [0u8, 63, 64, 100, 127]
598 .iter()
599 .map(|&i| PReg::from_index(i))
600 .collect();
601 let set: RegSet = regs.iter().copied().collect();
602 assert_eq!(set.len(), 5);
603 assert_eq!(set.iter().collect::<Vec<_>>(), regs);
604 assert_eq!(set.iter().len(), 5);
605 assert_eq!(set.without(regs[0]).first(), Some(regs[1]));
606 let high = RegSet::of(&[PReg::from_index(100)]);
607 assert_eq!(high.first(), Some(PReg::from_index(100)));
608 assert!(set.difference(set).is_empty());
609 assert_eq!(set.intersect(high), high);
610 }
611
612 #[test]
613 fn test_preg_new_bounds() {
614 assert!(PReg::new(127).is_some());
615 assert!(PReg::new(128).is_none());
616 assert!(PReg::new(usize::MAX).is_none());
617 }
618}