forked from Mirror/Ryujinx
parent
ad84f3a7b3
commit
0915731a9d
17 changed files with 856 additions and 379 deletions
|
@ -103,6 +103,7 @@ namespace ARMeilleure.CodeGen.X86
|
||||||
Add(X86Instruction.Cvtsi2sd, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000f2a, InstructionFlags.Vex | InstructionFlags.PrefixF2));
|
Add(X86Instruction.Cvtsi2sd, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000f2a, InstructionFlags.Vex | InstructionFlags.PrefixF2));
|
||||||
Add(X86Instruction.Cvtsi2ss, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000f2a, InstructionFlags.Vex | InstructionFlags.PrefixF3));
|
Add(X86Instruction.Cvtsi2ss, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000f2a, InstructionFlags.Vex | InstructionFlags.PrefixF3));
|
||||||
Add(X86Instruction.Cvtss2sd, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000f5a, InstructionFlags.Vex | InstructionFlags.PrefixF3));
|
Add(X86Instruction.Cvtss2sd, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000f5a, InstructionFlags.Vex | InstructionFlags.PrefixF3));
|
||||||
|
Add(X86Instruction.Cvtss2si, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000f2d, InstructionFlags.Vex | InstructionFlags.PrefixF3));
|
||||||
Add(X86Instruction.Div, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x060000f7, InstructionFlags.None));
|
Add(X86Instruction.Div, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x060000f7, InstructionFlags.None));
|
||||||
Add(X86Instruction.Divpd, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000f5e, InstructionFlags.Vex | InstructionFlags.Prefix66));
|
Add(X86Instruction.Divpd, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000f5e, InstructionFlags.Vex | InstructionFlags.Prefix66));
|
||||||
Add(X86Instruction.Divps, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000f5e, InstructionFlags.Vex));
|
Add(X86Instruction.Divps, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000f5e, InstructionFlags.Vex));
|
||||||
|
@ -791,6 +792,16 @@ namespace ARMeilleure.CodeGen.X86
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void WriteInstruction(
|
||||||
|
X86Instruction inst,
|
||||||
|
Operand dest,
|
||||||
|
Operand src1,
|
||||||
|
Operand src2,
|
||||||
|
OperandType type)
|
||||||
|
{
|
||||||
|
WriteInstruction(dest, src1, src2, inst, type);
|
||||||
|
}
|
||||||
|
|
||||||
public void WriteInstruction(X86Instruction inst, Operand dest, Operand source, byte imm)
|
public void WriteInstruction(X86Instruction inst, Operand dest, Operand source, byte imm)
|
||||||
{
|
{
|
||||||
WriteInstruction(dest, null, source, inst);
|
WriteInstruction(dest, null, source, inst);
|
||||||
|
|
|
@ -269,11 +269,11 @@ namespace ARMeilleure.CodeGen.X86
|
||||||
{
|
{
|
||||||
if (dest.Type == OperandType.I32)
|
if (dest.Type == OperandType.I32)
|
||||||
{
|
{
|
||||||
context.Assembler.Movd(dest, source); // int _mm_cvtsi128_si32
|
context.Assembler.Movd(dest, source); // int _mm_cvtsi128_si32(__m128i a)
|
||||||
}
|
}
|
||||||
else /* if (dest.Type == OperandType.I64) */
|
else /* if (dest.Type == OperandType.I64) */
|
||||||
{
|
{
|
||||||
context.Assembler.Movq(dest, source); // __int64 _mm_cvtsi128_si64
|
context.Assembler.Movq(dest, source); // __int64 _mm_cvtsi128_si64(__m128i a)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -305,6 +305,26 @@ namespace ARMeilleure.CodeGen.X86
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
case IntrinsicType.BinaryGpr:
|
||||||
|
{
|
||||||
|
Operand dest = operation.Destination;
|
||||||
|
Operand src1 = operation.GetSource(0);
|
||||||
|
Operand src2 = operation.GetSource(1);
|
||||||
|
|
||||||
|
EnsureSameType(dest, src1);
|
||||||
|
|
||||||
|
if (!HardwareCapabilities.SupportsVexEncoding)
|
||||||
|
{
|
||||||
|
EnsureSameReg(dest, src1);
|
||||||
|
}
|
||||||
|
|
||||||
|
Debug.Assert(!dest.Type.IsInteger() && src2.Type.IsInteger());
|
||||||
|
|
||||||
|
context.Assembler.WriteInstruction(info.Inst, dest, src1, src2, src2.Type);
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
case IntrinsicType.BinaryImm:
|
case IntrinsicType.BinaryImm:
|
||||||
{
|
{
|
||||||
Operand dest = operation.Destination;
|
Operand dest = operation.Destination;
|
||||||
|
@ -1070,11 +1090,11 @@ namespace ARMeilleure.CodeGen.X86
|
||||||
|
|
||||||
if (source.Type == OperandType.I32)
|
if (source.Type == OperandType.I32)
|
||||||
{
|
{
|
||||||
context.Assembler.Movd(dest, source);
|
context.Assembler.Movd(dest, source); // (__m128i _mm_cvtsi32_si128(int a))
|
||||||
}
|
}
|
||||||
else /* if (source.Type == OperandType.I64) */
|
else /* if (source.Type == OperandType.I64) */
|
||||||
{
|
{
|
||||||
context.Assembler.Movq(dest, source);
|
context.Assembler.Movq(dest, source); // (__m128i _mm_cvtsi64_si128(__int64 a))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -41,8 +41,11 @@ namespace ARMeilleure.CodeGen.X86
|
||||||
Add(Intrinsic.X86Cvtps2pd, new IntrinsicInfo(X86Instruction.Cvtps2pd, IntrinsicType.Unary));
|
Add(Intrinsic.X86Cvtps2pd, new IntrinsicInfo(X86Instruction.Cvtps2pd, IntrinsicType.Unary));
|
||||||
Add(Intrinsic.X86Cvtsd2si, new IntrinsicInfo(X86Instruction.Cvtsd2si, IntrinsicType.UnaryToGpr));
|
Add(Intrinsic.X86Cvtsd2si, new IntrinsicInfo(X86Instruction.Cvtsd2si, IntrinsicType.UnaryToGpr));
|
||||||
Add(Intrinsic.X86Cvtsd2ss, new IntrinsicInfo(X86Instruction.Cvtsd2ss, IntrinsicType.Binary));
|
Add(Intrinsic.X86Cvtsd2ss, new IntrinsicInfo(X86Instruction.Cvtsd2ss, IntrinsicType.Binary));
|
||||||
|
Add(Intrinsic.X86Cvtsi2sd, new IntrinsicInfo(X86Instruction.Cvtsi2sd, IntrinsicType.BinaryGpr));
|
||||||
Add(Intrinsic.X86Cvtsi2si, new IntrinsicInfo(X86Instruction.Movd, IntrinsicType.UnaryToGpr));
|
Add(Intrinsic.X86Cvtsi2si, new IntrinsicInfo(X86Instruction.Movd, IntrinsicType.UnaryToGpr));
|
||||||
|
Add(Intrinsic.X86Cvtsi2ss, new IntrinsicInfo(X86Instruction.Cvtsi2ss, IntrinsicType.BinaryGpr));
|
||||||
Add(Intrinsic.X86Cvtss2sd, new IntrinsicInfo(X86Instruction.Cvtss2sd, IntrinsicType.Binary));
|
Add(Intrinsic.X86Cvtss2sd, new IntrinsicInfo(X86Instruction.Cvtss2sd, IntrinsicType.Binary));
|
||||||
|
Add(Intrinsic.X86Cvtss2si, new IntrinsicInfo(X86Instruction.Cvtss2si, IntrinsicType.UnaryToGpr));
|
||||||
Add(Intrinsic.X86Divpd, new IntrinsicInfo(X86Instruction.Divpd, IntrinsicType.Binary));
|
Add(Intrinsic.X86Divpd, new IntrinsicInfo(X86Instruction.Divpd, IntrinsicType.Binary));
|
||||||
Add(Intrinsic.X86Divps, new IntrinsicInfo(X86Instruction.Divps, IntrinsicType.Binary));
|
Add(Intrinsic.X86Divps, new IntrinsicInfo(X86Instruction.Divps, IntrinsicType.Binary));
|
||||||
Add(Intrinsic.X86Divsd, new IntrinsicInfo(X86Instruction.Divsd, IntrinsicType.Binary));
|
Add(Intrinsic.X86Divsd, new IntrinsicInfo(X86Instruction.Divsd, IntrinsicType.Binary));
|
||||||
|
|
|
@ -7,6 +7,7 @@ namespace ARMeilleure.CodeGen.X86
|
||||||
Unary,
|
Unary,
|
||||||
UnaryToGpr,
|
UnaryToGpr,
|
||||||
Binary,
|
Binary,
|
||||||
|
BinaryGpr,
|
||||||
BinaryImm,
|
BinaryImm,
|
||||||
Ternary,
|
Ternary,
|
||||||
TernaryImm
|
TernaryImm
|
||||||
|
|
|
@ -38,6 +38,7 @@ namespace ARMeilleure.CodeGen.X86
|
||||||
Cvtsi2sd,
|
Cvtsi2sd,
|
||||||
Cvtsi2ss,
|
Cvtsi2ss,
|
||||||
Cvtss2sd,
|
Cvtss2sd,
|
||||||
|
Cvtss2si,
|
||||||
Div,
|
Div,
|
||||||
Divpd,
|
Divpd,
|
||||||
Divps,
|
Divps,
|
||||||
|
|
|
@ -2,6 +2,7 @@ using ARMeilleure.Decoders;
|
||||||
using ARMeilleure.IntermediateRepresentation;
|
using ARMeilleure.IntermediateRepresentation;
|
||||||
using ARMeilleure.State;
|
using ARMeilleure.State;
|
||||||
using ARMeilleure.Translation;
|
using ARMeilleure.Translation;
|
||||||
|
using System.Diagnostics;
|
||||||
|
|
||||||
using static ARMeilleure.Instructions.InstEmitAluHelper;
|
using static ARMeilleure.Instructions.InstEmitAluHelper;
|
||||||
using static ARMeilleure.Instructions.InstEmitHelper;
|
using static ARMeilleure.Instructions.InstEmitHelper;
|
||||||
|
@ -265,16 +266,52 @@ namespace ARMeilleure.Instructions
|
||||||
|
|
||||||
if (op.RegisterSize == RegisterSize.Int32)
|
if (op.RegisterSize == RegisterSize.Int32)
|
||||||
{
|
{
|
||||||
d = context.Call(new _U32_U32(SoftFallback.ReverseBits32), n);
|
d = EmitReverseBits32Op(context, n);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
d = context.Call(new _U64_U64(SoftFallback.ReverseBits64), n);
|
d = EmitReverseBits64Op(context, n);
|
||||||
}
|
}
|
||||||
|
|
||||||
SetAluDOrZR(context, d);
|
SetAluDOrZR(context, d);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static Operand EmitReverseBits32Op(ArmEmitterContext context, Operand op)
|
||||||
|
{
|
||||||
|
Debug.Assert(op.Type == OperandType.I32);
|
||||||
|
|
||||||
|
Operand val = context.BitwiseOr(context.ShiftRightUI(context.BitwiseAnd(op, Const(0xaaaaaaaau)), Const(1)),
|
||||||
|
context.ShiftLeft (context.BitwiseAnd(op, Const(0x55555555u)), Const(1)));
|
||||||
|
|
||||||
|
val = context.BitwiseOr(context.ShiftRightUI(context.BitwiseAnd(val, Const(0xccccccccu)), Const(2)),
|
||||||
|
context.ShiftLeft (context.BitwiseAnd(val, Const(0x33333333u)), Const(2)));
|
||||||
|
val = context.BitwiseOr(context.ShiftRightUI(context.BitwiseAnd(val, Const(0xf0f0f0f0u)), Const(4)),
|
||||||
|
context.ShiftLeft (context.BitwiseAnd(val, Const(0x0f0f0f0fu)), Const(4)));
|
||||||
|
val = context.BitwiseOr(context.ShiftRightUI(context.BitwiseAnd(val, Const(0xff00ff00u)), Const(8)),
|
||||||
|
context.ShiftLeft (context.BitwiseAnd(val, Const(0x00ff00ffu)), Const(8)));
|
||||||
|
|
||||||
|
return context.BitwiseOr(context.ShiftRightUI(val, Const(16)), context.ShiftLeft(val, Const(16)));
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Operand EmitReverseBits64Op(ArmEmitterContext context, Operand op)
|
||||||
|
{
|
||||||
|
Debug.Assert(op.Type == OperandType.I64);
|
||||||
|
|
||||||
|
Operand val = context.BitwiseOr(context.ShiftRightUI(context.BitwiseAnd(op, Const(0xaaaaaaaaaaaaaaaaul)), Const(1)),
|
||||||
|
context.ShiftLeft (context.BitwiseAnd(op, Const(0x5555555555555555ul)), Const(1)));
|
||||||
|
|
||||||
|
val = context.BitwiseOr(context.ShiftRightUI(context.BitwiseAnd(val, Const(0xccccccccccccccccul)), Const(2)),
|
||||||
|
context.ShiftLeft (context.BitwiseAnd(val, Const(0x3333333333333333ul)), Const(2)));
|
||||||
|
val = context.BitwiseOr(context.ShiftRightUI(context.BitwiseAnd(val, Const(0xf0f0f0f0f0f0f0f0ul)), Const(4)),
|
||||||
|
context.ShiftLeft (context.BitwiseAnd(val, Const(0x0f0f0f0f0f0f0f0ful)), Const(4)));
|
||||||
|
val = context.BitwiseOr(context.ShiftRightUI(context.BitwiseAnd(val, Const(0xff00ff00ff00ff00ul)), Const(8)),
|
||||||
|
context.ShiftLeft (context.BitwiseAnd(val, Const(0x00ff00ff00ff00fful)), Const(8)));
|
||||||
|
val = context.BitwiseOr(context.ShiftRightUI(context.BitwiseAnd(val, Const(0xffff0000ffff0000ul)), Const(16)),
|
||||||
|
context.ShiftLeft (context.BitwiseAnd(val, Const(0x0000ffff0000fffful)), Const(16)));
|
||||||
|
|
||||||
|
return context.BitwiseOr(context.ShiftRightUI(val, Const(32)), context.ShiftLeft(val, Const(32)));
|
||||||
|
}
|
||||||
|
|
||||||
public static void Rev16(ArmEmitterContext context)
|
public static void Rev16(ArmEmitterContext context)
|
||||||
{
|
{
|
||||||
OpCodeAlu op = (OpCodeAlu)context.CurrOp;
|
OpCodeAlu op = (OpCodeAlu)context.CurrOp;
|
||||||
|
@ -284,32 +321,60 @@ namespace ARMeilleure.Instructions
|
||||||
|
|
||||||
if (op.RegisterSize == RegisterSize.Int32)
|
if (op.RegisterSize == RegisterSize.Int32)
|
||||||
{
|
{
|
||||||
d = context.Call(new _U32_U32(SoftFallback.ReverseBytes16_32), n);
|
d = EmitReverseBytes16_32Op(context, n);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
d = context.Call(new _U64_U64(SoftFallback.ReverseBytes16_64), n);
|
d = EmitReverseBytes16_64Op(context, n);
|
||||||
}
|
}
|
||||||
|
|
||||||
SetAluDOrZR(context, d);
|
SetAluDOrZR(context, d);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static Operand EmitReverseBytes16_32Op(ArmEmitterContext context, Operand op)
|
||||||
|
{
|
||||||
|
Debug.Assert(op.Type == OperandType.I32);
|
||||||
|
|
||||||
|
Operand val = EmitReverseBytes16_64Op(context, context.ZeroExtend32(OperandType.I64, op));
|
||||||
|
|
||||||
|
return context.ConvertI64ToI32(val);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Operand EmitReverseBytes16_64Op(ArmEmitterContext context, Operand op)
|
||||||
|
{
|
||||||
|
Debug.Assert(op.Type == OperandType.I64);
|
||||||
|
|
||||||
|
return context.BitwiseOr(context.ShiftRightUI(context.BitwiseAnd(op, Const(0xff00ff00ff00ff00ul)), Const(8)),
|
||||||
|
context.ShiftLeft (context.BitwiseAnd(op, Const(0x00ff00ff00ff00fful)), Const(8)));
|
||||||
|
}
|
||||||
|
|
||||||
public static void Rev32(ArmEmitterContext context)
|
public static void Rev32(ArmEmitterContext context)
|
||||||
{
|
{
|
||||||
OpCodeAlu op = (OpCodeAlu)context.CurrOp;
|
OpCodeAlu op = (OpCodeAlu)context.CurrOp;
|
||||||
|
|
||||||
Operand n = GetIntOrZR(context, op.Rn);
|
Operand n = GetIntOrZR(context, op.Rn);
|
||||||
|
Operand d;
|
||||||
|
|
||||||
if (op.RegisterSize == RegisterSize.Int32)
|
if (op.RegisterSize == RegisterSize.Int32)
|
||||||
{
|
{
|
||||||
SetAluDOrZR(context, context.ByteSwap(n));
|
d = context.ByteSwap(n);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
Operand d = context.Call(new _U64_U64(SoftFallback.ReverseBytes32_64), n);
|
d = EmitReverseBytes32_64Op(context, n);
|
||||||
|
|
||||||
SetAluDOrZR(context, d);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
SetAluDOrZR(context, d);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Operand EmitReverseBytes32_64Op(ArmEmitterContext context, Operand op)
|
||||||
|
{
|
||||||
|
Debug.Assert(op.Type == OperandType.I64);
|
||||||
|
|
||||||
|
Operand val = EmitReverseBytes16_64Op(context, op);
|
||||||
|
|
||||||
|
return context.BitwiseOr(context.ShiftRightUI(context.BitwiseAnd(val, Const(0xffff0000ffff0000ul)), Const(16)),
|
||||||
|
context.ShiftLeft (context.BitwiseAnd(val, Const(0x0000ffff0000fffful)), Const(16)));
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void Rev64(ArmEmitterContext context)
|
public static void Rev64(ArmEmitterContext context)
|
||||||
|
|
|
@ -77,7 +77,14 @@ namespace ARMeilleure.Instructions
|
||||||
|
|
||||||
public static void Addp_V(ArmEmitterContext context)
|
public static void Addp_V(ArmEmitterContext context)
|
||||||
{
|
{
|
||||||
EmitVectorPairwiseOpZx(context, (op1, op2) => context.Add(op1, op2));
|
if (Optimizations.UseSsse3)
|
||||||
|
{
|
||||||
|
EmitSsse3VectorPairwiseOp(context, X86PaddInstruction);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
EmitVectorPairwiseOpZx(context, (op1, op2) => context.Add(op1, op2));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void Addv_V(ArmEmitterContext context)
|
public static void Addv_V(ArmEmitterContext context)
|
||||||
|
@ -399,7 +406,7 @@ namespace ARMeilleure.Instructions
|
||||||
{
|
{
|
||||||
if (Optimizations.FastFP && Optimizations.UseSse2)
|
if (Optimizations.FastFP && Optimizations.UseSse2)
|
||||||
{
|
{
|
||||||
EmitVectorPairwiseOpF(context, Intrinsic.X86Addps, Intrinsic.X86Addpd);
|
EmitSse2VectorPairwiseOpF(context, Intrinsic.X86Addps, Intrinsic.X86Addpd);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -547,7 +554,7 @@ namespace ARMeilleure.Instructions
|
||||||
{
|
{
|
||||||
if (Optimizations.FastFP && Optimizations.UseSse2)
|
if (Optimizations.FastFP && Optimizations.UseSse2)
|
||||||
{
|
{
|
||||||
EmitVectorPairwiseOpF(context, Intrinsic.X86Maxps, Intrinsic.X86Maxpd);
|
EmitSse2VectorPairwiseOpF(context, Intrinsic.X86Maxps, Intrinsic.X86Maxpd);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -622,7 +629,7 @@ namespace ARMeilleure.Instructions
|
||||||
{
|
{
|
||||||
if (Optimizations.FastFP && Optimizations.UseSse2)
|
if (Optimizations.FastFP && Optimizations.UseSse2)
|
||||||
{
|
{
|
||||||
EmitVectorPairwiseOpF(context, Intrinsic.X86Minps, Intrinsic.X86Minpd);
|
EmitSse2VectorPairwiseOpF(context, Intrinsic.X86Minps, Intrinsic.X86Minpd);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -664,7 +671,7 @@ namespace ARMeilleure.Instructions
|
||||||
res = context.VectorZeroUpper64(res);
|
res = context.VectorZeroUpper64(res);
|
||||||
}
|
}
|
||||||
|
|
||||||
context.Copy(GetVec(op.Rd), res);
|
context.Copy(d, res);
|
||||||
}
|
}
|
||||||
else /* if (sizeF == 1) */
|
else /* if (sizeF == 1) */
|
||||||
{
|
{
|
||||||
|
@ -672,7 +679,7 @@ namespace ARMeilleure.Instructions
|
||||||
|
|
||||||
res = context.AddIntrinsic(Intrinsic.X86Addpd, d, res);
|
res = context.AddIntrinsic(Intrinsic.X86Addpd, d, res);
|
||||||
|
|
||||||
context.Copy(GetVec(op.Rd), res);
|
context.Copy(d, res);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -710,7 +717,7 @@ namespace ARMeilleure.Instructions
|
||||||
res = context.VectorZeroUpper64(res);
|
res = context.VectorZeroUpper64(res);
|
||||||
}
|
}
|
||||||
|
|
||||||
context.Copy(GetVec(op.Rd), res);
|
context.Copy(d, res);
|
||||||
}
|
}
|
||||||
else /* if (sizeF == 1) */
|
else /* if (sizeF == 1) */
|
||||||
{
|
{
|
||||||
|
@ -721,7 +728,7 @@ namespace ARMeilleure.Instructions
|
||||||
res = context.AddIntrinsic(Intrinsic.X86Mulpd, n, res);
|
res = context.AddIntrinsic(Intrinsic.X86Mulpd, n, res);
|
||||||
res = context.AddIntrinsic(Intrinsic.X86Addpd, d, res);
|
res = context.AddIntrinsic(Intrinsic.X86Addpd, d, res);
|
||||||
|
|
||||||
context.Copy(GetVec(op.Rd), res);
|
context.Copy(d, res);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -764,7 +771,7 @@ namespace ARMeilleure.Instructions
|
||||||
res = context.VectorZeroUpper64(res);
|
res = context.VectorZeroUpper64(res);
|
||||||
}
|
}
|
||||||
|
|
||||||
context.Copy(GetVec(op.Rd), res);
|
context.Copy(d, res);
|
||||||
}
|
}
|
||||||
else /* if (sizeF == 1) */
|
else /* if (sizeF == 1) */
|
||||||
{
|
{
|
||||||
|
@ -772,7 +779,7 @@ namespace ARMeilleure.Instructions
|
||||||
|
|
||||||
res = context.AddIntrinsic(Intrinsic.X86Subpd, d, res);
|
res = context.AddIntrinsic(Intrinsic.X86Subpd, d, res);
|
||||||
|
|
||||||
context.Copy(GetVec(op.Rd), res);
|
context.Copy(d, res);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -810,7 +817,7 @@ namespace ARMeilleure.Instructions
|
||||||
res = context.VectorZeroUpper64(res);
|
res = context.VectorZeroUpper64(res);
|
||||||
}
|
}
|
||||||
|
|
||||||
context.Copy(GetVec(op.Rd), res);
|
context.Copy(d, res);
|
||||||
}
|
}
|
||||||
else /* if (sizeF == 1) */
|
else /* if (sizeF == 1) */
|
||||||
{
|
{
|
||||||
|
@ -821,7 +828,7 @@ namespace ARMeilleure.Instructions
|
||||||
res = context.AddIntrinsic(Intrinsic.X86Mulpd, n, res);
|
res = context.AddIntrinsic(Intrinsic.X86Mulpd, n, res);
|
||||||
res = context.AddIntrinsic(Intrinsic.X86Subpd, d, res);
|
res = context.AddIntrinsic(Intrinsic.X86Subpd, d, res);
|
||||||
|
|
||||||
context.Copy(GetVec(op.Rd), res);
|
context.Copy(d, res);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -2028,9 +2035,16 @@ namespace ARMeilleure.Instructions
|
||||||
|
|
||||||
public static void Smaxp_V(ArmEmitterContext context)
|
public static void Smaxp_V(ArmEmitterContext context)
|
||||||
{
|
{
|
||||||
Delegate dlg = new _S64_S64_S64(Math.Max);
|
if (Optimizations.UseSsse3)
|
||||||
|
{
|
||||||
|
EmitSsse3VectorPairwiseOp(context, X86PmaxsInstruction);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Delegate dlg = new _S64_S64_S64(Math.Max);
|
||||||
|
|
||||||
EmitVectorPairwiseOpSx(context, (op1, op2) => context.Call(dlg, op1, op2));
|
EmitVectorPairwiseOpSx(context, (op1, op2) => context.Call(dlg, op1, op2));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void Smaxv_V(ArmEmitterContext context)
|
public static void Smaxv_V(ArmEmitterContext context)
|
||||||
|
@ -2070,9 +2084,16 @@ namespace ARMeilleure.Instructions
|
||||||
|
|
||||||
public static void Sminp_V(ArmEmitterContext context)
|
public static void Sminp_V(ArmEmitterContext context)
|
||||||
{
|
{
|
||||||
Delegate dlg = new _S64_S64_S64(Math.Min);
|
if (Optimizations.UseSsse3)
|
||||||
|
{
|
||||||
|
EmitSsse3VectorPairwiseOp(context, X86PminsInstruction);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Delegate dlg = new _S64_S64_S64(Math.Min);
|
||||||
|
|
||||||
EmitVectorPairwiseOpSx(context, (op1, op2) => context.Call(dlg, op1, op2));
|
EmitVectorPairwiseOpSx(context, (op1, op2) => context.Call(dlg, op1, op2));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void Sminv_V(ArmEmitterContext context)
|
public static void Sminv_V(ArmEmitterContext context)
|
||||||
|
@ -2653,9 +2674,16 @@ namespace ARMeilleure.Instructions
|
||||||
|
|
||||||
public static void Umaxp_V(ArmEmitterContext context)
|
public static void Umaxp_V(ArmEmitterContext context)
|
||||||
{
|
{
|
||||||
Delegate dlg = new _U64_U64_U64(Math.Max);
|
if (Optimizations.UseSsse3)
|
||||||
|
{
|
||||||
|
EmitSsse3VectorPairwiseOp(context, X86PmaxuInstruction);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Delegate dlg = new _U64_U64_U64(Math.Max);
|
||||||
|
|
||||||
EmitVectorPairwiseOpZx(context, (op1, op2) => context.Call(dlg, op1, op2));
|
EmitVectorPairwiseOpZx(context, (op1, op2) => context.Call(dlg, op1, op2));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void Umaxv_V(ArmEmitterContext context)
|
public static void Umaxv_V(ArmEmitterContext context)
|
||||||
|
@ -2695,9 +2723,16 @@ namespace ARMeilleure.Instructions
|
||||||
|
|
||||||
public static void Uminp_V(ArmEmitterContext context)
|
public static void Uminp_V(ArmEmitterContext context)
|
||||||
{
|
{
|
||||||
Delegate dlg = new _U64_U64_U64(Math.Min);
|
if (Optimizations.UseSsse3)
|
||||||
|
{
|
||||||
|
EmitSsse3VectorPairwiseOp(context, X86PminuInstruction);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Delegate dlg = new _U64_U64_U64(Math.Min);
|
||||||
|
|
||||||
EmitVectorPairwiseOpZx(context, (op1, op2) => context.Call(dlg, op1, op2));
|
EmitVectorPairwiseOpZx(context, (op1, op2) => context.Call(dlg, op1, op2));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void Uminv_V(ArmEmitterContext context)
|
public static void Uminv_V(ArmEmitterContext context)
|
||||||
|
@ -3020,7 +3055,9 @@ namespace ARMeilleure.Instructions
|
||||||
|
|
||||||
int part = op.RegisterSize == RegisterSize.Simd128 ? elems : 0;
|
int part = op.RegisterSize == RegisterSize.Simd128 ? elems : 0;
|
||||||
|
|
||||||
Operand res = part == 0 ? context.VectorZero() : context.Copy(GetVec(op.Rd));
|
Operand d = GetVec(op.Rd);
|
||||||
|
|
||||||
|
Operand res = part == 0 ? context.VectorZero() : context.Copy(d);
|
||||||
|
|
||||||
long roundConst = 1L << (eSize - 1);
|
long roundConst = 1L << (eSize - 1);
|
||||||
|
|
||||||
|
@ -3041,7 +3078,7 @@ namespace ARMeilleure.Instructions
|
||||||
res = EmitVectorInsert(context, res, de, part + index, op.Size);
|
res = EmitVectorInsert(context, res, de, part + index, op.Size);
|
||||||
}
|
}
|
||||||
|
|
||||||
context.Copy(GetVec(op.Rd), res);
|
context.Copy(d, res);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void EmitScalarRoundOpF(ArmEmitterContext context, FPRoundingMode roundMode)
|
public static void EmitScalarRoundOpF(ArmEmitterContext context, FPRoundingMode roundMode)
|
||||||
|
@ -3124,12 +3161,12 @@ namespace ARMeilleure.Instructions
|
||||||
Operand n = GetVec(op.Rn);
|
Operand n = GetVec(op.Rn);
|
||||||
Operand m = GetVec(op.Rm);
|
Operand m = GetVec(op.Rm);
|
||||||
|
|
||||||
Operand nQNaNMask = EmitSse2VectorIsQNaNOpF(context, n);
|
|
||||||
Operand mQNaNMask = EmitSse2VectorIsQNaNOpF(context, m);
|
|
||||||
|
|
||||||
Operand nNum = context.Copy(n);
|
Operand nNum = context.Copy(n);
|
||||||
Operand mNum = context.Copy(m);
|
Operand mNum = context.Copy(m);
|
||||||
|
|
||||||
|
Operand nQNaNMask = EmitSse2VectorIsQNaNOpF(context, nNum);
|
||||||
|
Operand mQNaNMask = EmitSse2VectorIsQNaNOpF(context, mNum);
|
||||||
|
|
||||||
int sizeF = op.Size & 1;
|
int sizeF = op.Size & 1;
|
||||||
|
|
||||||
if (sizeF == 0)
|
if (sizeF == 0)
|
||||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -16,6 +16,24 @@ namespace ARMeilleure.Instructions
|
||||||
|
|
||||||
static class InstEmitSimdHelper
|
static class InstEmitSimdHelper
|
||||||
{
|
{
|
||||||
|
#region "Masks"
|
||||||
|
public static readonly long[] EvenMasks = new long[]
|
||||||
|
{
|
||||||
|
14L << 56 | 12L << 48 | 10L << 40 | 08L << 32 | 06L << 24 | 04L << 16 | 02L << 8 | 00L << 0, // B
|
||||||
|
13L << 56 | 12L << 48 | 09L << 40 | 08L << 32 | 05L << 24 | 04L << 16 | 01L << 8 | 00L << 0, // H
|
||||||
|
11L << 56 | 10L << 48 | 09L << 40 | 08L << 32 | 03L << 24 | 02L << 16 | 01L << 8 | 00L << 0 // S
|
||||||
|
};
|
||||||
|
|
||||||
|
public static readonly long[] OddMasks = new long[]
|
||||||
|
{
|
||||||
|
15L << 56 | 13L << 48 | 11L << 40 | 09L << 32 | 07L << 24 | 05L << 16 | 03L << 8 | 01L << 0, // B
|
||||||
|
15L << 56 | 14L << 48 | 11L << 40 | 10L << 32 | 07L << 24 | 06L << 16 | 03L << 8 | 02L << 0, // H
|
||||||
|
15L << 56 | 14L << 48 | 13L << 40 | 12L << 32 | 07L << 24 | 06L << 16 | 05L << 8 | 04L << 0 // S
|
||||||
|
};
|
||||||
|
|
||||||
|
private static readonly long _zeroMask = 128L << 56 | 128L << 48 | 128L << 40 | 128L << 32 | 128L << 24 | 128L << 16 | 128L << 8 | 128L << 0;
|
||||||
|
#endregion
|
||||||
|
|
||||||
#region "X86 SSE Intrinsics"
|
#region "X86 SSE Intrinsics"
|
||||||
public static readonly Intrinsic[] X86PaddInstruction = new Intrinsic[]
|
public static readonly Intrinsic[] X86PaddInstruction = new Intrinsic[]
|
||||||
{
|
{
|
||||||
|
@ -189,11 +207,19 @@ namespace ARMeilleure.Instructions
|
||||||
return vector;
|
return vector;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static Operand X86GetElements(ArmEmitterContext context, long e1, long e0)
|
||||||
|
{
|
||||||
|
Operand vector0 = context.VectorCreateScalar(Const(e0));
|
||||||
|
Operand vector1 = context.VectorCreateScalar(Const(e1));
|
||||||
|
|
||||||
|
return context.AddIntrinsic(Intrinsic.X86Punpcklqdq, vector0, vector1);
|
||||||
|
}
|
||||||
|
|
||||||
public static int X86GetRoundControl(FPRoundingMode roundMode)
|
public static int X86GetRoundControl(FPRoundingMode roundMode)
|
||||||
{
|
{
|
||||||
switch (roundMode)
|
switch (roundMode)
|
||||||
{
|
{
|
||||||
case FPRoundingMode.ToNearest: return 8 | 0;
|
case FPRoundingMode.ToNearest: return 8 | 0; // even
|
||||||
case FPRoundingMode.TowardsPlusInfinity: return 8 | 2;
|
case FPRoundingMode.TowardsPlusInfinity: return 8 | 2;
|
||||||
case FPRoundingMode.TowardsMinusInfinity: return 8 | 1;
|
case FPRoundingMode.TowardsMinusInfinity: return 8 | 1;
|
||||||
case FPRoundingMode.TowardsZero: return 8 | 3;
|
case FPRoundingMode.TowardsZero: return 8 | 3;
|
||||||
|
@ -991,6 +1017,46 @@ namespace ARMeilleure.Instructions
|
||||||
context.Copy(GetVec(op.Rd), res);
|
context.Copy(GetVec(op.Rd), res);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static void EmitSsse3VectorPairwiseOp(ArmEmitterContext context, Intrinsic[] inst)
|
||||||
|
{
|
||||||
|
OpCodeSimdReg op = (OpCodeSimdReg)context.CurrOp;
|
||||||
|
|
||||||
|
Operand n = GetVec(op.Rn);
|
||||||
|
Operand m = GetVec(op.Rm);
|
||||||
|
|
||||||
|
if (op.RegisterSize == RegisterSize.Simd64)
|
||||||
|
{
|
||||||
|
Operand zeroEvenMask = X86GetElements(context, _zeroMask, EvenMasks[op.Size]);
|
||||||
|
Operand zeroOddMask = X86GetElements(context, _zeroMask, OddMasks [op.Size]);
|
||||||
|
|
||||||
|
Operand mN = context.AddIntrinsic(Intrinsic.X86Punpcklqdq, n, m); // m:n
|
||||||
|
|
||||||
|
Operand left = context.AddIntrinsic(Intrinsic.X86Pshufb, mN, zeroEvenMask); // 0:even from m:n
|
||||||
|
Operand right = context.AddIntrinsic(Intrinsic.X86Pshufb, mN, zeroOddMask); // 0:odd from m:n
|
||||||
|
|
||||||
|
context.Copy(GetVec(op.Rd), context.AddIntrinsic(inst[op.Size], left, right));
|
||||||
|
}
|
||||||
|
else if (op.Size < 3)
|
||||||
|
{
|
||||||
|
Operand oddEvenMask = X86GetElements(context, OddMasks[op.Size], EvenMasks[op.Size]);
|
||||||
|
|
||||||
|
Operand oddEvenN = context.AddIntrinsic(Intrinsic.X86Pshufb, n, oddEvenMask); // odd:even from n
|
||||||
|
Operand oddEvenM = context.AddIntrinsic(Intrinsic.X86Pshufb, m, oddEvenMask); // odd:even from m
|
||||||
|
|
||||||
|
Operand left = context.AddIntrinsic(Intrinsic.X86Punpcklqdq, oddEvenN, oddEvenM);
|
||||||
|
Operand right = context.AddIntrinsic(Intrinsic.X86Punpckhqdq, oddEvenN, oddEvenM);
|
||||||
|
|
||||||
|
context.Copy(GetVec(op.Rd), context.AddIntrinsic(inst[op.Size], left, right));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Operand left = context.AddIntrinsic(Intrinsic.X86Punpcklqdq, n, m);
|
||||||
|
Operand right = context.AddIntrinsic(Intrinsic.X86Punpckhqdq, n, m);
|
||||||
|
|
||||||
|
context.Copy(GetVec(op.Rd), context.AddIntrinsic(inst[3], left, right));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public static void EmitVectorAcrossVectorOpSx(ArmEmitterContext context, Func2I emit)
|
public static void EmitVectorAcrossVectorOpSx(ArmEmitterContext context, Func2I emit)
|
||||||
{
|
{
|
||||||
EmitVectorAcrossVectorOp(context, emit, signed: true, isLong: false);
|
EmitVectorAcrossVectorOp(context, emit, signed: true, isLong: false);
|
||||||
|
@ -1066,7 +1132,7 @@ namespace ARMeilleure.Instructions
|
||||||
context.Copy(GetVec(op.Rd), res);
|
context.Copy(GetVec(op.Rd), res);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void EmitVectorPairwiseOpF(ArmEmitterContext context, Intrinsic inst32, Intrinsic inst64)
|
public static void EmitSse2VectorPairwiseOpF(ArmEmitterContext context, Intrinsic inst32, Intrinsic inst64)
|
||||||
{
|
{
|
||||||
OpCodeSimdReg op = (OpCodeSimdReg)context.CurrOp;
|
OpCodeSimdReg op = (OpCodeSimdReg)context.CurrOp;
|
||||||
|
|
||||||
|
@ -1231,8 +1297,7 @@ namespace ARMeilleure.Instructions
|
||||||
|
|
||||||
if (op.Size <= 2)
|
if (op.Size <= 2)
|
||||||
{
|
{
|
||||||
Operand temp = add ? context.Add (ne, me)
|
Operand temp = add ? context.Add(ne, me) : context.Subtract(ne, me);
|
||||||
: context.Subtract(ne, me);
|
|
||||||
|
|
||||||
de = EmitSatQ(context, temp, op.Size, signedSrc: true, signedDst: signed);
|
de = EmitSatQ(context, temp, op.Size, signedSrc: true, signedDst: signed);
|
||||||
}
|
}
|
||||||
|
@ -1316,7 +1381,9 @@ namespace ARMeilleure.Instructions
|
||||||
|
|
||||||
int part = !scalar && (op.RegisterSize == RegisterSize.Simd128) ? elems : 0;
|
int part = !scalar && (op.RegisterSize == RegisterSize.Simd128) ? elems : 0;
|
||||||
|
|
||||||
Operand res = part == 0 ? context.VectorZero() : context.Copy(GetVec(op.Rd));
|
Operand d = GetVec(op.Rd);
|
||||||
|
|
||||||
|
Operand res = part == 0 ? context.VectorZero() : context.Copy(d);
|
||||||
|
|
||||||
for (int index = 0; index < elems; index++)
|
for (int index = 0; index < elems; index++)
|
||||||
{
|
{
|
||||||
|
@ -1327,7 +1394,7 @@ namespace ARMeilleure.Instructions
|
||||||
res = EmitVectorInsert(context, res, temp, part + index, op.Size);
|
res = EmitVectorInsert(context, res, temp, part + index, op.Size);
|
||||||
}
|
}
|
||||||
|
|
||||||
context.Copy(GetVec(op.Rd), res);
|
context.Copy(d, res);
|
||||||
}
|
}
|
||||||
|
|
||||||
// TSrc (16bit, 32bit, 64bit; signed, unsigned) > TDst (8bit, 16bit, 32bit; signed, unsigned).
|
// TSrc (16bit, 32bit, 64bit; signed, unsigned) > TDst (8bit, 16bit, 32bit; signed, unsigned).
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
using ARMeilleure.Decoders;
|
using ARMeilleure.Decoders;
|
||||||
using ARMeilleure.IntermediateRepresentation;
|
using ARMeilleure.IntermediateRepresentation;
|
||||||
using ARMeilleure.Translation;
|
using ARMeilleure.Translation;
|
||||||
|
using System.Diagnostics;
|
||||||
|
|
||||||
using static ARMeilleure.Instructions.InstEmitHelper;
|
using static ARMeilleure.Instructions.InstEmitHelper;
|
||||||
using static ARMeilleure.Instructions.InstEmitSimdHelper;
|
using static ARMeilleure.Instructions.InstEmitSimdHelper;
|
||||||
|
@ -107,7 +108,7 @@ namespace ARMeilleure.Instructions
|
||||||
res = context.VectorZeroUpper64(res);
|
res = context.VectorZeroUpper64(res);
|
||||||
}
|
}
|
||||||
|
|
||||||
context.Copy(GetVec(op.Rd), res);
|
context.Copy(d, res);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -158,7 +159,7 @@ namespace ARMeilleure.Instructions
|
||||||
res = context.VectorZeroUpper64(res);
|
res = context.VectorZeroUpper64(res);
|
||||||
}
|
}
|
||||||
|
|
||||||
context.Copy(GetVec(op.Rd), res);
|
context.Copy(d, res);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -292,11 +293,7 @@ namespace ARMeilleure.Instructions
|
||||||
{
|
{
|
||||||
Operand ne = EmitVectorExtractZx(context, op.Rn, index, 0);
|
Operand ne = EmitVectorExtractZx(context, op.Rn, index, 0);
|
||||||
|
|
||||||
ne = context.ConvertI64ToI32(ne);
|
Operand de = EmitReverseBits8Op(context, ne);
|
||||||
|
|
||||||
Operand de = context.Call(new _U32_U32(SoftFallback.ReverseBits8), ne);
|
|
||||||
|
|
||||||
de = context.ZeroExtend32(OperandType.I64, de);
|
|
||||||
|
|
||||||
res = EmitVectorInsert(context, res, de, index, 0);
|
res = EmitVectorInsert(context, res, de, index, 0);
|
||||||
}
|
}
|
||||||
|
@ -304,6 +301,20 @@ namespace ARMeilleure.Instructions
|
||||||
context.Copy(GetVec(op.Rd), res);
|
context.Copy(GetVec(op.Rd), res);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static Operand EmitReverseBits8Op(ArmEmitterContext context, Operand op)
|
||||||
|
{
|
||||||
|
Debug.Assert(op.Type == OperandType.I64);
|
||||||
|
|
||||||
|
Operand val = context.BitwiseOr(context.ShiftRightUI(context.BitwiseAnd(op, Const(0xaaul)), Const(1)),
|
||||||
|
context.ShiftLeft (context.BitwiseAnd(op, Const(0x55ul)), Const(1)));
|
||||||
|
|
||||||
|
val = context.BitwiseOr(context.ShiftRightUI(context.BitwiseAnd(val, Const(0xccul)), Const(2)),
|
||||||
|
context.ShiftLeft (context.BitwiseAnd(val, Const(0x33ul)), Const(2)));
|
||||||
|
|
||||||
|
return context.BitwiseOr(context.ShiftRightUI(val, Const(4)),
|
||||||
|
context.ShiftLeft (context.BitwiseAnd(val, Const(0x0ful)), Const(4)));
|
||||||
|
}
|
||||||
|
|
||||||
public static void Rev16_V(ArmEmitterContext context)
|
public static void Rev16_V(ArmEmitterContext context)
|
||||||
{
|
{
|
||||||
if (Optimizations.UseSsse3)
|
if (Optimizations.UseSsse3)
|
||||||
|
|
|
@ -13,20 +13,6 @@ namespace ARMeilleure.Instructions
|
||||||
static partial class InstEmit
|
static partial class InstEmit
|
||||||
{
|
{
|
||||||
#region "Masks"
|
#region "Masks"
|
||||||
private static readonly long[] _masksE0_TrnUzpXtn = new long[]
|
|
||||||
{
|
|
||||||
14L << 56 | 12L << 48 | 10L << 40 | 08L << 32 | 06L << 24 | 04L << 16 | 02L << 8 | 00L << 0,
|
|
||||||
13L << 56 | 12L << 48 | 09L << 40 | 08L << 32 | 05L << 24 | 04L << 16 | 01L << 8 | 00L << 0,
|
|
||||||
11L << 56 | 10L << 48 | 09L << 40 | 08L << 32 | 03L << 24 | 02L << 16 | 01L << 8 | 00L << 0
|
|
||||||
};
|
|
||||||
|
|
||||||
private static readonly long[] _masksE1_TrnUzp = new long[]
|
|
||||||
{
|
|
||||||
15L << 56 | 13L << 48 | 11L << 40 | 09L << 32 | 07L << 24 | 05L << 16 | 03L << 8 | 01L << 0,
|
|
||||||
15L << 56 | 14L << 48 | 11L << 40 | 10L << 32 | 07L << 24 | 06L << 16 | 03L << 8 | 02L << 0,
|
|
||||||
15L << 56 | 14L << 48 | 13L << 40 | 12L << 32 | 07L << 24 | 06L << 16 | 05L << 8 | 04L << 0
|
|
||||||
};
|
|
||||||
|
|
||||||
private static readonly long[] _masksE0_Uzp = new long[]
|
private static readonly long[] _masksE0_Uzp = new long[]
|
||||||
{
|
{
|
||||||
13L << 56 | 09L << 48 | 05L << 40 | 01L << 32 | 12L << 24 | 08L << 16 | 04L << 8 | 00L << 0,
|
13L << 56 | 09L << 48 | 05L << 40 | 01L << 32 | 12L << 24 | 08L << 16 | 04L << 8 | 00L << 0,
|
||||||
|
@ -447,7 +433,7 @@ namespace ARMeilleure.Instructions
|
||||||
|
|
||||||
Operand res = context.VectorZeroUpper64(d);
|
Operand res = context.VectorZeroUpper64(d);
|
||||||
|
|
||||||
Operand mask = X86GetAllElements(context, _masksE0_TrnUzpXtn[op.Size]);
|
Operand mask = X86GetAllElements(context, EvenMasks[op.Size]);
|
||||||
|
|
||||||
Operand res2 = context.AddIntrinsic(Intrinsic.X86Pshufb, GetVec(op.Rn), mask);
|
Operand res2 = context.AddIntrinsic(Intrinsic.X86Pshufb, GetVec(op.Rn), mask);
|
||||||
|
|
||||||
|
@ -646,8 +632,8 @@ namespace ARMeilleure.Instructions
|
||||||
|
|
||||||
if (op.Size < 3)
|
if (op.Size < 3)
|
||||||
{
|
{
|
||||||
long maskE0 = _masksE0_TrnUzpXtn[op.Size];
|
long maskE0 = EvenMasks[op.Size];
|
||||||
long maskE1 = _masksE1_TrnUzp [op.Size];
|
long maskE1 = OddMasks [op.Size];
|
||||||
|
|
||||||
mask = X86GetScalar(context, maskE0);
|
mask = X86GetScalar(context, maskE0);
|
||||||
|
|
||||||
|
@ -714,8 +700,8 @@ namespace ARMeilleure.Instructions
|
||||||
|
|
||||||
if (op.Size < 3)
|
if (op.Size < 3)
|
||||||
{
|
{
|
||||||
long maskE0 = _masksE0_TrnUzpXtn[op.Size];
|
long maskE0 = EvenMasks[op.Size];
|
||||||
long maskE1 = _masksE1_TrnUzp [op.Size];
|
long maskE1 = OddMasks [op.Size];
|
||||||
|
|
||||||
mask = X86GetScalar(context, maskE0);
|
mask = X86GetScalar(context, maskE0);
|
||||||
|
|
||||||
|
|
|
@ -4,6 +4,7 @@ using ARMeilleure.Decoders;
|
||||||
using ARMeilleure.IntermediateRepresentation;
|
using ARMeilleure.IntermediateRepresentation;
|
||||||
using ARMeilleure.Translation;
|
using ARMeilleure.Translation;
|
||||||
using System;
|
using System;
|
||||||
|
using System.Diagnostics;
|
||||||
|
|
||||||
using static ARMeilleure.Instructions.InstEmitHelper;
|
using static ARMeilleure.Instructions.InstEmitHelper;
|
||||||
using static ARMeilleure.Instructions.InstEmitSimdHelper;
|
using static ARMeilleure.Instructions.InstEmitSimdHelper;
|
||||||
|
@ -16,13 +17,6 @@ namespace ARMeilleure.Instructions
|
||||||
static partial class InstEmit
|
static partial class InstEmit
|
||||||
{
|
{
|
||||||
#region "Masks"
|
#region "Masks"
|
||||||
private static readonly long[] _masks_RshrnShrn = new long[]
|
|
||||||
{
|
|
||||||
14L << 56 | 12L << 48 | 10L << 40 | 08L << 32 | 06L << 24 | 04L << 16 | 02L << 8 | 00L << 0,
|
|
||||||
13L << 56 | 12L << 48 | 09L << 40 | 08L << 32 | 05L << 24 | 04L << 16 | 01L << 8 | 00L << 0,
|
|
||||||
11L << 56 | 10L << 48 | 09L << 40 | 08L << 32 | 03L << 24 | 02L << 16 | 01L << 8 | 00L << 0
|
|
||||||
};
|
|
||||||
|
|
||||||
private static readonly long[] _masks_SliSri = new long[] // Replication masks.
|
private static readonly long[] _masks_SliSri = new long[] // Replication masks.
|
||||||
{
|
{
|
||||||
0x0101010101010101L, 0x0001000100010001L, 0x0000000100000001L, 0x0000000000000001L
|
0x0101010101010101L, 0x0001000100010001L, 0x0000000100000001L, 0x0000000000000001L
|
||||||
|
@ -42,7 +36,7 @@ namespace ARMeilleure.Instructions
|
||||||
Operand d = GetVec(op.Rd);
|
Operand d = GetVec(op.Rd);
|
||||||
Operand n = GetVec(op.Rn);
|
Operand n = GetVec(op.Rn);
|
||||||
|
|
||||||
Operand dLow = context.AddIntrinsic(Intrinsic.X86Movlhps, d, context.VectorZero());
|
Operand dLow = context.VectorZeroUpper64(d);
|
||||||
|
|
||||||
Operand mask = null;
|
Operand mask = null;
|
||||||
|
|
||||||
|
@ -61,7 +55,7 @@ namespace ARMeilleure.Instructions
|
||||||
|
|
||||||
res = context.AddIntrinsic(srlInst, res, Const(shift));
|
res = context.AddIntrinsic(srlInst, res, Const(shift));
|
||||||
|
|
||||||
Operand mask2 = X86GetAllElements(context, _masks_RshrnShrn[op.Size]);
|
Operand mask2 = X86GetAllElements(context, EvenMasks[op.Size]);
|
||||||
|
|
||||||
res = context.AddIntrinsic(Intrinsic.X86Pshufb, res, mask2);
|
res = context.AddIntrinsic(Intrinsic.X86Pshufb, res, mask2);
|
||||||
|
|
||||||
|
@ -157,13 +151,13 @@ namespace ARMeilleure.Instructions
|
||||||
Operand d = GetVec(op.Rd);
|
Operand d = GetVec(op.Rd);
|
||||||
Operand n = GetVec(op.Rn);
|
Operand n = GetVec(op.Rn);
|
||||||
|
|
||||||
Operand dLow = context.AddIntrinsic(Intrinsic.X86Movlhps, d, context.VectorZero());
|
Operand dLow = context.VectorZeroUpper64(d);
|
||||||
|
|
||||||
Intrinsic srlInst = X86PsrlInstruction[op.Size + 1];
|
Intrinsic srlInst = X86PsrlInstruction[op.Size + 1];
|
||||||
|
|
||||||
Operand nShifted = context.AddIntrinsic(srlInst, n, Const(shift));
|
Operand nShifted = context.AddIntrinsic(srlInst, n, Const(shift));
|
||||||
|
|
||||||
Operand mask = X86GetAllElements(context, _masks_RshrnShrn[op.Size]);
|
Operand mask = X86GetAllElements(context, EvenMasks[op.Size]);
|
||||||
|
|
||||||
Operand res = context.AddIntrinsic(Intrinsic.X86Pshufb, nShifted, mask);
|
Operand res = context.AddIntrinsic(Intrinsic.X86Pshufb, nShifted, mask);
|
||||||
|
|
||||||
|
@ -702,9 +696,9 @@ namespace ARMeilleure.Instructions
|
||||||
for (int index = 0; index < elems; index++)
|
for (int index = 0; index < elems; index++)
|
||||||
{
|
{
|
||||||
Operand ne = EmitVectorExtractZx(context, op.Rn, index, op.Size);
|
Operand ne = EmitVectorExtractZx(context, op.Rn, index, op.Size);
|
||||||
Operand me = EmitVectorExtractZx(context, op.Rm, index, op.Size);
|
Operand me = EmitVectorExtractSx(context, op.Rm, index << op.Size, 0);
|
||||||
|
|
||||||
Operand e = context.Call(new _U64_U64_U64_Bool_S32(SoftFallback.UnsignedShlReg), ne, me, Const(0), Const(op.Size));
|
Operand e = EmitUnsignedShlRegOp(context, ne, context.ConvertI64ToI32(me), op.Size);
|
||||||
|
|
||||||
res = EmitVectorInsert(context, res, e, index, op.Size);
|
res = EmitVectorInsert(context, res, e, index, op.Size);
|
||||||
}
|
}
|
||||||
|
@ -879,9 +873,7 @@ namespace ARMeilleure.Instructions
|
||||||
e = context.Add(e, Const(roundConst));
|
e = context.Add(e, Const(roundConst));
|
||||||
}
|
}
|
||||||
|
|
||||||
e = signed
|
e = signed ? context.ShiftRightSI(e, Const(shift)) : context.ShiftRightUI(e, Const(shift));
|
||||||
? context.ShiftRightSI(e, Const(shift))
|
|
||||||
: context.ShiftRightUI(e, Const(shift));
|
|
||||||
}
|
}
|
||||||
else /* if (op.Size == 3) */
|
else /* if (op.Size == 3) */
|
||||||
{
|
{
|
||||||
|
@ -901,6 +893,28 @@ namespace ARMeilleure.Instructions
|
||||||
context.Copy(GetVec(op.Rd), res);
|
context.Copy(GetVec(op.Rd), res);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static Operand EmitUnsignedShlRegOp(ArmEmitterContext context, Operand op, Operand shiftLsB, int size)
|
||||||
|
{
|
||||||
|
Debug.Assert(op.Type == OperandType.I64);
|
||||||
|
Debug.Assert(shiftLsB.Type == OperandType.I32);
|
||||||
|
Debug.Assert((uint)size < 4u);
|
||||||
|
|
||||||
|
Operand negShiftLsB = context.Negate(shiftLsB);
|
||||||
|
|
||||||
|
Operand isPositive = context.ICompareGreaterOrEqual(shiftLsB, Const(0));
|
||||||
|
|
||||||
|
Operand shl = context.ShiftLeft (op, shiftLsB);
|
||||||
|
Operand shr = context.ShiftRightUI(op, negShiftLsB);
|
||||||
|
|
||||||
|
Operand res = context.ConditionalSelect(isPositive, shl, shr);
|
||||||
|
|
||||||
|
Operand isOutOfRange = context.BitwiseOr(
|
||||||
|
context.ICompareGreaterOrEqual(shiftLsB, Const(8 << size)),
|
||||||
|
context.ICompareGreaterOrEqual(negShiftLsB, Const(8 << size)));
|
||||||
|
|
||||||
|
return context.ConditionalSelect(isOutOfRange, Const(0UL), res);
|
||||||
|
}
|
||||||
|
|
||||||
private static void EmitVectorShrImmNarrowOpZx(ArmEmitterContext context, bool round)
|
private static void EmitVectorShrImmNarrowOpZx(ArmEmitterContext context, bool round)
|
||||||
{
|
{
|
||||||
OpCodeSimdShImm op = (OpCodeSimdShImm)context.CurrOp;
|
OpCodeSimdShImm op = (OpCodeSimdShImm)context.CurrOp;
|
||||||
|
@ -913,7 +927,9 @@ namespace ARMeilleure.Instructions
|
||||||
|
|
||||||
int part = op.RegisterSize == RegisterSize.Simd128 ? elems : 0;
|
int part = op.RegisterSize == RegisterSize.Simd128 ? elems : 0;
|
||||||
|
|
||||||
Operand res = part == 0 ? context.VectorZero() : context.Copy(GetVec(op.Rd));
|
Operand d = GetVec(op.Rd);
|
||||||
|
|
||||||
|
Operand res = part == 0 ? context.VectorZero() : context.Copy(d);
|
||||||
|
|
||||||
for (int index = 0; index < elems; index++)
|
for (int index = 0; index < elems; index++)
|
||||||
{
|
{
|
||||||
|
@ -929,7 +945,7 @@ namespace ARMeilleure.Instructions
|
||||||
res = EmitVectorInsert(context, res, e, part + index, op.Size);
|
res = EmitVectorInsert(context, res, e, part + index, op.Size);
|
||||||
}
|
}
|
||||||
|
|
||||||
context.Copy(GetVec(op.Rd), res);
|
context.Copy(d, res);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Flags]
|
[Flags]
|
||||||
|
@ -972,7 +988,9 @@ namespace ARMeilleure.Instructions
|
||||||
|
|
||||||
int part = !scalar && (op.RegisterSize == RegisterSize.Simd128) ? elems : 0;
|
int part = !scalar && (op.RegisterSize == RegisterSize.Simd128) ? elems : 0;
|
||||||
|
|
||||||
Operand res = part == 0 ? context.VectorZero() : context.Copy(GetVec(op.Rd));
|
Operand d = GetVec(op.Rd);
|
||||||
|
|
||||||
|
Operand res = part == 0 ? context.VectorZero() : context.Copy(d);
|
||||||
|
|
||||||
for (int index = 0; index < elems; index++)
|
for (int index = 0; index < elems; index++)
|
||||||
{
|
{
|
||||||
|
@ -985,9 +1003,7 @@ namespace ARMeilleure.Instructions
|
||||||
e = context.Add(e, Const(roundConst));
|
e = context.Add(e, Const(roundConst));
|
||||||
}
|
}
|
||||||
|
|
||||||
e = signedSrc
|
e = signedSrc ? context.ShiftRightSI(e, Const(shift)) : context.ShiftRightUI(e, Const(shift));
|
||||||
? context.ShiftRightSI(e, Const(shift))
|
|
||||||
: context.ShiftRightUI(e, Const(shift));
|
|
||||||
}
|
}
|
||||||
else /* if (op.Size == 2 && round) */
|
else /* if (op.Size == 2 && round) */
|
||||||
{
|
{
|
||||||
|
@ -999,7 +1015,7 @@ namespace ARMeilleure.Instructions
|
||||||
res = EmitVectorInsert(context, res, e, part + index, op.Size);
|
res = EmitVectorInsert(context, res, e, part + index, op.Size);
|
||||||
}
|
}
|
||||||
|
|
||||||
context.Copy(GetVec(op.Rd), res);
|
context.Copy(d, res);
|
||||||
}
|
}
|
||||||
|
|
||||||
// dst64 = (Int(src64, signed) + roundConst) >> shift;
|
// dst64 = (Int(src64, signed) + roundConst) >> shift;
|
||||||
|
|
|
@ -1240,74 +1240,5 @@ namespace ARMeilleure.Instructions
|
||||||
: (uint)(value >> 32);
|
: (uint)(value >> 32);
|
||||||
}
|
}
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region "Reverse"
|
|
||||||
public static uint ReverseBits8(uint value)
|
|
||||||
{
|
|
||||||
value = ((value & 0xaa) >> 1) | ((value & 0x55) << 1);
|
|
||||||
value = ((value & 0xcc) >> 2) | ((value & 0x33) << 2);
|
|
||||||
|
|
||||||
return (value >> 4) | ((value & 0x0f) << 4);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static uint ReverseBits32(uint value)
|
|
||||||
{
|
|
||||||
value = ((value & 0xaaaaaaaa) >> 1) | ((value & 0x55555555) << 1);
|
|
||||||
value = ((value & 0xcccccccc) >> 2) | ((value & 0x33333333) << 2);
|
|
||||||
value = ((value & 0xf0f0f0f0) >> 4) | ((value & 0x0f0f0f0f) << 4);
|
|
||||||
value = ((value & 0xff00ff00) >> 8) | ((value & 0x00ff00ff) << 8);
|
|
||||||
|
|
||||||
return (value >> 16) | (value << 16);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static ulong ReverseBits64(ulong value)
|
|
||||||
{
|
|
||||||
value = ((value & 0xaaaaaaaaaaaaaaaa) >> 1 ) | ((value & 0x5555555555555555) << 1 );
|
|
||||||
value = ((value & 0xcccccccccccccccc) >> 2 ) | ((value & 0x3333333333333333) << 2 );
|
|
||||||
value = ((value & 0xf0f0f0f0f0f0f0f0) >> 4 ) | ((value & 0x0f0f0f0f0f0f0f0f) << 4 );
|
|
||||||
value = ((value & 0xff00ff00ff00ff00) >> 8 ) | ((value & 0x00ff00ff00ff00ff) << 8 );
|
|
||||||
value = ((value & 0xffff0000ffff0000) >> 16) | ((value & 0x0000ffff0000ffff) << 16);
|
|
||||||
|
|
||||||
return (value >> 32) | (value << 32);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static uint ReverseBytes16_32(uint value) => (uint)ReverseBytes16_64(value);
|
|
||||||
|
|
||||||
public static ulong ReverseBytes16_64(ulong value) => ReverseBytes(value, RevSize.Rev16);
|
|
||||||
public static ulong ReverseBytes32_64(ulong value) => ReverseBytes(value, RevSize.Rev32);
|
|
||||||
|
|
||||||
private enum RevSize
|
|
||||||
{
|
|
||||||
Rev16,
|
|
||||||
Rev32,
|
|
||||||
Rev64
|
|
||||||
}
|
|
||||||
|
|
||||||
private static ulong ReverseBytes(ulong value, RevSize size)
|
|
||||||
{
|
|
||||||
value = ((value & 0xff00ff00ff00ff00) >> 8) | ((value & 0x00ff00ff00ff00ff) << 8);
|
|
||||||
|
|
||||||
if (size == RevSize.Rev16)
|
|
||||||
{
|
|
||||||
return value;
|
|
||||||
}
|
|
||||||
|
|
||||||
value = ((value & 0xffff0000ffff0000) >> 16) | ((value & 0x0000ffff0000ffff) << 16);
|
|
||||||
|
|
||||||
if (size == RevSize.Rev32)
|
|
||||||
{
|
|
||||||
return value;
|
|
||||||
}
|
|
||||||
|
|
||||||
value = ((value & 0xffffffff00000000) >> 32) | ((value & 0x00000000ffffffff) << 32);
|
|
||||||
|
|
||||||
if (size == RevSize.Rev64)
|
|
||||||
{
|
|
||||||
return value;
|
|
||||||
}
|
|
||||||
|
|
||||||
throw new ArgumentException(nameof(size));
|
|
||||||
}
|
|
||||||
#endregion
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -30,8 +30,11 @@ namespace ARMeilleure.IntermediateRepresentation
|
||||||
X86Cvtps2pd,
|
X86Cvtps2pd,
|
||||||
X86Cvtsd2si,
|
X86Cvtsd2si,
|
||||||
X86Cvtsd2ss,
|
X86Cvtsd2ss,
|
||||||
|
X86Cvtsi2sd,
|
||||||
X86Cvtsi2si,
|
X86Cvtsi2si,
|
||||||
|
X86Cvtsi2ss,
|
||||||
X86Cvtss2sd,
|
X86Cvtss2sd,
|
||||||
|
X86Cvtss2si,
|
||||||
X86Divpd,
|
X86Divpd,
|
||||||
X86Divps,
|
X86Divps,
|
||||||
X86Divsd,
|
X86Divsd,
|
||||||
|
|
|
@ -2856,7 +2856,7 @@ namespace Ryujinx.Tests.Cpu
|
||||||
|
|
||||||
SingleOpcode(opcodes, v0: v0, v1: v1);
|
SingleOpcode(opcodes, v0: v0, v1: v1);
|
||||||
|
|
||||||
CompareAgainstUnicorn(fpTolerances: FpTolerances.UpToOneUlpsD); // unsigned
|
CompareAgainstUnicorn();
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test, Pairwise] [Explicit]
|
[Test, Pairwise] [Explicit]
|
||||||
|
@ -2892,7 +2892,7 @@ namespace Ryujinx.Tests.Cpu
|
||||||
|
|
||||||
SingleOpcode(opcodes, v0: v0, v1: v1);
|
SingleOpcode(opcodes, v0: v0, v1: v1);
|
||||||
|
|
||||||
CompareAgainstUnicorn(fpTolerances: FpTolerances.UpToOneUlpsD); // unsigned
|
CompareAgainstUnicorn();
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test, Pairwise]
|
[Test, Pairwise]
|
||||||
|
|
|
@ -582,7 +582,7 @@ namespace Ryujinx.Tests.Cpu
|
||||||
|
|
||||||
SingleOpcode(opcodes, x1: xn, x31: x31, v0: v0);
|
SingleOpcode(opcodes, x1: xn, x31: x31, v0: v0);
|
||||||
|
|
||||||
CompareAgainstUnicorn(fpTolerances: FpTolerances.UpToOneUlpsD); // unsigned
|
CompareAgainstUnicorn();
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test, Pairwise] [Explicit]
|
[Test, Pairwise] [Explicit]
|
||||||
|
@ -666,7 +666,7 @@ namespace Ryujinx.Tests.Cpu
|
||||||
|
|
||||||
SingleOpcode(opcodes, x1: xn, x31: x31, v0: v0);
|
SingleOpcode(opcodes, x1: xn, x31: x31, v0: v0);
|
||||||
|
|
||||||
CompareAgainstUnicorn(fpTolerances: FpTolerances.UpToOneUlpsD); // unsigned
|
CompareAgainstUnicorn();
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
|
@ -564,7 +564,7 @@ namespace Ryujinx.Tests.Cpu
|
||||||
|
|
||||||
SingleOpcode(opcodes, v0: v0, v1: v1);
|
SingleOpcode(opcodes, v0: v0, v1: v1);
|
||||||
|
|
||||||
CompareAgainstUnicorn(fpTolerances: FpTolerances.UpToOneUlpsD); // unsigned
|
CompareAgainstUnicorn();
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test, Pairwise]
|
[Test, Pairwise]
|
||||||
|
|
Loading…
Reference in a new issue