rjx-mirror/Ryujinx.Graphics.Shader/Decoders/Block.cs

119 lines
No EOL
2.8 KiB
C#

using System;
using System.Collections.Generic;
namespace Ryujinx.Graphics.Shader.Decoders
{
class Block
{
public ulong Address { get; set; }
public ulong EndAddress { get; set; }
public Block Next { get; set; }
public Block Branch { get; set; }
public OpCodeBranchIndir BrIndir { get; set; }
public List<OpCode> OpCodes { get; }
public List<OpCodePush> PushOpCodes { get; }
public Block(ulong address)
{
Address = address;
OpCodes = new List<OpCode>();
PushOpCodes = new List<OpCodePush>();
}
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.Next = Next;
rightBlock.Branch = Branch;
rightBlock.OpCodes.AddRange(OpCodes.GetRange(splitIndex, splitCount));
rightBlock.UpdatePushOps();
EndAddress = rightBlock.Address;
Next = rightBlock;
Branch = null;
OpCodes.RemoveRange(splitIndex, splitCount);
UpdatePushOps();
}
private static int BinarySearch(List<OpCode> 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);
OpCode opCode = opCodes[middle];
if (address == opCode.Address)
{
break;
}
if (address < opCode.Address)
{
right = middle - 1;
}
else
{
left = middle + 1;
}
}
return middle;
}
public OpCode GetLastOp()
{
if (OpCodes.Count != 0)
{
return OpCodes[OpCodes.Count - 1];
}
return null;
}
public void UpdatePushOps()
{
PushOpCodes.Clear();
for (int index = 0; index < OpCodes.Count; index++)
{
if (!(OpCodes[index] is OpCodePush op))
{
continue;
}
PushOpCodes.Add(op);
}
}
}
}