target/i386: use higher-precision arithmetic to compute CF

If the operands of the arithmetic instruction fit within a half-register,
it's easiest to use a comparison instruction to compute the carry.

Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
This commit is contained in:
Paolo Bonzini 2024-05-31 11:00:33 +02:00
parent 24899cdcd2
commit 134ffcb276

View File

@ -22,12 +22,17 @@
#if DATA_BITS == 8 #if DATA_BITS == 8
#define SUFFIX b #define SUFFIX b
#define DATA_TYPE uint8_t #define DATA_TYPE uint8_t
#define WIDER_TYPE uint32_t
#elif DATA_BITS == 16 #elif DATA_BITS == 16
#define SUFFIX w #define SUFFIX w
#define DATA_TYPE uint16_t #define DATA_TYPE uint16_t
#define WIDER_TYPE uint32_t
#elif DATA_BITS == 32 #elif DATA_BITS == 32
#define SUFFIX l #define SUFFIX l
#define DATA_TYPE uint32_t #define DATA_TYPE uint32_t
#if HOST_LONG_BITS >= 64
#define WIDER_TYPE uint64_t
#endif
#elif DATA_BITS == 64 #elif DATA_BITS == 64
#define SUFFIX q #define SUFFIX q
#define DATA_TYPE uint64_t #define DATA_TYPE uint64_t
@ -62,9 +67,18 @@ static uint32_t glue(compute_all_adc, SUFFIX)(DATA_TYPE dst, DATA_TYPE src1,
DATA_TYPE src3) DATA_TYPE src3)
{ {
uint32_t cf, pf, af, zf, sf, of; uint32_t cf, pf, af, zf, sf, of;
#ifdef WIDER_TYPE
WIDER_TYPE src13 = (WIDER_TYPE) src1 + (WIDER_TYPE) src3;
DATA_TYPE src2 = dst - src13;
cf = dst < src13;
#else
DATA_TYPE src2 = dst - src1 - src3; DATA_TYPE src2 = dst - src1 - src3;
cf = (src3 ? dst <= src1 : dst < src1); cf = (src3 ? dst <= src1 : dst < src1);
#endif
pf = compute_pf(dst); pf = compute_pf(dst);
af = (dst ^ src1 ^ src2) & 0x10; af = (dst ^ src1 ^ src2) & 0x10;
zf = (dst == 0) << 6; zf = (dst == 0) << 6;
@ -76,7 +90,13 @@ static uint32_t glue(compute_all_adc, SUFFIX)(DATA_TYPE dst, DATA_TYPE src1,
static int glue(compute_c_adc, SUFFIX)(DATA_TYPE dst, DATA_TYPE src1, static int glue(compute_c_adc, SUFFIX)(DATA_TYPE dst, DATA_TYPE src1,
DATA_TYPE src3) DATA_TYPE src3)
{ {
#ifdef WIDER_TYPE
WIDER_TYPE src13 = (WIDER_TYPE) src1 + (WIDER_TYPE) src3;
return dst < src13;
#else
return src3 ? dst <= src1 : dst < src1; return src3 ? dst <= src1 : dst < src1;
#endif
} }
static uint32_t glue(compute_all_sub, SUFFIX)(DATA_TYPE dst, DATA_TYPE src2) static uint32_t glue(compute_all_sub, SUFFIX)(DATA_TYPE dst, DATA_TYPE src2)
@ -104,9 +124,18 @@ static uint32_t glue(compute_all_sbb, SUFFIX)(DATA_TYPE dst, DATA_TYPE src2,
DATA_TYPE src3) DATA_TYPE src3)
{ {
uint32_t cf, pf, af, zf, sf, of; uint32_t cf, pf, af, zf, sf, of;
#ifdef WIDER_TYPE
WIDER_TYPE src23 = (WIDER_TYPE) src2 + (WIDER_TYPE) src3;
DATA_TYPE src1 = dst + src23;
cf = src1 < src23;
#else
DATA_TYPE src1 = dst + src2 + src3; DATA_TYPE src1 = dst + src2 + src3;
cf = (src3 ? src1 <= src2 : src1 < src2); cf = (src3 ? src1 <= src2 : src1 < src2);
#endif
pf = compute_pf(dst); pf = compute_pf(dst);
af = (dst ^ src1 ^ src2) & 0x10; af = (dst ^ src1 ^ src2) & 0x10;
zf = (dst == 0) << 6; zf = (dst == 0) << 6;
@ -118,9 +147,16 @@ static uint32_t glue(compute_all_sbb, SUFFIX)(DATA_TYPE dst, DATA_TYPE src2,
static int glue(compute_c_sbb, SUFFIX)(DATA_TYPE dst, DATA_TYPE src2, static int glue(compute_c_sbb, SUFFIX)(DATA_TYPE dst, DATA_TYPE src2,
DATA_TYPE src3) DATA_TYPE src3)
{ {
#ifdef WIDER_TYPE
WIDER_TYPE src23 = (WIDER_TYPE) src2 + (WIDER_TYPE) src3;
DATA_TYPE src1 = dst + src23;
return src1 < src23;
#else
DATA_TYPE src1 = dst + src2 + src3; DATA_TYPE src1 = dst + src2 + src3;
return (src3 ? src1 <= src2 : src1 < src2); return (src3 ? src1 <= src2 : src1 < src2);
#endif
} }
static uint32_t glue(compute_all_logic, SUFFIX)(DATA_TYPE dst, DATA_TYPE src1) static uint32_t glue(compute_all_logic, SUFFIX)(DATA_TYPE dst, DATA_TYPE src1)
@ -258,3 +294,4 @@ static int glue(compute_c_blsi, SUFFIX)(DATA_TYPE dst, DATA_TYPE src1)
#undef DATA_TYPE #undef DATA_TYPE
#undef DATA_MASK #undef DATA_MASK
#undef SUFFIX #undef SUFFIX
#undef WIDER_TYPE