Optimize pack/unpack sequences, some fixes related to half float instructions

This commit is contained in:
gdkchan 2019-04-06 15:36:30 -03:00
commit ce71abeec9
3 changed files with 103 additions and 20 deletions

View file

@ -2,7 +2,7 @@ using Ryujinx.Graphics.Shader.Instructions;
namespace Ryujinx.Graphics.Shader.Decoders namespace Ryujinx.Graphics.Shader.Decoders
{ {
class OpCodeAluImm2x10 : OpCode, IOpCodeImm class OpCodeAluImm2x10 : OpCodeAlu, IOpCodeImm
{ {
public int Immediate { get; } public int Immediate { get; }

View file

@ -292,7 +292,7 @@ namespace Ryujinx.Graphics.Shader.Instructions
FPHalfSwizzle swizzle = FPHalfSwizzle.FP16; FPHalfSwizzle swizzle = FPHalfSwizzle.FP16;
if (!(op is OpCodeAluImm32)) if (!(op is IOpCodeImm))
{ {
swizzle = (FPHalfSwizzle)op.RawOpCode.Extract(28, 2); swizzle = (FPHalfSwizzle)op.RawOpCode.Extract(28, 2);
} }
@ -314,16 +314,6 @@ namespace Ryujinx.Graphics.Shader.Instructions
return FPAbsNeg(context, operands, absoluteB, negateB); return FPAbsNeg(context, operands, absoluteB, negateB);
} }
private static Operand[] FPAbsNeg(EmitterContext context, Operand[] operands, bool abs, bool neg)
{
for (int index = 0; index < operands.Length; index++)
{
operands[index] = context.FPAbsNeg(operands[index], abs, neg);
}
return operands;
}
private static Operand[] GetHalfSources(EmitterContext context, Operand src, FPHalfSwizzle swizzle) private static Operand[] GetHalfSources(EmitterContext context, Operand src, FPHalfSwizzle swizzle)
{ {
switch (swizzle) switch (swizzle)
@ -355,6 +345,16 @@ namespace Ryujinx.Graphics.Shader.Instructions
throw new ArgumentException($"Invalid swizzle \"{swizzle}\"."); throw new ArgumentException($"Invalid swizzle \"{swizzle}\".");
} }
private static Operand[] FPAbsNeg(EmitterContext context, Operand[] operands, bool abs, bool neg)
{
for (int index = 0; index < operands.Length; index++)
{
operands[index] = context.FPAbsNeg(operands[index], abs, neg);
}
return operands;
}
private static Operand GetHalfPacked(EmitterContext context, Operand[] results) private static Operand GetHalfPacked(EmitterContext context, Operand[] results)
{ {
OpCode op = context.CurrOp; OpCode op = context.CurrOp;
@ -368,15 +368,40 @@ namespace Ryujinx.Graphics.Shader.Instructions
switch (swizzle) switch (swizzle)
{ {
case FPHalfSwizzle.FP16: return context.PackHalf2x16(results[0], results[1]); case FPHalfSwizzle.FP16: return context.PackHalf2x16(results[0], results[1]);
case FPHalfSwizzle.FP32: return results[0];
case FPHalfSwizzle.DupH0: return context.PackHalf2x16(results[0], results[0]); case FPHalfSwizzle.FP32: return results[0];
case FPHalfSwizzle.DupH1: return context.PackHalf2x16(results[1], results[1]);
case FPHalfSwizzle.DupH0:
{
Operand h1 = GetHalfDest(context, isHigh: true);
return context.PackHalf2x16(results[0], h1);
}
case FPHalfSwizzle.DupH1:
{
Operand h0 = GetHalfDest(context, isHigh: false);
return context.PackHalf2x16(h0, results[1]);
}
} }
throw new ArgumentException($"Invalid swizzle \"{swizzle}\"."); throw new ArgumentException($"Invalid swizzle \"{swizzle}\".");
} }
private static Operand GetHalfDest(EmitterContext context, bool isHigh)
{
if (isHigh)
{
return context.UnpackHalf2x16High(GetDest(context));
}
else
{
return context.UnpackHalf2x16Low(GetDest(context));
}
}
private static Operand GetFPComparison( private static Operand GetFPComparison(
EmitterContext context, EmitterContext context,
Condition cond, Condition cond,

View file

@ -1,5 +1,6 @@
using Ryujinx.Graphics.Shader.IntermediateRepresentation; using Ryujinx.Graphics.Shader.IntermediateRepresentation;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq;
namespace Ryujinx.Graphics.Shader.Translation.Optimizations namespace Ryujinx.Graphics.Shader.Translation.Optimizations
{ {
@ -43,13 +44,25 @@ namespace Ryujinx.Graphics.Shader.Translation.Optimizations
Simplification.Simplify(operation); Simplification.Simplify(operation);
if (operation.Inst == Instruction.Copy && DestIsLocalVar(operation)) if (DestIsLocalVar(operation))
{ {
PropagateCopy(operation); if (operation.Inst == Instruction.Copy)
{
PropagateCopy(operation);
RemoveNode(block, node); RemoveNode(block, node);
modified = true; modified = true;
}
else if (operation.Inst == Instruction.PackHalf2x16 && PropagatePack(operation))
{
if (operation.Dest.UseOps.Count == 0)
{
RemoveNode(block, node);
}
modified = true;
}
} }
node = nextNode; node = nextNode;
@ -85,6 +98,51 @@ namespace Ryujinx.Graphics.Shader.Translation.Optimizations
} }
} }
private static bool PropagatePack(Operation packOp)
{
//Propagate pack source operands to uses by unpack
//instruction. The source depends on the unpack instruction.
bool modified = false;
Operand dest = packOp.Dest;
Operand src0 = packOp.GetSource(0);
Operand src1 = packOp.GetSource(1);
INode[] uses = dest.UseOps.ToArray();
foreach (INode useNode in uses)
{
if (!(useNode is Operation operation))
{
continue;
}
Operand src;
if (operation.Inst == Instruction.UnpackHalf2x16High)
{
src = src1;
}
else if (operation.Inst == Instruction.UnpackHalf2x16Low)
{
src = src0;
}
else
{
continue;
}
if (operation.GetSource(0) == dest)
{
operation.TurnIntoCopy(src);
modified = true;
}
}
return modified;
}
private static void RemoveNode(BasicBlock block, LinkedListNode<INode> llNode) private static void RemoveNode(BasicBlock block, LinkedListNode<INode> llNode)
{ {
//Remove a node from the nodes list, and also remove itself //Remove a node from the nodes list, and also remove itself