private static void FillBlock(IGalMemory Memory, ShaderIrBlock Block, long Beginning) { long Position = Block.Position; do { //Ignore scheduling instructions, which are written every 32 bytes. if (((Position - Beginning) & 0x1f) == 0) { Position += 8; continue; } uint Word0 = (uint)Memory.ReadInt32(Position + 0); uint Word1 = (uint)Memory.ReadInt32(Position + 4); Position += 8; long OpCode = Word0 | (long)Word1 << 32; ShaderDecodeFunc Decode = ShaderOpCodeTable.GetDecoder(OpCode); if (AddDbgComments) { string DbgOpCode = $"0x{(Position - Beginning - 8):x16}: 0x{OpCode:x16} "; DbgOpCode += (Decode?.Method.Name ?? "???"); if (Decode == ShaderDecode.Bra) { int Offset = ((int)(OpCode >> 20) << 8) >> 8; long Target = Position + Offset; DbgOpCode += " (0x" + Target.ToString("x16") + ")"; } Block.AddNode(new ShaderIrCmnt(DbgOpCode)); } if (Decode == null) { continue; } Decode(Block, OpCode); }while (!IsFlowChange(Block.GetLastNode())); Block.EndPosition = Position; }
private static void FillBlock(IGalMemory memory, ShaderIrBlock block, long beginning) { int position = block.Position; do { //Ignore scheduling instructions, which are written every 32 bytes. if ((position & 0x1f) == 0) { position += 8; continue; } uint word0 = (uint)memory.ReadInt32(position + beginning + 0); uint word1 = (uint)memory.ReadInt32(position + beginning + 4); position += 8; long opCode = word0 | (long)word1 << 32; ShaderDecodeFunc decode = ShaderOpCodeTable.GetDecoder(opCode); if (AddDbgComments) { string dbgOpCode = $"0x{(position - 8):x16}: 0x{opCode:x16} "; dbgOpCode += (decode?.Method.Name ?? "???"); if (decode == ShaderDecode.Bra || decode == ShaderDecode.Ssy) { int offset = ((int)(opCode >> 20) << 8) >> 8; long target = position + offset; dbgOpCode += " (0x" + target.ToString("x16") + ")"; } block.AddNode(new ShaderIrCmnt(dbgOpCode)); } if (decode == null) { continue; } decode(block, opCode, position); }while (!IsFlowChange(block.GetLastNode())); block.EndPosition = position; }
private static void FillBlock(byte[] Binary, ShaderIrBlock Block, long Beginning) { long Position = Block.Position; do { //Ignore scheduling instructions, which are written every 32 bytes. if (((Position - Beginning) & 0x1f) == 0) { Position += 8; continue; } long OpCode = BitConverter.ToInt64(Binary, (int)Position); Position += 8; ShaderDecodeFunc Decode = ShaderOpCodeTable.GetDecoder(OpCode); if (AddDbgComments) { string DbgOpCode = $"0x{(Position - Beginning - 8):x16}: 0x{OpCode:x16} "; DbgOpCode += (Decode?.Method.Name ?? "???"); if (Decode == ShaderDecode.Bra) { int Offset = ((int)(OpCode >> 20) << 8) >> 8; long Target = Position + Offset - Beginning; DbgOpCode += " (0x" + Target.ToString("x16") + ")"; } Block.AddNode(new ShaderIrCmnt(DbgOpCode)); } if (Decode == null) { continue; } Decode(Block, OpCode, Position); }while (!IsFlowChange(Block.GetLastNode())); Block.EndPosition = Position; }
public static ShaderIrBlock[] Decode(IGalMemory Memory, long Start) { Dictionary <long, ShaderIrBlock> Visited = new Dictionary <long, ShaderIrBlock>(); Dictionary <long, ShaderIrBlock> VisitedEnd = new Dictionary <long, ShaderIrBlock>(); Queue <ShaderIrBlock> Blocks = new Queue <ShaderIrBlock>(); ShaderIrBlock Enqueue(long Position, ShaderIrBlock Source = null) { if (!Visited.TryGetValue(Position, out ShaderIrBlock Output)) { Output = new ShaderIrBlock(Position); Blocks.Enqueue(Output); Visited.Add(Position, Output); } if (Source != null) { Output.Sources.Add(Source); } return(Output); } ShaderIrBlock Entry = Enqueue(Start + HeaderSize); while (Blocks.Count > 0) { ShaderIrBlock Current = Blocks.Dequeue(); FillBlock(Memory, Current, Start + HeaderSize); //Set child blocks. "Branch" is the block the branch instruction //points to (when taken), "Next" is the block at the next address, //executed when the branch is not taken. For Unconditional Branches //or end of shader, Next is null. if (Current.Nodes.Count > 0) { ShaderIrNode LastNode = Current.GetLastNode(); ShaderIrOp Op = GetInnermostOp(LastNode); if (Op?.Inst == ShaderIrInst.Bra) { int Offset = ((ShaderIrOperImm)Op.OperandA).Value; long Target = Current.EndPosition + Offset; Current.Branch = Enqueue(Target, Current); } if (NodeHasNext(LastNode)) { Current.Next = Enqueue(Current.EndPosition); } } //If we have on the graph two blocks with the same end position, //then we need to split the bigger block and have two small blocks, //the end position of the bigger "Current" block should then be == to //the position of the "Smaller" block. while (VisitedEnd.TryGetValue(Current.EndPosition, out ShaderIrBlock Smaller)) { if (Current.Position > Smaller.Position) { ShaderIrBlock Temp = Smaller; Smaller = Current; Current = Temp; } Current.EndPosition = Smaller.Position; Current.Next = Smaller; Current.Branch = null; Current.Nodes.RemoveRange( Current.Nodes.Count - Smaller.Nodes.Count, Smaller.Nodes.Count); VisitedEnd[Smaller.EndPosition] = Smaller; } VisitedEnd.Add(Current.EndPosition, Current); } //Make and sort Graph blocks array by position. ShaderIrBlock[] Graph = new ShaderIrBlock[Visited.Count]; while (Visited.Count > 0) { ulong FirstPos = ulong.MaxValue; foreach (ShaderIrBlock Block in Visited.Values) { if (FirstPos > (ulong)Block.Position) { FirstPos = (ulong)Block.Position; } } ShaderIrBlock Current = Visited[(long)FirstPos]; do { Graph[Graph.Length - Visited.Count] = Current; Visited.Remove(Current.Position); Current = Current.Next; }while (Current != null); } return(Graph); }
public static ShaderIrBlock[] Decode(IGalMemory memory, long start) { Dictionary <int, ShaderIrBlock> visited = new Dictionary <int, ShaderIrBlock>(); Dictionary <int, ShaderIrBlock> visitedEnd = new Dictionary <int, ShaderIrBlock>(); Queue <ShaderIrBlock> blocks = new Queue <ShaderIrBlock>(); long beginning = start + HeaderSize; ShaderIrBlock Enqueue(int position, ShaderIrBlock source = null) { if (!visited.TryGetValue(position, out ShaderIrBlock output)) { output = new ShaderIrBlock(position); blocks.Enqueue(output); visited.Add(position, output); } if (source != null) { output.Sources.Add(source); } return(output); } ShaderIrBlock entry = Enqueue(0); while (blocks.Count > 0) { ShaderIrBlock current = blocks.Dequeue(); FillBlock(memory, current, beginning); //Set child blocks. "Branch" is the block the branch instruction //points to (when taken), "Next" is the block at the next address, //executed when the branch is not taken. For Unconditional Branches //or end of shader, Next is null. if (current.Nodes.Count > 0) { ShaderIrNode lastNode = current.GetLastNode(); ShaderIrOp innerOp = GetInnermostOp(lastNode); if (innerOp?.Inst == ShaderIrInst.Bra) { int target = ((ShaderIrOperImm)innerOp.OperandA).Value; current.Branch = Enqueue(target, current); } foreach (ShaderIrNode node in current.Nodes) { innerOp = GetInnermostOp(node); if (innerOp is ShaderIrOp currOp && currOp.Inst == ShaderIrInst.Ssy) { int target = ((ShaderIrOperImm)currOp.OperandA).Value; Enqueue(target, current); } } if (NodeHasNext(lastNode)) { current.Next = Enqueue(current.EndPosition); } } //If we have on the graph two blocks with the same end position, //then we need to split the bigger block and have two small blocks, //the end position of the bigger "Current" block should then be == to //the position of the "Smaller" block. while (visitedEnd.TryGetValue(current.EndPosition, out ShaderIrBlock smaller)) { if (current.Position > smaller.Position) { ShaderIrBlock temp = smaller; smaller = current; current = temp; } current.EndPosition = smaller.Position; current.Next = smaller; current.Branch = null; current.Nodes.RemoveRange( current.Nodes.Count - smaller.Nodes.Count, smaller.Nodes.Count); visitedEnd[smaller.EndPosition] = smaller; } visitedEnd.Add(current.EndPosition, current); } //Make and sort Graph blocks array by position. ShaderIrBlock[] graph = new ShaderIrBlock[visited.Count]; while (visited.Count > 0) { uint firstPos = uint.MaxValue; foreach (ShaderIrBlock block in visited.Values) { if (firstPos > (uint)block.Position) { firstPos = (uint)block.Position; } } ShaderIrBlock current = visited[(int)firstPos]; do { graph[graph.Length - visited.Count] = current; visited.Remove(current.Position); current = current.Next; }while (current != null); } return(graph); }