mirror of
				https://github.com/Ryujinx/Ryujinx.git
				synced 2025-10-25 04:32:34 -07:00 
			
		
		
		
	* Implement block placement Implement a simple pass which re-orders cold blocks at the end of the list of blocks in the CFG. * Set PPTC version * Use Array.Resize Address gdkchan's feedback
		
			
				
	
	
		
			147 lines
		
	
	
		
			4.2 KiB
		
	
	
	
		
			C#
		
	
	
	
	
	
			
		
		
	
	
			147 lines
		
	
	
		
			4.2 KiB
		
	
	
	
		
			C#
		
	
	
	
	
	
| using ARMeilleure.IntermediateRepresentation;
 | |
| using System;
 | |
| using System.Collections.Generic;
 | |
| using System.Diagnostics;
 | |
| 
 | |
| namespace ARMeilleure.Translation
 | |
| {
 | |
|     class ControlFlowGraph
 | |
|     {
 | |
|         private BasicBlock[] _postOrderBlocks;
 | |
|         private int[] _postOrderMap;
 | |
| 
 | |
|         public BasicBlock Entry { get; }
 | |
|         public IntrusiveList<BasicBlock> Blocks { get; }
 | |
|         public BasicBlock[] PostOrderBlocks => _postOrderBlocks;
 | |
|         public int[] PostOrderMap => _postOrderMap; 
 | |
| 
 | |
|         public ControlFlowGraph(BasicBlock entry, IntrusiveList<BasicBlock> blocks)
 | |
|         {
 | |
|             Entry = entry;
 | |
|             Blocks = blocks;
 | |
| 
 | |
|             Update(removeUnreachableBlocks: true);
 | |
|         }
 | |
| 
 | |
|         public void Update(bool removeUnreachableBlocks)
 | |
|         {
 | |
|             if (removeUnreachableBlocks)
 | |
|             {
 | |
|                 RemoveUnreachableBlocks(Blocks);
 | |
|             }
 | |
| 
 | |
|             var visited = new HashSet<BasicBlock>();
 | |
|             var blockStack = new Stack<BasicBlock>();
 | |
| 
 | |
|             Array.Resize(ref _postOrderBlocks, Blocks.Count);
 | |
|             Array.Resize(ref _postOrderMap, Blocks.Count);
 | |
| 
 | |
|             visited.Add(Entry);
 | |
|             blockStack.Push(Entry);
 | |
| 
 | |
|             int index = 0;
 | |
| 
 | |
|             while (blockStack.TryPop(out BasicBlock block))
 | |
|             {
 | |
|                 bool visitedNew = false;
 | |
| 
 | |
|                 for (int i = 0; i < block.SuccessorCount; i++)
 | |
|                 {
 | |
|                     BasicBlock succ = block.GetSuccessor(i);
 | |
| 
 | |
|                     if (visited.Add(succ))
 | |
|                     {
 | |
|                         blockStack.Push(block);
 | |
|                         blockStack.Push(succ);
 | |
| 
 | |
|                         visitedNew = true;
 | |
| 
 | |
|                         break;
 | |
|                     }
 | |
|                 }
 | |
| 
 | |
|                 if (!visitedNew)
 | |
|                 {
 | |
|                     PostOrderMap[block.Index] = index;
 | |
| 
 | |
|                     PostOrderBlocks[index++] = block;
 | |
|                 }
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         private void RemoveUnreachableBlocks(IntrusiveList<BasicBlock> blocks)
 | |
|         {
 | |
|             var visited = new HashSet<BasicBlock>();
 | |
|             var workQueue = new Queue<BasicBlock>();
 | |
| 
 | |
|             visited.Add(Entry);
 | |
|             workQueue.Enqueue(Entry);
 | |
| 
 | |
|             while (workQueue.TryDequeue(out BasicBlock block))
 | |
|             {
 | |
|                 Debug.Assert(block.Index != -1, "Invalid block index.");
 | |
| 
 | |
|                 for (int i = 0; i < block.SuccessorCount; i++)
 | |
|                 {
 | |
|                     BasicBlock succ = block.GetSuccessor(i);
 | |
| 
 | |
|                     if (visited.Add(succ))
 | |
|                     {
 | |
|                         workQueue.Enqueue(succ);
 | |
|                     }
 | |
|                 }
 | |
|             }
 | |
| 
 | |
|             if (visited.Count < blocks.Count)
 | |
|             {
 | |
|                 // Remove unreachable blocks and renumber.
 | |
|                 int index = 0;
 | |
| 
 | |
|                 for (BasicBlock block = blocks.First; block != null;)
 | |
|                 {
 | |
|                     BasicBlock nextBlock = block.ListNext;
 | |
| 
 | |
|                     if (!visited.Contains(block))
 | |
|                     {
 | |
|                         while (block.SuccessorCount > 0)
 | |
|                         {
 | |
|                             block.RemoveSuccessor(index: block.SuccessorCount - 1);
 | |
|                         }
 | |
| 
 | |
|                         blocks.Remove(block);
 | |
|                     }
 | |
|                     else
 | |
|                     {
 | |
|                         block.Index = index++;
 | |
|                     }
 | |
| 
 | |
|                     block = nextBlock;
 | |
|                 }
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         public BasicBlock SplitEdge(BasicBlock predecessor, BasicBlock successor)
 | |
|         {
 | |
|             BasicBlock splitBlock = new BasicBlock(Blocks.Count);
 | |
| 
 | |
|             for (int i = 0; i < predecessor.SuccessorCount; i++)
 | |
|             {
 | |
|                 if (predecessor.GetSuccessor(i) == successor)
 | |
|                 {
 | |
|                     predecessor.SetSuccessor(i, splitBlock);
 | |
|                 }
 | |
|             }
 | |
| 
 | |
|             if (splitBlock.Predecessors.Count == 0)
 | |
|             {
 | |
|                 throw new ArgumentException("Predecessor and successor are not connected.");
 | |
|             }
 | |
| 
 | |
|             splitBlock.AddSuccessor(successor);
 | |
| 
 | |
|             Blocks.AddBefore(successor, splitBlock);
 | |
| 
 | |
|             return splitBlock;
 | |
|         }
 | |
|     }
 | |
| } |