ruby-changes:73127
From: Maxime <ko1@a...>
Date: Tue, 30 Aug 2022 00:53:43 +0900 (JST)
Subject: [ruby-changes:73127] ea9abe547d (master): Add cpush and cpop IR instructions
https://git.ruby-lang.org/ruby.git/commit/?id=ea9abe547d From ea9abe547da383f30bd0afe73c6693ed1ff68765 Mon Sep 17 00:00:00 2001 From: Maxime Chevalier-Boisvert <maxime.chevalierboisvert@s...> Date: Wed, 8 Jun 2022 16:09:16 -0400 Subject: Add cpush and cpop IR instructions --- yjit/src/backend/ir.rs | 6 ++++ yjit/src/backend/x86_64/mod.rs | 20 +++++++----- yjit/src/codegen.rs | 74 ++++++++++++++++++++---------------------- 3 files changed, 54 insertions(+), 46 deletions(-) diff --git a/yjit/src/backend/ir.rs b/yjit/src/backend/ir.rs index e5bcd78932..514ac4a67e 100644 --- a/yjit/src/backend/ir.rs +++ b/yjit/src/backend/ir.rs @@ -82,6 +82,10 @@ pub enum Op https://github.com/ruby/ruby/blob/trunk/yjit/src/backend/ir.rs#L82 Je, Jnz, + // Push and pop registers to/from the C stack + CPush, + CPop, + // C function call with N arguments (variadic) CCall, @@ -710,6 +714,8 @@ def_push_jcc!(jnz, Op::Jnz); https://github.com/ruby/ruby/blob/trunk/yjit/src/backend/ir.rs#L714 def_push_2_opnd!(add, Op::Add); def_push_2_opnd!(sub, Op::Sub); def_push_2_opnd!(and, Op::And); +def_push_1_opnd_no_out!(cpush, Op::CPush); +def_push_1_opnd_no_out!(cpop, Op::CPop); def_push_1_opnd_no_out!(cret, Op::CRet); def_push_1_opnd!(load, Op::Load); def_push_1_opnd!(lea, Op::Lea); diff --git a/yjit/src/backend/x86_64/mod.rs b/yjit/src/backend/x86_64/mod.rs index 2d425c2fe0..a40bc2a980 100644 --- a/yjit/src/backend/x86_64/mod.rs +++ b/yjit/src/backend/x86_64/mod.rs @@ -136,14 +136,9 @@ impl Assembler https://github.com/ruby/ruby/blob/trunk/yjit/src/backend/x86_64/mod.rs#L136 // Load effective address Op::Lea => lea(cb, insn.out.into(), insn.opnds[0].into()), - // Test and set flags - Op::Test => test(cb, insn.opnds[0].into(), insn.opnds[1].into()), - - /* - Cmp, - Jnz, - Jbe, - */ + // Push and pop to the C stack + Op::CPush => push(cb, insn.opnds[0].into()), + Op::CPop => pop(cb, insn.opnds[0].into()), // C function call Op::CCall => { @@ -165,6 +160,15 @@ impl Assembler https://github.com/ruby/ruby/blob/trunk/yjit/src/backend/x86_64/mod.rs#L160 ret(cb); } + // Test and set flags + Op::Test => test(cb, insn.opnds[0].into(), insn.opnds[1].into()), + + /* + Cmp, + Jnz, + Jbe, + */ + _ => panic!("unsupported instruction passed to x86 backend: {:?}", insn.op) }; } diff --git a/yjit/src/codegen.rs b/yjit/src/codegen.rs index 59c6773fcc..be051c39a6 100644 --- a/yjit/src/codegen.rs +++ b/yjit/src/codegen.rs @@ -499,38 +499,6 @@ pub fn jit_ensure_block_entry_exit(jit: &mut JITState, ocb: &mut OutlinedCb) { https://github.com/ruby/ruby/blob/trunk/yjit/src/codegen.rs#L499 } } -// Generate a runtime guard that ensures the PC is at the expected -// instruction index in the iseq, otherwise takes a side-exit. -// This is to handle the situation of optional parameters. -// When a function with optional parameters is called, the entry -// PC for the method isn't necessarily 0. -fn gen_pc_guard(cb: &mut CodeBlock, iseq: IseqPtr, insn_idx: u32) { - let pc_opnd = mem_opnd(64, REG_CFP, RUBY_OFFSET_CFP_PC); - let expected_pc = unsafe { rb_iseq_pc_at_idx(iseq, insn_idx) }; - let expected_pc_opnd = const_ptr_opnd(expected_pc as *const u8); - - mov(cb, REG0, pc_opnd); - mov(cb, REG1, expected_pc_opnd); - cmp(cb, REG0, REG1); - - let pc_match = cb.new_label("pc_match".to_string()); - je_label(cb, pc_match); - - // We're not starting at the first PC, so we need to exit. - gen_counter_incr!(cb, leave_start_pc_non_zero); - - pop(cb, REG_SP); - pop(cb, REG_EC); - pop(cb, REG_CFP); - - mov(cb, RAX, imm_opnd(Qundef.into())); - ret(cb); - - // PC should match the expected insn_idx - cb.write_label(pc_match); - cb.link_labels(); -} - // Landing code for when c_return tracing is enabled. See full_cfunc_return(). fn gen_full_cfunc_return(ocb: &mut OutlinedCb) -> CodePtr { let cb = ocb.unwrap(); @@ -579,6 +547,38 @@ fn gen_leave_exit(ocb: &mut OutlinedCb) -> CodePtr { https://github.com/ruby/ruby/blob/trunk/yjit/src/codegen.rs#L547 return code_ptr; } +// Generate a runtime guard that ensures the PC is at the expected +// instruction index in the iseq, otherwise takes a side-exit. +// This is to handle the situation of optional parameters. +// When a function with optional parameters is called, the entry +// PC for the method isn't necessarily 0. +fn gen_pc_guard(cb: &mut CodeBlock, iseq: IseqPtr, insn_idx: u32) { + let pc_opnd = mem_opnd(64, REG_CFP, RUBY_OFFSET_CFP_PC); + let expected_pc = unsafe { rb_iseq_pc_at_idx(iseq, insn_idx) }; + let expected_pc_opnd = const_ptr_opnd(expected_pc as *const u8); + + mov(cb, REG0, pc_opnd); + mov(cb, REG1, expected_pc_opnd); + cmp(cb, REG0, REG1); + + let pc_match = cb.new_label("pc_match".to_string()); + je_label(cb, pc_match); + + // We're not starting at the first PC, so we need to exit. + gen_counter_incr!(cb, leave_start_pc_non_zero); + + pop(cb, REG_SP); + pop(cb, REG_EC); + pop(cb, REG_CFP); + + mov(cb, RAX, imm_opnd(Qundef.into())); + ret(cb); + + // PC should match the expected insn_idx + cb.write_label(pc_match); + cb.link_labels(); +} + /// Compile an interpreter entry block to be inserted into an iseq /// Returns None if compilation fails. pub fn gen_entry_prologue(cb: &mut CodeBlock, iseq: IseqPtr, insn_idx: u32) -> Option<CodePtr> { @@ -600,12 +600,10 @@ pub fn gen_entry_prologue(cb: &mut CodeBlock, iseq: IseqPtr, insn_idx: u32) -> O https://github.com/ruby/ruby/blob/trunk/yjit/src/codegen.rs#L600 let mut asm = Assembler::new(); - // TODO: on arm, we need to push the return address here? - - // FIXME - //push(cb, REG_CFP); - //push(cb, REG_EC); - //push(cb, REG_SP); + // Save the CFP, EC, SP registers to the C stack + asm.cpush(CFP); + asm.cpush(EC); + asm.cpush(SP); // We are passed EC and CFP as arguments asm.mov(EC, C_ARG_REGS[0].into()); -- cgit v1.2.1 -- ML: ruby-changes@q... Info: http://www.atdot.net/~ko1/quickml/