Browse Source

Cranelift: Remove the old stack maps implementation (#9159)

They are superseded by the new user stack maps implementation.
pull/9099/head
Nick Fitzgerald 3 months ago
committed by GitHub
parent
commit
c0c3a68c05
No known key found for this signature in database GPG Key ID: B5690EEEBB952194
  1. 3
      cranelift/codegen/src/binemit/mod.rs
  2. 141
      cranelift/codegen/src/binemit/stack_map.rs
  3. 62
      cranelift/codegen/src/ir/user_stack_maps.rs
  4. 29
      cranelift/codegen/src/isa/aarch64/inst/emit.rs
  5. 20
      cranelift/codegen/src/isa/pulley_shared/inst/emit.rs
  6. 32
      cranelift/codegen/src/isa/riscv64/inst/emit.rs
  7. 31
      cranelift/codegen/src/isa/s390x/inst/emit.rs
  8. 13
      cranelift/codegen/src/isa/x64/inst/emit.rs
  9. 18
      cranelift/codegen/src/isa/x64/inst/emit_state.rs
  10. 2
      cranelift/codegen/src/isa/x64/inst/mod.rs
  11. 4
      cranelift/codegen/src/lib.rs
  12. 32
      cranelift/codegen/src/machinst/abi.rs
  13. 71
      cranelift/codegen/src/machinst/buffer.rs
  14. 8
      cranelift/codegen/src/machinst/mod.rs
  15. 11
      cranelift/codegen/src/machinst/vcode.rs
  16. 1
      cranelift/src/compile.rs
  17. 38
      cranelift/src/disasm.rs

3
cranelift/codegen/src/binemit/mod.rs

@ -3,9 +3,6 @@
//! The `binemit` module contains code for translating Cranelift's intermediate representation into
//! binary machine code.
mod stack_map;
pub use self::stack_map::StackMap;
use core::fmt;
#[cfg(feature = "enable-serde")]
use serde_derive::{Deserialize, Serialize};

141
cranelift/codegen/src/binemit/stack_map.rs

@ -1,141 +0,0 @@
use cranelift_bitset::CompoundBitSet;
/// Stack maps record which words in a stack frame contain live GC references at
/// a given instruction pointer.
///
/// Logically, a set of stack maps for a function record a table of the form:
///
/// ```text
/// +---------------------+-------------------------------------------+
/// | Instruction Pointer | SP-Relative Offsets of Live GC References |
/// +---------------------+-------------------------------------------+
/// | 0x12345678 | 2, 6, 12 |
/// | 0x1234abcd | 2, 6 |
/// | ... | ... |
/// +---------------------+-------------------------------------------+
/// ```
///
/// Where "instruction pointer" is an instruction pointer within the function,
/// and "offsets of live GC references" contains the offsets (in units of words)
/// from the frame's stack pointer where live GC references are stored on the
/// stack. Instruction pointers within the function that do not have an entry in
/// this table are not GC safepoints.
///
/// Because
///
/// * offsets of live GC references are relative from the stack pointer, and
/// * stack frames grow down from higher addresses to lower addresses,
///
/// to get a pointer to a live reference at offset `x` within a stack frame, you
/// add `x` from the frame's stack pointer.
///
/// For example, to calculate the pointer to the live GC reference inside "frame
/// 1" below, you would do `frame_1_sp + x`:
///
/// ```text
/// Stack
/// +-------------------+
/// | Frame 0 |
/// | |
/// | | |
/// | +-------------------+ <--- Frame 0's SP
/// | | Frame 1 |
/// Grows | |
/// down | |
/// | | Live GC reference | --+--
/// | | | |
/// | | | |
/// V | | x = offset of live GC reference
/// | | |
/// | | |
/// +-------------------+ --+-- <--- Frame 1's SP
/// | Frame 2 |
/// | ... |
/// ```
///
/// An individual `StackMap` is associated with just one instruction pointer
/// within the function, contains the size of the stack frame, and represents
/// the stack frame as a bitmap. There is one bit per word in the stack frame,
/// and if the bit is set, then the word contains a live GC reference.
///
/// Note that a caller's `OutgoingArg` stack slots and callee's `IncomingArg`
/// stack slots overlap, so we must choose which function's stack maps record
/// live GC references in these slots. We record the `IncomingArg`s in the
/// callee's stack map.
#[derive(Clone, Debug, PartialEq, Eq)]
#[cfg_attr(
feature = "enable-serde",
derive(serde_derive::Deserialize, serde_derive::Serialize)
)]
pub struct StackMap {
bitset: CompoundBitSet,
mapped_words: u32,
}
impl StackMap {
/// Create a stack map from a slice of booleans.
pub fn from_slice(bools: &[bool]) -> Self {
let mut bitset = CompoundBitSet::with_capacity(bools.len());
for (i, b) in bools.iter().enumerate() {
if *b {
bitset.insert(i);
}
}
Self {
mapped_words: u32::try_from(bools.len()).unwrap(),
bitset,
}
}
/// Returns a specified bit.
pub fn get_bit(&self, bit_index: usize) -> bool {
self.bitset.contains(bit_index)
}
/// Returns the raw bitmap that represents this stack map.
pub fn into_bitset(self) -> CompoundBitSet {
self.bitset
}
/// Returns the number of words represented by this stack map.
pub fn mapped_words(&self) -> u32 {
self.mapped_words
}
}
#[cfg(test)]
mod tests {
use super::*;
use alloc::vec::Vec;
type Num = u32;
const NUM_BITS: usize = core::mem::size_of::<Num>() * 8;
#[test]
fn stack_maps() {
let vec: Vec<bool> = Vec::new();
assert!(StackMap::from_slice(&vec).bitset.is_empty());
let mut vec: [bool; NUM_BITS] = Default::default();
let set_true_idx = [5, 7, 24, 31];
for &idx in &set_true_idx {
vec[idx] = true;
}
let mut vec = vec.to_vec();
let stack_map = StackMap::from_slice(&vec);
for idx in 0..32 {
assert_eq!(stack_map.get_bit(idx), set_true_idx.contains(&idx));
}
vec.push(false);
vec.push(true);
let res = StackMap::from_slice(&vec);
for idx in 0..32 {
assert_eq!(stack_map.get_bit(idx), set_true_idx.contains(&idx));
}
assert!(!res.get_bit(32));
assert!(res.get_bit(33));
}
}

62
cranelift/codegen/src/ir/user_stack_maps.rs

@ -27,6 +27,68 @@
//! `cranelift_codegen::ir::DataFlowGraph::append_user_stack_map_entry`). Cranelift
//! will not insert spills and record these stack map entries automatically (in
//! contrast to the old system and its `r64` values).
//!
//! Logically, a set of stack maps for a function record a table of the form:
//!
//! ```text
//! +---------------------+-------------------------------------------+
//! | Instruction Pointer | SP-Relative Offsets of Live GC References |
//! +---------------------+-------------------------------------------+
//! | 0x12345678 | 2, 6, 12 |
//! | 0x1234abcd | 2, 6 |
//! | ... | ... |
//! +---------------------+-------------------------------------------+
//! ```
//!
//! Where "instruction pointer" is an instruction pointer within the function,
//! and "offsets of live GC references" contains the offsets (in units of words)
//! from the frame's stack pointer where live GC references are stored on the
//! stack. Instruction pointers within the function that do not have an entry in
//! this table are not GC safepoints.
//!
//! Because
//!
//! * offsets of live GC references are relative from the stack pointer, and
//! * stack frames grow down from higher addresses to lower addresses,
//!
//! to get a pointer to a live reference at offset `x` within a stack frame, you
//! add `x` to the frame's stack pointer.
//!
//! For example, to calculate the pointer to the live GC reference inside "frame
//! 1" below, you would do `frame_1_sp + x`:
//!
//! ```text
//! Stack
//! +-------------------+
//! | Frame 0 |
//! | |
//! | | |
//! | +-------------------+ <--- Frame 0's SP
//! | | Frame 1 |
//! Grows | |
//! down | |
//! | | Live GC reference | --+--
//! | | | |
//! | | | |
//! V | | x = offset of live GC reference
//! | | |
//! | | |
//! +-------------------+ --+-- <--- Frame 1's SP
//! | Frame 2 |
//! | ... |
//! ```
//!
//! An individual `UserStackMap` is associated with just one instruction pointer
//! within the function, contains the size of the stack frame, and represents
//! the stack frame as a bitmap. There is one bit per word in the stack frame,
//! and if the bit is set, then the word contains a live GC reference.
//!
//! Note that a caller's outgoing argument stack slots (if any) and callee's
//! incoming argument stack slots (if any) overlap, so we must choose which
//! function's stack maps record live GC references in these slots. We record
//! the incoming arguments in the callee's stack map. This choice plays nice
//! with tail calls, where by the time we transfer control to the callee, the
//! caller no longer exists.
use crate::ir;
use cranelift_bitset::CompoundBitSet;

29
cranelift/codegen/src/isa/aarch64/inst/emit.rs

@ -2,7 +2,6 @@
use cranelift_control::ControlPlane;
use crate::binemit::StackMap;
use crate::ir::{self, types::*};
use crate::isa::aarch64::inst::*;
use crate::trace;
@ -651,10 +650,6 @@ fn enc_asimd_mod_imm(rd: Writable<Reg>, q_op: u32, cmode: u32, imm: u8) -> u32 {
/// State carried between emissions of a sequence of instructions.
#[derive(Default, Clone, Debug)]
pub struct EmitState {
/// Safepoint stack map for upcoming instruction, as provided to
/// `pre_safepoint()`.
stack_map: Option<StackMap>,
/// The user stack map for the upcoming instruction, as provided to
/// `pre_safepoint()`.
user_stack_map: Option<ir::UserStackMap>,
@ -669,19 +664,13 @@ pub struct EmitState {
impl MachInstEmitState<Inst> for EmitState {
fn new(abi: &Callee<AArch64MachineDeps>, ctrl_plane: ControlPlane) -> Self {
EmitState {
stack_map: None,
user_stack_map: None,
ctrl_plane,
frame_layout: abi.frame_layout().clone(),
}
}
fn pre_safepoint(
&mut self,
stack_map: Option<StackMap>,
user_stack_map: Option<ir::UserStackMap>,
) {
self.stack_map = stack_map;
fn pre_safepoint(&mut self, user_stack_map: Option<ir::UserStackMap>) {
self.user_stack_map = user_stack_map;
}
@ -699,12 +688,12 @@ impl MachInstEmitState<Inst> for EmitState {
}
impl EmitState {
fn take_stack_map(&mut self) -> (Option<StackMap>, Option<ir::UserStackMap>) {
(self.stack_map.take(), self.user_stack_map.take())
fn take_stack_map(&mut self) -> Option<ir::UserStackMap> {
self.user_stack_map.take()
}
fn clear_post_insn(&mut self) {
self.stack_map = None;
self.user_stack_map = None;
}
}
@ -2935,10 +2924,7 @@ impl MachInstEmit for Inst {
}
}
&Inst::Call { ref info } => {
let (stack_map, user_stack_map) = state.take_stack_map();
if let Some(s) = stack_map {
sink.add_stack_map(StackMapExtent::UpcomingBytes(4), s);
}
let user_stack_map = state.take_stack_map();
sink.add_reloc(Reloc::Arm64Call, &info.dest, 0);
sink.put4(enc_jump26(0b100101, 0));
if let Some(s) = user_stack_map {
@ -2956,10 +2942,7 @@ impl MachInstEmit for Inst {
}
}
&Inst::CallInd { ref info } => {
let (stack_map, user_stack_map) = state.take_stack_map();
if let Some(s) = stack_map {
sink.add_stack_map(StackMapExtent::UpcomingBytes(4), s);
}
let user_stack_map = state.take_stack_map();
let rn = info.rn;
sink.put4(0b1101011_0001_11111_000000_00000_00000 | (machreg_to_gpr(rn) << 5));
if let Some(s) = user_stack_map {

20
cranelift/codegen/src/isa/pulley_shared/inst/emit.rs

@ -1,7 +1,6 @@
//! Pulley binary code emission.
use super::*;
use crate::binemit::StackMap;
use crate::ir;
use crate::isa::pulley_shared::abi::PulleyMachineDeps;
use crate::isa::pulley_shared::PointerWidth;
@ -40,7 +39,6 @@ where
{
_phantom: PhantomData<P>,
ctrl_plane: ControlPlane,
stack_map: Option<StackMap>,
user_stack_map: Option<ir::UserStackMap>,
pub virtual_sp_offset: i64,
frame_layout: FrameLayout,
@ -50,8 +48,8 @@ impl<P> EmitState<P>
where
P: PulleyTargetKind,
{
fn take_stack_map(&mut self) -> (Option<StackMap>, Option<ir::UserStackMap>) {
(self.stack_map.take(), self.user_stack_map.take())
fn take_stack_map(&mut self) -> Option<ir::UserStackMap> {
self.user_stack_map.take()
}
pub(crate) fn adjust_virtual_sp_offset(&mut self, amount: i64) {
@ -70,19 +68,13 @@ where
EmitState {
_phantom: PhantomData,
ctrl_plane,
stack_map: None,
user_stack_map: None,
virtual_sp_offset: 0,
frame_layout: abi.frame_layout().clone(),
}
}
fn pre_safepoint(
&mut self,
stack_map: Option<StackMap>,
user_stack_map: Option<ir::UserStackMap>,
) {
self.stack_map = stack_map;
fn pre_safepoint(&mut self, user_stack_map: Option<ir::UserStackMap>) {
self.user_stack_map = user_stack_map;
}
@ -156,10 +148,6 @@ fn pulley_emit<P>(
Inst::LoadExtName { .. } => todo!(),
Inst::Call { callee, info } => {
let (stack_map, user_stack_map) = state.take_stack_map();
if let Some(s) = stack_map {
sink.add_stack_map(StackMapExtent::UpcomingBytes(5), s);
}
sink.put1(pulley_interpreter::Opcode::Call as u8);
sink.add_reloc(
// TODO: is it actually okay to reuse this reloc here?
@ -170,7 +158,7 @@ fn pulley_emit<P>(
-1,
);
sink.put4(0);
if let Some(s) = user_stack_map {
if let Some(s) = state.take_stack_map() {
let offset = sink.cur_offset();
sink.push_user_stack_map(state, offset, s);
}

32
cranelift/codegen/src/isa/riscv64/inst/emit.rs

@ -1,6 +1,5 @@
//! Riscv64 ISA: binary code emission.
use crate::binemit::StackMap;
use crate::ir::{self, LibCall, TrapCode};
use crate::isa::riscv64::inst::*;
use crate::isa::riscv64::lower::isle::generated_code::{
@ -46,10 +45,6 @@ pub enum EmitVState {
/// State carried between emissions of a sequence of instructions.
#[derive(Default, Clone, Debug)]
pub struct EmitState {
/// Safepoint stack map for upcoming instruction, as provided to
/// `pre_safepoint()`.
stack_map: Option<StackMap>,
/// The user stack map for the upcoming instruction, as provided to
/// `pre_safepoint()`.
user_stack_map: Option<ir::UserStackMap>,
@ -66,8 +61,8 @@ pub struct EmitState {
}
impl EmitState {
fn take_stack_map(&mut self) -> (Option<StackMap>, Option<ir::UserStackMap>) {
(self.stack_map.take(), self.user_stack_map.take())
fn take_stack_map(&mut self) -> Option<ir::UserStackMap> {
self.user_stack_map.take()
}
}
@ -77,7 +72,6 @@ impl MachInstEmitState<Inst> for EmitState {
ctrl_plane: ControlPlane,
) -> Self {
EmitState {
stack_map: None,
user_stack_map: None,
ctrl_plane,
vstate: EmitVState::Unknown,
@ -85,12 +79,7 @@ impl MachInstEmitState<Inst> for EmitState {
}
}
fn pre_safepoint(
&mut self,
stack_map: Option<StackMap>,
user_stack_map: Option<ir::UserStackMap>,
) {
self.stack_map = stack_map;
fn pre_safepoint(&mut self, user_stack_map: Option<ir::UserStackMap>) {
self.user_stack_map = user_stack_map;
}
@ -1129,16 +1118,11 @@ impl Inst {
sink.add_call_site();
sink.add_reloc(Reloc::RiscvCallPlt, &info.dest, 0);
let (stack_map, user_stack_map) = state.take_stack_map();
if let Some(s) = stack_map {
sink.add_stack_map(StackMapExtent::UpcomingBytes(8), s);
}
Inst::construct_auipc_and_jalr(Some(writable_link_reg()), writable_link_reg(), 0)
.into_iter()
.for_each(|i| i.emit_uncompressed(sink, emit_info, state, start_off));
if let Some(s) = user_stack_map {
if let Some(s) = state.take_stack_map() {
let offset = sink.cur_offset();
sink.push_user_stack_map(state, offset, s);
}
@ -1151,8 +1135,6 @@ impl Inst {
}
}
&Inst::CallInd { ref info } => {
let start_offset = sink.cur_offset();
Inst::Jalr {
rd: writable_link_reg(),
base: info.rn,
@ -1160,11 +1142,7 @@ impl Inst {
}
.emit(sink, emit_info, state);
let (stack_map, user_stack_map) = state.take_stack_map();
if let Some(s) = stack_map {
sink.add_stack_map(StackMapExtent::StartedAtOffset(start_offset), s);
}
if let Some(s) = user_stack_map {
if let Some(s) = state.take_stack_map() {
let offset = sink.cur_offset();
sink.push_user_stack_map(state, offset, s);
}

31
cranelift/codegen/src/isa/s390x/inst/emit.rs

@ -1,6 +1,5 @@
//! S390x ISA: binary code emission.
use crate::binemit::StackMap;
use crate::ir::{self, MemFlags, TrapCode};
use crate::isa::s390x::inst::*;
use crate::isa::s390x::settings as s390x_settings;
@ -1320,10 +1319,6 @@ pub struct EmitState {
/// ABI, between the AllocateArgs and the actual call instruction.
pub(crate) nominal_sp_offset: u32,
/// Safepoint stack map for upcoming instruction, as provided to
/// `pre_safepoint()`.
stack_map: Option<StackMap>,
/// The user stack map for the upcoming instruction, as provided to
/// `pre_safepoint()`.
user_stack_map: Option<ir::UserStackMap>,
@ -1339,19 +1334,13 @@ impl MachInstEmitState<Inst> for EmitState {
fn new(abi: &Callee<S390xMachineDeps>, ctrl_plane: ControlPlane) -> Self {
EmitState {
nominal_sp_offset: 0,
stack_map: None,
user_stack_map: None,
ctrl_plane,
frame_layout: abi.frame_layout().clone(),
}
}
fn pre_safepoint(
&mut self,
stack_map: Option<StackMap>,
user_stack_map: Option<ir::UserStackMap>,
) {
self.stack_map = stack_map;
fn pre_safepoint(&mut self, user_stack_map: Option<ir::UserStackMap>) {
self.user_stack_map = user_stack_map;
}
@ -1369,12 +1358,12 @@ impl MachInstEmitState<Inst> for EmitState {
}
impl EmitState {
fn take_stack_map(&mut self) -> (Option<StackMap>, Option<ir::UserStackMap>) {
(self.stack_map.take(), self.user_stack_map.take())
fn take_stack_map(&mut self) -> Option<ir::UserStackMap> {
self.user_stack_map.take()
}
fn clear_post_insn(&mut self) {
self.stack_map = None;
self.user_stack_map = None;
}
}
@ -3287,11 +3276,7 @@ impl Inst {
_ => unreachable!(),
}
let (stack_map, user_stack_map) = state.take_stack_map();
if let Some(s) = stack_map {
sink.add_stack_map(StackMapExtent::UpcomingBytes(6), s);
}
if let Some(s) = user_stack_map {
if let Some(s) = state.take_stack_map() {
let offset = sink.cur_offset() + 6;
sink.push_user_stack_map(state, offset, s);
}
@ -3305,11 +3290,7 @@ impl Inst {
debug_assert_eq!(link.to_reg(), gpr(14));
let rn = info.rn;
let (stack_map, user_stack_map) = state.take_stack_map();
if let Some(s) = stack_map {
sink.add_stack_map(StackMapExtent::UpcomingBytes(2), s);
}
if let Some(s) = user_stack_map {
if let Some(s) = state.take_stack_map() {
let offset = sink.cur_offset() + 2;
sink.push_user_stack_map(state, offset, s);
}

13
cranelift/codegen/src/isa/x64/inst/emit.rs

@ -1598,11 +1598,7 @@ pub(crate) fn emit(
info: call_info,
..
} => {
let (stack_map, user_stack_map) = state.take_stack_map();
if let Some(s) = stack_map {
sink.add_stack_map(StackMapExtent::UpcomingBytes(5), s);
}
if let Some(s) = user_stack_map {
if let Some(s) = state.take_stack_map() {
let offset = sink.cur_offset() + 5;
sink.push_user_stack_map(state, offset, s);
}
@ -1670,7 +1666,6 @@ pub(crate) fn emit(
} => {
let dest = dest.clone();
let start_offset = sink.cur_offset();
match dest {
RegMem::Reg { reg } => {
let reg_enc = int_reg_enc(reg);
@ -1700,11 +1695,7 @@ pub(crate) fn emit(
}
}
let (stack_map, user_stack_map) = state.take_stack_map();
if let Some(s) = stack_map {
sink.add_stack_map(StackMapExtent::StartedAtOffset(start_offset), s);
}
if let Some(s) = user_stack_map {
if let Some(s) = state.take_stack_map() {
let offset = sink.cur_offset();
sink.push_user_stack_map(state, offset, s);
}

18
cranelift/codegen/src/isa/x64/inst/emit_state.rs

@ -5,10 +5,6 @@ use cranelift_control::ControlPlane;
/// State carried between emissions of a sequence of instructions.
#[derive(Default, Clone, Debug)]
pub struct EmitState {
/// Safepoint stack map for upcoming instruction, as provided to
/// `pre_safepoint()`.
stack_map: Option<StackMap>,
/// The user stack map for the upcoming instruction, as provided to
/// `pre_safepoint()`.
user_stack_map: Option<ir::UserStackMap>,
@ -25,19 +21,13 @@ pub struct EmitState {
impl MachInstEmitState<Inst> for EmitState {
fn new(abi: &Callee<X64ABIMachineSpec>, ctrl_plane: ControlPlane) -> Self {
EmitState {
stack_map: None,
user_stack_map: None,
ctrl_plane,
frame_layout: abi.frame_layout().clone(),
}
}
fn pre_safepoint(
&mut self,
stack_map: Option<StackMap>,
user_stack_map: Option<ir::UserStackMap>,
) {
self.stack_map = stack_map;
fn pre_safepoint(&mut self, user_stack_map: Option<ir::UserStackMap>) {
self.user_stack_map = user_stack_map;
}
@ -55,11 +45,11 @@ impl MachInstEmitState<Inst> for EmitState {
}
impl EmitState {
pub(crate) fn take_stack_map(&mut self) -> (Option<StackMap>, Option<ir::UserStackMap>) {
(self.stack_map.take(), self.user_stack_map.take())
pub(crate) fn take_stack_map(&mut self) -> Option<ir::UserStackMap> {
self.user_stack_map.take()
}
pub(crate) fn clear_post_insn(&mut self) {
self.stack_map = None;
self.user_stack_map = None;
}
}

2
cranelift/codegen/src/isa/x64/inst/mod.rs

@ -2,7 +2,7 @@
pub use emit_state::EmitState;
use crate::binemit::{Addend, CodeOffset, Reloc, StackMap};
use crate::binemit::{Addend, CodeOffset, Reloc};
use crate::ir::{types, ExternalName, LibCall, TrapCode, Type};
use crate::isa::x64::abi::X64ABIMachineSpec;
use crate::isa::x64::inst::regs::{pretty_print_reg, show_ireg_sized};

4
cranelift/codegen/src/lib.rs

@ -56,8 +56,8 @@ pub mod write;
pub use crate::entity::packed_option;
pub use crate::machinst::buffer::{
FinalizedMachReloc, FinalizedRelocTarget, MachCallSite, MachSrcLoc, MachStackMap,
MachTextSectionBuilder, MachTrap, OpenPatchRegion, PatchRegion,
FinalizedMachReloc, FinalizedRelocTarget, MachCallSite, MachSrcLoc, MachTextSectionBuilder,
MachTrap, OpenPatchRegion, PatchRegion,
};
pub use crate::machinst::{
CompiledCode, Final, MachBuffer, MachBufferFinalized, MachInst, MachInstEmit,

32
cranelift/codegen/src/machinst/abi.rs

@ -1664,38 +1664,6 @@ impl<M: ABIMachineSpec> Callee<M> {
/// These methods of `Callee` may only be called after
/// regalloc.
impl<M: ABIMachineSpec> Callee<M> {
/// Generate a stack map, given a list of spillslots and the emission state
/// at a given program point (prior to emission of the safepointing
/// instruction).
pub fn spillslots_to_stack_map(
&self,
slots: &[SpillSlot],
state: &<M::I as MachInstEmit>::State,
) -> StackMap {
let frame_layout = state.frame_layout();
let outgoing_args_size = frame_layout.outgoing_args_size;
let clobbers_and_slots = frame_layout.fixed_frame_storage_size + frame_layout.clobber_size;
trace!(
"spillslots_to_stackmap: slots = {:?}, state = {:?}",
slots,
state
);
let map_size = outgoing_args_size + clobbers_and_slots;
let bytes = M::word_bytes();
let map_words = (map_size + bytes - 1) / bytes;
let mut bits = std::iter::repeat(false)
.take(map_words as usize)
.collect::<Vec<bool>>();
let first_spillslot_word = ((self.stackslots_size + outgoing_args_size) / bytes) as usize;
for &slot in slots {
let slot = slot.index();
bits[first_spillslot_word + slot] = true;
}
StackMap::from_slice(&bits[..])
}
/// Compute the final frame layout, post-regalloc.
///
/// This must be called before gen_prologue or gen_epilogue.

71
cranelift/codegen/src/machinst/buffer.rs

@ -170,7 +170,7 @@
//! only process those which are required during island emission, deferring
//! all longer-range fixups to later.
use crate::binemit::{Addend, CodeOffset, Reloc, StackMap};
use crate::binemit::{Addend, CodeOffset, Reloc};
use crate::ir::function::FunctionParameters;
use crate::ir::{ExternalName, RelSourceLoc, SourceLoc, TrapCode};
use crate::isa::unwind::UnwindInst;
@ -249,8 +249,6 @@ pub struct MachBuffer<I: VCodeInst> {
call_sites: SmallVec<[MachCallSite; 16]>,
/// Any source location mappings referring to this code.
srclocs: SmallVec<[MachSrcLoc<Stencil>; 64]>,
/// Any stack maps referring to this code.
stack_maps: SmallVec<[MachStackMap; 8]>,
/// Any user stack maps for this code.
///
/// Each entry is an `(offset, span, stack_map)` triple. Entries are sorted
@ -334,7 +332,6 @@ impl MachBufferFinalized<Stencil> {
.into_iter()
.map(|srcloc| srcloc.apply_base_srcloc(base_srcloc))
.collect(),
stack_maps: self.stack_maps,
user_stack_maps: self.user_stack_maps,
unwind_info: self.unwind_info,
alignment: self.alignment,
@ -362,8 +359,6 @@ pub struct MachBufferFinalized<T: CompilePhase> {
pub(crate) call_sites: SmallVec<[MachCallSite; 16]>,
/// Any source location mappings referring to this code.
pub(crate) srclocs: SmallVec<[T::MachSrcLocType; 64]>,
/// Any stack maps referring to this code.
pub(crate) stack_maps: SmallVec<[MachStackMap; 8]>,
/// Any user stack maps for this code.
///
/// Each entry is an `(offset, span, stack_map)` triple. Entries are sorted
@ -414,17 +409,6 @@ impl Default for MachLabel {
}
}
/// A stack map extent, when creating a stack map.
pub enum StackMapExtent {
/// The stack map starts at this instruction, and ends after the number of upcoming bytes
/// (note: this is a code offset diff).
UpcomingBytes(CodeOffset),
/// The stack map started at the given offset and ends at the current one. This helps
/// architectures where the instruction size has not a fixed length.
StartedAtOffset(CodeOffset),
}
/// Represents the beginning of an editable region in the [`MachBuffer`], while code emission is
/// still occurring. An [`OpenPatchRegion`] is closed by [`MachBuffer::end_patchable`], consuming
/// the [`OpenPatchRegion`] token in the process.
@ -458,7 +442,6 @@ impl<I: VCodeInst> MachBuffer<I> {
traps: SmallVec::new(),
call_sites: SmallVec::new(),
srclocs: SmallVec::new(),
stack_maps: SmallVec::new(),
user_stack_maps: SmallVec::new(),
unwind_info: SmallVec::new(),
cur_srcloc: None,
@ -1547,7 +1530,6 @@ impl<I: VCodeInst> MachBuffer<I> {
traps: self.traps,
call_sites: self.call_sites,
srclocs,
stack_maps: self.stack_maps,
user_stack_maps: self.user_stack_maps,
unwind_info: self.unwind_info,
alignment,
@ -1658,28 +1640,6 @@ impl<I: VCodeInst> MachBuffer<I> {
}
}
/// Add stack map metadata for this program point: a set of stack offsets
/// (from SP upward) that contain live references.
pub fn add_stack_map(&mut self, extent: StackMapExtent, stack_map: StackMap) {
let (start, end) = match extent {
StackMapExtent::UpcomingBytes(insn_len) => {
let start_offset = self.cur_offset();
(start_offset, start_offset + insn_len)
}
StackMapExtent::StartedAtOffset(start_offset) => {
let end_offset = self.cur_offset();
debug_assert!(end_offset >= start_offset);
(start_offset, end_offset)
}
};
trace!("Adding stack map for offsets {start:#x}..{end:#x}: {stack_map:?}");
self.stack_maps.push(MachStackMap {
offset: start,
offset_end: end,
stack_map,
});
}
/// Push a user stack map onto this buffer.
///
/// The stack map is associated with the given `return_addr` code
@ -1768,17 +1728,7 @@ impl<T: CompilePhase> MachBufferFinalized<T> {
&self.traps[..]
}
/// Get the stack map metadata for this code.
pub fn stack_maps(&self) -> &[MachStackMap] {
&self.stack_maps[..]
}
/// Take this buffer's stack map metadata.
pub fn take_stack_maps(&mut self) -> SmallVec<[MachStackMap; 8]> {
mem::take(&mut self.stack_maps)
}
/// Ge tthe user stack map metadata for this code.
/// Get the user stack map metadata for this code.
pub fn user_stack_maps(&self) -> &[(CodeOffset, u32, ir::UserStackMap)] {
&self.user_stack_maps
}
@ -1987,23 +1937,6 @@ impl MachSrcLoc<Stencil> {
}
}
/// Record of stack map metadata: stack offsets containing references.
#[derive(Clone, Debug, PartialEq)]
#[cfg_attr(
feature = "enable-serde",
derive(serde_derive::Serialize, serde_derive::Deserialize)
)]
pub struct MachStackMap {
/// The code offset at which this stack map applies.
pub offset: CodeOffset,
/// The code offset just past the "end" of the instruction: that is, the
/// offset of the first byte of the following instruction, or equivalently,
/// the start offset plus the instruction length.
pub offset_end: CodeOffset,
/// The stack map itself.
pub stack_map: StackMap,
}
/// Record of branch instruction in the buffer, to facilitate editing.
#[derive(Clone, Debug)]
struct MachBranch {

8
cranelift/codegen/src/machinst/mod.rs

@ -44,7 +44,7 @@
//!
//! ```
use crate::binemit::{Addend, CodeInfo, CodeOffset, Reloc, StackMap};
use crate::binemit::{Addend, CodeInfo, CodeOffset, Reloc};
use crate::ir::{
self, function::FunctionParameters, DynamicStackSlot, RelSourceLoc, StackSlot, Type,
};
@ -304,11 +304,7 @@ pub trait MachInstEmitState<I: VCodeInst>: Default + Clone + Debug {
/// Update the emission state before emitting an instruction that is a
/// safepoint.
fn pre_safepoint(
&mut self,
stack_map: Option<StackMap>,
user_stack_map: Option<ir::UserStackMap>,
);
fn pre_safepoint(&mut self, user_stack_map: Option<ir::UserStackMap>);
/// The emission state holds ownership of a control plane, so it doesn't
/// have to be passed around explicitly too much. `ctrl_plane_mut` may

11
cranelift/codegen/src/machinst/vcode.rs

@ -935,15 +935,6 @@ impl<I: VCodeInst> VCode<I> {
safepoint_slots.push(slot);
}
let stack_map = if safepoint_slots.is_empty() {
None
} else {
Some(
self.abi
.spillslots_to_stack_map(&safepoint_slots[..], &state),
)
};
let (user_stack_map, user_stack_map_disasm) = {
// The `user_stack_maps` is keyed by reverse
// instruction index, so we must flip the
@ -958,7 +949,7 @@ impl<I: VCodeInst> VCode<I> {
(user_stack_map, user_stack_map_disasm)
};
state.pre_safepoint(stack_map, user_stack_map);
state.pre_safepoint(user_stack_map);
user_stack_map_disasm
} else {

1
cranelift/src/compile.rs

@ -134,7 +134,6 @@ fn handle_module(
options.print,
result.buffer.relocs(),
result.buffer.traps(),
result.buffer.stack_maps(),
)?;
}
}

38
cranelift/src/disasm.rs

@ -3,7 +3,7 @@ use cfg_if::cfg_if;
use cranelift_codegen::ir::function::FunctionParameters;
use cranelift_codegen::ir::Function;
use cranelift_codegen::isa::TargetIsa;
use cranelift_codegen::{FinalizedMachReloc, MachStackMap, MachTrap};
use cranelift_codegen::{FinalizedMachReloc, MachTrap};
use std::fmt::Write;
fn print_relocs(func_params: &FunctionParameters, relocs: &[FinalizedMachReloc]) -> String {
@ -36,38 +36,6 @@ pub fn print_traps(traps: &[MachTrap]) -> String {
text
}
pub fn print_stack_maps(traps: &[MachStackMap]) -> String {
let mut text = String::new();
for MachStackMap {
offset,
offset_end,
stack_map,
} in traps
{
writeln!(
text,
"add_stack_map at {offset:#x}-{offset_end:#x} mapped_words={}",
stack_map.mapped_words()
)
.unwrap();
write!(text, " entries: ").unwrap();
let mut first = true;
for i in 0..stack_map.mapped_words() {
if !stack_map.get_bit(i as usize) {
continue;
}
if !first {
write!(text, ", ").unwrap();
} else {
first = false;
}
write!(text, "{i}").unwrap();
}
}
text
}
cfg_if! {
if #[cfg(feature = "disas")] {
pub fn print_disassembly(func: &Function, isa: &dyn TargetIsa, mem: &[u8]) -> Result<()> {
@ -124,16 +92,14 @@ pub fn print_all(
print: bool,
relocs: &[FinalizedMachReloc],
traps: &[MachTrap],
stack_maps: &[MachStackMap],
) -> Result<()> {
print_bytes(&mem);
print_disassembly(func, isa, &mem[0..code_size as usize])?;
if print {
println!(
"\n{}\n{}\n{}",
"\n{}\n{}",
print_relocs(&func.params, relocs),
print_traps(traps),
print_stack_maps(stack_maps)
);
}
Ok(())

Loading…
Cancel
Save