aboutsummaryrefslogtreecommitdiff
path: root/src/Ryujinx.Cpu/LightningJit/Arm64/Block.cs
diff options
context:
space:
mode:
Diffstat (limited to 'src/Ryujinx.Cpu/LightningJit/Arm64/Block.cs')
-rw-r--r--src/Ryujinx.Cpu/LightningJit/Arm64/Block.cs138
1 files changed, 138 insertions, 0 deletions
diff --git a/src/Ryujinx.Cpu/LightningJit/Arm64/Block.cs b/src/Ryujinx.Cpu/LightningJit/Arm64/Block.cs
new file mode 100644
index 00000000..188630a1
--- /dev/null
+++ b/src/Ryujinx.Cpu/LightningJit/Arm64/Block.cs
@@ -0,0 +1,138 @@
+using Ryujinx.Cpu.LightningJit.Graph;
+using System.Collections.Generic;
+using System.Diagnostics;
+
+namespace Ryujinx.Cpu.LightningJit.Arm64
+{
+ class Block : IBlock
+ {
+ public int Index { get; private set; }
+
+ private readonly List<Block> _predecessors;
+ private readonly List<Block> _successors;
+
+ public int PredecessorsCount => _predecessors.Count;
+ public int SuccessorsCount => _successors.Count;
+
+ public readonly ulong Address;
+ public readonly ulong EndAddress;
+ public readonly List<InstInfo> Instructions;
+ public readonly bool EndsWithBranch;
+ public readonly bool IsTruncated;
+ public readonly bool IsLoopEnd;
+
+ public Block(ulong address, ulong endAddress, List<InstInfo> instructions, bool endsWithBranch, bool isTruncated, bool isLoopEnd)
+ {
+ Debug.Assert((int)((endAddress - address) / 4) == instructions.Count);
+
+ _predecessors = new();
+ _successors = new();
+ Address = address;
+ EndAddress = endAddress;
+ Instructions = instructions;
+ EndsWithBranch = endsWithBranch;
+ IsTruncated = isTruncated;
+ IsLoopEnd = isLoopEnd;
+ }
+
+ public (Block, Block) SplitAtAddress(ulong address)
+ {
+ int splitIndex = (int)((address - Address) / 4);
+ int splitCount = Instructions.Count - splitIndex;
+
+ // Technically those are valid, but we don't want to create empty blocks.
+ Debug.Assert(splitIndex != 0);
+ Debug.Assert(splitCount != 0);
+
+ Block leftBlock = new(
+ Address,
+ address,
+ Instructions.GetRange(0, splitIndex),
+ false,
+ false,
+ false);
+
+ Block rightBlock = new(
+ address,
+ EndAddress,
+ Instructions.GetRange(splitIndex, splitCount),
+ EndsWithBranch,
+ IsTruncated,
+ IsLoopEnd);
+
+ return (leftBlock, rightBlock);
+ }
+
+ public void Number(int index)
+ {
+ Index = index;
+ }
+
+ public void AddSuccessor(Block block)
+ {
+ if (!_successors.Contains(block))
+ {
+ _successors.Add(block);
+ }
+ }
+
+ public void AddPredecessor(Block block)
+ {
+ if (!_predecessors.Contains(block))
+ {
+ _predecessors.Add(block);
+ }
+ }
+
+ public IBlock GetSuccessor(int index)
+ {
+ return _successors[index];
+ }
+
+ public IBlock GetPredecessor(int index)
+ {
+ return _predecessors[index];
+ }
+
+ public RegisterUse ComputeUseMasks()
+ {
+ if (Instructions.Count == 0)
+ {
+ return new(0u, 0u, 0u, 0u, 0u, 0u);
+ }
+
+ RegisterUse use = Instructions[0].RegisterUse;
+
+ for (int index = 1; index < Instructions.Count; index++)
+ {
+ RegisterUse currentUse = Instructions[index].RegisterUse;
+
+ use = new(use.Read | (currentUse.Read & ~use.Write), use.Write | currentUse.Write);
+ }
+
+ return use;
+ }
+
+ public bool EndsWithContextLoad()
+ {
+ return !IsTruncated && EndsWithContextStoreAndLoad();
+ }
+
+ public bool EndsWithContextStore()
+ {
+ return EndsWithContextStoreAndLoad();
+ }
+
+ private bool EndsWithContextStoreAndLoad()
+ {
+ if (Instructions.Count == 0)
+ {
+ return false;
+ }
+
+ InstName lastInstructionName = Instructions[^1].Name;
+
+ return lastInstructionName.IsCall() || lastInstructionName.IsException();
+ }
+ }
+}