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
35 changes: 35 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,41 @@ 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.
"#,
&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
25 changes: 25 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 @@ -2473,6 +2478,26 @@
(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_r14 () PReg)
(extern constructor preg_r14 preg_r14)

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

(decl r14 () Reg)
(rule (r14)
(mov_preg (preg_r14)))

(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
10 changes: 10 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,13 @@
(_ 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))
(r14))
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
15 changes: 13 additions & 2 deletions cranelift/codegen/src/isa/s390x/lower/isle.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@ pub mod generated_code;
// Types that the generated ISLE code uses via `use super::*`.
use crate::isa::s390x::abi::S390xMachineDeps;
use crate::isa::s390x::inst::{
stack_reg, writable_gpr, zero_reg, CallIndInfo, CallInfo, Cond, Inst as MInst, MemArg, UImm12,
UImm16Shifted, UImm32Shifted,
regs, stack_reg, writable_gpr, zero_reg, CallIndInfo, CallInfo, Cond, Inst as MInst, MemArg,
UImm12, UImm16Shifted, UImm32Shifted,
};
use crate::isa::s390x::settings::Flags as IsaFlags;
use crate::machinst::isle::*;
Expand All @@ -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 @@ -670,6 +671,16 @@ where
fn emit(&mut self, inst: &MInst) -> Unit {
self.lower_ctx.emit(inst.clone());
}

#[inline]
fn preg_r14(&mut self) -> PReg {
regs::gpr(14).to_real_reg().unwrap().into()
}

#[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