Cranelift: Add instructions for getting the current stack/frame/return pointers (#4573)
* Cranelift: Add instructions for getting the current stack/frame pointers and return address This is the initial part of https://github.com/bytecodealliance/wasmtime/issues/4535 * x64: Remove `Amode::RbpOffset` and use `Amode::ImmReg` instead We just special case getting operands from `Amode`s now. * Fix s390x `get_return_address`; require `preserve_frame_pointers=true` * Assert that `Amode::ImmRegRegShift` doesn't use rbp/rsp * Handle non-allocatable registers in Amode::with_allocs * Use "stack" instead of "r15" on s390x * r14 is an allocatable register on s390x, so it shouldn't be used with `MovPReg`
This commit is contained in:
@@ -298,16 +298,16 @@ pub(crate) fn emit_std_enc_mem(
|
||||
|
||||
prefixes.emit(sink);
|
||||
|
||||
match mem_e {
|
||||
match *mem_e {
|
||||
Amode::ImmReg { simm32, base, .. } => {
|
||||
// If this is an access based off of RSP, it may trap with a stack overflow if it's the
|
||||
// first touch of a new stack page.
|
||||
if *base == regs::rsp() && !can_trap && info.flags.enable_probestack() {
|
||||
if base == regs::rsp() && !can_trap && info.flags.enable_probestack() {
|
||||
sink.add_trap(TrapCode::StackOverflow);
|
||||
}
|
||||
|
||||
// First, the REX byte.
|
||||
let enc_e = int_reg_enc(*base);
|
||||
let enc_e = int_reg_enc(base);
|
||||
rex.emit_two_op(sink, enc_g, enc_e);
|
||||
|
||||
// Now the opcode(s). These include any other prefixes the caller
|
||||
@@ -319,7 +319,7 @@ pub(crate) fn emit_std_enc_mem(
|
||||
|
||||
// Now the mod/rm and associated immediates. This is
|
||||
// significantly complicated due to the multiple special cases.
|
||||
if *simm32 == 0
|
||||
if simm32 == 0
|
||||
&& enc_e != regs::ENC_RSP
|
||||
&& enc_e != regs::ENC_RBP
|
||||
&& enc_e != regs::ENC_R12
|
||||
@@ -329,10 +329,10 @@ pub(crate) fn emit_std_enc_mem(
|
||||
// replaced by a single mask-and-compare check. We should do
|
||||
// that because this routine is likely to be hot.
|
||||
sink.put1(encode_modrm(0, enc_g & 7, enc_e & 7));
|
||||
} else if *simm32 == 0 && (enc_e == regs::ENC_RSP || enc_e == regs::ENC_R12) {
|
||||
} else if simm32 == 0 && (enc_e == regs::ENC_RSP || enc_e == regs::ENC_R12) {
|
||||
sink.put1(encode_modrm(0, enc_g & 7, 4));
|
||||
sink.put1(0x24);
|
||||
} else if low8_will_sign_extend_to_32(*simm32)
|
||||
} else if low8_will_sign_extend_to_32(simm32)
|
||||
&& enc_e != regs::ENC_RSP
|
||||
&& enc_e != regs::ENC_R12
|
||||
{
|
||||
@@ -340,9 +340,9 @@ pub(crate) fn emit_std_enc_mem(
|
||||
sink.put1((simm32 & 0xFF) as u8);
|
||||
} else if enc_e != regs::ENC_RSP && enc_e != regs::ENC_R12 {
|
||||
sink.put1(encode_modrm(2, enc_g & 7, enc_e & 7));
|
||||
sink.put4(*simm32);
|
||||
sink.put4(simm32);
|
||||
} else if (enc_e == regs::ENC_RSP || enc_e == regs::ENC_R12)
|
||||
&& low8_will_sign_extend_to_32(*simm32)
|
||||
&& low8_will_sign_extend_to_32(simm32)
|
||||
{
|
||||
// REX.B distinguishes RSP from R12
|
||||
sink.put1(encode_modrm(1, enc_g & 7, 4));
|
||||
@@ -353,7 +353,7 @@ pub(crate) fn emit_std_enc_mem(
|
||||
// REX.B distinguishes RSP from R12
|
||||
sink.put1(encode_modrm(2, enc_g & 7, 4));
|
||||
sink.put1(0x24);
|
||||
sink.put4(*simm32);
|
||||
sink.put4(simm32);
|
||||
} else {
|
||||
unreachable!("ImmReg");
|
||||
}
|
||||
@@ -385,14 +385,14 @@ pub(crate) fn emit_std_enc_mem(
|
||||
}
|
||||
|
||||
// modrm, SIB, immediates.
|
||||
if low8_will_sign_extend_to_32(*simm32) && enc_index != regs::ENC_RSP {
|
||||
if low8_will_sign_extend_to_32(simm32) && enc_index != regs::ENC_RSP {
|
||||
sink.put1(encode_modrm(1, enc_g & 7, 4));
|
||||
sink.put1(encode_sib(*shift, enc_index & 7, enc_base & 7));
|
||||
sink.put1(*simm32 as u8);
|
||||
sink.put1(encode_sib(shift, enc_index & 7, enc_base & 7));
|
||||
sink.put1(simm32 as u8);
|
||||
} else if enc_index != regs::ENC_RSP {
|
||||
sink.put1(encode_modrm(2, enc_g & 7, 4));
|
||||
sink.put1(encode_sib(*shift, enc_index & 7, enc_base & 7));
|
||||
sink.put4(*simm32);
|
||||
sink.put1(encode_sib(shift, enc_index & 7, enc_base & 7));
|
||||
sink.put4(simm32);
|
||||
} else {
|
||||
panic!("ImmRegRegShift");
|
||||
}
|
||||
|
||||
@@ -104,6 +104,11 @@
|
||||
(src Gpr)
|
||||
(dst WritableGpr))
|
||||
|
||||
;; Like `MovRR` but with a physical register source (for implementing
|
||||
;; CLIF instructions like `get_stack_pointer`).
|
||||
(MovPReg (src PReg)
|
||||
(dst WritableGpr))
|
||||
|
||||
;; Zero-extended loads, except for 64 bits: movz (bl bq wl wq lq) addr
|
||||
;; reg.
|
||||
;;
|
||||
@@ -3328,3 +3333,24 @@
|
||||
(decl synthetic_amode_to_xmm_mem (SyntheticAmode) XmmMem)
|
||||
(rule (synthetic_amode_to_xmm_mem amode)
|
||||
(synthetic_amode_to_reg_mem amode))
|
||||
|
||||
;; Helper for creating `MovPReg` instructions.
|
||||
(decl mov_preg (PReg) Reg)
|
||||
(rule (mov_preg preg)
|
||||
(let ((dst WritableGpr (temp_writable_gpr))
|
||||
(_ Unit (emit (MInst.MovPReg preg dst))))
|
||||
dst))
|
||||
|
||||
(decl preg_rbp () PReg)
|
||||
(extern constructor preg_rbp preg_rbp)
|
||||
|
||||
(decl preg_rsp () PReg)
|
||||
(extern constructor preg_rsp preg_rsp)
|
||||
|
||||
(decl x64_rbp () Reg)
|
||||
(rule (x64_rbp)
|
||||
(mov_preg (preg_rbp)))
|
||||
|
||||
(decl x64_rsp () Reg)
|
||||
(rule (x64_rsp)
|
||||
(mov_preg (preg_rsp)))
|
||||
|
||||
@@ -313,10 +313,16 @@ impl Amode {
|
||||
) {
|
||||
match self {
|
||||
Amode::ImmReg { base, .. } => {
|
||||
collector.reg_use(*base);
|
||||
if *base != regs::rbp() && *base != regs::rsp() {
|
||||
collector.reg_use(*base);
|
||||
}
|
||||
}
|
||||
Amode::ImmRegRegShift { base, index, .. } => {
|
||||
debug_assert_ne!(base.to_reg(), regs::rbp());
|
||||
debug_assert_ne!(base.to_reg(), regs::rsp());
|
||||
collector.reg_use(base.to_reg());
|
||||
debug_assert_ne!(index.to_reg(), regs::rbp());
|
||||
debug_assert_ne!(index.to_reg(), regs::rsp());
|
||||
collector.reg_use(index.to_reg());
|
||||
}
|
||||
Amode::RipRelative { .. } => {
|
||||
@@ -346,8 +352,7 @@ impl Amode {
|
||||
|
||||
pub(crate) fn get_flags(&self) -> MemFlags {
|
||||
match self {
|
||||
Amode::ImmReg { flags, .. } => *flags,
|
||||
Amode::ImmRegRegShift { flags, .. } => *flags,
|
||||
Amode::ImmReg { flags, .. } | Amode::ImmRegRegShift { flags, .. } => *flags,
|
||||
Amode::RipRelative { .. } => MemFlags::trusted(),
|
||||
}
|
||||
}
|
||||
@@ -364,11 +369,18 @@ impl Amode {
|
||||
simm32,
|
||||
base,
|
||||
flags,
|
||||
} => Amode::ImmReg {
|
||||
simm32,
|
||||
flags,
|
||||
base: allocs.next(base),
|
||||
},
|
||||
} => {
|
||||
let base = if base == regs::rsp() || base == regs::rbp() {
|
||||
base
|
||||
} else {
|
||||
allocs.next(base)
|
||||
};
|
||||
Amode::ImmReg {
|
||||
simm32,
|
||||
flags,
|
||||
base,
|
||||
}
|
||||
}
|
||||
&Amode::ImmRegRegShift {
|
||||
simm32,
|
||||
base,
|
||||
|
||||
@@ -678,6 +678,16 @@ pub(crate) fn emit(
|
||||
);
|
||||
}
|
||||
|
||||
Inst::MovPReg { src, dst } => {
|
||||
let src: Reg = (*src).into();
|
||||
debug_assert!([regs::rsp(), regs::rbp()].contains(&src));
|
||||
let src = Gpr::new(src).unwrap();
|
||||
let size = OperandSize::Size64;
|
||||
let dst = allocs.next(dst.to_reg().to_reg());
|
||||
let dst = WritableGpr::from_writable_reg(Writable::from_reg(dst)).unwrap();
|
||||
Inst::MovRR { size, src, dst }.emit(&[], sink, info, state);
|
||||
}
|
||||
|
||||
Inst::MovzxRmR { ext_mode, src, dst } => {
|
||||
let dst = allocs.next(dst.to_reg().to_reg());
|
||||
let (opcodes, num_opcodes, mut rex_flags) = match ext_mode {
|
||||
|
||||
@@ -91,6 +91,7 @@ impl Inst {
|
||||
| Inst::Mov64MR { .. }
|
||||
| Inst::MovRM { .. }
|
||||
| Inst::MovRR { .. }
|
||||
| Inst::MovPReg { .. }
|
||||
| Inst::MovsxRmR { .. }
|
||||
| Inst::MovzxRmR { .. }
|
||||
| Inst::MulHi { .. }
|
||||
@@ -1423,6 +1424,13 @@ impl PrettyPrint for Inst {
|
||||
)
|
||||
}
|
||||
|
||||
Inst::MovPReg { src, dst } => {
|
||||
let src: Reg = (*src).into();
|
||||
let src = regs::show_ireg_sized(src, 8);
|
||||
let dst = pretty_print_reg(dst.to_reg().to_reg(), 8, allocs);
|
||||
format!("{} {}, {}", ljustify("movq".to_string()), src, dst)
|
||||
}
|
||||
|
||||
Inst::MovzxRmR {
|
||||
ext_mode, src, dst, ..
|
||||
} => {
|
||||
@@ -1984,6 +1992,11 @@ fn x64_get_operands<F: Fn(VReg) -> VReg>(inst: &Inst, collector: &mut OperandCol
|
||||
collector.reg_use(src.to_reg());
|
||||
collector.reg_def(dst.to_writable_reg());
|
||||
}
|
||||
Inst::MovPReg { dst, src } => {
|
||||
debug_assert!([regs::rsp(), regs::rbp()].contains(&(*src).into()));
|
||||
debug_assert!(dst.to_reg().to_reg().is_virtual());
|
||||
collector.reg_def(dst.to_writable_reg());
|
||||
}
|
||||
Inst::XmmToGpr { src, dst, .. } => {
|
||||
collector.reg_use(src.to_reg());
|
||||
collector.reg_def(dst.to_writable_reg());
|
||||
|
||||
@@ -2839,3 +2839,16 @@
|
||||
|
||||
(rule (lower (call_indirect sig_ref val inputs))
|
||||
(gen_call_indirect sig_ref val inputs))
|
||||
|
||||
;;;; Rules for `get_{frame,stack}_pointer` and `get_return_address` ;;;;;;;;;;;;
|
||||
|
||||
(rule (lower (get_frame_pointer))
|
||||
(x64_rbp))
|
||||
|
||||
(rule (lower (get_stack_pointer))
|
||||
(x64_rsp))
|
||||
|
||||
(rule (lower (get_return_address))
|
||||
(x64_load $I64
|
||||
(Amode.ImmReg 8 (preg_rbp) (mem_flags_trusted))
|
||||
(ExtKind.None)))
|
||||
|
||||
@@ -914,7 +914,10 @@ fn lower_insn_to_regs<C: LowerCtx<I = Inst>>(
|
||||
| Opcode::Call
|
||||
| Opcode::CallIndirect
|
||||
| Opcode::Trapif
|
||||
| Opcode::Trapff => {
|
||||
| Opcode::Trapff
|
||||
| Opcode::GetFramePointer
|
||||
| Opcode::GetStackPointer
|
||||
| Opcode::GetReturnAddress => {
|
||||
implemented_in_isle(ctx);
|
||||
}
|
||||
|
||||
|
||||
@@ -31,6 +31,7 @@ use crate::{
|
||||
VCodeConstant, VCodeConstantData,
|
||||
},
|
||||
};
|
||||
use regalloc2::PReg;
|
||||
use smallvec::SmallVec;
|
||||
use std::boxed::Box;
|
||||
use std::convert::TryFrom;
|
||||
@@ -636,6 +637,16 @@ where
|
||||
|
||||
self.gen_call_common(abi, num_rets, caller, args)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn preg_rbp(&mut self) -> PReg {
|
||||
regs::rbp().to_real_reg().unwrap().into()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn preg_rsp(&mut self) -> PReg {
|
||||
regs::rsp().to_real_reg().unwrap().into()
|
||||
}
|
||||
}
|
||||
|
||||
impl<C> IsleContext<'_, C, Flags, IsaFlags, 6>
|
||||
|
||||
Reference in New Issue
Block a user