diff --git a/cranelift/codegen/src/isa/aarch64/inst/emit.rs b/cranelift/codegen/src/isa/aarch64/inst/emit.rs index 9d9d98d7c8..b014d9b22d 100644 --- a/cranelift/codegen/src/isa/aarch64/inst/emit.rs +++ b/cranelift/codegen/src/isa/aarch64/inst/emit.rs @@ -4,7 +4,7 @@ use crate::binemit::{CodeOffset, Reloc}; use crate::ir::constant::ConstantData; use crate::ir::types::*; use crate::ir::TrapCode; -use crate::isa::aarch64::inst::*; +use crate::isa::aarch64::{inst::regs::PINNED_REG, inst::*}; use regalloc::{Reg, RegClass, Writable}; @@ -1307,6 +1307,20 @@ impl MachInstEmit for Inst { } _ => unimplemented!("{:?}", mem), }, + &Inst::GetPinnedReg { rd } => { + let inst = Inst::Mov { + rd, + rm: xreg(PINNED_REG), + }; + inst.emit(sink); + } + &Inst::SetPinnedReg { rm } => { + let inst = Inst::Mov { + rd: Writable::from_reg(xreg(PINNED_REG)), + rm, + }; + inst.emit(sink); + } } } } @@ -1315,6 +1329,7 @@ impl MachInstEmit for Inst { mod test { use super::*; use crate::isa::test_utils; + use crate::settings; #[test] fn test_aarch64_binemit() { @@ -4074,7 +4089,7 @@ mod test { "frintn d23, d24", )); - let rru = create_reg_universe(); + let rru = create_reg_universe(&settings::Flags::new(settings::builder())); for (insn, expected_encoding, expected_printing) in insns { println!( "AArch64: {:?}, {}, {}", diff --git a/cranelift/codegen/src/isa/aarch64/inst/mod.rs b/cranelift/codegen/src/isa/aarch64/inst/mod.rs index 90fce9c5fa..72300f1151 100644 --- a/cranelift/codegen/src/isa/aarch64/inst/mod.rs +++ b/cranelift/codegen/src/isa/aarch64/inst/mod.rs @@ -7,6 +7,7 @@ use crate::binemit::CodeOffset; use crate::ir::types::{B1, B16, B32, B64, B8, F32, F64, FFLAGS, I16, I32, I64, I8, IFLAGS}; use crate::ir::{ExternalName, Opcode, SourceLoc, TrapCode, Type}; use crate::machinst::*; +use crate::settings; use regalloc::Map as RegallocMap; use regalloc::{RealReg, RealRegUniverse, Reg, RegClass, SpillSlot, VirtualReg, Writable}; @@ -714,6 +715,16 @@ pub enum Inst { rd: Writable, mem: MemArg, }, + + /// Sets the value of the pinned register to the given register target. + GetPinnedReg { + rd: Writable, + }, + + /// Writes the value of the given source register to the pinned register. + SetPinnedReg { + rm: Reg, + }, } fn count_zero_half_words(mut value: u64) -> usize { @@ -1099,6 +1110,12 @@ fn aarch64_get_regs(inst: &Inst, collector: &mut RegUsageCollector) { &Inst::LoadAddr { rd, mem: _ } => { collector.add_def(rd); } + &Inst::GetPinnedReg { rd } => { + collector.add_def(rd); + } + &Inst::SetPinnedReg { rm } => { + collector.add_use(rm); + } } } @@ -1660,6 +1677,12 @@ fn aarch64_map_regs( map_wr(d, rd); map_mem(u, mem); } + &mut Inst::GetPinnedReg { ref mut rd } => { + map_wr(d, rd); + } + &mut Inst::SetPinnedReg { ref mut rm } => { + map(u, rm); + } } } @@ -1850,8 +1873,8 @@ impl MachInst for Inst { } } - fn reg_universe() -> RealRegUniverse { - create_reg_universe() + fn reg_universe(flags: &settings::Flags) -> RealRegUniverse { + create_reg_universe(flags) } } @@ -2589,6 +2612,14 @@ impl ShowWithRRU for Inst { } _ => unimplemented!("{:?}", mem), }, + &Inst::GetPinnedReg { rd } => { + let rd = rd.show_rru(mb_rru); + format!("get_pinned_reg {}", rd) + } + &Inst::SetPinnedReg { rm } => { + let rm = rm.show_rru(mb_rru); + format!("set_pinned_reg {}", rm) + } } } } diff --git a/cranelift/codegen/src/isa/aarch64/inst/regs.rs b/cranelift/codegen/src/isa/aarch64/inst/regs.rs index b675d7f4d7..f4f19cf517 100644 --- a/cranelift/codegen/src/isa/aarch64/inst/regs.rs +++ b/cranelift/codegen/src/isa/aarch64/inst/regs.rs @@ -2,6 +2,7 @@ use crate::isa::aarch64::inst::InstSize; use crate::machinst::*; +use crate::settings; use regalloc::{RealRegUniverse, Reg, RegClass, RegClassInfo, Writable, NUM_REG_CLASSES}; @@ -10,6 +11,11 @@ use std::string::{String, ToString}; //============================================================================= // Registers, the Universe thereof, and printing +/// The pinned register on this architecture. +/// It must be the same as Spidermonkey's HeapReg, as found in this file. +/// https://searchfox.org/mozilla-central/source/js/src/jit/arm64/Assembler-arm64.h#103 +pub const PINNED_REG: u8 = 21; + #[rustfmt::skip] const XREG_INDICES: [u8; 31] = [ // X0 - X7 @@ -22,8 +28,12 @@ const XREG_INDICES: [u8; 31] = [ 47, 48, // X18 60, - // X19 - X28 - 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, + // X19, X20 + 49, 50, + // X21, put aside because it's the pinned register. + 58, + // X22 - X28 + 51, 52, 53, 54, 55, 56, 57, // X29 61, // X30 @@ -131,14 +141,13 @@ pub fn writable_spilltmp_reg() -> Writable { } /// Create the register universe for AArch64. -pub fn create_reg_universe() -> RealRegUniverse { +pub fn create_reg_universe(flags: &settings::Flags) -> RealRegUniverse { let mut regs = vec![]; let mut allocable_by_class = [None; NUM_REG_CLASSES]; - // Numbering Scheme: we put V-regs first, then X-regs. The X-regs - // exclude several registers: x18 (globally reserved for platform-specific - // purposes), x29 (frame pointer), x30 (link register), x31 (stack pointer - // or zero register, depending on context). + // Numbering Scheme: we put V-regs first, then X-regs. The X-regs exclude several registers: + // x18 (globally reserved for platform-specific purposes), x29 (frame pointer), x30 (link + // register), x31 (stack pointer or zero register, depending on context). let v_reg_base = 0u8; // in contiguous real-register index space let v_reg_count = 32; @@ -159,9 +168,12 @@ pub fn create_reg_universe() -> RealRegUniverse { let x_reg_base = 32u8; // in contiguous real-register index space let mut x_reg_count = 0; + + let uses_pinned_reg = flags.enable_pinned_reg(); + for i in 0u8..32u8 { // See above for excluded registers. - if i == 15 || i == 18 || i == 29 || i == 30 || i == 31 { + if i == 15 || i == 18 || i == 29 || i == 30 || i == 31 || i == PINNED_REG { continue; } let reg = Reg::new_real( @@ -188,13 +200,24 @@ pub fn create_reg_universe() -> RealRegUniverse { }); // Other regs, not available to the allocator. - let allocable = regs.len(); + let allocable = if uses_pinned_reg { + // The pinned register is not allocatable in this case, so record the length before adding + // it. + let len = regs.len(); + regs.push((xreg(PINNED_REG).to_real_reg(), "x21/pinned_reg".to_string())); + len + } else { + regs.push((xreg(PINNED_REG).to_real_reg(), "x21".to_string())); + regs.len() + }; + regs.push((xreg(15).to_real_reg(), "x15".to_string())); regs.push((xreg(18).to_real_reg(), "x18".to_string())); regs.push((fp_reg().to_real_reg(), "fp".to_string())); regs.push((link_reg().to_real_reg(), "lr".to_string())); regs.push((zero_reg().to_real_reg(), "xzr".to_string())); regs.push((stack_reg().to_real_reg(), "sp".to_string())); + // FIXME JRS 2020Feb06: unfortunately this pushes the number of real regs // to 65, which is potentially inconvenient from a compiler performance // standpoint. We could possibly drop back to 64 by "losing" a vector diff --git a/cranelift/codegen/src/isa/aarch64/lower.rs b/cranelift/codegen/src/isa/aarch64/lower.rs index 209b3d6c83..ac5adc8dd4 100644 --- a/cranelift/codegen/src/isa/aarch64/lower.rs +++ b/cranelift/codegen/src/isa/aarch64/lower.rs @@ -1935,9 +1935,16 @@ fn lower_insn_to_regs>(ctx: &mut C, insn: IRInst) { } } - Opcode::GetPinnedReg - | Opcode::SetPinnedReg - | Opcode::Spill + Opcode::GetPinnedReg => { + let rd = output_to_reg(ctx, outputs[0]); + ctx.emit(Inst::GetPinnedReg { rd }); + } + Opcode::SetPinnedReg => { + let rm = input_to_reg(ctx, inputs[0], NarrowValueMode::None); + ctx.emit(Inst::SetPinnedReg { rm }); + } + + Opcode::Spill | Opcode::Fill | Opcode::FillNop | Opcode::Regmove diff --git a/cranelift/codegen/src/isa/aarch64/mod.rs b/cranelift/codegen/src/isa/aarch64/mod.rs index 2f52e618c1..879788e32a 100644 --- a/cranelift/codegen/src/isa/aarch64/mod.rs +++ b/cranelift/codegen/src/isa/aarch64/mod.rs @@ -52,7 +52,7 @@ impl MachBackend for AArch64Backend { let frame_size = vcode.frame_size(); let disasm = if want_disasm { - Some(vcode.show_rru(Some(&create_reg_universe()))) + Some(vcode.show_rru(Some(&create_reg_universe(flags)))) } else { None }; @@ -77,7 +77,7 @@ impl MachBackend for AArch64Backend { } fn reg_universe(&self) -> RealRegUniverse { - create_reg_universe() + create_reg_universe(&self.flags) } } diff --git a/cranelift/codegen/src/machinst/compile.rs b/cranelift/codegen/src/machinst/compile.rs index 8b09568644..2fdaa7292c 100644 --- a/cranelift/codegen/src/machinst/compile.rs +++ b/cranelift/codegen/src/machinst/compile.rs @@ -20,7 +20,7 @@ where // This lowers the CL IR. let mut vcode = Lower::new(f, abi).lower(b); - let universe = &B::MInst::reg_universe(); + let universe = &B::MInst::reg_universe(vcode.flags()); debug!("vcode from lowering: \n{}", vcode.show_rru(Some(universe))); diff --git a/cranelift/codegen/src/machinst/mod.rs b/cranelift/codegen/src/machinst/mod.rs index 844d0d1a4f..b9f89cfe67 100644 --- a/cranelift/codegen/src/machinst/mod.rs +++ b/cranelift/codegen/src/machinst/mod.rs @@ -102,6 +102,7 @@ use crate::ir::condcodes::IntCC; use crate::ir::{Function, Type}; use crate::result::CodegenResult; use crate::settings::Flags; + use alloc::boxed::Box; use alloc::vec::Vec; use core::fmt::Debug; @@ -189,7 +190,7 @@ pub trait MachInst: Clone + Debug { fn with_block_offsets(&mut self, my_offset: CodeOffset, targets: &[CodeOffset]); /// Get the register universe for this backend. - fn reg_universe() -> RealRegUniverse; + fn reg_universe(flags: &Flags) -> RealRegUniverse; /// Align a basic block offset (from start of function). By default, no /// alignment occurs.