Skip to main content

backend_lang/target/
mod.rs

1//! Target descriptions: the backend's half of `TARGET-DESC.md`.
2//!
3//! A [`Target`] is data: its register file ([`RegInfo`]), its register
4//! classes ([`ClassInfo`]), and its machine instructions ([`InstDesc`]),
5//! each instruction with its operand rules, its implicit register uses and
6//! definitions, and the registers it clobbers. The generic machinery in this
7//! crate (MIR verification, the parallel-move resolver, frame layout) reads
8//! only this data; what is specific to an ISA is the description itself and
9//! the encoder that turns instructions into bytes (for x86-64, isa-lang).
10//!
11//! Implicit operands live here, not in isa-lang: as of isa-lang 0.2 the
12//! encoder's tables describe the explicit operands of each form only (the
13//! fixed `CL` of a shift is visible, `MUL`'s `RDX:RAX` is not). The register
14//! allocator needs all of them, so this layer records them per instruction;
15//! it can be cross-checked against isa-lang's own data once isa-lang carries
16//! it (isa-lang ROADMAP v0.5).
17//!
18//! [`abi`] adds calling conventions and [`frame`] the stack-frame model.
19
20pub mod abi;
21pub mod frame;
22
23use core::fmt;
24
25use crate::regs::{PReg, RegClass, RegSet};
26
27/// The instruction-set architecture a [`Target`] describes, which selects the
28/// encoder emission uses.
29///
30/// # Examples
31///
32/// ```
33/// use backend_lang::target::Isa;
34/// use backend_lang::x86_64;
35///
36/// assert_eq!(x86_64::TARGET.isa(), Isa::X86_64);
37/// ```
38#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
39#[non_exhaustive]
40pub enum Isa {
41    /// x86-64 (AMD64 / Intel 64), encoded by `isa-lang`.
42    X86_64,
43}
44
45/// One physical register: its name, its class, and its hardware number.
46///
47/// # Examples
48///
49/// ```
50/// use backend_lang::x86_64::{self, GPR, R12};
51///
52/// let r12 = x86_64::TARGET.reg(R12);
53/// assert_eq!(r12.name(), "r12");
54/// assert_eq!(r12.class(), GPR);
55/// assert_eq!(r12.hw(), 12);
56/// ```
57#[derive(Clone, Copy, Debug, PartialEq, Eq)]
58pub struct RegInfo {
59    name: &'static str,
60    class: RegClass,
61    hw: u8,
62}
63
64impl RegInfo {
65    /// Describes a register named `name` in `class`, encoded as `hw` (the
66    /// number the ISA's instruction fields carry).
67    ///
68    /// # Examples
69    ///
70    /// ```
71    /// use backend_lang::RegClass;
72    /// use backend_lang::target::RegInfo;
73    ///
74    /// let r = RegInfo::new("r0", RegClass::new(0), 0);
75    /// assert_eq!(r.name(), "r0");
76    /// ```
77    #[must_use]
78    pub const fn new(name: &'static str, class: RegClass, hw: u8) -> RegInfo {
79        RegInfo { name, class, hw }
80    }
81
82    /// The register's assembly name.
83    ///
84    /// # Examples
85    ///
86    /// ```
87    /// use backend_lang::x86_64::{self, XMM3};
88    ///
89    /// assert_eq!(x86_64::TARGET.reg(XMM3).name(), "xmm3");
90    /// ```
91    #[inline]
92    #[must_use]
93    pub const fn name(&self) -> &'static str {
94        self.name
95    }
96
97    /// The register's class.
98    ///
99    /// # Examples
100    ///
101    /// ```
102    /// use backend_lang::x86_64::{self, VEC, XMM3};
103    ///
104    /// assert_eq!(x86_64::TARGET.reg(XMM3).class(), VEC);
105    /// ```
106    #[inline]
107    #[must_use]
108    pub const fn class(&self) -> RegClass {
109        self.class
110    }
111
112    /// The register's hardware number.
113    ///
114    /// # Examples
115    ///
116    /// ```
117    /// use backend_lang::x86_64::{self, RSP};
118    ///
119    /// assert_eq!(x86_64::TARGET.reg(RSP).hw(), 4);
120    /// ```
121    #[inline]
122    #[must_use]
123    pub const fn hw(&self) -> u8 {
124        self.hw
125    }
126}
127
128/// The register returned by [`Target::reg`] for an index the target does not
129/// have: named `<invalid>`, in no class a target uses.
130const INVALID_REG: RegInfo = RegInfo::new("<invalid>", RegClass::new(u8::MAX), u8::MAX);
131
132/// A register class: its members, the members an allocator may hand out, and
133/// the size and alignment of a spill slot for one of its values.
134///
135/// # Examples
136///
137/// ```
138/// use backend_lang::x86_64::{self, GPR, RSP};
139///
140/// let gpr = x86_64::TARGET.class(GPR);
141/// assert!(gpr.regs().contains(RSP));
142/// assert!(!gpr.allocatable().contains(RSP));
143/// assert_eq!((gpr.spill_size(), gpr.spill_align()), (8, 8));
144/// ```
145#[derive(Clone, Copy, Debug, PartialEq, Eq)]
146pub struct ClassInfo {
147    name: &'static str,
148    regs: RegSet,
149    allocatable: RegSet,
150    spill_size: u32,
151    spill_align: u32,
152}
153
154impl ClassInfo {
155    /// Describes a class named `name` with members `regs`, of which
156    /// `allocatable` may be handed out by an allocator, spilled to slots of
157    /// `spill_size` bytes aligned to `spill_align`.
158    ///
159    /// # Examples
160    ///
161    /// ```
162    /// use backend_lang::RegSet;
163    /// use backend_lang::target::ClassInfo;
164    ///
165    /// let c = ClassInfo::new("int", RegSet::EMPTY, RegSet::EMPTY, 8, 8);
166    /// assert_eq!(c.name(), "int");
167    /// ```
168    #[must_use]
169    pub const fn new(
170        name: &'static str,
171        regs: RegSet,
172        allocatable: RegSet,
173        spill_size: u32,
174        spill_align: u32,
175    ) -> ClassInfo {
176        ClassInfo {
177            name,
178            regs,
179            allocatable,
180            spill_size,
181            spill_align,
182        }
183    }
184
185    /// The class's name, as the MIR printer writes it.
186    ///
187    /// # Examples
188    ///
189    /// ```
190    /// use backend_lang::x86_64::{self, VEC};
191    ///
192    /// assert_eq!(x86_64::TARGET.class(VEC).name(), "vec");
193    /// ```
194    #[inline]
195    #[must_use]
196    pub const fn name(&self) -> &'static str {
197        self.name
198    }
199
200    /// Every register of the class.
201    ///
202    /// # Examples
203    ///
204    /// ```
205    /// use backend_lang::x86_64::{self, VEC};
206    ///
207    /// assert_eq!(x86_64::TARGET.class(VEC).regs().len(), 16);
208    /// ```
209    #[inline]
210    #[must_use]
211    pub const fn regs(&self) -> RegSet {
212        self.regs
213    }
214
215    /// The registers an allocator may assign: the class minus the stack
216    /// pointer and the frame pointer. (Without a frame pointer the frame
217    /// pointer register is allocatable too; see
218    /// [`Function::omit_frame_pointer`](crate::mir::Function::omit_frame_pointer).)
219    ///
220    /// # Examples
221    ///
222    /// ```
223    /// use backend_lang::x86_64::{self, GPR, RBP};
224    ///
225    /// let gpr = x86_64::TARGET.class(GPR);
226    /// assert_eq!(gpr.allocatable().len(), 14);
227    /// assert!(!gpr.allocatable().contains(RBP));
228    /// ```
229    #[inline]
230    #[must_use]
231    pub const fn allocatable(&self) -> RegSet {
232        self.allocatable
233    }
234
235    /// Bytes in a spill slot for one value of the class.
236    ///
237    /// # Examples
238    ///
239    /// ```
240    /// use backend_lang::x86_64::{self, VEC};
241    ///
242    /// assert_eq!(x86_64::TARGET.class(VEC).spill_size(), 16);
243    /// ```
244    #[inline]
245    #[must_use]
246    pub const fn spill_size(&self) -> u32 {
247        self.spill_size
248    }
249
250    /// Required alignment of a spill slot for the class.
251    ///
252    /// # Examples
253    ///
254    /// ```
255    /// use backend_lang::x86_64::{self, VEC};
256    ///
257    /// assert_eq!(x86_64::TARGET.class(VEC).spill_align(), 16);
258    /// ```
259    #[inline]
260    #[must_use]
261    pub const fn spill_align(&self) -> u32 {
262        self.spill_align
263    }
264}
265
266/// The class returned by [`Target::class`] for an index the target does not
267/// have: no registers.
268const INVALID_CLASS: ClassInfo = ClassInfo::new("<invalid>", RegSet::EMPTY, RegSet::EMPTY, 0, 1);
269
270/// A machine opcode: an index into the target's instruction table.
271///
272/// Every target's table begins with the two generic pseudo-instructions
273/// [`Opcode::COPY`] and [`Opcode::PCOPY`]; the rest are the target's own
274/// (for x86-64, the constants in [`x86_64::op`](crate::x86_64::op)).
275///
276/// # Examples
277///
278/// ```
279/// use backend_lang::target::Opcode;
280/// use backend_lang::x86_64::{self, op};
281///
282/// assert_eq!(x86_64::TARGET.inst(Opcode::COPY).unwrap().name(), "copy");
283/// assert_eq!(x86_64::TARGET.inst(op::ADD64).unwrap().name(), "add64");
284/// ```
285#[derive(Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
286pub struct Opcode(u16);
287
288impl Opcode {
289    /// `dst = copy src`: one move between registers, stack slots, or from an
290    /// immediate. Lowered through the parallel-move resolver, so a
291    /// slot-to-slot copy gets a temporary register as the target requires.
292    /// A copy's width is its register's class; a copy with no register
293    /// (slot to slot, or an immediate to a slot) moves a value of the
294    /// target's address class (8 bytes on x86-64).
295    pub const COPY: Opcode = Opcode(0);
296    /// `d0, d1, ... = pcopy s0, s1, ...`: a parallel copy. Every source is
297    /// read before any destination is written, as on a control-flow edge.
298    /// Lowered through the parallel-move resolver.
299    pub const PCOPY: Opcode = Opcode(1);
300
301    /// The opcode with index `index` in a target's table.
302    ///
303    /// # Examples
304    ///
305    /// ```
306    /// use backend_lang::target::Opcode;
307    ///
308    /// assert_eq!(Opcode::new(0), Opcode::COPY);
309    /// ```
310    #[inline]
311    #[must_use]
312    pub const fn new(index: u16) -> Opcode {
313        Opcode(index)
314    }
315
316    /// The opcode's index in the target's instruction table.
317    ///
318    /// # Examples
319    ///
320    /// ```
321    /// use backend_lang::target::Opcode;
322    ///
323    /// assert_eq!(Opcode::PCOPY.index(), 1);
324    /// ```
325    #[inline]
326    #[must_use]
327    pub const fn index(self) -> usize {
328        self.0 as usize
329    }
330}
331
332impl fmt::Debug for Opcode {
333    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
334        write!(f, "Opcode({})", self.0)
335    }
336}
337
338/// What an instruction does to control flow, and which generic handling it
339/// gets.
340///
341/// # Examples
342///
343/// ```
344/// use backend_lang::target::InstKind;
345/// use backend_lang::x86_64::{self, op};
346///
347/// assert_eq!(x86_64::TARGET.inst(op::JMP).unwrap().kind(), InstKind::Jump);
348/// assert!(InstKind::Jump.is_terminator());
349/// assert!(!InstKind::Call.is_terminator());
350/// ```
351#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
352#[non_exhaustive]
353pub enum InstKind {
354    /// An ordinary instruction; control falls through.
355    Plain,
356    /// [`Opcode::COPY`].
357    Copy,
358    /// [`Opcode::PCOPY`].
359    ParallelCopy,
360    /// An unconditional branch to one block, passing arguments.
361    Jump,
362    /// A two-way conditional branch: a condition, then the taken and the
363    /// not-taken block, each with arguments.
364    Branch,
365    /// A return from the function (the epilogue runs first).
366    Return,
367    /// A call; control comes back to the next instruction.
368    Call,
369    /// An instruction that never falls through and never returns (`ud2`).
370    Trap,
371}
372
373impl InstKind {
374    /// Whether the instruction ends a block: jumps, branches, returns, traps.
375    ///
376    /// # Examples
377    ///
378    /// ```
379    /// use backend_lang::target::InstKind;
380    ///
381    /// assert!(InstKind::Return.is_terminator());
382    /// assert!(!InstKind::Plain.is_terminator());
383    /// ```
384    #[inline]
385    #[must_use]
386    pub const fn is_terminator(self) -> bool {
387        matches!(
388            self,
389            InstKind::Jump | InstKind::Branch | InstKind::Return | InstKind::Trap
390        )
391    }
392}
393
394/// The values an immediate operand may take.
395///
396/// Immediates are signed values of the operation's width, as isa-lang takes
397/// them (TARGET-DESC ยง3.1): for a 32-bit operation, all ones is `-1`.
398///
399/// # Examples
400///
401/// ```
402/// use backend_lang::target::ImmRange;
403///
404/// assert!(ImmRange::I8.fits(-128));
405/// assert!(!ImmRange::I8.fits(128));
406/// assert!(ImmRange::U8.fits(255));
407/// assert!(!ImmRange::None.fits(0));
408/// ```
409#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
410#[non_exhaustive]
411pub enum ImmRange {
412    /// No immediate is accepted.
413    None,
414    /// `-128..=127`.
415    I8,
416    /// `0..=255`.
417    U8,
418    /// `-32768..=32767`.
419    I16,
420    /// `-2^31..=2^31-1`.
421    I32,
422    /// Any 64-bit value.
423    I64,
424}
425
426impl ImmRange {
427    /// Whether `value` is in the range.
428    ///
429    /// # Examples
430    ///
431    /// ```
432    /// use backend_lang::target::ImmRange;
433    ///
434    /// assert!(ImmRange::I32.fits(i64::from(i32::MIN)));
435    /// assert!(!ImmRange::I32.fits(1 << 31));
436    /// assert!(ImmRange::I64.fits(i64::MIN));
437    /// ```
438    #[inline]
439    #[must_use]
440    pub const fn fits(self, value: i64) -> bool {
441        match self {
442            ImmRange::None => false,
443            ImmRange::I8 => value >= -128 && value <= 127,
444            ImmRange::U8 => value >= 0 && value <= 255,
445            ImmRange::I16 => value >= i16::MIN as i64 && value <= i16::MAX as i64,
446            ImmRange::I32 => value >= i32::MIN as i64 && value <= i32::MAX as i64,
447            ImmRange::I64 => true,
448        }
449    }
450}
451
452/// Which operand shapes a use accepts: a register, memory (an address or a
453/// stack slot), an immediate in a range, a function symbol.
454///
455/// # Examples
456///
457/// ```
458/// use backend_lang::target::{Accept, ImmRange};
459///
460/// let rmi = Accept::RM.with_imm(ImmRange::I32);
461/// assert!(rmi.reg() && rmi.mem());
462/// assert_eq!(rmi.imm(), ImmRange::I32);
463/// assert!(!Accept::REG.mem());
464/// ```
465#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
466pub struct Accept {
467    reg: bool,
468    mem: bool,
469    symbol: bool,
470    imm: ImmRange,
471}
472
473impl Accept {
474    /// A register only.
475    pub const REG: Accept = Accept {
476        reg: true,
477        mem: false,
478        symbol: false,
479        imm: ImmRange::None,
480    };
481    /// Memory only.
482    pub const MEM: Accept = Accept {
483        reg: false,
484        mem: true,
485        symbol: false,
486        imm: ImmRange::None,
487    };
488    /// A register or memory.
489    pub const RM: Accept = Accept {
490        reg: true,
491        mem: true,
492        symbol: false,
493        imm: ImmRange::None,
494    };
495    /// Nothing; extend with the `with_*` methods.
496    pub const NONE: Accept = Accept {
497        reg: false,
498        mem: false,
499        symbol: false,
500        imm: ImmRange::None,
501    };
502
503    /// Also accepts immediates in `range`.
504    ///
505    /// # Examples
506    ///
507    /// ```
508    /// use backend_lang::target::{Accept, ImmRange};
509    ///
510    /// assert_eq!(Accept::REG.with_imm(ImmRange::U8).imm(), ImmRange::U8);
511    /// ```
512    #[must_use]
513    pub const fn with_imm(self, range: ImmRange) -> Accept {
514        Accept { imm: range, ..self }
515    }
516
517    /// Also accepts a function symbol (a direct call target, or the address
518    /// of a function as a RIP-relative memory operand).
519    ///
520    /// # Examples
521    ///
522    /// ```
523    /// use backend_lang::target::Accept;
524    ///
525    /// assert!(Accept::MEM.with_symbol().symbol());
526    /// ```
527    #[must_use]
528    pub const fn with_symbol(self) -> Accept {
529        Accept {
530            symbol: true,
531            ..self
532        }
533    }
534
535    /// Whether a register is accepted.
536    ///
537    /// # Examples
538    ///
539    /// ```
540    /// use backend_lang::target::Accept;
541    ///
542    /// assert!(Accept::RM.reg());
543    /// ```
544    #[inline]
545    #[must_use]
546    pub const fn reg(self) -> bool {
547        self.reg
548    }
549
550    /// Whether memory (an address or a stack slot) is accepted.
551    ///
552    /// # Examples
553    ///
554    /// ```
555    /// use backend_lang::target::Accept;
556    ///
557    /// assert!(Accept::MEM.mem());
558    /// ```
559    #[inline]
560    #[must_use]
561    pub const fn mem(self) -> bool {
562        self.mem
563    }
564
565    /// Whether a function symbol is accepted.
566    ///
567    /// # Examples
568    ///
569    /// ```
570    /// use backend_lang::target::Accept;
571    ///
572    /// assert!(!Accept::RM.symbol());
573    /// ```
574    #[inline]
575    #[must_use]
576    pub const fn symbol(self) -> bool {
577        self.symbol
578    }
579
580    /// The immediates accepted.
581    ///
582    /// # Examples
583    ///
584    /// ```
585    /// use backend_lang::target::{Accept, ImmRange};
586    ///
587    /// assert_eq!(Accept::RM.imm(), ImmRange::None);
588    /// ```
589    #[inline]
590    #[must_use]
591    pub const fn imm(self) -> ImmRange {
592        self.imm
593    }
594}
595
596/// The rule for one explicit operand of an instruction.
597///
598/// Operands are listed definitions first, then uses, as the MIR printer
599/// shows them (`%2 = add64 %0, %1`).
600///
601/// # Examples
602///
603/// ```
604/// use backend_lang::target::{Accept, ImmRange, OperandRule};
605/// use backend_lang::x86_64::{self, op, GPR};
606///
607/// let add = x86_64::TARGET.inst(op::ADD64).unwrap();
608/// assert_eq!(add.operands()[0], OperandRule::Def(GPR));
609/// assert_eq!(add.operands()[1], OperandRule::Tied(0));
610/// assert_eq!(add.operands()[2], OperandRule::Use(GPR, Accept::RM.with_imm(ImmRange::I32)));
611/// ```
612#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
613#[non_exhaustive]
614pub enum OperandRule {
615    /// A register the instruction writes, of this class.
616    Def(RegClass),
617    /// A use that must be the same register as definition `n`: the
618    /// two-address constraint (`add d, s` reads and writes `d`). In SSA form
619    /// the definition and the tied use are different virtual registers; the
620    /// register allocator gives them one physical register.
621    Tied(u8),
622    /// A value the instruction reads, of this class (for a register; the
623    /// class of a memory operand's base and index is the target's address
624    /// class), in the shapes `Accept` allows.
625    Use(RegClass, Accept),
626    /// A condition code.
627    Cond,
628    /// A branch target with its arguments.
629    Block,
630}
631
632/// One machine instruction's description.
633///
634/// # Examples
635///
636/// ```
637/// use backend_lang::target::InstKind;
638/// use backend_lang::x86_64::{self, op, RAX, RDX, FLAGS};
639///
640/// let div = x86_64::TARGET.inst(op::IDIV64).unwrap();
641/// assert_eq!(div.name(), "idiv64");
642/// assert_eq!(div.kind(), InstKind::Plain);
643/// assert_eq!(div.implicit_uses(), [RAX, RDX]);
644/// assert_eq!(div.implicit_defs(), [RAX, RDX, FLAGS]);
645/// ```
646#[derive(Clone, Copy, Debug, PartialEq, Eq)]
647pub struct InstDesc {
648    name: &'static str,
649    kind: InstKind,
650    operands: &'static [OperandRule],
651    implicit_uses: &'static [PReg],
652    implicit_defs: &'static [PReg],
653    clobbers: RegSet,
654}
655
656impl InstDesc {
657    /// Describes an instruction.
658    ///
659    /// `implicit_uses` are registers read without being named as operands,
660    /// `implicit_defs` registers written that way (results the code may read
661    /// afterwards, such as `idiv`'s quotient in `rax`), and `clobbers`
662    /// registers left with unspecified contents.
663    ///
664    /// # Examples
665    ///
666    /// ```
667    /// use backend_lang::RegSet;
668    /// use backend_lang::target::{InstDesc, InstKind};
669    ///
670    /// let nop = InstDesc::new("nop", InstKind::Plain, &[], &[], &[], RegSet::EMPTY);
671    /// assert!(nop.operands().is_empty());
672    /// ```
673    #[must_use]
674    pub const fn new(
675        name: &'static str,
676        kind: InstKind,
677        operands: &'static [OperandRule],
678        implicit_uses: &'static [PReg],
679        implicit_defs: &'static [PReg],
680        clobbers: RegSet,
681    ) -> InstDesc {
682        InstDesc {
683            name,
684            kind,
685            operands,
686            implicit_uses,
687            implicit_defs,
688            clobbers,
689        }
690    }
691
692    /// The instruction's MIR name.
693    ///
694    /// # Examples
695    ///
696    /// ```
697    /// use backend_lang::x86_64::{self, op};
698    ///
699    /// assert_eq!(x86_64::TARGET.inst(op::MOVZX8).unwrap().name(), "movzx8");
700    /// ```
701    #[inline]
702    #[must_use]
703    pub const fn name(&self) -> &'static str {
704        self.name
705    }
706
707    /// What the instruction does to control flow.
708    ///
709    /// # Examples
710    ///
711    /// ```
712    /// use backend_lang::target::InstKind;
713    /// use backend_lang::x86_64::{self, op};
714    ///
715    /// assert_eq!(x86_64::TARGET.inst(op::RET).unwrap().kind(), InstKind::Return);
716    /// ```
717    #[inline]
718    #[must_use]
719    pub const fn kind(&self) -> InstKind {
720        self.kind
721    }
722
723    /// The explicit operands, definitions first. Empty for
724    /// [`Opcode::COPY`] and [`Opcode::PCOPY`], whose operands are checked
725    /// by their own rule.
726    ///
727    /// # Examples
728    ///
729    /// ```
730    /// use backend_lang::x86_64::{self, op};
731    ///
732    /// assert_eq!(x86_64::TARGET.inst(op::CMP64).unwrap().operands().len(), 2);
733    /// ```
734    #[inline]
735    #[must_use]
736    pub const fn operands(&self) -> &'static [OperandRule] {
737        self.operands
738    }
739
740    /// The number of explicit definitions (the leading `Def` operands).
741    ///
742    /// # Examples
743    ///
744    /// ```
745    /// use backend_lang::x86_64::{self, op};
746    ///
747    /// assert_eq!(x86_64::TARGET.inst(op::ADD64).unwrap().defs(), 1);
748    /// assert_eq!(x86_64::TARGET.inst(op::CMP64).unwrap().defs(), 0);
749    /// ```
750    #[must_use]
751    pub fn defs(&self) -> usize {
752        self.operands
753            .iter()
754            .take_while(|r| matches!(r, OperandRule::Def(_)))
755            .count()
756    }
757
758    /// Registers the instruction reads without naming them.
759    ///
760    /// # Examples
761    ///
762    /// ```
763    /// use backend_lang::x86_64::{self, op, RAX};
764    ///
765    /// assert_eq!(x86_64::TARGET.inst(op::CQO).unwrap().implicit_uses(), [RAX]);
766    /// ```
767    #[inline]
768    #[must_use]
769    pub const fn implicit_uses(&self) -> &'static [PReg] {
770        self.implicit_uses
771    }
772
773    /// Registers the instruction writes without naming them, with defined
774    /// results.
775    ///
776    /// # Examples
777    ///
778    /// ```
779    /// use backend_lang::x86_64::{self, op, RDX};
780    ///
781    /// assert_eq!(x86_64::TARGET.inst(op::CQO).unwrap().implicit_defs(), [RDX]);
782    /// ```
783    #[inline]
784    #[must_use]
785    pub const fn implicit_defs(&self) -> &'static [PReg] {
786        self.implicit_defs
787    }
788
789    /// Registers the instruction leaves with unspecified contents.
790    ///
791    /// # Examples
792    ///
793    /// ```
794    /// use backend_lang::x86_64::{self, op, RCX, R11};
795    ///
796    /// let clobbers = x86_64::TARGET.inst(op::SYSCALL).unwrap().clobbers();
797    /// assert!(clobbers.contains(RCX) && clobbers.contains(R11));
798    /// ```
799    #[inline]
800    #[must_use]
801    pub const fn clobbers(&self) -> RegSet {
802        self.clobbers
803    }
804}
805
806/// How a target can move values, which picks the parallel-move resolver's
807/// strategy (see [`moves`](crate::moves)).
808///
809/// # Examples
810///
811/// ```
812/// use backend_lang::target::ImmRange;
813/// use backend_lang::x86_64;
814///
815/// let caps = x86_64::TARGET.move_caps();
816/// assert!(caps.swap());
817/// assert!(!caps.mem_to_mem());
818/// assert_eq!(caps.store_imm(), ImmRange::I32);
819/// ```
820#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
821pub struct MoveCaps {
822    swap: bool,
823    mem_to_mem: bool,
824    store_imm: ImmRange,
825}
826
827impl MoveCaps {
828    /// Describes a target's moves: whether it can exchange two registers in
829    /// one instruction, move memory to memory directly, and which immediates
830    /// it can store to memory directly.
831    ///
832    /// # Examples
833    ///
834    /// ```
835    /// use backend_lang::target::{ImmRange, MoveCaps};
836    ///
837    /// let caps = MoveCaps::new(false, false, ImmRange::None);
838    /// assert!(!caps.swap());
839    /// ```
840    #[must_use]
841    pub const fn new(swap: bool, mem_to_mem: bool, store_imm: ImmRange) -> MoveCaps {
842        MoveCaps {
843            swap,
844            mem_to_mem,
845            store_imm,
846        }
847    }
848
849    /// Whether two registers of a class can be exchanged by one instruction
850    /// (x86-64 `xchg`).
851    ///
852    /// # Examples
853    ///
854    /// ```
855    /// use backend_lang::x86_64;
856    ///
857    /// assert!(x86_64::TARGET.move_caps().swap());
858    /// ```
859    #[inline]
860    #[must_use]
861    pub const fn swap(self) -> bool {
862        self.swap
863    }
864
865    /// Whether memory can be copied to memory without a register.
866    ///
867    /// # Examples
868    ///
869    /// ```
870    /// use backend_lang::x86_64;
871    ///
872    /// assert!(!x86_64::TARGET.move_caps().mem_to_mem());
873    /// ```
874    #[inline]
875    #[must_use]
876    pub const fn mem_to_mem(self) -> bool {
877        self.mem_to_mem
878    }
879
880    /// The immediates that can be stored to memory in one instruction.
881    ///
882    /// # Examples
883    ///
884    /// ```
885    /// use backend_lang::target::ImmRange;
886    /// use backend_lang::x86_64;
887    ///
888    /// assert!(x86_64::TARGET.move_caps().store_imm().fits(-1));
889    /// ```
890    #[inline]
891    #[must_use]
892    pub const fn store_imm(self) -> ImmRange {
893        self.store_imm
894    }
895}
896
897/// A target: register file, classes, instructions, and the registers with
898/// fixed jobs.
899///
900/// Targets are static data; [`x86_64::TARGET`](crate::x86_64::TARGET) is the
901/// one this release ships.
902///
903/// # Examples
904///
905/// ```
906/// use backend_lang::x86_64::{self, RSP, RBP, FLAGS};
907///
908/// let t = &x86_64::TARGET;
909/// assert_eq!(t.name(), "x86-64");
910/// assert_eq!(t.stack_pointer(), RSP);
911/// assert_eq!(t.frame_pointer(), RBP);
912/// assert_eq!(t.flags(), Some(FLAGS));
913/// ```
914#[derive(Debug)]
915pub struct Target {
916    name: &'static str,
917    isa: Isa,
918    regs: &'static [RegInfo],
919    classes: &'static [ClassInfo],
920    insts: &'static [InstDesc],
921    stack_pointer: PReg,
922    frame_pointer: PReg,
923    flags: Option<PReg>,
924    addr_class: RegClass,
925    move_caps: MoveCaps,
926    max_mem_operands: u8,
927    conds: &'static [&'static str],
928}
929
930/// The registers with fixed jobs, and the target-wide limits, for
931/// [`Target::new`].
932///
933/// # Examples
934///
935/// ```
936/// use backend_lang::target::TargetConfig;
937/// use backend_lang::x86_64::{self, RSP};
938///
939/// let cfg = TargetConfig::of(&x86_64::TARGET);
940/// assert_eq!(cfg.stack_pointer, RSP);
941/// ```
942#[derive(Clone, Copy, Debug, PartialEq, Eq)]
943pub struct TargetConfig {
944    /// The stack pointer.
945    pub stack_pointer: PReg,
946    /// The frame pointer.
947    pub frame_pointer: PReg,
948    /// The condition-flags register, if the ISA has one.
949    pub flags: Option<PReg>,
950    /// The class of a memory operand's base and index registers.
951    pub addr_class: RegClass,
952    /// How values move.
953    pub move_caps: MoveCaps,
954    /// The most memory operands one instruction may have.
955    pub max_mem_operands: u8,
956    /// The condition codes' names, indexed by
957    /// [`CondCode::code`](crate::mir::CondCode::code) (at most 255).
958    pub conds: &'static [&'static str],
959}
960
961impl TargetConfig {
962    /// The configuration of an existing target, to derive a variant from.
963    ///
964    /// # Examples
965    ///
966    /// ```
967    /// use backend_lang::target::TargetConfig;
968    /// use backend_lang::x86_64;
969    ///
970    /// assert_eq!(TargetConfig::of(&x86_64::TARGET).conds.len(), 16);
971    /// ```
972    #[must_use]
973    pub const fn of(target: &Target) -> TargetConfig {
974        TargetConfig {
975            stack_pointer: target.stack_pointer,
976            frame_pointer: target.frame_pointer,
977            flags: target.flags,
978            addr_class: target.addr_class,
979            move_caps: target.move_caps,
980            max_mem_operands: target.max_mem_operands,
981            conds: target.conds,
982        }
983    }
984}
985
986impl Target {
987    /// Describes a target.
988    ///
989    /// `insts` must begin with the [`Opcode::COPY`] and [`Opcode::PCOPY`]
990    /// descriptions (see [`Target::generic_insts`]); registers' classes must
991    /// index `classes`; at most [`MAX_PREGS`](crate::MAX_PREGS) registers.
992    /// The crate's own targets are checked by its tests; a hand-made one
993    /// that breaks these rules is caught by [`Function::verify`] as operands
994    /// that fit no class.
995    ///
996    /// # Examples
997    ///
998    /// A variant of x86-64 without `xchg`, to make the parallel-move
999    /// resolver break cycles through a scratch register instead:
1000    ///
1001    /// ```
1002    /// use backend_lang::target::{MoveCaps, ImmRange, Target, TargetConfig};
1003    /// use backend_lang::x86_64;
1004    ///
1005    /// let base = &x86_64::TARGET;
1006    /// let mut cfg = TargetConfig::of(base);
1007    /// cfg.move_caps = MoveCaps::new(false, false, ImmRange::I32);
1008    /// let no_swap = Target::new("x86-64-noswap", base.isa(), base.regs(), base.classes(), base.insts(), cfg);
1009    /// assert!(!no_swap.move_caps().swap());
1010    /// ```
1011    ///
1012    /// [`Function::verify`]: crate::mir::Function::verify
1013    #[must_use]
1014    pub const fn new(
1015        name: &'static str,
1016        isa: Isa,
1017        regs: &'static [RegInfo],
1018        classes: &'static [ClassInfo],
1019        insts: &'static [InstDesc],
1020        config: TargetConfig,
1021    ) -> Target {
1022        Target {
1023            name,
1024            isa,
1025            regs,
1026            classes,
1027            insts,
1028            stack_pointer: config.stack_pointer,
1029            frame_pointer: config.frame_pointer,
1030            flags: config.flags,
1031            addr_class: config.addr_class,
1032            move_caps: config.move_caps,
1033            max_mem_operands: config.max_mem_operands,
1034            conds: config.conds,
1035        }
1036    }
1037
1038    /// The two generic descriptions every instruction table starts with,
1039    /// [`Opcode::COPY`] then [`Opcode::PCOPY`].
1040    ///
1041    /// # Examples
1042    ///
1043    /// ```
1044    /// use backend_lang::target::{InstKind, Target};
1045    ///
1046    /// let [copy, pcopy] = Target::generic_insts();
1047    /// assert_eq!(copy.kind(), InstKind::Copy);
1048    /// assert_eq!(pcopy.name(), "pcopy");
1049    /// ```
1050    #[must_use]
1051    pub const fn generic_insts() -> [InstDesc; 2] {
1052        [
1053            InstDesc::new("copy", InstKind::Copy, &[], &[], &[], RegSet::EMPTY),
1054            InstDesc::new(
1055                "pcopy",
1056                InstKind::ParallelCopy,
1057                &[],
1058                &[],
1059                &[],
1060                RegSet::EMPTY,
1061            ),
1062        ]
1063    }
1064
1065    /// The target's name.
1066    ///
1067    /// # Examples
1068    ///
1069    /// ```
1070    /// use backend_lang::x86_64;
1071    ///
1072    /// assert_eq!(x86_64::TARGET.name(), "x86-64");
1073    /// ```
1074    #[inline]
1075    #[must_use]
1076    pub const fn name(&self) -> &'static str {
1077        self.name
1078    }
1079
1080    /// The ISA, which selects the encoder.
1081    ///
1082    /// # Examples
1083    ///
1084    /// ```
1085    /// use backend_lang::target::Isa;
1086    /// use backend_lang::x86_64;
1087    ///
1088    /// assert_eq!(x86_64::TARGET.isa(), Isa::X86_64);
1089    /// ```
1090    #[inline]
1091    #[must_use]
1092    pub const fn isa(&self) -> Isa {
1093        self.isa
1094    }
1095
1096    /// The register file, indexed by [`PReg::index`].
1097    ///
1098    /// # Examples
1099    ///
1100    /// ```
1101    /// use backend_lang::x86_64;
1102    ///
1103    /// assert_eq!(x86_64::TARGET.regs().len(), 33);
1104    /// ```
1105    #[inline]
1106    #[must_use]
1107    pub const fn regs(&self) -> &'static [RegInfo] {
1108        self.regs
1109    }
1110
1111    /// One register's description. An index the target does not have gets a
1112    /// placeholder named `<invalid>`, in no class.
1113    ///
1114    /// # Examples
1115    ///
1116    /// ```
1117    /// use backend_lang::PReg;
1118    /// use backend_lang::x86_64::{self, RDI};
1119    ///
1120    /// assert_eq!(x86_64::TARGET.reg(RDI).name(), "rdi");
1121    /// assert_eq!(x86_64::TARGET.reg(PReg::new(100).unwrap()).name(), "<invalid>");
1122    /// ```
1123    #[inline]
1124    #[must_use]
1125    pub fn reg(&self, reg: PReg) -> &RegInfo {
1126        self.regs.get(reg.index()).unwrap_or(&INVALID_REG)
1127    }
1128
1129    /// Whether the target has a register with this index.
1130    ///
1131    /// # Examples
1132    ///
1133    /// ```
1134    /// use backend_lang::PReg;
1135    /// use backend_lang::x86_64::{self, RAX};
1136    ///
1137    /// assert!(x86_64::TARGET.has_reg(RAX));
1138    /// assert!(!x86_64::TARGET.has_reg(PReg::new(100).unwrap()));
1139    /// ```
1140    #[inline]
1141    #[must_use]
1142    pub fn has_reg(&self, reg: PReg) -> bool {
1143        reg.index() < self.regs.len()
1144    }
1145
1146    /// The class table, indexed by [`RegClass::index`].
1147    ///
1148    /// # Examples
1149    ///
1150    /// ```
1151    /// use backend_lang::x86_64;
1152    ///
1153    /// assert_eq!(x86_64::TARGET.classes().len(), 3);
1154    /// ```
1155    #[inline]
1156    #[must_use]
1157    pub const fn classes(&self) -> &'static [ClassInfo] {
1158        self.classes
1159    }
1160
1161    /// One class's description. A class the target does not have gets an
1162    /// empty placeholder named `<invalid>`.
1163    ///
1164    /// # Examples
1165    ///
1166    /// ```
1167    /// use backend_lang::RegClass;
1168    /// use backend_lang::x86_64::{self, GPR};
1169    ///
1170    /// assert_eq!(x86_64::TARGET.class(GPR).name(), "gpr");
1171    /// assert!(x86_64::TARGET.class(RegClass::new(9)).regs().is_empty());
1172    /// ```
1173    #[inline]
1174    #[must_use]
1175    pub fn class(&self, class: RegClass) -> &ClassInfo {
1176        self.classes.get(class.index()).unwrap_or(&INVALID_CLASS)
1177    }
1178
1179    /// Whether the target has this class.
1180    ///
1181    /// # Examples
1182    ///
1183    /// ```
1184    /// use backend_lang::RegClass;
1185    /// use backend_lang::x86_64::{self, VEC};
1186    ///
1187    /// assert!(x86_64::TARGET.has_class(VEC));
1188    /// assert!(!x86_64::TARGET.has_class(RegClass::new(9)));
1189    /// ```
1190    #[inline]
1191    #[must_use]
1192    pub fn has_class(&self, class: RegClass) -> bool {
1193        class.index() < self.classes.len()
1194    }
1195
1196    /// The instruction table, indexed by [`Opcode::index`].
1197    ///
1198    /// # Examples
1199    ///
1200    /// ```
1201    /// use backend_lang::x86_64;
1202    ///
1203    /// assert!(x86_64::TARGET.insts().len() > 80);
1204    /// ```
1205    #[inline]
1206    #[must_use]
1207    pub const fn insts(&self) -> &'static [InstDesc] {
1208        self.insts
1209    }
1210
1211    /// One instruction's description, or `None` for an opcode the target
1212    /// does not have.
1213    ///
1214    /// # Examples
1215    ///
1216    /// ```
1217    /// use backend_lang::target::Opcode;
1218    /// use backend_lang::x86_64::{self, op};
1219    ///
1220    /// assert!(x86_64::TARGET.inst(op::LEA64).is_some());
1221    /// assert!(x86_64::TARGET.inst(Opcode::new(60000)).is_none());
1222    /// ```
1223    #[inline]
1224    #[must_use]
1225    pub fn inst(&self, opcode: Opcode) -> Option<&'static InstDesc> {
1226        self.insts.get(opcode.index())
1227    }
1228
1229    /// The opcode whose MIR name is `name`, by a scan of the table.
1230    ///
1231    /// # Examples
1232    ///
1233    /// ```
1234    /// use backend_lang::x86_64::{self, op};
1235    ///
1236    /// assert_eq!(x86_64::TARGET.opcode("sub32"), Some(op::SUB32));
1237    /// assert_eq!(x86_64::TARGET.opcode("frobnicate"), None);
1238    /// ```
1239    #[must_use]
1240    pub fn opcode(&self, name: &str) -> Option<Opcode> {
1241        self.insts
1242            .iter()
1243            .position(|d| d.name == name)
1244            .and_then(|i| u16::try_from(i).ok())
1245            .map(Opcode)
1246    }
1247
1248    /// The stack pointer.
1249    ///
1250    /// # Examples
1251    ///
1252    /// ```
1253    /// use backend_lang::x86_64::{self, RSP};
1254    ///
1255    /// assert_eq!(x86_64::TARGET.stack_pointer(), RSP);
1256    /// ```
1257    #[inline]
1258    #[must_use]
1259    pub const fn stack_pointer(&self) -> PReg {
1260        self.stack_pointer
1261    }
1262
1263    /// The frame pointer.
1264    ///
1265    /// # Examples
1266    ///
1267    /// ```
1268    /// use backend_lang::x86_64::{self, RBP};
1269    ///
1270    /// assert_eq!(x86_64::TARGET.frame_pointer(), RBP);
1271    /// ```
1272    #[inline]
1273    #[must_use]
1274    pub const fn frame_pointer(&self) -> PReg {
1275        self.frame_pointer
1276    }
1277
1278    /// The condition-flags register, modelled as a physical register so that
1279    /// flag producers and consumers are ordinary implicit definitions and
1280    /// uses.
1281    ///
1282    /// # Examples
1283    ///
1284    /// ```
1285    /// use backend_lang::x86_64::{self, FLAGS};
1286    ///
1287    /// assert_eq!(x86_64::TARGET.flags(), Some(FLAGS));
1288    /// ```
1289    #[inline]
1290    #[must_use]
1291    pub const fn flags(&self) -> Option<PReg> {
1292        self.flags
1293    }
1294
1295    /// The class of memory operands' base and index registers.
1296    ///
1297    /// # Examples
1298    ///
1299    /// ```
1300    /// use backend_lang::x86_64::{self, GPR};
1301    ///
1302    /// assert_eq!(x86_64::TARGET.addr_class(), GPR);
1303    /// ```
1304    #[inline]
1305    #[must_use]
1306    pub const fn addr_class(&self) -> RegClass {
1307        self.addr_class
1308    }
1309
1310    /// How values move on this target.
1311    ///
1312    /// # Examples
1313    ///
1314    /// ```
1315    /// use backend_lang::x86_64;
1316    ///
1317    /// assert!(x86_64::TARGET.move_caps().swap());
1318    /// ```
1319    #[inline]
1320    #[must_use]
1321    pub const fn move_caps(&self) -> MoveCaps {
1322        self.move_caps
1323    }
1324
1325    /// The most memory operands one instruction may have (one on x86-64).
1326    ///
1327    /// # Examples
1328    ///
1329    /// ```
1330    /// use backend_lang::x86_64;
1331    ///
1332    /// assert_eq!(x86_64::TARGET.max_mem_operands(), 1);
1333    /// ```
1334    #[inline]
1335    #[must_use]
1336    pub const fn max_mem_operands(&self) -> u8 {
1337        self.max_mem_operands
1338    }
1339
1340    /// The number of condition codes; a `Cond` operand is below it.
1341    ///
1342    /// # Examples
1343    ///
1344    /// ```
1345    /// use backend_lang::x86_64;
1346    ///
1347    /// assert_eq!(x86_64::TARGET.conds(), 16);
1348    /// ```
1349    #[inline]
1350    #[must_use]
1351    pub const fn conds(&self) -> u8 {
1352        if self.conds.len() > u8::MAX as usize {
1353            u8::MAX
1354        } else {
1355            self.conds.len() as u8
1356        }
1357    }
1358
1359    /// A condition code's name (`<invalid>` for one the target does not
1360    /// have).
1361    ///
1362    /// # Examples
1363    ///
1364    /// ```
1365    /// use backend_lang::mir::CondCode;
1366    /// use backend_lang::x86_64;
1367    ///
1368    /// assert_eq!(x86_64::TARGET.cond_name(CondCode::new(4)), "e");
1369    /// assert_eq!(x86_64::TARGET.cond_name(CondCode::new(99)), "<invalid>");
1370    /// ```
1371    #[inline]
1372    #[must_use]
1373    pub fn cond_name(&self, cond: crate::mir::CondCode) -> &'static str {
1374        self.conds
1375            .get(usize::from(cond.code()))
1376            .copied()
1377            .unwrap_or("<invalid>")
1378    }
1379
1380    /// The class of a physical register, or `None` if the target does not
1381    /// have it.
1382    ///
1383    /// # Examples
1384    ///
1385    /// ```
1386    /// use backend_lang::x86_64::{self, GPR, R8};
1387    ///
1388    /// assert_eq!(x86_64::TARGET.class_of(R8), Some(GPR));
1389    /// ```
1390    #[inline]
1391    #[must_use]
1392    pub fn class_of(&self, reg: PReg) -> Option<RegClass> {
1393        self.regs.get(reg.index()).map(RegInfo::class)
1394    }
1395}