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    /// A tail call: the epilogue runs, then control jumps to the callee,
372    /// which returns to this function's caller.
373    TailCall,
374    /// A multi-way branch through a table: a temporary definition, an index
375    /// register, then one target block per index (`jmptbl`). The targets
376    /// take no arguments. The temporary is written before the index is last
377    /// read, so the register allocator never gives the two one register.
378    Switch,
379}
380
381impl InstKind {
382    /// Whether the instruction ends a block: jumps, branches, returns, traps,
383    /// tail calls, and table branches.
384    ///
385    /// # Examples
386    ///
387    /// ```
388    /// use backend_lang::target::InstKind;
389    ///
390    /// assert!(InstKind::Return.is_terminator());
391    /// assert!(!InstKind::Plain.is_terminator());
392    /// ```
393    #[inline]
394    #[must_use]
395    pub const fn is_terminator(self) -> bool {
396        matches!(
397            self,
398            InstKind::Jump
399                | InstKind::Branch
400                | InstKind::Return
401                | InstKind::Trap
402                | InstKind::TailCall
403                | InstKind::Switch
404        )
405    }
406}
407
408/// The values an immediate operand may take.
409///
410/// Immediates are signed values of the operation's width, as isa-lang takes
411/// them (TARGET-DESC ยง3.1): for a 32-bit operation, all ones is `-1`.
412///
413/// # Examples
414///
415/// ```
416/// use backend_lang::target::ImmRange;
417///
418/// assert!(ImmRange::I8.fits(-128));
419/// assert!(!ImmRange::I8.fits(128));
420/// assert!(ImmRange::U8.fits(255));
421/// assert!(!ImmRange::None.fits(0));
422/// ```
423#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
424#[non_exhaustive]
425pub enum ImmRange {
426    /// No immediate is accepted.
427    None,
428    /// `-128..=127`.
429    I8,
430    /// `0..=255`.
431    U8,
432    /// `-32768..=32767`.
433    I16,
434    /// `-2^31..=2^31-1`.
435    I32,
436    /// Any 64-bit value.
437    I64,
438}
439
440impl ImmRange {
441    /// Whether `value` is in the range.
442    ///
443    /// # Examples
444    ///
445    /// ```
446    /// use backend_lang::target::ImmRange;
447    ///
448    /// assert!(ImmRange::I32.fits(i64::from(i32::MIN)));
449    /// assert!(!ImmRange::I32.fits(1 << 31));
450    /// assert!(ImmRange::I64.fits(i64::MIN));
451    /// ```
452    #[inline]
453    #[must_use]
454    pub const fn fits(self, value: i64) -> bool {
455        match self {
456            ImmRange::None => false,
457            ImmRange::I8 => value >= -128 && value <= 127,
458            ImmRange::U8 => value >= 0 && value <= 255,
459            ImmRange::I16 => value >= i16::MIN as i64 && value <= i16::MAX as i64,
460            ImmRange::I32 => value >= i32::MIN as i64 && value <= i32::MAX as i64,
461            ImmRange::I64 => true,
462        }
463    }
464}
465
466/// Which operand shapes a use accepts: a register, memory (an address or a
467/// stack slot), an immediate in a range, a function symbol.
468///
469/// # Examples
470///
471/// ```
472/// use backend_lang::target::{Accept, ImmRange};
473///
474/// let rmi = Accept::RM.with_imm(ImmRange::I32);
475/// assert!(rmi.reg() && rmi.mem());
476/// assert_eq!(rmi.imm(), ImmRange::I32);
477/// assert!(!Accept::REG.mem());
478/// ```
479#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
480pub struct Accept {
481    reg: bool,
482    mem: bool,
483    symbol: bool,
484    imm: ImmRange,
485}
486
487impl Accept {
488    /// A register only.
489    pub const REG: Accept = Accept {
490        reg: true,
491        mem: false,
492        symbol: false,
493        imm: ImmRange::None,
494    };
495    /// Memory only.
496    pub const MEM: Accept = Accept {
497        reg: false,
498        mem: true,
499        symbol: false,
500        imm: ImmRange::None,
501    };
502    /// A register or memory.
503    pub const RM: Accept = Accept {
504        reg: true,
505        mem: true,
506        symbol: false,
507        imm: ImmRange::None,
508    };
509    /// Nothing; extend with the `with_*` methods.
510    pub const NONE: Accept = Accept {
511        reg: false,
512        mem: false,
513        symbol: false,
514        imm: ImmRange::None,
515    };
516
517    /// Also accepts immediates in `range`.
518    ///
519    /// # Examples
520    ///
521    /// ```
522    /// use backend_lang::target::{Accept, ImmRange};
523    ///
524    /// assert_eq!(Accept::REG.with_imm(ImmRange::U8).imm(), ImmRange::U8);
525    /// ```
526    #[must_use]
527    pub const fn with_imm(self, range: ImmRange) -> Accept {
528        Accept { imm: range, ..self }
529    }
530
531    /// Also accepts a function symbol (a direct call target, or the address
532    /// of a function as a RIP-relative memory operand).
533    ///
534    /// # Examples
535    ///
536    /// ```
537    /// use backend_lang::target::Accept;
538    ///
539    /// assert!(Accept::MEM.with_symbol().symbol());
540    /// ```
541    #[must_use]
542    pub const fn with_symbol(self) -> Accept {
543        Accept {
544            symbol: true,
545            ..self
546        }
547    }
548
549    /// Whether a register is accepted.
550    ///
551    /// # Examples
552    ///
553    /// ```
554    /// use backend_lang::target::Accept;
555    ///
556    /// assert!(Accept::RM.reg());
557    /// ```
558    #[inline]
559    #[must_use]
560    pub const fn reg(self) -> bool {
561        self.reg
562    }
563
564    /// Whether memory (an address or a stack slot) is accepted.
565    ///
566    /// # Examples
567    ///
568    /// ```
569    /// use backend_lang::target::Accept;
570    ///
571    /// assert!(Accept::MEM.mem());
572    /// ```
573    #[inline]
574    #[must_use]
575    pub const fn mem(self) -> bool {
576        self.mem
577    }
578
579    /// Whether a function symbol is accepted.
580    ///
581    /// # Examples
582    ///
583    /// ```
584    /// use backend_lang::target::Accept;
585    ///
586    /// assert!(!Accept::RM.symbol());
587    /// ```
588    #[inline]
589    #[must_use]
590    pub const fn symbol(self) -> bool {
591        self.symbol
592    }
593
594    /// The immediates accepted.
595    ///
596    /// # Examples
597    ///
598    /// ```
599    /// use backend_lang::target::{Accept, ImmRange};
600    ///
601    /// assert_eq!(Accept::RM.imm(), ImmRange::None);
602    /// ```
603    #[inline]
604    #[must_use]
605    pub const fn imm(self) -> ImmRange {
606        self.imm
607    }
608}
609
610/// The rule for one explicit operand of an instruction.
611///
612/// Operands are listed definitions first, then uses, as the MIR printer
613/// shows them (`%2 = add64 %0, %1`).
614///
615/// # Examples
616///
617/// ```
618/// use backend_lang::target::{Accept, ImmRange, OperandRule};
619/// use backend_lang::x86_64::{self, op, GPR};
620///
621/// let add = x86_64::TARGET.inst(op::ADD64).unwrap();
622/// assert_eq!(add.operands()[0], OperandRule::Def(GPR));
623/// assert_eq!(add.operands()[1], OperandRule::Tied(0));
624/// assert_eq!(add.operands()[2], OperandRule::Use(GPR, Accept::RM.with_imm(ImmRange::I32)));
625/// ```
626#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
627#[non_exhaustive]
628pub enum OperandRule {
629    /// A register the instruction writes, of this class.
630    Def(RegClass),
631    /// A use that must be the same register as definition `n`: the
632    /// two-address constraint (`add d, s` reads and writes `d`). In SSA form
633    /// the definition and the tied use are different virtual registers; the
634    /// register allocator gives them one physical register.
635    Tied(u8),
636    /// A value the instruction reads, of this class (for a register; the
637    /// class of a memory operand's base and index is the target's address
638    /// class), in the shapes `Accept` allows.
639    Use(RegClass, Accept),
640    /// A condition code.
641    Cond,
642    /// A branch target with its arguments.
643    Block,
644}
645
646/// One machine instruction's description.
647///
648/// # Examples
649///
650/// ```
651/// use backend_lang::target::InstKind;
652/// use backend_lang::x86_64::{self, op, RAX, RDX, FLAGS};
653///
654/// let div = x86_64::TARGET.inst(op::IDIV64).unwrap();
655/// assert_eq!(div.name(), "idiv64");
656/// assert_eq!(div.kind(), InstKind::Plain);
657/// assert_eq!(div.implicit_uses(), [RAX, RDX]);
658/// assert_eq!(div.implicit_defs(), [RAX, RDX, FLAGS]);
659/// ```
660#[derive(Clone, Copy, Debug, PartialEq, Eq)]
661pub struct InstDesc {
662    name: &'static str,
663    kind: InstKind,
664    operands: &'static [OperandRule],
665    implicit_uses: &'static [PReg],
666    implicit_defs: &'static [PReg],
667    clobbers: RegSet,
668}
669
670impl InstDesc {
671    /// Describes an instruction.
672    ///
673    /// `implicit_uses` are registers read without being named as operands,
674    /// `implicit_defs` registers written that way (results the code may read
675    /// afterwards, such as `idiv`'s quotient in `rax`), and `clobbers`
676    /// registers left with unspecified contents.
677    ///
678    /// # Examples
679    ///
680    /// ```
681    /// use backend_lang::RegSet;
682    /// use backend_lang::target::{InstDesc, InstKind};
683    ///
684    /// let nop = InstDesc::new("nop", InstKind::Plain, &[], &[], &[], RegSet::EMPTY);
685    /// assert!(nop.operands().is_empty());
686    /// ```
687    #[must_use]
688    pub const fn new(
689        name: &'static str,
690        kind: InstKind,
691        operands: &'static [OperandRule],
692        implicit_uses: &'static [PReg],
693        implicit_defs: &'static [PReg],
694        clobbers: RegSet,
695    ) -> InstDesc {
696        InstDesc {
697            name,
698            kind,
699            operands,
700            implicit_uses,
701            implicit_defs,
702            clobbers,
703        }
704    }
705
706    /// The instruction's MIR name.
707    ///
708    /// # Examples
709    ///
710    /// ```
711    /// use backend_lang::x86_64::{self, op};
712    ///
713    /// assert_eq!(x86_64::TARGET.inst(op::MOVZX8).unwrap().name(), "movzx8");
714    /// ```
715    #[inline]
716    #[must_use]
717    pub const fn name(&self) -> &'static str {
718        self.name
719    }
720
721    /// What the instruction does to control flow.
722    ///
723    /// # Examples
724    ///
725    /// ```
726    /// use backend_lang::target::InstKind;
727    /// use backend_lang::x86_64::{self, op};
728    ///
729    /// assert_eq!(x86_64::TARGET.inst(op::RET).unwrap().kind(), InstKind::Return);
730    /// ```
731    #[inline]
732    #[must_use]
733    pub const fn kind(&self) -> InstKind {
734        self.kind
735    }
736
737    /// The explicit operands, definitions first. Empty for
738    /// [`Opcode::COPY`] and [`Opcode::PCOPY`], whose operands are checked
739    /// by their own rule.
740    ///
741    /// # Examples
742    ///
743    /// ```
744    /// use backend_lang::x86_64::{self, op};
745    ///
746    /// assert_eq!(x86_64::TARGET.inst(op::CMP64).unwrap().operands().len(), 2);
747    /// ```
748    #[inline]
749    #[must_use]
750    pub const fn operands(&self) -> &'static [OperandRule] {
751        self.operands
752    }
753
754    /// The number of explicit definitions (the leading `Def` operands).
755    ///
756    /// # Examples
757    ///
758    /// ```
759    /// use backend_lang::x86_64::{self, op};
760    ///
761    /// assert_eq!(x86_64::TARGET.inst(op::ADD64).unwrap().defs(), 1);
762    /// assert_eq!(x86_64::TARGET.inst(op::CMP64).unwrap().defs(), 0);
763    /// ```
764    #[must_use]
765    pub fn defs(&self) -> usize {
766        self.operands
767            .iter()
768            .take_while(|r| matches!(r, OperandRule::Def(_)))
769            .count()
770    }
771
772    /// Registers the instruction reads without naming them.
773    ///
774    /// # Examples
775    ///
776    /// ```
777    /// use backend_lang::x86_64::{self, op, RAX};
778    ///
779    /// assert_eq!(x86_64::TARGET.inst(op::CQO).unwrap().implicit_uses(), [RAX]);
780    /// ```
781    #[inline]
782    #[must_use]
783    pub const fn implicit_uses(&self) -> &'static [PReg] {
784        self.implicit_uses
785    }
786
787    /// Registers the instruction writes without naming them, with defined
788    /// results.
789    ///
790    /// # Examples
791    ///
792    /// ```
793    /// use backend_lang::x86_64::{self, op, RDX};
794    ///
795    /// assert_eq!(x86_64::TARGET.inst(op::CQO).unwrap().implicit_defs(), [RDX]);
796    /// ```
797    #[inline]
798    #[must_use]
799    pub const fn implicit_defs(&self) -> &'static [PReg] {
800        self.implicit_defs
801    }
802
803    /// Registers the instruction leaves with unspecified contents.
804    ///
805    /// # Examples
806    ///
807    /// ```
808    /// use backend_lang::x86_64::{self, op, RCX, R11};
809    ///
810    /// let clobbers = x86_64::TARGET.inst(op::SYSCALL).unwrap().clobbers();
811    /// assert!(clobbers.contains(RCX) && clobbers.contains(R11));
812    /// ```
813    #[inline]
814    #[must_use]
815    pub const fn clobbers(&self) -> RegSet {
816        self.clobbers
817    }
818}
819
820/// How a target can move values, which picks the parallel-move resolver's
821/// strategy (see [`moves`](crate::moves)).
822///
823/// # Examples
824///
825/// ```
826/// use backend_lang::target::ImmRange;
827/// use backend_lang::x86_64;
828///
829/// let caps = x86_64::TARGET.move_caps();
830/// assert!(caps.swap());
831/// assert!(!caps.mem_to_mem());
832/// assert_eq!(caps.store_imm(), ImmRange::I32);
833/// ```
834#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
835pub struct MoveCaps {
836    swap: bool,
837    mem_to_mem: bool,
838    store_imm: ImmRange,
839}
840
841impl MoveCaps {
842    /// Describes a target's moves: whether it can exchange two registers in
843    /// one instruction, move memory to memory directly, and which immediates
844    /// it can store to memory directly.
845    ///
846    /// # Examples
847    ///
848    /// ```
849    /// use backend_lang::target::{ImmRange, MoveCaps};
850    ///
851    /// let caps = MoveCaps::new(false, false, ImmRange::None);
852    /// assert!(!caps.swap());
853    /// ```
854    #[must_use]
855    pub const fn new(swap: bool, mem_to_mem: bool, store_imm: ImmRange) -> MoveCaps {
856        MoveCaps {
857            swap,
858            mem_to_mem,
859            store_imm,
860        }
861    }
862
863    /// Whether two registers of a class can be exchanged by one instruction
864    /// (x86-64 `xchg`).
865    ///
866    /// # Examples
867    ///
868    /// ```
869    /// use backend_lang::x86_64;
870    ///
871    /// assert!(x86_64::TARGET.move_caps().swap());
872    /// ```
873    #[inline]
874    #[must_use]
875    pub const fn swap(self) -> bool {
876        self.swap
877    }
878
879    /// Whether memory can be copied to memory without a register.
880    ///
881    /// # Examples
882    ///
883    /// ```
884    /// use backend_lang::x86_64;
885    ///
886    /// assert!(!x86_64::TARGET.move_caps().mem_to_mem());
887    /// ```
888    #[inline]
889    #[must_use]
890    pub const fn mem_to_mem(self) -> bool {
891        self.mem_to_mem
892    }
893
894    /// The immediates that can be stored to memory in one instruction.
895    ///
896    /// # Examples
897    ///
898    /// ```
899    /// use backend_lang::target::ImmRange;
900    /// use backend_lang::x86_64;
901    ///
902    /// assert!(x86_64::TARGET.move_caps().store_imm().fits(-1));
903    /// ```
904    #[inline]
905    #[must_use]
906    pub const fn store_imm(self) -> ImmRange {
907        self.store_imm
908    }
909}
910
911/// A target: register file, classes, instructions, and the registers with
912/// fixed jobs.
913///
914/// Targets are static data; [`x86_64::TARGET`](crate::x86_64::TARGET) is the
915/// one this release ships.
916///
917/// # Examples
918///
919/// ```
920/// use backend_lang::x86_64::{self, RSP, RBP, FLAGS};
921///
922/// let t = &x86_64::TARGET;
923/// assert_eq!(t.name(), "x86-64");
924/// assert_eq!(t.stack_pointer(), RSP);
925/// assert_eq!(t.frame_pointer(), RBP);
926/// assert_eq!(t.flags(), Some(FLAGS));
927/// ```
928#[derive(Debug)]
929pub struct Target {
930    name: &'static str,
931    isa: Isa,
932    regs: &'static [RegInfo],
933    classes: &'static [ClassInfo],
934    insts: &'static [InstDesc],
935    stack_pointer: PReg,
936    frame_pointer: PReg,
937    flags: Option<PReg>,
938    addr_class: RegClass,
939    move_caps: MoveCaps,
940    max_mem_operands: u8,
941    conds: &'static [&'static str],
942}
943
944/// The registers with fixed jobs, and the target-wide limits, for
945/// [`Target::new`].
946///
947/// # Examples
948///
949/// ```
950/// use backend_lang::target::TargetConfig;
951/// use backend_lang::x86_64::{self, RSP};
952///
953/// let cfg = TargetConfig::of(&x86_64::TARGET);
954/// assert_eq!(cfg.stack_pointer, RSP);
955/// ```
956#[derive(Clone, Copy, Debug, PartialEq, Eq)]
957pub struct TargetConfig {
958    /// The stack pointer.
959    pub stack_pointer: PReg,
960    /// The frame pointer.
961    pub frame_pointer: PReg,
962    /// The condition-flags register, if the ISA has one.
963    pub flags: Option<PReg>,
964    /// The class of a memory operand's base and index registers.
965    pub addr_class: RegClass,
966    /// How values move.
967    pub move_caps: MoveCaps,
968    /// The most memory operands one instruction may have.
969    pub max_mem_operands: u8,
970    /// The condition codes' names, indexed by
971    /// [`CondCode::code`](crate::mir::CondCode::code) (at most 255).
972    pub conds: &'static [&'static str],
973}
974
975impl TargetConfig {
976    /// The configuration of an existing target, to derive a variant from.
977    ///
978    /// # Examples
979    ///
980    /// ```
981    /// use backend_lang::target::TargetConfig;
982    /// use backend_lang::x86_64;
983    ///
984    /// assert_eq!(TargetConfig::of(&x86_64::TARGET).conds.len(), 16);
985    /// ```
986    #[must_use]
987    pub const fn of(target: &Target) -> TargetConfig {
988        TargetConfig {
989            stack_pointer: target.stack_pointer,
990            frame_pointer: target.frame_pointer,
991            flags: target.flags,
992            addr_class: target.addr_class,
993            move_caps: target.move_caps,
994            max_mem_operands: target.max_mem_operands,
995            conds: target.conds,
996        }
997    }
998}
999
1000impl Target {
1001    /// Describes a target.
1002    ///
1003    /// `insts` must begin with the [`Opcode::COPY`] and [`Opcode::PCOPY`]
1004    /// descriptions (see [`Target::generic_insts`]); registers' classes must
1005    /// index `classes`; at most [`MAX_PREGS`](crate::MAX_PREGS) registers.
1006    /// The crate's own targets are checked by its tests; a hand-made one
1007    /// that breaks these rules is caught by [`Function::verify`] as operands
1008    /// that fit no class.
1009    ///
1010    /// # Examples
1011    ///
1012    /// A variant of x86-64 without `xchg`, to make the parallel-move
1013    /// resolver break cycles through a scratch register instead:
1014    ///
1015    /// ```
1016    /// use backend_lang::target::{MoveCaps, ImmRange, Target, TargetConfig};
1017    /// use backend_lang::x86_64;
1018    ///
1019    /// let base = &x86_64::TARGET;
1020    /// let mut cfg = TargetConfig::of(base);
1021    /// cfg.move_caps = MoveCaps::new(false, false, ImmRange::I32);
1022    /// let no_swap = Target::new("x86-64-noswap", base.isa(), base.regs(), base.classes(), base.insts(), cfg);
1023    /// assert!(!no_swap.move_caps().swap());
1024    /// ```
1025    ///
1026    /// [`Function::verify`]: crate::mir::Function::verify
1027    #[must_use]
1028    pub const fn new(
1029        name: &'static str,
1030        isa: Isa,
1031        regs: &'static [RegInfo],
1032        classes: &'static [ClassInfo],
1033        insts: &'static [InstDesc],
1034        config: TargetConfig,
1035    ) -> Target {
1036        Target {
1037            name,
1038            isa,
1039            regs,
1040            classes,
1041            insts,
1042            stack_pointer: config.stack_pointer,
1043            frame_pointer: config.frame_pointer,
1044            flags: config.flags,
1045            addr_class: config.addr_class,
1046            move_caps: config.move_caps,
1047            max_mem_operands: config.max_mem_operands,
1048            conds: config.conds,
1049        }
1050    }
1051
1052    /// The two generic descriptions every instruction table starts with,
1053    /// [`Opcode::COPY`] then [`Opcode::PCOPY`].
1054    ///
1055    /// # Examples
1056    ///
1057    /// ```
1058    /// use backend_lang::target::{InstKind, Target};
1059    ///
1060    /// let [copy, pcopy] = Target::generic_insts();
1061    /// assert_eq!(copy.kind(), InstKind::Copy);
1062    /// assert_eq!(pcopy.name(), "pcopy");
1063    /// ```
1064    #[must_use]
1065    pub const fn generic_insts() -> [InstDesc; 2] {
1066        [
1067            InstDesc::new("copy", InstKind::Copy, &[], &[], &[], RegSet::EMPTY),
1068            InstDesc::new(
1069                "pcopy",
1070                InstKind::ParallelCopy,
1071                &[],
1072                &[],
1073                &[],
1074                RegSet::EMPTY,
1075            ),
1076        ]
1077    }
1078
1079    /// The target's name.
1080    ///
1081    /// # Examples
1082    ///
1083    /// ```
1084    /// use backend_lang::x86_64;
1085    ///
1086    /// assert_eq!(x86_64::TARGET.name(), "x86-64");
1087    /// ```
1088    #[inline]
1089    #[must_use]
1090    pub const fn name(&self) -> &'static str {
1091        self.name
1092    }
1093
1094    /// The ISA, which selects the encoder.
1095    ///
1096    /// # Examples
1097    ///
1098    /// ```
1099    /// use backend_lang::target::Isa;
1100    /// use backend_lang::x86_64;
1101    ///
1102    /// assert_eq!(x86_64::TARGET.isa(), Isa::X86_64);
1103    /// ```
1104    #[inline]
1105    #[must_use]
1106    pub const fn isa(&self) -> Isa {
1107        self.isa
1108    }
1109
1110    /// The register file, indexed by [`PReg::index`].
1111    ///
1112    /// # Examples
1113    ///
1114    /// ```
1115    /// use backend_lang::x86_64;
1116    ///
1117    /// assert_eq!(x86_64::TARGET.regs().len(), 33);
1118    /// ```
1119    #[inline]
1120    #[must_use]
1121    pub const fn regs(&self) -> &'static [RegInfo] {
1122        self.regs
1123    }
1124
1125    /// One register's description. An index the target does not have gets a
1126    /// placeholder named `<invalid>`, in no class.
1127    ///
1128    /// # Examples
1129    ///
1130    /// ```
1131    /// use backend_lang::PReg;
1132    /// use backend_lang::x86_64::{self, RDI};
1133    ///
1134    /// assert_eq!(x86_64::TARGET.reg(RDI).name(), "rdi");
1135    /// assert_eq!(x86_64::TARGET.reg(PReg::new(100).unwrap()).name(), "<invalid>");
1136    /// ```
1137    #[inline]
1138    #[must_use]
1139    pub fn reg(&self, reg: PReg) -> &RegInfo {
1140        self.regs.get(reg.index()).unwrap_or(&INVALID_REG)
1141    }
1142
1143    /// Whether the target has a register with this index.
1144    ///
1145    /// # Examples
1146    ///
1147    /// ```
1148    /// use backend_lang::PReg;
1149    /// use backend_lang::x86_64::{self, RAX};
1150    ///
1151    /// assert!(x86_64::TARGET.has_reg(RAX));
1152    /// assert!(!x86_64::TARGET.has_reg(PReg::new(100).unwrap()));
1153    /// ```
1154    #[inline]
1155    #[must_use]
1156    pub fn has_reg(&self, reg: PReg) -> bool {
1157        reg.index() < self.regs.len()
1158    }
1159
1160    /// The class table, indexed by [`RegClass::index`].
1161    ///
1162    /// # Examples
1163    ///
1164    /// ```
1165    /// use backend_lang::x86_64;
1166    ///
1167    /// assert_eq!(x86_64::TARGET.classes().len(), 3);
1168    /// ```
1169    #[inline]
1170    #[must_use]
1171    pub const fn classes(&self) -> &'static [ClassInfo] {
1172        self.classes
1173    }
1174
1175    /// One class's description. A class the target does not have gets an
1176    /// empty placeholder named `<invalid>`.
1177    ///
1178    /// # Examples
1179    ///
1180    /// ```
1181    /// use backend_lang::RegClass;
1182    /// use backend_lang::x86_64::{self, GPR};
1183    ///
1184    /// assert_eq!(x86_64::TARGET.class(GPR).name(), "gpr");
1185    /// assert!(x86_64::TARGET.class(RegClass::new(9)).regs().is_empty());
1186    /// ```
1187    #[inline]
1188    #[must_use]
1189    pub fn class(&self, class: RegClass) -> &ClassInfo {
1190        self.classes.get(class.index()).unwrap_or(&INVALID_CLASS)
1191    }
1192
1193    /// Whether the target has this class.
1194    ///
1195    /// # Examples
1196    ///
1197    /// ```
1198    /// use backend_lang::RegClass;
1199    /// use backend_lang::x86_64::{self, VEC};
1200    ///
1201    /// assert!(x86_64::TARGET.has_class(VEC));
1202    /// assert!(!x86_64::TARGET.has_class(RegClass::new(9)));
1203    /// ```
1204    #[inline]
1205    #[must_use]
1206    pub fn has_class(&self, class: RegClass) -> bool {
1207        class.index() < self.classes.len()
1208    }
1209
1210    /// The instruction table, indexed by [`Opcode::index`].
1211    ///
1212    /// # Examples
1213    ///
1214    /// ```
1215    /// use backend_lang::x86_64;
1216    ///
1217    /// assert!(x86_64::TARGET.insts().len() > 80);
1218    /// ```
1219    #[inline]
1220    #[must_use]
1221    pub const fn insts(&self) -> &'static [InstDesc] {
1222        self.insts
1223    }
1224
1225    /// One instruction's description, or `None` for an opcode the target
1226    /// does not have.
1227    ///
1228    /// # Examples
1229    ///
1230    /// ```
1231    /// use backend_lang::target::Opcode;
1232    /// use backend_lang::x86_64::{self, op};
1233    ///
1234    /// assert!(x86_64::TARGET.inst(op::LEA64).is_some());
1235    /// assert!(x86_64::TARGET.inst(Opcode::new(60000)).is_none());
1236    /// ```
1237    #[inline]
1238    #[must_use]
1239    pub fn inst(&self, opcode: Opcode) -> Option<&'static InstDesc> {
1240        self.insts.get(opcode.index())
1241    }
1242
1243    /// The opcode whose MIR name is `name`, by a scan of the table.
1244    ///
1245    /// # Examples
1246    ///
1247    /// ```
1248    /// use backend_lang::x86_64::{self, op};
1249    ///
1250    /// assert_eq!(x86_64::TARGET.opcode("sub32"), Some(op::SUB32));
1251    /// assert_eq!(x86_64::TARGET.opcode("frobnicate"), None);
1252    /// ```
1253    #[must_use]
1254    pub fn opcode(&self, name: &str) -> Option<Opcode> {
1255        self.insts
1256            .iter()
1257            .position(|d| d.name == name)
1258            .and_then(|i| u16::try_from(i).ok())
1259            .map(Opcode)
1260    }
1261
1262    /// The stack pointer.
1263    ///
1264    /// # Examples
1265    ///
1266    /// ```
1267    /// use backend_lang::x86_64::{self, RSP};
1268    ///
1269    /// assert_eq!(x86_64::TARGET.stack_pointer(), RSP);
1270    /// ```
1271    #[inline]
1272    #[must_use]
1273    pub const fn stack_pointer(&self) -> PReg {
1274        self.stack_pointer
1275    }
1276
1277    /// The frame pointer.
1278    ///
1279    /// # Examples
1280    ///
1281    /// ```
1282    /// use backend_lang::x86_64::{self, RBP};
1283    ///
1284    /// assert_eq!(x86_64::TARGET.frame_pointer(), RBP);
1285    /// ```
1286    #[inline]
1287    #[must_use]
1288    pub const fn frame_pointer(&self) -> PReg {
1289        self.frame_pointer
1290    }
1291
1292    /// The condition-flags register, modelled as a physical register so that
1293    /// flag producers and consumers are ordinary implicit definitions and
1294    /// uses.
1295    ///
1296    /// # Examples
1297    ///
1298    /// ```
1299    /// use backend_lang::x86_64::{self, FLAGS};
1300    ///
1301    /// assert_eq!(x86_64::TARGET.flags(), Some(FLAGS));
1302    /// ```
1303    #[inline]
1304    #[must_use]
1305    pub const fn flags(&self) -> Option<PReg> {
1306        self.flags
1307    }
1308
1309    /// The class of memory operands' base and index registers.
1310    ///
1311    /// # Examples
1312    ///
1313    /// ```
1314    /// use backend_lang::x86_64::{self, GPR};
1315    ///
1316    /// assert_eq!(x86_64::TARGET.addr_class(), GPR);
1317    /// ```
1318    #[inline]
1319    #[must_use]
1320    pub const fn addr_class(&self) -> RegClass {
1321        self.addr_class
1322    }
1323
1324    /// How values move on this target.
1325    ///
1326    /// # Examples
1327    ///
1328    /// ```
1329    /// use backend_lang::x86_64;
1330    ///
1331    /// assert!(x86_64::TARGET.move_caps().swap());
1332    /// ```
1333    #[inline]
1334    #[must_use]
1335    pub const fn move_caps(&self) -> MoveCaps {
1336        self.move_caps
1337    }
1338
1339    /// The most memory operands one instruction may have (one on x86-64).
1340    ///
1341    /// # Examples
1342    ///
1343    /// ```
1344    /// use backend_lang::x86_64;
1345    ///
1346    /// assert_eq!(x86_64::TARGET.max_mem_operands(), 1);
1347    /// ```
1348    #[inline]
1349    #[must_use]
1350    pub const fn max_mem_operands(&self) -> u8 {
1351        self.max_mem_operands
1352    }
1353
1354    /// The number of condition codes; a `Cond` operand is below it.
1355    ///
1356    /// # Examples
1357    ///
1358    /// ```
1359    /// use backend_lang::x86_64;
1360    ///
1361    /// assert_eq!(x86_64::TARGET.conds(), 16);
1362    /// ```
1363    #[inline]
1364    #[must_use]
1365    pub const fn conds(&self) -> u8 {
1366        if self.conds.len() > u8::MAX as usize {
1367            u8::MAX
1368        } else {
1369            self.conds.len() as u8
1370        }
1371    }
1372
1373    /// A condition code's name (`<invalid>` for one the target does not
1374    /// have).
1375    ///
1376    /// # Examples
1377    ///
1378    /// ```
1379    /// use backend_lang::mir::CondCode;
1380    /// use backend_lang::x86_64;
1381    ///
1382    /// assert_eq!(x86_64::TARGET.cond_name(CondCode::new(4)), "e");
1383    /// assert_eq!(x86_64::TARGET.cond_name(CondCode::new(99)), "<invalid>");
1384    /// ```
1385    #[inline]
1386    #[must_use]
1387    pub fn cond_name(&self, cond: crate::mir::CondCode) -> &'static str {
1388        self.conds
1389            .get(usize::from(cond.code()))
1390            .copied()
1391            .unwrap_or("<invalid>")
1392    }
1393
1394    /// The class of a physical register, or `None` if the target does not
1395    /// have it.
1396    ///
1397    /// # Examples
1398    ///
1399    /// ```
1400    /// use backend_lang::x86_64::{self, GPR, R8};
1401    ///
1402    /// assert_eq!(x86_64::TARGET.class_of(R8), Some(GPR));
1403    /// ```
1404    #[inline]
1405    #[must_use]
1406    pub fn class_of(&self, reg: PReg) -> Option<RegClass> {
1407        self.regs.get(reg.index()).map(RegInfo::class)
1408    }
1409}