Merge pull request #3413 from bjorn3/no_stack_layout
Remove StackLayoutInfo
This commit is contained in:
@@ -79,10 +79,6 @@ pub struct Function {
|
||||
/// Signature of this function.
|
||||
pub signature: Signature,
|
||||
|
||||
/// The old signature of this function, before the most recent legalization,
|
||||
/// if any.
|
||||
pub old_signature: Option<Signature>,
|
||||
|
||||
/// Stack slots allocated in this function.
|
||||
pub stack_slots: StackSlots,
|
||||
|
||||
@@ -145,7 +141,6 @@ impl Function {
|
||||
version_marker: VersionMarker,
|
||||
name,
|
||||
signature: sig,
|
||||
old_signature: None,
|
||||
stack_slots: StackSlots::new(),
|
||||
global_values: PrimaryMap::new(),
|
||||
heaps: PrimaryMap::new(),
|
||||
|
||||
@@ -52,7 +52,7 @@ pub use crate::ir::libcall::{get_probestack_funcref, LibCall};
|
||||
pub use crate::ir::memflags::{Endianness, MemFlags};
|
||||
pub use crate::ir::progpoint::{ExpandedProgramPoint, ProgramOrder, ProgramPoint};
|
||||
pub use crate::ir::sourceloc::SourceLoc;
|
||||
pub use crate::ir::stackslot::{StackLayoutInfo, StackSlotData, StackSlotKind, StackSlots};
|
||||
pub use crate::ir::stackslot::{StackSlotData, StackSlotKind, StackSlots};
|
||||
pub use crate::ir::table::TableData;
|
||||
pub use crate::ir::trapcode::TrapCode;
|
||||
pub use crate::ir::types::Type;
|
||||
|
||||
@@ -162,23 +162,6 @@ impl fmt::Display for StackSlotData {
|
||||
}
|
||||
}
|
||||
|
||||
/// Stack frame layout information.
|
||||
///
|
||||
/// This is computed by the `layout_stack()` method.
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
|
||||
#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))]
|
||||
pub struct StackLayoutInfo {
|
||||
/// The total size of the stack frame.
|
||||
///
|
||||
/// This is the distance from the stack pointer in the current function to the stack pointer in
|
||||
/// the calling function, so it includes a pushed return address as well as space for outgoing
|
||||
/// call arguments.
|
||||
pub frame_size: StackSize,
|
||||
|
||||
/// The total size of the stack frame for inbound arguments pushed by the caller.
|
||||
pub inbound_args_size: StackSize,
|
||||
}
|
||||
|
||||
/// Stack frame manager.
|
||||
///
|
||||
/// Keep track of all the stack slots used by a function.
|
||||
@@ -193,9 +176,6 @@ pub struct StackSlots {
|
||||
|
||||
/// All the emergency slots.
|
||||
emergency: Vec<StackSlot>,
|
||||
|
||||
/// Layout information computed from `layout_stack`.
|
||||
pub layout_info: Option<StackLayoutInfo>,
|
||||
}
|
||||
|
||||
/// Stack slot manager functions that behave mostly like an entity map.
|
||||
@@ -210,7 +190,6 @@ impl StackSlots {
|
||||
self.slots.clear();
|
||||
self.outgoing.clear();
|
||||
self.emergency.clear();
|
||||
self.layout_info = None;
|
||||
}
|
||||
|
||||
/// Allocate a new stack slot.
|
||||
|
||||
@@ -1,66 +0,0 @@
|
||||
//! Register constraints for instruction operands.
|
||||
//!
|
||||
//! An encoding recipe specifies how an instruction is encoded as binary machine code, but it only
|
||||
//! works if the operands and results satisfy certain constraints. Constraints on immediate
|
||||
//! operands are checked by instruction predicates when the recipe is chosen.
|
||||
//!
|
||||
//! It is the register allocator's job to make sure that the register constraints on value operands
|
||||
//! are satisfied.
|
||||
|
||||
use crate::binemit::CodeOffset;
|
||||
|
||||
/// Constraints on the range of a branch instruction.
|
||||
///
|
||||
/// A branch instruction usually encodes its destination as a signed n-bit offset from an origin.
|
||||
/// The origin depends on the ISA and the specific instruction:
|
||||
///
|
||||
/// - RISC-V and ARM Aarch64 use the address of the branch instruction, `origin = 0`.
|
||||
/// - x86 uses the address of the instruction following the branch, `origin = 2` for a 2-byte
|
||||
/// branch instruction.
|
||||
/// - ARM's A32 encoding uses the address of the branch instruction + 8 bytes, `origin = 8`.
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
pub struct BranchRange {
|
||||
/// Offset in bytes from the address of the branch instruction to the origin used for computing
|
||||
/// the branch displacement. This is the destination of a branch that encodes a 0 displacement.
|
||||
pub origin: u8,
|
||||
|
||||
/// Number of bits in the signed byte displacement encoded in the instruction. This does not
|
||||
/// account for branches that can only target aligned addresses.
|
||||
pub bits: u8,
|
||||
}
|
||||
|
||||
impl BranchRange {
|
||||
/// Determine if this branch range can represent the range from `branch` to `dest`, where
|
||||
/// `branch` is the code offset of the branch instruction itself and `dest` is the code offset
|
||||
/// of the destination block header.
|
||||
///
|
||||
/// This method does not detect if the range is larger than 2 GB.
|
||||
pub fn contains(self, branch: CodeOffset, dest: CodeOffset) -> bool {
|
||||
let d = dest.wrapping_sub(branch + CodeOffset::from(self.origin)) as i32;
|
||||
let s = 32 - self.bits;
|
||||
d == d << s >> s
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn branch_range() {
|
||||
// ARM T1 branch.
|
||||
let t1 = BranchRange { origin: 4, bits: 9 };
|
||||
assert!(t1.contains(0, 0));
|
||||
assert!(t1.contains(0, 2));
|
||||
assert!(t1.contains(2, 0));
|
||||
assert!(t1.contains(1000, 1000));
|
||||
|
||||
// Forward limit.
|
||||
assert!(t1.contains(1000, 1258));
|
||||
assert!(!t1.contains(1000, 1260));
|
||||
|
||||
// Backward limit
|
||||
assert!(t1.contains(1000, 748));
|
||||
assert!(!t1.contains(1000, 746));
|
||||
}
|
||||
}
|
||||
@@ -44,8 +44,6 @@
|
||||
//! concurrent function compilations.
|
||||
|
||||
pub use crate::isa::call_conv::CallConv;
|
||||
pub use crate::isa::constraints::BranchRange;
|
||||
pub use crate::isa::stack::{StackBase, StackBaseMask, StackRef};
|
||||
|
||||
use crate::flowgraph;
|
||||
use crate::ir;
|
||||
@@ -77,8 +75,6 @@ mod s390x;
|
||||
pub mod unwind;
|
||||
|
||||
mod call_conv;
|
||||
mod constraints;
|
||||
mod stack;
|
||||
|
||||
#[cfg(test)]
|
||||
mod test_utils;
|
||||
|
||||
@@ -1,95 +0,0 @@
|
||||
//! Low-level details of stack accesses.
|
||||
//!
|
||||
//! The `ir::StackSlots` type deals with stack slots and stack frame layout. The `StackRef` type
|
||||
//! defined in this module expresses the low-level details of accessing a stack slot from an
|
||||
//! encoded instruction.
|
||||
|
||||
use crate::ir::stackslot::{StackOffset, StackSlotKind, StackSlots};
|
||||
use crate::ir::StackSlot;
|
||||
|
||||
/// A method for referencing a stack slot in the current stack frame.
|
||||
///
|
||||
/// Stack slots are addressed with a constant offset from a base register. The base can be the
|
||||
/// stack pointer, the frame pointer, or (in the future) a zone register pointing to an inner zone
|
||||
/// of a large stack frame.
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
pub struct StackRef {
|
||||
/// The base register to use for addressing.
|
||||
pub base: StackBase,
|
||||
|
||||
/// Immediate offset from the base register to the first byte of the stack slot.
|
||||
pub offset: StackOffset,
|
||||
}
|
||||
|
||||
impl StackRef {
|
||||
/// Get a reference to the stack slot `ss` using one of the base pointers in `mask`.
|
||||
pub fn masked(ss: StackSlot, mask: StackBaseMask, frame: &StackSlots) -> Option<Self> {
|
||||
// Try an SP-relative reference.
|
||||
if mask.contains(StackBase::SP) {
|
||||
return Some(Self::sp(ss, frame));
|
||||
}
|
||||
|
||||
// No reference possible with this mask.
|
||||
None
|
||||
}
|
||||
|
||||
/// Get a reference to `ss` using the stack pointer as a base.
|
||||
pub fn sp(ss: StackSlot, frame: &StackSlots) -> Self {
|
||||
let size = frame
|
||||
.layout_info
|
||||
.expect("Stack layout must be computed before referencing stack slots")
|
||||
.frame_size;
|
||||
let slot = &frame[ss];
|
||||
let offset = if slot.kind == StackSlotKind::OutgoingArg {
|
||||
// Outgoing argument slots have offsets relative to our stack pointer.
|
||||
slot.offset.unwrap()
|
||||
} else {
|
||||
// All other slots have offsets relative to our caller's stack frame.
|
||||
// Offset where SP is pointing. (All ISAs have stacks growing downwards.)
|
||||
let sp_offset = -(size as StackOffset);
|
||||
slot.offset.unwrap() - sp_offset
|
||||
};
|
||||
Self {
|
||||
base: StackBase::SP,
|
||||
offset,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Generic base register for referencing stack slots.
|
||||
///
|
||||
/// Most ISAs have a stack pointer and an optional frame pointer, so provide generic names for
|
||||
/// those two base pointers.
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
|
||||
pub enum StackBase {
|
||||
/// Use the stack pointer.
|
||||
SP = 0,
|
||||
|
||||
/// Use the frame pointer (if one is present).
|
||||
FP = 1,
|
||||
|
||||
/// Use an explicit zone pointer in a general-purpose register.
|
||||
///
|
||||
/// This feature is not yet implemented.
|
||||
Zone = 2,
|
||||
}
|
||||
|
||||
/// Bit mask of supported stack bases.
|
||||
///
|
||||
/// Many instruction encodings can use different base registers while others only work with the
|
||||
/// stack pointer, say. A `StackBaseMask` is a bit mask of supported stack bases for a given
|
||||
/// instruction encoding.
|
||||
///
|
||||
/// This behaves like a set of `StackBase` variants.
|
||||
///
|
||||
/// The internal representation as a `u8` is public because stack base masks are used in constant
|
||||
/// tables generated from the meta-language encoding definitions.
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
|
||||
pub struct StackBaseMask(pub u8);
|
||||
|
||||
impl StackBaseMask {
|
||||
/// Check if this mask contains the `base` variant.
|
||||
pub fn contains(self, base: StackBase) -> bool {
|
||||
self.0 & (1 << base as usize) != 0
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user