1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
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);
}
}
}
|