1use std::collections::{HashMap, HashSet};
41
42use rucc_base::Idx;
43use rucc_diag::Span;
44use rucc_ir::{Block, BlockCall, Extra, Func, Imm, Inst, InstData, Opcode, Type, Value};
45
46#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
51pub struct Var(u32);
52
53impl Var {
54 #[must_use]
56 pub const fn new(raw: u32) -> Var {
57 Var(raw)
58 }
59
60 #[must_use]
62 pub const fn raw(self) -> u32 {
63 self.0
64 }
65}
66
67#[derive(Clone, Copy, Debug, PartialEq, Eq)]
74struct Edge {
75 from: Block,
76 call: Idx<BlockCall>,
77}
78
79#[derive(Clone, Copy, Debug, PartialEq, Eq)]
81struct Phi {
82 block: Block,
83 var: Var,
84}
85
86#[derive(Debug)]
88pub struct Ssa {
89 address: Type,
91 defs: HashMap<(Var, Block), Value>,
93 sealed: Vec<bool>,
95 incomplete: Vec<Vec<(Var, Value)>>,
97 preds: Vec<Vec<Edge>>,
99 phis: HashMap<Value, Phi>,
101 users: HashMap<Value, Vec<Value>>,
104 subst: HashMap<Value, Value>,
106 zero: Vec<(Type, Value)>,
108 named: HashMap<Var, u32>,
110 holds: Vec<(Value, u32)>,
112 owned: HashSet<Value>,
115}
116
117impl Ssa {
118 #[must_use]
125 pub fn new(address: Type) -> Ssa {
126 Ssa {
127 address,
128 defs: HashMap::new(),
129 sealed: Vec::new(),
130 incomplete: Vec::new(),
131 preds: Vec::new(),
132 phis: HashMap::new(),
133 users: HashMap::new(),
134 subst: HashMap::new(),
135 zero: Vec::new(),
136 named: HashMap::new(),
137 holds: Vec::new(),
138 owned: HashSet::new(),
139 }
140 }
141
142 pub fn stands_for(&mut self, var: Var, decl: u32) {
149 self.named.insert(var, decl);
150 }
151
152 pub fn write(&mut self, var: Var, block: Block, value: Value) {
163 if let Some(&decl) = self.named.get(&var) {
164 if self.owned.insert(value) {
165 self.holds.push((value, decl));
166 }
167 }
168 self.defs.insert((var, block), value);
169 }
170
171 pub fn read(&mut self, func: &mut Func, var: Var, block: Block, ty: Type) -> Value {
188 let mut chain = Vec::new();
193 let mut at = block;
194 let value = loop {
195 if let Some(&value) = self.defs.get(&(var, at)) {
196 break self.resolve(value);
197 }
198 self.reserve(at);
199 if !self.sealed[at.index()] {
200 break self.pending(func, var, at, ty);
201 }
202 match self.preds[at.index()].len() {
203 0 => break self.undefined(func, ty),
205 1 => {
207 chain.push(at);
208 at = self.preds[at.index()][0].from;
209 }
210 _ => break self.phi(func, var, at, ty),
211 }
212 };
213 for at in chain {
214 self.write(var, at, value);
215 }
216 self.write(var, block, value);
217 value
218 }
219
220 pub fn branch(&mut self, func: &Func, inst: Inst) {
231 let from = func.block_of(inst).expect("a terminator in a block");
232 for call in func.target_list(inst).iter() {
233 let to = func[call].block;
234 self.reserve(to);
235 self.preds[to.index()].push(Edge { from, call });
236 }
237 }
238
239 pub fn seal(&mut self, func: &mut Func, block: Block) {
245 self.reserve(block);
246 assert!(!self.sealed[block.index()], "a block is sealed once");
247 self.sealed[block.index()] = true;
248 let waiting = std::mem::take(&mut self.incomplete[block.index()]);
251 for (var, phi) in waiting {
252 let value = self.operands(func, var, phi);
253 if self.defs.get(&(var, block)) == Some(&phi) {
259 self.write(var, block, value);
260 }
261 }
262 }
263
264 #[must_use]
266 pub fn is_sealed(&self, block: Block) -> bool {
267 self.sealed.get(block.index()).copied().unwrap_or(false)
268 }
269
270 pub fn finish(mut self, func: &mut Func) {
277 self.names(func);
278 if self.subst.is_empty() {
279 return;
280 }
281
282 let blocks: Vec<Block> = func.blocks().collect();
283 for &block in &blocks {
284 let insts: Vec<Inst> = func.insts(block).collect();
285 for inst in insts {
286 let args = func[inst].args;
287 func.rewrite(args, |value| self.resolve(value));
288 for call in func.target_list(inst).iter() {
289 let args = func[call].args;
290 func.rewrite(args, |value| self.resolve(value));
291 }
292 }
293 }
294
295 let mut dropped: Vec<Vec<usize>> = vec![Vec::new(); func.counts().blocks];
299 for &block in &blocks {
300 for (index, ¶m) in func[block].params.iter().enumerate() {
301 if self.subst.contains_key(¶m) {
302 dropped[block.index()].push(index);
303 }
304 }
305 }
306
307 for &block in &blocks {
308 let insts: Vec<Inst> = func.insts(block).collect();
309 for inst in insts {
310 for at in func.target_list(inst).iter() {
311 let mut call = func[at];
312 let going = &dropped[call.block.index()];
313 if going.is_empty() {
314 continue;
315 }
316 let kept: Vec<Value> = func[call.args]
317 .iter()
318 .copied()
319 .enumerate()
320 .filter(|(index, _)| !going.contains(index))
321 .map(|(_, value)| value)
322 .collect();
323 call.args = func.push_values(&kept);
324 func.set_block_call(at, call);
325 }
326 }
327 }
328
329 for &block in &blocks {
330 if !dropped[block.index()].is_empty() {
331 func.retain_params(block, |param| !self.subst.contains_key(¶m));
332 }
333 }
334 }
335
336 fn names(&mut self, func: &mut Func) {
343 for (value, decl) in std::mem::take(&mut self.holds) {
344 let value = self.resolve(value);
345 func.declare_value(value, decl);
346 }
347 }
348
349 fn pending(&mut self, func: &mut Func, var: Var, block: Block, ty: Type) -> Value {
353 let phi = func.append_param(block, ty);
354 self.phis.insert(phi, Phi { block, var });
355 self.incomplete[block.index()].push((var, phi));
356 self.write(var, block, phi);
357 phi
358 }
359
360 fn phi(&mut self, func: &mut Func, var: Var, block: Block, ty: Type) -> Value {
362 let phi = func.append_param(block, ty);
363 self.phis.insert(phi, Phi { block, var });
364 self.write(var, block, phi);
367 self.operands(func, var, phi)
368 }
369
370 fn operands(&mut self, func: &mut Func, var: Var, phi: Value) -> Value {
372 let block = self.phis[&phi].block;
373 let ty = func[phi].ty;
374 for index in 0..self.preds[block.index()].len() {
378 let edge = self.preds[block.index()][index];
379 let value = self.read(func, var, edge.from, ty);
380 let mut call = func[edge.call];
381 call.args = func.append_arg(call.args, value);
382 func.set_block_call(edge.call, call);
383 self.users.entry(value).or_default().push(phi);
384 }
385 self.trivial(func, phi)
386 }
387
388 fn trivial(&mut self, func: &mut Func, phi: Value) -> Value {
395 let block = self.phis[&phi].block;
396 let Some(at) = func[block].params.iter().position(|¶m| param == phi) else {
397 return phi;
398 };
399
400 let mut same: Option<Value> = None;
401 for index in 0..self.preds[block.index()].len() {
402 let edge = self.preds[block.index()][index];
403 let arg = self.resolve(func[func[edge.call].args][at]);
404 if arg == phi || same == Some(arg) {
405 continue;
406 }
407 if same.is_some() {
408 return phi;
410 }
411 same = Some(arg);
412 }
413
414 let same = match same {
415 Some(value) => value,
416 None => self.undefined(func, func[phi].ty),
419 };
420 self.subst.insert(phi, same);
421
422 let users = self.users.remove(&phi).unwrap_or_default();
425 let inherited: Vec<Value> = users.iter().copied().filter(|&user| user != phi).collect();
426 self.users.entry(same).or_default().extend(inherited.iter().copied());
427 for user in inherited {
428 if !self.subst.contains_key(&user) {
429 self.trivial(func, user);
430 }
431 }
432 self.resolve(same)
433 }
434
435 fn resolve(&mut self, value: Value) -> Value {
441 let mut at = value;
442 while let Some(&next) = self.subst.get(&at) {
443 at = next;
444 }
445 if at != value {
446 self.subst.insert(value, at);
447 }
448 at
449 }
450
451 fn undefined(&mut self, func: &mut Func, ty: Type) -> Value {
456 if let Some(&(_, value)) = self.zero.iter().find(|&&(at, _)| at == ty) {
457 return value;
458 }
459
460 let entry = func.entry().expect("a function with a block in it");
461 let first = func.insts(entry).next();
462 let value = if ty.is_ptr() {
463 let int = self.constant(func, entry, first, self.address);
464 let args = func.push_values(&[int]);
465 let cast = func.create_inst(
466 InstData { args, ..InstData::new(Opcode::IntToPtr) },
467 &[ty],
468 Span::DUMMY,
469 );
470 place(func, entry, first, cast);
471 func[cast].first_result.expect("one result")
472 } else {
473 self.constant(func, entry, first, ty)
474 };
475
476 self.zero.push((ty, value));
477 value
478 }
479
480 fn constant(&mut self, func: &mut Func, entry: Block, first: Option<Inst>, ty: Type) -> Value {
482 let imm = if ty.lane().is_float() { Imm::from_bits(0) } else { Imm::int(0, ty.lane()) };
483 let imm = func.add_imm(imm);
484 let opcode = if ty.lane().is_float() { Opcode::FConst } else { Opcode::IConst };
485 let inst = func.create_inst(
486 InstData { extra: Extra::Imm(imm), ..InstData::new(opcode) },
487 &[ty],
488 Span::DUMMY,
489 );
490 place(func, entry, first, inst);
491 func[inst].first_result.expect("one result")
492 }
493
494 fn reserve(&mut self, block: Block) {
496 let wanted = block.index() + 1;
497 if self.sealed.len() < wanted {
498 self.sealed.resize(wanted, false);
499 self.incomplete.resize_with(wanted, Vec::new);
500 self.preds.resize_with(wanted, Vec::new);
501 }
502 }
503}
504
505fn place(func: &mut Func, entry: Block, first: Option<Inst>, inst: Inst) {
507 match first {
508 Some(first) => func.insert_before(inst, first),
509 None => func.append_inst(entry, inst),
510 }
511}
512
513#[cfg(test)]
514mod tests {
515 use rucc_base::Interner;
516 use rucc_ir::{Builder, Flags, IntPred, Module, Signature, print_func, verify_func};
517 use rucc_target::{Arch, Env, Os, TargetInfo, Triple};
518
519 use super::*;
520
521 const I32: Type = Type::int(32);
522 const BOOL: Type = Type::int(1);
523
524 fn target() -> TargetInfo {
525 TargetInfo::new(Triple::new(Arch::X86_64, Os::Linux, Env::Gnu))
526 }
527
528 fn checked(func: Func, names: &mut Interner) -> String {
535 let mut module = Module::new(names.intern("t.c"), &target());
536 let id = module.add_func(func);
537 if let Err(errors) = verify_func(&module, &module[id], names) {
538 let listed: Vec<String> = errors.iter().map(ToString::to_string).collect();
539 panic!("{}", listed.join("\n"));
540 }
541 print_func(&module, &module[id], names)
542 }
543
544 fn start(names: &mut Interner) -> (Func, Ssa, Block, Value) {
546 let signature = Signature::new().with_params(&[BOOL]).with_returns(&[I32]);
547 let mut func = Func::new(names.intern("f"), signature);
548 let entry = func.create_block();
549 let cond = func.append_param(entry, BOOL);
550 let mut ssa = Ssa::new(Type::int(64));
551 ssa.seal(&mut func, entry);
552 (func, ssa, entry, cond)
553 }
554
555 #[test]
556 fn a_variable_read_where_it_was_written_is_the_value_it_was_written() {
557 let mut names = Interner::new();
558 let (mut func, mut ssa, entry, _) = start(&mut names);
559 let x = Var::new(0);
560
561 let one = Builder::new(&mut func, entry).iconst(I32, 1);
562 ssa.write(x, entry, one);
563 let read = ssa.read(&mut func, x, entry, I32);
564 assert_eq!(read, one);
565
566 Builder::new(&mut func, entry).ret(&[read]);
567 ssa.finish(&mut func);
568 assert!(func[entry].params.len() == 1, "no parameter was needed");
569 }
570
571 #[test]
572 fn a_variable_written_on_both_arms_arrives_as_a_block_parameter() {
573 let mut names = Interner::new();
574 let (mut func, mut ssa, entry, cond) = start(&mut names);
575 let x = Var::new(0);
576
577 let then = func.create_block();
578 let otherwise = func.create_block();
579 let join = func.create_block();
580
581 let branch = Builder::new(&mut func, entry).br_if(cond, then, &[], otherwise, &[]);
582 ssa.branch(&func, branch);
583 ssa.seal(&mut func, then);
584 ssa.seal(&mut func, otherwise);
585
586 let one = Builder::new(&mut func, then).iconst(I32, 1);
587 ssa.write(x, then, one);
588 let jump = Builder::new(&mut func, then).jump(join, &[]);
589 ssa.branch(&func, jump);
590
591 let two = Builder::new(&mut func, otherwise).iconst(I32, 2);
592 ssa.write(x, otherwise, two);
593 let jump = Builder::new(&mut func, otherwise).jump(join, &[]);
594 ssa.branch(&func, jump);
595
596 ssa.seal(&mut func, join);
597 let read = ssa.read(&mut func, x, join, I32);
598 Builder::new(&mut func, join).ret(&[read]);
599 ssa.finish(&mut func);
600
601 assert_eq!(checked(func, &mut names), DIAMOND);
602 }
603
604 #[test]
605 fn a_variable_both_arms_agree_about_needs_no_block_parameter() {
606 let mut names = Interner::new();
607 let (mut func, mut ssa, entry, cond) = start(&mut names);
608 let x = Var::new(0);
609
610 let one = Builder::new(&mut func, entry).iconst(I32, 1);
611 ssa.write(x, entry, one);
612
613 let then = func.create_block();
614 let otherwise = func.create_block();
615 let join = func.create_block();
616
617 let branch = Builder::new(&mut func, entry).br_if(cond, then, &[], otherwise, &[]);
618 ssa.branch(&func, branch);
619 ssa.seal(&mut func, then);
620 ssa.seal(&mut func, otherwise);
621
622 for block in [then, otherwise] {
623 let jump = Builder::new(&mut func, block).jump(join, &[]);
624 ssa.branch(&func, jump);
625 }
626
627 ssa.seal(&mut func, join);
628 let read = ssa.read(&mut func, x, join, I32);
629 assert_eq!(read, one, "the parameter stood for the one value both arms had");
630 Builder::new(&mut func, join).ret(&[read]);
631 ssa.finish(&mut func);
632
633 assert!(func[join].params.is_empty(), "the parameter was taken out again");
634 assert_eq!(checked(func, &mut names), AGREED);
635 }
636
637 fn named(func: &Func) -> Vec<(usize, Vec<u32>)> {
639 (0..func.counts().values)
640 .map(|at| (at, func.value_decls(Idx::from_usize(at)).collect::<Vec<u32>>()))
641 .filter(|(_, decls)| !decls.is_empty())
642 .collect()
643 }
644
645 #[test]
652 fn a_named_variable_leaves_every_value_it_turned_into_knowing_which_it_is() {
653 let mut names = Interner::new();
654 let (mut func, mut ssa, entry, cond) = start(&mut names);
655 let x = Var::new(0);
656 ssa.stands_for(x, 41);
657
658 let then = func.create_block();
659 let otherwise = func.create_block();
660 let join = func.create_block();
661
662 let branch = Builder::new(&mut func, entry).br_if(cond, then, &[], otherwise, &[]);
663 ssa.branch(&func, branch);
664 ssa.seal(&mut func, then);
665 ssa.seal(&mut func, otherwise);
666
667 let one = Builder::new(&mut func, then).iconst(I32, 1);
668 ssa.write(x, then, one);
669 let jump = Builder::new(&mut func, then).jump(join, &[]);
670 ssa.branch(&func, jump);
671
672 let two = Builder::new(&mut func, otherwise).iconst(I32, 2);
673 ssa.write(x, otherwise, two);
674 let jump = Builder::new(&mut func, otherwise).jump(join, &[]);
675 ssa.branch(&func, jump);
676
677 ssa.seal(&mut func, join);
678 let read = ssa.read(&mut func, x, join, I32);
679 Builder::new(&mut func, join).ret(&[read]);
680 ssa.finish(&mut func);
681
682 let held = vec![(one.index(), vec![41]), (two.index(), vec![41]), (read.index(), vec![41])];
683 assert_eq!(named(&func), held);
684 }
685
686 #[test]
692 fn a_name_recorded_against_a_parameter_follows_it_to_what_it_stood_for() {
693 let mut names = Interner::new();
694 let (mut func, mut ssa, entry, cond) = start(&mut names);
695 let x = Var::new(0);
696 ssa.stands_for(x, 41);
697
698 let one = Builder::new(&mut func, entry).iconst(I32, 1);
699 ssa.write(x, entry, one);
700
701 let then = func.create_block();
702 let otherwise = func.create_block();
703 let join = func.create_block();
704
705 let branch = Builder::new(&mut func, entry).br_if(cond, then, &[], otherwise, &[]);
706 ssa.branch(&func, branch);
707 ssa.seal(&mut func, then);
708 ssa.seal(&mut func, otherwise);
709
710 for block in [then, otherwise] {
711 let jump = Builder::new(&mut func, block).jump(join, &[]);
712 ssa.branch(&func, jump);
713 }
714
715 ssa.seal(&mut func, join);
716 let read = ssa.read(&mut func, x, join, I32);
717 Builder::new(&mut func, join).ret(&[read]);
718 ssa.finish(&mut func);
719
720 assert_eq!(named(&func), vec![(one.index(), vec![41])]);
721 }
722
723 #[test]
730 fn a_variable_written_a_value_another_one_already_holds_takes_no_name_from_it() {
731 let mut names = Interner::new();
732 let (mut func, mut ssa, entry, _) = start(&mut names);
733 let (a, m) = (Var::new(0), Var::new(1));
734 ssa.stands_for(a, 41);
735 ssa.stands_for(m, 42);
736
737 let one = Builder::new(&mut func, entry).iconst(I32, 1);
738 ssa.write(a, entry, one);
739 let read = ssa.read(&mut func, a, entry, I32);
740 ssa.write(m, entry, read);
741 Builder::new(&mut func, entry).ret(&[read]);
742 ssa.finish(&mut func);
743
744 assert_eq!(named(&func), vec![(one.index(), vec![41])]);
745 }
746
747 #[test]
750 fn a_variable_nothing_named_leaves_no_names_at_all() {
751 let mut names = Interner::new();
752 let (mut func, mut ssa, entry, _) = start(&mut names);
753 let x = Var::new(0);
754
755 let one = Builder::new(&mut func, entry).iconst(I32, 1);
756 ssa.write(x, entry, one);
757 let read = ssa.read(&mut func, x, entry, I32);
758 Builder::new(&mut func, entry).ret(&[read]);
759 ssa.finish(&mut func);
760
761 assert!(named(&func).is_empty());
762 }
763
764 #[test]
765 fn a_variable_a_loop_changes_is_carried_by_the_headers_parameter() {
766 let mut names = Interner::new();
767 let (mut func, mut ssa, entry, _) = start(&mut names);
768 let x = Var::new(0);
769
770 let zero = Builder::new(&mut func, entry).iconst(I32, 0);
771 ssa.write(x, entry, zero);
772
773 let header = func.create_block();
774 let body = func.create_block();
775 let exit = func.create_block();
776
777 let jump = Builder::new(&mut func, entry).jump(header, &[]);
778 ssa.branch(&func, jump);
779
780 let counter = ssa.read(&mut func, x, header, I32);
783 let mut build = Builder::new(&mut func, header);
784 let ten = build.iconst(I32, 10);
785 let test = build.icmp(IntPred::Slt, counter, ten);
786 let branch = build.br_if(test, body, &[], exit, &[]);
787 ssa.branch(&func, branch);
788 ssa.seal(&mut func, body);
789 ssa.seal(&mut func, exit);
790
791 let carried = ssa.read(&mut func, x, body, I32);
792 let mut build = Builder::new(&mut func, body);
793 let one = build.iconst(I32, 1);
794 let next = build.binary(Opcode::Add, carried, one, Flags::NONE);
795 let jump = build.jump(header, &[]);
796 ssa.write(x, body, next);
797 ssa.branch(&func, jump);
798 ssa.seal(&mut func, header);
799
800 let result = ssa.read(&mut func, x, exit, I32);
801 Builder::new(&mut func, exit).ret(&[result]);
802 ssa.finish(&mut func);
803
804 assert_eq!(checked(func, &mut names), LOOP);
805 }
806
807 #[test]
808 fn a_variable_a_loop_does_not_change_is_not_carried_at_all() {
809 let mut names = Interner::new();
810 let (mut func, mut ssa, entry, cond) = start(&mut names);
811 let x = Var::new(0);
812
813 let seven = Builder::new(&mut func, entry).iconst(I32, 7);
814 ssa.write(x, entry, seven);
815
816 let header = func.create_block();
817 let body = func.create_block();
818 let exit = func.create_block();
819
820 let jump = Builder::new(&mut func, entry).jump(header, &[]);
821 ssa.branch(&func, jump);
822
823 let branch = Builder::new(&mut func, header).br_if(cond, body, &[], exit, &[]);
824 ssa.branch(&func, branch);
825 ssa.seal(&mut func, body);
826 ssa.seal(&mut func, exit);
827
828 let inside = ssa.read(&mut func, x, body, I32);
831 let mut build = Builder::new(&mut func, body);
832 build.binary(Opcode::Add, inside, inside, Flags::NONE);
833 let jump = build.jump(header, &[]);
834 ssa.branch(&func, jump);
835 ssa.seal(&mut func, header);
836
837 let result = ssa.read(&mut func, x, exit, I32);
838 Builder::new(&mut func, exit).ret(&[result]);
839 ssa.finish(&mut func);
840
841 assert!(func[header].params.is_empty(), "the parameter went, and the addition reads %1");
842 assert_eq!(checked(func, &mut names), UNCHANGED);
843 }
844
845 #[test]
846 fn a_variable_two_nested_loops_do_not_change_is_carried_by_neither() {
847 let mut names = Interner::new();
851 let (mut func, mut ssa, entry, cond) = start(&mut names);
852 let x = Var::new(0);
853
854 let seven = Builder::new(&mut func, entry).iconst(I32, 7);
855 ssa.write(x, entry, seven);
856
857 let outer = func.create_block();
858 let inner = func.create_block();
859 let latch = func.create_block();
860 let exit = func.create_block();
861
862 let jump = Builder::new(&mut func, entry).jump(outer, &[]);
863 ssa.branch(&func, jump);
864
865 let jump = Builder::new(&mut func, outer).jump(inner, &[]);
866 ssa.branch(&func, jump);
867
868 let read = ssa.read(&mut func, x, inner, I32);
869 let mut build = Builder::new(&mut func, inner);
870 build.binary(Opcode::Add, read, read, Flags::NONE);
871 let branch = build.br_if(cond, inner, &[], latch, &[]);
872 ssa.branch(&func, branch);
873 ssa.seal(&mut func, inner);
874 ssa.seal(&mut func, latch);
875
876 let branch = Builder::new(&mut func, latch).br_if(cond, outer, &[], exit, &[]);
877 ssa.branch(&func, branch);
878 ssa.seal(&mut func, outer);
879 ssa.seal(&mut func, exit);
880
881 let result = ssa.read(&mut func, x, exit, I32);
882 Builder::new(&mut func, exit).ret(&[result]);
883 ssa.finish(&mut func);
884
885 assert!(func[outer].params.is_empty() && func[inner].params.is_empty());
886 assert_eq!(checked(func, &mut names), NESTED);
887 }
888
889 #[test]
890 fn a_write_after_the_read_that_made_a_parameter_is_what_the_block_holds() {
891 let mut names = Interner::new();
895 let (mut func, mut ssa, entry, cond) = start(&mut names);
896 let x = Var::new(0);
897
898 let one = Builder::new(&mut func, entry).iconst(I32, 1);
899 ssa.write(x, entry, one);
900
901 let case = func.create_block();
902 let other = func.create_block();
903 let branch = Builder::new(&mut func, entry).br_if(cond, case, &[], other, &[]);
904 ssa.branch(&func, branch);
905 ssa.seal(&mut func, other);
906
907 let read = ssa.read(&mut func, x, case, I32);
909 let sum = Builder::new(&mut func, case).binary(Opcode::Add, read, read, Flags::NONE);
910 ssa.write(x, case, sum);
911
912 let mut build = Builder::new(&mut func, other);
914 let two = build.iconst(I32, 2);
915 let jump = build.jump(case, &[]);
916 ssa.write(x, other, two);
917 ssa.branch(&func, jump);
918 ssa.seal(&mut func, case);
919
920 let after = ssa.read(&mut func, x, case, I32);
921 assert_eq!(after, sum, "the block holds what it wrote, not the parameter it started at");
922 Builder::new(&mut func, case).ret(&[after]);
923 ssa.finish(&mut func);
924
925 assert_eq!(checked(func, &mut names), WRITTEN_AFTER);
926 }
927
928 #[test]
929 fn a_variable_nothing_wrote_reads_as_the_same_zero_every_time() {
930 let mut names = Interner::new();
931 let (mut func, mut ssa, entry, _) = start(&mut names);
932 let x = Var::new(0);
933 let y = Var::new(1);
934 let z = Var::new(2);
935
936 let first = ssa.read(&mut func, x, entry, I32);
937 let second = ssa.read(&mut func, y, entry, I32);
938 let pointer = ssa.read(&mut func, z, entry, Type::PTR);
939 assert_eq!(first, second, "unspecified, and the same both times");
940 assert_ne!(first, pointer);
941
942 Builder::new(&mut func, entry).ret(&[first]);
943 ssa.finish(&mut func);
944 assert_eq!(checked(func, &mut names), UNWRITTEN);
945 }
946
947 const DIAMOND: &str = "\
949func @f(i1) -> i32, linkage(external) {
950block0(%0: i1):
951 br_if %0, block1, block2
952
953block1:
954 %1 = iconst.i32 1
955 jump block3(%1)
956
957block2:
958 %2 = iconst.i32 2
959 jump block3(%2)
960
961block3(%3: i32):
962 return %3
963}
964";
965
966 const AGREED: &str = "\
968func @f(i1) -> i32, linkage(external) {
969block0(%0: i1):
970 %1 = iconst.i32 1
971 br_if %0, block1, block2
972
973block1:
974 jump block3
975
976block2:
977 jump block3
978
979block3:
980 return %1
981}
982";
983
984 const LOOP: &str = "\
987func @f(i1) -> i32, linkage(external) {
988block0(%0: i1):
989 %1 = iconst.i32 0
990 jump block1(%1)
991
992block1(%2: i32):
993 %3 = iconst.i32 10
994 %4 = icmp slt %2, %3
995 br_if %4, block2, block3
996
997block2:
998 %5 = iconst.i32 1
999 %6 = add %2, %5
1000 jump block1(%6)
1001
1002block3:
1003 return %2
1004}
1005";
1006
1007 const UNCHANGED: &str = "\
1010func @f(i1) -> i32, linkage(external) {
1011block0(%0: i1):
1012 %1 = iconst.i32 7
1013 jump block1
1014
1015block1:
1016 br_if %0, block2, block3
1017
1018block2:
1019 %2 = add %1, %1
1020 jump block1
1021
1022block3:
1023 return %1
1024}
1025";
1026
1027 const NESTED: &str = "\
1030func @f(i1) -> i32, linkage(external) {
1031block0(%0: i1):
1032 %1 = iconst.i32 7
1033 jump block1
1034
1035block1:
1036 jump block2
1037
1038block2:
1039 %2 = add %1, %1
1040 br_if %0, block2, block3
1041
1042block3:
1043 br_if %0, block1, block4
1044
1045block4:
1046 return %1
1047}
1048";
1049
1050 const WRITTEN_AFTER: &str = "\
1053func @f(i1) -> i32, linkage(external) {
1054block0(%0: i1):
1055 %1 = iconst.i32 1
1056 br_if %0, block1(%1), block2
1057
1058block1(%2: i32):
1059 %3 = add %2, %2
1060 return %3
1061
1062block2:
1063 %4 = iconst.i32 2
1064 jump block1(%4)
1065}
1066";
1067
1068 const UNWRITTEN: &str = "\
1071func @f(i1) -> i32, linkage(external) {
1072block0(%0: i1):
1073 %1 = iconst.i64 0
1074 %2 = inttoptr.ptr %1
1075 %3 = iconst.i32 0
1076 return %3
1077}
1078";
1079}