Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Cranelift: Add instructions for getting the current stack/frame/return pointers #4573

Merged
37 changes: 37 additions & 0 deletions cranelift/codegen/meta/src/shared/instructions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1314,6 +1314,43 @@ pub(crate) fn define(
.other_side_effects(true),
);

ig.push(
Inst::new(
"get_frame_pointer",
r#"
Get the address in the frame pointer register.

Usage of this instruction requires setting `preserve_frame_pointers` to `true`.
"#,
&formats.nullary,
)
.operands_out(vec![addr]),
);

ig.push(
Inst::new(
"get_stack_pointer",
r#"
Get the address in the stack pointer register.
"#,
&formats.nullary,
)
.operands_out(vec![addr]),
);

ig.push(
Inst::new(
"get_return_address",
r#"
Get the PC where this function will transfer control to when it returns.

Usage of this instruction requires setting `preserve_frame_pointers` to `true`.
"#,
&formats.nullary,
)
.operands_out(vec![addr]),
);

let TableOffset = &TypeVar::new(
"TableOffset",
"An unsigned table offset",
Expand Down
34 changes: 34 additions & 0 deletions cranelift/codegen/src/isa/aarch64/inst.isle
Original file line number Diff line number Diff line change
Expand Up @@ -165,6 +165,12 @@
(rd WritableReg)
(rm Reg))

;; Like `Move` but with a particular `PReg` source (for implementing CLIF
;; instructions like `get_stack_pointer`).
(MovPReg
(rd WritableReg)
(rm PReg))

;; A MOV[Z,N,K] with a 16-bit immediate.
(MovWide
(op MoveWideOp)
Expand Down Expand Up @@ -2426,3 +2432,31 @@
;; And finally, copy the preordained AtomicCASLoop output reg to its destination.
;; Also, x24 and x28 are trashed.
(mov64_from_real 27)))

;; Helper for emitting `MInst.MovPReg` instructions.
(decl mov_preg (PReg) Reg)
(rule (mov_preg src)
(let ((dst WritableReg (temp_writable_reg $I64))
(_ Unit (emit (MInst.MovPReg dst src))))
dst))

(decl preg_sp () PReg)
(extern constructor preg_sp preg_sp)

(decl preg_fp () PReg)
(extern constructor preg_fp preg_fp)

(decl preg_link () PReg)
(extern constructor preg_link preg_link)

(decl aarch64_sp () Reg)
(rule (aarch64_sp)
(mov_preg (preg_sp)))

(decl aarch64_fp () Reg)
(rule (aarch64_fp)
(mov_preg (preg_fp)))

(decl aarch64_link () Reg)
(rule (aarch64_link)
(mov_preg (preg_link)))
9 changes: 9 additions & 0 deletions cranelift/codegen/src/isa/aarch64/inst/emit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1337,6 +1337,15 @@ impl MachInstEmit for Inst {
}
}
}
&Inst::MovPReg { rd, rm } => {
let rd = allocs.next_writable(rd);
let rm: Reg = rm.into();
fitzgen marked this conversation as resolved.
Show resolved Hide resolved
debug_assert!([regs::fp_reg(), regs::stack_reg(), regs::link_reg()].contains(&rm));
assert!(rm.class() == RegClass::Int);
assert!(rd.to_reg().class() == rm.class());
let size = OperandSize::Size64;
Inst::Mov { size, rd, rm }.emit(&[], sink, emit_info, state);
}
&Inst::MovWide { op, rd, imm, size } => {
let rd = allocs.next_writable(rd);
sink.put4(enc_move_wide(op, rd, imm, size));
Expand Down
12 changes: 12 additions & 0 deletions cranelift/codegen/src/isa/aarch64/inst/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -649,6 +649,13 @@ fn aarch64_get_operands<F: Fn(VReg) -> VReg>(inst: &Inst, collector: &mut Operan
collector.reg_def(rd);
collector.reg_use(rm);
}
&Inst::MovPReg { rd, rm } => {
debug_assert!(
[regs::fp_reg(), regs::stack_reg(), regs::link_reg()].contains(&rm.into())
);
debug_assert!(rd.to_reg().is_virtual());
collector.reg_def(rd);
}
&Inst::MovWide { op, rd, .. } => match op {
MoveWideOp::MovK => collector.reg_mod(rd),
_ => collector.reg_def(rd),
Expand Down Expand Up @@ -1482,6 +1489,11 @@ impl Inst {
let rm = pretty_print_ireg(rm, size, allocs);
format!("mov {}, {}", rd, rm)
}
&Inst::MovPReg { rd, rm } => {
let rd = pretty_print_ireg(rd.to_reg(), OperandSize::Size64, allocs);
let rm = show_ireg_sized(rm.into(), OperandSize::Size64);
format!("mov {}, {}", rd, rm)
}
&Inst::MovWide {
op,
rd,
Expand Down
12 changes: 12 additions & 0 deletions cranelift/codegen/src/isa/aarch64/lower.isle
Original file line number Diff line number Diff line change
Expand Up @@ -1687,6 +1687,7 @@


;;;; Rules for `uunarrow` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

(rule (lower (has_type (ty_vec128_int ty) (uunarrow x y)))
(if (zero_value y))
(uqxtn x (lane_size ty)))
Expand Down Expand Up @@ -1723,3 +1724,14 @@

(rule (lower (debugtrap))
(side_effect (brk)))

;;; Rules for `get_{frame,stack}_pointer` and `get_return_address` ;;;;;;;;;;;;;

(rule (lower (get_frame_pointer))
(aarch64_fp))

(rule (lower (get_stack_pointer))
(aarch64_sp))

(rule (lower (get_return_address))
(aarch64_link))
13 changes: 13 additions & 0 deletions cranelift/codegen/src/isa/aarch64/lower/isle.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ use crate::{
isa::unwind::UnwindInst,
machinst::{ty_bits, InsnOutput, LowerCtx, VCodeConstant, VCodeConstantData},
};
use regalloc2::PReg;
use std::boxed::Box;
use std::convert::TryFrom;
use std::vec::Vec;
Expand Down Expand Up @@ -466,4 +467,16 @@ where

rd.to_reg()
}

fn preg_sp(&mut self) -> PReg {
super::regs::stack_reg().to_real_reg().unwrap().into()
}

fn preg_fp(&mut self) -> PReg {
super::regs::fp_reg().to_real_reg().unwrap().into()
}

fn preg_link(&mut self) -> PReg {
super::regs::link_reg().to_real_reg().unwrap().into()
}
}
4 changes: 4 additions & 0 deletions cranelift/codegen/src/isa/aarch64/lower_inst.rs
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,10 @@ pub(crate) fn lower_insn_to_regs<C: LowerCtx<I = Inst>>(
point, as constants are rematerialized at use-sites"
),

Opcode::GetFramePointer | Opcode::GetStackPointer | Opcode::GetReturnAddress => {
implemented_in_isle(ctx)
}

Opcode::Iadd => implemented_in_isle(ctx),
Opcode::Isub => implemented_in_isle(ctx),
Opcode::UaddSat | Opcode::SaddSat | Opcode::UsubSat | Opcode::SsubSat => {
Expand Down
23 changes: 23 additions & 0 deletions cranelift/codegen/src/isa/s390x/inst.isle
Original file line number Diff line number Diff line change
Expand Up @@ -373,6 +373,11 @@
(rd WritableReg)
(rm Reg))

;; Like `Mov64` but with a particular physical register source.
(MovPReg
(rd WritableReg)
(rm PReg))

;; A 32-bit move instruction with a full 32-bit immediate.
(Mov32Imm
(rd WritableReg)
Expand Down Expand Up @@ -1560,6 +1565,10 @@
(decl memarg_stack_off (i64 i64) MemArg)
(extern constructor memarg_stack_off memarg_stack_off)

;; Create a `MemArg` referring to an offset from the initial SP.
(decl memarg_initial_sp_offset (i64) MemArg)
(extern constructor memarg_initial_sp_offset memarg_initial_sp_offset)

;; Form the sum of two offset values, and check that the result is
;; a valid `MemArg::Symbol` offset (i.e. is even and fits into i32).
(decl pure memarg_symbol_offset_sum (i64 i64) i32)
Expand Down Expand Up @@ -2473,6 +2482,20 @@
(rule (emit_load $I64 dst addr)
(emit (MInst.Load64 dst addr)))

;; Helper for creating `MInst.MovPReg` instructions.
(decl mov_preg (PReg) Reg)
(rule (mov_preg src)
(let ((dst WritableReg (temp_writable_reg $I64))
(_ Unit (emit (MInst.MovPReg dst src))))
dst))

(decl preg_r15 () PReg)
(extern constructor preg_r15 preg_r15)
fitzgen marked this conversation as resolved.
Show resolved Hide resolved

;; Copy `r15`, the physical stack register, into a virtual register.
(decl r15 () Reg)
(rule (r15)
(mov_preg (preg_r15)))

;; Helpers for accessing argument / return value slots ;;;;;;;;;;;;;;;;;;;;;;;;;

Expand Down
6 changes: 6 additions & 0 deletions cranelift/codegen/src/isa/s390x/inst/emit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2082,6 +2082,12 @@ impl MachInstEmit for Inst {
let opcode = 0xb904; // LGR
put(sink, &enc_rre(opcode, rd.to_reg(), rm));
}
&Inst::MovPReg { rd, rm } => {
let rm: Reg = rm.into();
debug_assert!([regs::gpr(14), regs::gpr(15)].contains(&rm));
fitzgen marked this conversation as resolved.
Show resolved Hide resolved
let rd = allocs.next_writable(rd);
Inst::Mov64 { rd, rm }.emit(&[], sink, emit_info, state);
}
&Inst::Mov32 { rd, rm } => {
let rd = allocs.next_writable(rd);
let rm = allocs.next(rm);
Expand Down
11 changes: 11 additions & 0 deletions cranelift/codegen/src/isa/s390x/inst/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -144,6 +144,7 @@ impl Inst {
| Inst::StoreMultiple64 { .. }
| Inst::Mov32 { .. }
| Inst::Mov64 { .. }
| Inst::MovPReg { .. }
| Inst::Mov32Imm { .. }
| Inst::Mov32SImm16 { .. }
| Inst::Mov64SImm16 { .. }
Expand Down Expand Up @@ -624,6 +625,11 @@ fn s390x_get_operands<F: Fn(VReg) -> VReg>(inst: &Inst, collector: &mut OperandC
collector.reg_def(rd);
collector.reg_use(rm);
}
&Inst::MovPReg { rd, rm } => {
debug_assert!([regs::gpr(14), regs::gpr(15)].contains(&rm.into()));
debug_assert!(rd.to_reg().is_virtual());
collector.reg_def(rd);
}
&Inst::Mov32 { rd, rm } => {
collector.reg_def(rd);
collector.reg_use(rm);
Expand Down Expand Up @@ -1787,6 +1793,11 @@ impl Inst {
let rm = pretty_print_reg(rm, allocs);
format!("lgr {}, {}", rd, rm)
}
&Inst::MovPReg { rd, rm } => {
let rd = pretty_print_reg(rd.to_reg(), allocs);
let rm = show_reg(rm.into());
format!("lgr {}, {}", rd, rm)
}
&Inst::Mov32 { rd, rm } => {
let rd = pretty_print_reg(rd.to_reg(), allocs);
let rm = pretty_print_reg(rm, allocs);
Expand Down
12 changes: 12 additions & 0 deletions cranelift/codegen/src/isa/s390x/lower.isle
Original file line number Diff line number Diff line change
Expand Up @@ -3619,3 +3619,15 @@
(_ Unit (output_builder_push builder ret)))
(lower_call_rets abi tail builder)))

;;;; Rules for `get_{frame,stack}_pointer` and `get_return_address` ;;;;;;;;;;;;

(rule (lower (get_stack_pointer))
(r15))

(rule (lower (get_frame_pointer))
(load64 (memarg_stack_off 0 0)))

(rule (lower (get_return_address))
;; The return address is 14 pointer-sized slots above the SP. So our
;; offset is `14 * 8 = 112`.
(load64 (memarg_initial_sp_offset 112)))
5 changes: 4 additions & 1 deletion cranelift/codegen/src/isa/s390x/lower.rs
Original file line number Diff line number Diff line change
Expand Up @@ -181,7 +181,10 @@ impl LowerBackend for S390xBackend {
| Opcode::Return
| Opcode::StackAddr
| Opcode::FuncAddr
| Opcode::SymbolValue => {
| Opcode::SymbolValue
| Opcode::GetFramePointer
| Opcode::GetStackPointer
| Opcode::GetReturnAddress => {
unreachable!(
"implemented in ISLE: inst = `{}`, type = `{:?}`",
ctx.dfg().display_inst(ir_inst),
Expand Down
11 changes: 11 additions & 0 deletions cranelift/codegen/src/isa/s390x/lower/isle.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ use crate::{
isa::unwind::UnwindInst,
machinst::{InsnOutput, LowerCtx, VCodeConstant, VCodeConstantData},
};
use regalloc2::PReg;
use std::boxed::Box;
use std::cell::Cell;
use std::convert::TryFrom;
Expand Down Expand Up @@ -603,6 +604,11 @@ where
MemArg::reg_plus_off(stack_reg(), base + off, MemFlags::trusted())
}

#[inline]
fn memarg_initial_sp_offset(&mut self, off: i64) -> MemArg {
MemArg::InitialSPOffset { off }
}

#[inline]
fn memarg_symbol(&mut self, name: ExternalName, offset: i32, flags: MemFlags) -> MemArg {
MemArg::Symbol {
Expand Down Expand Up @@ -670,6 +676,11 @@ where
fn emit(&mut self, inst: &MInst) -> Unit {
self.lower_ctx.emit(inst.clone());
}

#[inline]
fn preg_r15(&mut self) -> PReg {
stack_reg().to_real_reg().unwrap().into()
}
}

/// Zero-extend the low `from_bits` bits of `value` to a full u64.
Expand Down
Loading