Skip to main content

rucc_ir/
opcode.rs

1//! The instruction set.
2//!
3//! Design: `spec/08-ir.md` section 8.3.
4//!
5//! The set is small enough to enumerate and it is closed. Adding an opcode is a spec change,
6//! because the verifier, the printer, the parser, the rewrite rules and the lowering all have
7//! to learn it, and an opcode that only half of them know about is a silent miscompilation
8//! waiting for the right input.
9//!
10//! Two things are deliberately absent. There is no `getelementptr`: pointer arithmetic is
11//! [`Opcode::PtrAdd`] over a byte offset the frontend computed, because C never needs the
12//! multi-index form and its absence removes a well known source of complexity. And there is no
13//! `phi`: values arriving at a block are the block's parameters, passed by the branch, so
14//! there is no operand list positionally tied to a predecessor list kept somewhere else.
15
16use std::fmt;
17
18/// One instruction of the IR.
19///
20/// The names are the textual form exactly, so [`Opcode::name`] and [`Opcode::from_name`] are
21/// what the printer and the parser use, and neither carries a table of its own that could
22/// drift from this one.
23///
24/// The enum is not `non_exhaustive`, deliberately. The set is closed, so a pass that matches
25/// on every opcode should stop compiling when one is added rather than fall into a wildcard
26/// arm that quietly does the wrong thing.
27#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
28pub enum Opcode {
29    // Constants. A constant is an instruction rather than an operand kind, so that every
30    // operand is a value and every value has one definition, which is what makes the
31    // dominance check in the verifier a single rule rather than a rule with exceptions.
32    /// An integer constant, `iconst.i32 7`.
33    IConst,
34    /// A floating point constant, `fconst.f64 0x1.8p+1`.
35    FConst,
36    /// A vector constant with every lane the same, `splat.i8x16 0`.
37    Splat,
38    /// The address of a global or a function, `global_addr @counter`.
39    GlobalAddr,
40    /// The address of a block in this function, `block_addr block3`.
41    ///
42    /// The one instruction that names a block without being a branch, which is what GNU's
43    /// `&&label` is. Where it goes is [`Opcode::IndirectBr`], and the two are only useful
44    /// together: an address on its own is a number that nothing can do anything with.
45    BlockAddr,
46
47    // Arithmetic.
48    /// Integer addition.
49    Add,
50    /// Integer subtraction.
51    Sub,
52    /// Integer multiplication.
53    Mul,
54    /// Signed division.
55    SDiv,
56    /// Unsigned division.
57    UDiv,
58    /// Signed remainder, with the sign of the dividend.
59    SRem,
60    /// Unsigned remainder.
61    URem,
62    /// The high half of the product of two unsigned integers, which is the half an ordinary
63    /// multiply throws away. Only the back end writes one, for a division by a constant.
64    UMulHigh,
65    /// The high half of the product of two signed integers.
66    SMulHigh,
67    /// Bitwise and.
68    And,
69    /// Bitwise or.
70    Or,
71    /// Bitwise exclusive or.
72    Xor,
73    /// Shift left.
74    Shl,
75    /// Logical shift right, shifting in zeroes.
76    LShr,
77    /// Arithmetic shift right, shifting in the sign bit.
78    AShr,
79    /// Floating point addition.
80    FAdd,
81    /// Floating point subtraction.
82    FSub,
83    /// Floating point multiplication.
84    FMul,
85    /// Floating point division.
86    FDiv,
87    /// Floating point remainder.
88    FRem,
89    /// Floating point negation, which flips the sign bit and is not `0 - x`.
90    FNeg,
91    /// Fused multiply-add, rounded once.
92    Fma,
93
94    // Comparison.
95    /// Integer comparison, producing `i1` or a vector of `i1`.
96    ICmp,
97    /// Floating point comparison, producing `i1` or a vector of `i1`.
98    FCmp,
99
100    // Selection.
101    /// One of two values, chosen by a bit. `select c, a, b` is `a` when `c` is one.
102    ///
103    /// This is what control flow becomes when it stops being control flow.
104    /// `spec/optimizer/22-phiopt-and-if-conversion.md` section 22.2 makes it the lowering target
105    /// for a diamond whose two arms compute a value, and the reason it is an opcode rather than a
106    /// pattern is that it is the form the rule set is written against: `select(c, a, a) -> a` and
107    /// `select(c, 1, 0) -> zext(c)` are ordinary rules once the shape has a name.
108    ///
109    /// Both arms are evaluated, which is the whole point and also the whole danger. Whatever
110    /// produces one of these owes the argument that evaluating the arm that is not chosen is
111    /// harmless, and section 22.6 is the list of ways that argument goes wrong.
112    Select,
113
114    // Conversion.
115    /// Narrows an integer, discarding the high bits.
116    Trunc,
117    /// Widens an integer, copying the sign bit.
118    SExt,
119    /// Widens an integer, filling with zeroes.
120    ZExt,
121    /// Narrows a floating point value.
122    FPTrunc,
123    /// Widens a floating point value.
124    FPExt,
125    /// Floating point to signed integer.
126    FPToSI,
127    /// Floating point to unsigned integer.
128    FPToUI,
129    /// Signed integer to floating point.
130    SIToFP,
131    /// Unsigned integer to floating point.
132    UIToFP,
133    /// An address to an integer of the same width.
134    PtrToInt,
135    /// An integer to an address.
136    IntToPtr,
137    /// A reinterpretation of the same bits at the same width.
138    Bitcast,
139
140    // Memory.
141    /// Memory as the function found it, which is where a memory SSA chain starts.
142    ///
143    /// It produces one `mem` and takes nothing, and it belongs at the top of the entry block.
144    /// GCC calls the same thing the default definition of `.MEM` and LLVM calls it
145    /// `liveOnEntry`. It exists as an instruction rather than as a parameter of the entry block
146    /// because the entry block's parameters are the function's parameters and the verifier
147    /// checks them against the signature, and memory is not an argument anybody passed.
148    MemEntry,
149    /// A stack slot. In the entry block, or marked dynamic for a variable length array.
150    Alloca,
151    /// A read.
152    Load,
153    /// A write, producing no value.
154    Store,
155    /// Address arithmetic: an address and a byte offset.
156    PtrAdd,
157    /// A copy between addresses that do not overlap, of the payload's size or of a third operand.
158    Memcpy,
159    /// A copy between addresses that may overlap, of the payload's size or of a third operand.
160    Memmove,
161    /// A fill with one byte, of the payload's size or of a third operand.
162    Memset,
163    /// An atomic read.
164    AtomicLoad,
165    /// An atomic write.
166    AtomicStore,
167    /// An atomic read-modify-write, carrying which operation in [`RmwOp`](crate::RmwOp).
168    AtomicRmw,
169    /// An atomic compare and exchange, producing the old value and whether it succeeded.
170    Cmpxchg,
171    /// A memory barrier.
172    Fence,
173
174    // Memory safety. Design: `spec/safe-memory/06-instrumentation.md` section 6.2.2. None of
175    // these is emitted unless `-fsafety` asked for it, and a function compiled without it
176    // contains not one of them.
177    /// The capability of a pointer value, taken from the pointer's provenance.
178    ///
179    /// One operand, the pointer, and one capability out. This is the general question and the other
180    /// producers are all the special cases of it that have a cheap answer, which is why it is the
181    /// one that always works and the one to reach for last. A pointer whose provenance the compiler
182    /// still holds should have got its capability from wherever that provenance came from: from the
183    /// allocation site, from the aux slot beside it in memory, from the frame its caller wrote, or
184    /// from the derivation that narrowed it. One of these is what is left when none of those did.
185    ///
186    /// So it has two lowerings and which one it gets is not a property of the instruction. A pointer
187    /// the lowering can trace back to an allocation site gets the cheap answer, which is a subtract
188    /// and a load off the header the allocator wrote. Anything else gets the plane walk, which is
189    /// the expensive answer and the only one that is always available, and comes back marked as
190    /// recovered so the summary counts it as the weakening it is.
191    ///
192    /// An interior pointer is always the second of those, and that is the answer to the question
193    /// document 05 section 5.2.3 leaves open rather than a gap in it. The header is behind the
194    /// payload so that finding it is a subtract by a constant, which is true of a pointer to the
195    /// base of an object and false of a pointer to the middle of one, and the lowering asks for the
196    /// base by construction rather than by checking.
197    CapOf,
198    /// The capability in the auxiliary slot beside a stored pointer, read back.
199    ///
200    /// A pointer written to memory and read again has to bring its capability with it, and where
201    /// the capability lives is document 05's question rather than this one's. What this says is
202    /// that a capability comes back from an address.
203    ///
204    /// Three operands: the capability of the object the word is in, the address of the word, and
205    /// the pointer that was loaded from it. The first is what says where the slot is, since the
206    /// aux is in front of the object and the arithmetic is over the object's own base and extent,
207    /// and the third is what the slot's two numbers are relative to. Both of those are facts about
208    /// the representation document 05 section 5.2.2 chose, and an instrumented load has both
209    /// values in hand already, since the capability is the one its bounds check used and the
210    /// pointer is what the load produced.
211    CapLoad,
212    /// The other half of [`Opcode::CapLoad`], writing one into the slot beside a pointer.
213    ///
214    /// Four operands: the capability of the object the word is in, the address of the word, the
215    /// pointer being stored there, and that pointer's capability. The first three are the same
216    /// three [`Opcode::CapLoad`] takes and for the same reasons, and the fourth is what is being
217    /// written down.
218    CapStore,
219    /// The slots beside a run of copied words, carried over from the run they were copied from.
220    ///
221    /// Three operands, for the reason [`Opcode::MetaTypeCopy`] has three: the destination, the
222    /// source, and how many bytes moved. A copy of a structure moves whatever pointers are in it
223    /// and the capability of each of those lives in the slot beside it, so a copy that moved the
224    /// bytes and left the slots alone would leave every pointer in the destination described by
225    /// whatever was there before, which is nothing at best and another instance's answer at worst.
226    ///
227    /// No capability operand, for the reason the other two copies name no node. What each
228    /// destination slot ends up saying is whatever the slot beside the word it came from said, and
229    /// the only place that is written down is the aux over the source.
230    CapCopy,
231    /// The capability that permits nothing, which is what a null pointer has.
232    CapNull,
233    /// A capability narrowed to a sub-object of what it covered.
234    ///
235    /// Only under `-fsafety-subobject`. Narrowing is what catches an overflow from one member of
236    /// a struct into the next, and it is separate because C code that walks off the end of a
237    /// member on purpose exists and a project has to be able to say so.
238    CapNarrow,
239    /// The capability for an address that arrived from outside, recovered from the planes.
240    CapRecover,
241    /// How many bytes from an address on the capability covers, asking for no more than a limit.
242    ///
243    /// Three operands, the capability, the address and how many bytes the asker wants, and one
244    /// integer result that is never more than that limit. It is what
245    /// `spec/safe-memory/07-check-elimination.md` section 7.4 needs to split a loop: the checked
246    /// part and the unchecked part are divided at `min(n, extent / sizeof(T))`, and the extent is
247    /// the half of that a compiler cannot work out on its own.
248    ///
249    /// The limit is an operand because under milestone S1 answering means walking the lifetime
250    /// plane, and a walk that stops at the number of bytes the loop was going to read anyway is
251    /// bounded by the work the loop is already doing. An answer smaller than the truth costs
252    /// iterations in the checked half and is never wrong, which is what makes stopping early
253    /// allowed. Once a capability carries its own bounds, which is milestone S2, this is a
254    /// subtraction on the capability and the limit is one `min`.
255    CapExtent,
256    /// How many bytes below an address on the capability covers, asking for no more than a limit.
257    ///
258    /// The mirror of [`Opcode::CapExtent`], with the same three operands and the same kind of
259    /// answer. What it counts is the bytes ending at the address rather than the bytes starting
260    /// there, so an answer of `n` says that `[addr - n, addr)` belongs to one thing. The address
261    /// itself is one past what is asked about, which is what a walk from high to low needs: the
262    /// question is about where the walk ends up, and where it ends up is below where it began.
263    ///
264    /// The ownership asked about is the byte below the address rather than the byte at it, since
265    /// the address may be one past the end of the object and the object is what the question is
266    /// about. Everything else, the limit operand and why an answer short of the truth is allowed,
267    /// is [`Opcode::CapExtent`]'s.
268    CapExtentBack,
269    /// The capabilities of a call's pointer arguments, handed over beside the arguments.
270    ///
271    /// Document 05 section 5.3 is the whole of why this is an instruction of its own rather than
272    /// more operands on the call. An instrumented function's calling convention is unchanged, so a
273    /// pointer argument goes in the register it always went in and `sizeof(void *)` is still eight,
274    /// which is what lets an object this compiler built link against one nobody instrumented. The
275    /// capability therefore travels out of band, in a small per thread frame the caller writes and
276    /// the callee reads, indexed by argument position.
277    ///
278    /// One operand per pointer argument, in the order the call passes them, and no operand for the
279    /// arguments that are not pointers. A call handing over more pointers than the frame has room
280    /// for describes the ones that fit and the callee recovers the rest, which is a weakening the
281    /// summary counts rather than a refusal. How many fit is the runtime's number and
282    /// `rucc_safety::frame` is where the compiler keeps it, so nothing here is a bound on the
283    /// operand count.
284    ///
285    /// It goes immediately in front of the call it is about, which is how the two are tied
286    /// together, the same way [`Opcode::MetaRelease`] is tied to the atomic it goes in front of.
287    CapPublish,
288    /// There is no frame for this call, which is what a callee that might not be instrumented gets.
289    ///
290    /// The other half of [`Opcode::CapPublish`] and not the absence of one. Publishing to a callee
291    /// that never reads the frame leaves it in place for whatever that callee calls back into, and
292    /// a callback entered from uninstrumented code holding somebody else's capabilities is worse
293    /// than one entered holding none. So a call the compiler cannot say reads frames says there is
294    /// nothing rather than saying nothing at all, and document 10 section 10.8's callback recovers
295    /// its arguments the way an entry from outside always does.
296    CapClear,
297    /// The capability of a pointer parameter, out of the frame the caller published.
298    ///
299    /// The reading end of [`Opcode::CapPublish`], in the callee rather than in the caller. Two
300    /// operands, the parameter itself and which position it is in the call, and one capability out.
301    ///
302    /// The parameter is an operand because it is the answer when there is no frame. A function
303    /// entered from code this build never compiled finds nothing published, and so does one whose
304    /// caller could not vouch for it and said `cap_clear`, and in both cases the capability has to be
305    /// worked out from the pointer the way [`Opcode::CapRecover`] does. That is the expensive answer
306    /// the frame exists to avoid, it is available whatever the caller did, and it is counted as the
307    /// weakening it is.
308    ///
309    /// The position is an operand rather than a payload for the same reason [`Opcode::CapNarrow`]'s
310    /// offset and length are: it is a number the runtime is handed. A position the frame does not
311    /// reach is not an error either, since it is the recovery again, so nothing here has to know how
312    /// many capabilities a frame holds.
313    CapArg,
314    /// The capability of the pointer this function is returning, left where its caller reads.
315    ///
316    /// One operand, the capability, and it goes immediately in front of the `ret` it is about, which
317    /// is the tie [`Opcode::CapPublish`] has with its call. A function that returns from several
318    /// places has one of these in front of each of them, because what is being said is about the
319    /// value leaving by that particular one.
320    ///
321    /// This is the only thing in the design that writes into a frame somebody else made. It is
322    /// allowed to because the frame is the caller's stack and the caller is waiting for this
323    /// function to return, and it is needed because a returned pointer is the one value that crosses
324    /// a call in the other direction.
325    CapYield,
326    /// The capability of the pointer a call gave back, out of the frame the call was published with.
327    ///
328    /// The reading end of [`Opcode::CapYield`], in the caller. One operand, the pointer that came
329    /// back, and one capability out. The operand is there for the reason [`Opcode::CapArg`]'s is: a
330    /// callee that wrote nothing leaves the bottom capability where the caller put it, and the
331    /// bottom one is the signal to work the answer out from the pointer instead.
332    ///
333    /// It goes immediately after the call it is about, and that call has to be one a `cap_publish`
334    /// goes in front of. A call that says there is no frame has no frame for a callee to have
335    /// written into, so there would be nothing for this to read.
336    CapResult,
337    /// An access is within its capability's bounds, aligned, and permitted.
338    ///
339    /// The size and the alignment are the access's, and they are in the memory payload rather
340    /// than in operands because they are what the front end knew and not what the program
341    /// computed.
342    ///
343    /// A third operand overrides how many bytes are asked about, and it exists for the one check
344    /// the front end did not write. `spec/safe-memory/07-check-elimination.md` section 7.4 replaces
345    /// the checks in a loop that runs `n` times with one check over `n * sizeof(T)` bytes, and that
346    /// is a length the program computes rather than one anybody knew when the access was parsed. The
347    /// payload still holds the alignment and the type information of the access the check came from,
348    /// and its size becomes the size of one of them rather than the size of the question.
349    CheckBounds,
350    /// The capability's provenance is still live.
351    CheckLive,
352    /// The access agrees with the type plane, which is the effective type rule of C 6.5.
353    ///
354    /// A third operand overrides how many bytes are asked about, as on [`Opcode::CheckBounds`] and
355    /// for the same reason. Agreeing with a type is a property of a range that holds of every
356    /// subrange of it, so one check over a loop's whole walk says what the loop's checks were going
357    /// to say, which is `spec/safe-memory/07-check-elimination.md` section 7.4's transformation
358    /// applied to this plane rather than to the bounds. The plane entry stays in the payload, since
359    /// the checks a hoisted one stands for all asked at the same type or it would not have been
360    /// written.
361    ///
362    /// A fourth operand is a step, and then the check is not about a range. It asks about one
363    /// access of the payload's width at the pointer and at every step along from it that still
364    /// fits in the third operand's span, which is a loop's checks over a walk that leaves gaps
365    /// written in front of it. Nothing may read one of these as saying anything about the bytes
366    /// between the accesses.
367    CheckType,
368    /// The bytes the access reads have been written.
369    ///
370    /// A third operand overrides how many bytes are asked about, and a fourth is a step, both as on
371    /// [`Opcode::CheckType`].
372    CheckInit,
373    /// A pointer derived from another stays inside the capability the first one had.
374    ///
375    /// Three operands, because the answer is about the new pointer and the question is about
376    /// the old one's capability.
377    CheckDeriv,
378    /// The metadata this access is about to consult has not been changed under it.
379    ///
380    /// Judgement J9, which document 09 section 9.5 specifies and which document 04 section 4.5
381    /// keeps out of J1 for the reason the `restrict` checks are kept out: it is a statement about
382    /// two operations rather than about one. The payload holds the size of the access, because the
383    /// question is whether any granule of the range this touches carries a write by another thread.
384    CheckRace,
385    /// This read did not reach a byte another `restrict` pointer of the same block wrote.
386    ///
387    /// Judgement J8, which document 09 section 9.6 specifies and which document 04 section 4.6
388    /// keeps out of J1 because it is a statement about a pair of accesses rather than about one.
389    /// The payload holds the size of the access and the two numbers saying which pointer it went
390    /// through, and those are the same two [`crate::Restrict`] carries on the access itself.
391    ///
392    /// Read and write are two opcodes rather than one with a flag on it, because every bit of
393    /// [`crate::Flags`] is spoken for and because the operand would then be a constant the program
394    /// does not compute, which is the thing [`Opcode::CheckBounds`] says belongs in the payload.
395    CheckRestrictRead,
396    /// The same about a write, which is the half of the pair that makes the other half a violation.
397    ///
398    /// Two accesses that both only read are not a violation of anything, so what the scope records
399    /// is which of them wrote and the check refuses a pair only when at least one did.
400    CheckRestrictWrite,
401    /// The capability this free goes through still names the instance that owns the address.
402    ///
403    /// Judgement J6, and the same two operands [`Opcode::CheckLive`] has for the same reason: a
404    /// capability and the pointer it is about, with no payload, because how many bytes are at the
405    /// address is not something a free asks. What separates it from the lifetime check is where it
406    /// goes and what it is about. This one sits in front of a call that ends a storage instance
407    /// rather than in front of an access, and the question it decides is whether the pointer being
408    /// handed over still names the instance it was made for.
409    ///
410    /// It exists because that question has no other way of being asked. `free` takes an address and
411    /// nothing else, so a second free of a block the allocator has already handed back out looks
412    /// like an ordinary free to the allocator and releases somebody else's live object.
413    /// tamnd/rucc#492 is that, and the version the capability carries is what tells the two apart.
414    ///
415    /// Nothing discharges one. A bounds fact says nothing about it and a lifetime fact about an
416    /// access says nothing about a free, so it stays where the pass put it and the cost is one
417    /// check per free rather than one per access.
418    CheckFree,
419    /// A storage instance begins here, over a range, with a class.
420    ///
421    /// Judgement J4. This is the `alloca` for an automatic instance and the allocator's report
422    /// for an allocated one, and the range is a pointer and a length in registers rather than a
423    /// payload, because the length of a variable length array is not known when the instruction
424    /// is written down.
425    MetaBegin,
426    /// A storage instance ends here, which is judgement J5.
427    ///
428    /// Every capability for it fails from this point on and keeps failing after the address is
429    /// handed out again, which is what makes the check a use after free check rather than a use
430    /// after reallocation one.
431    MetaEnd,
432    /// The effective type of a range is now this one.
433    MetaType,
434    /// The effective types of a range are now the ones the range it was copied from had.
435    ///
436    /// Three operands, because a copy has two ranges and one length: the destination, the source,
437    /// and how many bytes moved. A `memcpy` does not store through a type, so there is no type to
438    /// name here and naming one would be wrong: C 6.5 says the copied bytes keep the effective type
439    /// they had, whatever that was, and the only place that is written down is the plane over the
440    /// source.
441    MetaTypeCopy,
442    /// The bytes of a range are now initialized.
443    MetaInit,
444    /// The bytes of a range are now initialized wherever the range they were copied from was.
445    ///
446    /// Three operands, for the reason [`Opcode::MetaTypeCopy`] has three. A copy does not write
447    /// values of its own, so whether a destination byte holds anything is whether the byte it came
448    /// from did, and the only place that is written down is the plane over the source. That is what
449    /// makes a structure filled member by member and then copied whole still have padding nothing
450    /// wrote, which is the infoleak the plane is for.
451    MetaInitCopy,
452    /// This thread wrote a range, at whatever step of its own counting it has reached.
453    ///
454    /// The epoch plane's only write, from `spec/safe-memory/09-type-init-and-races.md` section 9.5.
455    /// Two operands like the other plane writes, and the range is a pointer shaped slot rather than
456    /// whatever the access covered: the plane holds one stamp per eight bytes because that is what
457    /// a pointer comes in, and a granule two threads share is one holding no pointer.
458    ///
459    /// It carries no thread and no count. Which thread is running and how far it has counted are
460    /// both facts about the moment the program reaches this, so the runtime reads them and nothing
461    /// here could name them.
462    MetaEpoch,
463    /// Everything this thread has done so far is published at the atomic object named here.
464    ///
465    /// One half of a synchronization edge in the sense of section 9.5, and the half that goes in
466    /// front of the atomic that carries it. The operand is the object's address, because that is
467    /// the key whoever takes the other end will look the clock up under, and there is no payload:
468    /// which thread is publishing and how far it has counted are facts about the moment the program
469    /// reaches this, the same way they are for [`Opcode::MetaEpoch`].
470    ///
471    /// This exists because an atomic is not a call. Every other edge the monitor knows about is a
472    /// `pthread` function and is interposed, and a C11 release store is a machine instruction with
473    /// nothing to interpose, so the compiler is the only thing that can say the edge was there.
474    MetaRelease,
475    /// Everything published at the atomic object named here is now ordered before this thread.
476    ///
477    /// The other half of [`Opcode::MetaRelease`], and it goes after the atomic rather than in front
478    /// of it, because the ordering it takes is the ordering the atomic just read.
479    ///
480    /// A missing edge is the one kind of missing instrumentation in the whole safety pass that
481    /// costs a false report rather than a missed one: two threads that really were ordered by an
482    /// edge nobody recorded look concurrent, and a race is reported against a program doing nothing
483    /// wrong. That is why the edges go in before the race check is ever on by default.
484    MetaAcquire,
485    /// Everything this thread has done so far is published at no object in particular.
486    ///
487    /// What a release fence is, and the reason it cannot reuse [`Opcode::MetaRelease`]: a fence
488    /// orders against every other thread rather than against one object, so there is no address to
489    /// key it on and it takes no operands at all. The relaxed atomic that usually sits beside it in
490    /// the source is not the key either, because the fence orders everything, not that one word.
491    ///
492    /// The runtime pays for that with one cell shared by every fence in the program, which orders
493    /// more pairs of threads than the program really ordered. That direction is safe. A thread put
494    /// further ahead than it needed to be reports fewer races, never a wrong one.
495    MetaFenceRelease,
496    /// Everything published at any release fence is now ordered before this thread.
497    ///
498    /// The other half of [`Opcode::MetaFenceRelease`], after the fence rather than in front of it,
499    /// for the same reason [`Opcode::MetaAcquire`] goes after its atomic.
500    MetaFenceAcquire,
501    /// A range leaves the monitor's authority, or comes back, which is judgement J7.
502    MetaTransfer,
503    /// A declared exemption starts here, with the reason it was declared.
504    ///
505    /// Not an optimization hint. Everything between this and its `safe_region_end` is code the
506    /// monitor is told not to judge, so the reason it carries is a trust set entry, and
507    /// `spec/safe-memory/10-boundaries.md` section 10.2 counts them per build precisely so that
508    /// a reviewer can read what a binary's guarantee rests on.
509    SafeRegionBegin,
510    /// The end of the region the last `safe_region_begin` opened.
511    SafeRegionEnd,
512    /// A block that declares `restrict` pointers begins here, over a slot to keep its record in.
513    ///
514    /// The operand is the storage the record lives in, which is the block's own stack slot, and the
515    /// payload says how large it is. The clique the block was given is [`crate::Restrict::clique`]
516    /// of the payload and how many pointers it declares is [`crate::Restrict::base`], which is the
517    /// one place that field counts bases rather than naming one.
518    ///
519    /// A marker rather than something the front end could fold into the accesses, because the
520    /// promise is about the block's dynamic extent: a function called twice has made the promise
521    /// twice, and what the second call reached says nothing about the first.
522    RestrictEnter,
523    /// The block the last `restrict_enter` opened ends here.
524    ///
525    /// The operand is the same slot, so that the record can be unlinked from whatever encloses it
526    /// without the runtime having to keep a list of its own.
527    RestrictLeave,
528
529    // Control. Every one of these is a terminator.
530    /// An unconditional branch, `jump block1(%a, %b)`.
531    Jump,
532    /// A two-way branch on an `i1`.
533    BrIf,
534    /// A multi-way branch on an integer, with a default.
535    Switch,
536    /// A branch to an address, `indirect_br %0, block1, block2`.
537    ///
538    /// The targets are every block control can arrive at, which is what makes the edges of a
539    /// computed `goto` ordinary edges: nothing else in the compiler has to know that the
540    /// address decides which one it is. A target that is not listed is a branch that does not
541    /// happen, so a frontend that leaves one out has made a promise on the program's behalf.
542    IndirectBr,
543    /// A return, with the values the signature says.
544    Return,
545    /// A place control cannot reach, which the frontend emits after a `noreturn` call.
546    Unreachable,
547
548    // Calls.
549    /// A call to a named function.
550    Call,
551    /// A call through an address, carrying the signature it is called with.
552    CallIndirect,
553    /// A call in tail position that reuses the frame, which is a terminator.
554    TailCall,
555
556    // Intrinsics, which is the closed part. The open part is `TargetIntrinsic`.
557    /// Count leading zeroes.
558    Ctlz,
559    /// Count trailing zeroes.
560    Cttz,
561    /// Count set bits.
562    Ctpop,
563    /// Reverse the bytes.
564    Bswap,
565    /// Reverse the bits.
566    Bitreverse,
567    /// Signed addition, producing the result and whether it overflowed.
568    SAddOverflow,
569    /// Unsigned addition, producing the result and whether it overflowed.
570    UAddOverflow,
571    /// Signed subtraction, producing the result and whether it overflowed.
572    SSubOverflow,
573    /// Unsigned subtraction, producing the result and whether it overflowed.
574    USubOverflow,
575    /// Signed multiplication, producing the result and whether it overflowed.
576    SMulOverflow,
577    /// Unsigned multiplication, producing the result and whether it overflowed.
578    UMulOverflow,
579    /// `__builtin_expect`, which is the value with a hint attached.
580    Expect,
581    /// `__builtin_unreachable` as a hint on a path, distinct from the terminator.
582    UnreachableHint,
583    /// `__builtin_trap`, which stops the program where it stands.
584    ///
585    /// Not a terminator, for the reason `unreachable_hint` is not one: what ends a block here is
586    /// control going somewhere, and this goes nowhere at all. The block it is in goes on being
587    /// lowered and whatever follows it is written and never run, which costs a few bytes nothing
588    /// reaches and keeps every pass that walks a block from needing a second shape for it.
589    Trap,
590    /// `__builtin_prefetch`.
591    Prefetch,
592    /// `__builtin_frame_address`.
593    FrameAddress,
594    /// `__builtin_return_address`.
595    ReturnAddress,
596    /// `__builtin_thread_pointer`, the address of the storage the running thread has.
597    ///
598    /// It takes nothing and answers a pointer. Unlike the two above it there is no walk to do and
599    /// no frame to have kept: the machine holds the address in a place of its own, so this is one
600    /// instruction on every target that has the builtin at all.
601    ThreadPointer,
602    /// `__builtin_apply_args`, the address of a block holding every argument the function it is in
603    /// was called with.
604    ///
605    /// It takes nothing and answers a pointer. What is in the block is the argument registers as
606    /// they were on the way in and the address of the arguments that came in memory, and it is the
607    /// back end that writes it, in the prologue, because that is the one place every register an
608    /// argument can arrive in still holds what the caller put there. A function holding one reads
609    /// its arguments as registers rather than as parameters, so it is never inlined and its
610    /// parameters are never taken apart, since either would change what the registers hold.
611    ApplyArgs,
612    /// `__builtin_apply`, a call to the function in the first operand with the arguments in the
613    /// block in the second, and the address of a block holding what came back.
614    ///
615    /// Three operands: the function, the block an `apply_args` answered, and a constant, which is
616    /// how many bytes of the arguments that came in memory go with the call. It is a call to
617    /// something nothing here can see, so every pass that asks about a call through an address asks
618    /// the same about this and gets the same answer.
619    Apply,
620    /// `__builtin_object_size` where the front end could not see the object, which is how many
621    /// bytes there are from the address to the end of whatever it points into.
622    ///
623    /// One operand, the address, and the question as a number from zero to three beside it: the
624    /// low bit asks about the closest member rather than the whole object and the high bit asks
625    /// for the smallest answer rather than the largest. It never reaches the back end:
626    /// `rucc_opt::objsize` answers every one before any other pass runs, from the allocations and
627    /// the arithmetic the address was built out of, and says it does not know where it cannot
628    /// see, which is the largest number there is for the first two questions and zero for the
629    /// other two.
630    ObjectSize,
631    /// `__builtin_constant_p` of a value the front end could not see to be a constant, which is
632    /// one where the optimizer may yet make it one.
633    ///
634    /// One operand, an integer or a floating point value, and an `i32` answer. It never reaches the
635    /// back end: `rucc_opt::constant_p` answers one where the operand has become a constant by the
636    /// time it runs and zero everywhere else, which is when gcc answers it too, and at `-O0` it
637    /// answers zero before any other pass runs, which is what gcc answers at that level.
638    IsConstant,
639    /// `__builtin_va_arg_pack`, which stands for every anonymous argument of the call the function
640    /// it is in was inlined into.
641    ///
642    /// No operands, and an `i32` result that is only ever the last argument of a variadic call,
643    /// which is the one place gcc lets the builtin be written. It never reaches the back end:
644    /// `rucc_opt::inline` takes the argument out of that call and puts the anonymous arguments of
645    /// the call it is inlining in its place, and a body still holding one after that is a body the
646    /// unit does not emit.
647    VaArgPack,
648    /// `__builtin_va_arg_pack_len`, which is how many anonymous arguments the call the function it
649    /// is in was inlined into had.
650    ///
651    /// No operands and an `i32` result. `rucc_opt::inline` puts the count in its place, and a body
652    /// still holding one after that is not emitted, the same as for [`Self::VaArgPack`].
653    VaArgPackLen,
654    /// What is in a machine register, for `register long x asm ("rbx");`.
655    ///
656    /// The GNU extension that puts an object in a named register rather than in the frame. The
657    /// name of the register is the payload and the result is whatever that register holds where
658    /// this stands, which is the value the object starts with. A garbage collector written in C
659    /// reads the callee saved registers this way, because a root that is only in one of those is
660    /// a root no walk of the stack finds.
661    ///
662    /// It is not pure. Two of these on the same register in one function are two different
663    /// answers, since anything in between may have written the register, so neither may be moved
664    /// to where the other is and neither may be dropped for the other.
665    RegisterValue,
666    /// The start of a variable argument list.
667    VaStart,
668    /// One argument off a variable argument list, which moves the list on as it reads it. Two
669    /// of these on one list are two arguments and never one argument read twice, so whatever
670    /// decides which instructions may be folded together has to leave these alone.
671    VaArg,
672    /// One argument off a variable argument list, when that argument is an object rather than a
673    /// value, which is what a `struct` or a `union` read out of one is.
674    ///
675    /// It answers the address of the object rather than the object, because an aggregate is not
676    /// a value and there is nothing for one result to be. Where the object arrives in registers
677    /// there is no address until something makes one, so what this asks of a target is a place
678    /// to put the registers and the address of that place, which is the copy every psABI's own
679    /// description of the algorithm makes. It moves the list on for the reason [`Opcode::VaArg`]
680    /// does.
681    VaObject,
682    /// The end of a variable argument list.
683    VaEnd,
684    /// A copy of a variable argument list.
685    VaCopy,
686    /// The stack pointer, saved before a variable length array.
687    StackSave,
688    /// The stack pointer, restored after one.
689    StackRestore,
690    /// The marker a `setjmp` leaves, which pins everything live across it.
691    ///
692    /// One operand, the buffer, and one result, which is the `int` the save answers with: zero
693    /// where control went past it and one where control came back to it. That is the one
694    /// instruction here whose value depends on how control reached it, and it is one instruction
695    /// rather than a branch and a block because the edge a `longjmp` travels is not in this
696    /// function's control flow graph. It is written into the buffer and taken at run time, so a
697    /// pass that walked the edges would find a block nothing reaches and take it away.
698    SetjmpMarker,
699    /// The marker a `longjmp` leaves.
700    ///
701    /// One operand, the buffer, and no result, and not a terminator either, for the reason above:
702    /// where control goes is not a block of this function. What follows it is written and never
703    /// reached.
704    LongjmpMarker,
705    /// Whether the call just before this in its block unwound rather than returned.
706    ///
707    /// No operands and one `i1`, and nothing but the condition of the `br_if` that ends the block
708    /// reads it. That branch is the edge an exception travels to the landing pad on, written as
709    /// an ordinary edge so that every pass that walks the graph sees the pad as reachable and
710    /// keeps what the pad reads alive, which is the whole reason the answer is a value and not
711    /// something the call says about itself. Nothing computes it: the code generator writes no
712    /// instruction for it or for the branch, and the call is given the pad in the table the
713    /// unwinder reads instead. So it has to stay where it is, straight after its call, and one
714    /// with no call in front of it, which is a call something folded away, answers false.
715    Unwound,
716    /// The exception an unwind arrived at a landing pad with, which is the first thing in the
717    /// block a `br_if` on [`Opcode::Unwound`] sends it to.
718    ///
719    /// No operands and one pointer, which is what the unwinder left in the first return register
720    /// and what `_Unwind_Resume` is handed at the end of the pad to carry on unwinding.
721    Landing,
722    /// A target-specific intrinsic, named rather than enumerated, for the vector builtins.
723    TargetIntrinsic,
724
725    /// Inline assembly. A terminator when it has labels, which is `asm goto`.
726    InlineAsm,
727}
728
729impl Opcode {
730    /// The textual form, which is also what the parser reads.
731    #[must_use]
732    pub const fn name(self) -> &'static str {
733        match self {
734            Self::IConst => "iconst",
735            Self::FConst => "fconst",
736            Self::Splat => "splat",
737            Self::GlobalAddr => "global_addr",
738            Self::BlockAddr => "block_addr",
739            Self::Add => "add",
740            Self::Sub => "sub",
741            Self::Mul => "mul",
742            Self::SDiv => "sdiv",
743            Self::UDiv => "udiv",
744            Self::SRem => "srem",
745            Self::URem => "urem",
746            Self::UMulHigh => "umulh",
747            Self::SMulHigh => "smulh",
748            Self::And => "and",
749            Self::Or => "or",
750            Self::Xor => "xor",
751            Self::Shl => "shl",
752            Self::LShr => "lshr",
753            Self::AShr => "ashr",
754            Self::FAdd => "fadd",
755            Self::FSub => "fsub",
756            Self::FMul => "fmul",
757            Self::FDiv => "fdiv",
758            Self::FRem => "frem",
759            Self::FNeg => "fneg",
760            Self::Fma => "fma",
761            Self::ICmp => "icmp",
762            Self::FCmp => "fcmp",
763            Self::Select => "select",
764            Self::Trunc => "trunc",
765            Self::SExt => "sext",
766            Self::ZExt => "zext",
767            Self::FPTrunc => "fptrunc",
768            Self::FPExt => "fpext",
769            Self::FPToSI => "fptosi",
770            Self::FPToUI => "fptoui",
771            Self::SIToFP => "sitofp",
772            Self::UIToFP => "uitofp",
773            Self::PtrToInt => "ptrtoint",
774            Self::IntToPtr => "inttoptr",
775            Self::Bitcast => "bitcast",
776            Self::MemEntry => "mem_entry",
777            Self::Alloca => "alloca",
778            Self::Load => "load",
779            Self::Store => "store",
780            Self::PtrAdd => "ptr_add",
781            Self::Memcpy => "memcpy",
782            Self::Memmove => "memmove",
783            Self::Memset => "memset",
784            Self::AtomicLoad => "atomic_load",
785            Self::AtomicStore => "atomic_store",
786            Self::AtomicRmw => "atomic_rmw",
787            Self::Cmpxchg => "cmpxchg",
788            Self::Fence => "fence",
789            Self::CapOf => "cap_of",
790            Self::CapLoad => "cap_load",
791            Self::CapStore => "cap_store",
792            Self::CapCopy => "cap_copy",
793            Self::CapNull => "cap_null",
794            Self::CapNarrow => "cap_narrow",
795            Self::CapRecover => "cap_recover",
796            Self::CapExtent => "cap_extent",
797            Self::CapExtentBack => "cap_extent_back",
798            Self::CapPublish => "cap_publish",
799            Self::CapClear => "cap_clear",
800            Self::CapArg => "cap_arg",
801            Self::CapYield => "cap_yield",
802            Self::CapResult => "cap_result",
803            Self::CheckBounds => "check_bounds",
804            Self::CheckLive => "check_live",
805            Self::CheckType => "check_type",
806            Self::CheckInit => "check_init",
807            Self::CheckDeriv => "check_deriv",
808            Self::CheckRace => "check_race",
809            Self::CheckRestrictRead => "check_restrict_read",
810            Self::CheckRestrictWrite => "check_restrict_write",
811            Self::CheckFree => "check_free",
812            Self::MetaBegin => "meta_begin",
813            Self::MetaEnd => "meta_end",
814            Self::MetaType => "meta_type",
815            Self::MetaTypeCopy => "meta_type_copy",
816            Self::MetaInit => "meta_init",
817            Self::MetaInitCopy => "meta_init_copy",
818            Self::MetaEpoch => "meta_epoch",
819            Self::MetaRelease => "meta_release",
820            Self::MetaAcquire => "meta_acquire",
821            Self::MetaFenceRelease => "meta_fence_release",
822            Self::MetaFenceAcquire => "meta_fence_acquire",
823            Self::MetaTransfer => "meta_transfer",
824            Self::SafeRegionBegin => "safe_region_begin",
825            Self::SafeRegionEnd => "safe_region_end",
826            Self::RestrictEnter => "restrict_enter",
827            Self::RestrictLeave => "restrict_leave",
828            Self::Jump => "jump",
829            Self::BrIf => "br_if",
830            Self::Switch => "switch",
831            Self::IndirectBr => "indirect_br",
832            Self::Return => "return",
833            Self::Unreachable => "unreachable",
834            Self::Call => "call",
835            Self::CallIndirect => "call_indirect",
836            Self::TailCall => "tail_call",
837            Self::Ctlz => "ctlz",
838            Self::Cttz => "cttz",
839            Self::Ctpop => "ctpop",
840            Self::Bswap => "bswap",
841            Self::Bitreverse => "bitreverse",
842            Self::SAddOverflow => "sadd_overflow",
843            Self::UAddOverflow => "uadd_overflow",
844            Self::SSubOverflow => "ssub_overflow",
845            Self::USubOverflow => "usub_overflow",
846            Self::SMulOverflow => "smul_overflow",
847            Self::UMulOverflow => "umul_overflow",
848            Self::Expect => "expect",
849            Self::UnreachableHint => "unreachable_hint",
850            Self::Trap => "trap",
851            Self::Prefetch => "prefetch",
852            Self::FrameAddress => "frame_address",
853            Self::ReturnAddress => "return_address",
854            Self::ThreadPointer => "thread_pointer",
855            Self::ApplyArgs => "apply_args",
856            Self::Apply => "apply",
857            Self::ObjectSize => "object_size",
858            Self::IsConstant => "is_constant",
859            Self::VaArgPack => "va_arg_pack",
860            Self::VaArgPackLen => "va_arg_pack_len",
861            Self::RegisterValue => "register_value",
862            Self::VaStart => "va_start",
863            Self::VaArg => "va_arg",
864            Self::VaObject => "va_object",
865            Self::VaEnd => "va_end",
866            Self::VaCopy => "va_copy",
867            Self::StackSave => "stacksave",
868            Self::StackRestore => "stackrestore",
869            Self::SetjmpMarker => "setjmp_marker",
870            Self::LongjmpMarker => "longjmp_marker",
871            Self::Unwound => "unwound",
872            Self::Landing => "landing",
873            Self::TargetIntrinsic => "target_intrinsic",
874            Self::InlineAsm => "inline_asm",
875        }
876    }
877
878    /// Every opcode, in the order they are declared.
879    ///
880    /// The parser walks this rather than holding a second table, because a second table is a
881    /// table that can disagree with the first one.
882    pub fn all() -> impl Iterator<Item = Self> {
883        ALL.iter().copied()
884    }
885
886    /// The opcode with that name, if there is one.
887    #[must_use]
888    pub fn from_name(name: &str) -> Option<Self> {
889        ALL.iter().copied().find(|op| op.name() == name)
890    }
891
892    /// Whether this ends a block.
893    ///
894    /// [`Opcode::InlineAsm`] is not here and is the one instruction whose answer depends on
895    /// the instruction rather than on the opcode: `asm goto` has successors and everything
896    /// else does not. Ask the instruction, not the opcode.
897    #[must_use]
898    pub const fn is_terminator(self) -> bool {
899        matches!(
900            self,
901            Self::Jump
902                | Self::BrIf
903                | Self::Switch
904                | Self::IndirectBr
905                | Self::Return
906                | Self::Unreachable
907                | Self::TailCall
908        )
909    }
910
911    /// Whether the operands can be swapped without changing the result.
912    ///
913    /// The floating point cases are commutative even under the strictest rounding, because
914    /// swapping the operands of an addition does not change which of them is a NaN, and the
915    /// sign of a NaN result is not something we promise anything about either way.
916    #[must_use]
917    pub const fn is_commutative(self) -> bool {
918        matches!(
919            self,
920            Self::Add
921                | Self::Mul
922                | Self::UMulHigh
923                | Self::SMulHigh
924                | Self::And
925                | Self::Or
926                | Self::Xor
927                | Self::FAdd
928                | Self::FMul
929                | Self::SAddOverflow
930                | Self::UAddOverflow
931                | Self::SMulOverflow
932                | Self::UMulOverflow
933        )
934    }
935
936    /// Whether this reads or writes memory, or has an effect the optimizer has to preserve.
937    ///
938    /// An instruction that answers no can be deleted when nothing uses its result, moved
939    /// across a call, and merged with another one computing the same thing. Everything else
940    /// has to be argued about individually, so the conservative answer is the true one here
941    /// and the list of exceptions is the part that is checked.
942    #[must_use]
943    pub const fn has_effects(self) -> bool {
944        !matches!(
945            self,
946            Self::IConst
947                | Self::FConst
948                | Self::Splat
949                | Self::GlobalAddr
950                | Self::BlockAddr
951                | Self::Add
952                | Self::Sub
953                | Self::Mul
954                | Self::SDiv
955                | Self::UDiv
956                | Self::SRem
957                | Self::URem
958                | Self::UMulHigh
959                | Self::SMulHigh
960                | Self::And
961                | Self::Or
962                | Self::Xor
963                | Self::Shl
964                | Self::LShr
965                | Self::AShr
966                | Self::FAdd
967                | Self::FSub
968                | Self::FMul
969                | Self::FDiv
970                | Self::FRem
971                | Self::FNeg
972                | Self::Fma
973                | Self::ICmp
974                | Self::FCmp
975                | Self::Select
976                | Self::Trunc
977                | Self::SExt
978                | Self::ZExt
979                | Self::FPTrunc
980                | Self::FPExt
981                | Self::FPToSI
982                | Self::FPToUI
983                | Self::SIToFP
984                | Self::UIToFP
985                | Self::PtrToInt
986                | Self::IntToPtr
987                | Self::Bitcast
988                | Self::PtrAdd
989                | Self::Ctlz
990                | Self::Cttz
991                | Self::Ctpop
992                | Self::Bswap
993                | Self::Bitreverse
994                | Self::SAddOverflow
995                | Self::UAddOverflow
996                | Self::SSubOverflow
997                | Self::USubOverflow
998                | Self::SMulOverflow
999                | Self::UMulOverflow
1000                | Self::Expect
1001                | Self::FrameAddress
1002                | Self::ReturnAddress
1003                // The same address for as long as the thread runs, and a thread cannot change
1004                // which one it is part way through a function, so two of these in one function
1005                // are the same value and either may be moved to where the other is.
1006                | Self::ThreadPointer
1007                // A question about an address that reads nothing: the answer is a fact about where
1008                // the address came from, which is the same fact wherever the question is asked.
1009                | Self::ObjectSize
1010                // A question about a value, whose answer is the same wherever it is asked.
1011                | Self::IsConstant
1012                // Nothing yet, and something the inliner fills in before any pass asks.
1013                | Self::VaArgPack
1014                | Self::VaArgPackLen
1015                | Self::MemEntry
1016                // Three of the capability instructions are arithmetic on a pointer's
1017                // provenance and touch nothing. The other four do: `cap_load`, `cap_store` and
1018                // `cap_copy` are an access, and `cap_recover` reads the planes.
1019                | Self::CapOf
1020                | Self::CapNull
1021                | Self::CapNarrow
1022        )
1023    }
1024
1025    /// Whether an instruction with this opcode touches memory.
1026    ///
1027    /// This is what decides whether it takes a memory operand once memory SSA is built, per
1028    /// document 09 of `spec/optimizer`. It is written as the exceptions to touching memory
1029    /// rather than as a list of what does, for the reason document 08.6 gives about the escape
1030    /// analysis: an opcode added later has to end up on the conservative side by default, and a
1031    /// list of what touches memory would silently leave a new one out.
1032    ///
1033    /// `mem_entry` answers no. It produces memory rather than touching it, which is the whole
1034    /// of what it is for.
1035    #[must_use]
1036    pub const fn touches_memory(self) -> bool {
1037        if !self.has_effects() {
1038            return false;
1039        }
1040        !matches!(
1041            self,
1042            // Fresh storage nothing could have been reading, and the pointer that names it.
1043            Self::Alloca
1044                // The stack pointer, which is a register and not memory. Putting it back is a
1045                // different matter and is below, because it takes storage away.
1046                | Self::StackSave
1047                // Two questions about how control arrived, which read the unwinder's answer
1048                // rather than anything in memory.
1049                | Self::Unwound
1050                | Self::Landing
1051                // Control, which goes somewhere rather than touching anything. A tail call is
1052                // not here, because it is a call.
1053                | Self::Jump
1054                | Self::BrIf
1055                | Self::Switch
1056                | Self::IndirectBr
1057                | Self::Return
1058                | Self::Unreachable
1059                | Self::UnreachableHint
1060        )
1061    }
1062
1063    /// Whether an instruction with this opcode writes memory, and so produces a new version of
1064    /// it rather than only reading the version it was given.
1065    ///
1066    /// Everything that touches memory writes it except the ones that plainly do not. A `fence`
1067    /// writes nothing and is still a write here, because document 09.5 says an atomic or a
1068    /// barrier is a definition nothing walks past, and giving it one is how that is expressed
1069    /// in a representation whose only ordering is the memory chain.
1070    ///
1071    /// The checks read the planes and change nothing, which
1072    /// `spec/safe-memory/06-instrumentation.md` section 6.2.4 states as the word `readonly`. A
1073    /// check that trapped is a program that stopped and there is no version of memory after it
1074    /// for anything to observe, so the trap costs nothing here. What it does cost is that a
1075    /// check may not be moved across a plane write, and that is the memory chain saying so
1076    /// rather than this.
1077    #[must_use]
1078    pub const fn writes_memory(self) -> bool {
1079        self.touches_memory()
1080            && !matches!(
1081                self,
1082                Self::Load
1083                    | Self::AtomicLoad
1084                    | Self::Prefetch
1085                    | Self::CapLoad
1086                    | Self::CapRecover
1087                    | Self::CapArg
1088                    | Self::CapResult
1089                    | Self::CapExtent
1090                    | Self::CapExtentBack
1091                    | Self::CheckBounds
1092                    | Self::CheckLive
1093                    | Self::CheckType
1094                    | Self::CheckInit
1095                    | Self::CheckDeriv
1096                    | Self::CheckRace
1097                    | Self::CheckFree
1098            )
1099    }
1100
1101    /// Whether the only memory this touches is the safety planes.
1102    ///
1103    /// The planes are storage the runtime keeps for itself, one entry per range of program bytes,
1104    /// laid out by `spec/safe-memory/05-representation.md` section 5.2. What matters here is that
1105    /// no name in the program reaches one. A plane write and a program store can never be the same
1106    /// byte, and neither can a plane read and a program load, so an alias oracle that knows this
1107    /// answers no to every pair with one of each.
1108    ///
1109    /// The aux plane sits in the same allocation as the object rather than in a map of its own, so
1110    /// an address far enough outside an object does land in somebody's plane. That is an access
1111    /// outside the bounds of the thing it was derived from, which is the access every check in this
1112    /// list exists to refuse, and it is undefined before it is refused. An optimizer is entitled to
1113    /// the assumption that the program does not make one, and this is that assumption and not a
1114    /// second one.
1115    ///
1116    /// Nothing above can work that out by looking at the access, which is why this is here. The
1117    /// address operand of one of these is a locator and not the memory it touches: `meta_init %p`
1118    /// writes the entry the plane keeps for `%p` and does not write `%p`, so an oracle reading the
1119    /// operand the ordinary way sees a write to exactly the bytes a load of `%p` wants.
1120    ///
1121    /// A list of what does rather than the exceptions to it, which is the other way round from
1122    /// [`Opcode::touches_memory`] and for the same reason: an opcode added later and left out of
1123    /// this one is an opcode the oracle says nothing about, which costs a missed optimization,
1124    /// and an opcode added later that lands in here without anybody reading what it does would be
1125    /// a wrong answer about memory in the safety pass of all places.
1126    ///
1127    /// Two families are deliberately not here even though their names look like they belong. The
1128    /// `restrict` markers take the block's own stack slot as an operand and write their record into
1129    /// it. The synchronization edges say something about the ordering of program memory rather than
1130    /// only about a plane, and a wrong answer there is a false report rather than a missed one.
1131    ///
1132    /// The capability instructions are mostly out and not all of them, so the line between them is
1133    /// worth saying plainly: it is whether every pointer the instruction takes is a locator.
1134    /// `cap_load`, `cap_store` and `cap_recover` each have one that is not, because the point of
1135    /// the aux pair is that a pointer written into a slot comes back out of one, so an address
1136    /// handed to any of those has gone somewhere a later instruction can get it from. `cap_copy`
1137    /// has no such operand. Its three are a destination, a source and a length, it writes nothing
1138    /// but the slots over the destination and reads nothing but the slots over the source, and a
1139    /// slot holds a displacement from the pointer beside it rather than an address, so a run of
1140    /// slots that ends up saying what another run said has moved no address anywhere the copy of
1141    /// the words themselves did not move it already.
1142    #[must_use]
1143    pub const fn touches_only_planes(self) -> bool {
1144        matches!(
1145            self,
1146            Self::CheckBounds
1147                | Self::CheckLive
1148                | Self::CheckType
1149                | Self::CheckInit
1150                | Self::CheckDeriv
1151                | Self::CheckRace
1152                | Self::CheckFree
1153                | Self::CapExtent
1154                | Self::CapExtentBack
1155                | Self::CapCopy
1156                | Self::MetaBegin
1157                | Self::MetaEnd
1158                | Self::MetaType
1159                | Self::MetaTypeCopy
1160                | Self::MetaInit
1161                | Self::MetaInitCopy
1162                | Self::MetaEpoch
1163                | Self::MetaTransfer
1164        )
1165    }
1166
1167    /// Whether this marks one end of a jump along an edge this function's control flow graph does
1168    /// not have.
1169    ///
1170    /// The two `setjmp` markers and nothing else. It exists because an alias oracle that reasons
1171    /// about a call reasons from what the call was handed, and neither of these was handed
1172    /// anything. Control arrives at the instruction after a `setjmp_marker` from wherever the
1173    /// matching `longjmp` sits, so the memory there is a join of the chain that flows into the
1174    /// marker and the memory at every one of those points, and a `longjmp_marker` is the other end
1175    /// of that join and so reads everything the landing will look at. An object whose address never
1176    /// left this function is as exposed to both as anything else, because the jump comes back into
1177    /// this frame and the program reads the frame's own slots afterwards. The only answer about a
1178    /// reference across one of these that cannot be wrong is that it may be touched.
1179    #[must_use]
1180    pub const fn is_jump_marker(self) -> bool {
1181        matches!(self, Self::SetjmpMarker | Self::LongjmpMarker)
1182    }
1183
1184    /// How many values this produces, for the opcodes where the count is fixed.
1185    ///
1186    /// `None` means the count comes from somewhere else: a call takes it from its signature,
1187    /// and inline assembly takes it from its output constraints. A tail call is not one of
1188    /// them, because whatever it returns goes straight out of the function and there is no
1189    /// instruction after it to use anything.
1190    #[must_use]
1191    pub const fn results(self) -> Option<u8> {
1192        match self {
1193            Self::Call | Self::CallIndirect | Self::InlineAsm => None,
1194            Self::Cmpxchg
1195            | Self::SAddOverflow
1196            | Self::UAddOverflow
1197            | Self::SSubOverflow
1198            | Self::USubOverflow
1199            | Self::SMulOverflow
1200            | Self::UMulOverflow => Some(2),
1201            Self::Store
1202            | Self::Memcpy
1203            | Self::Memmove
1204            | Self::Memset
1205            | Self::AtomicStore
1206            | Self::Fence
1207            | Self::Prefetch
1208            | Self::VaStart
1209            | Self::VaEnd
1210            | Self::VaCopy
1211            | Self::StackRestore
1212            | Self::UnreachableHint
1213            | Self::Trap
1214            | Self::LongjmpMarker
1215            | Self::CapStore
1216            | Self::CapCopy
1217            | Self::CapPublish
1218            | Self::CapClear
1219            | Self::CapYield
1220            | Self::CheckBounds
1221            | Self::CheckLive
1222            | Self::CheckType
1223            | Self::CheckInit
1224            | Self::CheckDeriv
1225            | Self::CheckRace
1226            | Self::CheckRestrictRead
1227            | Self::CheckRestrictWrite
1228            | Self::CheckFree
1229            | Self::MetaBegin
1230            | Self::MetaEnd
1231            | Self::MetaType
1232            | Self::MetaTypeCopy
1233            | Self::MetaInit
1234            | Self::MetaInitCopy
1235            | Self::MetaEpoch
1236            | Self::MetaRelease
1237            | Self::MetaAcquire
1238            | Self::MetaFenceRelease
1239            | Self::MetaFenceAcquire
1240            | Self::MetaTransfer
1241            | Self::SafeRegionBegin
1242            | Self::SafeRegionEnd
1243            | Self::RestrictEnter
1244            | Self::RestrictLeave => Some(0),
1245            _ if self.is_terminator() => Some(0),
1246            _ => Some(1),
1247        }
1248    }
1249
1250    /// Whether an instruction with this opcode produces a capability.
1251    ///
1252    /// Seven of the fourteen `cap` instructions. The other seven consume one instead, or none at
1253    /// all: `cap_store` writes one beside a pointer, `cap_copy` moves a run of them from beside one
1254    /// set of words to beside another, `cap_extent` and `cap_extent_back` ask one a
1255    /// question about itself and answer with a number, `cap_publish` hands a call's worth of them
1256    /// to a callee, `cap_yield` leaves one where the caller of this function will look for it, and
1257    /// `cap_clear` takes no operands because saying there is no frame is not a statement about any
1258    /// capability. The reason this is a question about the opcode rather than
1259    /// about the result type is that the verifier asks it the other way round: it walks the results
1260    /// looking for a `cap` and needs to know whether the instruction under it was entitled to make
1261    /// one.
1262    #[must_use]
1263    pub const fn makes_capability(self) -> bool {
1264        matches!(
1265            self,
1266            Self::CapOf
1267                | Self::CapLoad
1268                | Self::CapNull
1269                | Self::CapNarrow
1270                | Self::CapRecover
1271                | Self::CapArg
1272                | Self::CapResult
1273        )
1274    }
1275
1276    /// Which operand of a capability producer names the pointer the capability is about.
1277    ///
1278    /// Five of the seven [`Opcode::makes_capability`] lists, and they all mean the same thing by it:
1279    /// the capability describes the object that pointer is in. Where they differ is only in how the
1280    /// answer was arrived at, which is a walk of the lifetime plane for `cap_recover`, a read of the
1281    /// slot beside the word for `cap_load`, a read of the caller's frame for `cap_arg`, a read of
1282    /// the frame the caller published for `cap_result`, and whatever the back end has at hand for
1283    /// `cap_of`.
1284    ///
1285    /// That is worth stating as one question because the optimizer asks it. A rule that discharges a
1286    /// check by knowing which pointer the check's capability is about has no business caring which
1287    /// producer supplied it, and while `cap_of` was the only one anything emitted, asking for the
1288    /// opcode by name and taking operand zero was the same question. It stopped being the same
1289    /// question when tamnd/rucc#1241 started emitting the cheap producers, and a rule that still
1290    /// asked by name would quietly discharge less the better the code got.
1291    ///
1292    /// The two that answer nothing are the two that are not about a pointer at all. A `cap_narrow`
1293    /// is about another capability and a `cap_null` is about nothing by construction.
1294    ///
1295    /// `cap_result` was in that group and did not belong there. The reasoning was that it is about a
1296    /// pointer the callee returned, which sounds like a value this function has only as the call's
1297    /// own result, and the opcode carries that pointer as operand zero for the same reason
1298    /// `cap_arg` carries one: a callee that wrote nothing leaves the bottom capability in the slot,
1299    /// and the pointer is what the runtime falls back to working the answer out from. So the
1300    /// operand was there the whole time and this said there was none. It is the same mistake the
1301    /// paragraph above is about, made once more in the place that exists to stop it, which is
1302    /// exactly how much care this question wants: every producer that names a pointer has to be
1303    /// here, and the way to tell is to read the opcode's operands rather than its purpose.
1304    #[must_use]
1305    pub const fn capability_names(self) -> Option<usize> {
1306        match self {
1307            Self::CapOf | Self::CapRecover | Self::CapArg | Self::CapResult => Some(0),
1308            // The third, because the first two are the container's capability and the address of
1309            // the word, and the pointer this one is about is the value that came out of the word.
1310            Self::CapLoad => Some(2),
1311            _ => None,
1312        }
1313    }
1314
1315    /// Which payload an instruction with this opcode carries.
1316    ///
1317    /// The printer reads the payload it finds and does not need this. The parser has only the
1318    /// opcode when it reaches the operands, so this is where the two of them agree on what
1319    /// comes after them. An instruction carrying a payload of some other kind prints as text
1320    /// the parser cannot read back, which is why the verifier checks it against
1321    /// [`Extra::kind`](crate::Extra::kind) rather than leaving it to be found later.
1322    #[must_use]
1323    pub const fn extra_kind(self) -> ExtraKind {
1324        match self {
1325            Self::IConst | Self::FConst | Self::Splat => ExtraKind::Imm,
1326            Self::GlobalAddr | Self::TargetIntrinsic | Self::RegisterValue => ExtraKind::Symbol,
1327            Self::ICmp => ExtraKind::IntPred,
1328            Self::FCmp => ExtraKind::FloatPred,
1329            Self::Alloca
1330            | Self::Load
1331            | Self::Store
1332            | Self::Memcpy
1333            | Self::Memmove
1334            | Self::Memset
1335            | Self::AtomicLoad
1336            | Self::AtomicStore
1337            | Self::Cmpxchg
1338            // Four of the checks are about a run of bytes and the payload is where the size
1339            // of that run is, along with the alignment `check_bounds` wants and the aliasing
1340            // node `check_type` compares against. The other two ask a question about a
1341            // pointer and not about a range, so they carry nothing.
1342            | Self::CheckBounds
1343            | Self::CheckType
1344            | Self::CheckInit
1345            | Self::CheckRace
1346            // The two `restrict` checks and the marker that opens their scope. The first two carry
1347            // the size of the access and the two numbers saying which pointer it went through, and
1348            // the third carries the size of the slot and the numbers describing the scope itself.
1349            | Self::CheckRestrictRead
1350            | Self::CheckRestrictWrite
1351            | Self::RestrictEnter => ExtraKind::Mem,
1352            // The plane writes. What each one needs beyond the range is different, and the range
1353            // itself is operands, since the length of a variable length array is a value.
1354            Self::MetaBegin => ExtraKind::Class,
1355            Self::MetaTransfer => ExtraKind::Owner,
1356            Self::MetaType => ExtraKind::Node,
1357            Self::SafeRegionBegin => ExtraKind::Reason,
1358            Self::VaObject => ExtraKind::VaObject,
1359            Self::AtomicRmw => ExtraKind::Rmw,
1360            Self::Fence => ExtraKind::Order,
1361            Self::Prefetch => ExtraKind::Prefetch,
1362            Self::ObjectSize => ExtraKind::Question,
1363            // How far up the chain of frames to walk, which is a number written in the instruction
1364            // and never a value. The builtins these came from take a constant and nothing else, for
1365            // the reason `prefetch` takes one: the instructions this becomes are a walk of that
1366            // length, and a length not known until the program runs has nothing to walk.
1367            Self::FrameAddress | Self::ReturnAddress => ExtraKind::Depth,
1368            Self::Jump | Self::BrIf | Self::BlockAddr | Self::IndirectBr => ExtraKind::Targets,
1369            Self::Switch => ExtraKind::Switch,
1370            Self::Call | Self::CallIndirect | Self::TailCall => ExtraKind::Call,
1371            Self::InlineAsm => ExtraKind::Asm,
1372            _ => ExtraKind::None,
1373        }
1374    }
1375}
1376
1377/// Which of [`Extra`](crate::Extra)'s shapes an instruction carries.
1378///
1379/// The same list of names, without any of the payloads, so that a question about an opcode can
1380/// be answered without an instruction to look at.
1381#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
1382pub enum ExtraKind {
1383    /// Nothing.
1384    None,
1385    /// A constant.
1386    Imm,
1387    /// A name.
1388    Symbol,
1389    /// An integer comparison predicate.
1390    IntPred,
1391    /// A floating point comparison predicate.
1392    FloatPred,
1393    /// An access.
1394    Mem,
1395    /// An atomic read-modify-write.
1396    Rmw,
1397    /// A barrier's ordering.
1398    Order,
1399    /// What a prefetch is a hint about.
1400    Prefetch,
1401    /// How many frames up to walk.
1402    Depth,
1403    /// Which of the four object size questions.
1404    Question,
1405    /// Branch targets.
1406    Targets,
1407    /// A call.
1408    Call,
1409    /// A `switch`.
1410    Switch,
1411    /// Inline assembly.
1412    Asm,
1413    /// An object read off a variable argument list.
1414    VaObject,
1415    /// What kind of storage an instance is.
1416    Class,
1417    /// Who a range of memory went to.
1418    Owner,
1419    /// A metadata node.
1420    Node,
1421    /// Why a declared exemption is there.
1422    Reason,
1423}
1424
1425impl ExtraKind {
1426    /// What it is, in words, for a message that names two of them and has to read as English.
1427    #[must_use]
1428    pub const fn name(self) -> &'static str {
1429        match self {
1430            Self::None => "nothing",
1431            Self::Imm => "a constant",
1432            Self::Symbol => "a name",
1433            Self::IntPred => "an integer comparison",
1434            Self::FloatPred => "a floating point comparison",
1435            Self::Mem => "an access",
1436            Self::Rmw => "a read-modify-write",
1437            Self::Order => "an ordering",
1438            Self::Prefetch => "a prefetch hint",
1439            Self::Depth => "a depth",
1440            Self::Question => "an object size question",
1441            Self::Targets => "branch targets",
1442            Self::Call => "a call",
1443            Self::Switch => "a switch",
1444            Self::Asm => "inline assembly",
1445            Self::VaObject => "an object off a variable argument list",
1446            Self::Class => "a storage class",
1447            Self::Owner => "an owner",
1448            Self::Node => "a metadata node",
1449            Self::Reason => "a reason",
1450        }
1451    }
1452}
1453
1454impl fmt::Display for Opcode {
1455    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1456        f.write_str(self.name())
1457    }
1458}
1459
1460/// Every opcode, which is what [`Opcode::all`] hands out.
1461///
1462/// This is written out rather than derived, and the test below is what keeps it complete: it
1463/// checks the count against [`Opcode::InlineAsm`], the last variant, so a new opcode that is
1464/// not added here fails the build rather than going quietly missing from the parser.
1465static ALL: &[Opcode] = &[
1466    Opcode::IConst,
1467    Opcode::FConst,
1468    Opcode::Splat,
1469    Opcode::GlobalAddr,
1470    Opcode::BlockAddr,
1471    Opcode::Add,
1472    Opcode::Sub,
1473    Opcode::Mul,
1474    Opcode::SDiv,
1475    Opcode::UDiv,
1476    Opcode::SRem,
1477    Opcode::URem,
1478    Opcode::UMulHigh,
1479    Opcode::SMulHigh,
1480    Opcode::And,
1481    Opcode::Or,
1482    Opcode::Xor,
1483    Opcode::Shl,
1484    Opcode::LShr,
1485    Opcode::AShr,
1486    Opcode::FAdd,
1487    Opcode::FSub,
1488    Opcode::FMul,
1489    Opcode::FDiv,
1490    Opcode::FRem,
1491    Opcode::FNeg,
1492    Opcode::Fma,
1493    Opcode::ICmp,
1494    Opcode::FCmp,
1495    Opcode::Select,
1496    Opcode::Trunc,
1497    Opcode::SExt,
1498    Opcode::ZExt,
1499    Opcode::FPTrunc,
1500    Opcode::FPExt,
1501    Opcode::FPToSI,
1502    Opcode::FPToUI,
1503    Opcode::SIToFP,
1504    Opcode::UIToFP,
1505    Opcode::PtrToInt,
1506    Opcode::IntToPtr,
1507    Opcode::Bitcast,
1508    Opcode::MemEntry,
1509    Opcode::Alloca,
1510    Opcode::Load,
1511    Opcode::Store,
1512    Opcode::PtrAdd,
1513    Opcode::Memcpy,
1514    Opcode::Memmove,
1515    Opcode::Memset,
1516    Opcode::AtomicLoad,
1517    Opcode::AtomicStore,
1518    Opcode::AtomicRmw,
1519    Opcode::Cmpxchg,
1520    Opcode::Fence,
1521    Opcode::CapOf,
1522    Opcode::CapLoad,
1523    Opcode::CapStore,
1524    Opcode::CapCopy,
1525    Opcode::CapNull,
1526    Opcode::CapNarrow,
1527    Opcode::CapRecover,
1528    Opcode::CapExtent,
1529    Opcode::CapExtentBack,
1530    Opcode::CapPublish,
1531    Opcode::CapClear,
1532    Opcode::CapArg,
1533    Opcode::CapYield,
1534    Opcode::CapResult,
1535    Opcode::CheckBounds,
1536    Opcode::CheckLive,
1537    Opcode::CheckType,
1538    Opcode::CheckInit,
1539    Opcode::CheckDeriv,
1540    Opcode::CheckRace,
1541    Opcode::CheckRestrictRead,
1542    Opcode::CheckRestrictWrite,
1543    Opcode::CheckFree,
1544    Opcode::MetaBegin,
1545    Opcode::MetaEnd,
1546    Opcode::MetaType,
1547    Opcode::MetaTypeCopy,
1548    Opcode::MetaInit,
1549    Opcode::MetaInitCopy,
1550    Opcode::MetaEpoch,
1551    Opcode::MetaRelease,
1552    Opcode::MetaAcquire,
1553    Opcode::MetaFenceRelease,
1554    Opcode::MetaFenceAcquire,
1555    Opcode::MetaTransfer,
1556    Opcode::SafeRegionBegin,
1557    Opcode::SafeRegionEnd,
1558    Opcode::RestrictEnter,
1559    Opcode::RestrictLeave,
1560    Opcode::Jump,
1561    Opcode::BrIf,
1562    Opcode::Switch,
1563    Opcode::IndirectBr,
1564    Opcode::Return,
1565    Opcode::Unreachable,
1566    Opcode::Call,
1567    Opcode::CallIndirect,
1568    Opcode::TailCall,
1569    Opcode::Ctlz,
1570    Opcode::Cttz,
1571    Opcode::Ctpop,
1572    Opcode::Bswap,
1573    Opcode::Bitreverse,
1574    Opcode::SAddOverflow,
1575    Opcode::UAddOverflow,
1576    Opcode::SSubOverflow,
1577    Opcode::USubOverflow,
1578    Opcode::SMulOverflow,
1579    Opcode::UMulOverflow,
1580    Opcode::Expect,
1581    Opcode::UnreachableHint,
1582    Opcode::Trap,
1583    Opcode::Prefetch,
1584    Opcode::FrameAddress,
1585    Opcode::ReturnAddress,
1586    Opcode::ThreadPointer,
1587    Opcode::ApplyArgs,
1588    Opcode::Apply,
1589    Opcode::ObjectSize,
1590    Opcode::IsConstant,
1591    Opcode::VaArgPack,
1592    Opcode::VaArgPackLen,
1593    Opcode::RegisterValue,
1594    Opcode::VaStart,
1595    Opcode::VaArg,
1596    Opcode::VaObject,
1597    Opcode::VaEnd,
1598    Opcode::VaCopy,
1599    Opcode::StackSave,
1600    Opcode::StackRestore,
1601    Opcode::SetjmpMarker,
1602    Opcode::LongjmpMarker,
1603    Opcode::Unwound,
1604    Opcode::Landing,
1605    Opcode::TargetIntrinsic,
1606    Opcode::InlineAsm,
1607];
1608
1609/// The ten integer comparisons.
1610///
1611/// Signedness is on the predicate rather than on the type, for the same reason it is on
1612/// `sdiv` and `udiv`: the type space is halved and the operation says what it means.
1613#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
1614pub enum IntPred {
1615    /// Equal.
1616    Eq,
1617    /// Not equal.
1618    Ne,
1619    /// Signed less than.
1620    Slt,
1621    /// Signed less than or equal.
1622    Sle,
1623    /// Signed greater than.
1624    Sgt,
1625    /// Signed greater than or equal.
1626    Sge,
1627    /// Unsigned less than.
1628    Ult,
1629    /// Unsigned less than or equal.
1630    Ule,
1631    /// Unsigned greater than.
1632    Ugt,
1633    /// Unsigned greater than or equal.
1634    Uge,
1635}
1636
1637impl IntPred {
1638    /// The textual form.
1639    #[must_use]
1640    pub const fn name(self) -> &'static str {
1641        match self {
1642            Self::Eq => "eq",
1643            Self::Ne => "ne",
1644            Self::Slt => "slt",
1645            Self::Sle => "sle",
1646            Self::Sgt => "sgt",
1647            Self::Sge => "sge",
1648            Self::Ult => "ult",
1649            Self::Ule => "ule",
1650            Self::Ugt => "ugt",
1651            Self::Uge => "uge",
1652        }
1653    }
1654
1655    /// The predicate with that name, if there is one.
1656    #[must_use]
1657    pub fn from_name(name: &str) -> Option<Self> {
1658        Self::all().find(|pred| pred.name() == name)
1659    }
1660
1661    /// Every predicate.
1662    pub fn all() -> impl Iterator<Item = Self> {
1663        [
1664            Self::Eq,
1665            Self::Ne,
1666            Self::Slt,
1667            Self::Sle,
1668            Self::Sgt,
1669            Self::Sge,
1670            Self::Ult,
1671            Self::Ule,
1672            Self::Ugt,
1673            Self::Uge,
1674        ]
1675        .into_iter()
1676    }
1677
1678    /// The predicate that holds exactly when this one does not.
1679    #[must_use]
1680    pub const fn inverse(self) -> Self {
1681        match self {
1682            Self::Eq => Self::Ne,
1683            Self::Ne => Self::Eq,
1684            Self::Slt => Self::Sge,
1685            Self::Sge => Self::Slt,
1686            Self::Sle => Self::Sgt,
1687            Self::Sgt => Self::Sle,
1688            Self::Ult => Self::Uge,
1689            Self::Uge => Self::Ult,
1690            Self::Ule => Self::Ugt,
1691            Self::Ugt => Self::Ule,
1692        }
1693    }
1694
1695    /// The predicate that holds when the operands are given the other way round.
1696    #[must_use]
1697    pub const fn swapped(self) -> Self {
1698        match self {
1699            Self::Eq => Self::Eq,
1700            Self::Ne => Self::Ne,
1701            Self::Slt => Self::Sgt,
1702            Self::Sgt => Self::Slt,
1703            Self::Sle => Self::Sge,
1704            Self::Sge => Self::Sle,
1705            Self::Ult => Self::Ugt,
1706            Self::Ugt => Self::Ult,
1707            Self::Ule => Self::Uge,
1708            Self::Uge => Self::Ule,
1709        }
1710    }
1711
1712    /// Whether this reads its operands as signed. Equality reads them as neither.
1713    #[must_use]
1714    pub const fn is_signed(self) -> bool {
1715        matches!(self, Self::Slt | Self::Sle | Self::Sgt | Self::Sge)
1716    }
1717
1718    /// The predicate that asks the same question with the bits read as unsigned.
1719    ///
1720    /// Each ordering has a counterpart the other way round and equality is the same question at
1721    /// both readings, so every predicate has one and nothing here is a refusal. What it is for is
1722    /// operands known not to be negative: the two readings agree on those, so a signed comparison
1723    /// of two of them is the unsigned comparison of them, and the unsigned one is the one that
1724    /// still holds when the same values are looked at in fewer bits.
1725    #[must_use]
1726    pub const fn unsigned(self) -> Self {
1727        match self {
1728            Self::Slt => Self::Ult,
1729            Self::Sle => Self::Ule,
1730            Self::Sgt => Self::Ugt,
1731            Self::Sge => Self::Uge,
1732            other => other,
1733        }
1734    }
1735}
1736
1737impl fmt::Display for IntPred {
1738    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1739        f.write_str(self.name())
1740    }
1741}
1742
1743/// The floating point comparisons, ordered and unordered.
1744///
1745/// An ordered predicate is false if either operand is a NaN, and an unordered one is true. C's
1746/// `<` is `olt` and C's `!=` is `une`, which is the whole of why both families are here.
1747#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
1748pub enum FloatPred {
1749    /// Always false.
1750    False,
1751    /// Ordered and equal.
1752    Oeq,
1753    /// Ordered and greater than.
1754    Ogt,
1755    /// Ordered and greater than or equal.
1756    Oge,
1757    /// Ordered and less than.
1758    Olt,
1759    /// Ordered and less than or equal.
1760    Ole,
1761    /// Ordered and not equal.
1762    One,
1763    /// Ordered, which is to say neither operand is a NaN.
1764    Ord,
1765    /// Unordered, which is to say one of them is.
1766    Uno,
1767    /// Unordered or equal.
1768    Ueq,
1769    /// Unordered or greater than.
1770    Ugt,
1771    /// Unordered or greater than or equal.
1772    Uge,
1773    /// Unordered or less than.
1774    Ult,
1775    /// Unordered or less than or equal.
1776    Ule,
1777    /// Unordered or not equal.
1778    Une,
1779    /// Always true.
1780    True,
1781}
1782
1783impl FloatPred {
1784    /// The textual form.
1785    #[must_use]
1786    pub const fn name(self) -> &'static str {
1787        match self {
1788            Self::False => "false",
1789            Self::Oeq => "oeq",
1790            Self::Ogt => "ogt",
1791            Self::Oge => "oge",
1792            Self::Olt => "olt",
1793            Self::Ole => "ole",
1794            Self::One => "one",
1795            Self::Ord => "ord",
1796            Self::Uno => "uno",
1797            Self::Ueq => "ueq",
1798            Self::Ugt => "ugt",
1799            Self::Uge => "uge",
1800            Self::Ult => "ult",
1801            Self::Ule => "ule",
1802            Self::Une => "une",
1803            Self::True => "true",
1804        }
1805    }
1806
1807    /// The predicate with that name, if there is one.
1808    #[must_use]
1809    pub fn from_name(name: &str) -> Option<Self> {
1810        Self::all().find(|pred| pred.name() == name)
1811    }
1812
1813    /// Every predicate.
1814    pub fn all() -> impl Iterator<Item = Self> {
1815        [
1816            Self::False,
1817            Self::Oeq,
1818            Self::Ogt,
1819            Self::Oge,
1820            Self::Olt,
1821            Self::Ole,
1822            Self::One,
1823            Self::Ord,
1824            Self::Uno,
1825            Self::Ueq,
1826            Self::Ugt,
1827            Self::Uge,
1828            Self::Ult,
1829            Self::Ule,
1830            Self::Une,
1831            Self::True,
1832        ]
1833        .into_iter()
1834    }
1835
1836    /// The predicate that holds exactly when this one does not.
1837    #[must_use]
1838    pub const fn inverse(self) -> Self {
1839        match self {
1840            Self::False => Self::True,
1841            Self::Oeq => Self::Une,
1842            Self::Ogt => Self::Ule,
1843            Self::Oge => Self::Ult,
1844            Self::Olt => Self::Uge,
1845            Self::Ole => Self::Ugt,
1846            Self::One => Self::Ueq,
1847            Self::Ord => Self::Uno,
1848            Self::Uno => Self::Ord,
1849            Self::Ueq => Self::One,
1850            Self::Ugt => Self::Ole,
1851            Self::Uge => Self::Olt,
1852            Self::Ult => Self::Oge,
1853            Self::Ule => Self::Ogt,
1854            Self::Une => Self::Oeq,
1855            Self::True => Self::False,
1856        }
1857    }
1858
1859    /// The predicate that holds when the operands are given the other way round.
1860    #[must_use]
1861    pub const fn swapped(self) -> Self {
1862        match self {
1863            Self::Ogt => Self::Olt,
1864            Self::Olt => Self::Ogt,
1865            Self::Oge => Self::Ole,
1866            Self::Ole => Self::Oge,
1867            Self::Ugt => Self::Ult,
1868            Self::Ult => Self::Ugt,
1869            Self::Uge => Self::Ule,
1870            Self::Ule => Self::Uge,
1871            same => same,
1872        }
1873    }
1874
1875    /// Whether this is false when either operand is a NaN.
1876    ///
1877    /// [`FloatPred::False`] and [`FloatPred::True`] are neither ordered nor unordered, since
1878    /// they do not look at their operands at all, and both answer no here.
1879    #[must_use]
1880    pub const fn is_ordered(self) -> bool {
1881        matches!(
1882            self,
1883            Self::Oeq | Self::Ogt | Self::Oge | Self::Olt | Self::Ole | Self::One | Self::Ord
1884        )
1885    }
1886}
1887
1888impl fmt::Display for FloatPred {
1889    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1890        f.write_str(self.name())
1891    }
1892}
1893
1894#[cfg(test)]
1895mod tests {
1896    use super::*;
1897
1898    #[test]
1899    fn every_opcode_is_in_the_table() {
1900        // `InlineAsm` is the last variant, so its discriminant plus one is how many there are.
1901        // A new opcode declared after it moves this number, and a new opcode declared before
1902        // it and not added to `ALL` moves the length, so either mistake fails here.
1903        assert_eq!(ALL.len(), Opcode::InlineAsm as usize + 1);
1904        for (position, &op) in ALL.iter().enumerate() {
1905            assert_eq!(op as usize, position, "{op} is out of order in ALL");
1906        }
1907    }
1908
1909    #[test]
1910    fn every_opcode_name_is_one_word_the_reader_can_take() {
1911        // The textual form keeps the dot for the type suffix and the flags, so an opcode with a
1912        // dot in it reads back as a shorter opcode with a suffix that is not a type. The safety
1913        // instructions are spelled `cap_of` and not `cap.of` for this reason, and the
1914        // specification says so at `spec/safe-memory/06-instrumentation.md` section 6.2.2.
1915        for opcode in Opcode::all() {
1916            let name = opcode.name();
1917            assert!(!name.is_empty(), "an opcode with no name");
1918            assert!(
1919                name.bytes().all(|b| b.is_ascii_lowercase() || b.is_ascii_digit() || b == b'_'),
1920                "{name} is not one word"
1921            );
1922        }
1923    }
1924
1925    #[test]
1926    fn every_opcode_has_its_own_name_and_finds_it_again() {
1927        let mut names: Vec<&str> = Opcode::all().map(Opcode::name).collect();
1928        let total = names.len();
1929        names.sort_unstable();
1930        names.dedup();
1931        assert_eq!(names.len(), total, "two opcodes share a name");
1932        for op in Opcode::all() {
1933            assert_eq!(Opcode::from_name(op.name()), Some(op));
1934        }
1935        assert_eq!(Opcode::from_name("phi"), None);
1936        assert_eq!(Opcode::from_name("getelementptr"), None);
1937        assert_eq!(Opcode::from_name(""), None);
1938    }
1939
1940    #[test]
1941    fn the_terminators_are_the_ones_control_leaves_by() {
1942        let terminators: Vec<&str> =
1943            Opcode::all().filter(|op| op.is_terminator()).map(Opcode::name).collect();
1944        assert_eq!(
1945            terminators,
1946            ["jump", "br_if", "switch", "indirect_br", "return", "unreachable", "tail_call"]
1947        );
1948    }
1949
1950    #[test]
1951    fn a_terminator_produces_nothing() {
1952        for op in Opcode::all().filter(|op| op.is_terminator()) {
1953            assert_eq!(op.results(), Some(0), "{op}");
1954        }
1955    }
1956
1957    #[test]
1958    fn the_pair_producing_opcodes_are_the_ones_with_a_flag_beside_the_value() {
1959        let pairs: Vec<&str> =
1960            Opcode::all().filter(|op| op.results() == Some(2)).map(Opcode::name).collect();
1961        assert_eq!(
1962            pairs,
1963            [
1964                "cmpxchg",
1965                "sadd_overflow",
1966                "uadd_overflow",
1967                "ssub_overflow",
1968                "usub_overflow",
1969                "smul_overflow",
1970                "umul_overflow"
1971            ]
1972        );
1973    }
1974
1975    #[test]
1976    fn the_capability_instructions_are_the_ones_that_make_a_capability() {
1977        let makers: Vec<Opcode> = Opcode::all().filter(|op| op.makes_capability()).collect();
1978        assert_eq!(
1979            makers,
1980            vec![
1981                Opcode::CapOf,
1982                Opcode::CapLoad,
1983                Opcode::CapNull,
1984                Opcode::CapNarrow,
1985                Opcode::CapRecover,
1986                Opcode::CapArg,
1987                Opcode::CapResult
1988            ]
1989        );
1990        // The other three read a capability rather than making one. `cap_store` writes it out and
1991        // produces nothing at all, and the two extent queries answer with a number.
1992        assert!(!Opcode::CapStore.makes_capability());
1993        assert_eq!(Opcode::CapStore.results(), Some(0));
1994        assert!(!Opcode::CapExtent.makes_capability());
1995        assert_eq!(Opcode::CapExtent.results(), Some(1));
1996        assert!(!Opcode::CapExtentBack.makes_capability());
1997        assert_eq!(Opcode::CapExtentBack.results(), Some(1));
1998        for opcode in makers {
1999            assert_eq!(opcode.results(), Some(1), "{}", opcode.name());
2000        }
2001    }
2002
2003    #[test]
2004    fn a_producer_says_which_of_its_operands_is_the_pointer_it_is_about() {
2005        // Five of the seven, and the one that is not operand zero is the one whose first two
2006        // operands are the container and the word rather than the value that came out of it.
2007        assert_eq!(Opcode::CapOf.capability_names(), Some(0));
2008        assert_eq!(Opcode::CapRecover.capability_names(), Some(0));
2009        assert_eq!(Opcode::CapArg.capability_names(), Some(0));
2010        assert_eq!(Opcode::CapResult.capability_names(), Some(0));
2011        assert_eq!(Opcode::CapLoad.capability_names(), Some(2));
2012
2013        // The two that are about something other than a pointer this function has an operand for.
2014        assert_eq!(Opcode::CapNarrow.capability_names(), None);
2015        assert_eq!(Opcode::CapNull.capability_names(), None);
2016
2017        // Nothing that is not a producer answers, since the question is what a capability describes
2018        // and those have no capability to describe anything with.
2019        assert_eq!(Opcode::CapStore.capability_names(), None);
2020        assert_eq!(Opcode::Load.capability_names(), None);
2021        assert_eq!(Opcode::CheckLive.capability_names(), None);
2022    }
2023
2024    #[test]
2025    fn a_check_reads_the_planes_and_writes_nothing() {
2026        let checks = [
2027            Opcode::CheckBounds,
2028            Opcode::CheckLive,
2029            Opcode::CheckType,
2030            Opcode::CheckInit,
2031            Opcode::CheckDeriv,
2032            Opcode::CheckRace,
2033            Opcode::CheckFree,
2034        ];
2035        for opcode in checks {
2036            let name = opcode.name();
2037            // It traps, so it stays where it was put and nothing deletes it for having no
2038            // result. It reads a plane, so it takes a memory operand. It writes nothing, so
2039            // the access after it reads the version the check was given.
2040            assert!(opcode.has_effects(), "{name}");
2041            assert!(opcode.touches_memory(), "{name}");
2042            assert!(!opcode.writes_memory(), "{name}");
2043            assert_eq!(opcode.results(), Some(0), "{name}");
2044        }
2045    }
2046
2047    #[test]
2048    fn a_restrict_check_writes_memory_because_it_records_what_it_saw() {
2049        // The one place the sentence above does not hold. Every other check reads a plane and
2050        // leaves it alone, so the optimizer may hoist one out of a loop or keep the later of two
2051        // identical ones. These record the range they were asked about into the block's own slot,
2052        // so a check that ran twice saw two accesses and a check that was hoisted saw one, and
2053        // either rewrite changes what the next one answers. Saying they write memory is how the
2054        // memory chain refuses both.
2055        let recording = [
2056            Opcode::CheckRestrictRead,
2057            Opcode::CheckRestrictWrite,
2058            Opcode::RestrictEnter,
2059            Opcode::RestrictLeave,
2060        ];
2061        for opcode in recording {
2062            let name = opcode.name();
2063            assert!(opcode.has_effects(), "{name}");
2064            assert!(opcode.touches_memory(), "{name}");
2065            assert!(opcode.writes_memory(), "{name}");
2066            assert_eq!(opcode.results(), Some(0), "{name}");
2067        }
2068    }
2069
2070    #[test]
2071    fn the_capability_instructions_that_touch_memory_are_the_five_that_have_to() {
2072        // `cap_load` and `cap_store` are an access to the slot beside a pointer, and `cap_recover`
2073        // and the two extent queries read the planes. The other three are arithmetic on a
2074        // provenance the program already had, so the optimizer may treat them as it treats
2075        // `ptr_add`.
2076        assert!(!Opcode::CapOf.has_effects());
2077        assert!(!Opcode::CapNull.has_effects());
2078        assert!(!Opcode::CapNarrow.has_effects());
2079        assert!(Opcode::CapLoad.touches_memory() && !Opcode::CapLoad.writes_memory());
2080        assert!(Opcode::CapRecover.touches_memory() && !Opcode::CapRecover.writes_memory());
2081        assert!(Opcode::CapExtent.touches_memory() && !Opcode::CapExtent.writes_memory());
2082        assert!(Opcode::CapExtentBack.touches_memory() && !Opcode::CapExtentBack.writes_memory());
2083        assert!(Opcode::CapStore.writes_memory());
2084    }
2085
2086    #[test]
2087    fn what_only_touches_a_plane_touches_memory_and_is_not_an_access() {
2088        // Two halves. Everything in the list is on the memory chain, because an instruction the
2089        // chain does not carry is one the walk never sees and saying anything about it would be
2090        // saying it about nothing. And everything in the list comes from the safety lowering,
2091        // because the planes are the lowering's own storage and an opcode from somewhere else
2092        // claiming to touch only them is the claim being made about the wrong memory.
2093        for opcode in Opcode::all() {
2094            if !opcode.touches_only_planes() {
2095                continue;
2096            }
2097            let name = opcode.name();
2098            assert!(opcode.touches_memory(), "{name}");
2099            let instrumentation = name.starts_with("check_")
2100                || name.starts_with("meta_")
2101                || name.starts_with("cap_extent")
2102                || name == "cap_copy";
2103            assert!(instrumentation, "{name}");
2104        }
2105        for opcode in [Opcode::MetaInit, Opcode::MetaType, Opcode::CheckBounds, Opcode::CapExtent] {
2106            assert!(opcode.touches_only_planes(), "{opcode}");
2107        }
2108    }
2109
2110    #[test]
2111    fn what_goes_through_a_frame_slot_is_not_a_plane_access() {
2112        // What the list leaves out on purpose. The three capability instructions here each take a
2113        // pointer that is not a locator, since a pointer written into a slot is one a later
2114        // instruction reads back out, and the `restrict` markers write their record into the
2115        // block's own slot. The synchronization edges are left out for a different reason, which is
2116        // that they say something about the ordering of program memory and not only about a plane.
2117        let outside = [
2118            Opcode::CapLoad,
2119            Opcode::CapStore,
2120            Opcode::CapRecover,
2121            Opcode::CheckRestrictRead,
2122            Opcode::CheckRestrictWrite,
2123            Opcode::RestrictEnter,
2124            Opcode::RestrictLeave,
2125            Opcode::MetaRelease,
2126            Opcode::MetaAcquire,
2127            Opcode::MetaFenceRelease,
2128            Opcode::MetaFenceAcquire,
2129        ];
2130        for opcode in outside {
2131            assert!(!opcode.touches_only_planes(), "{opcode}");
2132        }
2133        // And nothing ordinary is in it either, since a store answering yes would be the whole
2134        // optimizer told that program memory is unreachable.
2135        for opcode in [Opcode::Load, Opcode::Store, Opcode::Call, Opcode::Memcpy, Opcode::Fence] {
2136            assert!(!opcode.touches_only_planes(), "{opcode}");
2137        }
2138    }
2139
2140    #[test]
2141    fn memory_has_effects_and_arithmetic_does_not() {
2142        for op in [Opcode::Load, Opcode::Store, Opcode::Call, Opcode::Alloca, Opcode::Fence] {
2143            assert!(op.has_effects(), "{op}");
2144        }
2145        for op in [Opcode::Add, Opcode::FDiv, Opcode::ICmp, Opcode::PtrAdd, Opcode::IConst] {
2146            assert!(!op.has_effects(), "{op}");
2147        }
2148    }
2149
2150    #[test]
2151    fn commuting_is_only_claimed_where_it_holds() {
2152        assert!(Opcode::Add.is_commutative());
2153        assert!(Opcode::FAdd.is_commutative());
2154        assert!(!Opcode::Sub.is_commutative());
2155        assert!(!Opcode::FDiv.is_commutative());
2156        assert!(!Opcode::Shl.is_commutative());
2157    }
2158
2159    #[test]
2160    fn an_integer_predicate_inverts_and_swaps_back_to_itself() {
2161        for pred in IntPred::all() {
2162            assert_eq!(pred.inverse().inverse(), pred);
2163            assert_eq!(pred.swapped().swapped(), pred);
2164            assert_eq!(IntPred::from_name(pred.name()), Some(pred));
2165        }
2166        assert_eq!(IntPred::Slt.inverse(), IntPred::Sge);
2167        assert_eq!(IntPred::Slt.swapped(), IntPred::Sgt);
2168        assert_eq!(IntPred::from_name("lt"), None);
2169    }
2170
2171    #[test]
2172    fn an_integer_predicate_has_an_unsigned_counterpart_that_asks_the_same_way_round() {
2173        for pred in IntPred::all() {
2174            let unsigned = pred.unsigned();
2175            assert!(!unsigned.is_signed(), "{pred}");
2176            assert_eq!(unsigned.unsigned(), unsigned, "{pred}");
2177            // The same way round, so inverting or swapping either first gives the same answer.
2178            assert_eq!(pred.inverse().unsigned(), unsigned.inverse(), "{pred}");
2179            assert_eq!(pred.swapped().unsigned(), unsigned.swapped(), "{pred}");
2180        }
2181        assert_eq!(IntPred::Slt.unsigned(), IntPred::Ult);
2182        assert_eq!(IntPred::Sge.unsigned(), IntPred::Uge);
2183        // Equality is the same question at both readings, so it is already its own counterpart.
2184        assert_eq!(IntPred::Eq.unsigned(), IntPred::Eq);
2185        assert_eq!(IntPred::Ne.unsigned(), IntPred::Ne);
2186    }
2187
2188    #[test]
2189    fn a_floating_predicate_inverts_across_the_ordered_line() {
2190        for pred in FloatPred::all() {
2191            assert_eq!(pred.inverse().inverse(), pred);
2192            assert_eq!(pred.swapped().swapped(), pred);
2193            assert_eq!(FloatPred::from_name(pred.name()), Some(pred));
2194        }
2195        // Inverting has to cross the line, because the negation of an ordered comparison is
2196        // true when an operand is a NaN. This is where `!(a < b)` stops being `a >= b`. The
2197        // two constants are outside it: neither of them looks at its operands.
2198        for pred in FloatPred::all().filter(|p| !matches!(p, FloatPred::False | FloatPred::True)) {
2199            assert_ne!(pred.is_ordered(), pred.inverse().is_ordered(), "{pred}");
2200        }
2201        assert_eq!(FloatPred::Olt.inverse(), FloatPred::Uge);
2202        assert_eq!(FloatPred::Olt.swapped(), FloatPred::Ogt);
2203    }
2204
2205    #[test]
2206    fn swapping_a_predicate_keeps_it_ordered_or_unordered() {
2207        for pred in FloatPred::all() {
2208            assert_eq!(pred.is_ordered(), pred.swapped().is_ordered(), "{pred}");
2209        }
2210        for pred in IntPred::all() {
2211            assert_eq!(pred.is_signed(), pred.swapped().is_signed(), "{pred}");
2212        }
2213    }
2214
2215    #[test]
2216    fn no_two_predicates_share_a_name_within_their_family() {
2217        for names in [
2218            IntPred::all().map(IntPred::name).collect::<Vec<_>>(),
2219            FloatPred::all().map(FloatPred::name).collect::<Vec<_>>(),
2220        ] {
2221            let total = names.len();
2222            let mut names = names;
2223            names.sort_unstable();
2224            names.dedup();
2225            assert_eq!(names.len(), total);
2226        }
2227    }
2228}