Rename "local variables" to "explicit stack slots".
The term "local variables" predated the SSA builder in the front-end crate, which also provides a way to implement source-language local variables. The name "explicit stack slot" makes it clear what this construct is.
This commit is contained in:
@@ -1,7 +1,7 @@
|
|||||||
test verifier
|
test verifier
|
||||||
|
|
||||||
function %average(i32, i32) -> f32 native {
|
function %average(i32, i32) -> f32 native {
|
||||||
ss1 = local 8 ; Stack slot for ``sum``.
|
ss1 = explicit_slot 8 ; Stack slot for ``sum``.
|
||||||
|
|
||||||
ebb1(v1: i32, v2: i32):
|
ebb1(v1: i32, v2: i32):
|
||||||
v3 = f64const 0x0.0
|
v3 = f64const 0x0.0
|
||||||
|
|||||||
@@ -37,7 +37,7 @@ The first line of a function definition provides the function *name* and
|
|||||||
the :term:`function signature` which declares the parameter and return types.
|
the :term:`function signature` which declares the parameter and return types.
|
||||||
Then follows the :term:`function preamble` which declares a number of entities
|
Then follows the :term:`function preamble` which declares a number of entities
|
||||||
that can be referenced inside the function. In the example above, the preamble
|
that can be referenced inside the function. In the example above, the preamble
|
||||||
declares a single local variable, ``ss1``.
|
declares a single explicit stack slot, ``ss1``.
|
||||||
|
|
||||||
After the preamble follows the :term:`function body` which consists of
|
After the preamble follows the :term:`function body` which consists of
|
||||||
:term:`extended basic block`\s (EBBs), the first of which is the
|
:term:`extended basic block`\s (EBBs), the first of which is the
|
||||||
@@ -471,8 +471,8 @@ the expected alignment. By default, misaligned loads and stores are allowed,
|
|||||||
but when the ``aligned`` flag is set, a misaligned memory access is allowed to
|
but when the ``aligned`` flag is set, a misaligned memory access is allowed to
|
||||||
:term:`trap`.
|
:term:`trap`.
|
||||||
|
|
||||||
Local variables
|
Explicit Stack Slots
|
||||||
---------------
|
--------------------
|
||||||
|
|
||||||
One set of restricted memory operations access the current function's stack
|
One set of restricted memory operations access the current function's stack
|
||||||
frame. The stack frame is divided into fixed-size stack slots that are
|
frame. The stack frame is divided into fixed-size stack slots that are
|
||||||
@@ -480,9 +480,9 @@ allocated in the :term:`function preamble`. Stack slots are not typed, they
|
|||||||
simply represent a contiguous sequence of :term:`accessible` bytes in the stack
|
simply represent a contiguous sequence of :term:`accessible` bytes in the stack
|
||||||
frame.
|
frame.
|
||||||
|
|
||||||
.. inst:: SS = local Bytes, Flags...
|
.. inst:: SS = explicit_slot Bytes, Flags...
|
||||||
|
|
||||||
Allocate a stack slot for a local variable in the preamble.
|
Allocate a stack slot in the preamble.
|
||||||
|
|
||||||
If no alignment is specified, Cretonne will pick an appropriate alignment
|
If no alignment is specified, Cretonne will pick an appropriate alignment
|
||||||
for the stack slot based on its size and access patterns.
|
for the stack slot based on its size and access patterns.
|
||||||
@@ -1135,7 +1135,7 @@ Glossary
|
|||||||
A list of declarations of entities that are used by the function body.
|
A list of declarations of entities that are used by the function body.
|
||||||
Some of the entities that can be declared in the preamble are:
|
Some of the entities that can be declared in the preamble are:
|
||||||
|
|
||||||
- Local variables.
|
- Stack slots.
|
||||||
- Functions that are called directly.
|
- Functions that are called directly.
|
||||||
- Function signatures for indirect function calls.
|
- Function signatures for indirect function calls.
|
||||||
- Function flags and attributes that are not part of the signature.
|
- Function flags and attributes that are not part of the signature.
|
||||||
@@ -1158,9 +1158,16 @@ Glossary
|
|||||||
intermediate representation. Cretonne's IR can be converted to text
|
intermediate representation. Cretonne's IR can be converted to text
|
||||||
losslessly.
|
losslessly.
|
||||||
|
|
||||||
stack slot
|
explicit stack slot
|
||||||
A fixed size memory allocation in the current function's activation
|
A fixed size memory allocation in the current function's activation
|
||||||
frame. Also called a local variable.
|
frame. These differ from :term:`spill stack slots` in that they can
|
||||||
|
be created by frontends and they may have their addresses taken.
|
||||||
|
|
||||||
|
spill stack slot
|
||||||
|
A fixed size memory allocation in the current function's activation
|
||||||
|
frame. These differ from :term:`explicit stack slots` in that they are
|
||||||
|
only created during register allocation, and they may not have their
|
||||||
|
address taken.
|
||||||
|
|
||||||
terminator instruction
|
terminator instruction
|
||||||
A control flow instruction that unconditionally directs the flow of
|
A control flow instruction that unconditionally directs the flow of
|
||||||
|
|||||||
@@ -4,13 +4,13 @@ set is_compressed
|
|||||||
isa intel haswell
|
isa intel haswell
|
||||||
|
|
||||||
function %foo() {
|
function %foo() {
|
||||||
ss0 = local 168
|
ss0 = explicit_slot 168
|
||||||
ebb0:
|
ebb0:
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
; check: function %foo(i64 fp [%rbp], i64 csr [%rbx], i64 csr [%r12], i64 csr [%r13], i64 csr [%r14], i64 csr [%r15]) -> i64 fp [%rbp], i64 csr [%rbx], i64 csr [%r12], i64 csr [%r13], i64 csr [%r14], i64 csr [%r15] native {
|
; check: function %foo(i64 fp [%rbp], i64 csr [%rbx], i64 csr [%r12], i64 csr [%r13], i64 csr [%r14], i64 csr [%r15]) -> i64 fp [%rbp], i64 csr [%rbx], i64 csr [%r12], i64 csr [%r13], i64 csr [%r14], i64 csr [%r15] native {
|
||||||
; nextln: ss0 = local 168, offset -224
|
; nextln: ss0 = explicit_slot 168, offset -224
|
||||||
; nextln: ss1 = incoming_arg 56, offset -56
|
; nextln: ss1 = incoming_arg 56, offset -56
|
||||||
; check: ebb0(v0: i64 [%rbp], v1: i64 [%rbx], v2: i64 [%r12], v3: i64 [%r13], v4: i64 [%r14], v5: i64 [%r15]):
|
; check: ebb0(v0: i64 [%rbp], v1: i64 [%rbx], v2: i64 [%r12], v3: i64 [%r13], v4: i64 [%r14], v5: i64 [%r15]):
|
||||||
; nextln: x86_push v0
|
; nextln: x86_push v0
|
||||||
|
|||||||
@@ -124,7 +124,7 @@ ebb0(v90: i32, v91: f32):
|
|||||||
; Stack slot references
|
; Stack slot references
|
||||||
function %stack() {
|
function %stack() {
|
||||||
ss10 = spill_slot 8
|
ss10 = spill_slot 8
|
||||||
ss2 = local 4
|
ss2 = explicit_slot 4
|
||||||
ss3 = incoming_arg 4, offset 8
|
ss3 = incoming_arg 4, offset 8
|
||||||
ss4 = outgoing_arg 4
|
ss4 = outgoing_arg 4
|
||||||
ss5 = emergency_slot 4
|
ss5 = emergency_slot 4
|
||||||
@@ -136,7 +136,7 @@ ebb0:
|
|||||||
stack_store v2, ss2
|
stack_store v2, ss2
|
||||||
}
|
}
|
||||||
; sameln: function %stack() native {
|
; sameln: function %stack() native {
|
||||||
; check: ss2 = local 4
|
; check: ss2 = explicit_slot 4
|
||||||
; check: ss3 = incoming_arg 4, offset 8
|
; check: ss3 = incoming_arg 4, offset 8
|
||||||
; check: ss4 = outgoing_arg 4
|
; check: ss4 = outgoing_arg 4
|
||||||
; check: ss5 = emergency_slot 4
|
; check: ss5 = emergency_slot 4
|
||||||
|
|||||||
@@ -40,9 +40,9 @@ pub enum StackSlotKind {
|
|||||||
/// A spill slot. This is a stack slot created by the register allocator.
|
/// A spill slot. This is a stack slot created by the register allocator.
|
||||||
SpillSlot,
|
SpillSlot,
|
||||||
|
|
||||||
/// A local variable. This is a chunk of local stack memory for use by the `stack_load` and
|
/// An explicit stack slot. This is a chunk of stack memory for use by the `stack_load`
|
||||||
/// `stack_store` instructions.
|
/// and `stack_store` instructions.
|
||||||
Local,
|
ExplicitSlot,
|
||||||
|
|
||||||
/// An incoming function argument.
|
/// An incoming function argument.
|
||||||
///
|
///
|
||||||
@@ -71,7 +71,7 @@ impl FromStr for StackSlotKind {
|
|||||||
fn from_str(s: &str) -> Result<StackSlotKind, ()> {
|
fn from_str(s: &str) -> Result<StackSlotKind, ()> {
|
||||||
use self::StackSlotKind::*;
|
use self::StackSlotKind::*;
|
||||||
match s {
|
match s {
|
||||||
"local" => Ok(Local),
|
"explicit_slot" => Ok(ExplicitSlot),
|
||||||
"spill_slot" => Ok(SpillSlot),
|
"spill_slot" => Ok(SpillSlot),
|
||||||
"incoming_arg" => Ok(IncomingArg),
|
"incoming_arg" => Ok(IncomingArg),
|
||||||
"outgoing_arg" => Ok(OutgoingArg),
|
"outgoing_arg" => Ok(OutgoingArg),
|
||||||
@@ -85,7 +85,7 @@ impl fmt::Display for StackSlotKind {
|
|||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
use self::StackSlotKind::*;
|
use self::StackSlotKind::*;
|
||||||
f.write_str(match *self {
|
f.write_str(match *self {
|
||||||
Local => "local",
|
ExplicitSlot => "explicit_slot",
|
||||||
SpillSlot => "spill_slot",
|
SpillSlot => "spill_slot",
|
||||||
IncomingArg => "incoming_arg",
|
IncomingArg => "incoming_arg",
|
||||||
OutgoingArg => "outgoing_arg",
|
OutgoingArg => "outgoing_arg",
|
||||||
@@ -366,7 +366,7 @@ mod tests {
|
|||||||
assert_eq!(slot.alignment(8), 8);
|
assert_eq!(slot.alignment(8), 8);
|
||||||
assert_eq!(slot.alignment(16), 8);
|
assert_eq!(slot.alignment(16), 8);
|
||||||
|
|
||||||
let slot2 = StackSlotData::new(StackSlotKind::Local, 24);
|
let slot2 = StackSlotData::new(StackSlotKind::ExplicitSlot, 24);
|
||||||
|
|
||||||
assert_eq!(slot2.alignment(4), 4);
|
assert_eq!(slot2.alignment(4), 4);
|
||||||
assert_eq!(slot2.alignment(8), 8);
|
assert_eq!(slot2.alignment(8), 8);
|
||||||
|
|||||||
@@ -7,8 +7,8 @@ use std::cmp::{min, max};
|
|||||||
|
|
||||||
/// Compute the stack frame layout.
|
/// Compute the stack frame layout.
|
||||||
///
|
///
|
||||||
/// Determine the total size of this stack frame and assign offsets to all `Spill` and `Local`
|
/// Determine the total size of this stack frame and assign offsets to all `Spill` and
|
||||||
/// stack slots.
|
/// `Explicit` stack slots.
|
||||||
///
|
///
|
||||||
/// The total frame size will be a multiple of `alignment` which must be a power of two.
|
/// The total frame size will be a multiple of `alignment` which must be a power of two.
|
||||||
///
|
///
|
||||||
@@ -25,7 +25,7 @@ pub fn layout_stack(frame: &mut StackSlots, alignment: StackSize) -> Result<Stac
|
|||||||
// stack layout from high to low addresses will be:
|
// stack layout from high to low addresses will be:
|
||||||
//
|
//
|
||||||
// 1. incoming arguments.
|
// 1. incoming arguments.
|
||||||
// 2. spills + locals.
|
// 2. spills + explicits.
|
||||||
// 3. outgoing arguments.
|
// 3. outgoing arguments.
|
||||||
//
|
//
|
||||||
// The incoming arguments can have both positive and negative offsets. A negative offset
|
// The incoming arguments can have both positive and negative offsets. A negative offset
|
||||||
@@ -57,15 +57,15 @@ pub fn layout_stack(frame: &mut StackSlots, alignment: StackSize) -> Result<Stac
|
|||||||
outgoing_max = max(outgoing_max, offset);
|
outgoing_max = max(outgoing_max, offset);
|
||||||
}
|
}
|
||||||
StackSlotKind::SpillSlot |
|
StackSlotKind::SpillSlot |
|
||||||
StackSlotKind::Local |
|
StackSlotKind::ExplicitSlot |
|
||||||
StackSlotKind::EmergencySlot => {
|
StackSlotKind::EmergencySlot => {
|
||||||
// Determine the smallest alignment of any local or spill slot.
|
// Determine the smallest alignment of any explicit or spill slot.
|
||||||
min_align = slot.alignment(min_align);
|
min_align = slot.alignment(min_align);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Lay out spill slots and locals below the incoming arguments.
|
// Lay out spill slots and explicit slots below the incoming arguments.
|
||||||
// The offset is negative, growing downwards.
|
// The offset is negative, growing downwards.
|
||||||
// Start with the smallest alignments for better packing.
|
// Start with the smallest alignments for better packing.
|
||||||
let mut offset = incoming_min;
|
let mut offset = incoming_min;
|
||||||
@@ -74,9 +74,10 @@ pub fn layout_stack(frame: &mut StackSlots, alignment: StackSize) -> Result<Stac
|
|||||||
for ss in frame.keys() {
|
for ss in frame.keys() {
|
||||||
let slot = frame[ss].clone();
|
let slot = frame[ss].clone();
|
||||||
|
|
||||||
// Pick out locals and spill slots with exact alignment `min_align`.
|
// Pick out explicit and spill slots with exact alignment `min_align`.
|
||||||
match slot.kind {
|
match slot.kind {
|
||||||
StackSlotKind::SpillSlot | StackSlotKind::Local => {
|
StackSlotKind::SpillSlot |
|
||||||
|
StackSlotKind::ExplicitSlot => {
|
||||||
if slot.alignment(alignment) != min_align {
|
if slot.alignment(alignment) != min_align {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -475,29 +475,29 @@ mod tests {
|
|||||||
f.name = ExternalName::testcase("foo");
|
f.name = ExternalName::testcase("foo");
|
||||||
assert_eq!(f.to_string(), "function %foo() native {\n}\n");
|
assert_eq!(f.to_string(), "function %foo() native {\n}\n");
|
||||||
|
|
||||||
f.create_stack_slot(StackSlotData::new(StackSlotKind::Local, 4));
|
f.create_stack_slot(StackSlotData::new(StackSlotKind::ExplicitSlot, 4));
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
f.to_string(),
|
f.to_string(),
|
||||||
"function %foo() native {\n ss0 = local 4\n}\n"
|
"function %foo() native {\n ss0 = explicit_slot 4\n}\n"
|
||||||
);
|
);
|
||||||
|
|
||||||
let ebb = f.dfg.make_ebb();
|
let ebb = f.dfg.make_ebb();
|
||||||
f.layout.append_ebb(ebb);
|
f.layout.append_ebb(ebb);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
f.to_string(),
|
f.to_string(),
|
||||||
"function %foo() native {\n ss0 = local 4\n\nebb0:\n}\n"
|
"function %foo() native {\n ss0 = explicit_slot 4\n\nebb0:\n}\n"
|
||||||
);
|
);
|
||||||
|
|
||||||
f.dfg.append_ebb_param(ebb, types::I8);
|
f.dfg.append_ebb_param(ebb, types::I8);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
f.to_string(),
|
f.to_string(),
|
||||||
"function %foo() native {\n ss0 = local 4\n\nebb0(v0: i8):\n}\n"
|
"function %foo() native {\n ss0 = explicit_slot 4\n\nebb0(v0: i8):\n}\n"
|
||||||
);
|
);
|
||||||
|
|
||||||
f.dfg.append_ebb_param(ebb, types::F32.by(4).unwrap());
|
f.dfg.append_ebb_param(ebb, types::F32.by(4).unwrap());
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
f.to_string(),
|
f.to_string(),
|
||||||
"function %foo() native {\n ss0 = local 4\n\nebb0(v0: i8, v1: f32x4):\n}\n"
|
"function %foo() native {\n ss0 = explicit_slot 4\n\nebb0(v0: i8, v1: f32x4):\n}\n"
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1044,7 +1044,7 @@ impl<'a> Parser<'a> {
|
|||||||
// Parse a stack slot decl.
|
// Parse a stack slot decl.
|
||||||
//
|
//
|
||||||
// stack-slot-decl ::= * StackSlot(ss) "=" stack-slot-kind Bytes {"," stack-slot-flag}
|
// stack-slot-decl ::= * StackSlot(ss) "=" stack-slot-kind Bytes {"," stack-slot-flag}
|
||||||
// stack-slot-kind ::= "local"
|
// stack-slot-kind ::= "explicit_slot"
|
||||||
// | "spill_slot"
|
// | "spill_slot"
|
||||||
// | "incoming_arg"
|
// | "incoming_arg"
|
||||||
// | "outgoing_arg"
|
// | "outgoing_arg"
|
||||||
|
|||||||
Reference in New Issue
Block a user