ruby-changes:73224
From: Alan <ko1@a...>
Date: Tue, 30 Aug 2022 01:03:06 +0900 (JST)
Subject: [ruby-changes:73224] 813df1f27a (master): Add LiveReg IR instruction to fix stats leave exit code (https://github.com/Shopify/ruby/pull/341)
https://git.ruby-lang.org/ruby.git/commit/?id=813df1f27a From 813df1f27aa52a3050d90dab23bc72093da00e6c Mon Sep 17 00:00:00 2001 From: Alan Wu <XrXr@u...> Date: Fri, 22 Jul 2022 16:24:18 -0400 Subject: Add LiveReg IR instruction to fix stats leave exit code (https://github.com/Shopify/ruby/pull/341) It allows for reserving a specific register and prevents the register allocator from clobbering it. Without this `./miniruby --yjit-stats --yjit-callthreshold=1 -e0` was crashing because the counter incrementing code was clobbering RAX incorrectly. --- yjit/src/backend/arm64/mod.rs | 1 + yjit/src/backend/ir.rs | 15 ++++++++++++--- yjit/src/backend/x86_64/mod.rs | 3 ++- yjit/src/codegen.rs | 7 ++++--- 4 files changed, 19 insertions(+), 7 deletions(-) diff --git a/yjit/src/backend/arm64/mod.rs b/yjit/src/backend/arm64/mod.rs index 9726a0f8f2..c6cd1b882c 100644 --- a/yjit/src/backend/arm64/mod.rs +++ b/yjit/src/backend/arm64/mod.rs @@ -792,6 +792,7 @@ impl Assembler https://github.com/ruby/ruby/blob/trunk/yjit/src/backend/arm64/mod.rs#L792 Op::CSelGE => { csel(cb, insn.out.into(), insn.opnds[0].into(), insn.opnds[1].into(), Condition::GE); } + Op::LiveReg => (), // just a reg alloc signal, no code }; } diff --git a/yjit/src/backend/ir.rs b/yjit/src/backend/ir.rs index c55a8f609b..dc0e450df4 100644 --- a/yjit/src/backend/ir.rs +++ b/yjit/src/backend/ir.rs @@ -145,7 +145,10 @@ pub enum Op https://github.com/ruby/ruby/blob/trunk/yjit/src/backend/ir.rs#L145 FrameSetup, /// Tear down the frame stack as necessary per the architecture. - FrameTeardown + FrameTeardown, + + /// Take a specific register. Signal the register allocator to not use it. + LiveReg, } // Memory operand base @@ -633,7 +636,6 @@ impl Assembler https://github.com/ruby/ruby/blob/trunk/yjit/src/backend/ir.rs#L636 if let Some(reg_index) = reg_index { assert_eq!(*pool & (1 << reg_index), 0); *pool |= 1 << reg_index; - //return regs[reg_index]; } return *reg; @@ -713,7 +715,13 @@ impl Assembler https://github.com/ruby/ruby/blob/trunk/yjit/src/backend/ir.rs#L715 // Allocate a new register for this instruction if out_reg == Opnd::None { - out_reg = Opnd::Reg(alloc_reg(&mut pool, ®s)) + out_reg = if op == Op::LiveReg { + // Allocate a specific register + let reg = opnds[0].unwrap_reg(); + Opnd::Reg(take_reg(&mut pool, ®s, ®)) + } else { + Opnd::Reg(alloc_reg(&mut pool, ®s)) + } } } @@ -902,6 +910,7 @@ def_push_1_opnd_no_out!(cret, Op::CRet); https://github.com/ruby/ruby/blob/trunk/yjit/src/backend/ir.rs#L910 def_push_1_opnd!(load, Op::Load); def_push_1_opnd!(load_sext, Op::LoadSExt); def_push_1_opnd!(lea, Op::Lea); +def_push_1_opnd!(live_reg_opnd, Op::LiveReg); def_push_2_opnd_no_out!(store, Op::Store); def_push_2_opnd_no_out!(mov, Op::Mov); def_push_2_opnd_no_out!(cmp, Op::Cmp); diff --git a/yjit/src/backend/x86_64/mod.rs b/yjit/src/backend/x86_64/mod.rs index 7b84e62134..5bae5c7f29 100644 --- a/yjit/src/backend/x86_64/mod.rs +++ b/yjit/src/backend/x86_64/mod.rs @@ -448,7 +448,8 @@ impl Assembler https://github.com/ruby/ruby/blob/trunk/yjit/src/backend/x86_64/mod.rs#L448 Op::CSelGE => { mov(cb, insn.out.into(), insn.opnds[0].into()); cmovl(cb, insn.out.into(), insn.opnds[1].into()); - }, + } + Op::LiveReg => (), // just a reg alloc signal, no code // We want to keep the panic here because some instructions that // we feed to the backend could get lowered into other diff --git a/yjit/src/codegen.rs b/yjit/src/codegen.rs index fa0394eed5..e122d67910 100644 --- a/yjit/src/codegen.rs +++ b/yjit/src/codegen.rs @@ -213,7 +213,7 @@ macro_rules! gen_counter_incr { https://github.com/ruby/ruby/blob/trunk/yjit/src/codegen.rs#L213 let counter_opnd = Opnd::mem(64, ptr_reg, 0); // Increment and store the updated value - $asm.incr_counter(counter_opnd, 1.into() ); + $asm.incr_counter(counter_opnd, 1.into()); } }; } @@ -552,8 +552,9 @@ fn gen_leave_exit(ocb: &mut OutlinedCb) -> CodePtr { https://github.com/ruby/ruby/blob/trunk/yjit/src/codegen.rs#L552 let code_ptr = ocb.get_write_ptr(); let mut asm = Assembler::new(); - // NOTE: gen_leave() fully reconstructs interpreter state and leaves the + // gen_leave() fully reconstructs interpreter state and leaves the // return value in C_RET_OPND before coming here. + let ret_opnd = asm.live_reg_opnd(C_RET_OPND); // Every exit to the interpreter should be counted gen_counter_incr!(asm, leave_interp_return); @@ -564,7 +565,7 @@ fn gen_leave_exit(ocb: &mut OutlinedCb) -> CodePtr { https://github.com/ruby/ruby/blob/trunk/yjit/src/codegen.rs#L565 asm.frame_teardown(); - asm.cret(C_RET_OPND); + asm.cret(ret_opnd); asm.compile(ocb); -- cgit v1.2.1 -- ML: ruby-changes@q... Info: http://www.atdot.net/~ko1/quickml/