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 OpCodes { get; } public List PushOpCodes { get; } public Block(ulong address) { Address = address; OpCodes = new List(); PushOpCodes = new List(); } 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 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); } } } }