forked from MeloNX/MeloNX
172 lines
6.4 KiB
C#
172 lines
6.4 KiB
C#
namespace Ryujinx.Cpu.LightningJit.Graph
|
|
{
|
|
static class DataFlow
|
|
{
|
|
public static (RegisterMask[], RegisterMask[]) GetGlobalUses(IBlockList blocks)
|
|
{
|
|
// Compute local register inputs and outputs used inside blocks.
|
|
RegisterMask[] localInputs = new RegisterMask[blocks.Count];
|
|
RegisterMask[] localOutputs = new RegisterMask[blocks.Count];
|
|
|
|
for (int index = 0; index < blocks.Count; index++)
|
|
{
|
|
IBlock block = blocks[index];
|
|
|
|
RegisterUse use = block.ComputeUseMasks();
|
|
|
|
localInputs[block.Index] = use.Read;
|
|
localOutputs[block.Index] = use.Write;
|
|
}
|
|
|
|
// Compute global register inputs and outputs used across blocks.
|
|
RegisterMask[] globalInputs = new RegisterMask[blocks.Count];
|
|
RegisterMask[] globalOutputs = new RegisterMask[blocks.Count];
|
|
|
|
bool modified;
|
|
|
|
// Compute register outputs.
|
|
do
|
|
{
|
|
modified = false;
|
|
|
|
for (int index = 0; index < blocks.Count; index++)
|
|
{
|
|
IBlock block = blocks[index];
|
|
|
|
int firstPIndex = GetFirstPredecessorIndex(block);
|
|
if (firstPIndex >= 0)
|
|
{
|
|
IBlock predecessor = block.GetPredecessor(firstPIndex);
|
|
|
|
RegisterMask outputs = globalOutputs[predecessor.Index];
|
|
|
|
for (int pIndex = firstPIndex + 1; pIndex < block.PredecessorsCount; pIndex++)
|
|
{
|
|
predecessor = block.GetPredecessor(pIndex);
|
|
|
|
if (predecessor.EndsWithContextStore())
|
|
{
|
|
// If a block ended with a context store, then we don't need to care
|
|
// about any of it's outputs, as they have already been saved to the context.
|
|
// Common outputs must be reset as doing a context stores indicates we will
|
|
// do a function call and wipe all register values.
|
|
|
|
continue;
|
|
}
|
|
|
|
outputs |= globalOutputs[predecessor.Index];
|
|
}
|
|
|
|
outputs |= localOutputs[block.Index];
|
|
modified |= Exchange(globalOutputs, block.Index, globalOutputs[block.Index] | outputs);
|
|
}
|
|
else
|
|
{
|
|
modified |= Exchange(globalOutputs, block.Index, localOutputs[block.Index]);
|
|
}
|
|
}
|
|
}
|
|
while (modified);
|
|
|
|
// Compute register inputs.
|
|
do
|
|
{
|
|
modified = false;
|
|
|
|
for (int index = blocks.Count - 1; index >= 0; index--)
|
|
{
|
|
IBlock block = blocks[index];
|
|
|
|
RegisterMask cmnOutputs = RegisterMask.Zero;
|
|
RegisterMask allOutputs = RegisterMask.Zero;
|
|
|
|
int firstPIndex = GetFirstPredecessorIndex(block);
|
|
if (firstPIndex == 0)
|
|
{
|
|
IBlock predecessor = block.GetPredecessor(0);
|
|
|
|
// Assumes that block index 0 is the entry block.
|
|
cmnOutputs = block.Index != 0 ? globalOutputs[predecessor.Index] : RegisterMask.Zero;
|
|
allOutputs = globalOutputs[predecessor.Index];
|
|
|
|
for (int pIndex = 1; pIndex < block.PredecessorsCount; pIndex++)
|
|
{
|
|
predecessor = block.GetPredecessor(pIndex);
|
|
|
|
if (!predecessor.EndsWithContextStore())
|
|
{
|
|
RegisterMask outputs = globalOutputs[predecessor.Index];
|
|
|
|
cmnOutputs &= outputs;
|
|
allOutputs |= outputs;
|
|
}
|
|
else
|
|
{
|
|
cmnOutputs = RegisterMask.Zero;
|
|
}
|
|
}
|
|
}
|
|
else if (firstPIndex > 0)
|
|
{
|
|
IBlock predecessor = block.GetPredecessor(firstPIndex);
|
|
|
|
allOutputs = globalOutputs[predecessor.Index];
|
|
|
|
for (int pIndex = firstPIndex + 1; pIndex < block.PredecessorsCount; pIndex++)
|
|
{
|
|
predecessor = block.GetPredecessor(pIndex);
|
|
|
|
if (!predecessor.EndsWithContextStore())
|
|
{
|
|
allOutputs |= globalOutputs[predecessor.Index];
|
|
}
|
|
}
|
|
}
|
|
|
|
RegisterMask inputs = localInputs[block.Index];
|
|
|
|
// If this block will load from context at the end,
|
|
// we don't need to care about what comes next.
|
|
if (!block.EndsWithContextLoad())
|
|
{
|
|
for (int sIndex = 0; sIndex < block.SuccessorsCount; sIndex++)
|
|
{
|
|
inputs |= globalInputs[block.GetSuccessor(sIndex).Index] & ~localOutputs[block.Index];
|
|
}
|
|
}
|
|
|
|
inputs |= allOutputs & ~localOutputs[block.Index];
|
|
inputs &= ~cmnOutputs;
|
|
|
|
modified |= Exchange(globalInputs, block.Index, globalInputs[block.Index] | inputs);
|
|
}
|
|
}
|
|
while (modified);
|
|
|
|
return (globalInputs, globalOutputs);
|
|
}
|
|
|
|
private static bool Exchange(RegisterMask[] masks, int blkIndex, RegisterMask value)
|
|
{
|
|
ref RegisterMask curValue = ref masks[blkIndex];
|
|
bool changed = curValue != value;
|
|
curValue = value;
|
|
|
|
return changed;
|
|
}
|
|
|
|
private static int GetFirstPredecessorIndex(IBlock block)
|
|
{
|
|
for (int pIndex = 0; pIndex < block.PredecessorsCount; pIndex++)
|
|
{
|
|
if (!block.GetPredecessor(pIndex).EndsWithContextStore())
|
|
{
|
|
return pIndex;
|
|
}
|
|
}
|
|
|
|
return -1;
|
|
}
|
|
}
|
|
}
|