pub struct FrameInsts {Show 21 fields
pub prefix: &'static str,
pub classes: &'static [ClassMoves],
pub push: &'static str,
pub pop: &'static str,
pub pair: Option<Pair>,
pub add: &'static str,
pub sub: &'static str,
pub grow: &'static str,
pub align: &'static str,
pub imm: &'static str,
pub lea: &'static str,
pub sum: &'static str,
pub ret: &'static str,
pub differ: &'static str,
pub above: &'static str,
pub call: &'static str,
pub probe: Option<Probe>,
pub landing: Option<&'static str>,
pub pad: Option<&'static str>,
pub step_bits: Option<u32>,
pub reaches: Option<fn(&str, i32) -> bool>,
}Expand description
Every instruction a prologue, an epilogue, a spill or a reload is made of.
Fields§
§prefix: &'static strWhat a rule file and the machine IR put in front of this target’s opcodes, such as
x64., which says which target a term belongs to and is not part of the opcode.
classes: &'static [ClassMoves]How a register of each class is moved, one for each class of the register file in the order the file numbers them.
Shorter than the file when the classes at the end are ones nothing spills. An x87 stack register is one of those: the allocator is never given one to hand out, so nothing ever asks how to move it, and a target that answered anyway would be writing down a guess.
push: &'static strPuts a register on the stack and moves the stack pointer down by one word.
pop: &'static strTakes a word off the stack into a register and moves the stack pointer back up.
pair: Option<Pair>Pushes two registers at once, or None on a machine that pushes one at a time. See
Pair.
add: &'static strAdds a constant to the stack pointer, which is how an epilogue gives the frame back.
sub: &'static strTakes a constant off the stack pointer, which is how a prologue takes the frame.
grow: &'static strTakes whatever is in a register off the stack pointer, which is how a function makes room for an array whose size it does not know until it runs.
The same shape as Self::sub and different in where the amount comes from, which is the
whole of the difference between the bytes a prologue takes and the bytes a variable length
array takes. A prologue knows its number when it is written and a declaration in the body
does not know it until the expression in the brackets has been worked out.
align: &'static strClears the low bits of the stack pointer, which is how a prologue forces an alignment nothing else can give it.
imm: &'static strWrites a constant into a general purpose register.
The one thing a prologue has to do that is not about the stack pointer, and it is here for
a platform that hands the size of the frame to a routine rather than reaching the pages
itself. See crate::Chkstk. A rule file selects this same opcode for a constant the
program wrote, for the reason the header of a target’s table gives: a prologue writing a
number into a register is the same instruction as an assignment, and the encoder should
not have two answers for it.
lea: &'static strWrites a register with an address rather than with what is at it, which is how an epilogue puts the stack pointer back when the frame pointer is the only record of where it was.
sum: &'static strAdds two general purpose registers at the width of an address.
Not something a prologue writes. It is here because the sum of two registers is the one
address the selector leaves as arithmetic rather than as a lea, and the pass that folds
addresses into their readers has to know which instruction that is to read it as a base and
an index at a scale of one.
ret: &'static strReturns to the caller.
differ: &'static strCompares two general purpose registers and writes whether they differ into a third.
The stack protector’s check is the only thing that asks for this, and it is here rather than left to a lowering rule because no rule ever sees the comparison: the two words being compared are the canary the prologue wrote and the one the runtime still holds, and neither of them is a value the program named.
above: &'static strCompares two general purpose registers as unsigned numbers and writes whether the first is above the second into a third.
Here for the same reason Self::differ is, and asked for by the one loop that walks a
distance nothing knew when it was written, which is the pages a variable length array takes.
A prologue knows how many pages its own frame is and can stop when the stack pointer reaches
an address worked out in advance, so equality is enough for it. A declaration in the body
does not: the bytes arrive in a register, the last step down is a whole page whatever is
left, and the stack pointer lands at or past where it was going rather than on it.
Unsigned because both registers hold addresses. A stack that has grown past the middle of the address space is one where a signed comparison of two stack pointers says the wrong thing, and nothing about a guard page cares which half of the space it is in.
call: &'static strCalls the name it is given and reads no register.
Here for the same reason, and used for the one call an epilogue can make, which is the one a changed canary makes.
probe: Option<Probe>How a prologue touches a page of the stack, or None on a target where nothing can.
See Probe. It is an option rather than a name because a target that has no such
instruction is a target where -fstack-clash-protection has to do nothing, and a name
standing for nothing is worse than an absence a caller has to look at.
landing: Option<&'static str>What says an indirect branch may arrive at an address, or None on a target where nothing
does.
What -fcf-protection=branch asks for, and an option for the same reason Self::probe
is: a target with no such instruction is one the flag cannot be honoured on, and the answer
there is to say so rather than to write a name that stands for nothing. A prologue puts one
at the top of every function, because a function’s own address is the one address of it a
pointer can hold, and one goes at the top of every label a program took the address of,
because a computed goto is an indirect branch and those are the addresses it arrives at.
pad: Option<&'static str>A byte that does nothing, or None on a target where nothing is written for the purpose.
What -fpatchable-function-entry= reserves room with, and an option for the same reason
Self::landing is. The room is counted in bytes, so what is wanted is the shortest
instruction the machine has that does nothing rather than the shortest sequence that adds
up to the length: a patcher writes over the room from its start and wants a whole number of
places it could have started at.
step_bits: Option<u32>How many bits of constant Self::add and Self::sub carry, when a frame can need
more, or None when they carry any size a frame can be.
AArch64’s carry twelve bits, or twelve bits shifted up by twelve, which is the machine’s
whole answer and not a form the encoder has yet to learn. A frame of 4608 bytes is taken as
4096 and then 512, which is what gcc writes, and Self::steps is the rule for that.
reaches: Option<fn(&str, i32) -> bool>Whether the instruction of that name can carry that displacement from the stack pointer or
the frame pointer, or None on a target where every offset a frame has fits.
An AArch64 load reaches 4095 bytes, or that many of its own size, and add carries twelve
bits, so a local more than a few kilobytes into a large frame is out of reach of the one
instruction the lowering wrote for it. What reaches is the encoder’s to say, since it is
the one that refuses, and the finish pass asks it and writes the address into a scratch
register first when the answer is no.
Implementations§
Source§impl FrameInsts
impl FrameInsts
Sourcepub fn steps(&self, bytes: u32) -> Vec<u32>
pub fn steps(&self, bytes: u32) -> Vec<u32>
The amounts one Self::add or Self::sub each moves the stack pointer by, which
together move it by bytes.
One step on a machine whose instruction carries the whole of it. Otherwise the part above the low bits goes first, in steps as large as the shifted form holds, and the low bits last, so a frame under sixteen megabytes on AArch64 is at most two instructions.
Sourcepub fn moves(&self, class: RegClass) -> Option<ClassMoves>
pub fn moves(&self, class: RegClass) -> Option<ClassMoves>
How a register of that class is moved, or None for a class nothing spills.