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;
        }
Exemple #3
0
        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);
        }