pub struct CallRegs {Show 27 fields
pub abi: &'static AbiDescription,
pub int_class: RegClass,
pub sse_class: RegClass,
pub int_args: &'static [PhysReg],
pub sse_args: &'static [PhysReg],
pub shared_positions: bool,
pub int_returns: &'static [PhysReg],
pub sse_returns: &'static [PhysReg],
pub x87_returns: &'static [PhysReg],
pub int_saved: &'static [PhysReg],
pub sse_saved: &'static [PhysReg],
pub int_order: &'static [PhysReg],
pub sse_order: &'static [PhysReg],
pub stack_pointer: PhysReg,
pub frame_pointer: PhysReg,
pub late_frame_pointer: bool,
pub vector_count: Option<PhysReg>,
pub red_zone: u32,
pub shadow: u32,
pub stack_align: u32,
pub return_address: u32,
pub word: u32,
pub dwarf: &'static [&'static [u16]],
pub dwarf_return_address: u16,
pub guard: Option<Guard>,
pub trace: Option<Trace>,
pub chkstk: Option<Chkstk>,
}Expand description
Which registers a calling convention gives which job.
This is the second half of a target description and it is separate from RegFile because
the two do not vary together. x86-64 has one register file and two conventions over it, and
they disagree about nearly everything below: rdi is where the first argument arrives on
SysV and a register a callee has to preserve on Windows, and a Windows caller reserves
thirty two bytes below the call that a SysV caller does not.
The allocation order is here rather than on a class because it is a consequence of what a call clobbers. A value that does not live across a call belongs in a register the callee is free to destroy, because putting it in a preserved one costs a push and a pop in the prologue of whichever function ends up owning it.
Every register named here is a register of the file the same target describes, and each list
is in the order the convention uses them, so the fourth integer argument is int_args[3] and
nothing has to count.
Fields§
§abi: &'static AbiDescriptionThe ABI these registers are the register half of.
The two halves of one convention: this structure says which register a value goes in and
the description says what form it travels in on the way there, and a target that has one
has the other. It is a link rather than a copy of the fact anybody wants, because a back end
pass that writes a call to a runtime routine has to ask the same classification question a
call in the program is asked and there is one place that answers it. A target’s registers and
a target’s ABI are still chosen by two separate matches, one in crate::TargetInfo and one
in rucc_abi::abis::for_target, and the crate’s test that walks every triple asking both is
what holds them together.
int_class: RegClassThe class the general purpose registers named here are in.
A register is a number inside its class, so a list of them says nothing about which registers they are without this. Everything else could get the class from the operand it came off, and a frame cannot, because a saved register is not an operand of anything.
sse_class: RegClassThe class the vector registers named here are in.
int_args: &'static [PhysReg]The general purpose registers integer arguments arrive in, in order.
sse_args: &'static [PhysReg]The vector registers floating point arguments arrive in, in order.
Whether an argument’s position counts against both lists or only against its own is
CallRegs::shared_positions.
Whether an argument’s position counts against both argument lists or only against its own.
False on SysV, which counts each separately, so a double after six integers is still in
xmm0. True on Windows, which counts one position for both, so a double in the third
position is in xmm2 and r8 is skipped.
int_returns: &'static [PhysReg]The general purpose registers an integer return value comes back in.
sse_returns: &'static [PhysReg]The vector registers a floating point return value comes back in.
x87_returns: &'static [PhysReg]The x87 registers a long double comes back in, which is empty on a target whose
long double is a double.
int_saved: &'static [PhysReg]The general purpose registers a call leaves alone, so a value in one survives it.
sse_saved: &'static [PhysReg]The vector registers a call leaves alone, which is none of them on SysV.
int_order: &'static [PhysReg]The general purpose registers the allocator may hand out, in the order it prefers them.
The stack pointer is never in this list, and neither is the frame pointer, which a target could allocate when nothing needs a frame and which nothing here does yet.
sse_order: &'static [PhysReg]The vector registers the allocator may hand out, in the order it prefers them.
stack_pointer: PhysRegThe stack pointer.
frame_pointer: PhysRegThe frame pointer, which is the register a prologue puts the old stack pointer in.
late_frame_pointer: boolWhether the prologue points the frame pointer at the frame after taking it rather than before taking it.
False everywhere but Windows, and there it is the unwind table asking rather than a preference. The record a function carries on that platform counts every slot in it from where the stack pointer ends the prologue, and it finds that place by taking a constant off the frame pointer, so a register pushed after the pointer was established is below the place the record counts from and has no row the format can write. The order that does work is the pushes, then the frame, and only then the pointer, which is what Microsoft’s compiler emits and what gcc emits for this target in every function that saves anything besides the pointer itself.
What it costs is the chain: the frame pointer holds a copy of the body’s stack pointer rather than the address of the caller’s copy of itself, so the words that used to lead from one frame to the next no longer do. Nothing on this platform walks that chain. Unwinding reads the table, there is no profiler’s hook that reads the pointer, and gcc gives the chain up on the same functions for the same reason.
vector_count: Option<PhysReg>Where a variadic call says how many vector registers it passed arguments in, when the convention makes it say.
SysV puts the count in al and a variadic callee reads it to decide whether to save the
vector argument registers at all, which is what makes a call to printf with no
floating point argument cheap.
red_zone: u32How many bytes below the stack pointer a leaf function may use without moving it.
A hundred and twenty eight on SysV and nothing on Windows. It is nothing in kernel code
on either, because an interrupt handler runs on the interrupted stack and writes over
exactly this, which is what -mno-red-zone is for.
shadow: u32How many bytes a caller reserves below the call for the callee to spill its register arguments into, which is thirty two on Windows and nothing on SysV.
stack_align: u32What the stack pointer has to be a multiple of at the instruction that makes a call.
Sixteen on every convention here, and it is a real obligation rather than a preference, because a callee is entitled to use an aligned vector store on its own frame and gets a fault rather than a wrong answer when a caller got this wrong.
return_address: u32How many bytes the call instruction itself pushes before the callee starts running.
Eight on x86-64, where the return address is on the stack, and nothing on a machine that leaves it in a register. It is what makes the stack pointer misaligned on entry by exactly one word, which every frame layout has to undo.
word: u32How many bytes one general purpose register takes when it is saved on the stack.
dwarf: &'static [&'static [u16]]What DWARF calls each register, one list per class in the order the file numbers the classes, and inside a list in the order the class numbers its registers.
The two numberings are a real difference and not a formality. On x86-64 the machine puts
rcx at one and DWARF puts rdx there, so a table written with the machine’s numbers is
well formed and describes the wrong registers, which is a backtrace with plausible
nonsense in it rather than an error. Shorter than the file when the classes at the end are
ones DWARF has no column for, and empty on a target nobody has written this down for yet.
dwarf_return_address: u16The column an unwind table files the return address under.
Not a register on x86-64, where it is sixteen and rip is not a register anything can
name, and a real one on a machine that returns through a link register.
guard: Option<Guard>Where the word a stack protector’s canary is copied from lives, on a convention that has somewhere to put one.
Here rather than beside the frame instructions because it is a fact about the runtime the code is linked against rather than about the machine. The two x86-64 conventions share every instruction the check is made of and disagree about this.
trace: Option<Trace>What a profiler’s hook is called on this platform, on one that has one.
Here for the same reason CallRegs::guard is: the names are the runtime’s rather than the
machine’s, and the two x86-64 conventions write the same call instruction and disagree about
what goes in it.
chkstk: Option<Chkstk>What this platform calls the routine a prologue reaches the pages of a large frame with, on one where reaching them is the convention.
Here for the same reason the two above are, and it is the clearest case of the three: the walk itself is written out of the machine’s own instructions and both x86-64 conventions have them, and what the two disagree about is whether a frame may be taken in one step at all. A prologue that leaves this out on Windows writes a function that faults on its own locals.
Implementations§
Source§impl CallRegs
impl CallRegs
Sourcepub fn dwarf(&self, class: RegClass, reg: PhysReg) -> Option<u16>
pub fn dwarf(&self, class: RegClass, reg: PhysReg) -> Option<u16>
The number DWARF gives that register, or None for one it has no column for.
The x87 stack is the case that answers None on x86-64, and it is not an omission: a
register whose name means whichever one is on top of the stack is not one a table can have
a column for. Nothing saves one across a call either, so nothing ever asks.
Sourcepub fn machine(&self, class: RegClass, dwarf: u16) -> Option<PhysReg>
pub fn machine(&self, class: RegClass, dwarf: u16) -> Option<PhysReg>
Which register of that class DWARF gave that number to, which is Self::dwarf the other
way round, and None for a number no register of the class holds.
What asks is a table written in the machine’s own numbering rather than DWARF’s, which is what Windows unwinds from. A row a prologue produces carries DWARF’s number, because that is what the format two of the three platforms want is written in, and the machine’s number is this register’s place in its class. The two disagree over the first eight general purpose registers on x86-64 and nowhere else, which is the worst shape a disagreement can have: every number is a register either way, so the table comes out well formed and about the wrong registers.
Sourcepub fn preserves_int(&self, reg: PhysReg) -> bool
pub fn preserves_int(&self, reg: PhysReg) -> bool
Whether a call preserves that general purpose register.
Sourcepub fn preserves_sse(&self, reg: PhysReg) -> bool
pub fn preserves_sse(&self, reg: PhysReg) -> bool
Whether a call preserves that vector register.