Use unique temporary variables for function call parameters on SPIR-V (#5757)

* Use unique temporary variables for function call parameters on SPIR-V

* Shader cache version bump
This commit is contained in:
gdkchan 2023-10-04 19:46:11 -03:00 committed by GitHub
parent f61b7818c3
commit a0af6e4d07
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
7 changed files with 33 additions and 49 deletions

View file

@ -22,7 +22,7 @@ namespace Ryujinx.Graphics.Gpu.Shader.DiskCache
private const ushort FileFormatVersionMajor = 1; private const ushort FileFormatVersionMajor = 1;
private const ushort FileFormatVersionMinor = 2; private const ushort FileFormatVersionMinor = 2;
private const uint FileFormatVersionPacked = ((uint)FileFormatVersionMajor << 16) | FileFormatVersionMinor; private const uint FileFormatVersionPacked = ((uint)FileFormatVersionMajor << 16) | FileFormatVersionMinor;
private const uint CodeGenVersion = 5750; private const uint CodeGenVersion = 5757;
private const string SharedTocFileName = "shared.toc"; private const string SharedTocFileName = "shared.toc";
private const string SharedDataFileName = "shared.data"; private const string SharedDataFileName = "shared.data";

View file

@ -44,7 +44,6 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv
public StructuredFunction CurrentFunction { get; set; } public StructuredFunction CurrentFunction { get; set; }
private readonly Dictionary<AstOperand, Instruction> _locals = new(); private readonly Dictionary<AstOperand, Instruction> _locals = new();
private readonly Dictionary<int, Instruction[]> _localForArgs = new();
private readonly Dictionary<int, Instruction> _funcArgs = new(); private readonly Dictionary<int, Instruction> _funcArgs = new();
private readonly Dictionary<int, (StructuredFunction, Instruction)> _functions = new(); private readonly Dictionary<int, (StructuredFunction, Instruction)> _functions = new();
@ -112,7 +111,6 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv
IsMainFunction = isMainFunction; IsMainFunction = isMainFunction;
MayHaveReturned = false; MayHaveReturned = false;
_locals.Clear(); _locals.Clear();
_localForArgs.Clear();
_funcArgs.Clear(); _funcArgs.Clear();
} }
@ -169,11 +167,6 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv
_locals.Add(local, spvLocal); _locals.Add(local, spvLocal);
} }
public void DeclareLocalForArgs(int funcIndex, Instruction[] spvLocals)
{
_localForArgs.Add(funcIndex, spvLocals);
}
public void DeclareArgument(int argIndex, Instruction spvLocal) public void DeclareArgument(int argIndex, Instruction spvLocal)
{ {
_funcArgs.Add(argIndex, spvLocal); _funcArgs.Add(argIndex, spvLocal);
@ -278,11 +271,6 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv
return _locals[local]; return _locals[local];
} }
public Instruction[] GetLocalForArgsPointers(int funcIndex)
{
return _localForArgs[funcIndex];
}
public Instruction GetArgumentPointer(AstOperand funcArg) public Instruction GetArgumentPointer(AstOperand funcArg)
{ {
return _funcArgs[funcArg.Value]; return _funcArgs[funcArg.Value];

View file

@ -41,28 +41,6 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv
} }
} }
public static void DeclareLocalForArgs(CodeGenContext context, List<StructuredFunction> functions)
{
for (int funcIndex = 0; funcIndex < functions.Count; funcIndex++)
{
StructuredFunction function = functions[funcIndex];
SpvInstruction[] locals = new SpvInstruction[function.InArguments.Length];
for (int i = 0; i < function.InArguments.Length; i++)
{
var type = function.GetArgumentType(i);
var localPointerType = context.TypePointer(StorageClass.Function, context.GetType(type));
var spvLocal = context.Variable(localPointerType, StorageClass.Function);
context.AddLocalVariable(spvLocal);
locals[i] = spvLocal;
}
context.DeclareLocalForArgs(funcIndex, locals);
}
}
public static void DeclareAll(CodeGenContext context, StructuredProgramInfo info) public static void DeclareAll(CodeGenContext context, StructuredProgramInfo info)
{ {
DeclareConstantBuffers(context, context.Properties.ConstantBuffers.Values); DeclareConstantBuffers(context, context.Properties.ConstantBuffers.Values);

View file

@ -311,7 +311,6 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv
var (function, spvFunc) = context.GetFunction(funcId.Value); var (function, spvFunc) = context.GetFunction(funcId.Value);
var args = new SpvInstruction[operation.SourcesCount - 1]; var args = new SpvInstruction[operation.SourcesCount - 1];
var spvLocals = context.GetLocalForArgsPointers(funcId.Value);
for (int i = 0; i < args.Length; i++) for (int i = 0; i < args.Length; i++)
{ {
@ -324,12 +323,8 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv
else else
{ {
var type = function.GetArgumentType(i); var type = function.GetArgumentType(i);
var value = context.Get(type, operand);
var spvLocal = spvLocals[i];
context.Store(spvLocal, value); args[i] = context.Get(type, operand);
args[i] = spvLocal;
} }
} }

View file

@ -161,7 +161,6 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv
context.EnterBlock(function.MainBlock); context.EnterBlock(function.MainBlock);
Declarations.DeclareLocals(context, function); Declarations.DeclareLocals(context, function);
Declarations.DeclareLocalForArgs(context, info.Functions);
Generate(context, function.MainBlock); Generate(context, function.MainBlock);

View file

@ -8,11 +8,15 @@ namespace Ryujinx.Graphics.Shader.StructuredIr
{ {
static class StructuredProgram static class StructuredProgram
{ {
// TODO: Eventually it should be possible to specify the parameter types for the function instead of using S32 for everything.
private const AggregateType FuncParameterType = AggregateType.S32;
public static StructuredProgramInfo MakeStructuredProgram( public static StructuredProgramInfo MakeStructuredProgram(
IReadOnlyList<Function> functions, IReadOnlyList<Function> functions,
AttributeUsage attributeUsage, AttributeUsage attributeUsage,
ShaderDefinitions definitions, ShaderDefinitions definitions,
ResourceManager resourceManager, ResourceManager resourceManager,
TargetLanguage targetLanguage,
bool debugMode) bool debugMode)
{ {
StructuredProgramContext context = new(attributeUsage, definitions, resourceManager, debugMode); StructuredProgramContext context = new(attributeUsage, definitions, resourceManager, debugMode);
@ -23,19 +27,19 @@ namespace Ryujinx.Graphics.Shader.StructuredIr
BasicBlock[] blocks = function.Blocks; BasicBlock[] blocks = function.Blocks;
AggregateType returnType = function.ReturnsValue ? AggregateType.S32 : AggregateType.Void; AggregateType returnType = function.ReturnsValue ? FuncParameterType : AggregateType.Void;
AggregateType[] inArguments = new AggregateType[function.InArgumentsCount]; AggregateType[] inArguments = new AggregateType[function.InArgumentsCount];
AggregateType[] outArguments = new AggregateType[function.OutArgumentsCount]; AggregateType[] outArguments = new AggregateType[function.OutArgumentsCount];
for (int i = 0; i < inArguments.Length; i++) for (int i = 0; i < inArguments.Length; i++)
{ {
inArguments[i] = AggregateType.S32; inArguments[i] = FuncParameterType;
} }
for (int i = 0; i < outArguments.Length; i++) for (int i = 0; i < outArguments.Length; i++)
{ {
outArguments[i] = AggregateType.S32; outArguments[i] = FuncParameterType;
} }
context.EnterFunction(blocks.Length, function.Name, returnType, inArguments, outArguments); context.EnterFunction(blocks.Length, function.Name, returnType, inArguments, outArguments);
@ -58,7 +62,7 @@ namespace Ryujinx.Graphics.Shader.StructuredIr
} }
else else
{ {
AddOperation(context, operation); AddOperation(context, operation, targetLanguage);
} }
} }
} }
@ -73,7 +77,7 @@ namespace Ryujinx.Graphics.Shader.StructuredIr
return context.Info; return context.Info;
} }
private static void AddOperation(StructuredProgramContext context, Operation operation) private static void AddOperation(StructuredProgramContext context, Operation operation, TargetLanguage targetLanguage)
{ {
Instruction inst = operation.Inst; Instruction inst = operation.Inst;
StorageKind storageKind = operation.StorageKind; StorageKind storageKind = operation.StorageKind;
@ -114,10 +118,29 @@ namespace Ryujinx.Graphics.Shader.StructuredIr
IAstNode[] sources = new IAstNode[sourcesCount + outDestsCount]; IAstNode[] sources = new IAstNode[sourcesCount + outDestsCount];
if (inst == Instruction.Call && targetLanguage == TargetLanguage.Spirv)
{
// SPIR-V requires that all function parameters are copied to a local variable before the call
// (or at least that's what the Khronos compiler does).
// First one is the function index.
sources[0] = context.GetOperandOrCbLoad(operation.GetSource(0));
// Remaining ones are parameters, copy them to a temp local variable.
for (int index = 1; index < operation.SourcesCount; index++)
{
AstOperand argTemp = context.NewTemp(FuncParameterType);
context.AddNode(new AstAssignment(argTemp, context.GetOperandOrCbLoad(operation.GetSource(index))));
sources[index] = argTemp;
}
}
else
{
for (int index = 0; index < operation.SourcesCount; index++) for (int index = 0; index < operation.SourcesCount; index++)
{ {
sources[index] = context.GetOperandOrCbLoad(operation.GetSource(index)); sources[index] = context.GetOperandOrCbLoad(operation.GetSource(index));
} }
}
for (int index = 0; index < outDestsCount; index++) for (int index = 0; index < outDestsCount; index++)
{ {

View file

@ -329,6 +329,7 @@ namespace Ryujinx.Graphics.Shader.Translation
attributeUsage, attributeUsage,
definitions, definitions,
resourceManager, resourceManager,
Options.TargetLanguage,
Options.Flags.HasFlag(TranslationFlags.DebugMode)); Options.Flags.HasFlag(TranslationFlags.DebugMode));
int geometryVerticesPerPrimitive = Definitions.OutputTopology switch int geometryVerticesPerPrimitive = Definitions.OutputTopology switch