1use std::collections::HashMap;
41
42use rucc_base::Idx;
43use rucc_diag::Span;
44use rucc_ir::{Block, BlockCall, Extra, Func, Imm, Inst, InstData, Opcode, Start, 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 starts: Vec<(Value, Start)>,
115 owned: HashMap<Value, u32>,
118}
119
120impl Ssa {
121 #[must_use]
128 pub fn new(address: Type) -> Ssa {
129 Ssa {
130 address,
131 defs: HashMap::new(),
132 sealed: Vec::new(),
133 incomplete: Vec::new(),
134 preds: Vec::new(),
135 phis: HashMap::new(),
136 users: HashMap::new(),
137 subst: HashMap::new(),
138 zero: Vec::new(),
139 named: HashMap::new(),
140 holds: Vec::new(),
141 starts: Vec::new(),
142 owned: HashMap::new(),
143 }
144 }
145
146 pub fn stands_for(&mut self, var: Var, decl: u32) {
153 self.named.insert(var, decl);
154 }
155
156 pub fn write(&mut self, var: Var, block: Block, value: Value) {
167 self.written(var, value, None);
168 self.defs.insert((var, block), value);
169 }
170
171 pub fn assign(&mut self, var: Var, block: Block, value: Value, after: Option<Inst>) {
179 self.written(var, value, Some(Start { decl: 0, block, after }));
180 self.defs.insert((var, block), value);
181 }
182
183 fn written(&mut self, var: Var, value: Value, start: Option<Start>) {
186 let Some(&decl) = self.named.get(&var) else { return };
187 match self.owned.get(&value) {
188 None => {
189 self.owned.insert(value, decl);
190 self.holds.push((value, decl));
191 }
192 Some(_) => {
197 if let Some(start) = start {
198 self.starts.push((value, Start { decl, ..start }));
199 }
200 }
201 }
202 }
203
204 pub fn read(&mut self, func: &mut Func, var: Var, block: Block, ty: Type) -> Value {
221 let mut chain = Vec::new();
226 let mut at = block;
227 let value = loop {
228 if let Some(&value) = self.defs.get(&(var, at)) {
229 break self.resolve(value);
230 }
231 self.reserve(at);
232 if !self.sealed[at.index()] {
233 break self.pending(func, var, at, ty);
234 }
235 match self.preds[at.index()].len() {
236 0 => break self.undefined(func, ty),
238 1 => {
240 chain.push(at);
241 at = self.preds[at.index()][0].from;
242 }
243 _ => break self.phi(func, var, at, ty),
244 }
245 };
246 for at in chain {
247 self.write(var, at, value);
248 }
249 self.write(var, block, value);
250 value
251 }
252
253 pub fn branch(&mut self, func: &Func, inst: Inst) {
264 let from = func.block_of(inst).expect("a terminator in a block");
265 for call in func.target_list(inst).iter() {
266 let to = func[call].block;
267 self.reserve(to);
268 self.preds[to.index()].push(Edge { from, call });
269 }
270 }
271
272 pub fn seal(&mut self, func: &mut Func, block: Block) {
278 self.reserve(block);
279 assert!(!self.sealed[block.index()], "a block is sealed once");
280 self.sealed[block.index()] = true;
281 let waiting = std::mem::take(&mut self.incomplete[block.index()]);
284 for (var, phi) in waiting {
285 let value = self.operands(func, var, phi);
286 if self.defs.get(&(var, block)) == Some(&phi) {
292 self.write(var, block, value);
293 }
294 }
295 }
296
297 #[must_use]
299 pub fn is_sealed(&self, block: Block) -> bool {
300 self.sealed.get(block.index()).copied().unwrap_or(false)
301 }
302
303 pub fn finish(mut self, func: &mut Func) {
310 self.names(func);
311 if self.subst.is_empty() {
312 return;
313 }
314
315 let blocks: Vec<Block> = func.blocks().collect();
316 for &block in &blocks {
317 let insts: Vec<Inst> = func.insts(block).collect();
318 for inst in insts {
319 let args = func[inst].args;
320 func.rewrite(args, |value| self.resolve(value));
321 for call in func.target_list(inst).iter() {
322 let args = func[call].args;
323 func.rewrite(args, |value| self.resolve(value));
324 }
325 }
326 }
327
328 let mut dropped: Vec<Vec<usize>> = vec![Vec::new(); func.counts().blocks];
332 for &block in &blocks {
333 for (index, ¶m) in func[block].params.iter().enumerate() {
334 if self.subst.contains_key(¶m) {
335 dropped[block.index()].push(index);
336 }
337 }
338 }
339
340 for &block in &blocks {
341 let insts: Vec<Inst> = func.insts(block).collect();
342 for inst in insts {
343 for at in func.target_list(inst).iter() {
344 let mut call = func[at];
345 let going = &dropped[call.block.index()];
346 if going.is_empty() {
347 continue;
348 }
349 let kept: Vec<Value> = func[call.args]
350 .iter()
351 .copied()
352 .enumerate()
353 .filter(|(index, _)| !going.contains(index))
354 .map(|(_, value)| value)
355 .collect();
356 call.args = func.push_values(&kept);
357 func.set_block_call(at, call);
358 }
359 }
360 }
361
362 for &block in &blocks {
363 if !dropped[block.index()].is_empty() {
364 func.retain_params(block, |param| !self.subst.contains_key(¶m));
365 }
366 }
367 }
368
369 fn names(&mut self, func: &mut Func) {
376 for (value, decl) in std::mem::take(&mut self.holds) {
377 let value = self.resolve(value);
378 func.declare_value(value, decl);
379 }
380 for (value, start) in std::mem::take(&mut self.starts) {
381 let value = self.resolve(value);
382 func.declare_value_from(value, start);
383 }
384 }
385
386 fn pending(&mut self, func: &mut Func, var: Var, block: Block, ty: Type) -> Value {
390 let phi = func.append_param(block, ty);
391 self.phis.insert(phi, Phi { block, var });
392 self.incomplete[block.index()].push((var, phi));
393 self.write(var, block, phi);
394 phi
395 }
396
397 fn phi(&mut self, func: &mut Func, var: Var, block: Block, ty: Type) -> Value {
399 let phi = func.append_param(block, ty);
400 self.phis.insert(phi, Phi { block, var });
401 self.write(var, block, phi);
404 self.operands(func, var, phi)
405 }
406
407 fn operands(&mut self, func: &mut Func, var: Var, phi: Value) -> Value {
409 let block = self.phis[&phi].block;
410 let ty = func[phi].ty;
411 for index in 0..self.preds[block.index()].len() {
415 let edge = self.preds[block.index()][index];
416 let value = self.read(func, var, edge.from, ty);
417 let mut call = func[edge.call];
418 call.args = func.append_arg(call.args, value);
419 func.set_block_call(edge.call, call);
420 self.users.entry(value).or_default().push(phi);
421 }
422 self.trivial(func, phi)
423 }
424
425 fn trivial(&mut self, func: &mut Func, phi: Value) -> Value {
432 let block = self.phis[&phi].block;
433 let Some(at) = func[block].params.iter().position(|¶m| param == phi) else {
434 return phi;
435 };
436
437 let mut same: Option<Value> = None;
438 for index in 0..self.preds[block.index()].len() {
439 let edge = self.preds[block.index()][index];
440 let arg = self.resolve(func[func[edge.call].args][at]);
441 if arg == phi || same == Some(arg) {
442 continue;
443 }
444 if same.is_some() {
445 return phi;
447 }
448 same = Some(arg);
449 }
450
451 let same = match same {
452 Some(value) => value,
453 None => self.undefined(func, func[phi].ty),
456 };
457 self.subst.insert(phi, same);
458
459 let users = self.users.remove(&phi).unwrap_or_default();
462 let inherited: Vec<Value> = users.iter().copied().filter(|&user| user != phi).collect();
463 self.users.entry(same).or_default().extend(inherited.iter().copied());
464 for user in inherited {
465 if !self.subst.contains_key(&user) {
466 self.trivial(func, user);
467 }
468 }
469 self.resolve(same)
470 }
471
472 fn resolve(&mut self, value: Value) -> Value {
478 let mut at = value;
479 while let Some(&next) = self.subst.get(&at) {
480 at = next;
481 }
482 if at != value {
483 self.subst.insert(value, at);
484 }
485 at
486 }
487
488 fn undefined(&mut self, func: &mut Func, ty: Type) -> Value {
493 if let Some(&(_, value)) = self.zero.iter().find(|&&(at, _)| at == ty) {
494 return value;
495 }
496
497 let entry = func.entry().expect("a function with a block in it");
498 let first = func.insts(entry).next();
499 let value = if ty.is_ptr() {
500 let int = self.constant(func, entry, first, self.address);
501 let args = func.push_values(&[int]);
502 let cast = func.create_inst(
503 InstData { args, ..InstData::new(Opcode::IntToPtr) },
504 &[ty],
505 Span::DUMMY,
506 );
507 place(func, entry, first, cast);
508 func[cast].first_result.expect("one result")
509 } else {
510 self.constant(func, entry, first, ty)
511 };
512
513 self.zero.push((ty, value));
514 value
515 }
516
517 fn constant(&mut self, func: &mut Func, entry: Block, first: Option<Inst>, ty: Type) -> Value {
519 let imm = if ty.lane().is_float() { Imm::from_bits(0) } else { Imm::int(0, ty.lane()) };
520 let imm = func.add_imm(imm);
521 let opcode = if ty.lane().is_float() { Opcode::FConst } else { Opcode::IConst };
522 let inst = func.create_inst(
523 InstData { extra: Extra::Imm(imm), ..InstData::new(opcode) },
524 &[ty],
525 Span::DUMMY,
526 );
527 place(func, entry, first, inst);
528 func[inst].first_result.expect("one result")
529 }
530
531 fn reserve(&mut self, block: Block) {
533 let wanted = block.index() + 1;
534 if self.sealed.len() < wanted {
535 self.sealed.resize(wanted, false);
536 self.incomplete.resize_with(wanted, Vec::new);
537 self.preds.resize_with(wanted, Vec::new);
538 }
539 }
540}
541
542fn place(func: &mut Func, entry: Block, first: Option<Inst>, inst: Inst) {
544 match first {
545 Some(first) => func.insert_before(inst, first),
546 None => func.append_inst(entry, inst),
547 }
548}
549
550#[cfg(test)]
551mod tests {
552 use rucc_base::Interner;
553 use rucc_ir::{Builder, Flags, IntPred, Module, Signature, print_func, verify_func};
554 use rucc_target::{Arch, Env, Os, TargetInfo, Triple};
555
556 use super::*;
557
558 const I32: Type = Type::int(32);
559 const BOOL: Type = Type::int(1);
560
561 fn target() -> TargetInfo {
562 TargetInfo::new(Triple::new(Arch::X86_64, Os::Linux, Env::Gnu))
563 }
564
565 fn checked(func: Func, names: &mut Interner) -> String {
572 let mut module = Module::new(names.intern("t.c"), &target());
573 let id = module.add_func(func);
574 if let Err(errors) = verify_func(&module, &module[id], names) {
575 let listed: Vec<String> = errors.iter().map(ToString::to_string).collect();
576 panic!("{}", listed.join("\n"));
577 }
578 print_func(&module, &module[id], names)
579 }
580
581 fn start(names: &mut Interner) -> (Func, Ssa, Block, Value) {
583 let signature = Signature::new().with_params(&[BOOL]).with_returns(&[I32]);
584 let mut func = Func::new(names.intern("f"), signature);
585 let entry = func.create_block();
586 let cond = func.append_param(entry, BOOL);
587 let mut ssa = Ssa::new(Type::int(64));
588 ssa.seal(&mut func, entry);
589 (func, ssa, entry, cond)
590 }
591
592 #[test]
593 fn a_variable_read_where_it_was_written_is_the_value_it_was_written() {
594 let mut names = Interner::new();
595 let (mut func, mut ssa, entry, _) = start(&mut names);
596 let x = Var::new(0);
597
598 let one = Builder::new(&mut func, entry).iconst(I32, 1);
599 ssa.write(x, entry, one);
600 let read = ssa.read(&mut func, x, entry, I32);
601 assert_eq!(read, one);
602
603 Builder::new(&mut func, entry).ret(&[read]);
604 ssa.finish(&mut func);
605 assert!(func[entry].params.len() == 1, "no parameter was needed");
606 }
607
608 #[test]
609 fn a_variable_written_on_both_arms_arrives_as_a_block_parameter() {
610 let mut names = Interner::new();
611 let (mut func, mut ssa, entry, cond) = start(&mut names);
612 let x = Var::new(0);
613
614 let then = func.create_block();
615 let otherwise = func.create_block();
616 let join = func.create_block();
617
618 let branch = Builder::new(&mut func, entry).br_if(cond, then, &[], otherwise, &[]);
619 ssa.branch(&func, branch);
620 ssa.seal(&mut func, then);
621 ssa.seal(&mut func, otherwise);
622
623 let one = Builder::new(&mut func, then).iconst(I32, 1);
624 ssa.write(x, then, one);
625 let jump = Builder::new(&mut func, then).jump(join, &[]);
626 ssa.branch(&func, jump);
627
628 let two = Builder::new(&mut func, otherwise).iconst(I32, 2);
629 ssa.write(x, otherwise, two);
630 let jump = Builder::new(&mut func, otherwise).jump(join, &[]);
631 ssa.branch(&func, jump);
632
633 ssa.seal(&mut func, join);
634 let read = ssa.read(&mut func, x, join, I32);
635 Builder::new(&mut func, join).ret(&[read]);
636 ssa.finish(&mut func);
637
638 assert_eq!(checked(func, &mut names), DIAMOND);
639 }
640
641 #[test]
642 fn a_variable_both_arms_agree_about_needs_no_block_parameter() {
643 let mut names = Interner::new();
644 let (mut func, mut ssa, entry, cond) = start(&mut names);
645 let x = Var::new(0);
646
647 let one = Builder::new(&mut func, entry).iconst(I32, 1);
648 ssa.write(x, entry, one);
649
650 let then = func.create_block();
651 let otherwise = func.create_block();
652 let join = func.create_block();
653
654 let branch = Builder::new(&mut func, entry).br_if(cond, then, &[], otherwise, &[]);
655 ssa.branch(&func, branch);
656 ssa.seal(&mut func, then);
657 ssa.seal(&mut func, otherwise);
658
659 for block in [then, otherwise] {
660 let jump = Builder::new(&mut func, block).jump(join, &[]);
661 ssa.branch(&func, jump);
662 }
663
664 ssa.seal(&mut func, join);
665 let read = ssa.read(&mut func, x, join, I32);
666 assert_eq!(read, one, "the parameter stood for the one value both arms had");
667 Builder::new(&mut func, join).ret(&[read]);
668 ssa.finish(&mut func);
669
670 assert!(func[join].params.is_empty(), "the parameter was taken out again");
671 assert_eq!(checked(func, &mut names), AGREED);
672 }
673
674 fn named(func: &Func) -> Vec<(usize, Vec<u32>)> {
676 (0..func.counts().values)
677 .map(|at| (at, func.value_decls(Idx::from_usize(at)).collect::<Vec<u32>>()))
678 .filter(|(_, decls)| !decls.is_empty())
679 .collect()
680 }
681
682 #[test]
689 fn a_named_variable_leaves_every_value_it_turned_into_knowing_which_it_is() {
690 let mut names = Interner::new();
691 let (mut func, mut ssa, entry, cond) = start(&mut names);
692 let x = Var::new(0);
693 ssa.stands_for(x, 41);
694
695 let then = func.create_block();
696 let otherwise = func.create_block();
697 let join = func.create_block();
698
699 let branch = Builder::new(&mut func, entry).br_if(cond, then, &[], otherwise, &[]);
700 ssa.branch(&func, branch);
701 ssa.seal(&mut func, then);
702 ssa.seal(&mut func, otherwise);
703
704 let one = Builder::new(&mut func, then).iconst(I32, 1);
705 ssa.write(x, then, one);
706 let jump = Builder::new(&mut func, then).jump(join, &[]);
707 ssa.branch(&func, jump);
708
709 let two = Builder::new(&mut func, otherwise).iconst(I32, 2);
710 ssa.write(x, otherwise, two);
711 let jump = Builder::new(&mut func, otherwise).jump(join, &[]);
712 ssa.branch(&func, jump);
713
714 ssa.seal(&mut func, join);
715 let read = ssa.read(&mut func, x, join, I32);
716 Builder::new(&mut func, join).ret(&[read]);
717 ssa.finish(&mut func);
718
719 let held = vec![(one.index(), vec![41]), (two.index(), vec![41]), (read.index(), vec![41])];
720 assert_eq!(named(&func), held);
721 }
722
723 #[test]
729 fn a_name_recorded_against_a_parameter_follows_it_to_what_it_stood_for() {
730 let mut names = Interner::new();
731 let (mut func, mut ssa, entry, cond) = start(&mut names);
732 let x = Var::new(0);
733 ssa.stands_for(x, 41);
734
735 let one = Builder::new(&mut func, entry).iconst(I32, 1);
736 ssa.write(x, entry, one);
737
738 let then = func.create_block();
739 let otherwise = func.create_block();
740 let join = func.create_block();
741
742 let branch = Builder::new(&mut func, entry).br_if(cond, then, &[], otherwise, &[]);
743 ssa.branch(&func, branch);
744 ssa.seal(&mut func, then);
745 ssa.seal(&mut func, otherwise);
746
747 for block in [then, otherwise] {
748 let jump = Builder::new(&mut func, block).jump(join, &[]);
749 ssa.branch(&func, jump);
750 }
751
752 ssa.seal(&mut func, join);
753 let read = ssa.read(&mut func, x, join, I32);
754 Builder::new(&mut func, join).ret(&[read]);
755 ssa.finish(&mut func);
756
757 assert_eq!(named(&func), vec![(one.index(), vec![41])]);
758 }
759
760 #[test]
767 fn a_variable_written_a_value_another_one_already_holds_takes_no_name_from_it() {
768 let mut names = Interner::new();
769 let (mut func, mut ssa, entry, _) = start(&mut names);
770 let (a, m) = (Var::new(0), Var::new(1));
771 ssa.stands_for(a, 41);
772 ssa.stands_for(m, 42);
773
774 let one = Builder::new(&mut func, entry).iconst(I32, 1);
775 ssa.write(a, entry, one);
776 let read = ssa.read(&mut func, a, entry, I32);
777 ssa.write(m, entry, read);
778 Builder::new(&mut func, entry).ret(&[read]);
779 ssa.finish(&mut func);
780
781 assert_eq!(named(&func), vec![(one.index(), vec![41])]);
782 }
783
784 #[test]
787 fn a_variable_assigned_a_value_another_one_holds_says_where_it_started() {
788 let mut names = Interner::new();
789 let (mut func, mut ssa, entry, _) = start(&mut names);
790 let (a, m) = (Var::new(0), Var::new(1));
791 ssa.stands_for(a, 41);
792 ssa.stands_for(m, 42);
793
794 let one = Builder::new(&mut func, entry).iconst(I32, 1);
795 ssa.assign(a, entry, one, None);
796 let made = func.insts(entry).last();
797 let read = ssa.read(&mut func, a, entry, I32);
798 ssa.assign(m, entry, read, made);
799 ssa.assign(a, entry, read, made);
802 Builder::new(&mut func, entry).ret(&[read]);
803 ssa.finish(&mut func);
804
805 assert_eq!(named(&func), vec![(one.index(), vec![41])]);
806 let starts: Vec<Start> = func.value_starts(one).collect();
807 assert_eq!(
808 starts,
809 vec![
810 Start { decl: 42, block: entry, after: made },
811 Start { decl: 41, block: entry, after: made },
812 ]
813 );
814 }
815
816 #[test]
819 fn a_variable_nothing_named_leaves_no_names_at_all() {
820 let mut names = Interner::new();
821 let (mut func, mut ssa, entry, _) = start(&mut names);
822 let x = Var::new(0);
823
824 let one = Builder::new(&mut func, entry).iconst(I32, 1);
825 ssa.write(x, entry, one);
826 let read = ssa.read(&mut func, x, entry, I32);
827 Builder::new(&mut func, entry).ret(&[read]);
828 ssa.finish(&mut func);
829
830 assert!(named(&func).is_empty());
831 }
832
833 #[test]
834 fn a_variable_a_loop_changes_is_carried_by_the_headers_parameter() {
835 let mut names = Interner::new();
836 let (mut func, mut ssa, entry, _) = start(&mut names);
837 let x = Var::new(0);
838
839 let zero = Builder::new(&mut func, entry).iconst(I32, 0);
840 ssa.write(x, entry, zero);
841
842 let header = func.create_block();
843 let body = func.create_block();
844 let exit = func.create_block();
845
846 let jump = Builder::new(&mut func, entry).jump(header, &[]);
847 ssa.branch(&func, jump);
848
849 let counter = ssa.read(&mut func, x, header, I32);
852 let mut build = Builder::new(&mut func, header);
853 let ten = build.iconst(I32, 10);
854 let test = build.icmp(IntPred::Slt, counter, ten);
855 let branch = build.br_if(test, body, &[], exit, &[]);
856 ssa.branch(&func, branch);
857 ssa.seal(&mut func, body);
858 ssa.seal(&mut func, exit);
859
860 let carried = ssa.read(&mut func, x, body, I32);
861 let mut build = Builder::new(&mut func, body);
862 let one = build.iconst(I32, 1);
863 let next = build.binary(Opcode::Add, carried, one, Flags::NONE);
864 let jump = build.jump(header, &[]);
865 ssa.write(x, body, next);
866 ssa.branch(&func, jump);
867 ssa.seal(&mut func, header);
868
869 let result = ssa.read(&mut func, x, exit, I32);
870 Builder::new(&mut func, exit).ret(&[result]);
871 ssa.finish(&mut func);
872
873 assert_eq!(checked(func, &mut names), LOOP);
874 }
875
876 #[test]
877 fn a_variable_a_loop_does_not_change_is_not_carried_at_all() {
878 let mut names = Interner::new();
879 let (mut func, mut ssa, entry, cond) = start(&mut names);
880 let x = Var::new(0);
881
882 let seven = Builder::new(&mut func, entry).iconst(I32, 7);
883 ssa.write(x, entry, seven);
884
885 let header = func.create_block();
886 let body = func.create_block();
887 let exit = func.create_block();
888
889 let jump = Builder::new(&mut func, entry).jump(header, &[]);
890 ssa.branch(&func, jump);
891
892 let branch = Builder::new(&mut func, header).br_if(cond, body, &[], exit, &[]);
893 ssa.branch(&func, branch);
894 ssa.seal(&mut func, body);
895 ssa.seal(&mut func, exit);
896
897 let inside = ssa.read(&mut func, x, body, I32);
900 let mut build = Builder::new(&mut func, body);
901 build.binary(Opcode::Add, inside, inside, Flags::NONE);
902 let jump = build.jump(header, &[]);
903 ssa.branch(&func, jump);
904 ssa.seal(&mut func, header);
905
906 let result = ssa.read(&mut func, x, exit, I32);
907 Builder::new(&mut func, exit).ret(&[result]);
908 ssa.finish(&mut func);
909
910 assert!(func[header].params.is_empty(), "the parameter went, and the addition reads %1");
911 assert_eq!(checked(func, &mut names), UNCHANGED);
912 }
913
914 #[test]
915 fn a_variable_two_nested_loops_do_not_change_is_carried_by_neither() {
916 let mut names = Interner::new();
920 let (mut func, mut ssa, entry, cond) = start(&mut names);
921 let x = Var::new(0);
922
923 let seven = Builder::new(&mut func, entry).iconst(I32, 7);
924 ssa.write(x, entry, seven);
925
926 let outer = func.create_block();
927 let inner = func.create_block();
928 let latch = func.create_block();
929 let exit = func.create_block();
930
931 let jump = Builder::new(&mut func, entry).jump(outer, &[]);
932 ssa.branch(&func, jump);
933
934 let jump = Builder::new(&mut func, outer).jump(inner, &[]);
935 ssa.branch(&func, jump);
936
937 let read = ssa.read(&mut func, x, inner, I32);
938 let mut build = Builder::new(&mut func, inner);
939 build.binary(Opcode::Add, read, read, Flags::NONE);
940 let branch = build.br_if(cond, inner, &[], latch, &[]);
941 ssa.branch(&func, branch);
942 ssa.seal(&mut func, inner);
943 ssa.seal(&mut func, latch);
944
945 let branch = Builder::new(&mut func, latch).br_if(cond, outer, &[], exit, &[]);
946 ssa.branch(&func, branch);
947 ssa.seal(&mut func, outer);
948 ssa.seal(&mut func, exit);
949
950 let result = ssa.read(&mut func, x, exit, I32);
951 Builder::new(&mut func, exit).ret(&[result]);
952 ssa.finish(&mut func);
953
954 assert!(func[outer].params.is_empty() && func[inner].params.is_empty());
955 assert_eq!(checked(func, &mut names), NESTED);
956 }
957
958 #[test]
959 fn a_write_after_the_read_that_made_a_parameter_is_what_the_block_holds() {
960 let mut names = Interner::new();
964 let (mut func, mut ssa, entry, cond) = start(&mut names);
965 let x = Var::new(0);
966
967 let one = Builder::new(&mut func, entry).iconst(I32, 1);
968 ssa.write(x, entry, one);
969
970 let case = func.create_block();
971 let other = func.create_block();
972 let branch = Builder::new(&mut func, entry).br_if(cond, case, &[], other, &[]);
973 ssa.branch(&func, branch);
974 ssa.seal(&mut func, other);
975
976 let read = ssa.read(&mut func, x, case, I32);
978 let sum = Builder::new(&mut func, case).binary(Opcode::Add, read, read, Flags::NONE);
979 ssa.write(x, case, sum);
980
981 let mut build = Builder::new(&mut func, other);
983 let two = build.iconst(I32, 2);
984 let jump = build.jump(case, &[]);
985 ssa.write(x, other, two);
986 ssa.branch(&func, jump);
987 ssa.seal(&mut func, case);
988
989 let after = ssa.read(&mut func, x, case, I32);
990 assert_eq!(after, sum, "the block holds what it wrote, not the parameter it started at");
991 Builder::new(&mut func, case).ret(&[after]);
992 ssa.finish(&mut func);
993
994 assert_eq!(checked(func, &mut names), WRITTEN_AFTER);
995 }
996
997 #[test]
998 fn a_variable_nothing_wrote_reads_as_the_same_zero_every_time() {
999 let mut names = Interner::new();
1000 let (mut func, mut ssa, entry, _) = start(&mut names);
1001 let x = Var::new(0);
1002 let y = Var::new(1);
1003 let z = Var::new(2);
1004
1005 let first = ssa.read(&mut func, x, entry, I32);
1006 let second = ssa.read(&mut func, y, entry, I32);
1007 let pointer = ssa.read(&mut func, z, entry, Type::PTR);
1008 assert_eq!(first, second, "unspecified, and the same both times");
1009 assert_ne!(first, pointer);
1010
1011 Builder::new(&mut func, entry).ret(&[first]);
1012 ssa.finish(&mut func);
1013 assert_eq!(checked(func, &mut names), UNWRITTEN);
1014 }
1015
1016 const DIAMOND: &str = "\
1018func @f(i1) -> i32, linkage(external) {
1019block0(%0: i1):
1020 br_if %0, block1, block2
1021
1022block1:
1023 %1 = iconst.i32 1
1024 jump block3(%1)
1025
1026block2:
1027 %2 = iconst.i32 2
1028 jump block3(%2)
1029
1030block3(%3: i32):
1031 return %3
1032}
1033";
1034
1035 const AGREED: &str = "\
1037func @f(i1) -> i32, linkage(external) {
1038block0(%0: i1):
1039 %1 = iconst.i32 1
1040 br_if %0, block1, block2
1041
1042block1:
1043 jump block3
1044
1045block2:
1046 jump block3
1047
1048block3:
1049 return %1
1050}
1051";
1052
1053 const LOOP: &str = "\
1056func @f(i1) -> i32, linkage(external) {
1057block0(%0: i1):
1058 %1 = iconst.i32 0
1059 jump block1(%1)
1060
1061block1(%2: i32):
1062 %3 = iconst.i32 10
1063 %4 = icmp slt %2, %3
1064 br_if %4, block2, block3
1065
1066block2:
1067 %5 = iconst.i32 1
1068 %6 = add %2, %5
1069 jump block1(%6)
1070
1071block3:
1072 return %2
1073}
1074";
1075
1076 const UNCHANGED: &str = "\
1079func @f(i1) -> i32, linkage(external) {
1080block0(%0: i1):
1081 %1 = iconst.i32 7
1082 jump block1
1083
1084block1:
1085 br_if %0, block2, block3
1086
1087block2:
1088 %2 = add %1, %1
1089 jump block1
1090
1091block3:
1092 return %1
1093}
1094";
1095
1096 const NESTED: &str = "\
1099func @f(i1) -> i32, linkage(external) {
1100block0(%0: i1):
1101 %1 = iconst.i32 7
1102 jump block1
1103
1104block1:
1105 jump block2
1106
1107block2:
1108 %2 = add %1, %1
1109 br_if %0, block2, block3
1110
1111block3:
1112 br_if %0, block1, block4
1113
1114block4:
1115 return %1
1116}
1117";
1118
1119 const WRITTEN_AFTER: &str = "\
1122func @f(i1) -> i32, linkage(external) {
1123block0(%0: i1):
1124 %1 = iconst.i32 1
1125 br_if %0, block1(%1), block2
1126
1127block1(%2: i32):
1128 %3 = add %2, %2
1129 return %3
1130
1131block2:
1132 %4 = iconst.i32 2
1133 jump block1(%4)
1134}
1135";
1136
1137 const UNWRITTEN: &str = "\
1140func @f(i1) -> i32, linkage(external) {
1141block0(%0: i1):
1142 %1 = iconst.i64 0
1143 %2 = inttoptr.ptr %1
1144 %3 = iconst.i32 0
1145 return %3
1146}
1147";
1148}