fidget_core/compiler/
reg_tape.rs

1//! Tape used for evaluation
2use crate::compiler::{RegOp, RegisterAllocator, SsaTape};
3use serde::{Deserialize, Serialize};
4
5/// Low-level tape for use with the Fidget virtual machine (or to be lowered
6/// further into machine instructions).
7#[derive(Clone, Default, Serialize, Deserialize)]
8pub struct RegTape {
9    tape: Vec<RegOp>,
10
11    /// Total allocated slots
12    pub(super) slot_count: u32,
13}
14
15impl RegTape {
16    /// Lowers the tape to assembly with a particular register limit
17    ///
18    /// Note that if you _also_ want to simplify the tape, it's more efficient
19    /// to use [`VmData::simplify`](crate::vm::VmData::simplify), which
20    /// simultaneously simplifies **and** performs register allocation in a
21    /// single pass.
22    pub fn new<const N: usize>(ssa: &SsaTape) -> Self {
23        let mut alloc = RegisterAllocator::<N>::new(ssa.len());
24        for &op in ssa.iter() {
25            alloc.op(op)
26        }
27        alloc.finalize()
28    }
29
30    /// Builds a new empty tape
31    pub(crate) fn empty() -> Self {
32        Self {
33            tape: vec![],
34            slot_count: 0,
35        }
36    }
37
38    /// Resets this tape, retaining its allocations
39    pub fn reset(&mut self) {
40        self.tape.clear();
41        self.slot_count = 0;
42    }
43
44    /// Returns the number of unique register and memory locations that are used
45    /// by this tape.
46    #[inline]
47    pub fn slot_count(&self) -> usize {
48        self.slot_count as usize
49    }
50    /// Returns the number of elements in the tape
51    #[inline]
52    pub fn len(&self) -> usize {
53        self.tape.len()
54    }
55    /// Returns `true` if the tape contains no elements
56    #[inline]
57    pub fn is_empty(&self) -> bool {
58        self.tape.is_empty()
59    }
60    /// Returns a front-to-back iterator
61    ///
62    /// This is the opposite of evaluation order; it will visit the root of the
63    /// tree first, and end at the leaves.
64    #[inline]
65    pub fn iter(&self) -> impl DoubleEndedIterator<Item = &RegOp> {
66        self.into_iter()
67    }
68    #[inline]
69    pub(crate) fn push(&mut self, op: RegOp) {
70        self.tape.push(op)
71    }
72}
73
74impl<'a> IntoIterator for &'a RegTape {
75    type Item = &'a RegOp;
76    type IntoIter = std::slice::Iter<'a, RegOp>;
77    fn into_iter(self) -> Self::IntoIter {
78        self.tape.iter()
79    }
80}