1use crate::global::Global;
2use crate::internal::commas;
3use crate::{Assign, BlockId, Constant, Error, Phi, StaticId, Term, Value, Var};
4use std::cell::{Cell, RefCell};
5use std::collections::{BTreeMap, VecDeque};
6use std::fmt;
7use std::rc::Rc;
8
9macro_rules! block_unary_op {
11 ($new:ident, $assign:ident, $variant:ident, $doc:literal) => {
12 #[doc = $doc]
13 pub fn $new(&self, a: Var) -> Result<Var, Error> {
14 let a = self.read(a)?;
15 self.assign_new(Value::$variant(a))
16 }
17
18 #[doc = $doc]
19 pub fn $assign(&self, id: Var, a: Var) -> Result<(), Error> {
20 let a = self.read(a)?;
21 self.assign_value(id, Value::$variant(a))?;
22 Ok(())
23 }
24 };
25}
26
27macro_rules! block_binary_op {
29 ($new:ident, $assign:ident, $variant:ident, $doc:literal) => {
30 #[doc = $doc]
31 pub fn $new(&self, a: Var, b: Var) -> Result<Var, Error> {
32 let a = self.read(a)?;
33 let b = self.read(b)?;
34 self.assign_new(Value::$variant(a, b))
35 }
36
37 #[doc = $doc]
38 pub fn $assign(&self, id: Var, a: Var, b: Var) -> Result<(), Error> {
39 let a = self.read(a)?;
40 let b = self.read(b)?;
41 self.assign_value(id, Value::$variant(a, b))?;
42 Ok(())
43 }
44 };
45}
46
47#[derive(Clone)]
52pub struct Block {
53 inner: Rc<BlockInner>,
54}
55
56impl Block {
57 pub(crate) fn new(id: BlockId, global: Global, name: Option<Box<str>>) -> Self {
59 Self {
60 inner: Rc::new(BlockInner {
61 id,
62 inputs: Cell::new(0),
63 name,
64 global,
65 open: Cell::new(true),
66 vars: RefCell::new(BTreeMap::new()),
67 incomplete: RefCell::new(Vec::new()),
68 term: RefCell::new(Term::Panic),
69 ancestors: RefCell::new(Vec::new()),
70 }),
71 }
72 }
73
74 pub fn name(&self) -> Option<&str> {
76 self.inner.name.as_deref()
77 }
78
79 pub fn read(&self, var: Var) -> Result<Assign, Error> {
82 if let Some(assign) = self.inner.vars.borrow().get(&var) {
84 return Ok(assign.clone());
85 }
86
87 let id = self.inner.global.static_id();
88 let assign = Assign::new(id, self.id());
89
90 self.inner
91 .global
92 .values_mut()
93 .insert(id, Value::Phi(Phi::new()));
94
95 self.inner.vars.borrow_mut().insert(var, assign.clone());
96
97 if self.inner.open.get() {
98 self.inner
99 .incomplete
100 .borrow_mut()
101 .push((assign.clone(), var));
102 } else {
103 self.add_phi(id, var)?;
104 }
105
106 Ok(assign)
107 }
108
109 fn read_dependencies(&self, var: Var) -> Result<Vec<Assign>, Error> {
111 let blocks = self.inner.global.blocks();
112 let mut deps = Vec::new();
113
114 let mut queue = VecDeque::new();
115
116 for ancestor in &*self.inner.ancestors.borrow() {
117 queue.push_back(blocks.get(*ancestor)?);
118 }
119
120 while let Some(block) = queue.pop_front() {
121 if let Some(assign) = block.inner.vars.borrow().get(&var) {
122 deps.push(assign.clone());
123 continue;
124 }
125
126 for ancestor in &*block.inner.ancestors.borrow() {
127 queue.push_back(blocks.get(*ancestor)?);
128 }
129 }
130
131 Ok(deps)
132 }
133
134 fn assign_new(&self, value: Value) -> Result<Var, Error> {
136 let var = self.inner.global.var();
137 self.assign_value(var, value)?;
138 Ok(var)
139 }
140
141 fn assign_value(&self, id: Var, value: Value) -> Result<(), Error> {
143 self.inner.assign(id, value)?;
144 Ok(())
145 }
146
147 pub fn assign(&self, var: Var, to_read: Var) -> Result<(), Error> {
149 let assign = self.read(to_read)?;
150 self.inner.vars.borrow_mut().insert(var, assign);
151 Ok(())
152 }
153
154 pub fn input(&self) -> Result<Var, Error> {
156 let id = self.inner.global.var();
157 let input = self.inner.inputs.get();
158 self.inner.inputs.set(input + 1);
159 self.assign_value(id, Value::Input(input))?;
160 Ok(id)
161 }
162
163 pub(crate) fn seal(&self) -> Result<(), Error> {
165 let open = self.inner.open.take();
166
167 if open {
168 let incomplete = std::mem::take(&mut *self.inner.incomplete.borrow_mut());
169
170 for (assign, var_to_read) in incomplete {
171 self.add_phi(assign.id(), var_to_read)?;
172 }
173 }
174
175 Ok(())
176 }
177
178 fn add_phi(&self, id: StaticId, var_to_read: Var) -> Result<(), Error> {
180 let deps = self.read_dependencies(var_to_read)?;
181
182 if deps.len() <= 1 {
183 if let Some(assign) = deps.into_iter().next() {
184 if let Some(Value::Phi(..)) = self.inner.global.values_mut().remove(id) {
185 let old = self
186 .inner
187 .vars
188 .borrow_mut()
189 .insert(var_to_read, assign.clone());
190
191 if let Some(existing) = old {
192 existing.replace(&assign);
193 }
194
195 return Ok(());
196 }
197 }
198 } else {
199 if let Some(Value::Phi(phi)) = self.inner.global.values_mut().get_mut(id) {
200 phi.extend(deps);
201 return Ok(());
202 }
203 }
204
205 Err(Error::MissingPhiNode(id))
206 }
207
208 #[inline]
210 pub fn id(&self) -> BlockId {
211 self.inner.id
212 }
213
214 #[inline]
216 pub fn dump(&self) -> BlockDump<'_> {
217 BlockDump(self)
218 }
219
220 pub fn unit(&self) -> Result<Var, Error> {
222 self.constant(Constant::Unit)
223 }
224
225 pub fn assign_unit(&self, id: Var) -> Result<(), Error> {
227 self.assign_constant(id, Constant::Unit)?;
228 Ok(())
229 }
230
231 pub fn constant(&self, constant: Constant) -> Result<Var, Error> {
233 let const_id = self.inner.global.constant(constant);
234 self.assign_new(Value::Const(const_id))
235 }
236
237 pub fn assign_constant(&self, id: Var, constant: Constant) -> Result<(), Error> {
239 let const_id = self.inner.global.constant(constant);
240 self.assign_value(id, Value::Const(const_id))?;
241 Ok(())
242 }
243
244 block_unary_op!(not, assign_not, Not, "Compute `!arg`.");
245 block_binary_op!(add, assign_add, Add, "Compute `lhs + rhs`.");
246 block_binary_op!(sub, assign_sub, Sub, "Compute `lhs - rhs`.");
247 block_binary_op!(div, assign_div, Div, "Compute `lhs / rhs`.");
248 block_binary_op!(mul, assign_mul, Mul, "Compute `lhs * rhs`.");
249 block_binary_op!(cmp_lt, assign_cmp_lt, CmpLt, "Compare if `lhs < rhs`.");
250 block_binary_op!(cmp_lte, assign_cmp_lte, CmpLte, "Compare if `lhs <= rhs`.");
251 block_binary_op!(cmp_eq, assign_cmp_eq, CmpEq, "Compare if `lhs == rhs`.");
252 block_binary_op!(cmp_gt, assign_cmp_gt, CmpGt, "Compare if `lhs > rhs`.");
253 block_binary_op!(cmp_gte, assign_cmp_gte, CmpGte, "Compare if `lhs >= rhs`.");
254
255 pub fn jump(&self, block: &Block) -> Result<(), Error> {
258 self.mark_control(block)?;
259
260 *self.inner.term.borrow_mut() = Term::Jump { block: block.id() };
261 Ok(())
262 }
263
264 pub fn jump_if(
267 &self,
268 condition: Var,
269 then_block: &Block,
270 else_block: &Block,
271 ) -> Result<(), Error> {
272 let condition = self.read(condition)?;
273
274 self.mark_control(then_block)?;
275 self.mark_control(else_block)?;
276
277 *self.inner.term.borrow_mut() = Term::JumpIf {
278 condition,
279 then_block: then_block.id(),
280 else_block: else_block.id(),
281 };
282
283 Ok(())
284 }
285
286 pub fn return_unit(&self) -> Result<(), Error> {
288 let var = self.unit()?;
289 let var = self.read(var)?;
290
291 *self.inner.term.borrow_mut() = Term::Return { var };
292 self.inner.global.mark_return(self.id());
293 Ok(())
294 }
295
296 pub fn return_(&self, var: Var) -> Result<(), Error> {
298 let var = self.read(var)?;
299
300 *self.inner.term.borrow_mut() = Term::Return { var };
301 self.inner.global.mark_return(self.id());
302 Ok(())
303 }
304
305 fn mark_control(&self, other: &Self) -> Result<(), Error> {
306 if !other.inner.open.get() {
307 return Err(Error::SealedBlockJump(self.id(), other.inner.id));
308 }
309
310 other.inner.ancestors.borrow_mut().push(self.id());
311 Ok(())
312 }
313}
314
315pub struct BlockDump<'a>(&'a Block);
316
317impl fmt::Display for BlockDump<'_> {
318 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
319 let ancestors = self.0.inner.ancestors.borrow();
320
321 write!(f, "{}", self.0.id())?;
322
323 if self.0.inner.open.get() {
324 write!(f, " (open)")?;
325 }
326
327 if ancestors.is_empty() {
328 write!(f, ":")?;
329 } else {
330 write!(f, ": {}", commas(&ancestors[..]))?;
331 }
332
333 if let Some(name) = &self.0.inner.name {
334 write!(f, " // {}", name)?;
335 }
336
337 writeln!(f)?;
338
339 for (var, assign) in self.0.inner.vars.borrow().iter() {
340 if let Some(value) = self.0.inner.global.values().get(assign.id()) {
341 writeln!(f, " {}: {} <- {}", var, assign, value.dump())?;
342 } else {
343 writeln!(f, " {}: {} <- ?", var, assign)?;
344 }
345 }
346
347 writeln!(f, " {}", self.0.inner.term.borrow().dump())?;
348 Ok(())
349 }
350}
351
352struct BlockInner {
353 id: BlockId,
355 inputs: Cell<usize>,
357 open: Cell<bool>,
361 name: Option<Box<str>>,
363 global: Global,
365 vars: RefCell<BTreeMap<Var, Assign>>,
367 incomplete: RefCell<Vec<(Assign, Var)>>,
369 term: RefCell<Term>,
371 ancestors: RefCell<Vec<BlockId>>,
373}
374
375impl BlockInner {
376 fn assign(&self, var: Var, value: Value) -> Result<(), Error> {
378 let id = self.global.static_id();
379 self.vars.borrow_mut().insert(var, Assign::new(id, self.id));
380 self.global.values_mut().insert(id, value);
381 Ok(())
382 }
383}