diff options
author | Takashi Kokubun <takashikkbn@gmail.com> | 2023-04-11 08:02:52 -0700 |
---|---|---|
committer | GitHub <noreply@github.com> | 2023-04-11 11:02:52 -0400 |
commit | 7297374c5e3dc2b66ee55d918b3f933e78dd23fd (patch) | |
tree | 44b4f37c1bd8617aa948af79b9c0c8101e29efc0 /yjit/src/backend | |
parent | 8c360ce713f57d4177de833297364f6f6d950420 (diff) | |
download | ruby-7297374c5e3dc2b66ee55d918b3f933e78dd23fd.tar.gz |
YJIT: Reduce paddings if --yjit-exec-mem-size <= 128 on arm64 (#7671)
* YJIT: Reduce paddings if --yjit-exec-mem-size <= 128
on arm64
* YJIT: Define jmp_ptr_bytes on CodeBlock
Diffstat (limited to 'yjit/src/backend')
-rw-r--r-- | yjit/src/backend/arm64/mod.rs | 42 | ||||
-rw-r--r-- | yjit/src/backend/x86_64/mod.rs | 10 |
2 files changed, 43 insertions, 9 deletions
diff --git a/yjit/src/backend/arm64/mod.rs b/yjit/src/backend/arm64/mod.rs index b85c032076..a1823c478e 100644 --- a/yjit/src/backend/arm64/mod.rs +++ b/yjit/src/backend/arm64/mod.rs @@ -2,6 +2,7 @@ #![allow(unused_variables)] #![allow(unused_imports)] +use crate::asm::x86_64::jmp_ptr; use crate::asm::{CodeBlock}; use crate::asm::arm64::*; use crate::codegen::{JITState, CodegenGlobals}; @@ -38,8 +39,25 @@ pub const _C_RET_OPND: Opnd = Opnd::Reg(X0_REG); pub const C_SP_REG: A64Opnd = X31; pub const C_SP_STEP: i32 = 16; -// The number of bytes that are generated by emit_jmp_ptr -pub const JMP_PTR_BYTES: usize = 20; +impl CodeBlock { + // The maximum number of bytes that can be generated by emit_jmp_ptr. + pub fn jmp_ptr_bytes(&self) -> usize { + // b instruction's offset is encoded as imm26 times 4. It can jump to + // +/-128MiB, so this can be used when --yjit-exec-mem-size <= 128. + let num_insns = if b_offset_fits_bits(self.virtual_region_size() as i64 / 4) { + 1 // b instruction + } else { + 5 // 4 instructions to load a 64-bit absolute address + br instruction + }; + num_insns * 4 + } + + // The maximum number of instructions that can be generated by emit_conditional_jump. + fn conditional_jump_insns(&self) -> i32 { + // The worst case is instructions for a jump + bcond. + self.jmp_ptr_bytes() as i32 / 4 + 1 + } +} /// Map Opnd to A64Opnd impl From<Opnd> for A64Opnd { @@ -110,7 +128,8 @@ fn emit_jmp_ptr(cb: &mut CodeBlock, dst_ptr: CodePtr, padding: bool) { // Make sure it's always a consistent number of // instructions in case it gets patched and has to // use the other branch. - for _ in num_insns..(JMP_PTR_BYTES / 4) { + assert!(num_insns * 4 <= cb.jmp_ptr_bytes()); + for _ in num_insns..(cb.jmp_ptr_bytes() / 4) { nop(cb); } } @@ -697,6 +716,18 @@ impl Assembler // Here we're going to return 1 because we've only // written out 1 instruction. 1 + } else if b_offset_fits_bits((dst_addr - (src_addr + 4)) / 4) { // + 4 for bcond + // If the jump offset fits into the unconditional jump as + // an immediate value, we can use inverse b.cond + b. + // + // We're going to write out the inverse condition so + // that if it doesn't match it will skip over the + // instruction used for branching. + bcond(cb, Condition::inverse(CONDITION), 2.into()); + b(cb, InstructionOffset::from_bytes((dst_addr - (src_addr + 4)) as i32)); // + 4 for bcond + + // We've only written out 2 instructions. + 2 } else { // Otherwise, we need to load the address into a // register and use the branch register instruction. @@ -720,7 +751,8 @@ impl Assembler // We need to make sure we have at least 6 instructions for // every kind of jump for invalidation purposes, so we're // going to write out padding nop instructions here. - for _ in num_insns..6 { nop(cb); } + assert!(num_insns <= cb.conditional_jump_insns()); + for _ in num_insns..cb.conditional_jump_insns() { nop(cb); } } }, Target::Label(label_idx) => { @@ -1063,7 +1095,7 @@ impl Assembler Insn::RegTemps(_) | Insn::SpillTemp(_) => (), // just a reg alloc signal, no code Insn::PadInvalPatch => { - while (cb.get_write_pos().saturating_sub(std::cmp::max(start_write_pos, cb.page_start_pos()))) < JMP_PTR_BYTES && !cb.has_dropped_bytes() { + while (cb.get_write_pos().saturating_sub(std::cmp::max(start_write_pos, cb.page_start_pos()))) < cb.jmp_ptr_bytes() && !cb.has_dropped_bytes() { nop(cb); } } diff --git a/yjit/src/backend/x86_64/mod.rs b/yjit/src/backend/x86_64/mod.rs index dffac1758d..170fc888e0 100644 --- a/yjit/src/backend/x86_64/mod.rs +++ b/yjit/src/backend/x86_64/mod.rs @@ -34,8 +34,10 @@ pub const _C_ARG_OPNDS: [Opnd; 6] = [ pub const C_RET_REG: Reg = RAX_REG; pub const _C_RET_OPND: Opnd = Opnd::Reg(RAX_REG); -// The number of bytes that are generated by jmp_ptr -pub const JMP_PTR_BYTES: usize = 6; +impl CodeBlock { + // The number of bytes that are generated by jmp_ptr + pub fn jmp_ptr_bytes(&self) -> usize { 6 } +} /// Map Opnd to X86Opnd impl From<Opnd> for X86Opnd { @@ -718,8 +720,8 @@ impl Assembler Insn::SpillTemp(_) => (), // just a reg alloc signal, no code Insn::PadInvalPatch => { let code_size = cb.get_write_pos().saturating_sub(std::cmp::max(start_write_pos, cb.page_start_pos())); - if code_size < JMP_PTR_BYTES { - nop(cb, (JMP_PTR_BYTES - code_size) as u32); + if code_size < cb.jmp_ptr_bytes() { + nop(cb, (cb.jmp_ptr_bytes() - code_size) as u32); } } |