1#[cfg(feature = "program-image-execution")]
26mod dialect;
27
28#[cfg(feature = "program-image-execution")]
29pub use dialect::program;
30
31#[cfg(feature = "program-image-execution")]
32mod literal;
33
34#[cfg(feature = "program-image-execution")]
35pub mod lower;
36
37#[cfg(feature = "program-image-execution")]
38pub mod operand;
39
40use vihaco_abi::{Type, Value};
41use vihaco_bytecode::{ConstantId, ContextHandle};
42use vihaco_module::{
43 host::{GetProgramInfo, ProgramCounter},
44 module::{LocalModule, NoInfo},
45};
46
47#[derive(Debug, Clone)]
49pub struct ProgramImage<I, C, V = Value, Ty = Type, Info = NoInfo> {
50 pub module: LocalModule<I, V, Ty, Info>,
51 pub context: Option<ContextHandle<C>>,
52 pub pc: u32,
53}
54
55impl<I, C, V, Ty, Info: Default> Default for ProgramImage<I, C, V, Ty, Info> {
56 fn default() -> Self {
57 Self {
58 module: LocalModule::default(),
59 context: None,
60 pc: 0,
61 }
62 }
63}
64
65impl<I, C, V, Ty, Info> ProgramImage<I, C, V, Ty, Info> {
66 pub fn new() -> Self
67 where
68 Info: Default,
69 {
70 Self::default()
71 }
72
73 pub fn with_extra(extra: Info) -> Self {
74 Self {
75 module: LocalModule {
76 code: Vec::new(),
77 functions: Vec::new(),
78 labels: Vec::new(),
79 constants: Vec::new(),
80 strings: Vec::new(),
81 main_function: None,
82 source_symbols: Vec::new(),
83 extra,
84 },
85 context: None,
86 pc: 0,
87 }
88 }
89
90 pub fn context(&self) -> eyre::Result<&C> {
91 self.context
92 .as_ref()
93 .map(ContextHandle::get)
94 .ok_or_else(|| eyre::eyre!("program image has not been loaded with a context"))
95 }
96}
97
98impl<I, C, V, Ty, Info> ProgramCounter for ProgramImage<I, C, V, Ty, Info> {
99 type Instruction = I;
100
101 fn pc(&self) -> u32 {
102 self.pc
103 }
104
105 fn pc_mut(&mut self) -> &mut u32 {
106 &mut self.pc
107 }
108
109 fn get_instruction(&self, pc: u32) -> eyre::Result<&Self::Instruction> {
110 self.module.code.get(pc as usize).ok_or_else(|| {
111 eyre::eyre!(format!(
112 "program counter out of bounds: {} (max {})",
113 pc,
114 self.module.code.len()
115 ))
116 })
117 }
118}
119
120impl<I, C, V, Ty, Info> GetProgramInfo for ProgramImage<I, C, V, Ty, Info>
121where
122 Ty: Clone,
123{
124 type Type = Ty;
125 type Value = V;
126
127 fn get_function(
128 &self,
129 index: usize,
130 ) -> eyre::Result<vihaco_module::module::FunctionInfo<Self::Type>> {
131 self.module.functions.get(index).cloned().ok_or_else(|| {
132 eyre::eyre!(format!(
133 "function index out of bounds: {} (max {})",
134 index,
135 self.module.functions.len()
136 ))
137 })
138 }
139
140 fn get_string(&self, index: usize) -> eyre::Result<&String> {
141 self.module.strings.get(index).ok_or_else(|| {
142 eyre::eyre!(format!(
143 "string index out of bounds: {} (max {})",
144 index,
145 self.module.strings.len()
146 ))
147 })
148 }
149
150 fn get_constant(&self, id: ConstantId) -> eyre::Result<&Self::Value> {
151 self.module.constants.get(id.0 as usize).ok_or_else(|| {
152 eyre::eyre!(format!(
153 "constant index out of bounds: {} (max {})",
154 id.0,
155 self.module.constants.len()
156 ))
157 })
158 }
159}
160
161#[cfg(all(
162 feature = "typed-declarations",
163 not(feature = "program-image-execution")
164))]
165impl<I, C, V, Ty, Info> vihaco_cpu::lower::StringIntern for ProgramImage<I, C, V, Ty, Info> {
166 fn intern_string(&mut self, value: &str) -> eyre::Result<u32> {
167 if let Some(index) = self
168 .module
169 .strings
170 .iter()
171 .position(|existing| existing == value)
172 {
173 return Ok(u32::try_from(index)?);
174 }
175 let index = u32::try_from(self.module.strings.len())?;
176 self.module.strings.push(value.to_owned());
177 Ok(index)
178 }
179}