aboutsummaryrefslogtreecommitdiff
path: root/src/Ryujinx.Cpu/LightningJit/Arm32/Target/Arm64/InstEmitAbsDiff.cs
diff options
context:
space:
mode:
Diffstat (limited to 'src/Ryujinx.Cpu/LightningJit/Arm32/Target/Arm64/InstEmitAbsDiff.cs')
-rw-r--r--src/Ryujinx.Cpu/LightningJit/Arm32/Target/Arm64/InstEmitAbsDiff.cs87
1 files changed, 87 insertions, 0 deletions
diff --git a/src/Ryujinx.Cpu/LightningJit/Arm32/Target/Arm64/InstEmitAbsDiff.cs b/src/Ryujinx.Cpu/LightningJit/Arm32/Target/Arm64/InstEmitAbsDiff.cs
new file mode 100644
index 00000000..f8100503
--- /dev/null
+++ b/src/Ryujinx.Cpu/LightningJit/Arm32/Target/Arm64/InstEmitAbsDiff.cs
@@ -0,0 +1,87 @@
+using Ryujinx.Cpu.LightningJit.CodeGen;
+using Ryujinx.Cpu.LightningJit.CodeGen.Arm64;
+
+namespace Ryujinx.Cpu.LightningJit.Arm32.Target.Arm64
+{
+ static class InstEmitAbsDiff
+ {
+ public static void Usad8(CodeGenContext context, uint rd, uint rn, uint rm)
+ {
+ using ScopedRegister tempD = context.RegisterAllocator.AllocateTempGprRegisterScoped();
+ using ScopedRegister tempD2 = context.RegisterAllocator.AllocateTempGprRegisterScoped();
+ using ScopedRegister tempN = context.RegisterAllocator.AllocateTempGprRegisterScoped();
+ using ScopedRegister tempM = context.RegisterAllocator.AllocateTempGprRegisterScoped();
+
+ Operand rdOperand = InstEmitCommon.GetOutputGpr(context, rd);
+ Operand rnOperand = InstEmitCommon.GetInputGpr(context, rn);
+ Operand rmOperand = InstEmitCommon.GetInputGpr(context, rm);
+
+ for (int b = 0; b < 4; b++)
+ {
+ context.Arm64Assembler.Ubfx(tempN.Operand, rnOperand, b * 8, 8);
+ context.Arm64Assembler.Ubfx(tempM.Operand, rmOperand, b * 8, 8);
+
+ Operand dest = b == 0 ? tempD.Operand : tempD2.Operand;
+
+ context.Arm64Assembler.Sub(dest, tempN.Operand, tempM.Operand);
+
+ EmitAbs(context, dest);
+
+ if (b > 0)
+ {
+ if (b < 3)
+ {
+ context.Arm64Assembler.Add(tempD.Operand, tempD.Operand, dest);
+ }
+ else
+ {
+ context.Arm64Assembler.Add(rdOperand, tempD.Operand, dest);
+ }
+ }
+ }
+ }
+
+ public static void Usada8(CodeGenContext context, uint rd, uint rn, uint rm, uint ra)
+ {
+ using ScopedRegister tempD = context.RegisterAllocator.AllocateTempGprRegisterScoped();
+ using ScopedRegister tempD2 = context.RegisterAllocator.AllocateTempGprRegisterScoped();
+ using ScopedRegister tempN = context.RegisterAllocator.AllocateTempGprRegisterScoped();
+ using ScopedRegister tempM = context.RegisterAllocator.AllocateTempGprRegisterScoped();
+
+ Operand rdOperand = InstEmitCommon.GetOutputGpr(context, rd);
+ Operand rnOperand = InstEmitCommon.GetInputGpr(context, rn);
+ Operand rmOperand = InstEmitCommon.GetInputGpr(context, rm);
+ Operand raOperand = InstEmitCommon.GetInputGpr(context, ra);
+
+ for (int b = 0; b < 4; b++)
+ {
+ context.Arm64Assembler.Ubfx(tempN.Operand, rnOperand, b * 8, 8);
+ context.Arm64Assembler.Ubfx(tempM.Operand, rmOperand, b * 8, 8);
+
+ Operand dest = b == 0 ? tempD.Operand : tempD2.Operand;
+
+ context.Arm64Assembler.Sub(dest, tempN.Operand, tempM.Operand);
+
+ EmitAbs(context, dest);
+
+ if (b > 0)
+ {
+ context.Arm64Assembler.Add(tempD.Operand, tempD.Operand, dest);
+ }
+ }
+
+ context.Arm64Assembler.Add(rdOperand, tempD.Operand, raOperand);
+ }
+
+ private static void EmitAbs(CodeGenContext context, Operand value)
+ {
+ using ScopedRegister tempRegister = context.RegisterAllocator.AllocateTempGprRegisterScoped();
+
+ // r = (value + ((int)value >> 31)) ^ ((int)value >> 31).
+ // Subtracts 1 and then inverts the value if the sign bit is set, same as a conditional negation.
+
+ context.Arm64Assembler.Add(tempRegister.Operand, value, value, ArmShiftType.Asr, 31);
+ context.Arm64Assembler.Eor(value, tempRegister.Operand, value, ArmShiftType.Asr, 31);
+ }
+ }
+}