aboutsummaryrefslogtreecommitdiff
path: root/src/Ryujinx.Graphics.Shader/Decoders/Block.cs
diff options
context:
space:
mode:
authorTSR Berry <20988865+TSRBerry@users.noreply.github.com>2023-04-08 01:22:00 +0200
committerMary <thog@protonmail.com>2023-04-27 23:51:14 +0200
commitcee712105850ac3385cd0091a923438167433f9f (patch)
tree4a5274b21d8b7f938c0d0ce18736d3f2993b11b1 /src/Ryujinx.Graphics.Shader/Decoders/Block.cs
parentcd124bda587ef09668a971fa1cac1c3f0cfc9f21 (diff)
Move solution and projects to src
Diffstat (limited to 'src/Ryujinx.Graphics.Shader/Decoders/Block.cs')
-rw-r--r--src/Ryujinx.Graphics.Shader/Decoders/Block.cs168
1 files changed, 168 insertions, 0 deletions
diff --git a/src/Ryujinx.Graphics.Shader/Decoders/Block.cs b/src/Ryujinx.Graphics.Shader/Decoders/Block.cs
new file mode 100644
index 00000000..7d94e3f9
--- /dev/null
+++ b/src/Ryujinx.Graphics.Shader/Decoders/Block.cs
@@ -0,0 +1,168 @@
+using Ryujinx.Graphics.Shader.IntermediateRepresentation;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+
+namespace Ryujinx.Graphics.Shader.Decoders
+{
+ class PushOpInfo
+ {
+ public InstOp Op { get; }
+ public Dictionary<Block, Operand> Consumers;
+
+ public PushOpInfo(InstOp op)
+ {
+ Op = op;
+ Consumers = new Dictionary<Block, Operand>();
+ }
+ }
+
+ readonly struct SyncTarget
+ {
+ public PushOpInfo PushOpInfo { get; }
+ public int PushOpId { get; }
+
+ public SyncTarget(PushOpInfo pushOpInfo, int pushOpId)
+ {
+ PushOpInfo = pushOpInfo;
+ PushOpId = pushOpId;
+ }
+ }
+
+ class Block
+ {
+ public ulong Address { get; set; }
+ public ulong EndAddress { get; set; }
+
+ public List<Block> Predecessors { get; }
+ public List<Block> Successors { get; }
+
+ public List<InstOp> OpCodes { get; }
+ public List<PushOpInfo> PushOpCodes { get; }
+ public Dictionary<ulong, SyncTarget> SyncTargets { get; }
+
+ public Block(ulong address)
+ {
+ Address = address;
+
+ Predecessors = new List<Block>();
+ Successors = new List<Block>();
+
+ OpCodes = new List<InstOp>();
+ PushOpCodes = new List<PushOpInfo>();
+ SyncTargets = new Dictionary<ulong, SyncTarget>();
+ }
+
+ public void Split(Block rightBlock)
+ {
+ int splitIndex = BinarySearch(OpCodes, rightBlock.Address);
+
+ if (OpCodes[splitIndex].Address < rightBlock.Address)
+ {
+ splitIndex++;
+ }
+
+ int splitCount = OpCodes.Count - splitIndex;
+ if (splitCount <= 0)
+ {
+ throw new ArgumentException("Can't split at right block address.");
+ }
+
+ rightBlock.EndAddress = EndAddress;
+ rightBlock.Successors.AddRange(Successors);
+ rightBlock.Predecessors.Add(this);
+
+ EndAddress = rightBlock.Address;
+
+ Successors.Clear();
+ Successors.Add(rightBlock);
+
+ // Move ops.
+ rightBlock.OpCodes.AddRange(OpCodes.GetRange(splitIndex, splitCount));
+
+ OpCodes.RemoveRange(splitIndex, splitCount);
+
+ // Update push consumers that points to this block.
+ foreach (SyncTarget syncTarget in SyncTargets.Values)
+ {
+ PushOpInfo pushOpInfo = syncTarget.PushOpInfo;
+
+ Operand local = pushOpInfo.Consumers[this];
+ pushOpInfo.Consumers.Remove(this);
+ pushOpInfo.Consumers.Add(rightBlock, local);
+ }
+
+ foreach ((ulong key, SyncTarget value) in SyncTargets)
+ {
+ rightBlock.SyncTargets.Add(key, value);
+ }
+
+ SyncTargets.Clear();
+
+ // Move push ops.
+ for (int i = 0; i < PushOpCodes.Count; i++)
+ {
+ if (PushOpCodes[i].Op.Address >= rightBlock.Address)
+ {
+ int count = PushOpCodes.Count - i;
+ rightBlock.PushOpCodes.AddRange(PushOpCodes.Skip(i));
+ PushOpCodes.RemoveRange(i, count);
+ break;
+ }
+ }
+ }
+
+ private static int BinarySearch(List<InstOp> opCodes, ulong address)
+ {
+ int left = 0;
+ int middle = 0;
+ int right = opCodes.Count - 1;
+
+ while (left <= right)
+ {
+ int size = right - left;
+
+ middle = left + (size >> 1);
+
+ InstOp opCode = opCodes[middle];
+
+ if (address == opCode.Address)
+ {
+ break;
+ }
+
+ if (address < opCode.Address)
+ {
+ right = middle - 1;
+ }
+ else
+ {
+ left = middle + 1;
+ }
+ }
+
+ return middle;
+ }
+
+ public InstOp GetLastOp()
+ {
+ if (OpCodes.Count != 0)
+ {
+ return OpCodes[OpCodes.Count - 1];
+ }
+
+ return default;
+ }
+
+ public bool HasNext()
+ {
+ InstOp lastOp = GetLastOp();
+ return OpCodes.Count != 0 && !Decoder.IsUnconditionalBranch(ref lastOp);
+ }
+
+ public void AddPushOp(InstOp op)
+ {
+ PushOpCodes.Add(new PushOpInfo(op));
+ }
+ }
+} \ No newline at end of file