IPC code gen improvements (#6352)

* HipcGenerator: skip do-nothing call to MemoryMarshal.Cast<byte, byte>() in generated code

* HipcGenerator: fix method name typos

* HipcGenerator: make generated methods use stackalloc for `isBufferMapAlias` bool array

* HipcGenerator: make generated GetCommandHandlers() method return a FrozenDictionary<int, CommandHandler>

* HipcGenerator: return `FrozenDictionary<,>.Empty` when there are no command implementations, otherwise create `FrozenDictionary` from a `IEnumerable<KeyValuePair<,>>`` instead of a `Dictionary<,>``
This commit is contained in:
jhorv 2024-02-23 19:12:24 -05:00 committed by GitHub
parent d4d0a48bfe
commit 08384ee5a8
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 54 additions and 42 deletions

View file

@ -74,6 +74,7 @@ namespace Ryujinx.Horizon.Generators.Hipc
generator.AppendLine("using Ryujinx.Horizon.Sdk.Sf.Cmif;"); generator.AppendLine("using Ryujinx.Horizon.Sdk.Sf.Cmif;");
generator.AppendLine("using Ryujinx.Horizon.Sdk.Sf.Hipc;"); generator.AppendLine("using Ryujinx.Horizon.Sdk.Sf.Hipc;");
generator.AppendLine("using System;"); generator.AppendLine("using System;");
generator.AppendLine("using System.Collections.Frozen;");
generator.AppendLine("using System.Collections.Generic;"); generator.AppendLine("using System.Collections.Generic;");
generator.AppendLine("using System.Runtime.CompilerServices;"); generator.AppendLine("using System.Runtime.CompilerServices;");
generator.AppendLine("using System.Runtime.InteropServices;"); generator.AppendLine("using System.Runtime.InteropServices;");
@ -115,67 +116,76 @@ namespace Ryujinx.Horizon.Generators.Hipc
private static void GenerateMethodTable(CodeGenerator generator, Compilation compilation, CommandInterface commandInterface) private static void GenerateMethodTable(CodeGenerator generator, Compilation compilation, CommandInterface commandInterface)
{ {
generator.EnterScope($"public IReadOnlyDictionary<int, CommandHandler> GetCommandHandlers()"); generator.EnterScope($"public IReadOnlyDictionary<int, CommandHandler> GetCommandHandlers()");
generator.EnterScope($"return new Dictionary<int, CommandHandler>()");
foreach (var method in commandInterface.CommandImplementations) if (commandInterface.CommandImplementations.Count == 0)
{ {
foreach (var commandId in GetAttributeAguments(compilation, method, TypeCommandAttribute, 0)) generator.AppendLine("return FrozenDictionary<int, CommandHandler>.Empty;");
}
else
{
generator.EnterScope($"return FrozenDictionary.ToFrozenDictionary(new []");
foreach (var method in commandInterface.CommandImplementations)
{ {
string[] args = new string[method.ParameterList.Parameters.Count]; foreach (var commandId in GetAttributeArguments(compilation, method, TypeCommandAttribute, 0))
if (args.Length == 0)
{ {
generator.AppendLine($"{{ {commandId}, new CommandHandler({method.Identifier.Text}, Array.Empty<CommandArg>()) }},"); string[] args = new string[method.ParameterList.Parameters.Count];
}
else
{
int index = 0;
foreach (var parameter in method.ParameterList.Parameters) if (args.Length == 0)
{ {
string canonicalTypeName = GetCanonicalTypeNameWithGenericArguments(compilation, parameter.Type); generator.AppendLine($"KeyValuePair.Create({commandId}, new CommandHandler({method.Identifier.Text}, Array.Empty<CommandArg>())),");
CommandArgType argType = GetCommandArgType(compilation, parameter); }
else
{
int index = 0;
string arg; foreach (var parameter in method.ParameterList.Parameters)
if (argType == CommandArgType.Buffer)
{ {
string bufferFlags = GetFirstAttributeAgument(compilation, parameter, TypeBufferAttribute, 0); string canonicalTypeName = GetCanonicalTypeNameWithGenericArguments(compilation, parameter.Type);
string bufferFixedSize = GetFirstAttributeAgument(compilation, parameter, TypeBufferAttribute, 1); CommandArgType argType = GetCommandArgType(compilation, parameter);
if (bufferFixedSize != null) string arg;
if (argType == CommandArgType.Buffer)
{ {
arg = $"new CommandArg({bufferFlags} | HipcBufferFlags.FixedSize, {bufferFixedSize})"; string bufferFlags = GetFirstAttributeArgument(compilation, parameter, TypeBufferAttribute, 0);
string bufferFixedSize = GetFirstAttributeArgument(compilation, parameter, TypeBufferAttribute, 1);
if (bufferFixedSize != null)
{
arg = $"new CommandArg({bufferFlags} | HipcBufferFlags.FixedSize, {bufferFixedSize})";
}
else
{
arg = $"new CommandArg({bufferFlags})";
}
}
else if (argType == CommandArgType.InArgument || argType == CommandArgType.OutArgument)
{
string alignment = GetTypeAlignmentExpression(compilation, parameter.Type);
arg = $"new CommandArg(CommandArgType.{argType}, Unsafe.SizeOf<{canonicalTypeName}>(), {alignment})";
} }
else else
{ {
arg = $"new CommandArg({bufferFlags})"; arg = $"new CommandArg(CommandArgType.{argType})";
} }
}
else if (argType == CommandArgType.InArgument || argType == CommandArgType.OutArgument)
{
string alignment = GetTypeAlignmentExpression(compilation, parameter.Type);
arg = $"new CommandArg(CommandArgType.{argType}, Unsafe.SizeOf<{canonicalTypeName}>(), {alignment})"; args[index++] = arg;
}
else
{
arg = $"new CommandArg(CommandArgType.{argType})";
} }
args[index++] = arg; generator.AppendLine($"KeyValuePair.Create({commandId}, new CommandHandler({method.Identifier.Text}, {string.Join(", ", args)})),");
} }
generator.AppendLine($"{{ {commandId}, new CommandHandler({method.Identifier.Text}, {string.Join(", ", args)}) }},");
} }
} }
generator.LeaveScope(");");
} }
generator.LeaveScope(";");
generator.LeaveScope(); generator.LeaveScope();
} }
private static IEnumerable<string> GetAttributeAguments(Compilation compilation, SyntaxNode syntaxNode, string attributeName, int argIndex) private static IEnumerable<string> GetAttributeArguments(Compilation compilation, SyntaxNode syntaxNode, string attributeName, int argIndex)
{ {
ISymbol symbol = compilation.GetSemanticModel(syntaxNode.SyntaxTree).GetDeclaredSymbol(syntaxNode); ISymbol symbol = compilation.GetSemanticModel(syntaxNode.SyntaxTree).GetDeclaredSymbol(syntaxNode);
@ -188,9 +198,9 @@ namespace Ryujinx.Horizon.Generators.Hipc
} }
} }
private static string GetFirstAttributeAgument(Compilation compilation, SyntaxNode syntaxNode, string attributeName, int argIndex) private static string GetFirstAttributeArgument(Compilation compilation, SyntaxNode syntaxNode, string attributeName, int argIndex)
{ {
return GetAttributeAguments(compilation, syntaxNode, attributeName, argIndex).FirstOrDefault(); return GetAttributeArguments(compilation, syntaxNode, attributeName, argIndex).FirstOrDefault();
} }
private static void GenerateMethod(CodeGenerator generator, Compilation compilation, MethodDeclarationSyntax method) private static void GenerateMethod(CodeGenerator generator, Compilation compilation, MethodDeclarationSyntax method)
@ -233,7 +243,7 @@ namespace Ryujinx.Horizon.Generators.Hipc
if (buffersCount != 0) if (buffersCount != 0)
{ {
generator.AppendLine($"bool[] {IsBufferMapAliasVariableName} = new bool[{method.ParameterList.Parameters.Count}];"); generator.AppendLine($"Span<bool> {IsBufferMapAliasVariableName} = stackalloc bool[{method.ParameterList.Parameters.Count}];");
generator.AppendLine(); generator.AppendLine();
generator.AppendLine($"{ResultVariableName} = processor.ProcessBuffers(ref context, {IsBufferMapAliasVariableName}, runtimeMetadata);"); generator.AppendLine($"{ResultVariableName} = processor.ProcessBuffers(ref context, {IsBufferMapAliasVariableName}, runtimeMetadata);");
@ -719,7 +729,9 @@ namespace Ryujinx.Horizon.Generators.Hipc
private static string GenerateSpanCast(string targetType, string input) private static string GenerateSpanCast(string targetType, string input)
{ {
return $"MemoryMarshal.Cast<byte, {targetType}>({input})"; return targetType == "byte"
? input
: $"MemoryMarshal.Cast<byte, {targetType}>({input})";
} }
private static bool HasAttribute(Compilation compilation, ParameterSyntax parameterSyntax, string fullAttributeName) private static bool HasAttribute(Compilation compilation, ParameterSyntax parameterSyntax, string fullAttributeName)

View file

@ -127,7 +127,7 @@ namespace Ryujinx.Horizon.Sdk.Sf
return _bufferRanges[argIndex]; return _bufferRanges[argIndex];
} }
public Result ProcessBuffers(ref ServiceDispatchContext context, bool[] isBufferMapAlias, ServerMessageRuntimeMetadata runtimeMetadata) public Result ProcessBuffers(ref ServiceDispatchContext context, scoped Span<bool> isBufferMapAlias, ServerMessageRuntimeMetadata runtimeMetadata)
{ {
bool mapAliasBuffersValid = true; bool mapAliasBuffersValid = true;
@ -246,7 +246,7 @@ namespace Ryujinx.Horizon.Sdk.Sf
return mode == HipcBufferMode.Normal; return mode == HipcBufferMode.Normal;
} }
public void SetOutBuffers(HipcMessageData response, bool[] isBufferMapAlias) public void SetOutBuffers(HipcMessageData response, ReadOnlySpan<bool> isBufferMapAlias)
{ {
int recvPointerIndex = 0; int recvPointerIndex = 0;