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