forked from Mirror/Ryujinx
Fix branch with CC and predicate, and a case of SYNC propagation (#967)
This commit is contained in:
parent
68e15c1a74
commit
54501962f6
2 changed files with 40 additions and 5 deletions
|
@ -390,7 +390,14 @@ namespace Ryujinx.Graphics.Shader.Decoders
|
||||||
|
|
||||||
void Push(PathBlockState pbs)
|
void Push(PathBlockState pbs)
|
||||||
{
|
{
|
||||||
if (pbs.Block == null || visited.Add(pbs.Block))
|
// When block is null, this means we are pushing a restore operation.
|
||||||
|
// Restore operations are used to undo the work done inside a block
|
||||||
|
// when we return from it, for example it pops addresses pushed by
|
||||||
|
// SSY/PBK instructions inside the block, and pushes addresses poped
|
||||||
|
// by SYNC/BRK.
|
||||||
|
// For blocks, if it's already visited, we just ignore to avoid going
|
||||||
|
// around in circles and getting stuck here.
|
||||||
|
if (pbs.Block == null || !visited.Contains(pbs.Block))
|
||||||
{
|
{
|
||||||
workQueue.Push(pbs);
|
workQueue.Push(pbs);
|
||||||
}
|
}
|
||||||
|
@ -409,6 +416,14 @@ namespace Ryujinx.Graphics.Shader.Decoders
|
||||||
|
|
||||||
Block current = pbs.Block;
|
Block current = pbs.Block;
|
||||||
|
|
||||||
|
// If the block was already processed, we just ignore it, otherwise
|
||||||
|
// we would push the same child blocks of an already processed block,
|
||||||
|
// and go around in circles until memory is exhausted.
|
||||||
|
if (!visited.Add(current))
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
int pushOpsCount = current.PushOpCodes.Count;
|
int pushOpsCount = current.PushOpCodes.Count;
|
||||||
|
|
||||||
if (pushOpsCount != 0)
|
if (pushOpsCount != 0)
|
||||||
|
@ -434,7 +449,9 @@ namespace Ryujinx.Graphics.Shader.Decoders
|
||||||
}
|
}
|
||||||
else if (current.GetLastOp() is OpCodeBranchIndir brIndir)
|
else if (current.GetLastOp() is OpCodeBranchIndir brIndir)
|
||||||
{
|
{
|
||||||
foreach (Block possibleTarget in brIndir.PossibleTargets)
|
// By adding them in descending order (sorted by address), we process the blocks
|
||||||
|
// in order (of ascending address), since we work with a LIFO.
|
||||||
|
foreach (Block possibleTarget in brIndir.PossibleTargets.OrderByDescending(x => x.Address))
|
||||||
{
|
{
|
||||||
Push(new PathBlockState(possibleTarget));
|
Push(new PathBlockState(possibleTarget));
|
||||||
}
|
}
|
||||||
|
@ -453,6 +470,10 @@ namespace Ryujinx.Graphics.Shader.Decoders
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
// First we push the target address (this will be used to push the
|
||||||
|
// address back into the SSY/PBK stack when we return from that block),
|
||||||
|
// then we push the block itself into the work "queue" (well, it's a stack)
|
||||||
|
// for processing.
|
||||||
Push(new PathBlockState(targetAddress));
|
Push(new PathBlockState(targetAddress));
|
||||||
Push(new PathBlockState(blocks[targetAddress]));
|
Push(new PathBlockState(blocks[targetAddress]));
|
||||||
}
|
}
|
||||||
|
|
|
@ -145,10 +145,24 @@ namespace Ryujinx.Graphics.Shader.Instructions
|
||||||
|
|
||||||
if (op is OpCodeBranch opBranch && opBranch.Condition != Condition.Always)
|
if (op is OpCodeBranch opBranch && opBranch.Condition != Condition.Always)
|
||||||
{
|
{
|
||||||
pred = context.BitwiseAnd(pred, GetCondition(context, opBranch.Condition));
|
Operand cond = GetCondition(context, opBranch.Condition);
|
||||||
}
|
|
||||||
|
|
||||||
if (op.Predicate.IsPT)
|
if (op.Predicate.IsPT)
|
||||||
|
{
|
||||||
|
pred = cond;
|
||||||
|
}
|
||||||
|
else if (op.InvertPredicate)
|
||||||
|
{
|
||||||
|
pred = context.BitwiseAnd(context.BitwiseNot(pred), cond);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
pred = context.BitwiseAnd(pred, cond);
|
||||||
|
}
|
||||||
|
|
||||||
|
context.BranchIfTrue(label, pred);
|
||||||
|
}
|
||||||
|
else if (op.Predicate.IsPT)
|
||||||
{
|
{
|
||||||
context.Branch(label);
|
context.Branch(label);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue