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