diff options
| author | Aaron Patterson <tenderlove@ruby-lang.org> | 2025-11-24 16:16:08 -0800 |
|---|---|---|
| committer | Aaron Patterson <aaron.patterson@gmail.com> | 2025-12-03 13:37:40 -0800 |
| commit | 2b23b05bf2c0f30f2c4ee9bb3030fa58f2cba3a6 (patch) | |
| tree | 94e2b1795beeeca7917940d46656ace756f07d7d | |
| parent | a773bbf0cc35cd4b73509edd58a0757d06abaca6 (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.rs | 47 |
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 { |
