Implement a new JIT for Arm devices (#6057)
* Implement a new JIT for Arm devices * Auto-format * Make a lot of Assembler members read-only * More read-only * Fix more warnings * ObjectDisposedException.ThrowIf * New JIT cache for platforms that enforce W^X, currently unused * Remove unused using * Fix assert * Pass memory manager type around * Safe memory manager mode support + other improvements * Actual safe memory manager mode masking support * PR feedback
This commit is contained in:
178
src/Ryujinx.Cpu/LightningJit/Arm32/Target/Arm64/InstEmitHalve.cs
Normal file
178
src/Ryujinx.Cpu/LightningJit/Arm32/Target/Arm64/InstEmitHalve.cs
Normal file
@@ -0,0 +1,178 @@
|
||||
using Ryujinx.Cpu.LightningJit.CodeGen;
|
||||
|
||||
namespace Ryujinx.Cpu.LightningJit.Arm32.Target.Arm64
|
||||
{
|
||||
static class InstEmitHalve
|
||||
{
|
||||
public static void Shadd16(CodeGenContext context, uint rd, uint rn, uint rm)
|
||||
{
|
||||
EmitHadd(context, rd, rn, rm, 0x7fff7fff, unsigned: false);
|
||||
}
|
||||
|
||||
public static void Shadd8(CodeGenContext context, uint rd, uint rn, uint rm)
|
||||
{
|
||||
EmitHadd(context, rd, rn, rm, 0x7f7f7f7f, unsigned: false);
|
||||
}
|
||||
|
||||
public static void Shsub16(CodeGenContext context, uint rd, uint rn, uint rm)
|
||||
{
|
||||
EmitHsub(context, rd, rn, rm, 0x7fff7fff, unsigned: false);
|
||||
}
|
||||
|
||||
public static void Shsub8(CodeGenContext context, uint rd, uint rn, uint rm)
|
||||
{
|
||||
EmitHsub(context, rd, rn, rm, 0x7f7f7f7f, unsigned: false);
|
||||
}
|
||||
|
||||
public static void Shasx(CodeGenContext context, uint rd, uint rn, uint rm)
|
||||
{
|
||||
InstEmitCommon.EmitSigned16BitXPair(context, rd, rn, rm, (d, n, m, e) =>
|
||||
{
|
||||
if (e == 0)
|
||||
{
|
||||
context.Arm64Assembler.Sub(d, n, m);
|
||||
}
|
||||
else
|
||||
{
|
||||
context.Arm64Assembler.Add(d, n, m);
|
||||
}
|
||||
|
||||
context.Arm64Assembler.Lsr(d, d, InstEmitCommon.Const(1));
|
||||
});
|
||||
}
|
||||
|
||||
public static void Shsax(CodeGenContext context, uint rd, uint rn, uint rm)
|
||||
{
|
||||
InstEmitCommon.EmitSigned16BitXPair(context, rd, rn, rm, (d, n, m, e) =>
|
||||
{
|
||||
if (e == 0)
|
||||
{
|
||||
context.Arm64Assembler.Add(d, n, m);
|
||||
}
|
||||
else
|
||||
{
|
||||
context.Arm64Assembler.Sub(d, n, m);
|
||||
}
|
||||
|
||||
context.Arm64Assembler.Lsr(d, d, InstEmitCommon.Const(1));
|
||||
});
|
||||
}
|
||||
|
||||
public static void Uhadd16(CodeGenContext context, uint rd, uint rn, uint rm)
|
||||
{
|
||||
EmitHadd(context, rd, rn, rm, 0x7fff7fff, unsigned: true);
|
||||
}
|
||||
|
||||
public static void Uhadd8(CodeGenContext context, uint rd, uint rn, uint rm)
|
||||
{
|
||||
EmitHadd(context, rd, rn, rm, 0x7f7f7f7f, unsigned: true);
|
||||
}
|
||||
|
||||
public static void Uhasx(CodeGenContext context, uint rd, uint rn, uint rm)
|
||||
{
|
||||
InstEmitCommon.EmitUnsigned16BitXPair(context, rd, rn, rm, (d, n, m, e) =>
|
||||
{
|
||||
if (e == 0)
|
||||
{
|
||||
context.Arm64Assembler.Sub(d, n, m);
|
||||
}
|
||||
else
|
||||
{
|
||||
context.Arm64Assembler.Add(d, n, m);
|
||||
}
|
||||
|
||||
context.Arm64Assembler.Lsr(d, d, InstEmitCommon.Const(1));
|
||||
});
|
||||
}
|
||||
|
||||
public static void Uhsax(CodeGenContext context, uint rd, uint rn, uint rm)
|
||||
{
|
||||
InstEmitCommon.EmitUnsigned16BitXPair(context, rd, rn, rm, (d, n, m, e) =>
|
||||
{
|
||||
if (e == 0)
|
||||
{
|
||||
context.Arm64Assembler.Add(d, n, m);
|
||||
}
|
||||
else
|
||||
{
|
||||
context.Arm64Assembler.Sub(d, n, m);
|
||||
}
|
||||
|
||||
context.Arm64Assembler.Lsr(d, d, InstEmitCommon.Const(1));
|
||||
});
|
||||
}
|
||||
|
||||
public static void Uhsub16(CodeGenContext context, uint rd, uint rn, uint rm)
|
||||
{
|
||||
EmitHsub(context, rd, rn, rm, 0x7fff7fff, unsigned: true);
|
||||
}
|
||||
|
||||
public static void Uhsub8(CodeGenContext context, uint rd, uint rn, uint rm)
|
||||
{
|
||||
EmitHsub(context, rd, rn, rm, 0x7f7f7f7f, unsigned: true);
|
||||
}
|
||||
|
||||
private static void EmitHadd(CodeGenContext context, uint rd, uint rn, uint rm, int mask, bool unsigned)
|
||||
{
|
||||
Operand rdOperand = InstEmitCommon.GetOutputGpr(context, rd);
|
||||
Operand rnOperand = InstEmitCommon.GetInputGpr(context, rn);
|
||||
Operand rmOperand = InstEmitCommon.GetInputGpr(context, rm);
|
||||
|
||||
using ScopedRegister res = context.RegisterAllocator.AllocateTempGprRegisterScoped();
|
||||
using ScopedRegister carry = context.RegisterAllocator.AllocateTempGprRegisterScoped();
|
||||
|
||||
// This relies on the equality x+y == ((x&y) << 1) + (x^y).
|
||||
// Note that x^y always contains the LSB of the result.
|
||||
// Since we want to calculate (x+y)/2, we can instead calculate (x&y) + ((x^y)>>1).
|
||||
// We mask by 0x7F/0x7FFF to remove the LSB so that it doesn't leak into the field below.
|
||||
|
||||
context.Arm64Assembler.And(res.Operand, rmOperand, rnOperand);
|
||||
context.Arm64Assembler.Eor(carry.Operand, rmOperand, rnOperand);
|
||||
context.Arm64Assembler.Lsr(rdOperand, carry.Operand, InstEmitCommon.Const(1));
|
||||
context.Arm64Assembler.And(rdOperand, rdOperand, InstEmitCommon.Const(mask));
|
||||
context.Arm64Assembler.Add(rdOperand, rdOperand, res.Operand);
|
||||
|
||||
if (!unsigned)
|
||||
{
|
||||
// Propagates the sign bit from (x^y)>>1 upwards by one.
|
||||
context.Arm64Assembler.And(carry.Operand, carry.Operand, InstEmitCommon.Const(~mask));
|
||||
context.Arm64Assembler.Eor(rdOperand, rdOperand, carry.Operand);
|
||||
}
|
||||
}
|
||||
|
||||
private static void EmitHsub(CodeGenContext context, uint rd, uint rn, uint rm, int mask, bool unsigned)
|
||||
{
|
||||
Operand rdOperand = InstEmitCommon.GetOutputGpr(context, rd);
|
||||
Operand rnOperand = InstEmitCommon.GetInputGpr(context, rn);
|
||||
Operand rmOperand = InstEmitCommon.GetInputGpr(context, rm);
|
||||
|
||||
using ScopedRegister carry = context.RegisterAllocator.AllocateTempGprRegisterScoped();
|
||||
using ScopedRegister left = context.RegisterAllocator.AllocateTempGprRegisterScoped();
|
||||
using ScopedRegister right = context.RegisterAllocator.AllocateTempGprRegisterScoped();
|
||||
|
||||
// This relies on the equality x-y == (x^y) - (((x^y)&y) << 1).
|
||||
// Note that x^y always contains the LSB of the result.
|
||||
// Since we want to calculate (x+y)/2, we can instead calculate ((x^y)>>1) - ((x^y)&y).
|
||||
|
||||
context.Arm64Assembler.Eor(carry.Operand, rmOperand, rnOperand);
|
||||
context.Arm64Assembler.Lsr(left.Operand, carry.Operand, InstEmitCommon.Const(1));
|
||||
context.Arm64Assembler.And(right.Operand, carry.Operand, rmOperand);
|
||||
|
||||
// We must now perform a partitioned subtraction.
|
||||
// We can do this because minuend contains 7/15 bit fields.
|
||||
// We use the extra bit in minuend as a bit to borrow from; we set this bit.
|
||||
// We invert this bit at the end as this tells us if that bit was borrowed from.
|
||||
|
||||
context.Arm64Assembler.Orr(rdOperand, left.Operand, InstEmitCommon.Const(~mask));
|
||||
context.Arm64Assembler.Sub(rdOperand, rdOperand, right.Operand);
|
||||
context.Arm64Assembler.Eor(rdOperand, rdOperand, InstEmitCommon.Const(~mask));
|
||||
|
||||
if (!unsigned)
|
||||
{
|
||||
// We then sign extend the result into this bit.
|
||||
context.Arm64Assembler.And(carry.Operand, carry.Operand, InstEmitCommon.Const(~mask));
|
||||
context.Arm64Assembler.Eor(rdOperand, rdOperand, carry.Operand);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user