Tamper generic explosion and code style

This commit is contained in:
Aaron Robinson 2025-11-19 22:28:50 -06:00
parent b9da6a15d7
commit 529d6f44bb
30 changed files with 180 additions and 98 deletions

View file

@ -68,8 +68,8 @@ namespace Ryujinx.HLE.Generators
public void Initialize(IncrementalGeneratorInitializationContext context)
{
var predicate = (SyntaxNode node, CancellationToken _) => node is MethodDeclarationSyntax;
var transform = (GeneratorAttributeSyntaxContext ctx, CancellationToken _) =>
Func<SyntaxNode, CancellationToken, bool> predicate = (node, _) => node is MethodDeclarationSyntax;
Func<GeneratorAttributeSyntaxContext, CancellationToken, CommandData> transform = (ctx, _) =>
{
var target = (IMethodSymbol)ctx.TargetSymbol;
return new CommandData
@ -80,27 +80,28 @@ namespace Ryujinx.HLE.Generators
CommandIds = ctx.Attributes.Select(attr => (int)attr.ConstructorArguments[0].Value!).ToImmutableArray(),
};
};
var cmifCommands =
IncrementalValuesProvider<CommandData> cmifCommands =
context.SyntaxProvider.ForAttributeWithMetadataName("Ryujinx.HLE.HOS.Services.CommandCmifAttribute",
predicate,
transform
);
var tipcCommands =
IncrementalValuesProvider<CommandData> tipcCommands =
context.SyntaxProvider.ForAttributeWithMetadataName("Ryujinx.HLE.HOS.Services.CommandTipcAttribute",
predicate,
transform
);
var allCommands = cmifCommands.Collect().Combine(tipcCommands.Collect());
IncrementalValueProvider<(ImmutableArray<CommandData> Left, ImmutableArray<CommandData> Right)> allCommands =
cmifCommands.Collect().Combine(tipcCommands.Collect());
var types = allCommands.SelectMany((commands, _) =>
IncrementalValuesProvider<ServiceData> types = allCommands.SelectMany((commands, _) =>
{
var cmif = commands.Left.ToLookup(c => (c.Namespace, c.TypeName));
var tipc = commands.Right.ToLookup(c => (c.Namespace, c.TypeName));
ILookup<(string Namespace, string TypeName), CommandData> cmif = commands.Left.ToLookup(c => (c.Namespace, c.TypeName));
ILookup<(string Namespace, string TypeName), CommandData> tipc = commands.Right.ToLookup(c => (c.Namespace, c.TypeName));
var builder = ImmutableArray.CreateBuilder<ServiceData>();
ImmutableArray<ServiceData>.Builder builder = ImmutableArray.CreateBuilder<ServiceData>();
foreach (var type in cmif.Select(c => c.Key).Union(tipc.Select(t => t.Key)))
foreach ((string Namespace, string TypeName) type in cmif.Select(c => c.Key).Union(tipc.Select(t => t.Key)))
{
builder.Add(new ServiceData
{
@ -143,7 +144,7 @@ namespace Ryujinx.HLE.Generators
{
generator.EnterScope($"protected override RC Invoke{commandType}Method(int id, ServiceCtx context)");
generator.EnterScope("switch (id)");
foreach (var command in commands)
foreach (CommandData command in commands)
{
generator.AppendLine($"case {string.Join(" or ", command.CommandIds)}:");
generator.IncreaseIndentation();
@ -157,7 +158,7 @@ namespace Ryujinx.HLE.Generators
generator.EnterScope($"public override int {commandType}CommandIdByMethodName(string name)");
generator.EnterScope("return name switch");
foreach (var command in commands)
foreach (CommandData command in commands)
{
// just return the first command with this name
generator.AppendLine($"\"{command.MethodName}\" => {command.CommandIds[0]},");

View file

@ -28,12 +28,12 @@ namespace Ryujinx.HLE.Generators
public void Initialize(IncrementalGeneratorInitializationContext context)
{
var pipeline = context.SyntaxProvider.ForAttributeWithMetadataName("Ryujinx.HLE.HOS.Services.ServiceAttribute",
IncrementalValuesProvider<ServiceData> pipeline = context.SyntaxProvider.ForAttributeWithMetadataName("Ryujinx.HLE.HOS.Services.ServiceAttribute",
predicate: (node, _) => node is ClassDeclarationSyntax decl && !decl.Modifiers.Any(SyntaxKind.AbstractKeyword) && !decl.Modifiers.Any(SyntaxKind.PrivateKeyword),
transform: (ctx, _) =>
{
var target = (INamedTypeSymbol)ctx.TargetSymbol;
var instances = ctx.Attributes.Select(attr =>
IEnumerable<(string, string param)> instances = ctx.Attributes.Select(attr =>
{
string param = attr.ConstructorArguments is [_, { IsNull: false } arg] ? arg.ToCSharpString() : null;
return ((string)attr.ConstructorArguments[0].Value, param);
@ -60,9 +60,9 @@ namespace Ryujinx.HLE.Generators
generator.EnterScope("return name switch");
foreach (var serviceImpl in data)
foreach (ServiceData serviceImpl in data)
{
foreach (var instance in serviceImpl.Instances)
foreach ((string ServiceName, string ParameterValue) instance in serviceImpl.Instances)
{
if (instance.ParameterValue == null)
{

View file

@ -48,7 +48,7 @@ namespace Ryujinx.HLE.Exceptions
{
StringBuilder sb = new();
var commandId = Request.Type > IpcMessageType.TipcCloseSession
int commandId = Request.Type > IpcMessageType.TipcCloseSession
? Service.TipcCommandIdByMethodName(MethodName)
: Service.CmifCommandIdByMethodName(MethodName);

View file

@ -69,7 +69,7 @@ namespace Ryujinx.HLE.HOS.Tamper.CodeEmitters
throw new TamperCompilationException($"Invalid right-hand side switch {rightHandSideIsImmediate} in Atmosphere cheat");
}
void EmitCore<TOp>(IOperand rhs = null) where TOp : IOperation
void EmitCore<TOp>(IOperand rhs = null) where TOp : IOperationFactory
{
InstructionHelper.Emit<TOp>(operationWidth, context, destinationRegister, leftHandSideRegister, rhs);
}
@ -77,34 +77,34 @@ namespace Ryujinx.HLE.HOS.Tamper.CodeEmitters
switch (operation)
{
case Add:
EmitCore<OpAdd<byte>>(rightHandSideOperand);
EmitCore<OpAddFactory>(rightHandSideOperand);
break;
case Sub:
EmitCore<OpSub<byte>>(rightHandSideOperand);
EmitCore<OpSubFactory>(rightHandSideOperand);
break;
case Mul:
EmitCore<OpMul<byte>>(rightHandSideOperand);
EmitCore<OpMulFactory>(rightHandSideOperand);
break;
case Lsh:
EmitCore<OpLsh<byte>>(rightHandSideOperand);
EmitCore<OpLshFactory>(rightHandSideOperand);
break;
case Rsh:
EmitCore<OpRsh<byte>>(rightHandSideOperand);
EmitCore<OpRshFactory>(rightHandSideOperand);
break;
case And:
EmitCore<OpAnd<byte>>(rightHandSideOperand);
EmitCore<OpAndFactory>(rightHandSideOperand);
break;
case Or:
EmitCore<OpOr<byte>>(rightHandSideOperand);
EmitCore<OpOrFactory>(rightHandSideOperand);
break;
case Not:
EmitCore<OpNot<byte>>();
EmitCore<OpNotFactory>();
break;
case Xor:
EmitCore<OpXor<byte>>(rightHandSideOperand);
EmitCore<OpXorFactory>(rightHandSideOperand);
break;
case Mov:
EmitCore<OpMov<byte>>();
EmitCore<OpMovFactory>();
break;
default:
throw new TamperCompilationException($"Invalid arithmetic operation {operation} in Atmosphere cheat");

View file

@ -37,7 +37,7 @@ namespace Ryujinx.HLE.HOS.Tamper.CodeEmitters
ulong immediate = InstructionHelper.GetImmediate(instruction, ValueImmediateIndex, ValueImmediateSize);
Value<ulong> rightHandSideValue = new(immediate);
void EmitCore<TOp>() where TOp : IOperation
void EmitCore<TOp>() where TOp : IOperationFactory
{
InstructionHelper.Emit<TOp>(operationWidth, context, register, register, rightHandSideValue);
}
@ -45,19 +45,19 @@ namespace Ryujinx.HLE.HOS.Tamper.CodeEmitters
switch (operation)
{
case Add:
EmitCore<OpAdd<byte>>();
EmitCore<OpAddFactory>();
break;
case Sub:
EmitCore<OpAdd<byte>>();
EmitCore<OpAddFactory>();
break;
case Mul:
EmitCore<OpMul<byte>>();
EmitCore<OpMulFactory>();
break;
case Lsh:
EmitCore<OpLsh<byte>>();
EmitCore<OpLshFactory>();
break;
case Rsh:
EmitCore<OpRsh<byte>>();
EmitCore<OpRshFactory>();
break;
default:
throw new TamperCompilationException($"Invalid arithmetic operation {operation} in Atmosphere cheat");

View file

@ -53,7 +53,7 @@ namespace Ryujinx.HLE.HOS.Tamper.CodeEmitters
throw new TamperCompilationException($"Invalid source mode {useDestinationAsSourceIndex} in Atmosphere cheat");
}
InstructionHelper.Emit<OpMov<byte>>(operationWidth, context, destinationRegister, sourceMemory, null);
InstructionHelper.Emit<OpMovFactory>(operationWidth, context, destinationRegister, sourceMemory, null);
}
}
}

View file

@ -37,7 +37,7 @@ namespace Ryujinx.HLE.HOS.Tamper.CodeEmitters
ulong valueImmediate = InstructionHelper.GetImmediate(instruction, ValueImmediateIndex, valueImmediateSize);
Value<ulong> storeValue = new(valueImmediate);
InstructionHelper.Emit<OpMov<byte>>(operationWidth, context, dstMem, storeValue, null);
InstructionHelper.Emit<OpMovFactory>(operationWidth, context, dstMem, storeValue, null);
}
}
}

View file

@ -51,7 +51,7 @@ namespace Ryujinx.HLE.HOS.Tamper.CodeEmitters
throw new TamperCompilationException($"Invalid offset mode {useOffsetRegister} in Atmosphere cheat");
}
InstructionHelper.Emit<OpMov<byte>>(operationWidth, context, destinationMemory, storeValue, null);
InstructionHelper.Emit<OpMovFactory>(operationWidth, context, destinationMemory, storeValue, null);
switch (incrementAddressRegister)
{

View file

@ -79,7 +79,7 @@ namespace Ryujinx.HLE.HOS.Tamper.CodeEmitters
throw new TamperCompilationException($"Invalid offset type {offsetType} in Atmosphere cheat");
}
InstructionHelper.Emit<OpMov<byte>>(operationWidth, context, destinationMemory, sourceRegister, null);
InstructionHelper.Emit<OpMovFactory>(operationWidth, context, destinationMemory, sourceRegister, null);
switch (incrementAddressRegister)
{

View file

@ -3,6 +3,13 @@ using System.Numerics;
namespace Ryujinx.HLE.HOS.Tamper.Conditions
{
sealed class CondEQFactory : IConditionFactory
{
private CondEQFactory() { }
public static ICondition CreateFor<T>(IOperand lhs, IOperand rhs) where T : unmanaged, INumber<T>
=> new CondEQ<T>(lhs, rhs);
}
class CondEQ<T> : ICondition where T : unmanaged, INumber<T>
{
private readonly IOperand _lhs;
@ -18,8 +25,5 @@ namespace Ryujinx.HLE.HOS.Tamper.Conditions
{
return _lhs.Get<T>() == _rhs.Get<T>();
}
public static ICondition CreateFor<T1>(IOperand lhs, IOperand rhs) where T1 : INumber<T1>
=> new CondEQ<T>(lhs, rhs);
}
}

View file

@ -3,6 +3,13 @@ using System.Numerics;
namespace Ryujinx.HLE.HOS.Tamper.Conditions
{
sealed class CondGEFactory : IConditionFactory
{
private CondGEFactory() { }
public static ICondition CreateFor<T>(IOperand lhs, IOperand rhs) where T : unmanaged, INumber<T>
=> new CondGE<T>(lhs, rhs);
}
class CondGE<T> : ICondition where T : unmanaged, INumber<T>
{
private readonly IOperand _lhs;
@ -18,8 +25,5 @@ namespace Ryujinx.HLE.HOS.Tamper.Conditions
{
return _lhs.Get<T>() >= _rhs.Get<T>();
}
public static ICondition CreateFor<T1>(IOperand lhs, IOperand rhs) where T1 : INumber<T1>
=> new CondGE<T>(lhs, rhs);
}
}

View file

@ -3,6 +3,13 @@ using System.Numerics;
namespace Ryujinx.HLE.HOS.Tamper.Conditions
{
sealed class CondGTFactory : IConditionFactory
{
private CondGTFactory() { }
public static ICondition CreateFor<T>(IOperand lhs, IOperand rhs) where T : unmanaged, INumber<T>
=> new CondGT<T>(lhs, rhs);
}
class CondGT<T> : ICondition where T : unmanaged, INumber<T>
{
private readonly IOperand _lhs;
@ -18,8 +25,5 @@ namespace Ryujinx.HLE.HOS.Tamper.Conditions
{
return _lhs.Get<T>() > _rhs.Get<T>();
}
public static ICondition CreateFor<T1>(IOperand lhs, IOperand rhs) where T1 : INumber<T1>
=> new CondGT<T>(lhs, rhs);
}
}

View file

@ -3,6 +3,13 @@ using System.Numerics;
namespace Ryujinx.HLE.HOS.Tamper.Conditions
{
sealed class CondLEFactory : IConditionFactory
{
private CondLEFactory() { }
public static ICondition CreateFor<T>(IOperand lhs, IOperand rhs) where T : unmanaged, INumber<T>
=> new CondLE<T>(lhs, rhs);
}
class CondLE<T> : ICondition where T : unmanaged, INumber<T>
{
private readonly IOperand _lhs;
@ -18,8 +25,5 @@ namespace Ryujinx.HLE.HOS.Tamper.Conditions
{
return _lhs.Get<T>() <= _rhs.Get<T>();
}
public static ICondition CreateFor<T1>(IOperand lhs, IOperand rhs) where T1 : INumber<T1>
=> new CondLE<T>(lhs, rhs);
}
}

View file

@ -3,6 +3,13 @@ using System.Numerics;
namespace Ryujinx.HLE.HOS.Tamper.Conditions
{
sealed class CondLTFactory : IConditionFactory
{
private CondLTFactory() { }
public static ICondition CreateFor<T>(IOperand lhs, IOperand rhs) where T : unmanaged, INumber<T>
=> new CondLT<T>(lhs, rhs);
}
class CondLT<T> : ICondition where T : unmanaged, INumber<T>
{
private readonly IOperand _lhs;

View file

@ -3,6 +3,13 @@ using System.Numerics;
namespace Ryujinx.HLE.HOS.Tamper.Conditions
{
sealed class CondNEFactory : IConditionFactory
{
private CondNEFactory() { }
public static ICondition CreateFor<T>(IOperand lhs, IOperand rhs) where T : unmanaged, INumber<T>
=> new CondNE<T>(lhs, rhs);
}
class CondNE<T> : ICondition where T : unmanaged, INumber<T>
{
private readonly IOperand _lhs;

View file

@ -1,13 +1,7 @@
using Ryujinx.HLE.HOS.Tamper.Operations;
using System;
using System.Numerics;
namespace Ryujinx.HLE.HOS.Tamper.Conditions
{
interface ICondition
{
bool Evaluate();
static virtual ICondition CreateFor<T>(IOperand lhs, IOperand rhs) where T : INumber<T> => throw new NotImplementedException();
}
}

View file

@ -0,0 +1,10 @@
using Ryujinx.HLE.HOS.Tamper.Operations;
using System.Numerics;
namespace Ryujinx.HLE.HOS.Tamper.Conditions
{
interface IConditionFactory
{
static abstract ICondition CreateFor<T>(IOperand lhs, IOperand rhs) where T : unmanaged, INumber<T>;
}
}

View file

@ -15,14 +15,14 @@ namespace Ryujinx.HLE.HOS.Tamper
context.CurrentOperations.Add(operation);
}
public static void Emit<TOp>(byte width, CompilationContext context, IOperand destination, IOperand lhs, IOperand rhs) where TOp : IOperation
public static void Emit<TOp>(byte width, CompilationContext context, IOperand destination, IOperand lhs, IOperand rhs) where TOp : IOperationFactory
{
Emit(Create<TOp>(width, destination, lhs, rhs), context);
}
public static ICondition CreateCondition(Comparison comparison, byte width, IOperand lhs, IOperand rhs)
{
ICondition CreateCore<TOp>() where TOp : ICondition
ICondition CreateCore<TOp>() where TOp : IConditionFactory
{
return width switch
{
@ -36,17 +36,17 @@ namespace Ryujinx.HLE.HOS.Tamper
return comparison switch
{
Comparison.Greater => CreateCore<CondGT<byte>>(),
Comparison.GreaterOrEqual => CreateCore<CondGE<byte>>(),
Comparison.Less => CreateCore<CondLT<byte>>(),
Comparison.LessOrEqual => CreateCore<CondLE<byte>>(),
Comparison.Equal => CreateCore<CondEQ<byte>>(),
Comparison.NotEqual => CreateCore<CondNE<byte>>(),
Comparison.Greater => CreateCore<CondGTFactory>(),
Comparison.GreaterOrEqual => CreateCore<CondGEFactory>(),
Comparison.Less => CreateCore<CondLTFactory>(),
Comparison.LessOrEqual => CreateCore<CondLEFactory>(),
Comparison.Equal => CreateCore<CondEQFactory>(),
Comparison.NotEqual => CreateCore<CondNEFactory>(),
_ => throw new TamperCompilationException($"Invalid comparison {comparison} in Atmosphere cheat"),
};
}
public static IOperation Create<TOp>(byte width, IOperand destination, IOperand lhs, IOperand rhs) where TOp : IOperation
public static IOperation Create<TOp>(byte width, IOperand destination, IOperand lhs, IOperand rhs) where TOp : IOperationFactory
{
return width switch
{

View file

@ -6,8 +6,5 @@ namespace Ryujinx.HLE.HOS.Tamper.Operations
interface IOperation
{
void Execute();
static virtual IOperation CreateFor<T>(IOperand destination, IOperand lhs, IOperand rhs) where T : unmanaged, IBinaryInteger<T>
=> throw new NotImplementedException();
}
}

View file

@ -0,0 +1,10 @@
using System;
using System.Numerics;
namespace Ryujinx.HLE.HOS.Tamper.Operations
{
interface IOperationFactory
{
static abstract IOperation CreateFor<T>(IOperand destination, IOperand lhs, IOperand rhs) where T : unmanaged, IBinaryInteger<T>;
}
}

View file

@ -2,6 +2,13 @@ using System.Numerics;
namespace Ryujinx.HLE.HOS.Tamper.Operations
{
sealed class OpAddFactory : IOperationFactory
{
private OpAddFactory() { }
public static IOperation CreateFor<T>(IOperand destination, IOperand lhs, IOperand rhs) where T : unmanaged, IBinaryInteger<T>
=> new OpAdd<T>(destination, lhs, rhs);
}
class OpAdd<T> : IOperation where T : unmanaged, INumber<T>
{
readonly IOperand _destination;
@ -19,8 +26,5 @@ namespace Ryujinx.HLE.HOS.Tamper.Operations
{
_destination.Set(_lhs.Get<T>() + _rhs.Get<T>());
}
public static IOperation CreateFor<T1>(IOperand destination, IOperand lhs, IOperand rhs) where T1 : unmanaged, IBinaryInteger<T1>
=> new OpAdd<T1>(destination, lhs, rhs);
}
}

View file

@ -2,6 +2,13 @@ using System.Numerics;
namespace Ryujinx.HLE.HOS.Tamper.Operations
{
sealed class OpAndFactory : IOperationFactory
{
private OpAndFactory() { }
public static IOperation CreateFor<T>(IOperand destination, IOperand lhs, IOperand rhs) where T : unmanaged, IBinaryInteger<T>
=> new OpAnd<T>(destination, lhs, rhs);
}
class OpAnd<T> : IOperation where T : unmanaged, IBinaryNumber<T>
{
readonly IOperand _destination;
@ -19,8 +26,5 @@ namespace Ryujinx.HLE.HOS.Tamper.Operations
{
_destination.Set(_lhs.Get<T>() & _rhs.Get<T>());
}
public static IOperation CreateFor<T1>(IOperand destination, IOperand lhs, IOperand rhs) where T1 : unmanaged, IBinaryInteger<T1>
=> new OpAnd<T1>(destination, lhs, rhs);
}
}

View file

@ -2,6 +2,13 @@ using System.Numerics;
namespace Ryujinx.HLE.HOS.Tamper.Operations
{
sealed class OpLshFactory : IOperationFactory
{
private OpLshFactory() { }
public static IOperation CreateFor<T>(IOperand destination, IOperand lhs, IOperand rhs) where T : unmanaged, IBinaryInteger<T>
=> new OpLsh<T>(destination, lhs, rhs);
}
class OpLsh<T> : IOperation where T : unmanaged, IBinaryInteger<T>
{
readonly IOperand _destination;
@ -19,8 +26,5 @@ namespace Ryujinx.HLE.HOS.Tamper.Operations
{
_destination.Set(_lhs.Get<T>() << int.CreateTruncating(_rhs.Get<T>()));
}
public static IOperation CreateFor<T1>(IOperand destination, IOperand lhs, IOperand rhs) where T1 : unmanaged, IBinaryInteger<T1>
=> new OpLsh<T1>(destination, lhs, rhs);
}
}

View file

@ -2,6 +2,13 @@ using System.Numerics;
namespace Ryujinx.HLE.HOS.Tamper.Operations
{
sealed class OpMovFactory : IOperationFactory
{
private OpMovFactory() { }
public static IOperation CreateFor<T>(IOperand destination, IOperand lhs, IOperand rhs) where T : unmanaged, IBinaryInteger<T>
=> new OpMov<T>(destination, lhs);
}
class OpMov<T> : IOperation where T : unmanaged, INumber<T>
{
readonly IOperand _destination;
@ -17,8 +24,5 @@ namespace Ryujinx.HLE.HOS.Tamper.Operations
{
_destination.Set(_source.Get<T>());
}
public static IOperation CreateFor<T1>(IOperand destination, IOperand lhs, IOperand rhs) where T1 : unmanaged, IBinaryInteger<T1>
=> new OpMov<T1>(destination, lhs);
}
}

View file

@ -2,6 +2,13 @@ using System.Numerics;
namespace Ryujinx.HLE.HOS.Tamper.Operations
{
sealed class OpMulFactory : IOperationFactory
{
private OpMulFactory() { }
public static IOperation CreateFor<T>(IOperand destination, IOperand lhs, IOperand rhs) where T : unmanaged, IBinaryInteger<T>
=> new OpMul<T>(destination, lhs, rhs);
}
class OpMul<T> : IOperation where T : unmanaged, INumber<T>
{
readonly IOperand _destination;
@ -19,8 +26,5 @@ namespace Ryujinx.HLE.HOS.Tamper.Operations
{
_destination.Set(_lhs.Get<T>() * _rhs.Get<T>());
}
public static IOperation CreateFor<T1>(IOperand destination, IOperand lhs, IOperand rhs) where T1 : unmanaged, IBinaryInteger<T1>
=> new OpMul<T1>(destination, lhs, rhs);
}
}

View file

@ -2,6 +2,13 @@ using System.Numerics;
namespace Ryujinx.HLE.HOS.Tamper.Operations
{
sealed class OpNotFactory : IOperationFactory
{
private OpNotFactory() { }
public static IOperation CreateFor<T>(IOperand destination, IOperand lhs, IOperand rhs) where T : unmanaged, IBinaryInteger<T>
=> new OpNot<T>(destination, lhs);
}
class OpNot<T> : IOperation where T : unmanaged, IBinaryNumber<T>
{
readonly IOperand _destination;
@ -17,8 +24,5 @@ namespace Ryujinx.HLE.HOS.Tamper.Operations
{
_destination.Set(~_source.Get<T>());
}
public static IOperation CreateFor<T1>(IOperand destination, IOperand lhs, IOperand rhs) where T1 : unmanaged, IBinaryInteger<T1>
=> new OpNot<T1>(destination, lhs);
}
}

View file

@ -2,6 +2,13 @@ using System.Numerics;
namespace Ryujinx.HLE.HOS.Tamper.Operations
{
sealed class OpOrFactory : IOperationFactory
{
private OpOrFactory() { }
public static IOperation CreateFor<T>(IOperand destination, IOperand lhs, IOperand rhs) where T : unmanaged, IBinaryInteger<T>
=> new OpOr<T>(destination, lhs, rhs);
}
class OpOr<T> : IOperation where T : unmanaged, IBinaryNumber<T>
{
readonly IOperand _destination;
@ -19,8 +26,5 @@ namespace Ryujinx.HLE.HOS.Tamper.Operations
{
_destination.Set(_lhs.Get<T>() | _rhs.Get<T>());
}
public static IOperation CreateFor<T1>(IOperand destination, IOperand lhs, IOperand rhs) where T1 : unmanaged, IBinaryInteger<T1>
=> new OpOr<T1>(destination, lhs, rhs);
}
}

View file

@ -2,6 +2,13 @@ using System.Numerics;
namespace Ryujinx.HLE.HOS.Tamper.Operations
{
sealed class OpRshFactory : IOperationFactory
{
private OpRshFactory() { }
public static IOperation CreateFor<T>(IOperand destination, IOperand lhs, IOperand rhs) where T : unmanaged, IBinaryInteger<T>
=> new OpRsh<T>(destination, lhs, rhs);
}
class OpRsh<T> : IOperation where T : unmanaged, IBinaryInteger<T>
{
readonly IOperand _destination;
@ -19,8 +26,5 @@ namespace Ryujinx.HLE.HOS.Tamper.Operations
{
_destination.Set(_lhs.Get<T>() >> int.CreateTruncating(_rhs.Get<T>()));
}
public static IOperation CreateFor<T1>(IOperand destination, IOperand lhs, IOperand rhs) where T1 : unmanaged, IBinaryInteger<T1>
=> new OpRsh<T1>(destination, lhs, rhs);
}
}

View file

@ -2,6 +2,13 @@ using System.Numerics;
namespace Ryujinx.HLE.HOS.Tamper.Operations
{
sealed class OpSubFactory : IOperationFactory
{
private OpSubFactory() { }
public static IOperation CreateFor<T>(IOperand destination, IOperand lhs, IOperand rhs) where T : unmanaged, IBinaryInteger<T>
=> new OpSub<T>(destination, lhs, rhs);
}
class OpSub<T> : IOperation where T : unmanaged, INumber<T>
{
readonly IOperand _destination;
@ -19,8 +26,5 @@ namespace Ryujinx.HLE.HOS.Tamper.Operations
{
_destination.Set(_lhs.Get<T>() - _rhs.Get<T>());
}
public static IOperation CreateFor<T1>(IOperand destination, IOperand lhs, IOperand rhs) where T1 : unmanaged, IBinaryInteger<T1>
=> new OpSub<T1>(destination, lhs, rhs);
}
}

View file

@ -2,6 +2,13 @@ using System.Numerics;
namespace Ryujinx.HLE.HOS.Tamper.Operations
{
sealed class OpXorFactory : IOperationFactory
{
private OpXorFactory() { }
public static IOperation CreateFor<T>(IOperand destination, IOperand lhs, IOperand rhs) where T : unmanaged, IBinaryInteger<T>
=> new OpXor<T>(destination, lhs, rhs);
}
class OpXor<T> : IOperation where T : unmanaged, IBinaryNumber<T>
{
readonly IOperand _destination;
@ -19,8 +26,5 @@ namespace Ryujinx.HLE.HOS.Tamper.Operations
{
_destination.Set(_lhs.Get<T>() ^ _rhs.Get<T>());
}
public static IOperation CreateFor<T1>(IOperand destination, IOperand lhs, IOperand rhs) where T1 : unmanaged, IBinaryInteger<T1>
=> new OpXor<T1>(destination, lhs, rhs);
}
}