Skip to main content

rucc_ir/
inst.rs

1//! What one instruction is, and what a value is.
2//!
3//! Design: `spec/08-ir.md` sections 8.1 and 8.3.
4//!
5//! An instruction is an [`Opcode`], a set of [`Flags`], a run of value operands, and whatever
6//! else that opcode needs, which is [`Extra`]. Everything that fits in eight bytes is in the
7//! [`Extra`] itself and everything larger is an index into a side table, so the instruction
8//! stays small enough that walking a function is walking one dense array.
9//!
10//! A value is the result of an instruction or a parameter of a block, and it is nothing else.
11//! There is no constant operand kind: a constant is an [`Opcode::IConst`] with a result like
12//! any other instruction. That is what makes the dominance rule in the verifier a single rule
13//! with no exceptions, and it costs nothing, because a constant with no uses is deleted by the
14//! same pass that deletes anything else with no uses.
15
16use rucc_base::{Idx, IdxRange, Symbol};
17
18use rucc_target::Slot;
19
20use crate::{
21    ExtraKind, Flags, FloatPred, IntPred, MemOrder, Opcode, Owner, PrefetchHint, RmwOp,
22    StorageClass, Type,
23};
24
25/// One value: the result of an instruction, or a parameter of a block.
26pub type Value = Idx<ValueData>;
27/// One instruction, in the function that owns it.
28pub type Inst = Idx<InstData>;
29/// One basic block, in the function that owns it.
30pub type Block = Idx<BlockData>;
31
32/// The table of references to values, which is what an operand list is a run of.
33#[derive(Debug)]
34pub struct ValueRef;
35/// A run of value operands.
36pub type ValueList = IdxRange<ValueRef>;
37/// A run of branch targets, which is what a terminator's successors are.
38pub type BlockCallList = IdxRange<BlockCall>;
39/// A run of immediates, which is what a `switch` holds its case values in.
40pub type ImmList = IdxRange<Imm>;
41/// A run of ABI attributes, which is what a call says about the arguments its signature does
42/// not name.
43pub type AbiList = IdxRange<Abi>;
44/// A run of eightbytes, which is how an object read off a variable argument list travelled.
45pub type SlotList = IdxRange<Slot>;
46
47/// A constant, in the immediate table.
48///
49/// The bits and nothing else. An integer is stored two's complement in as many of the low bits
50/// as its type is wide, and a floating point value is stored as its bit pattern, so the same
51/// table holds both and the type on the result says how to read it. That keeps a bit-preserving
52/// answer for a NaN payload, which a value of a Rust floating type would not.
53#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
54pub struct Imm(u128);
55
56impl Imm {
57    /// The bits, as they are stored.
58    #[must_use]
59    pub const fn bits(self) -> u128 {
60        self.0
61    }
62
63    /// An immediate holding these bits.
64    #[must_use]
65    pub const fn from_bits(bits: u128) -> Self {
66        Self(bits)
67    }
68
69    /// An integer, with the bits above `ty` cleared.
70    ///
71    /// A value is stored in exactly the width its type has, so two immediates are equal when
72    /// they are the same value, which is what lets an equality on the table stand in for an
73    /// equality on the numbers.
74    ///
75    /// # Panics
76    ///
77    /// Panics if `ty` is not an integer type.
78    #[must_use]
79    pub fn int(value: i128, ty: Type) -> Self {
80        assert!(ty.is_int(), "an integer immediate needs an integer type");
81        Self(value as u128 & mask(ty.bits()))
82    }
83
84    /// The value read as unsigned.
85    #[must_use]
86    pub const fn unsigned(self) -> u128 {
87        self.0
88    }
89
90    /// The value read as signed, with the sign bit of `ty` extended.
91    ///
92    /// # Panics
93    ///
94    /// Panics if `ty` is not an integer type.
95    #[must_use]
96    pub fn signed(self, ty: Type) -> i128 {
97        assert!(ty.is_int(), "an integer immediate needs an integer type");
98        let spare = 128 - ty.bits();
99        // Shifting left and then arithmetic right is the branch-free way to sign extend from
100        // an arbitrary width, and it is correct for a width of 128 because the shift is zero.
101        ((self.0 << spare) as i128) >> spare
102    }
103}
104
105/// The low `bits` bits set, and a width of 128 meaning all of them.
106fn mask(bits: u32) -> u128 {
107    if bits >= 128 { u128::MAX } else { (1u128 << bits) - 1 }
108}
109
110/// How often an arm of a branch is the one taken, where something knows.
111///
112/// Parts out of [`Hint::SCALE`], and nothing at all for an arm nobody has said anything about,
113/// which is almost every arm of almost every branch. A hint is what somebody claimed and not what
114/// a heuristic guessed: `__builtin_expect` writes one, a profile will write one, and the ten
115/// static predictors in `rucc_opt::predict` write none, because a guess that was written down
116/// would be indistinguishable afterwards from a fact.
117///
118/// The scale is ten thousandths because that is the scale `rucc_opt::Probability` and
119/// `rucc_mir::Weight` are in, and a number that changed scale on its way through the compiler is a
120/// number somebody will eventually divide twice.
121#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
122pub struct Hint(Option<u16>);
123
124impl Hint {
125    /// What a hint is out of.
126    pub const SCALE: u32 = 10_000;
127
128    /// Nothing said about this arm, which is what every arm starts as.
129    pub const NONE: Self = Self(None);
130
131    /// This arm is taken `parts` times in [`Hint::SCALE`].
132    ///
133    /// More than the scale is certainty rather than a mistake worth refusing, because the callers
134    /// that can produce one are doing arithmetic whose answer is certainty, so it is clamped.
135    #[must_use]
136    pub fn parts(parts: u32) -> Self {
137        Self(Some(u16::try_from(parts.min(Self::SCALE)).unwrap_or(u16::MAX)))
138    }
139
140    /// The number, or nothing where nothing was said.
141    #[must_use]
142    pub fn taken(self) -> Option<u32> {
143        self.0.map(u32::from)
144    }
145
146    /// The hint the other arm of a two armed branch carries, so that the two sum to certainty.
147    #[must_use]
148    pub fn complement(self) -> Self {
149        match self.0 {
150            Some(parts) => Self::parts(Self::SCALE - u32::from(parts)),
151            None => Self::NONE,
152        }
153    }
154}
155
156/// A branch target, and the values passed to it.
157///
158/// This is the whole reason there are no phi nodes. The arguments are here, in the branch,
159/// beside the block they go to, so removing a predecessor is one edit in one place and there
160/// is no second list anywhere that has to be kept in step with this one.
161///
162/// The hint is here for the same reason and not on the instruction: a branch has as many arms as
163/// it has block calls, and a weight held anywhere else would be a second list to keep in step with
164/// this one.
165#[derive(Clone, Copy, Debug, PartialEq, Eq)]
166pub struct BlockCall {
167    /// Where control goes.
168    pub block: Block,
169    /// What is passed, one for each of the block's parameters.
170    pub args: ValueList,
171    /// How often this arm is the one taken, where something said so.
172    pub hint: Hint,
173}
174
175impl BlockCall {
176    /// An arm going to a block with arguments and nothing said about how often it is taken.
177    #[must_use]
178    pub const fn new(block: Block, args: ValueList) -> Self {
179        Self { block, args, hint: Hint::NONE }
180    }
181
182    /// An arm going to a block that takes no arguments.
183    #[must_use]
184    pub const fn to(block: Block) -> Self {
185        Self::new(block, ValueList::EMPTY)
186    }
187}
188
189/// What defines a value.
190#[derive(Clone, Copy, Debug, PartialEq, Eq)]
191pub enum Def {
192    /// The result of an instruction, at this position among its results.
193    Result {
194        /// The instruction.
195        inst: Inst,
196        /// Which of its results this is.
197        index: u8,
198    },
199    /// A parameter of a block, at this position among its parameters.
200    Param {
201        /// The block.
202        block: Block,
203        /// Which of its parameters this is.
204        index: u32,
205    },
206}
207
208/// One value.
209#[derive(Clone, Copy, Debug, PartialEq, Eq)]
210pub struct ValueData {
211    /// Its type.
212    pub ty: Type,
213    /// Where it comes from.
214    pub def: Def,
215}
216
217/// The three parts of a bulk memory operation, taken apart so that nothing has to know the order.
218///
219/// It exists because the length is a number on almost every one of these and a value on a few, and
220/// a reader that takes the operands apart itself is a reader that can get the number from the
221/// payload without noticing that this one has an operand instead. Asking for this hands back the
222/// length either way and there is no shape of it that reads as a length when it is not one.
223#[derive(Clone, Copy, Debug, PartialEq, Eq)]
224pub struct Bulk {
225    /// Where it writes.
226    pub to: Value,
227    /// What it puts there: the address it reads for a copy, the byte for a fill.
228    pub with: Value,
229    /// How many bytes, where the program works the count out rather than the compiler.
230    ///
231    /// `None` is the ordinary one, where the count is [`MemInfo::size`].
232    pub length: Option<Value>,
233}
234
235/// What an access does beyond naming an address.
236#[derive(Clone, Copy, Debug, PartialEq, Eq)]
237pub struct MemInfo {
238    /// How many bytes the access covers, for the ones whose size is not their result type.
239    ///
240    /// A `load` takes its size from the type it produces. An `alloca` and a `memset` do not,
241    /// and this is where theirs is.
242    ///
243    /// Zero on a bulk operation that carries its length as an operand, which is the one shape
244    /// where this is not the count. [`Bulk`] is how those are read, and the verifier refuses a
245    /// zero here on one that has no operand, so a reader that goes through it cannot mistake the
246    /// one for the other.
247    pub size: u64,
248    /// The alignment the access is known to have, in bytes.
249    pub align: u32,
250    /// How strongly it is ordered, with [`MemOrder::NotAtomic`] for an ordinary access.
251    pub order: MemOrder,
252    /// The type-based aliasing node, if the front end knew one.
253    pub tbaa: Option<Meta>,
254    /// How many bytes of its record this access owns, counting the padding after it.
255    ///
256    /// Zero for an access that is not a member of a record, and zero when the front end was not
257    /// asked to work it out. What it is for is the init plane of
258    /// `spec/safe-memory/09-type-init-and-races.md` section 9.3: under `-fsafety-init=nopadding`
259    /// a store through a member records the padding after the member as written too, so that a
260    /// record filled a member at a time comes out whole and the ordinary reads of it, which are a
261    /// `memcmp` or a hash or a `write` of the record, are not refused.
262    ///
263    /// Only the init plane reads it. A bounds check over these bytes would be asking about bytes
264    /// the access does not touch, and a type plane write over them would be saying the padding
265    /// holds a value of the member's type, which it does not.
266    pub owns: u32,
267    /// Which `restrict` scope the access is in and which pointer it went through.
268    pub restrict: Restrict,
269}
270
271/// Which `restrict` scope an access is in, and which pointer inside that scope it went through.
272///
273/// Two small numbers, which is the whole of the mechanism. GCC spells them
274/// `MR_DEPENDENCE_CLIQUE` and `MR_DEPENDENCE_BASE` at `gcc/tree-ssa-alias.cc:2503` and the rule
275/// is one line: same clique and different base means the two accesses cannot touch the same
276/// byte, because that is exactly what `restrict` promises. A clique is one scope, numbered as
277/// lowering enters it, and a base is one `restrict` pointer declared inside it. Clique zero
278/// means nothing is known, which is what every access that is not under a `restrict` gets.
279///
280/// This is spec 9.4's scope tree rather than a blanket assumption, and it costs four bytes that
281/// were padding in [`MemInfo`] already.
282#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
283pub struct Restrict {
284    /// The scope, with zero meaning no information.
285    pub clique: u16,
286    /// The pointer within that scope, which only means anything when the clique is not zero.
287    pub base: u16,
288}
289
290impl Restrict {
291    /// No information, which is what an access outside any `restrict` scope carries.
292    pub const NONE: Self = Self { clique: 0, base: 0 };
293
294    /// Whether `restrict` says these two accesses cannot touch the same byte.
295    ///
296    /// Only accesses. GCC's PR71062 is what happens when this answer is used to fold a
297    /// comparison of the two pointers: `restrict` constrains what is read and written through a
298    /// pointer and says nothing about what the pointer's value is, so two pointers that may not
299    /// be used to reach the same object can still compare equal. A rule that folds `p == q` to
300    /// false on the strength of this is wrong.
301    #[must_use]
302    pub const fn disjoint(self, other: Self) -> bool {
303        self.clique != 0 && self.clique == other.clique && self.base != other.base
304    }
305}
306
307/// A metadata node, in the module's table.
308pub type Meta = Idx<MetaNode>;
309
310/// A node of the metadata graph.
311///
312/// Two kinds share the one table and the one numbering, because both of them are the compiler's
313/// interned type universe seen from a different side and a reader chasing a `!3` should not have
314/// to know which table it came out of.
315#[derive(Clone, Copy, Debug, PartialEq, Eq)]
316pub enum MetaNode {
317    /// What aliasing needs: a type, and where it sits in the tree of types.
318    Tbaa(TbaaNode),
319    /// What the type plane needs: one entry in the vocabulary its bytes are written in.
320    Plane(PlaneNode),
321}
322
323impl MetaNode {
324    /// The aliasing node this is, or `None` when it is a plane entry.
325    #[must_use]
326    pub const fn tbaa(self) -> Option<TbaaNode> {
327        match self {
328            Self::Tbaa(node) => Some(node),
329            Self::Plane(_) => None,
330        }
331    }
332
333    /// The plane entry this is, or `None` when it is an aliasing node.
334    #[must_use]
335    pub const fn plane(self) -> Option<PlaneNode> {
336        match self {
337            Self::Plane(node) => Some(node),
338            Self::Tbaa(_) => None,
339        }
340    }
341
342    /// The node one level up, which a plane entry never has.
343    ///
344    /// The tree is the aliasing tree and a plane entry is not in it. A plane entry that names a
345    /// type points at a node of that tree, and that is a reference and not a parent: the walk
346    /// that answers an aliasing query has no business leaving the tree it is walking.
347    #[must_use]
348    pub const fn parent(self) -> Option<Meta> {
349        match self {
350            Self::Tbaa(node) => node.parent,
351            Self::Plane(_) => None,
352        }
353    }
354
355    /// The node it points at, which is the parent of an aliasing node and the type of a plane
356    /// entry, and is what has to come earlier in the table than the node itself.
357    #[must_use]
358    pub const fn points_at(self) -> Option<Meta> {
359        match self {
360            Self::Tbaa(node) => node.parent,
361            Self::Plane(PlaneNode::Type(node)) => Some(node),
362            Self::Plane(_) => None,
363        }
364    }
365}
366
367/// A node of the type based aliasing tree.
368///
369/// The tree this forms is checked by the verifier, since a cycle in it would make the aliasing
370/// query that walks it not terminate, and the place to find that out is here and not there.
371#[derive(Clone, Copy, Debug, PartialEq, Eq)]
372pub struct TbaaNode {
373    /// What this node is called, which is what the printer writes and the parser reads.
374    pub name: Symbol,
375    /// The node one level up, with the root having none.
376    pub parent: Option<Meta>,
377    /// The offset within the parent, for a member of a struct type.
378    pub offset: u64,
379}
380
381/// One entry in the type plane's vocabulary, per `spec/safe-memory/09-type-init-and-races.md`
382/// section 9.1.
383///
384/// The plane maps every byte to one of these, so this is what a `meta_type` writes and what a
385/// `check_type` is asking about. Three of the four are the distinguished values that document
386/// says the plane has beyond the types themselves, and they are why the plane needs a node kind
387/// of its own rather than pointing straight at an aliasing node: there is no aliasing node for
388/// "nobody has stored here yet".
389#[derive(Clone, Copy, Debug, PartialEq, Eq)]
390pub enum PlaneNode {
391    /// A type, named by the aliasing node that is that type.
392    ///
393    /// The same node the front end already interned, so the plane's vocabulary is exactly the
394    /// compiler's and a report can name a type in the spelling the source used.
395    Type(Meta),
396    /// Bytes nothing has stored through, or stored from an untyped source.
397    ///
398    /// Compatible with every access, because storage with no declared type takes its effective
399    /// type from the store, which is C's rule and is also the only choice that does not fire at
400    /// every boundary with uninstrumented code.
401    NoType,
402    /// Bytes stored through a character type, which is compatible with every access.
403    ///
404    /// This is what makes the byte-wise copy idiom work. C 6.5 says a character access is
405    /// always permitted and that a store through a character lvalue does not set an effective
406    /// type, so the plane says `character` over those bytes and the later read of the field
407    /// still passes.
408    Character,
409    /// Byte `k` of a pointer shaped word.
410    ///
411    /// A pointer is not one type over its bytes, it is a word whose bytes are only meaningful
412    /// together, so reading four bytes out of the middle of one is a different thing from
413    /// reading four bytes of an `int` and the plane has to be able to say which byte it is.
414    PointerSlot(u8),
415}
416
417/// What a call needs beyond its arguments.
418#[derive(Clone, Copy, Debug, PartialEq, Eq)]
419pub struct CallInfo {
420    /// The name, for a direct call. `None` for a call through an address, where the address is
421    /// the first operand.
422    pub callee: Option<Symbol>,
423    /// The signature it is called with, which is where the ABI attributes are.
424    pub signature: Sig,
425    /// What the ABI asks of the arguments the signature does not name, one entry for each of
426    /// them.
427    ///
428    /// Only a variadic call has any, because only a variadic call passes an argument no
429    /// parameter stands for, and it is empty when every one of them travels as the value in
430    /// hand, which is nearly always. A structure the classification puts in the argument area
431    /// is the case it exists for: the bytes travel and there is no parameter to hang the
432    /// [`Abi::ByVal`] on, so it hangs here instead.
433    pub varargs: AbiList,
434}
435
436/// The argument registers an object in the argument area leaves behind it with nothing in them.
437///
438/// AAPCS64 is the ABI that asks for it. A homogeneous floating point aggregate that finds too few
439/// vector registers left goes in memory, and so does every floating point argument after it, even
440/// one that would fit in the register the aggregate did not take. A record of sixteen bytes or
441/// less that finds too few general purpose registers does the same to those. The classification
442/// knows which of the two happened and the backend placing the arguments does not, so the object
443/// carries it.
444#[derive(Clone, Copy, Debug, PartialEq, Eq, Default)]
445pub enum Drains {
446    /// Every register left is still there for the arguments after the object.
447    #[default]
448    Nothing,
449    /// No general purpose register is.
450    Integers,
451    /// No vector register is.
452    Floats,
453}
454
455/// A signature, in the function's table.
456pub type Sig = Idx<Signature>;
457
458/// What a `switch` needs beyond the value it switches on.
459#[derive(Clone, Copy, Debug, PartialEq, Eq)]
460pub struct SwitchInfo {
461    /// The targets, with the default first and one for each case after it.
462    pub targets: BlockCallList,
463    /// The case values, one for each target after the default.
464    pub cases: ImmList,
465}
466
467/// What an object read off a variable argument list is.
468///
469/// The access says how many bytes it is and what it is aligned to, which is the whole of what an
470/// object the convention put in the caller's argument area needs: it is there, and those two say
471/// where the argument behind it starts. An object that travelled in registers is not there at all.
472/// It is in the callee's own register save area, in as many places as it has eightbytes, and which
473/// register file each of those came from is not something the size and the alignment say. So the
474/// slots say it, and they are empty for the object that went in memory.
475///
476/// The classification is the front end's, because it is the one that still has the type. By the
477/// time an instruction reaches a backend the type is a size and an alignment, and the algorithm in
478/// section 3.5.7 of the psABI wants more than that.
479#[derive(Clone, Copy, Debug, PartialEq, Eq)]
480pub struct VaInfo {
481    /// The object, as any other access describes one.
482    pub mem: Idx<MemInfo>,
483    /// Where each of its eightbytes travelled, or nothing at all for one that travelled whole in
484    /// the caller's memory.
485    pub slots: SlotList,
486}
487
488/// What inline assembly needs.
489///
490/// The semantics belong to the inline assembly document. What is here is the shape: a
491/// template, the constraints, the clobbers, and the successors that make `asm goto` the one
492/// instruction whose being a terminator is a property of the instruction and not the opcode.
493#[derive(Clone, Copy, Debug, PartialEq, Eq)]
494pub struct AsmInfo {
495    /// The template string, as written.
496    pub template: Symbol,
497    /// The constraint list, as written.
498    pub constraints: Symbol,
499    /// The clobber list, as written.
500    pub clobbers: Symbol,
501    /// The labels, which are empty for everything except `asm goto`.
502    pub targets: BlockCallList,
503}
504
505/// Everything an instruction carries that is not a value operand.
506///
507/// Anything that fits in eight bytes is here and anything larger is an index into a side
508/// table, so that the common instructions, which are the arithmetic ones carrying nothing at
509/// all, do not pay for the rare ones.
510#[derive(Clone, Copy, Debug, PartialEq, Eq)]
511pub enum Extra {
512    /// Nothing, which is most instructions.
513    None,
514    /// A constant, for `iconst`, `fconst` and `splat`.
515    Imm(Idx<Imm>),
516    /// A name, for `global_addr` and for a target-specific intrinsic.
517    Symbol(Symbol),
518    /// Which comparison, for `icmp`.
519    IntPred(IntPred),
520    /// Which comparison, for `fcmp`.
521    FloatPred(FloatPred),
522    /// An access, for the loads, the stores, the copies and `alloca`.
523    Mem(Idx<MemInfo>),
524    /// An atomic read-modify-write, which is an access and which operation.
525    Rmw(RmwOp, Idx<MemInfo>),
526    /// A barrier's ordering, for `fence`.
527    Order(MemOrder),
528    /// What a `prefetch` is a hint about, which is a read or a write and how much locality.
529    Prefetch(PrefetchHint),
530    /// How many frames up to walk, for `frame_address` and `return_address`.
531    Depth(u32),
532    /// Which question an `object_size` asks, from zero to three.
533    Question(u8),
534    /// The targets of a branch, with the default first for a `switch`.
535    Targets(BlockCallList),
536    /// A call.
537    Call(Idx<CallInfo>),
538    /// A `switch`, which is targets and the values that select them.
539    Switch(Idx<SwitchInfo>),
540    /// Inline assembly.
541    Asm(Idx<AsmInfo>),
542    /// An object read off a variable argument list, which is an access and how it travelled.
543    VaObject(Idx<VaInfo>),
544    /// What kind of storage an instance is, for `meta_begin`.
545    Class(StorageClass),
546    /// Who a range went to, for `meta_transfer`.
547    Owner(Owner),
548    /// A metadata node, for `meta_type`, which is the one plane write that names a type.
549    Node(Meta),
550    /// Why an exemption was declared, for `safe_region_begin`.
551    Reason(Symbol),
552}
553
554impl Extra {
555    /// Which shape this is, without the payload.
556    ///
557    /// The verifier compares this with [`Opcode::extra_kind`], because an instruction carrying
558    /// the payload of some other opcode prints as text the parser cannot read back.
559    #[must_use]
560    pub const fn kind(self) -> ExtraKind {
561        match self {
562            Self::None => ExtraKind::None,
563            Self::Imm(_) => ExtraKind::Imm,
564            Self::Symbol(_) => ExtraKind::Symbol,
565            Self::IntPred(_) => ExtraKind::IntPred,
566            Self::FloatPred(_) => ExtraKind::FloatPred,
567            Self::Mem(_) => ExtraKind::Mem,
568            Self::Rmw(..) => ExtraKind::Rmw,
569            Self::Order(_) => ExtraKind::Order,
570            Self::Prefetch(_) => ExtraKind::Prefetch,
571            Self::Depth(_) => ExtraKind::Depth,
572            Self::Question(_) => ExtraKind::Question,
573            Self::Targets(_) => ExtraKind::Targets,
574            Self::Call(_) => ExtraKind::Call,
575            Self::Switch(_) => ExtraKind::Switch,
576            Self::Asm(_) => ExtraKind::Asm,
577            Self::VaObject(_) => ExtraKind::VaObject,
578            Self::Class(_) => ExtraKind::Class,
579            Self::Owner(_) => ExtraKind::Owner,
580            Self::Node(_) => ExtraKind::Node,
581            Self::Reason(_) => ExtraKind::Reason,
582        }
583    }
584}
585
586/// One instruction.
587///
588/// There is no result type here. Each result is a value in the function's value table and the
589/// type is on the value, which means a reader asking what an instruction produces asks the
590/// same question about `add` as about `call`, and there is no second copy of the type to
591/// disagree with the first.
592#[derive(Clone, Copy, Debug, PartialEq, Eq)]
593pub struct InstData {
594    /// Which instruction this is.
595    pub opcode: Opcode,
596    /// What the optimizer is licensed to assume about it.
597    pub flags: Flags,
598    /// How many values it produces.
599    pub results: u8,
600    /// The first of them, with the rest following it in the value table.
601    pub first_result: Option<Value>,
602    /// Its value operands.
603    pub args: ValueList,
604    /// Everything else it carries.
605    pub extra: Extra,
606}
607
608impl InstData {
609    /// An instruction with no operands, no flags, no results and nothing extra.
610    #[must_use]
611    pub const fn new(opcode: Opcode) -> Self {
612        Self {
613            opcode,
614            flags: Flags::NONE,
615            results: 0,
616            first_result: None,
617            args: ValueList::EMPTY,
618            extra: Extra::None,
619        }
620    }
621
622    /// The values it produces, in order.
623    pub fn results(&self) -> impl Iterator<Item = Value> + use<> {
624        let first = self.first_result.map_or(0, Idx::raw);
625        (0..u32::from(self.results)).map(move |offset| Value::new(first + offset))
626    }
627
628    /// The run of targets it branches to, which is empty when it does not branch.
629    ///
630    /// A `switch` keeps its targets in a side table, so this reads `Extra::Targets` only and
631    /// the function is what answers for the rest.
632    #[must_use]
633    pub fn targets(&self) -> BlockCallList {
634        match self.extra {
635            Extra::Targets(targets) => targets,
636            _ => BlockCallList::EMPTY,
637        }
638    }
639}
640
641/// How one parameter or one return value travels, beyond what its type says.
642///
643/// The IR's types are the machine's and not C's, so a `ptr` parameter says nothing about
644/// whether the pointer is the argument or whether the object it points at is, and an `i8` says
645/// nothing about which half of the register above it the callee may read. Both are the ABI's
646/// answer rather than the type's, which is why they are here and not on [`Type`].
647///
648/// A signature carrying one of these has already had the ABI applied to it. What the walk to
649/// the IR builds first is the C-level form, where every parameter is [`Abi::Plain`], and the
650/// classification in `rucc-target` is what turns one into the other.
651#[derive(Clone, Copy, Debug, PartialEq, Eq, Default)]
652pub enum Abi {
653    /// The value itself, in the type it is written as.
654    #[default]
655    Plain,
656    /// An integer narrower than a register, with the bits above it its own sign.
657    ///
658    /// Which of these an ABI asks for is not a property of the value: `unsigned char` is
659    /// [`Abi::Sext`] on the Darwin ABIs and [`Abi::Zext`] elsewhere, and on SysV neither the
660    /// caller nor the callee may assume anything about those bits at all.
661    Sext,
662    /// An integer narrower than a register, with zeroes above it.
663    Zext,
664    /// The bytes of the object the pointer points at, in the argument area, with no address
665    /// travelling anywhere.
666    ///
667    /// The caller makes the copy the callee is free to write to, which is what makes this a C
668    /// call by value rather than a pointer the callee must not keep.
669    ByVal {
670        /// How many bytes travel.
671        size: u64,
672        /// What the copy is aligned to, which is the C alignment of the type and not the
673        /// pointer's.
674        align: u32,
675        /// The argument registers of one kind that nothing after this object may have.
676        drains: Drains,
677    },
678    /// Somewhere for the return value to go, whose address the caller passes as the first
679    /// argument because the value does not fit in the registers a return comes back in.
680    Sret {
681        /// How many bytes the callee writes.
682        size: u64,
683        /// What the space is aligned to.
684        align: u32,
685    },
686}
687
688impl Abi {
689    /// Whether this describes an object behind a pointer rather than the value in hand.
690    #[must_use]
691    pub const fn indirect(self) -> bool {
692        matches!(self, Self::ByVal { .. } | Self::Sret { .. })
693    }
694
695    /// The size and alignment of that object, for the two that have one.
696    #[must_use]
697    pub const fn object(self) -> Option<(u64, u32)> {
698        match self {
699            Self::ByVal { size, align, .. } | Self::Sret { size, align } => Some((size, align)),
700            _ => None,
701        }
702    }
703}
704
705/// One parameter, or one return value: a type and how it travels.
706#[derive(Clone, Copy, Debug, PartialEq, Eq)]
707pub struct Param {
708    /// The type the IR sees, which for the indirect forms is `ptr`.
709    pub ty: Type,
710    /// What the ABI asks of it.
711    pub abi: Abi,
712}
713
714impl Param {
715    /// A parameter of this type, in its C-level form.
716    #[must_use]
717    pub const fn new(ty: Type) -> Self {
718        Self { ty, abi: Abi::Plain }
719    }
720
721    /// A parameter of this type travelling this way.
722    #[must_use]
723    pub const fn with_abi(ty: Type, abi: Abi) -> Self {
724        Self { ty, abi }
725    }
726}
727
728/// What a function takes and returns.
729///
730/// A signature is not a type. Nothing in the IR has a function type, because a `ptr` has no
731/// pointee and there is nothing else a function type could sit on. A `call_indirect` names the
732/// signature it is called with, and that is where the ABI attributes are read from.
733#[derive(Clone, Debug, PartialEq, Eq, Default)]
734pub struct Signature {
735    /// What it takes, in their C-level form until the ABI has been applied.
736    pub params: Vec<Param>,
737    /// What it returns, which is empty for a `void` function and for one whose return value
738    /// comes back through an [`Abi::Sret`] parameter.
739    pub returns: Vec<Param>,
740    /// Whether it takes arguments beyond the ones named.
741    pub variadic: bool,
742}
743
744impl Signature {
745    /// A signature taking and returning nothing.
746    #[must_use]
747    pub fn new() -> Self {
748        Self::default()
749    }
750
751    /// The same signature with these parameters, each in its C-level form.
752    #[must_use]
753    pub fn with_params(mut self, params: &[Type]) -> Self {
754        self.params = params.iter().copied().map(Param::new).collect();
755        self
756    }
757
758    /// The same signature returning these, each in its C-level form.
759    #[must_use]
760    pub fn with_returns(mut self, returns: &[Type]) -> Self {
761        self.returns = returns.iter().copied().map(Param::new).collect();
762        self
763    }
764
765    /// The same signature with one more parameter, travelling the way the ABI said.
766    #[must_use]
767    pub fn and_param(mut self, param: Param) -> Self {
768        self.params.push(param);
769        self
770    }
771
772    /// The same signature with one more return value, travelling the way the ABI said.
773    #[must_use]
774    pub fn and_return(mut self, param: Param) -> Self {
775        self.returns.push(param);
776        self
777    }
778
779    /// The types it takes, without what the ABI asks of them.
780    pub fn param_types(&self) -> impl Iterator<Item = Type> + use<'_> {
781        self.params.iter().map(|param| param.ty)
782    }
783
784    /// The types it returns.
785    pub fn return_types(&self) -> impl Iterator<Item = Type> + use<'_> {
786        self.returns.iter().map(|param| param.ty)
787    }
788
789    /// The same signature, variadic.
790    #[must_use]
791    pub fn variadic(mut self) -> Self {
792        self.variadic = true;
793        self
794    }
795}
796
797/// One basic block: parameters, then instructions, then exactly one terminator.
798///
799/// The instructions are a doubly linked list rather than a vector, so that inserting one in
800/// the middle of a block does not move the ones after it. An optimizer does that constantly,
801/// and a move would invalidate every [`Inst`] anybody was holding.
802#[derive(Clone, Debug, Default, PartialEq, Eq)]
803pub struct BlockData {
804    /// The values arriving here, which is what other IRs spell as phi nodes.
805    ///
806    /// A `Vec` and not a run in a pool, because SSA construction adds a parameter to a loop
807    /// header long after the blocks that come after it have been built, and a run in a pool
808    /// cannot grow in the middle.
809    pub params: Vec<Value>,
810    /// The first instruction, or `None` for a block nothing has been put in yet.
811    pub first: Option<Inst>,
812    /// The last instruction, which is the terminator once the block is finished.
813    pub last: Option<Inst>,
814    /// The block before this one in layout order.
815    pub prev: Option<Block>,
816    /// The block after it.
817    pub next: Option<Block>,
818}
819
820/// Where one instruction sits.
821#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
822pub struct InstLayout {
823    /// The block it is in, or `None` if it has been made and not yet inserted.
824    pub block: Option<Block>,
825    /// The instruction before it in that block.
826    pub prev: Option<Inst>,
827    /// The instruction after it.
828    pub next: Option<Inst>,
829}
830
831#[cfg(test)]
832mod tests {
833    use super::*;
834
835    #[test]
836    fn an_immediate_keeps_only_the_bits_its_type_has() {
837        let byte = Type::int(8);
838        assert_eq!(Imm::int(-1, byte).unsigned(), 0xff);
839        assert_eq!(Imm::int(-1, byte).signed(byte), -1);
840        assert_eq!(Imm::int(255, byte), Imm::int(-1, byte));
841        assert_eq!(Imm::int(127, byte).signed(byte), 127);
842        assert_eq!(Imm::int(128, byte).signed(byte), -128);
843    }
844
845    #[test]
846    fn a_widest_immediate_is_not_truncated() {
847        let word = Type::int(128);
848        assert_eq!(Imm::int(i128::MIN, word).signed(word), i128::MIN);
849        assert_eq!(Imm::int(i128::MAX, word).signed(word), i128::MAX);
850        assert_eq!(Imm::int(-1, word).unsigned(), u128::MAX);
851    }
852
853    #[test]
854    fn a_one_bit_immediate_is_a_bit() {
855        let bit = Type::I1;
856        assert_eq!(Imm::int(1, bit).unsigned(), 1);
857        assert_eq!(Imm::int(3, bit).unsigned(), 1);
858        assert_eq!(Imm::int(2, bit).unsigned(), 0);
859        // The one bit is the sign bit, so the only two values are zero and minus one.
860        assert_eq!(Imm::int(1, bit).signed(bit), -1);
861    }
862
863    #[test]
864    fn a_floating_immediate_keeps_its_bits() {
865        let bits = f64::NAN.to_bits() | 0x7;
866        assert_eq!(Imm::from_bits(u128::from(bits)).bits(), u128::from(bits));
867    }
868
869    #[test]
870    fn an_instruction_with_no_results_yields_none() {
871        let inst = InstData::new(Opcode::Store);
872        assert_eq!(inst.results().count(), 0);
873    }
874
875    #[test]
876    fn results_follow_the_first_one() {
877        let mut inst = InstData::new(Opcode::SAddOverflow);
878        inst.first_result = Some(Value::new(4));
879        inst.results = 2;
880        let got: Vec<u32> = inst.results().map(Idx::raw).collect();
881        assert_eq!(got, [4, 5]);
882    }
883
884    #[test]
885    fn a_jump_says_where_it_goes() {
886        let mut inst = InstData::new(Opcode::Jump);
887        inst.extra = Extra::Targets(BlockCallList::new(Idx::new(0), Idx::new(1)));
888        assert_eq!(inst.targets().len(), 1);
889    }
890
891    #[test]
892    fn a_signature_is_built_by_saying_what_it_takes_and_returns() {
893        let sig = Signature::new()
894            .with_params(&[Type::int(32), Type::PTR])
895            .with_returns(&[Type::int(32)])
896            .variadic();
897        assert_eq!(sig.param_types().collect::<Vec<_>>(), [Type::int(32), Type::PTR]);
898        assert_eq!(sig.return_types().collect::<Vec<_>>(), [Type::int(32)]);
899        assert!(sig.variadic);
900        assert_eq!(Signature::new(), Signature::default());
901    }
902
903    #[test]
904    fn a_parameter_says_how_it_travels_and_not_only_what_it_is() {
905        let object = Abi::ByVal { size: 24, align: 8, drains: Drains::Nothing };
906        let sig = Signature::new()
907            .and_param(Param::with_abi(Type::PTR, Abi::Sret { size: 32, align: 16 }))
908            .and_param(Param::with_abi(Type::PTR, object))
909            .and_param(Param::with_abi(Type::int(8), Abi::Zext));
910        // The types alone say `ptr, ptr, i8`, which is three of the calls in any C program and
911        // none of them the same call.
912        assert_eq!(sig.param_types().collect::<Vec<_>>(), [Type::PTR, Type::PTR, Type::int(8)]);
913        assert_eq!(sig.params[1].abi.object(), Some((24, 8)));
914        assert!(sig.params[0].abi.indirect() && !sig.params[2].abi.indirect());
915        assert_eq!(Param::new(Type::PTR).abi, Abi::Plain);
916        assert_eq!(Abi::Plain.object(), None);
917    }
918
919    #[test]
920    fn an_instruction_stays_small() {
921        // Not a promise, a tripwire. Every function in the program is a run of these, and a
922        // change that doubles this should be a change somebody decided to make.
923        assert!(size_of::<InstData>() <= 32, "{}", size_of::<InstData>());
924        assert_eq!(size_of::<ValueData>(), 16);
925        assert_eq!(size_of::<Extra>(), 12);
926    }
927}