1use std::collections::HashMap;
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}
109
110impl Ssa {
111 #[must_use]
118 pub fn new(address: Type) -> Ssa {
119 Ssa {
120 address,
121 defs: HashMap::new(),
122 sealed: Vec::new(),
123 incomplete: Vec::new(),
124 preds: Vec::new(),
125 phis: HashMap::new(),
126 users: HashMap::new(),
127 subst: HashMap::new(),
128 zero: Vec::new(),
129 }
130 }
131
132 pub fn write(&mut self, var: Var, block: Block, value: Value) {
134 self.defs.insert((var, block), value);
135 }
136
137 pub fn read(&mut self, func: &mut Func, var: Var, block: Block, ty: Type) -> Value {
154 let mut chain = Vec::new();
159 let mut at = block;
160 let value = loop {
161 if let Some(&value) = self.defs.get(&(var, at)) {
162 break self.resolve(value);
163 }
164 self.reserve(at);
165 if !self.sealed[at.index()] {
166 break self.pending(func, var, at, ty);
167 }
168 match self.preds[at.index()].len() {
169 0 => break self.undefined(func, ty),
171 1 => {
173 chain.push(at);
174 at = self.preds[at.index()][0].from;
175 }
176 _ => break self.phi(func, var, at, ty),
177 }
178 };
179 for at in chain {
180 self.write(var, at, value);
181 }
182 self.write(var, block, value);
183 value
184 }
185
186 pub fn branch(&mut self, func: &Func, inst: Inst) {
197 let from = func.block_of(inst).expect("a terminator in a block");
198 for call in func.target_list(inst).iter() {
199 let to = func[call].block;
200 self.reserve(to);
201 self.preds[to.index()].push(Edge { from, call });
202 }
203 }
204
205 pub fn seal(&mut self, func: &mut Func, block: Block) {
211 self.reserve(block);
212 assert!(!self.sealed[block.index()], "a block is sealed once");
213 self.sealed[block.index()] = true;
214 let waiting = std::mem::take(&mut self.incomplete[block.index()]);
217 for (var, phi) in waiting {
218 let value = self.operands(func, var, phi);
219 if self.defs.get(&(var, block)) == Some(&phi) {
225 self.write(var, block, value);
226 }
227 }
228 }
229
230 #[must_use]
232 pub fn is_sealed(&self, block: Block) -> bool {
233 self.sealed.get(block.index()).copied().unwrap_or(false)
234 }
235
236 pub fn finish(mut self, func: &mut Func) {
243 if self.subst.is_empty() {
244 return;
245 }
246
247 let blocks: Vec<Block> = func.blocks().collect();
248 for &block in &blocks {
249 let insts: Vec<Inst> = func.insts(block).collect();
250 for inst in insts {
251 let args = func[inst].args;
252 func.rewrite(args, |value| self.resolve(value));
253 for call in func.target_list(inst).iter() {
254 let args = func[call].args;
255 func.rewrite(args, |value| self.resolve(value));
256 }
257 }
258 }
259
260 let mut dropped: Vec<Vec<usize>> = vec![Vec::new(); func.counts().blocks];
264 for &block in &blocks {
265 for (index, ¶m) in func[block].params.iter().enumerate() {
266 if self.subst.contains_key(¶m) {
267 dropped[block.index()].push(index);
268 }
269 }
270 }
271
272 for &block in &blocks {
273 let insts: Vec<Inst> = func.insts(block).collect();
274 for inst in insts {
275 for at in func.target_list(inst).iter() {
276 let mut call = func[at];
277 let going = &dropped[call.block.index()];
278 if going.is_empty() {
279 continue;
280 }
281 let kept: Vec<Value> = func[call.args]
282 .iter()
283 .copied()
284 .enumerate()
285 .filter(|(index, _)| !going.contains(index))
286 .map(|(_, value)| value)
287 .collect();
288 call.args = func.push_values(&kept);
289 func.set_block_call(at, call);
290 }
291 }
292 }
293
294 for &block in &blocks {
295 if !dropped[block.index()].is_empty() {
296 func.retain_params(block, |param| !self.subst.contains_key(¶m));
297 }
298 }
299 }
300
301 fn pending(&mut self, func: &mut Func, var: Var, block: Block, ty: Type) -> Value {
305 let phi = func.append_param(block, ty);
306 self.phis.insert(phi, Phi { block, var });
307 self.incomplete[block.index()].push((var, phi));
308 self.write(var, block, phi);
309 phi
310 }
311
312 fn phi(&mut self, func: &mut Func, var: Var, block: Block, ty: Type) -> Value {
314 let phi = func.append_param(block, ty);
315 self.phis.insert(phi, Phi { block, var });
316 self.write(var, block, phi);
319 self.operands(func, var, phi)
320 }
321
322 fn operands(&mut self, func: &mut Func, var: Var, phi: Value) -> Value {
324 let block = self.phis[&phi].block;
325 let ty = func[phi].ty;
326 for index in 0..self.preds[block.index()].len() {
330 let edge = self.preds[block.index()][index];
331 let value = self.read(func, var, edge.from, ty);
332 let mut call = func[edge.call];
333 call.args = func.append_arg(call.args, value);
334 func.set_block_call(edge.call, call);
335 self.users.entry(value).or_default().push(phi);
336 }
337 self.trivial(func, phi)
338 }
339
340 fn trivial(&mut self, func: &mut Func, phi: Value) -> Value {
347 let block = self.phis[&phi].block;
348 let Some(at) = func[block].params.iter().position(|¶m| param == phi) else {
349 return phi;
350 };
351
352 let mut same: Option<Value> = None;
353 for index in 0..self.preds[block.index()].len() {
354 let edge = self.preds[block.index()][index];
355 let arg = self.resolve(func[func[edge.call].args][at]);
356 if arg == phi || same == Some(arg) {
357 continue;
358 }
359 if same.is_some() {
360 return phi;
362 }
363 same = Some(arg);
364 }
365
366 let same = match same {
367 Some(value) => value,
368 None => self.undefined(func, func[phi].ty),
371 };
372 self.subst.insert(phi, same);
373
374 let users = self.users.remove(&phi).unwrap_or_default();
377 let inherited: Vec<Value> = users.iter().copied().filter(|&user| user != phi).collect();
378 self.users.entry(same).or_default().extend(inherited.iter().copied());
379 for user in inherited {
380 if !self.subst.contains_key(&user) {
381 self.trivial(func, user);
382 }
383 }
384 self.resolve(same)
385 }
386
387 fn resolve(&mut self, value: Value) -> Value {
393 let mut at = value;
394 while let Some(&next) = self.subst.get(&at) {
395 at = next;
396 }
397 if at != value {
398 self.subst.insert(value, at);
399 }
400 at
401 }
402
403 fn undefined(&mut self, func: &mut Func, ty: Type) -> Value {
408 if let Some(&(_, value)) = self.zero.iter().find(|&&(at, _)| at == ty) {
409 return value;
410 }
411
412 let entry = func.entry().expect("a function with a block in it");
413 let first = func.insts(entry).next();
414 let value = if ty.is_ptr() {
415 let int = self.constant(func, entry, first, self.address);
416 let args = func.push_values(&[int]);
417 let cast = func.create_inst(
418 InstData { args, ..InstData::new(Opcode::IntToPtr) },
419 &[ty],
420 Span::DUMMY,
421 );
422 place(func, entry, first, cast);
423 func[cast].first_result.expect("one result")
424 } else {
425 self.constant(func, entry, first, ty)
426 };
427
428 self.zero.push((ty, value));
429 value
430 }
431
432 fn constant(&mut self, func: &mut Func, entry: Block, first: Option<Inst>, ty: Type) -> Value {
434 let imm = if ty.lane().is_float() { Imm::from_bits(0) } else { Imm::int(0, ty.lane()) };
435 let imm = func.add_imm(imm);
436 let opcode = if ty.lane().is_float() { Opcode::FConst } else { Opcode::IConst };
437 let inst = func.create_inst(
438 InstData { extra: Extra::Imm(imm), ..InstData::new(opcode) },
439 &[ty],
440 Span::DUMMY,
441 );
442 place(func, entry, first, inst);
443 func[inst].first_result.expect("one result")
444 }
445
446 fn reserve(&mut self, block: Block) {
448 let wanted = block.index() + 1;
449 if self.sealed.len() < wanted {
450 self.sealed.resize(wanted, false);
451 self.incomplete.resize_with(wanted, Vec::new);
452 self.preds.resize_with(wanted, Vec::new);
453 }
454 }
455}
456
457fn place(func: &mut Func, entry: Block, first: Option<Inst>, inst: Inst) {
459 match first {
460 Some(first) => func.insert_before(inst, first),
461 None => func.append_inst(entry, inst),
462 }
463}
464
465#[cfg(test)]
466mod tests {
467 use rucc_base::Interner;
468 use rucc_ir::{Builder, Flags, IntPred, Module, Signature, print_func, verify_func};
469 use rucc_target::{Arch, Env, Os, TargetInfo, Triple};
470
471 use super::*;
472
473 const I32: Type = Type::int(32);
474 const BOOL: Type = Type::int(1);
475
476 fn target() -> TargetInfo {
477 TargetInfo::new(Triple::new(Arch::X86_64, Os::Linux, Env::Gnu))
478 }
479
480 fn checked(func: Func, names: &mut Interner) -> String {
487 let mut module = Module::new(names.intern("t.c"), &target());
488 let id = module.add_func(func);
489 if let Err(errors) = verify_func(&module, &module[id], names) {
490 let listed: Vec<String> = errors.iter().map(ToString::to_string).collect();
491 panic!("{}", listed.join("\n"));
492 }
493 print_func(&module, &module[id], names)
494 }
495
496 fn start(names: &mut Interner) -> (Func, Ssa, Block, Value) {
498 let signature = Signature::new().with_params(&[BOOL]).with_returns(&[I32]);
499 let mut func = Func::new(names.intern("f"), signature);
500 let entry = func.create_block();
501 let cond = func.append_param(entry, BOOL);
502 let mut ssa = Ssa::new(Type::int(64));
503 ssa.seal(&mut func, entry);
504 (func, ssa, entry, cond)
505 }
506
507 #[test]
508 fn a_variable_read_where_it_was_written_is_the_value_it_was_written() {
509 let mut names = Interner::new();
510 let (mut func, mut ssa, entry, _) = start(&mut names);
511 let x = Var::new(0);
512
513 let one = Builder::new(&mut func, entry).iconst(I32, 1);
514 ssa.write(x, entry, one);
515 let read = ssa.read(&mut func, x, entry, I32);
516 assert_eq!(read, one);
517
518 Builder::new(&mut func, entry).ret(&[read]);
519 ssa.finish(&mut func);
520 assert!(func[entry].params.len() == 1, "no parameter was needed");
521 }
522
523 #[test]
524 fn a_variable_written_on_both_arms_arrives_as_a_block_parameter() {
525 let mut names = Interner::new();
526 let (mut func, mut ssa, entry, cond) = start(&mut names);
527 let x = Var::new(0);
528
529 let then = func.create_block();
530 let otherwise = func.create_block();
531 let join = func.create_block();
532
533 let branch = Builder::new(&mut func, entry).br_if(cond, then, &[], otherwise, &[]);
534 ssa.branch(&func, branch);
535 ssa.seal(&mut func, then);
536 ssa.seal(&mut func, otherwise);
537
538 let one = Builder::new(&mut func, then).iconst(I32, 1);
539 ssa.write(x, then, one);
540 let jump = Builder::new(&mut func, then).jump(join, &[]);
541 ssa.branch(&func, jump);
542
543 let two = Builder::new(&mut func, otherwise).iconst(I32, 2);
544 ssa.write(x, otherwise, two);
545 let jump = Builder::new(&mut func, otherwise).jump(join, &[]);
546 ssa.branch(&func, jump);
547
548 ssa.seal(&mut func, join);
549 let read = ssa.read(&mut func, x, join, I32);
550 Builder::new(&mut func, join).ret(&[read]);
551 ssa.finish(&mut func);
552
553 assert_eq!(checked(func, &mut names), DIAMOND);
554 }
555
556 #[test]
557 fn a_variable_both_arms_agree_about_needs_no_block_parameter() {
558 let mut names = Interner::new();
559 let (mut func, mut ssa, entry, cond) = start(&mut names);
560 let x = Var::new(0);
561
562 let one = Builder::new(&mut func, entry).iconst(I32, 1);
563 ssa.write(x, entry, one);
564
565 let then = func.create_block();
566 let otherwise = func.create_block();
567 let join = func.create_block();
568
569 let branch = Builder::new(&mut func, entry).br_if(cond, then, &[], otherwise, &[]);
570 ssa.branch(&func, branch);
571 ssa.seal(&mut func, then);
572 ssa.seal(&mut func, otherwise);
573
574 for block in [then, otherwise] {
575 let jump = Builder::new(&mut func, block).jump(join, &[]);
576 ssa.branch(&func, jump);
577 }
578
579 ssa.seal(&mut func, join);
580 let read = ssa.read(&mut func, x, join, I32);
581 assert_eq!(read, one, "the parameter stood for the one value both arms had");
582 Builder::new(&mut func, join).ret(&[read]);
583 ssa.finish(&mut func);
584
585 assert!(func[join].params.is_empty(), "the parameter was taken out again");
586 assert_eq!(checked(func, &mut names), AGREED);
587 }
588
589 #[test]
590 fn a_variable_a_loop_changes_is_carried_by_the_headers_parameter() {
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 zero = Builder::new(&mut func, entry).iconst(I32, 0);
596 ssa.write(x, entry, zero);
597
598 let header = func.create_block();
599 let body = func.create_block();
600 let exit = func.create_block();
601
602 let jump = Builder::new(&mut func, entry).jump(header, &[]);
603 ssa.branch(&func, jump);
604
605 let counter = ssa.read(&mut func, x, header, I32);
608 let mut build = Builder::new(&mut func, header);
609 let ten = build.iconst(I32, 10);
610 let test = build.icmp(IntPred::Slt, counter, ten);
611 let branch = build.br_if(test, body, &[], exit, &[]);
612 ssa.branch(&func, branch);
613 ssa.seal(&mut func, body);
614 ssa.seal(&mut func, exit);
615
616 let carried = ssa.read(&mut func, x, body, I32);
617 let mut build = Builder::new(&mut func, body);
618 let one = build.iconst(I32, 1);
619 let next = build.binary(Opcode::Add, carried, one, Flags::NONE);
620 let jump = build.jump(header, &[]);
621 ssa.write(x, body, next);
622 ssa.branch(&func, jump);
623 ssa.seal(&mut func, header);
624
625 let result = ssa.read(&mut func, x, exit, I32);
626 Builder::new(&mut func, exit).ret(&[result]);
627 ssa.finish(&mut func);
628
629 assert_eq!(checked(func, &mut names), LOOP);
630 }
631
632 #[test]
633 fn a_variable_a_loop_does_not_change_is_not_carried_at_all() {
634 let mut names = Interner::new();
635 let (mut func, mut ssa, entry, cond) = start(&mut names);
636 let x = Var::new(0);
637
638 let seven = Builder::new(&mut func, entry).iconst(I32, 7);
639 ssa.write(x, entry, seven);
640
641 let header = func.create_block();
642 let body = func.create_block();
643 let exit = func.create_block();
644
645 let jump = Builder::new(&mut func, entry).jump(header, &[]);
646 ssa.branch(&func, jump);
647
648 let branch = Builder::new(&mut func, header).br_if(cond, body, &[], exit, &[]);
649 ssa.branch(&func, branch);
650 ssa.seal(&mut func, body);
651 ssa.seal(&mut func, exit);
652
653 let inside = ssa.read(&mut func, x, body, I32);
656 let mut build = Builder::new(&mut func, body);
657 build.binary(Opcode::Add, inside, inside, Flags::NONE);
658 let jump = build.jump(header, &[]);
659 ssa.branch(&func, jump);
660 ssa.seal(&mut func, header);
661
662 let result = ssa.read(&mut func, x, exit, I32);
663 Builder::new(&mut func, exit).ret(&[result]);
664 ssa.finish(&mut func);
665
666 assert!(func[header].params.is_empty(), "the parameter went, and the addition reads %1");
667 assert_eq!(checked(func, &mut names), UNCHANGED);
668 }
669
670 #[test]
671 fn a_variable_two_nested_loops_do_not_change_is_carried_by_neither() {
672 let mut names = Interner::new();
676 let (mut func, mut ssa, entry, cond) = start(&mut names);
677 let x = Var::new(0);
678
679 let seven = Builder::new(&mut func, entry).iconst(I32, 7);
680 ssa.write(x, entry, seven);
681
682 let outer = func.create_block();
683 let inner = func.create_block();
684 let latch = func.create_block();
685 let exit = func.create_block();
686
687 let jump = Builder::new(&mut func, entry).jump(outer, &[]);
688 ssa.branch(&func, jump);
689
690 let jump = Builder::new(&mut func, outer).jump(inner, &[]);
691 ssa.branch(&func, jump);
692
693 let read = ssa.read(&mut func, x, inner, I32);
694 let mut build = Builder::new(&mut func, inner);
695 build.binary(Opcode::Add, read, read, Flags::NONE);
696 let branch = build.br_if(cond, inner, &[], latch, &[]);
697 ssa.branch(&func, branch);
698 ssa.seal(&mut func, inner);
699 ssa.seal(&mut func, latch);
700
701 let branch = Builder::new(&mut func, latch).br_if(cond, outer, &[], exit, &[]);
702 ssa.branch(&func, branch);
703 ssa.seal(&mut func, outer);
704 ssa.seal(&mut func, exit);
705
706 let result = ssa.read(&mut func, x, exit, I32);
707 Builder::new(&mut func, exit).ret(&[result]);
708 ssa.finish(&mut func);
709
710 assert!(func[outer].params.is_empty() && func[inner].params.is_empty());
711 assert_eq!(checked(func, &mut names), NESTED);
712 }
713
714 #[test]
715 fn a_write_after_the_read_that_made_a_parameter_is_what_the_block_holds() {
716 let mut names = Interner::new();
720 let (mut func, mut ssa, entry, cond) = start(&mut names);
721 let x = Var::new(0);
722
723 let one = Builder::new(&mut func, entry).iconst(I32, 1);
724 ssa.write(x, entry, one);
725
726 let case = func.create_block();
727 let other = func.create_block();
728 let branch = Builder::new(&mut func, entry).br_if(cond, case, &[], other, &[]);
729 ssa.branch(&func, branch);
730 ssa.seal(&mut func, other);
731
732 let read = ssa.read(&mut func, x, case, I32);
734 let sum = Builder::new(&mut func, case).binary(Opcode::Add, read, read, Flags::NONE);
735 ssa.write(x, case, sum);
736
737 let mut build = Builder::new(&mut func, other);
739 let two = build.iconst(I32, 2);
740 let jump = build.jump(case, &[]);
741 ssa.write(x, other, two);
742 ssa.branch(&func, jump);
743 ssa.seal(&mut func, case);
744
745 let after = ssa.read(&mut func, x, case, I32);
746 assert_eq!(after, sum, "the block holds what it wrote, not the parameter it started at");
747 Builder::new(&mut func, case).ret(&[after]);
748 ssa.finish(&mut func);
749
750 assert_eq!(checked(func, &mut names), WRITTEN_AFTER);
751 }
752
753 #[test]
754 fn a_variable_nothing_wrote_reads_as_the_same_zero_every_time() {
755 let mut names = Interner::new();
756 let (mut func, mut ssa, entry, _) = start(&mut names);
757 let x = Var::new(0);
758 let y = Var::new(1);
759 let z = Var::new(2);
760
761 let first = ssa.read(&mut func, x, entry, I32);
762 let second = ssa.read(&mut func, y, entry, I32);
763 let pointer = ssa.read(&mut func, z, entry, Type::PTR);
764 assert_eq!(first, second, "unspecified, and the same both times");
765 assert_ne!(first, pointer);
766
767 Builder::new(&mut func, entry).ret(&[first]);
768 ssa.finish(&mut func);
769 assert_eq!(checked(func, &mut names), UNWRITTEN);
770 }
771
772 const DIAMOND: &str = "\
774func @f(i1) -> i32, linkage(external) {
775block0(%0: i1):
776 br_if %0, block1, block2
777
778block1:
779 %1 = iconst.i32 1
780 jump block3(%1)
781
782block2:
783 %2 = iconst.i32 2
784 jump block3(%2)
785
786block3(%3: i32):
787 return %3
788}
789";
790
791 const AGREED: &str = "\
793func @f(i1) -> i32, linkage(external) {
794block0(%0: i1):
795 %1 = iconst.i32 1
796 br_if %0, block1, block2
797
798block1:
799 jump block3
800
801block2:
802 jump block3
803
804block3:
805 return %1
806}
807";
808
809 const LOOP: &str = "\
812func @f(i1) -> i32, linkage(external) {
813block0(%0: i1):
814 %1 = iconst.i32 0
815 jump block1(%1)
816
817block1(%2: i32):
818 %3 = iconst.i32 10
819 %4 = icmp slt %2, %3
820 br_if %4, block2, block3
821
822block2:
823 %5 = iconst.i32 1
824 %6 = add %2, %5
825 jump block1(%6)
826
827block3:
828 return %2
829}
830";
831
832 const UNCHANGED: &str = "\
835func @f(i1) -> i32, linkage(external) {
836block0(%0: i1):
837 %1 = iconst.i32 7
838 jump block1
839
840block1:
841 br_if %0, block2, block3
842
843block2:
844 %2 = add %1, %1
845 jump block1
846
847block3:
848 return %1
849}
850";
851
852 const NESTED: &str = "\
855func @f(i1) -> i32, linkage(external) {
856block0(%0: i1):
857 %1 = iconst.i32 7
858 jump block1
859
860block1:
861 jump block2
862
863block2:
864 %2 = add %1, %1
865 br_if %0, block2, block3
866
867block3:
868 br_if %0, block1, block4
869
870block4:
871 return %1
872}
873";
874
875 const WRITTEN_AFTER: &str = "\
878func @f(i1) -> i32, linkage(external) {
879block0(%0: i1):
880 %1 = iconst.i32 1
881 br_if %0, block1(%1), block2
882
883block1(%2: i32):
884 %3 = add %2, %2
885 return %3
886
887block2:
888 %4 = iconst.i32 2
889 jump block1(%4)
890}
891";
892
893 const UNWRITTEN: &str = "\
896func @f(i1) -> i32, linkage(external) {
897block0(%0: i1):
898 %1 = iconst.i64 0
899 %2 = inttoptr.ptr %1
900 %3 = iconst.i32 0
901 return %3
902}
903";
904}