ruby-changes:73272
From: Kevin <ko1@a...>
Date: Tue, 30 Aug 2022 01:07:30 +0900 (JST)
Subject: [ruby-changes:73272] 3f42028e3e (master): Iterator (https://github.com/Shopify/ruby/pull/372)
https://git.ruby-lang.org/ruby.git/commit/?id=3f42028e3e From 3f42028e3e7df7d476e71cc995608e26208e3ae0 Mon Sep 17 00:00:00 2001 From: Kevin Newton <kddnewton@g...> Date: Thu, 4 Aug 2022 15:29:31 -0400 Subject: Iterator (https://github.com/Shopify/ruby/pull/372) * Iterator * Use the new iterator for the X86 backend split * Use iterator for reg alloc, remove forward pass * Fix up iterator usage on AArch64 * Update yjit/src/backend/ir.rs Co-authored-by: Maxime Chevalier-Boisvert <maximechevalierb@g...> * Various PR feedback for iterators for IR * Use a local mutable reference for a64_split * Move tests from ir.rs to tests.rs in backend * Fix x86 shift instructions live range calculation * Iterator * Use the new iterator for the X86 backend split * Fix up x86 iterator usage * Fix ARM iterator usage * Remove unintentionally duplicated tests --- yjit/src/backend/arm64/mod.rs | 34 +++--- yjit/src/backend/ir.rs | 238 +++++++++++++++++++++++++++-------------- yjit/src/backend/tests.rs | 38 +++++++ yjit/src/backend/x86_64/mod.rs | 114 +++++++++++--------- 4 files changed, 274 insertions(+), 150 deletions(-) diff --git a/yjit/src/backend/arm64/mod.rs b/yjit/src/backend/arm64/mod.rs index 234339ca4e..fac77f972d 100644 --- a/yjit/src/backend/arm64/mod.rs +++ b/yjit/src/backend/arm64/mod.rs @@ -182,12 +182,14 @@ impl Assembler https://github.com/ruby/ruby/blob/trunk/yjit/src/backend/arm64/mod.rs#L182 } } - self.forward_pass(|asm, index, op, opnds, target, text, pos_marker, original_opnds| { - // Load all Value operands into registers that aren't already a part - // of Load instructions. - let opnds = match op { - Op::Load => opnds, - _ => opnds.into_iter().map(|opnd| { + let mut asm_local = Assembler::new_with_label_names(std::mem::take(&mut self.label_names)); + let asm = &mut asm_local; + let mut iterator = self.into_draining_iter(); + + while let Some((index, insn)) = iterator.next_mapped() { + let opnds = match insn.op { + Op::Load => insn.opnds, + _ => insn.opnds.into_iter().map(|opnd| { if let Opnd::Value(_) = opnd { asm.load(opnd) } else { @@ -196,7 +198,7 @@ impl Assembler https://github.com/ruby/ruby/blob/trunk/yjit/src/backend/arm64/mod.rs#L198 }).collect() }; - match op { + match insn.op { Op::Add => { match (opnds[0], opnds[1]) { (Opnd::Reg(_) | Opnd::InsnOut { .. }, Opnd::Reg(_) | Opnd::InsnOut { .. }) => { @@ -217,17 +219,17 @@ impl Assembler https://github.com/ruby/ruby/blob/trunk/yjit/src/backend/arm64/mod.rs#L219 Op::And | Op::Or => { match (opnds[0], opnds[1]) { (Opnd::Reg(_), Opnd::Reg(_)) => { - asm.push_insn(op, vec![opnds[0], opnds[1]], target, text, pos_marker); + asm.push_insn(insn.op, vec![opnds[0], opnds[1]], insn.target, insn.text, insn.pos_marker); }, (reg_opnd @ Opnd::Reg(_), other_opnd) | (other_opnd, reg_opnd @ Opnd::Reg(_)) => { let opnd1 = split_bitmask_immediate(asm, other_opnd); - asm.push_insn(op, vec![reg_opnd, opnd1], target, text, pos_marker); + asm.push_insn(insn.op, vec![reg_opnd, opnd1], insn.target, insn.text, insn.pos_marker); }, _ => { let opnd0 = split_load_operand(asm, opnds[0]); let opnd1 = split_bitmask_immediate(asm, opnds[1]); - asm.push_insn(op, vec![opnd0, opnd1], target, text, pos_marker); + asm.push_insn(insn.op, vec![opnd0, opnd1], insn.target, insn.text, insn.pos_marker); } } }, @@ -246,7 +248,7 @@ impl Assembler https://github.com/ruby/ruby/blob/trunk/yjit/src/backend/arm64/mod.rs#L248 // Now we push the CCall without any arguments so that it // just performs the call. - asm.ccall(target.unwrap().unwrap_fun_ptr(), vec![]); + asm.ccall(insn.target.unwrap().unwrap_fun_ptr(), vec![]); }, Op::Cmp => { let opnd0 = match opnds[0] { @@ -273,7 +275,7 @@ impl Assembler https://github.com/ruby/ruby/blob/trunk/yjit/src/backend/arm64/mod.rs#L275 } }).collect(); - asm.push_insn(op, new_opnds, target, text, pos_marker); + asm.push_insn(insn.op, new_opnds, insn.target, insn.text, insn.pos_marker); }, Op::IncrCounter => { // We'll use LDADD later which only works with registers @@ -392,10 +394,14 @@ impl Assembler https://github.com/ruby/ruby/blob/trunk/yjit/src/backend/arm64/mod.rs#L394 asm.test(opnd0, opnd1); }, _ => { - asm.push_insn(op, opnds, target, text, pos_marker); + asm.push_insn(insn.op, opnds, insn.target, insn.text, insn.pos_marker); } }; - }) + + iterator.map_insn_index(asm); + } + + asm_local } /// Emit platform-specific machine code diff --git a/yjit/src/backend/ir.rs b/yjit/src/backend/ir.rs index 5eee61b228..2dfb859fe9 100644 --- a/yjit/src/backend/ir.rs +++ b/yjit/src/backend/ir.rs @@ -2,8 +2,10 @@ https://github.com/ruby/ruby/blob/trunk/yjit/src/backend/ir.rs#L2 #![allow(unused_variables)] #![allow(unused_imports)] +use std::cell::Cell; use std::fmt; use std::convert::From; +use std::mem::take; use crate::cruby::{VALUE}; use crate::virtualmem::{CodePtr}; use crate::asm::{CodeBlock, uimm_num_bits, imm_num_bits}; @@ -288,6 +290,20 @@ impl Opnd https://github.com/ruby/ruby/blob/trunk/yjit/src/backend/ir.rs#L290 _ => unreachable!() } } + + /// Maps the indices from a previous list of instructions to a new list of + /// instructions. + pub fn map_index(self, indices: &Vec<usize>) -> Opnd { + match self { + Opnd::InsnOut { idx, num_bits } => { + Opnd::InsnOut { idx: indices[idx], num_bits } + } + Opnd::Mem(Mem { base: MemBase::InsnOut(idx), disp, num_bits }) => { + Opnd::Mem(Mem { base: MemBase::InsnOut(indices[idx]), disp, num_bits }) + }, + _ => self + } + } } impl From<usize> for Opnd { @@ -433,11 +449,15 @@ pub struct Assembler https://github.com/ruby/ruby/blob/trunk/yjit/src/backend/ir.rs#L449 impl Assembler { - pub fn new() -> Assembler { - Assembler { + pub fn new() -> Self { + Self::new_with_label_names(Vec::default()) + } + + pub fn new_with_label_names(label_names: Vec<String>) -> Self { + Self { insns: Vec::default(), live_ranges: Vec::default(), - label_names: Vec::default(), + label_names } } @@ -573,58 +593,6 @@ impl Assembler https://github.com/ruby/ruby/blob/trunk/yjit/src/backend/ir.rs#L593 self.live_ranges.push(self.insns.len()); } - /// Transform input instructions, consumes the input assembler - pub(super) fn forward_pass<F>(mut self, mut map_insn: F) -> Assembler - where F: FnMut(&mut Assembler, usize, Op, Vec<Opnd>, Option<Target>, Option<String>, Option<PosMarkerFn>, Vec<Opnd>) - { - let mut asm = Assembler { - insns: Vec::default(), - live_ranges: Vec::default(), - label_names: self.label_names, - }; - - // Indices maps from the old instruction index to the new instruction - // index. - let mut indices: Vec<usize> = Vec::default(); - - // Map an operand to the next set of instructions by correcting previous - // InsnOut indices. - fn map_opnd(opnd: Opnd, indices: &mut Vec<usize>) -> Opnd { - match opnd { - Opnd::InsnOut{ idx, num_bits } => { - Opnd::InsnOut{ idx: indices[idx], num_bits } - } - Opnd::Mem(Mem{ base: MemBase::InsnOut(idx), disp, num_bits, }) => { - Opnd::Mem(Mem{ base:MemBase::InsnOut(indices[idx]), disp, num_bits }) - } - _ => opnd - } - } - - for (index, insn) in self.insns.drain(..).enumerate() { - let original_opnds = insn.opnds.clone(); - let opnds: Vec<Opnd> = insn.opnds.into_iter().map(|opnd| map_opnd(opnd, &mut indices)).collect(); - - // For each instruction, either handle it here or allow the map_insn - // callback to handle it. - match insn.op { - Op::Comment => { - asm.comment(insn.text.unwrap().as_str()); - }, - _ => { - map_insn(&mut asm, index, insn.op, opnds, insn.target, insn.text, insn.pos_marker, original_opnds); - } - }; - - // Here we're assuming that if we've pushed multiple instructions, - // the output that we're using is still the final instruction that - // was pushed. - indices.push(asm.insns.len() - 1); - } - - asm - } - /// Sets the out field on the various instructions that require allocated /// registers because their output is used as the operand on a subsequent /// instruction. This is our implementation of the linear scan algorithm. @@ -671,13 +639,15 @@ impl Assembler https://github.com/ruby (... truncated) -- ML: ruby-changes@q... Info: http://www.atdot.net/~ko1/quickml/