summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAaron Patterson <tenderlove@ruby-lang.org>2025-11-24 16:16:08 -0800
committerAaron Patterson <aaron.patterson@gmail.com>2025-12-03 13:37:40 -0800
commit2b23b05bf2c0f30f2c4ee9bb3030fa58f2cba3a6 (patch)
tree94e2b1795beeeca7917940d46656ace756f07d7d
parenta773bbf0cc35cd4b73509edd58a0757d06abaca6 (diff)
ZJIT: Add a specialized instruction iterator to the assembler
This commit adds a specialized instruction iterator to the assembler with a custom "peek" method. The reason is that we want to add basic blocks to LIR. When we split instructions, we need to add any new instructions to the correct basic block. The custom iterator will maintain the correct basic block inside the assembler, that way when we push any new instructions they will be appended to the correct place.
-rw-r--r--zjit/src/backend/lir.rs47
1 files changed, 47 insertions, 0 deletions
diff --git a/zjit/src/backend/lir.rs b/zjit/src/backend/lir.rs
index 3c9bf72023..d7c6740d13 100644
--- a/zjit/src/backend/lir.rs
+++ b/zjit/src/backend/lir.rs
@@ -1399,6 +1399,15 @@ impl Assembler
}
}
+ pub fn instruction_iterator(&mut self) -> InsnIter {
+ let insns = take(&mut self.insns);
+ InsnIter {
+ old_insns_iter: insns.into_iter(),
+ peeked: None,
+ index: 0,
+ }
+ }
+
pub fn expect_leaf_ccall(&mut self, stack_size: usize) {
self.leaf_ccall_stack_size = Some(stack_size);
}
@@ -1998,6 +2007,44 @@ impl fmt::Debug for Assembler {
}
}
+pub struct InsnIter {
+ old_insns_iter: std::vec::IntoIter<Insn>,
+ peeked: Option<(usize, Insn)>,
+ index: usize,
+}
+
+impl InsnIter {
+ // We're implementing our own peek() because we don't want peek to
+ // cross basic blocks as we're iterating.
+ pub fn peek(&mut self) -> Option<&(usize, Insn)> {
+ // If we don't have a peeked value, get one
+ if self.peeked.is_none() {
+ let insn = self.old_insns_iter.next()?;
+ let idx = self.index;
+ self.index += 1;
+ self.peeked = Some((idx, insn));
+ }
+ // Return a reference to the peeked value
+ self.peeked.as_ref()
+ }
+
+ // Get the next instruction. Right now we're passing the "new" assembler
+ // (the assembler we're copying in to) as a parameter. Once we've
+ // introduced basic blocks to LIR, we'll use the to set the correct BB
+ // on the new assembler, but for now it is unused.
+ pub fn next(&mut self, _new_asm: &mut Assembler) -> Option<(usize, Insn)> {
+ // If we have a peeked value, return it
+ if let Some(item) = self.peeked.take() {
+ return Some(item);
+ }
+ // Otherwise get the next from underlying iterator
+ let insn = self.old_insns_iter.next()?;
+ let idx = self.index;
+ self.index += 1;
+ Some((idx, insn))
+ }
+}
+
impl Assembler {
#[must_use]
pub fn add(&mut self, left: Opnd, right: Opnd) -> Opnd {