Initial work

This commit is contained in:
gdk 2019-10-13 03:02:07 -03:00 committed by Thog
parent f617fb542a
commit 1876b346fe
518 changed files with 15170 additions and 12486 deletions

View file

@ -0,0 +1,61 @@
using System.Collections.Generic;
namespace Ryujinx.Graphics.Shader.IntermediateRepresentation
{
class BasicBlock
{
public int Index { get; set; }
public LinkedList<INode> Operations { get; }
private BasicBlock _next;
private BasicBlock _branch;
public BasicBlock Next
{
get => _next;
set => _next = AddSuccessor(_next, value);
}
public BasicBlock Branch
{
get => _branch;
set => _branch = AddSuccessor(_branch, value);
}
public bool HasBranch => _branch != null;
public List<BasicBlock> Predecessors { get; }
public HashSet<BasicBlock> DominanceFrontiers { get; }
public BasicBlock ImmediateDominator { get; set; }
public BasicBlock()
{
Operations = new LinkedList<INode>();
Predecessors = new List<BasicBlock>();
DominanceFrontiers = new HashSet<BasicBlock>();
}
public BasicBlock(int index) : this()
{
Index = index;
}
private BasicBlock AddSuccessor(BasicBlock oldBlock, BasicBlock newBlock)
{
oldBlock?.Predecessors.Remove(this);
newBlock?.Predecessors.Add(this);
return newBlock;
}
public INode GetLastOp()
{
return Operations.Last?.Value;
}
}
}

View file

@ -0,0 +1,12 @@
namespace Ryujinx.Graphics.Shader.IntermediateRepresentation
{
class CommentNode : Operation
{
public string Comment { get; }
public CommentNode(string comment) : base(Instruction.Comment, null)
{
Comment = comment;
}
}
}

View file

@ -0,0 +1,13 @@
namespace Ryujinx.Graphics.Shader.IntermediateRepresentation
{
interface INode
{
Operand Dest { get; set; }
int SourcesCount { get; }
Operand GetSource(int index);
void SetSource(int index, Operand operand);
}
}

View file

@ -0,0 +1,91 @@
using System;
namespace Ryujinx.Graphics.Shader.IntermediateRepresentation
{
[Flags]
enum Instruction
{
Absolute = 1,
Add,
BitfieldExtractS32,
BitfieldExtractU32,
BitfieldInsert,
BitfieldReverse,
BitwiseAnd,
BitwiseExclusiveOr,
BitwiseNot,
BitwiseOr,
Branch,
BranchIfFalse,
BranchIfTrue,
Ceiling,
Clamp,
ClampU32,
Comment,
CompareEqual,
CompareGreater,
CompareGreaterOrEqual,
CompareGreaterOrEqualU32,
CompareGreaterU32,
CompareLess,
CompareLessOrEqual,
CompareLessOrEqualU32,
CompareLessU32,
CompareNotEqual,
ConditionalSelect,
ConvertFPToS32,
ConvertS32ToFP,
ConvertU32ToFP,
Copy,
Cosine,
Discard,
Divide,
EmitVertex,
EndPrimitive,
ExponentB2,
Floor,
FusedMultiplyAdd,
IsNan,
LoadAttribute,
LoadConstant,
LoadGlobal,
LoadLocal,
LoadStorage,
LogarithmB2,
LogicalAnd,
LogicalExclusiveOr,
LogicalNot,
LogicalOr,
LoopBreak,
LoopContinue,
MarkLabel,
Maximum,
MaximumU32,
Minimum,
MinimumU32,
Multiply,
Negate,
PackDouble2x32,
PackHalf2x16,
ReciprocalSquareRoot,
Return,
ShiftLeft,
ShiftRightS32,
ShiftRightU32,
Sine,
SquareRoot,
StoreGlobal,
StoreLocal,
StoreStorage,
Subtract,
TextureSample,
TextureSize,
Truncate,
UnpackDouble2x32,
UnpackHalf2x16,
Count,
FP = 1 << 16,
Mask = 0xffff
}
}

View file

@ -0,0 +1,8 @@
namespace Ryujinx.Graphics.Shader.IntermediateRepresentation
{
static class IrConsts
{
public const int False = 0;
public const int True = -1;
}
}

View file

@ -0,0 +1,82 @@
using Ryujinx.Graphics.Shader.Decoders;
using System;
using System.Collections.Generic;
namespace Ryujinx.Graphics.Shader.IntermediateRepresentation
{
class Operand
{
private const int CbufSlotBits = 5;
private const int CbufSlotLsb = 32 - CbufSlotBits;
private const int CbufSlotMask = (1 << CbufSlotBits) - 1;
public OperandType Type { get; }
public int Value { get; }
public InterpolationQualifier Interpolation { get; }
public INode AsgOp { get; set; }
public HashSet<INode> UseOps { get; }
private Operand()
{
UseOps = new HashSet<INode>();
}
public Operand(OperandType type) : this()
{
Type = type;
}
public Operand(OperandType type, int value, InterpolationQualifier iq = InterpolationQualifier.None) : this()
{
Type = type;
Value = value;
Interpolation = iq;
}
public Operand(Register reg) : this()
{
Type = OperandType.Register;
Value = PackRegInfo(reg.Index, reg.Type);
}
public Operand(int slot, int offset) : this()
{
Type = OperandType.ConstantBuffer;
Value = PackCbufInfo(slot, offset);
}
private static int PackCbufInfo(int slot, int offset)
{
return (slot << CbufSlotLsb) | offset;
}
private static int PackRegInfo(int index, RegisterType type)
{
return ((int)type << 24) | index;
}
public int GetCbufSlot()
{
return (Value >> CbufSlotLsb) & CbufSlotMask;
}
public int GetCbufOffset()
{
return Value & ~(CbufSlotMask << CbufSlotLsb);
}
public Register GetRegister()
{
return new Register(Value & 0xffffff, (RegisterType)(Value >> 24));
}
public float AsFloat()
{
return BitConverter.Int32BitsToSingle(Value);
}
}
}

View file

@ -0,0 +1,62 @@
using Ryujinx.Graphics.Shader.Decoders;
using System;
namespace Ryujinx.Graphics.Shader.IntermediateRepresentation
{
static class OperandHelper
{
public static Operand Attribute(int value, InterpolationQualifier iq = InterpolationQualifier.None)
{
return new Operand(OperandType.Attribute, value, iq);
}
public static Operand Cbuf(int slot, int offset)
{
return new Operand(slot, offset);
}
public static Operand Const(int value)
{
return new Operand(OperandType.Constant, value);
}
public static Operand ConstF(float value)
{
return new Operand(OperandType.Constant, BitConverter.SingleToInt32Bits(value));
}
public static Operand Label()
{
return new Operand(OperandType.Label);
}
public static Operand Local()
{
return new Operand(OperandType.LocalVariable);
}
public static Operand Register(int index, RegisterType type)
{
return Register(new Register(index, type));
}
public static Operand Register(Register reg)
{
if (reg.IsRZ)
{
return Const(0);
}
else if (reg.IsPT)
{
return Const(IrConsts.True);
}
return new Operand(reg);
}
public static Operand Undef()
{
return new Operand(OperandType.Undefined);
}
}
}

View file

@ -0,0 +1,13 @@
namespace Ryujinx.Graphics.Shader.IntermediateRepresentation
{
enum OperandType
{
Attribute,
Constant,
ConstantBuffer,
Label,
LocalVariable,
Register,
Undefined
}
}

View file

@ -0,0 +1,101 @@
namespace Ryujinx.Graphics.Shader.IntermediateRepresentation
{
class Operation : INode
{
public Instruction Inst { get; private set; }
private Operand _dest;
public Operand Dest
{
get => _dest;
set => _dest = AssignDest(value);
}
private Operand[] _sources;
public int SourcesCount => _sources.Length;
public int ComponentIndex { get; }
public Operation(Instruction inst, Operand dest, params Operand[] sources)
{
Inst = inst;
Dest = dest;
// The array may be modified externally, so we store a copy.
_sources = (Operand[])sources.Clone();
for (int index = 0; index < _sources.Length; index++)
{
Operand source = _sources[index];
if (source.Type == OperandType.LocalVariable)
{
source.UseOps.Add(this);
}
}
}
public Operation(
Instruction inst,
int compIndex,
Operand dest,
params Operand[] sources) : this(inst, dest, sources)
{
ComponentIndex = compIndex;
}
private Operand AssignDest(Operand dest)
{
if (dest != null && dest.Type == OperandType.LocalVariable)
{
dest.AsgOp = this;
}
return dest;
}
public Operand GetSource(int index)
{
return _sources[index];
}
public void SetSource(int index, Operand source)
{
Operand oldSrc = _sources[index];
if (oldSrc != null && oldSrc.Type == OperandType.LocalVariable)
{
oldSrc.UseOps.Remove(this);
}
if (source != null && source.Type == OperandType.LocalVariable)
{
source.UseOps.Add(this);
}
_sources[index] = source;
}
public void TurnIntoCopy(Operand source)
{
Inst = Instruction.Copy;
foreach (Operand oldSrc in _sources)
{
if (oldSrc != null && oldSrc.Type == OperandType.LocalVariable)
{
oldSrc.UseOps.Remove(this);
}
}
if (source.Type == OperandType.LocalVariable)
{
source.UseOps.Add(this);
}
_sources = new Operand[] { source };
}
}
}

View file

@ -0,0 +1,94 @@
using System.Collections.Generic;
namespace Ryujinx.Graphics.Shader.IntermediateRepresentation
{
class PhiNode : INode
{
private Operand _dest;
public Operand Dest
{
get => _dest;
set => _dest = AssignDest(value);
}
private HashSet<BasicBlock> _blocks;
private class PhiSource
{
public BasicBlock Block { get; }
public Operand Operand { get; set; }
public PhiSource(BasicBlock block, Operand operand)
{
Block = block;
Operand = operand;
}
}
private List<PhiSource> _sources;
public int SourcesCount => _sources.Count;
public PhiNode(Operand dest)
{
_blocks = new HashSet<BasicBlock>();
_sources = new List<PhiSource>();
dest.AsgOp = this;
Dest = dest;
}
private Operand AssignDest(Operand dest)
{
if (dest != null && dest.Type == OperandType.LocalVariable)
{
dest.AsgOp = this;
}
return dest;
}
public void AddSource(BasicBlock block, Operand operand)
{
if (_blocks.Add(block))
{
if (operand.Type == OperandType.LocalVariable)
{
operand.UseOps.Add(this);
}
_sources.Add(new PhiSource(block, operand));
}
}
public Operand GetSource(int index)
{
return _sources[index].Operand;
}
public BasicBlock GetBlock(int index)
{
return _sources[index].Block;
}
public void SetSource(int index, Operand source)
{
Operand oldSrc = _sources[index].Operand;
if (oldSrc != null && oldSrc.Type == OperandType.LocalVariable)
{
oldSrc.UseOps.Remove(this);
}
if (source.Type == OperandType.LocalVariable)
{
source.UseOps.Add(this);
}
_sources[index].Operand = source;
}
}
}

View file

@ -0,0 +1,17 @@
using System;
namespace Ryujinx.Graphics.Shader.IntermediateRepresentation
{
[Flags]
enum TextureFlags
{
None = 0,
Bindless = 1 << 0,
Gather = 1 << 1,
IntCoords = 1 << 2,
LodBias = 1 << 3,
LodLevel = 1 << 4,
Offset = 1 << 5,
Offsets = 1 << 6
}
}

View file

@ -0,0 +1,24 @@
namespace Ryujinx.Graphics.Shader.IntermediateRepresentation
{
class TextureOperation : Operation
{
public TextureTarget Target { get; }
public TextureFlags Flags { get; }
public int Handle { get; }
public TextureOperation(
Instruction inst,
TextureTarget target,
TextureFlags flags,
int handle,
int compIndex,
Operand dest,
params Operand[] sources) : base(inst, compIndex, dest, sources)
{
Target = target;
Flags = flags;
Handle = handle;
}
}
}