pub struct Flags(/* private fields */);Expand description
The flags on one instruction.
A bitset rather than a struct of bools, because it rides along in the instruction table
and two bytes there is two bytes per instruction in every function in the program.
Implementations§
Source§impl Flags
impl Flags
Sourcepub const NONE: Self
pub const NONE: Self
No flags, which is what -O0 and -fwrapv and a plain unsigned addition all produce.
Sourcepub const NSW: Self
pub const NSW: Self
No signed wrap. Signed overflow is undefined, so the optimizer may assume it does not
happen. -fwrapv stops the frontend setting this and nothing else changes.
Sourcepub const NUW: Self
pub const NUW: Self
No unsigned wrap. Set only where the frontend knows it from the source, since C’s unsigned arithmetic wraps by definition and most unsigned arithmetic does not get this.
Sourcepub const EXACT: Self
pub const EXACT: Self
The shift or division is exact, so no bits are discarded and no remainder is dropped.
Sourcepub const REASSOC: Self
pub const REASSOC: Self
The operation may be reassociated, which is the one that changes results the most.
Sourcepub const VOLATILE: Self
pub const VOLATILE: Self
The access is volatile, so it happens exactly once and is never moved or merged.
Sourcepub const NOALIAS: Self
pub const NOALIAS: Self
The result does not alias anything else reachable, which is what restrict gives.
Sourcepub const NOFREE: Self
pub const NOFREE: Self
Nothing this call reaches ends the lifetime of any storage.
The nofree summary of spec/safe-memory/07-check-elimination.md section 7.5, written onto
the call site by a module-level analysis rather than by the frontend. A pass carrying what
an earlier safety check established keeps it across a call that has this and gives it up
across a call that does not.
Sourcepub const STATIC: Self
pub const STATIC: Self
The bytes this safety check is about lie inside one object of static storage duration whose extent this module knows.
Section 7.2 of spec/safe-memory/07-check-elimination.md puts the frontend first of the
four sources of a discharge, because most accesses in real C are to a local or a global at a
constant offset and how big either one is is not something anybody has to work out. The
local half is read straight off the alloca by the pass that removes the check. The global
half is this flag, because a global’s size lives on the module and a pass is given one
function, so a module-level analysis works it out before the pipeline starts and writes it
onto the check.
A fact rather than a licence, like Flags::NOFREE and unlike everything above it. It
says what is true of the bytes, and whether that is enough for the check to go is a rule.
Sourcepub const HANDED: Self
pub const HANDED: Self
The bytes this safety check is about lie inside one object that every call to this function hands it, and whose extent this module knows.
The same shape as Flags::STATIC and the next of the four sources section 7.2 lists,
which is section 7.5’s summaries. A pointer that arrived as a parameter is a pointer
nothing in the function can say anything about, and it is where most of the checks a real
program keeps are. What can be said about it is said by the callers: if every call to a
function only this module can call passes a frame slot or a global with at least so many
bytes left in it, then the parameter has at least so many bytes wherever it is used.
Worked out over the module before the pipeline starts, for the reason Flags::STATIC
gives: a call site is in a different function from the parameter it is about, and a pass is
given one function.
It says the same two things Flags::STATIC says, an extent and a lifetime, because the
objects it is ever about are a caller’s frame slot or a global and both of those are alive
for as long as the call runs. A fact rather than a licence, in the same way.
Sourcepub const HEAP: Self
pub const HEAP: Self
This call hands back either null or one fresh storage instance of at least as many bytes as its last argument asks for.
The third of the objects whose extent is known without anybody having checked it, after the
two Flags::STATIC and Flags::HANDED are about. malloc(n) states the same fact an
alloca states, with a different instruction stating it, and the null half is why a program
has to test what it gets: a null pointer is inside no object at all, so a bounds check on one
is a check that is supposed to fail.
On the call rather than on the checks, which is the shape Flags::NOFREE has and not the
shape the two flags above have. What has to be worked out before the pipeline starts is only
which function this call names, because resolving a name takes the interner and a pass is
handed a function and no names. Everything else, which is how many bytes and where the
program has tested for null, is read out of the function by the pass that removes the check,
and has to be: before anything has folded, malloc(16) is a call to malloc of a sign
extension of a thirty two bit sixteen.
What it says is an extent, and never a lifetime, which is the difference from the two flags
above. A global and a caller’s frame slot are alive for as long as the call runs, and an
object on the heap is alive until something frees it, which may well be this same function.
So a free between the allocation and the access leaves the lifetime check standing to
report the use after free.
A fact rather than a licence, in the way Flags::NOFREE is.
Sourcepub const ALIGNED: Self
pub const ALIGNED: Self
The address the check this is on is about starts where the access assumes it does.
The alignment conjunct of judgement J1 rides on check_bounds, which
spec/safe-memory/06-instrumentation.md section 6.3 settled, so a check that goes takes the
test of it away with it and crate::discharge will not take one out until something has
answered it. Mostly it answers itself, off the alloca or the allocation the address was
computed from and the steps taken from there. This is the case it cannot: how aligned a
global is lives on the module and a pass is given one function, which is the reason
Flags::STATIC exists and the same reason repeated.
It says the address and not the object. A global aligned to sixteen read four bytes in at a width of four is one of these and the same global read one byte in is not, so what was worked out before the pipeline started is the offset as well as the object.
A fact rather than a licence, in the way Flags::STATIC is.
Sourcepub const fn bits(self) -> u16
pub const fn bits(self) -> u16
The underlying bits, for the printer and for hashing an instruction.
Sourcepub const fn intersection(self, other: Self) -> Self
pub const fn intersection(self, other: Self) -> Self
The flags in both sets.
This is what a rewrite does when it replaces two instructions with one: a licence granted on one of them and not the other is not a licence over the result.
Sourcepub const fn legal_on(opcode: Opcode) -> Self
pub const fn legal_on(opcode: Opcode) -> Self
The flags that mean anything on that opcode.
Anything outside this is a verifier failure rather than something ignored, because a flag on an instruction that does not read it is a flag somebody meant to put somewhere else.
Trait Implementations§
Source§impl BitOrAssign for Flags
impl BitOrAssign for Flags
Source§fn bitor_assign(&mut self, other: Self)
fn bitor_assign(&mut self, other: Self)
|= operation. Read more