Skip to content

Commit 18e97b6

Browse files
committed
ZJIT: Add clean_ssa pass
This is "phi elimination".
1 parent fa8c919 commit 18e97b6

4 files changed

Lines changed: 168 additions & 86 deletions

File tree

zjit.rb

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -152,6 +152,7 @@ def stats_string
152152
:compile_hir_strength_reduce_time_ns,
153153
:compile_hir_fold_constants_time_ns,
154154
:compile_hir_clean_cfg_time_ns,
155+
:compile_hir_clean_ssa_time_ns,
155156
:compile_hir_eliminate_dead_code_time_ns,
156157
:compile_lir_time_ns,
157158
:profile_time_ns,

zjit/src/hir.rs

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3669,6 +3669,84 @@ impl Function {
36693669
})
36703670
}
36713671

3672+
fn clean_ssa(&mut self) {
3673+
let mut predecessors: HashMap<BlockId, HashSet<InsnId>> = HashMap::new();
3674+
let rpo = self.rpo();
3675+
for &block in &rpo {
3676+
for &insn_id in &self.blocks[block.0].insns {
3677+
// Instructions without output, including branch instructions, can't be targets of
3678+
// make_equal_to, so we don't need find() here.
3679+
match &self.insns[insn_id.0] {
3680+
Insn::IfTrue { target, .. }
3681+
| Insn::IfFalse { target, .. }
3682+
| Insn::Jump(target) => {
3683+
predecessors.entry(target.target).or_default().insert(insn_id);
3684+
}
3685+
// Entries does not pass block arguments
3686+
_ => {}
3687+
}
3688+
}
3689+
}
3690+
3691+
fn is_trivial(out: InsnId, operands: &[InsnId]) -> Option<InsnId> {
3692+
let mut same = None;
3693+
for &op in operands {
3694+
if Some(op) == same || op == out {
3695+
continue; // Unique value or self-reference
3696+
}
3697+
if !same.is_none() {
3698+
return None; // Merges at least two values: not trivial
3699+
}
3700+
same = Some(op);
3701+
}
3702+
same
3703+
}
3704+
3705+
let mut changed = true;
3706+
while changed {
3707+
changed = false;
3708+
for &block in &rpo {
3709+
let Some(preds) = predecessors.get(&block) else { continue; };
3710+
let mut new_params = vec![];
3711+
let mut num_removed = 0;
3712+
for (idx, &param) in self.blocks[block.0].params.iter().enumerate() {
3713+
let incoming = preds.iter().map(|&pred_insn| {
3714+
// Instructions without output, including branch instructions, can't be targets of
3715+
// make_equal_to, so we don't need find() here.
3716+
match &self.insns[pred_insn.0] {
3717+
Insn::IfTrue { target, .. }
3718+
| Insn::IfFalse { target, .. }
3719+
| Insn::Jump(target) => {
3720+
self.union_find.borrow().find_const(target.args[idx - num_removed])
3721+
}
3722+
_ => unreachable!(),
3723+
}
3724+
}).collect::<Vec<_>>();
3725+
if let Some(same) = is_trivial(param, &incoming) {
3726+
self.union_find.borrow_mut().make_equal_to(param, same);
3727+
for &pred in preds {
3728+
match &mut self.insns[pred.0] {
3729+
Insn::IfTrue { target, .. }
3730+
| Insn::IfFalse { target, .. }
3731+
| Insn::Jump(target) => {
3732+
target.args.remove(idx - num_removed);
3733+
}
3734+
_ => unreachable!(),
3735+
}
3736+
}
3737+
num_removed += 1;
3738+
} else {
3739+
new_params.push(param);
3740+
}
3741+
}
3742+
if num_removed > 0 {
3743+
self.blocks[block.0].params = new_params;
3744+
changed = true;
3745+
}
3746+
}
3747+
}
3748+
}
3749+
36723750
/// Rewrite eligible Send opcodes into SendDirect
36733751
/// opcodes if we know the target ISEQ statically. This removes run-time method lookups and
36743752
/// opens the door for inlining.
@@ -5932,6 +6010,7 @@ impl Function {
59326010
// End strength reduction bucket
59336011
(optimize_load_store) => { Counter::compile_hir_optimize_load_store_time_ns };
59346012
(fold_constants) => { Counter::compile_hir_fold_constants_time_ns };
6013+
(clean_ssa) => { Counter::compile_hir_clean_ssa_time_ns };
59356014
(clean_cfg) => { Counter::compile_hir_clean_cfg_time_ns };
59366015
(remove_redundant_patch_points) => { Counter::compile_hir_remove_redundant_patch_points_time_ns };
59376016
(remove_duplicate_check_interrupts) => { Counter::compile_hir_remove_duplicate_check_interrupts_time_ns };
@@ -5959,6 +6038,7 @@ impl Function {
59596038
}
59606039

59616040
// Function is assumed to have types inferred already
6041+
run_pass!(clean_ssa);
59626042
run_pass!(type_specialize);
59636043
run_pass!(inline);
59646044
run_pass!(optimize_getivar);

0 commit comments

Comments
 (0)