diff options
Diffstat (limited to 'Ryujinx.Graphics.Shader/Decoders')
-rw-r--r-- | Ryujinx.Graphics.Shader/Decoders/Block.cs | 22 | ||||
-rw-r--r-- | Ryujinx.Graphics.Shader/Decoders/Decoder.cs | 138 | ||||
-rw-r--r-- | Ryujinx.Graphics.Shader/Decoders/FPMultiplyScale.cs (renamed from Ryujinx.Graphics.Shader/Decoders/FmulScale.cs) | 2 | ||||
-rw-r--r-- | Ryujinx.Graphics.Shader/Decoders/IOpCodeFArith.cs | 2 | ||||
-rw-r--r-- | Ryujinx.Graphics.Shader/Decoders/OpCodeBranchIndir.cs | 23 | ||||
-rw-r--r-- | Ryujinx.Graphics.Shader/Decoders/OpCodeBranchPop.cs | 15 | ||||
-rw-r--r-- | Ryujinx.Graphics.Shader/Decoders/OpCodeFArith.cs | 4 | ||||
-rw-r--r-- | Ryujinx.Graphics.Shader/Decoders/OpCodeFArithImm32.cs | 2 | ||||
-rw-r--r-- | Ryujinx.Graphics.Shader/Decoders/OpCodePush.cs (renamed from Ryujinx.Graphics.Shader/Decoders/OpCodeSsy.cs) | 8 | ||||
-rw-r--r-- | Ryujinx.Graphics.Shader/Decoders/OpCodeSync.cs | 15 | ||||
-rw-r--r-- | Ryujinx.Graphics.Shader/Decoders/OpCodeTable.cs | 9 |
11 files changed, 155 insertions, 85 deletions
diff --git a/Ryujinx.Graphics.Shader/Decoders/Block.cs b/Ryujinx.Graphics.Shader/Decoders/Block.cs index b5e610d7..238b0bd6 100644 --- a/Ryujinx.Graphics.Shader/Decoders/Block.cs +++ b/Ryujinx.Graphics.Shader/Decoders/Block.cs @@ -11,15 +11,17 @@ namespace Ryujinx.Graphics.Shader.Decoders public Block Next { get; set; } public Block Branch { get; set; } - public List<OpCode> OpCodes { get; } - public List<OpCodeSsy> SsyOpCodes { get; } + 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>(); - SsyOpCodes = new List<OpCodeSsy>(); + OpCodes = new List<OpCode>(); + PushOpCodes = new List<OpCodePush>(); } public void Split(Block rightBlock) @@ -45,7 +47,7 @@ namespace Ryujinx.Graphics.Shader.Decoders rightBlock.OpCodes.AddRange(OpCodes.GetRange(splitIndex, splitCount)); - rightBlock.UpdateSsyOpCodes(); + rightBlock.UpdatePushOps(); EndAddress = rightBlock.Address; @@ -54,7 +56,7 @@ namespace Ryujinx.Graphics.Shader.Decoders OpCodes.RemoveRange(splitIndex, splitCount); - UpdateSsyOpCodes(); + UpdatePushOps(); } private static int BinarySearch(List<OpCode> opCodes, ulong address) @@ -99,18 +101,18 @@ namespace Ryujinx.Graphics.Shader.Decoders return null; } - public void UpdateSsyOpCodes() + public void UpdatePushOps() { - SsyOpCodes.Clear(); + PushOpCodes.Clear(); for (int index = 0; index < OpCodes.Count; index++) { - if (!(OpCodes[index] is OpCodeSsy op)) + if (!(OpCodes[index] is OpCodePush op)) { continue; } - SsyOpCodes.Add(op); + PushOpCodes.Add(op); } } } diff --git a/Ryujinx.Graphics.Shader/Decoders/Decoder.cs b/Ryujinx.Graphics.Shader/Decoders/Decoder.cs index 4078440b..6841c98d 100644 --- a/Ryujinx.Graphics.Shader/Decoders/Decoder.cs +++ b/Ryujinx.Graphics.Shader/Decoders/Decoder.cs @@ -43,9 +43,7 @@ namespace Ryujinx.Graphics.Shader.Decoders return block; } - ulong startAddress = headerSize; - - GetBlock(startAddress); + GetBlock(0); while (workQueue.TryDequeue(out Block currBlock)) { @@ -67,7 +65,7 @@ namespace Ryujinx.Graphics.Shader.Decoders } // If we have a block after the current one, set the limit address. - ulong limitAddress = (ulong)code.Length; + ulong limitAddress = (ulong)code.Length - headerSize; if (nBlkIndex != blocks.Count) { @@ -85,13 +83,15 @@ namespace Ryujinx.Graphics.Shader.Decoders } } - FillBlock(code, currBlock, limitAddress, startAddress); + FillBlock(code, currBlock, limitAddress, headerSize); if (currBlock.OpCodes.Count != 0) { - foreach (OpCodeSsy ssyOp in currBlock.SsyOpCodes) + // We should have blocks for all possible branch targets, + // including those from SSY/PBK instructions. + foreach (OpCodePush pushOp in currBlock.PushOpCodes) { - GetBlock(ssyOp.GetAbsoluteAddress()); + GetBlock(pushOp.GetAbsoluteAddress()); } // Set child blocks. "Branch" is the block the branch instruction @@ -100,9 +100,25 @@ namespace Ryujinx.Graphics.Shader.Decoders // or end of program, Next is null. OpCode lastOp = currBlock.GetLastOp(); - if (lastOp is OpCodeBranch op) + if (lastOp is OpCodeBranch opBr) + { + currBlock.Branch = GetBlock(opBr.GetAbsoluteAddress()); + } + else if (lastOp is OpCodeBranchIndir opBrIndir) { - currBlock.Branch = GetBlock(op.GetAbsoluteAddress()); + // An indirect branch could go anywhere, we don't know the target. + // Those instructions are usually used on a switch to jump table + // compiler optimization, and in those cases the possible targets + // seems to be always right after the BRX itself. We can assume + // that the possible targets are all the blocks in-between the + // instruction right after the BRX, and the common target that + // all the "cases" should eventually jump to, acting as the + // switch break. + Block firstTarget = GetBlock(currBlock.EndAddress); + + firstTarget.BrIndir = opBrIndir; + + opBrIndir.PossibleTargets.Add(firstTarget); } if (!IsUnconditionalBranch(lastOp)) @@ -122,13 +138,28 @@ namespace Ryujinx.Graphics.Shader.Decoders { blocks.Add(currBlock); } + + // Do we have a block after the current one? + if (!IsExit(currBlock.GetLastOp()) && currBlock.BrIndir != null) + { + bool targetVisited = visited.ContainsKey(currBlock.EndAddress); + + Block possibleTarget = GetBlock(currBlock.EndAddress); + + currBlock.BrIndir.PossibleTargets.Add(possibleTarget); + + if (!targetVisited) + { + possibleTarget.BrIndir = currBlock.BrIndir; + } + } } - foreach (Block ssyBlock in blocks.Where(x => x.SsyOpCodes.Count != 0)) + foreach (Block block in blocks.Where(x => x.PushOpCodes.Count != 0)) { - for (int ssyIndex = 0; ssyIndex < ssyBlock.SsyOpCodes.Count; ssyIndex++) + for (int pushOpIndex = 0; pushOpIndex < block.PushOpCodes.Count; pushOpIndex++) { - PropagateSsy(visited, ssyBlock, ssyIndex); + PropagatePushOp(visited, block, pushOpIndex); } } @@ -180,21 +211,21 @@ namespace Ryujinx.Graphics.Shader.Decoders do { - if (address >= limitAddress) + if (address + 7 >= limitAddress) { break; } // Ignore scheduling instructions, which are written every 32 bytes. - if (((address - startAddress) & 0x1f) == 0) + if ((address & 0x1f) == 0) { address += 8; continue; } - uint word0 = BinaryPrimitives.ReadUInt32LittleEndian(code.Slice((int)address)); - uint word1 = BinaryPrimitives.ReadUInt32LittleEndian(code.Slice((int)address + 4)); + uint word0 = BinaryPrimitives.ReadUInt32LittleEndian(code.Slice((int)(startAddress + address))); + uint word1 = BinaryPrimitives.ReadUInt32LittleEndian(code.Slice((int)(startAddress + address + 4))); ulong opAddress = address; @@ -221,7 +252,7 @@ namespace Ryujinx.Graphics.Shader.Decoders block.EndAddress = address; - block.UpdateSsyOpCodes(); + block.UpdatePushOps(); } private static bool IsUnconditionalBranch(OpCode opCode) @@ -242,10 +273,16 @@ namespace Ryujinx.Graphics.Shader.Decoders private static bool IsBranch(OpCode opCode) { return (opCode is OpCodeBranch opBranch && !opBranch.PushTarget) || - opCode is OpCodeSync || + opCode is OpCodeBranchIndir || + opCode is OpCodeBranchPop || opCode is OpCodeExit; } + private static bool IsExit(OpCode opCode) + { + return opCode is OpCodeExit; + } + private static OpCode MakeOpCode(Type type, InstEmitter emitter, ulong address, long opCode) { if (type == null) @@ -282,8 +319,8 @@ namespace Ryujinx.Graphics.Shader.Decoders private enum RestoreType { None, - PopSsy, - PushSync + PopPushOp, + PushBranchOp } private RestoreType _restoreType; @@ -299,45 +336,45 @@ namespace Ryujinx.Graphics.Shader.Decoders _restoreValue = 0; } - public PathBlockState(int oldSsyStackSize) + public PathBlockState(int oldStackSize) { Block = null; - _restoreType = RestoreType.PopSsy; - _restoreValue = (ulong)oldSsyStackSize; + _restoreType = RestoreType.PopPushOp; + _restoreValue = (ulong)oldStackSize; } public PathBlockState(ulong syncAddress) { Block = null; - _restoreType = RestoreType.PushSync; + _restoreType = RestoreType.PushBranchOp; _restoreValue = syncAddress; } - public void RestoreStackState(Stack<ulong> ssyStack) + public void RestoreStackState(Stack<ulong> branchStack) { - if (_restoreType == RestoreType.PushSync) + if (_restoreType == RestoreType.PushBranchOp) { - ssyStack.Push(_restoreValue); + branchStack.Push(_restoreValue); } - else if (_restoreType == RestoreType.PopSsy) + else if (_restoreType == RestoreType.PopPushOp) { - while (ssyStack.Count > (uint)_restoreValue) + while (branchStack.Count > (uint)_restoreValue) { - ssyStack.Pop(); + branchStack.Pop(); } } } } - private static void PropagateSsy(Dictionary<ulong, Block> blocks, Block ssyBlock, int ssyIndex) + private static void PropagatePushOp(Dictionary<ulong, Block> blocks, Block currBlock, int pushOpIndex) { - OpCodeSsy ssyOp = ssyBlock.SsyOpCodes[ssyIndex]; + OpCodePush pushOp = currBlock.PushOpCodes[pushOpIndex]; Stack<PathBlockState> workQueue = new Stack<PathBlockState>(); HashSet<Block> visited = new HashSet<Block>(); - Stack<ulong> ssyStack = new Stack<ulong>(); + Stack<ulong> branchStack = new Stack<ulong>(); void Push(PathBlockState pbs) { @@ -347,32 +384,32 @@ namespace Ryujinx.Graphics.Shader.Decoders } } - Push(new PathBlockState(ssyBlock)); + Push(new PathBlockState(currBlock)); while (workQueue.TryPop(out PathBlockState pbs)) { if (pbs.ReturningFromVisit) { - pbs.RestoreStackState(ssyStack); + pbs.RestoreStackState(branchStack); continue; } Block current = pbs.Block; - int ssyOpCodesCount = current.SsyOpCodes.Count; + int pushOpsCount = current.PushOpCodes.Count; - if (ssyOpCodesCount != 0) + if (pushOpsCount != 0) { - Push(new PathBlockState(ssyStack.Count)); + Push(new PathBlockState(branchStack.Count)); - for (int index = ssyIndex; index < ssyOpCodesCount; index++) + for (int index = pushOpIndex; index < pushOpsCount; index++) { - ssyStack.Push(current.SsyOpCodes[index].GetAbsoluteAddress()); + branchStack.Push(current.PushOpCodes[index].GetAbsoluteAddress()); } } - ssyIndex = 0; + pushOpIndex = 0; if (current.Next != null) { @@ -383,17 +420,24 @@ namespace Ryujinx.Graphics.Shader.Decoders { Push(new PathBlockState(current.Branch)); } - else if (current.GetLastOp() is OpCodeSync op) + else if (current.GetLastOp() is OpCodeBranchIndir brIndir) + { + foreach (Block possibleTarget in brIndir.PossibleTargets) + { + Push(new PathBlockState(possibleTarget)); + } + } + else if (current.GetLastOp() is OpCodeBranchPop op) { - ulong syncAddress = ssyStack.Pop(); + ulong syncAddress = branchStack.Pop(); - if (ssyStack.Count == 0) + if (branchStack.Count == 0) { - ssyStack.Push(syncAddress); + branchStack.Push(syncAddress); - op.Targets.Add(ssyOp, op.Targets.Count); + op.Targets.Add(pushOp, op.Targets.Count); - ssyOp.Syncs.TryAdd(op, Local()); + pushOp.PopOps.TryAdd(op, Local()); } else { diff --git a/Ryujinx.Graphics.Shader/Decoders/FmulScale.cs b/Ryujinx.Graphics.Shader/Decoders/FPMultiplyScale.cs index c35c6e48..398c0e66 100644 --- a/Ryujinx.Graphics.Shader/Decoders/FmulScale.cs +++ b/Ryujinx.Graphics.Shader/Decoders/FPMultiplyScale.cs @@ -1,6 +1,6 @@ namespace Ryujinx.Graphics.Shader.Decoders { - enum FmulScale + enum FPMultiplyScale { None = 0, Divide2 = 1, diff --git a/Ryujinx.Graphics.Shader/Decoders/IOpCodeFArith.cs b/Ryujinx.Graphics.Shader/Decoders/IOpCodeFArith.cs index d68ccf59..3d06eae0 100644 --- a/Ryujinx.Graphics.Shader/Decoders/IOpCodeFArith.cs +++ b/Ryujinx.Graphics.Shader/Decoders/IOpCodeFArith.cs @@ -4,7 +4,7 @@ namespace Ryujinx.Graphics.Shader.Decoders { RoundingMode RoundingMode { get; } - FmulScale Scale { get; } + FPMultiplyScale Scale { get; } bool FlushToZero { get; } bool AbsoluteA { get; } diff --git a/Ryujinx.Graphics.Shader/Decoders/OpCodeBranchIndir.cs b/Ryujinx.Graphics.Shader/Decoders/OpCodeBranchIndir.cs new file mode 100644 index 00000000..3e694e61 --- /dev/null +++ b/Ryujinx.Graphics.Shader/Decoders/OpCodeBranchIndir.cs @@ -0,0 +1,23 @@ +using Ryujinx.Graphics.Shader.Instructions; +using System.Collections.Generic; + +namespace Ryujinx.Graphics.Shader.Decoders +{ + class OpCodeBranchIndir : OpCode + { + public HashSet<Block> PossibleTargets { get; } + + public Register Ra { get; } + + public int Offset { get; } + + public OpCodeBranchIndir(InstEmitter emitter, ulong address, long opCode) : base(emitter, address, opCode) + { + PossibleTargets = new HashSet<Block>(); + + Ra = new Register(opCode.Extract(8, 8), RegisterType.Gpr); + + Offset = ((int)(opCode >> 20) << 8) >> 8; + } + } +}
\ No newline at end of file diff --git a/Ryujinx.Graphics.Shader/Decoders/OpCodeBranchPop.cs b/Ryujinx.Graphics.Shader/Decoders/OpCodeBranchPop.cs new file mode 100644 index 00000000..7ea66fe4 --- /dev/null +++ b/Ryujinx.Graphics.Shader/Decoders/OpCodeBranchPop.cs @@ -0,0 +1,15 @@ +using Ryujinx.Graphics.Shader.Instructions; +using System.Collections.Generic; + +namespace Ryujinx.Graphics.Shader.Decoders +{ + class OpCodeBranchPop : OpCode + { + public Dictionary<OpCodePush, int> Targets { get; } + + public OpCodeBranchPop(InstEmitter emitter, ulong address, long opCode) : base(emitter, address, opCode) + { + Targets = new Dictionary<OpCodePush, int>(); + } + } +}
\ No newline at end of file diff --git a/Ryujinx.Graphics.Shader/Decoders/OpCodeFArith.cs b/Ryujinx.Graphics.Shader/Decoders/OpCodeFArith.cs index c88f7f0e..cfbf65c3 100644 --- a/Ryujinx.Graphics.Shader/Decoders/OpCodeFArith.cs +++ b/Ryujinx.Graphics.Shader/Decoders/OpCodeFArith.cs @@ -6,7 +6,7 @@ namespace Ryujinx.Graphics.Shader.Decoders { public RoundingMode RoundingMode { get; } - public FmulScale Scale { get; } + public FPMultiplyScale Scale { get; } public bool FlushToZero { get; } public bool AbsoluteA { get; } @@ -15,7 +15,7 @@ namespace Ryujinx.Graphics.Shader.Decoders { RoundingMode = (RoundingMode)opCode.Extract(39, 2); - Scale = (FmulScale)opCode.Extract(41, 3); + Scale = (FPMultiplyScale)opCode.Extract(41, 3); FlushToZero = opCode.Extract(44); AbsoluteA = opCode.Extract(46); diff --git a/Ryujinx.Graphics.Shader/Decoders/OpCodeFArithImm32.cs b/Ryujinx.Graphics.Shader/Decoders/OpCodeFArithImm32.cs index ec9da6f3..aecc5143 100644 --- a/Ryujinx.Graphics.Shader/Decoders/OpCodeFArithImm32.cs +++ b/Ryujinx.Graphics.Shader/Decoders/OpCodeFArithImm32.cs @@ -7,7 +7,7 @@ namespace Ryujinx.Graphics.Shader.Decoders { public RoundingMode RoundingMode => RoundingMode.ToNearest; - public FmulScale Scale => FmulScale.None; + public FPMultiplyScale Scale => FPMultiplyScale.None; public bool FlushToZero { get; } public bool AbsoluteA { get; } diff --git a/Ryujinx.Graphics.Shader/Decoders/OpCodeSsy.cs b/Ryujinx.Graphics.Shader/Decoders/OpCodePush.cs index d3831e22..a7657bcf 100644 --- a/Ryujinx.Graphics.Shader/Decoders/OpCodeSsy.cs +++ b/Ryujinx.Graphics.Shader/Decoders/OpCodePush.cs @@ -4,13 +4,13 @@ using System.Collections.Generic; namespace Ryujinx.Graphics.Shader.Decoders { - class OpCodeSsy : OpCodeBranch + class OpCodePush : OpCodeBranch { - public Dictionary<OpCodeSync, Operand> Syncs { get; } + public Dictionary<OpCodeBranchPop, Operand> PopOps { get; } - public OpCodeSsy(InstEmitter emitter, ulong address, long opCode) : base(emitter, address, opCode) + public OpCodePush(InstEmitter emitter, ulong address, long opCode) : base(emitter, address, opCode) { - Syncs = new Dictionary<OpCodeSync, Operand>(); + PopOps = new Dictionary<OpCodeBranchPop, Operand>(); Predicate = new Register(RegisterConsts.PredicateTrueIndex, RegisterType.Predicate); diff --git a/Ryujinx.Graphics.Shader/Decoders/OpCodeSync.cs b/Ryujinx.Graphics.Shader/Decoders/OpCodeSync.cs deleted file mode 100644 index 081d08a0..00000000 --- a/Ryujinx.Graphics.Shader/Decoders/OpCodeSync.cs +++ /dev/null @@ -1,15 +0,0 @@ -using Ryujinx.Graphics.Shader.Instructions; -using System.Collections.Generic; - -namespace Ryujinx.Graphics.Shader.Decoders -{ - class OpCodeSync : OpCode - { - public Dictionary<OpCodeSsy, int> Targets { get; } - - public OpCodeSync(InstEmitter emitter, ulong address, long opCode) : base(emitter, address, opCode) - { - Targets = new Dictionary<OpCodeSsy, int>(); - } - } -}
\ No newline at end of file diff --git a/Ryujinx.Graphics.Shader/Decoders/OpCodeTable.cs b/Ryujinx.Graphics.Shader/Decoders/OpCodeTable.cs index 58bd2b88..bc30940d 100644 --- a/Ryujinx.Graphics.Shader/Decoders/OpCodeTable.cs +++ b/Ryujinx.Graphics.Shader/Decoders/OpCodeTable.cs @@ -41,7 +41,8 @@ namespace Ryujinx.Graphics.Shader.Decoders Set("0101001111110x", InstEmit.Bfi, typeof(OpCodeAluRegCbuf)); Set("0101101111110x", InstEmit.Bfi, typeof(OpCodeAluReg)); Set("111000100100xx", InstEmit.Bra, typeof(OpCodeBranch)); - Set("111000110100xx", InstEmit.Brk, typeof(OpCodeSync)); + Set("111000110100xx", InstEmit.Brk, typeof(OpCodeBranchPop)); + Set("111000100101xx", InstEmit.Brx, typeof(OpCodeBranchIndir)); Set("0101000010100x", InstEmit.Csetp, typeof(OpCodePsetp)); Set("111000110000xx", InstEmit.Exit, typeof(OpCodeExit)); Set("0100110010101x", InstEmit.F2F, typeof(OpCodeFArithCbuf)); @@ -137,7 +138,7 @@ namespace Ryujinx.Graphics.Shader.Decoders Set("0101110010011x", InstEmit.Mov, typeof(OpCodeAluReg)); Set("0101000010000x", InstEmit.Mufu, typeof(OpCodeFArith)); Set("1111101111100x", InstEmit.Out, typeof(OpCode)); - Set("111000101010xx", InstEmit.Pbk, typeof(OpCodeSsy)); + Set("111000101010xx", InstEmit.Pbk, typeof(OpCodePush)); Set("0100110000001x", InstEmit.Popc, typeof(OpCodeAluCbuf)); Set("0011100x00001x", InstEmit.Popc, typeof(OpCodeAluImm)); Set("0101110000001x", InstEmit.Popc, typeof(OpCodeAluReg)); @@ -157,12 +158,12 @@ namespace Ryujinx.Graphics.Shader.Decoders Set("0100110000101x", InstEmit.Shr, typeof(OpCodeAluCbuf)); Set("0011100x00101x", InstEmit.Shr, typeof(OpCodeAluImm)); Set("0101110000101x", InstEmit.Shr, typeof(OpCodeAluReg)); - Set("111000101001xx", InstEmit.Ssy, typeof(OpCodeSsy)); + Set("111000101001xx", InstEmit.Ssy, typeof(OpCodePush)); Set("1110111101010x", InstEmit.St, typeof(OpCodeMemory)); Set("1110111011011x", InstEmit.Stg, typeof(OpCodeMemory)); Set("1110111101011x", InstEmit.Sts, typeof(OpCodeMemory)); Set("11101011001xxx", InstEmit.Sust, typeof(OpCodeImage)); - Set("1111000011111x", InstEmit.Sync, typeof(OpCodeSync)); + Set("1111000011111x", InstEmit.Sync, typeof(OpCodeBranchPop)); Set("110000xxxx111x", InstEmit.Tex, typeof(OpCodeTex)); Set("1101111010111x", InstEmit.TexB, typeof(OpCodeTexB)); Set("1101x00xxxxxxx", InstEmit.Texs, typeof(OpCodeTexs)); |