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:
Dan Gohman
2018-02-28 13:58:46 -08:00
parent c93f29ad1e
commit 5dc449ec9e
8 changed files with 42 additions and 34 deletions

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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);

View File

@@ -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;
} }

View File

@@ -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"
); );
} }
} }

View File

@@ -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"