aboutsummaryrefslogtreecommitdiff
path: root/ARMeilleure/Instructions
diff options
context:
space:
mode:
authormerry <git@mary.rs>2022-02-06 15:25:45 +0000
committerGitHub <noreply@github.com>2022-02-06 12:25:45 -0300
commit88d3ffb97c9d6e29a7eb44135ccea88753ca5f61 (patch)
tree448a5f7bd29cebc964bdaff87b23b34293406941 /ARMeilleure/Instructions
parent222b1ad7da04830852664dbd465117e441211f28 (diff)
ARMeilleure: A32: Implement SHADD8 (#3086)1.1.18
Diffstat (limited to 'ARMeilleure/Instructions')
-rw-r--r--ARMeilleure/Instructions/InstEmitAlu32.cs52
-rw-r--r--ARMeilleure/Instructions/InstName.cs1
2 files changed, 38 insertions, 15 deletions
diff --git a/ARMeilleure/Instructions/InstEmitAlu32.cs b/ARMeilleure/Instructions/InstEmitAlu32.cs
index 5f55fcd1..9aff0261 100644
--- a/ARMeilleure/Instructions/InstEmitAlu32.cs
+++ b/ARMeilleure/Instructions/InstEmitAlu32.cs
@@ -387,6 +387,11 @@ namespace ARMeilleure.Instructions
EmitDiv(context, false);
}
+ public static void Shadd8(ArmEmitterContext context)
+ {
+ EmitHadd8(context, false);
+ }
+
public static void Ssat(ArmEmitterContext context)
{
OpCode32Sat op = (OpCode32Sat)context.CurrOp;
@@ -474,20 +479,7 @@ namespace ARMeilleure.Instructions
public static void Uhadd8(ArmEmitterContext context)
{
- OpCode32AluReg op = (OpCode32AluReg)context.CurrOp;
-
- Operand m = GetIntA32(context, op.Rm);
- Operand n = GetIntA32(context, op.Rn);
-
- Operand xor, res;
-
- res = context.BitwiseAnd(m, n);
- xor = context.BitwiseExclusiveOr(m, n);
- xor = context.ShiftRightUI(xor, Const(1));
- xor = context.BitwiseAnd(xor, Const(0x7F7F7F7Fu));
- res = context.Add(res, xor);
-
- SetIntA32(context, op.Rd, res);
+ EmitHadd8(context, true);
}
public static void Usat(ArmEmitterContext context)
@@ -659,6 +651,36 @@ namespace ARMeilleure.Instructions
context.MarkLabel(lblEnd);
}
+ private static void EmitHadd8(ArmEmitterContext context, bool unsigned)
+ {
+ OpCode32AluReg op = (OpCode32AluReg)context.CurrOp;
+
+ Operand m = GetIntA32(context, op.Rm);
+ Operand n = GetIntA32(context, op.Rn);
+
+ Operand xor, res, carry;
+
+ // 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 to remove the LSB so that it doesn't leak into the field below.
+
+ res = context.BitwiseAnd(m, n);
+ carry = context.BitwiseExclusiveOr(m, n);
+ xor = context.ShiftRightUI(carry, Const(1));
+ xor = context.BitwiseAnd(xor, Const(0x7F7F7F7Fu));
+ res = context.Add(res, xor);
+
+ if (!unsigned)
+ {
+ // Propagates the sign bit from (x^y)>>1 upwards by one.
+ carry = context.BitwiseAnd(carry, Const(0x80808080u));
+ res = context.BitwiseExclusiveOr(res, carry);
+ }
+
+ SetIntA32(context, op.Rd, res);
+ }
+
private static void EmitSat(ArmEmitterContext context, int intMin, int intMax)
{
OpCode32Sat op = (OpCode32Sat)context.CurrOp;
@@ -772,4 +794,4 @@ namespace ARMeilleure.Instructions
EmitGenericAluStoreA32(context, op.Rd, op.SetFlags, value);
}
}
-} \ No newline at end of file
+}
diff --git a/ARMeilleure/Instructions/InstName.cs b/ARMeilleure/Instructions/InstName.cs
index a520c86a..698979b9 100644
--- a/ARMeilleure/Instructions/InstName.cs
+++ b/ARMeilleure/Instructions/InstName.cs
@@ -516,6 +516,7 @@ namespace ARMeilleure.Instructions
Rsb,
Rsc,
Sbfx,
+ Shadd8,
Smla__,
Smlal,
Smlal__,