Make iseq_to_ssa return Function object

This commit is contained in:
Maxime Chevalier-Boisvert 2025-02-06 15:41:22 -05:00 committed by Takashi Kokubun
parent 5208720746
commit c5e17f50b7
Notes: git 2025-04-18 13:49:31 +00:00

View File

@ -24,7 +24,7 @@ impl std::fmt::Display for BlockId {
/// Instruction operand /// Instruction operand
#[derive(Debug, PartialEq, Clone, Copy)] #[derive(Debug, PartialEq, Clone, Copy)]
enum Opnd { pub enum Opnd {
Const(VALUE), Const(VALUE),
Insn(InsnId), Insn(InsnId),
} }
@ -40,13 +40,13 @@ impl std::fmt::Display for Opnd {
} }
#[derive(Debug, PartialEq)] #[derive(Debug, PartialEq)]
struct BranchEdge { pub struct BranchEdge {
target: BlockId, target: BlockId,
args: Vec<Opnd>, args: Vec<Opnd>,
} }
#[derive(Debug, PartialEq)] #[derive(Debug, PartialEq)]
enum Insn { pub enum Insn {
// SSA block parameter. Also used for function parameters in the function's entry block. // SSA block parameter. Also used for function parameters in the function's entry block.
Param { idx: usize }, Param { idx: usize },
@ -89,7 +89,7 @@ enum Insn {
} }
#[derive(Default, Debug, PartialEq)] #[derive(Default, Debug, PartialEq)]
struct Block { pub struct Block {
params: Vec<InsnId>, params: Vec<InsnId>,
insns: Vec<InsnId>, insns: Vec<InsnId>,
} }
@ -98,7 +98,7 @@ impl Block {
} }
#[derive(Debug, PartialEq)] #[derive(Debug, PartialEq)]
struct Function { pub struct Function {
// TODO: // TODO:
// ISEQ this function refers to // ISEQ this function refers to
//iseq: *const iseqptr_t, //iseq: *const iseqptr_t,
@ -240,6 +240,7 @@ fn to_ssa(opcodes: &Vec<RubyOpcode>) -> Function {
result result
} }
/// Get instruction argument
fn get_arg(pc: *const VALUE, arg_idx: isize) -> VALUE { fn get_arg(pc: *const VALUE, arg_idx: isize) -> VALUE {
unsafe { *(pc.offset(arg_idx + 1)) } unsafe { *(pc.offset(arg_idx + 1)) }
} }
@ -272,10 +273,10 @@ fn compute_jump_targets(iseq: *const rb_iseq_t) -> Vec<u32> {
jump_targets jump_targets
} }
pub fn iseq_to_ssa(iseq: *const rb_iseq_t) { pub fn iseq_to_ssa(iseq: *const rb_iseq_t) -> Function {
let mut result = Function::new(); let mut fun = Function::new();
let mut state = FrameState::new(); let mut state = FrameState::new();
let mut block = result.entry_block; let mut block = fun.entry_block;
let iseq_size = unsafe { get_iseq_encoded_size(iseq) }; let iseq_size = unsafe { get_iseq_encoded_size(iseq) };
let mut insn_idx = 0; let mut insn_idx = 0;
@ -287,7 +288,7 @@ pub fn iseq_to_ssa(iseq: *const rb_iseq_t) {
if insn_idx == 0 { if insn_idx == 0 {
todo!("Separate entry block for param/self/..."); todo!("Separate entry block for param/self/...");
} }
insn_idx_to_block.insert(insn_idx, result.new_block()); insn_idx_to_block.insert(insn_idx, fun.new_block());
} }
while insn_idx < iseq_size { while insn_idx < iseq_size {
@ -310,19 +311,19 @@ pub fn iseq_to_ssa(iseq: *const rb_iseq_t) {
YARVINSN_putobject => { state.push(Opnd::Const(get_arg(pc, 0))); }, YARVINSN_putobject => { state.push(Opnd::Const(get_arg(pc, 0))); },
YARVINSN_putstring => { YARVINSN_putstring => {
let val = Opnd::Const(get_arg(pc, 0)); let val = Opnd::Const(get_arg(pc, 0));
let insn_id = result.push_insn(block, Insn::StringCopy { val }); let insn_id = fun.push_insn(block, Insn::StringCopy { val });
state.push(Opnd::Insn(insn_id)); state.push(Opnd::Insn(insn_id));
} }
YARVINSN_intern => { YARVINSN_intern => {
let val = state.pop(); let val = state.pop();
let insn_id = result.push_insn(block, Insn::StringIntern { val }); let insn_id = fun.push_insn(block, Insn::StringIntern { val });
state.push(Opnd::Insn(insn_id)); state.push(Opnd::Insn(insn_id));
} }
YARVINSN_newarray => { YARVINSN_newarray => {
let count = get_arg(pc, 0).as_usize(); let count = get_arg(pc, 0).as_usize();
let insn_id = result.push_insn(block, Insn::NewArray { count }); let insn_id = fun.push_insn(block, Insn::NewArray { count });
for idx in (0..count).rev() { for idx in (0..count).rev() {
result.push_insn(block, Insn::ArraySet { idx, val: state.pop() }); fun.push_insn(block, Insn::ArraySet { idx, val: state.pop() });
} }
state.push(Opnd::Insn(insn_id)); state.push(Opnd::Insn(insn_id));
} }
@ -341,18 +342,18 @@ pub fn iseq_to_ssa(iseq: *const rb_iseq_t) {
let obj = get_arg(pc, 0); let obj = get_arg(pc, 0);
let pushval = get_arg(pc, 0); let pushval = get_arg(pc, 0);
let v = state.pop(); let v = state.pop();
state.push(Opnd::Insn(result.push_insn(block, Insn::Defined { op_type, obj, pushval, v }))); state.push(Opnd::Insn(fun.push_insn(block, Insn::Defined { op_type, obj, pushval, v })));
} }
YARVINSN_opt_getconstant_path => { YARVINSN_opt_getconstant_path => {
let ic = get_arg(pc, 0).as_ptr::<u8>(); let ic = get_arg(pc, 0).as_ptr::<u8>();
state.push(Opnd::Insn(result.push_insn(block, Insn::GetConstantPath { ic }))); state.push(Opnd::Insn(fun.push_insn(block, Insn::GetConstantPath { ic })));
} }
YARVINSN_branchunless => { YARVINSN_branchunless => {
let offset = get_arg(pc, 0).as_i64(); let offset = get_arg(pc, 0).as_i64();
let val = state.pop(); let val = state.pop();
let test_id = result.push_insn(block, Insn::Test { val }); let test_id = fun.push_insn(block, Insn::Test { val });
// TODO(max): Check interrupts // TODO(max): Check interrupts
let branch_id = result.push_insn(block, let branch_id = fun.push_insn(block,
Insn::IfFalse { Insn::IfFalse {
val: Opnd::Insn(test_id), val: Opnd::Insn(test_id),
target: BranchEdge { target: BranchEdge {
@ -378,7 +379,7 @@ pub fn iseq_to_ssa(iseq: *const rb_iseq_t) {
// TODO: we need to add a BOP not redefined check here // TODO: we need to add a BOP not redefined check here
let v0 = state.pop(); let v0 = state.pop();
let v1 = state.pop(); let v1 = state.pop();
let add_id = result.push_insn(block, Insn::Add { v0, v1 }); let add_id = fun.push_insn(block, Insn::Add { v0, v1 });
state.push(Opnd::Insn(add_id)); state.push(Opnd::Insn(add_id));
} }
@ -386,18 +387,19 @@ pub fn iseq_to_ssa(iseq: *const rb_iseq_t) {
// TODO: we need to add a BOP not redefined check here // TODO: we need to add a BOP not redefined check here
let v0 = state.pop(); let v0 = state.pop();
let v1 = state.pop(); let v1 = state.pop();
let lt_id = result.push_insn(block, Insn::Lt { v0, v1 }); let lt_id = fun.push_insn(block, Insn::Lt { v0, v1 });
state.push(Opnd::Insn(lt_id)); state.push(Opnd::Insn(lt_id));
} }
YARVINSN_leave => { YARVINSN_leave => {
result.push_insn(block, Insn::Return { val: state.pop() }); fun.push_insn(block, Insn::Return { val: state.pop() });
} }
_ => eprintln!("zjit: to_ssa: unknown opcode `{}'", insn_name(opcode as usize)), _ => eprintln!("zjit: to_ssa: unknown opcode `{}'", insn_name(opcode as usize)),
} }
} }
print!("SSA:\n{result}");
return; print!("SSA:\n{fun}");
return fun;
} }
#[cfg(test)] #[cfg(test)]