Skip to main content

rucc_target/
bits.rs

1//! How much of a register each instruction reads and writes.
2//!
3//! Design: `spec/optimizer/37-machine-level-optimization.md` section 37.4.
4//!
5//! A register is one register at every width, and what says how much of it an instruction is
6//! about is the instruction. `movzbl %sil, %esi` writes thirty two bits and reads eight of them,
7//! `movb %sil, %r12b` writes eight and reads eight, and put the two next to each other and the
8//! twenty four bits the first one worked out are bits nothing reads. Finding that out is the bit
9//! group liveness of `gcc/ext-dce.cc`, which tracks what is live per group of bits rather than
10//! per register, and what it needs from a target is this: for each operand of each instruction,
11//! how much of it the instruction names.
12//!
13//! It is here rather than in the pass for the reason [`crate::FrameInsts`] and
14//! [`crate::BranchInsts`] are here. The pass is in a pipeline crate and
15//! `spec/10-backend.md` section 10.8 says a pipeline crate holds no target-specific code, so what
16//! the pass knows about a machine arrives as a description rather than as a name it says out
17//! loud.
18//!
19//! # Why two questions rather than a table of instructions
20//!
21//! Neither question is about a particular instruction. The first is how wide an operand is, which
22//! every instruction of every target has an answer to, and the second is whether an instruction
23//! is one that copies the low bits of its source into its destination, which is the one family
24//! the transformation acts on. A target with no widening instructions answers `false` to the
25//! second everywhere and the pass finds nothing, which is the right answer rather than a special
26//! case.
27
28/// What a pass has to know about a machine to work out which bits of a register anything reads.
29///
30/// Both are functions of an opcode's name rather than tables, because a target already has the
31/// table both of them read: the assembly listing names each operand at the width the instruction
32/// uses it at, and the encoder is generated from the same description, so the widths here are the
33/// ones the machine really has rather than a second opinion about them.
34#[derive(Debug, Clone, Copy)]
35pub struct BitInsts {
36    /// What a rule file and the machine IR put in front of this target's opcodes, such as `x64.`.
37    pub prefix: &'static str,
38    /// How many bits of the operand at that index the instruction of that name uses.
39    ///
40    /// `None` means all of it, which is the answer for an operand the target's description does
41    /// not name: a register inside an addressing mode, an operand of an opcode that encodes to
42    /// nothing, and an opcode this target does not have. Answering "all of it" where nothing is
43    /// known is what keeps the analysis from believing bits are dead because a description was
44    /// silent about them.
45    pub width: fn(&str, u8) -> Option<u32>,
46    /// Whether the instruction of that name puts the low bits of its one source into its one
47    /// destination, and nothing else.
48    ///
49    /// The widenings and the narrowings, and nothing else. It is what makes the instruction one
50    /// the pass may take out when the bits above the source's width turn out to be read by
51    /// nobody, since what is left of it then is a copy.
52    pub copies_low: fn(&str) -> bool,
53}