1use std::collections::{BTreeMap, BTreeSet, VecDeque};
4use std::fmt;
5
6use crate::cfg::{ControlFlowGraph, ForwardControlFlowGraph};
7
8pub trait SsaCfg {
13 type FrontierIter<'a>: Iterator<Item = usize>
14 where
15 Self: 'a;
16
17 fn root(&self) -> usize;
18 fn predecessors(&self) -> &[Vec<usize>];
19 fn successors(&self) -> &[Vec<usize>];
20 fn dominator_children(&self) -> &[Vec<usize>];
21 fn dominance_frontier_len(&self) -> usize;
22 fn dominance_frontier(&self, block: usize) -> Self::FrontierIter<'_>;
23}
24
25impl SsaCfg for ControlFlowGraph {
26 type FrontierIter<'a> = std::iter::Copied<std::slice::Iter<'a, usize>>;
27
28 fn root(&self) -> usize {
29 self.root
30 }
31
32 fn predecessors(&self) -> &[Vec<usize>] {
33 &self.predecessors
34 }
35
36 fn successors(&self) -> &[Vec<usize>] {
37 &self.successors
38 }
39
40 fn dominator_children(&self) -> &[Vec<usize>] {
41 &self.dominators.children
42 }
43
44 fn dominance_frontier_len(&self) -> usize {
45 self.dominance_frontier.len()
46 }
47
48 fn dominance_frontier(&self, block: usize) -> Self::FrontierIter<'_> {
49 self.dominance_frontier[block].iter().copied()
50 }
51}
52
53impl SsaCfg for ForwardControlFlowGraph {
54 type FrontierIter<'a> = std::iter::Copied<std::slice::Iter<'a, usize>>;
55
56 fn root(&self) -> usize {
57 self.root
58 }
59
60 fn predecessors(&self) -> &[Vec<usize>] {
61 &self.predecessors
62 }
63
64 fn successors(&self) -> &[Vec<usize>] {
65 &self.successors
66 }
67
68 fn dominator_children(&self) -> &[Vec<usize>] {
69 &self.dominators.children
70 }
71
72 fn dominance_frontier_len(&self) -> usize {
73 self.dominance_frontier.len()
74 }
75
76 fn dominance_frontier(&self, block: usize) -> Self::FrontierIter<'_> {
77 self.dominance_frontier[block].iter().copied()
78 }
79}
80
81#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
82pub enum Version<V, D> {
83 Entry(V),
84 Definition { variable: V, definition: D },
85 Phi { variable: V, block: usize },
86}
87
88#[derive(Debug, Clone, Copy, PartialEq, Eq)]
89pub enum Event<V, D, U> {
90 Use { variable: V, usage: U },
91 Definition { variable: V, definition: D },
92}
93
94#[derive(Debug, Clone, PartialEq, Eq)]
95pub struct Phi<V, D> {
96 pub variable: V,
97 pub block: usize,
98 pub version: Version<V, D>,
99 pub inputs: Vec<(usize, Version<V, D>)>,
100}
101
102#[derive(Debug, Clone, PartialEq, Eq)]
103pub struct SparseSsa<V, D, U> {
104 pub phis: Vec<Phi<V, D>>,
105 pub phis_by_block: Vec<Vec<usize>>,
106 pub uses: BTreeMap<U, Version<V, D>>,
107}
108
109#[derive(Debug, Clone, PartialEq, Eq)]
110pub struct SsaError {
111 pub rule: &'static str,
112 pub block: Option<usize>,
113 pub message: String,
114}
115
116impl SsaError {
117 fn new(rule: &'static str, block: Option<usize>, message: impl Into<String>) -> Self {
118 Self {
119 rule,
120 block,
121 message: message.into(),
122 }
123 }
124}
125
126impl fmt::Display for SsaError {
127 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
128 write!(formatter, "{}", self.rule)?;
129 if let Some(block) = self.block {
130 write!(formatter, " at block {block}")?;
131 }
132 write!(formatter, ": {}", self.message)
133 }
134}
135
136impl std::error::Error for SsaError {}
137
138pub fn build<V, D, U>(
140 cfg: &impl SsaCfg,
141 events: &[Vec<Event<V, D, U>>],
142) -> Result<SparseSsa<V, D, U>, SsaError>
143where
144 V: Copy + Ord,
145 D: Copy + Ord,
146 U: Copy + Ord,
147{
148 let blocks = cfg.successors().len();
149 if events.len() != blocks
150 || cfg.predecessors().len() != blocks
151 || cfg.dominator_children().len() != blocks
152 || cfg.dominance_frontier_len() != blocks
153 {
154 return Err(SsaError::new(
155 "SSA.MODEL_SHAPE",
156 None,
157 "CFG and event tables do not cover the same block domain",
158 ));
159 }
160
161 let mut definitions = BTreeMap::<V, BTreeSet<usize>>::new();
162 let mut definition_ids = BTreeSet::<(V, D)>::new();
163 let mut upward_uses = BTreeMap::<V, Vec<usize>>::new();
164 let mut usage_ids = BTreeSet::<U>::new();
165 for (block, block_events) in events.iter().enumerate() {
166 let mut locally_defined = BTreeSet::<V>::new();
167 for event in block_events {
168 match *event {
169 Event::Use { variable, usage } => {
170 if !usage_ids.insert(usage) {
171 return Err(SsaError::new(
172 "SSA.USE_IDENTITY",
173 Some(block),
174 "one use identity occurs more than once",
175 ));
176 }
177 if !locally_defined.contains(&variable) {
178 let uses = upward_uses.entry(variable).or_default();
179 if uses.last().copied() != Some(block) {
180 uses.push(block);
181 }
182 }
183 }
184 Event::Definition {
185 variable,
186 definition,
187 } => {
188 if !definition_ids.insert((variable, definition)) {
189 return Err(SsaError::new(
190 "SSA.DEFINITION_IDENTITY",
191 Some(block),
192 "one variable-definition identity occurs more than once",
193 ));
194 }
195 locally_defined.insert(variable);
196 definitions.entry(variable).or_default().insert(block);
197 }
198 }
199 }
200 }
201
202 drop(definition_ids);
203 let mut defined = vec![0usize; blocks];
207 let mut live_in = vec![0usize; blocks];
208 let mut queued = vec![0usize; blocks];
209 let mut work = VecDeque::new();
210 let mut phi_pairs = BTreeSet::<(usize, V)>::new();
211 for (index, (&variable, original_definitions)) in definitions.iter().enumerate() {
212 let Some(uses) = upward_uses.get(&variable) else {
213 continue;
214 };
215 let generation = index + 1;
216 for &block in original_definitions {
217 defined[block] = generation;
218 }
219 for &block in uses {
220 live_in[block] = generation;
221 work.push_back(block);
222 }
223 while let Some(block) = work.pop_front() {
224 for &predecessor in &cfg.predecessors()[block] {
225 if defined[predecessor] != generation && live_in[predecessor] != generation {
226 live_in[predecessor] = generation;
227 work.push_back(predecessor);
228 }
229 }
230 }
231 for &block in original_definitions {
232 queued[block] = generation;
233 work.push_back(block);
234 }
235 while let Some(definition) = work.pop_front() {
236 for frontier in cfg.dominance_frontier(definition) {
237 if live_in[frontier] != generation || !phi_pairs.insert((frontier, variable)) {
238 continue;
239 }
240 if queued[frontier] != generation {
241 queued[frontier] = generation;
242 work.push_back(frontier);
243 }
244 }
245 }
246 }
247 drop((defined, live_in, queued, work, definitions, upward_uses));
248
249 let mut phis = Vec::<Phi<V, D>>::with_capacity(phi_pairs.len());
250 let mut phis_by_block = vec![Vec::<usize>::new(); blocks];
251 for (block, variable) in phi_pairs {
252 let phi = phis.len();
253 phis.push(Phi {
254 variable,
255 block,
256 version: Version::Phi { variable, block },
257 inputs: Vec::with_capacity(cfg.predecessors()[block].len()),
258 });
259 phis_by_block[block].push(phi);
260 }
261
262 enum Action<V, D> {
263 Enter(usize),
264 Exit(Vec<(V, Option<Version<V, D>>)>),
265 }
266 let mut current = BTreeMap::<V, Version<V, D>>::new();
267 let mut uses = BTreeMap::<U, Version<V, D>>::new();
268 let mut actions = vec![Action::Enter(cfg.root())];
269 while let Some(action) = actions.pop() {
270 let block = match action {
271 Action::Exit(changes) => {
272 for (variable, previous) in changes.into_iter().rev() {
273 if let Some(previous) = previous {
274 current.insert(variable, previous);
275 } else {
276 current.remove(&variable);
277 }
278 }
279 continue;
280 }
281 Action::Enter(block) => block,
282 };
283 let mut changes = Vec::new();
284 for &phi in &phis_by_block[block] {
285 let variable = phis[phi].variable;
286 changes.push((variable, current.insert(variable, phis[phi].version)));
287 }
288 for event in &events[block] {
289 match *event {
290 Event::Use { variable, usage } => {
291 let version = current
292 .get(&variable)
293 .copied()
294 .unwrap_or(Version::Entry(variable));
295 if uses.insert(usage, version).is_some() {
296 return Err(SsaError::new(
297 "SSA.USE_RENAME",
298 Some(block),
299 "dominator rename visited one use more than once",
300 ));
301 }
302 }
303 Event::Definition {
304 variable,
305 definition,
306 } => {
307 let version = Version::Definition {
308 variable,
309 definition,
310 };
311 changes.push((variable, current.insert(variable, version)));
312 }
313 }
314 }
315 for &successor in &cfg.successors()[block] {
316 for &phi in &phis_by_block[successor] {
317 let variable = phis[phi].variable;
318 let version = current
319 .get(&variable)
320 .copied()
321 .unwrap_or(Version::Entry(variable));
322 phis[phi].inputs.push((block, version));
323 }
324 }
325 actions.push(Action::Exit(changes));
326 actions.extend(
327 cfg.dominator_children()[block]
328 .iter()
329 .rev()
330 .copied()
331 .map(Action::Enter),
332 );
333 }
334
335 if uses.len() != usage_ids.len() {
336 return Err(SsaError::new(
337 "SSA.USE_COVERAGE",
338 None,
339 "dominator rename did not visit every use",
340 ));
341 }
342 for phi in &mut phis {
343 phi.inputs
344 .sort_unstable_by_key(|(predecessor, _)| *predecessor);
345 if phi.inputs.len() != cfg.predecessors()[phi.block].len()
346 || phi
347 .inputs
348 .iter()
349 .zip(&cfg.predecessors()[phi.block])
350 .any(|((actual, _), expected)| actual != expected)
351 {
352 return Err(SsaError::new(
353 "SSA.PHI_INPUTS",
354 Some(phi.block),
355 "phi inputs do not cover every CFG predecessor exactly once",
356 ));
357 }
358 }
359
360 Ok(SparseSsa {
361 phis,
362 phis_by_block,
363 uses,
364 })
365}
366
367#[cfg(test)]
368mod tests {
369 use super::*;
370
371 #[test]
372 fn overlapping_variable_lifetimes_preserve_loop_and_local_definition_semantics() {
373 let cfg = ControlFlowGraph::analyze(
374 vec![vec![1, 2], vec![3], vec![3], vec![4, 5], vec![3], vec![]],
375 0,
376 )
377 .unwrap();
378 let (a, b, entry_only, carried) = (3usize, 17usize, usize::MAX - 1, usize::MAX);
379 let definition = |variable, definition| Event::Definition {
380 variable,
381 definition,
382 };
383 let usage = |variable, usage| Event::Use { variable, usage };
384 let events = vec![
385 vec![definition(a, 100), definition(b, 200)],
386 vec![definition(a, 101)],
387 vec![definition(b, 202)],
388 vec![
389 usage(a, 300),
390 usage(carried, 301),
391 definition(b, 203),
392 definition(carried, 303),
393 ],
394 vec![definition(a, 104), usage(b, 400)],
395 vec![usage(a, 500), usage(entry_only, 501), usage(carried, 502)],
396 ];
397 let ssa = build(&cfg, &events).unwrap();
398 assert_eq!(ssa.phis.len(), 2);
399 assert_eq!(ssa.phis[0].variable, a);
400 assert_eq!(ssa.phis[0].block, 3);
401 assert_eq!(
402 ssa.phis[0].inputs,
403 vec![
404 (
405 1,
406 Version::Definition {
407 variable: a,
408 definition: 101
409 }
410 ),
411 (
412 2,
413 Version::Definition {
414 variable: a,
415 definition: 100
416 }
417 ),
418 (
419 4,
420 Version::Definition {
421 variable: a,
422 definition: 104
423 }
424 ),
425 ]
426 );
427 assert_eq!(ssa.phis[1].variable, carried);
428 assert_eq!(ssa.phis[1].block, 3);
429 assert_eq!(
430 ssa.phis[1].inputs,
431 vec![
432 (1, Version::Entry(carried)),
433 (2, Version::Entry(carried)),
434 (
435 4,
436 Version::Definition {
437 variable: carried,
438 definition: 303
439 }
440 ),
441 ]
442 );
443 assert_eq!(
444 ssa.uses[&300],
445 Version::Phi {
446 variable: a,
447 block: 3
448 }
449 );
450 assert_eq!(ssa.uses[&500], ssa.uses[&300]);
451 assert_eq!(
452 ssa.uses[&301],
453 Version::Phi {
454 variable: carried,
455 block: 3
456 }
457 );
458 assert_eq!(
459 ssa.uses[&400],
460 Version::Definition {
461 variable: b,
462 definition: 203
463 }
464 );
465 assert_eq!(ssa.uses[&501], Version::Entry(entry_only));
466 assert_eq!(
467 ssa.uses[&502],
468 Version::Definition {
469 variable: carried,
470 definition: 303
471 }
472 );
473 }
474
475 #[test]
476 fn many_live_variables_in_a_long_chain_reach_their_entry_definitions() {
477 let blocks = 256;
478 let cfg = ControlFlowGraph::analyze(
479 (0..blocks)
480 .map(|block| {
481 if block + 1 == blocks {
482 vec![]
483 } else {
484 vec![block + 1]
485 }
486 })
487 .collect(),
488 0,
489 )
490 .unwrap();
491 let mut events = vec![Vec::new(); blocks];
492 for usage in 0..128 {
493 let variable = usize::MAX - usage;
494 events[0].push(Event::Definition {
495 variable,
496 definition: 0,
497 });
498 events[blocks - 1].push(Event::Use { variable, usage });
499 }
500 let ssa = build(&cfg, &events).unwrap();
501 assert!(ssa.phis.is_empty());
502 assert_eq!(ssa.uses.len(), 128);
503 for usage in 0..128 {
504 assert_eq!(
505 ssa.uses[&usage],
506 Version::Definition {
507 variable: usize::MAX - usage,
508 definition: 0
509 }
510 );
511 }
512 }
513
514 #[test]
515 fn branch_definitions_create_one_live_join_phi() {
516 let cfg = ControlFlowGraph::analyze(vec![vec![1, 2], vec![3], vec![3], vec![]], 0).unwrap();
517 let events = vec![
518 vec![],
519 vec![Event::Definition {
520 variable: 7,
521 definition: 10,
522 }],
523 vec![Event::Definition {
524 variable: 7,
525 definition: 20,
526 }],
527 vec![Event::Use {
528 variable: 7,
529 usage: 30,
530 }],
531 ];
532
533 let ssa = build(&cfg, &events).unwrap();
534
535 assert_eq!(ssa.phis.len(), 1);
536 assert_eq!(ssa.phis[0].block, 3);
537 assert_eq!(ssa.phis[0].inputs.len(), 2);
538 assert_eq!(
539 ssa.uses[&30],
540 Version::Phi {
541 variable: 7,
542 block: 3
543 }
544 );
545 }
546
547 #[test]
548 fn dead_join_does_not_receive_a_phi() {
549 let cfg = ControlFlowGraph::analyze(vec![vec![1, 2], vec![3], vec![3], vec![]], 0).unwrap();
550 let events = vec![
551 vec![],
552 vec![Event::Definition {
553 variable: 7,
554 definition: 10,
555 }],
556 vec![Event::Definition {
557 variable: 7,
558 definition: 20,
559 }],
560 vec![],
561 ];
562
563 let ssa = build::<_, _, usize>(&cfg, &events).unwrap();
564
565 assert!(ssa.phis.is_empty());
566 }
567
568 #[test]
569 fn loop_use_observes_header_phi() {
570 let cfg = ControlFlowGraph::analyze(vec![vec![1], vec![2, 3], vec![1], vec![]], 0).unwrap();
571 let events = vec![
572 vec![Event::Definition {
573 variable: 1,
574 definition: 0,
575 }],
576 vec![Event::Use {
577 variable: 1,
578 usage: 10,
579 }],
580 vec![Event::Definition {
581 variable: 1,
582 definition: 20,
583 }],
584 vec![],
585 ];
586
587 let ssa = build(&cfg, &events).unwrap();
588
589 assert_eq!(
590 ssa.uses[&10],
591 Version::Phi {
592 variable: 1,
593 block: 1
594 }
595 );
596 assert_eq!(ssa.phis[0].inputs.len(), 2);
597 }
598
599 #[test]
600 fn same_block_uses_observe_event_order() {
601 let cfg = ControlFlowGraph::analyze(vec![vec![]], 0).unwrap();
602 let events = vec![vec![
603 Event::Use {
604 variable: 1,
605 usage: 1,
606 },
607 Event::Definition {
608 variable: 1,
609 definition: 2,
610 },
611 Event::Use {
612 variable: 1,
613 usage: 3,
614 },
615 ]];
616
617 let ssa = build(&cfg, &events).unwrap();
618
619 assert_eq!(ssa.uses[&1], Version::Entry(1));
620 assert_eq!(
621 ssa.uses[&3],
622 Version::Definition {
623 variable: 1,
624 definition: 2
625 }
626 );
627 }
628}