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