/ src / Ryujinx.Graphics.Shader / Translation / ControlFlowGraph.cs
ControlFlowGraph.cs
  1  using Ryujinx.Graphics.Shader.IntermediateRepresentation;
  2  using System.Collections.Generic;
  3  
  4  namespace Ryujinx.Graphics.Shader.Translation
  5  {
  6      class ControlFlowGraph
  7      {
  8          public BasicBlock[] Blocks { get; }
  9          public BasicBlock[] PostOrderBlocks { get; }
 10          public int[] PostOrderMap { get; }
 11  
 12          public ControlFlowGraph(BasicBlock[] blocks)
 13          {
 14              Blocks = blocks;
 15  
 16              HashSet<BasicBlock> visited = new();
 17  
 18              Stack<BasicBlock> blockStack = new();
 19  
 20              List<BasicBlock> postOrderBlocks = new(blocks.Length);
 21  
 22              PostOrderMap = new int[blocks.Length];
 23  
 24              visited.Add(blocks[0]);
 25  
 26              blockStack.Push(blocks[0]);
 27  
 28              while (blockStack.TryPop(out BasicBlock block))
 29              {
 30                  if (block.Next != null && visited.Add(block.Next))
 31                  {
 32                      blockStack.Push(block);
 33                      blockStack.Push(block.Next);
 34                  }
 35                  else if (block.Branch != null && visited.Add(block.Branch))
 36                  {
 37                      blockStack.Push(block);
 38                      blockStack.Push(block.Branch);
 39                  }
 40                  else
 41                  {
 42                      PostOrderMap[block.Index] = postOrderBlocks.Count;
 43  
 44                      postOrderBlocks.Add(block);
 45                  }
 46              }
 47  
 48              PostOrderBlocks = postOrderBlocks.ToArray();
 49          }
 50  
 51          public static ControlFlowGraph Create(Operation[] operations)
 52          {
 53              Dictionary<Operand, BasicBlock> labels = new();
 54  
 55              List<BasicBlock> blocks = new();
 56  
 57              BasicBlock currentBlock = null;
 58  
 59              void NextBlock(BasicBlock nextBlock)
 60              {
 61                  if (currentBlock != null && !EndsWithUnconditionalInst(currentBlock.GetLastOp()))
 62                  {
 63                      currentBlock.Next = nextBlock;
 64                  }
 65  
 66                  currentBlock = nextBlock;
 67              }
 68  
 69              void NewNextBlock()
 70              {
 71                  BasicBlock block = new(blocks.Count);
 72  
 73                  blocks.Add(block);
 74  
 75                  NextBlock(block);
 76              }
 77  
 78              bool needsNewBlock = true;
 79  
 80              for (int index = 0; index < operations.Length; index++)
 81              {
 82                  Operation operation = operations[index];
 83  
 84                  if (operation.Inst == Instruction.MarkLabel)
 85                  {
 86                      Operand label = operation.Dest;
 87  
 88                      if (labels.TryGetValue(label, out BasicBlock nextBlock))
 89                      {
 90                          nextBlock.Index = blocks.Count;
 91  
 92                          blocks.Add(nextBlock);
 93  
 94                          NextBlock(nextBlock);
 95                      }
 96                      else
 97                      {
 98                          NewNextBlock();
 99  
100                          labels.Add(label, currentBlock);
101                      }
102                  }
103                  else
104                  {
105                      if (needsNewBlock)
106                      {
107                          NewNextBlock();
108                      }
109  
110                      currentBlock.Operations.AddLast(operation);
111                  }
112  
113                  needsNewBlock = operation.Inst == Instruction.Branch ||
114                                  operation.Inst == Instruction.BranchIfTrue ||
115                                  operation.Inst == Instruction.BranchIfFalse;
116  
117                  if (needsNewBlock)
118                  {
119                      Operand label = operation.Dest;
120  
121                      if (!labels.TryGetValue(label, out BasicBlock branchBlock))
122                      {
123                          branchBlock = new BasicBlock();
124  
125                          labels.Add(label, branchBlock);
126                      }
127  
128                      currentBlock.Branch = branchBlock;
129                  }
130              }
131  
132              // Remove unreachable blocks.
133              bool hasUnreachable;
134  
135              do
136              {
137                  hasUnreachable = false;
138  
139                  for (int blkIndex = 1; blkIndex < blocks.Count; blkIndex++)
140                  {
141                      BasicBlock block = blocks[blkIndex];
142  
143                      if (block.Predecessors.Count == 0)
144                      {
145                          block.Next = null;
146                          block.Branch = null;
147                          blocks.RemoveAt(blkIndex--);
148                          hasUnreachable = true;
149                      }
150                      else
151                      {
152                          block.Index = blkIndex;
153                      }
154                  }
155              } while (hasUnreachable);
156  
157              return new ControlFlowGraph(blocks.ToArray());
158          }
159  
160          private static bool EndsWithUnconditionalInst(INode node)
161          {
162              if (node is Operation operation)
163              {
164                  switch (operation.Inst)
165                  {
166                      case Instruction.Branch:
167                      case Instruction.Discard:
168                      case Instruction.Return:
169                          return true;
170                  }
171              }
172  
173              return false;
174          }
175      }
176  }