ControlFlowGraph.cs 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156
  1. using ARMeilleure.IntermediateRepresentation;
  2. using System;
  3. using System.Collections.Generic;
  4. using System.Diagnostics;
  5. namespace ARMeilleure.Translation
  6. {
  7. class ControlFlowGraph
  8. {
  9. public BasicBlock Entry { get; }
  10. public IntrusiveList<BasicBlock> Blocks { get; }
  11. public BasicBlock[] PostOrderBlocks { get; }
  12. public int[] PostOrderMap { get; }
  13. public ControlFlowGraph(BasicBlock entry, IntrusiveList<BasicBlock> blocks)
  14. {
  15. Entry = entry;
  16. Blocks = blocks;
  17. RemoveUnreachableBlocks(blocks);
  18. HashSet<BasicBlock> visited = new HashSet<BasicBlock>();
  19. Stack<BasicBlock> blockStack = new Stack<BasicBlock>();
  20. PostOrderBlocks = new BasicBlock[blocks.Count];
  21. PostOrderMap = new int[blocks.Count];
  22. visited.Add(entry);
  23. blockStack.Push(entry);
  24. int index = 0;
  25. while (blockStack.TryPop(out BasicBlock block))
  26. {
  27. if (block.Next != null && visited.Add(block.Next))
  28. {
  29. blockStack.Push(block);
  30. blockStack.Push(block.Next);
  31. }
  32. else if (block.Branch != null && visited.Add(block.Branch))
  33. {
  34. blockStack.Push(block);
  35. blockStack.Push(block.Branch);
  36. }
  37. else
  38. {
  39. PostOrderMap[block.Index] = index;
  40. PostOrderBlocks[index++] = block;
  41. }
  42. }
  43. }
  44. private void RemoveUnreachableBlocks(IntrusiveList<BasicBlock> blocks)
  45. {
  46. HashSet<BasicBlock> visited = new HashSet<BasicBlock>();
  47. Queue<BasicBlock> workQueue = new Queue<BasicBlock>();
  48. visited.Add(Entry);
  49. workQueue.Enqueue(Entry);
  50. while (workQueue.TryDequeue(out BasicBlock block))
  51. {
  52. Debug.Assert(block.Index != -1, "Invalid block index.");
  53. if (block.Next != null && visited.Add(block.Next))
  54. {
  55. workQueue.Enqueue(block.Next);
  56. }
  57. if (block.Branch != null && visited.Add(block.Branch))
  58. {
  59. workQueue.Enqueue(block.Branch);
  60. }
  61. }
  62. if (visited.Count < blocks.Count)
  63. {
  64. // Remove unreachable blocks and renumber.
  65. int index = 0;
  66. for (BasicBlock block = blocks.First; block != null;)
  67. {
  68. BasicBlock nextBlock = block.ListNext;
  69. if (!visited.Contains(block))
  70. {
  71. block.Next = null;
  72. block.Branch = null;
  73. blocks.Remove(block);
  74. }
  75. else
  76. {
  77. block.Index = index++;
  78. }
  79. block = nextBlock;
  80. }
  81. }
  82. }
  83. public BasicBlock SplitEdge(BasicBlock predecessor, BasicBlock successor)
  84. {
  85. BasicBlock splitBlock = new BasicBlock(Blocks.Count);
  86. if (predecessor.Next == successor)
  87. {
  88. predecessor.Next = splitBlock;
  89. }
  90. if (predecessor.Branch == successor)
  91. {
  92. predecessor.Branch = splitBlock;
  93. }
  94. if (splitBlock.Predecessors.Count == 0)
  95. {
  96. throw new ArgumentException("Predecessor and successor are not connected.");
  97. }
  98. // Insert the new block on the list of blocks.
  99. BasicBlock succPrev = successor.ListPrevious;
  100. if (succPrev != null && succPrev != predecessor && succPrev.Next == successor)
  101. {
  102. // Can't insert after the predecessor or before the successor.
  103. // Here, we insert it before the successor by also spliting another
  104. // edge (the one between the block before "successor" and "successor").
  105. BasicBlock splitBlock2 = new BasicBlock(splitBlock.Index + 1);
  106. succPrev.Next = splitBlock2;
  107. splitBlock2.Branch = successor;
  108. splitBlock2.Operations.AddLast(OperationHelper.Operation(Instruction.Branch, null));
  109. Blocks.AddBefore(successor, splitBlock2);
  110. }
  111. splitBlock.Next = successor;
  112. Blocks.AddBefore(successor, splitBlock);
  113. return splitBlock;
  114. }
  115. }
  116. }