summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMaxime Chevalier-Boisvert <maxime.chevalierboisvert@shopify.com>2022-06-08 16:09:16 -0400
committerTakashi Kokubun <takashikkbn@gmail.com>2022-08-29 08:46:55 -0700
commitea9abe547da383f30bd0afe73c6693ed1ff68765 (patch)
tree09c0bf60477c18acb546e9a7e9c12a956c68cad4
parent77383b3958a90c3e6c257e3c4431fed54a9de10b (diff)
Add cpush and cpop IR instructions
-rw-r--r--yjit/src/backend/ir.rs6
-rw-r--r--yjit/src/backend/x86_64/mod.rs20
-rw-r--r--yjit/src/codegen.rs74
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
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);
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
// 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
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) {
}
}
-// 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 {
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
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());