aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPaolo Bonzini <pbonzini@redhat.com>2025-03-20 14:55:42 +0100
committerPaolo Bonzini <pbonzini@redhat.com>2025-04-17 18:23:26 +0200
commit767149d3d078356073a32238b313cee9d02db5d8 (patch)
tree5d030823b0fdfa6bddbbad72f874196c60c88c2c
parent3fec86e95cd44ac7db639686ef1dda143af59aea (diff)
downloadqemu-767149d3d078356073a32238b313cee9d02db5d8.zip
qemu-767149d3d078356073a32238b313cee9d02db5d8.tar.gz
qemu-767149d3d078356073a32238b313cee9d02db5d8.tar.bz2
target/i386: emulate: microoptimize and explain ADD_COUT_VEC/SUB_COUT_VEC
The logic is the same, but the majority(NOT a, b, c) is brought out to a separate macro and implemented without NOT operations. Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
-rw-r--r--target/i386/hvf/x86_flags.c26
1 files changed, 21 insertions, 5 deletions
diff --git a/target/i386/hvf/x86_flags.c b/target/i386/hvf/x86_flags.c
index fedc70a..60ab4f0 100644
--- a/target/i386/hvf/x86_flags.c
+++ b/target/i386/hvf/x86_flags.c
@@ -45,14 +45,30 @@
#define LF_MASK_CF (0x01 << LF_BIT_CF)
#define LF_MASK_PO (0x01 << LF_BIT_PO)
+/* majority(NOT a, b, c) = (a ^ b) ? b : c */
+#define MAJ_INV1(a, b, c) ((((a) ^ (b)) & ((b) ^ (c))) ^ (c))
+
+/*
+ * ADD_COUT_VEC(x, y) = majority((x + y) ^ x ^ y, x, y)
+ *
+ * If two corresponding bits in x and y are the same, that's the carry
+ * independent of the value (x+y)^x^y. Hence x^y can be replaced with
+ * 1 in (x+y)^x^y, resulting in majority(NOT (x+y), x, y)
+ */
#define ADD_COUT_VEC(op1, op2, result) \
- (((op1) & (op2)) | (((op1) | (op2)) & (~(result))))
+ MAJ_INV1(result, op1, op2)
+/*
+ * SUB_COUT_VEC(x, y) = NOT majority(x, NOT y, (x - y) ^ x ^ NOT y)
+ * = majority(NOT x, y, (x - y) ^ x ^ y)
+ *
+ * Note that the carry out is actually a borrow, i.e. it is inverted.
+ * If two corresponding bits in x and y are different, the value of the
+ * bit in (x-y)^x^y likewise does not matter. Hence, x^y can be replaced
+ * with 0 in (x-y)^x^y, resulting in majority(NOT x, y, x-y)
+ */
#define SUB_COUT_VEC(op1, op2, result) \
- (((~(op1)) & (op2)) | (((~(op1)) ^ (op2)) & (result)))
-
-#define GET_ADD_OVERFLOW(op1, op2, result, mask) \
- ((((op1) ^ (result)) & ((op2) ^ (result))) & (mask))
+ MAJ_INV1(op1, op2, result)
/* ******************* */
/* OSZAPC */