/ src / ARMeilleure / Translation / ControlFlowGraph.cs
ControlFlowGraph.cs
  1  using ARMeilleure.IntermediateRepresentation;
  2  using System;
  3  using System.Collections.Generic;
  4  using System.Diagnostics;
  5  
  6  namespace ARMeilleure.Translation
  7  {
  8      class ControlFlowGraph
  9      {
 10          private BasicBlock[] _postOrderBlocks;
 11          private int[] _postOrderMap;
 12  
 13          public int LocalsCount { get; private set; }
 14          public BasicBlock Entry { get; private set; }
 15          public IntrusiveList<BasicBlock> Blocks { get; }
 16          public BasicBlock[] PostOrderBlocks => _postOrderBlocks;
 17          public int[] PostOrderMap => _postOrderMap;
 18  
 19          public ControlFlowGraph(BasicBlock entry, IntrusiveList<BasicBlock> blocks, int localsCount)
 20          {
 21              Entry = entry;
 22              Blocks = blocks;
 23              LocalsCount = localsCount;
 24  
 25              Update();
 26          }
 27  
 28          public Operand AllocateLocal(OperandType type)
 29          {
 30              Operand result = Operand.Factory.Local(type);
 31  
 32              result.NumberLocal(++LocalsCount);
 33  
 34              return result;
 35          }
 36  
 37          public void UpdateEntry(BasicBlock newEntry)
 38          {
 39              newEntry.AddSuccessor(Entry);
 40  
 41              Entry = newEntry;
 42              Blocks.AddFirst(newEntry);
 43              Update();
 44          }
 45  
 46          public void Update()
 47          {
 48              RemoveUnreachableBlocks(Blocks);
 49  
 50              var visited = new HashSet<BasicBlock>();
 51              var blockStack = new Stack<BasicBlock>();
 52  
 53              Array.Resize(ref _postOrderBlocks, Blocks.Count);
 54              Array.Resize(ref _postOrderMap, Blocks.Count);
 55  
 56              visited.Add(Entry);
 57              blockStack.Push(Entry);
 58  
 59              int index = 0;
 60  
 61              while (blockStack.TryPop(out BasicBlock block))
 62              {
 63                  bool visitedNew = false;
 64  
 65                  for (int i = 0; i < block.SuccessorsCount; i++)
 66                  {
 67                      BasicBlock succ = block.GetSuccessor(i);
 68  
 69                      if (visited.Add(succ))
 70                      {
 71                          blockStack.Push(block);
 72                          blockStack.Push(succ);
 73  
 74                          visitedNew = true;
 75  
 76                          break;
 77                      }
 78                  }
 79  
 80                  if (!visitedNew)
 81                  {
 82                      PostOrderMap[block.Index] = index;
 83  
 84                      PostOrderBlocks[index++] = block;
 85                  }
 86              }
 87          }
 88  
 89          private void RemoveUnreachableBlocks(IntrusiveList<BasicBlock> blocks)
 90          {
 91              var visited = new HashSet<BasicBlock>();
 92              var workQueue = new Queue<BasicBlock>();
 93  
 94              visited.Add(Entry);
 95              workQueue.Enqueue(Entry);
 96  
 97              while (workQueue.TryDequeue(out BasicBlock block))
 98              {
 99                  Debug.Assert(block.Index != -1, "Invalid block index.");
100  
101                  for (int i = 0; i < block.SuccessorsCount; i++)
102                  {
103                      BasicBlock succ = block.GetSuccessor(i);
104  
105                      if (visited.Add(succ))
106                      {
107                          workQueue.Enqueue(succ);
108                      }
109                  }
110              }
111  
112              if (visited.Count < blocks.Count)
113              {
114                  // Remove unreachable blocks and renumber.
115                  int index = 0;
116  
117                  for (BasicBlock block = blocks.First; block != null;)
118                  {
119                      BasicBlock nextBlock = block.ListNext;
120  
121                      if (!visited.Contains(block))
122                      {
123                          while (block.SuccessorsCount > 0)
124                          {
125                              block.RemoveSuccessor(index: block.SuccessorsCount - 1);
126                          }
127  
128                          blocks.Remove(block);
129                      }
130                      else
131                      {
132                          block.Index = index++;
133                      }
134  
135                      block = nextBlock;
136                  }
137              }
138          }
139  
140          public BasicBlock SplitEdge(BasicBlock predecessor, BasicBlock successor)
141          {
142              BasicBlock splitBlock = new(Blocks.Count);
143  
144              for (int i = 0; i < predecessor.SuccessorsCount; i++)
145              {
146                  if (predecessor.GetSuccessor(i) == successor)
147                  {
148                      predecessor.SetSuccessor(i, splitBlock);
149                  }
150              }
151  
152              if (splitBlock.Predecessors.Count == 0)
153              {
154                  throw new ArgumentException("Predecessor and successor are not connected.");
155              }
156  
157              splitBlock.AddSuccessor(successor);
158  
159              Blocks.AddBefore(successor, splitBlock);
160  
161              return splitBlock;
162          }
163      }
164  }