aboutsummaryrefslogtreecommitdiff
path: root/ARMeilleure/Instructions/InstEmitSimdArithmetic32.cs
diff options
context:
space:
mode:
Diffstat (limited to 'ARMeilleure/Instructions/InstEmitSimdArithmetic32.cs')
-rw-r--r--ARMeilleure/Instructions/InstEmitSimdArithmetic32.cs143
1 files changed, 142 insertions, 1 deletions
diff --git a/ARMeilleure/Instructions/InstEmitSimdArithmetic32.cs b/ARMeilleure/Instructions/InstEmitSimdArithmetic32.cs
index ed6b2a31..79b376e9 100644
--- a/ARMeilleure/Instructions/InstEmitSimdArithmetic32.cs
+++ b/ARMeilleure/Instructions/InstEmitSimdArithmetic32.cs
@@ -777,6 +777,13 @@ namespace ARMeilleure.Instructions
}
}
+ public static void Vmlal_I(ArmEmitterContext context)
+ {
+ OpCode32SimdReg op = (OpCode32SimdReg)context.CurrOp;
+
+ EmitVectorTernaryLongOpI32(context, (d, n, m) => context.Add(d, context.Multiply(n, m)), !op.U);
+ }
+
public static void Vmls_S(ArmEmitterContext context)
{
if (Optimizations.FastFP && Optimizations.UseSse2)
@@ -992,6 +999,13 @@ namespace ARMeilleure.Instructions
}
}
+ public static void Vpaddl(ArmEmitterContext context)
+ {
+ OpCode32Simd op = (OpCode32Simd)context.CurrOp;
+
+ EmitVectorPairwiseLongOpI32(context, (op1, op2) => context.Add(op1, op2), (op.Opc & 1) == 0);
+ }
+
public static void Vpmax_V(ArmEmitterContext context)
{
if (Optimizations.FastFP && Optimizations.UseSse2)
@@ -1014,7 +1028,7 @@ namespace ARMeilleure.Instructions
}
else
{
- EmitVectorPairwiseOpI32(context, (op1, op2) =>
+ EmitVectorPairwiseOpI32(context, (op1, op2) =>
{
Operand greater = op.U ? context.ICompareGreaterUI(op1, op2) : context.ICompareGreater(op1, op2);
return context.ConditionalSelect(greater, op1, op2);
@@ -1052,6 +1066,62 @@ namespace ARMeilleure.Instructions
}
}
+ public static void Vqadd(ArmEmitterContext context)
+ {
+ OpCode32SimdReg op = (OpCode32SimdReg)context.CurrOp;
+
+ EmitSaturatingAddSubBinaryOp(context, add: true, !op.U);
+ }
+
+ public static void Vqdmulh(ArmEmitterContext context)
+ {
+ OpCode32SimdReg op = (OpCode32SimdReg)context.CurrOp;
+ int eSize = 8 << op.Size;
+
+ EmitVectorBinaryOpI32(context, (op1, op2) =>
+ {
+ if (op.Size == 2)
+ {
+ op1 = context.SignExtend32(OperandType.I64, op1);
+ op2 = context.SignExtend32(OperandType.I64, op2);
+ }
+
+ Operand res = context.Multiply(op1, op2);
+ res = context.ShiftRightSI(res, Const(eSize - 1));
+ res = EmitSatQ(context, res, eSize, signedSrc: true, signedDst: true);
+
+ if (op.Size == 2)
+ {
+ res = context.ConvertI64ToI32(res);
+ }
+
+ return res;
+ }, signed: true);
+ }
+
+ public static void Vqmovn(ArmEmitterContext context)
+ {
+ OpCode32SimdMovn op = (OpCode32SimdMovn)context.CurrOp;
+
+ bool signed = !op.Q;
+
+ EmitVectorUnaryNarrowOp32(context, (op1) => EmitSatQ(context, op1, 8 << op.Size, signed, signed), signed);
+ }
+
+ public static void Vqmovun(ArmEmitterContext context)
+ {
+ OpCode32SimdMovn op = (OpCode32SimdMovn)context.CurrOp;
+
+ EmitVectorUnaryNarrowOp32(context, (op1) => EmitSatQ(context, op1, 8 << op.Size, signedSrc: true, signedDst: false), signed: true);
+ }
+
+ public static void Vqsub(ArmEmitterContext context)
+ {
+ OpCode32SimdReg op = (OpCode32SimdReg)context.CurrOp;
+
+ EmitSaturatingAddSubBinaryOp(context, add: false, !op.U);
+ }
+
public static void Vrev(ArmEmitterContext context)
{
OpCode32SimdRev op = (OpCode32SimdRev)context.CurrOp;
@@ -1202,6 +1272,30 @@ namespace ARMeilleure.Instructions
}
}
+ public static void Vrhadd(ArmEmitterContext context)
+ {
+ OpCode32SimdReg op = (OpCode32SimdReg)context.CurrOp;
+
+ EmitVectorBinaryOpI32(context, (op1, op2) =>
+ {
+ if (op.Size == 2)
+ {
+ op1 = context.ZeroExtend32(OperandType.I64, op1);
+ op2 = context.ZeroExtend32(OperandType.I64, op2);
+ }
+
+ Operand res = context.Add(context.Add(op1, op2), Const(op1.Type, 1L));
+ res = context.ShiftRightUI(res, Const(1));
+
+ if (op.Size == 2)
+ {
+ res = context.ConvertI64ToI32(res);
+ }
+
+ return res;
+ }, !op.U);
+ }
+
public static void Vrsqrte(ArmEmitterContext context)
{
OpCode32SimdSqrte op = (OpCode32SimdSqrte)context.CurrOp;
@@ -1349,6 +1443,13 @@ namespace ARMeilleure.Instructions
}
}
+ public static void Vsubl_I(ArmEmitterContext context)
+ {
+ OpCode32SimdRegLong op = (OpCode32SimdRegLong)context.CurrOp;
+
+ EmitVectorBinaryLongOpI32(context, (op1, op2) => context.Subtract(op1, op2), !op.U);
+ }
+
public static void Vsubw_I(ArmEmitterContext context)
{
OpCode32SimdRegWide op = (OpCode32SimdRegWide)context.CurrOp;
@@ -1356,6 +1457,46 @@ namespace ARMeilleure.Instructions
EmitVectorBinaryWideOpI32(context, (op1, op2) => context.Subtract(op1, op2), !op.U);
}
+ private static void EmitSaturatingAddSubBinaryOp(ArmEmitterContext context, bool add, bool signed)
+ {
+ OpCode32Simd op = (OpCode32Simd)context.CurrOp;
+
+ EmitVectorBinaryOpI32(context, (ne, me) =>
+ {
+ if (op.Size <= 2)
+ {
+ if (op.Size == 2)
+ {
+ ne = signed ? context.SignExtend32(OperandType.I64, ne) : context.ZeroExtend32(OperandType.I64, ne);
+ me = signed ? context.SignExtend32(OperandType.I64, me) : context.ZeroExtend32(OperandType.I64, me);
+ }
+
+ Operand res = add ? context.Add(ne, me) : context.Subtract(ne, me);
+
+ res = EmitSatQ(context, res, 8 << op.Size, signedSrc: true, signed);
+
+ if (op.Size == 2)
+ {
+ res = context.ConvertI64ToI32(res);
+ }
+
+ return res;
+ }
+ else if (add) /* if (op.Size == 3) */
+ {
+ return signed
+ ? EmitBinarySignedSatQAdd(context, ne, me)
+ : EmitBinaryUnsignedSatQAdd(context, ne, me);
+ }
+ else /* if (sub) */
+ {
+ return signed
+ ? EmitBinarySignedSatQSub(context, ne, me)
+ : EmitBinaryUnsignedSatQSub(context, ne, me);
+ }
+ }, signed);
+ }
+
private static void EmitSse41MaxMinNumOpF32(ArmEmitterContext context, bool isMaxNum, bool scalar)
{
IOpCode32Simd op = (IOpCode32Simd)context.CurrOp;