Skip to main content

swamp_code_gen/
reg_pool.rs

1/*
2 * Copyright (c) Peter Bjorklund. All rights reserved. https://github.com/swamp/swamp
3 * Licensed under the MIT License. See LICENSE in the project root for license information.
4 */
5use std::fmt::{Debug, Display, Formatter};
6use swamp_vm_types::types::{TypedRegister, VmType};
7
8#[derive(Debug)]
9pub struct TempRegister {
10    pub(crate) register: TypedRegister,
11}
12
13impl Display for TempRegister {
14    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
15        write!(f, "{}", self.register)
16    }
17}
18
19impl TempRegister {
20    pub(crate) const fn register(&self) -> &TypedRegister {
21        &self.register
22    }
23    #[must_use]
24    pub const fn addressing(&self) -> u8 {
25        self.register.addressing()
26    }
27}
28
29#[derive(Debug)]
30pub struct RegisterInfo {
31    pub index: u8,
32}
33
34pub struct HwmTempRegisterPool {
35    start_index: u8,
36    capacity: u8,
37    num_allocated: u8,
38}
39
40impl Debug for HwmTempRegisterPool {
41    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
42        if self.num_allocated == 0 {
43            write!(f, "hwm(no protected)")
44        } else {
45            write!(
46                f,
47                "hwm({}-{})",
48                self.start_index,
49                self.start_index + self.num_allocated - 1
50            )
51        }
52    }
53}
54
55impl HwmTempRegisterPool {
56    /// # Panics
57    ///
58    #[must_use]
59    pub fn new(start: u8, count: usize) -> Self {
60        if count == 0 {
61            return Self {
62                start_index: start,
63                capacity: 0,
64                num_allocated: 0,
65            };
66        }
67        assert!(
68            count <= u8::MAX as usize + 1,
69            "Register count too large for u8 capacity"
70        );
71        assert!(
72            start.checked_add((count - 1) as u8).is_some(),
73            "Register index range would overflow u8"
74        );
75
76        Self {
77            start_index: start,
78            capacity: count as u8,
79            num_allocated: 0, // Initially, no registers are allocated
80        }
81    }
82
83    pub(crate) const fn start_index_and_number_of_allocated(&self) -> (u8, u8) {
84        (self.start_index, self.num_allocated)
85    }
86
87    /// # Panics
88    /// if out of registers
89    pub fn allocate(&mut self, ty: VmType, comment: &str) -> TempRegister {
90        assert!(
91            (self.num_allocated < self.capacity),
92            "HwmTempRegisterPool: Out of temporary registers, capacity: {}. Requested for: '{comment}'", self.capacity
93        );
94
95
96        let register_index = self.start_index + self.num_allocated;
97        self.num_allocated += 1;
98        //info!("temp register hwm {}", self.num_allocated);
99
100        TempRegister {
101            register: TypedRegister {
102                index: register_index,
103                ty,
104                comment: comment.to_string(),
105            },
106        }
107    }
108
109    #[must_use]
110    pub const fn save_mark(&self) -> u8 {
111        self.num_allocated
112    }
113
114    /// # Panics
115    ///
116    pub fn restore_to_mark(&mut self, mark: u8) {
117        // TODO: add a check that we aren't using marks in the pinned range
118        assert!(
119            (mark <= self.num_allocated),
120            "HwmTempRegisterPool: Invalid mark {} provided. Current allocation count is {}.",
121            mark,
122            self.num_allocated
123        );
124
125        self.num_allocated = mark;
126    }
127}
128
129#[derive(Debug)]
130pub struct RegisterPool {
131    pub start_index: u8,
132    pub end_index: u8,
133    pub current_index: u8,
134}
135
136impl RegisterPool {
137    #[must_use]
138    pub const fn new(start: u8, count: u8) -> Self {
139        Self {
140            start_index: start,
141            end_index: start + count,
142            current_index: start,
143        }
144    }
145
146    /// # Panics
147    ///
148    pub fn alloc_register(&mut self, ty: VmType, comment: &str) -> TypedRegister {
149        assert!(
150            self.current_index < self.end_index,
151            "out of registers {} {}",
152            self.current_index,
153            self.end_index
154        );
155        let allocated_register = self.current_index;
156        self.current_index += 1;
157        TypedRegister {
158            index: allocated_register,
159            ty,
160            comment: comment.to_string(),
161        }
162    }
163}