Reftypes part two: add support for stackmaps.
This commit adds support for generating stackmaps at safepoints to the new backend framework and to the AArch64 backend in particular. It has been tested to work with SpiderMonkey.
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
//! AArch64 ISA: binary code emission.
|
||||
|
||||
use crate::binemit::{CodeOffset, Reloc};
|
||||
use crate::binemit::{CodeOffset, Reloc, Stackmap};
|
||||
use crate::ir::constant::ConstantData;
|
||||
use crate::ir::types::*;
|
||||
use crate::ir::TrapCode;
|
||||
@@ -376,7 +376,37 @@ fn enc_vec_lanes(q: u32, u: u32, size: u32, opcode: u32, rd: Writable<Reg>, rn:
|
||||
/// State carried between emissions of a sequence of instructions.
|
||||
#[derive(Default, Clone, Debug)]
|
||||
pub struct EmitState {
|
||||
virtual_sp_offset: i64,
|
||||
/// Addend to convert nominal-SP offsets to real-SP offsets at the current
|
||||
/// program point.
|
||||
pub(crate) virtual_sp_offset: i64,
|
||||
/// Offset of FP from nominal-SP.
|
||||
pub(crate) nominal_sp_to_fp: i64,
|
||||
/// Safepoint stackmap for upcoming instruction, as provided to `pre_safepoint()`.
|
||||
stackmap: Option<Stackmap>,
|
||||
}
|
||||
|
||||
impl MachInstEmitState<Inst> for EmitState {
|
||||
fn new(abi: &dyn ABIBody<I = Inst>) -> Self {
|
||||
EmitState {
|
||||
virtual_sp_offset: 0,
|
||||
nominal_sp_to_fp: abi.frame_size() as i64,
|
||||
stackmap: None,
|
||||
}
|
||||
}
|
||||
|
||||
fn pre_safepoint(&mut self, stackmap: Stackmap) {
|
||||
self.stackmap = Some(stackmap);
|
||||
}
|
||||
}
|
||||
|
||||
impl EmitState {
|
||||
fn take_stackmap(&mut self) -> Option<Stackmap> {
|
||||
self.stackmap.take()
|
||||
}
|
||||
|
||||
fn clear_post_insn(&mut self) {
|
||||
self.stackmap = None;
|
||||
}
|
||||
}
|
||||
|
||||
impl MachInstEmit for Inst {
|
||||
@@ -1463,6 +1493,9 @@ impl MachInstEmit for Inst {
|
||||
// Noop; this is just a placeholder for epilogues.
|
||||
}
|
||||
&Inst::Call { ref info } => {
|
||||
if let Some(s) = state.take_stackmap() {
|
||||
sink.add_stackmap(4, s);
|
||||
}
|
||||
sink.add_reloc(info.loc, Reloc::Arm64Call, &info.dest, 0);
|
||||
sink.put4(enc_jump26(0b100101, 0));
|
||||
if info.opcode.is_call() {
|
||||
@@ -1470,6 +1503,9 @@ impl MachInstEmit for Inst {
|
||||
}
|
||||
}
|
||||
&Inst::CallInd { ref info } => {
|
||||
if let Some(s) = state.take_stackmap() {
|
||||
sink.add_stackmap(4, s);
|
||||
}
|
||||
sink.put4(0b1101011_0001_11111_000000_00000_00000 | (machreg_to_gpr(info.rn) << 5));
|
||||
if info.opcode.is_call() {
|
||||
sink.add_call_site(info.loc, info.opcode);
|
||||
@@ -1525,6 +1561,9 @@ impl MachInstEmit for Inst {
|
||||
&Inst::Udf { trap_info } => {
|
||||
let (srcloc, code) = trap_info;
|
||||
sink.add_trap(srcloc, code);
|
||||
if let Some(s) = state.take_stackmap() {
|
||||
sink.add_stackmap(4, s);
|
||||
}
|
||||
sink.put4(0xd4a00000);
|
||||
}
|
||||
&Inst::Adr { rd, off } => {
|
||||
@@ -1709,7 +1748,7 @@ impl MachInstEmit for Inst {
|
||||
debug!(
|
||||
"virtual sp offset adjusted by {} -> {}",
|
||||
offset,
|
||||
state.virtual_sp_offset + offset
|
||||
state.virtual_sp_offset + offset,
|
||||
);
|
||||
state.virtual_sp_offset += offset;
|
||||
}
|
||||
@@ -1728,5 +1767,11 @@ impl MachInstEmit for Inst {
|
||||
|
||||
let end_off = sink.cur_offset();
|
||||
debug_assert!((end_off - start_off) <= Inst::worst_case_size());
|
||||
|
||||
state.clear_post_insn();
|
||||
}
|
||||
|
||||
fn pretty_print(&self, mb_rru: Option<&RealRegUniverse>, state: &mut EmitState) -> String {
|
||||
self.print_with_state(mb_rru, state)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1346,11 +1346,11 @@ fn aarch64_get_regs(inst: &Inst, collector: &mut RegUsageCollector) {
|
||||
collector.add_use(rn);
|
||||
}
|
||||
&Inst::Jump { .. } | &Inst::Ret | &Inst::EpiloguePlaceholder => {}
|
||||
&Inst::Call { ref info } => {
|
||||
&Inst::Call { ref info, .. } => {
|
||||
collector.add_uses(&*info.uses);
|
||||
collector.add_defs(&*info.defs);
|
||||
}
|
||||
&Inst::CallInd { ref info } => {
|
||||
&Inst::CallInd { ref info, .. } => {
|
||||
collector.add_uses(&*info.uses);
|
||||
collector.add_defs(&*info.defs);
|
||||
collector.add_use(info.rn);
|
||||
@@ -2137,13 +2137,21 @@ impl MachInst for Inst {
|
||||
// feasible for other reasons).
|
||||
44
|
||||
}
|
||||
|
||||
fn ref_type_rc(_: &settings::Flags) -> RegClass {
|
||||
RegClass::I64
|
||||
}
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
// Pretty-printing of instructions.
|
||||
|
||||
fn mem_finalize_for_show(mem: &MemArg, mb_rru: Option<&RealRegUniverse>) -> (String, MemArg) {
|
||||
let (mem_insts, mem) = mem_finalize(0, mem, &mut Default::default());
|
||||
fn mem_finalize_for_show(
|
||||
mem: &MemArg,
|
||||
mb_rru: Option<&RealRegUniverse>,
|
||||
state: &EmitState,
|
||||
) -> (String, MemArg) {
|
||||
let (mem_insts, mem) = mem_finalize(0, mem, state);
|
||||
let mut mem_str = mem_insts
|
||||
.into_iter()
|
||||
.map(|inst| inst.show_rru(mb_rru))
|
||||
@@ -2158,6 +2166,12 @@ fn mem_finalize_for_show(mem: &MemArg, mb_rru: Option<&RealRegUniverse>) -> (Str
|
||||
|
||||
impl ShowWithRRU for Inst {
|
||||
fn show_rru(&self, mb_rru: Option<&RealRegUniverse>) -> String {
|
||||
self.pretty_print(mb_rru, &mut EmitState::default())
|
||||
}
|
||||
}
|
||||
|
||||
impl Inst {
|
||||
fn print_with_state(&self, mb_rru: Option<&RealRegUniverse>, state: &mut EmitState) -> String {
|
||||
fn op_name_size(alu_op: ALUOp) -> (&'static str, OperandSize) {
|
||||
match alu_op {
|
||||
ALUOp::Add32 => ("add", OperandSize::Size32),
|
||||
@@ -2344,7 +2358,7 @@ impl ShowWithRRU for Inst {
|
||||
srcloc: _srcloc,
|
||||
..
|
||||
} => {
|
||||
let (mem_str, mem) = mem_finalize_for_show(mem, mb_rru);
|
||||
let (mem_str, mem) = mem_finalize_for_show(mem, mb_rru, state);
|
||||
|
||||
let is_unscaled = match &mem {
|
||||
&MemArg::Unscaled(..) => true,
|
||||
@@ -2392,7 +2406,7 @@ impl ShowWithRRU for Inst {
|
||||
srcloc: _srcloc,
|
||||
..
|
||||
} => {
|
||||
let (mem_str, mem) = mem_finalize_for_show(mem, mb_rru);
|
||||
let (mem_str, mem) = mem_finalize_for_show(mem, mb_rru, state);
|
||||
|
||||
let is_unscaled = match &mem {
|
||||
&MemArg::Unscaled(..) => true,
|
||||
@@ -2576,39 +2590,39 @@ impl ShowWithRRU for Inst {
|
||||
}
|
||||
&Inst::FpuLoad32 { rd, ref mem, .. } => {
|
||||
let rd = show_freg_sized(rd.to_reg(), mb_rru, ScalarSize::Size32);
|
||||
let (mem_str, mem) = mem_finalize_for_show(mem, mb_rru);
|
||||
let (mem_str, mem) = mem_finalize_for_show(mem, mb_rru, state);
|
||||
let mem = mem.show_rru(mb_rru);
|
||||
format!("{}ldr {}, {}", mem_str, rd, mem)
|
||||
}
|
||||
&Inst::FpuLoad64 { rd, ref mem, .. } => {
|
||||
let rd = show_freg_sized(rd.to_reg(), mb_rru, ScalarSize::Size64);
|
||||
let (mem_str, mem) = mem_finalize_for_show(mem, mb_rru);
|
||||
let (mem_str, mem) = mem_finalize_for_show(mem, mb_rru, state);
|
||||
let mem = mem.show_rru(mb_rru);
|
||||
format!("{}ldr {}, {}", mem_str, rd, mem)
|
||||
}
|
||||
&Inst::FpuLoad128 { rd, ref mem, .. } => {
|
||||
let rd = rd.to_reg().show_rru(mb_rru);
|
||||
let rd = "q".to_string() + &rd[1..];
|
||||
let (mem_str, mem) = mem_finalize_for_show(mem, mb_rru);
|
||||
let (mem_str, mem) = mem_finalize_for_show(mem, mb_rru, state);
|
||||
let mem = mem.show_rru(mb_rru);
|
||||
format!("{}ldr {}, {}", mem_str, rd, mem)
|
||||
}
|
||||
&Inst::FpuStore32 { rd, ref mem, .. } => {
|
||||
let rd = show_freg_sized(rd, mb_rru, ScalarSize::Size32);
|
||||
let (mem_str, mem) = mem_finalize_for_show(mem, mb_rru);
|
||||
let (mem_str, mem) = mem_finalize_for_show(mem, mb_rru, state);
|
||||
let mem = mem.show_rru(mb_rru);
|
||||
format!("{}str {}, {}", mem_str, rd, mem)
|
||||
}
|
||||
&Inst::FpuStore64 { rd, ref mem, .. } => {
|
||||
let rd = show_freg_sized(rd, mb_rru, ScalarSize::Size64);
|
||||
let (mem_str, mem) = mem_finalize_for_show(mem, mb_rru);
|
||||
let (mem_str, mem) = mem_finalize_for_show(mem, mb_rru, state);
|
||||
let mem = mem.show_rru(mb_rru);
|
||||
format!("{}str {}, {}", mem_str, rd, mem)
|
||||
}
|
||||
&Inst::FpuStore128 { rd, ref mem, .. } => {
|
||||
let rd = rd.show_rru(mb_rru);
|
||||
let rd = "q".to_string() + &rd[1..];
|
||||
let (mem_str, mem) = mem_finalize_for_show(mem, mb_rru);
|
||||
let (mem_str, mem) = mem_finalize_for_show(mem, mb_rru, state);
|
||||
let mem = mem.show_rru(mb_rru);
|
||||
format!("{}str {}, {}", mem_str, rd, mem)
|
||||
}
|
||||
@@ -2978,7 +2992,7 @@ impl ShowWithRRU for Inst {
|
||||
// this logic between `emit()` and `show_rru()` -- a separate 1-to-N
|
||||
// expansion stage (i.e., legalization, but without the slow edit-in-place
|
||||
// of the existing legalization framework).
|
||||
let (mem_insts, mem) = mem_finalize(0, mem, &EmitState::default());
|
||||
let (mem_insts, mem) = mem_finalize(0, mem, state);
|
||||
let mut ret = String::new();
|
||||
for inst in mem_insts.into_iter() {
|
||||
ret.push_str(&inst.show_rru(mb_rru));
|
||||
@@ -3025,7 +3039,10 @@ impl ShowWithRRU for Inst {
|
||||
}
|
||||
ret
|
||||
}
|
||||
&Inst::VirtualSPOffsetAdj { offset } => format!("virtual_sp_offset_adjust {}", offset),
|
||||
&Inst::VirtualSPOffsetAdj { offset } => {
|
||||
state.virtual_sp_offset += offset;
|
||||
format!("virtual_sp_offset_adjust {}", offset)
|
||||
}
|
||||
&Inst::EmitIsland { needed_space } => format!("emit_island {}", needed_space),
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user