Commit e494ead52114e9d7baa9f33bca0e5b15b577c16b
1 parent
86f1d3ac
Restore a more maintainable version of the 64bit multiply code.
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3439 c046a42c-6fe2-441c-8c8c-71466251a162
Showing
1 changed file
with
69 additions
and
34 deletions
host-utils.c
| 1 | /* | 1 | /* |
| 2 | * Utility compute operations used by translated code. | 2 | * Utility compute operations used by translated code. |
| 3 | * | 3 | * |
| 4 | + * Copyright (c) 2003 Fabrice Bellard | ||
| 4 | * Copyright (c) 2007 Aurelien Jarno | 5 | * Copyright (c) 2007 Aurelien Jarno |
| 5 | * | 6 | * |
| 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy | 7 | * Permission is hereby granted, free of charge, to any person obtaining a copy |
| @@ -24,54 +25,88 @@ | @@ -24,54 +25,88 @@ | ||
| 24 | 25 | ||
| 25 | #include "vl.h" | 26 | #include "vl.h" |
| 26 | 27 | ||
| 27 | -/* Signed 64x64 -> 128 multiplication */ | 28 | +/* Long integer helpers */ |
| 29 | +static void add128 (uint64_t *plow, uint64_t *phigh, uint64_t a, uint64_t b) | ||
| 30 | +{ | ||
| 31 | + *plow += a; | ||
| 32 | + /* carry test */ | ||
| 33 | + if (*plow < a) | ||
| 34 | + (*phigh)++; | ||
| 35 | + *phigh += b; | ||
| 36 | +} | ||
| 28 | 37 | ||
| 29 | -void muls64(int64_t *phigh, int64_t *plow, int64_t a, int64_t b) | 38 | +static void neg128 (uint64_t *plow, uint64_t *phigh) |
| 30 | { | 39 | { |
| 31 | -#if defined(__x86_64__) | ||
| 32 | - __asm__ ("imul %0\n\t" | ||
| 33 | - : "=d" (*phigh), "=a" (*plow) | ||
| 34 | - : "a" (a), "0" (b) | ||
| 35 | - ); | ||
| 36 | -#else | ||
| 37 | - int64_t ph; | ||
| 38 | - uint64_t pm1, pm2, pl; | 40 | + *plow = ~*plow; |
| 41 | + *phigh = ~*phigh; | ||
| 42 | + add128(plow, phigh, 1, 0); | ||
| 43 | +} | ||
| 39 | 44 | ||
| 40 | - pl = (uint64_t)((uint32_t)a) * (uint64_t)((uint32_t)b); | ||
| 41 | - pm1 = (a >> 32) * (uint32_t)b; | ||
| 42 | - pm2 = (uint32_t)a * (b >> 32); | ||
| 43 | - ph = (a >> 32) * (b >> 32); | 45 | +static void mul64 (uint64_t *plow, uint64_t *phigh, uint64_t a, uint64_t b) |
| 46 | +{ | ||
| 47 | + uint32_t a0, a1, b0, b1; | ||
| 48 | + uint64_t v; | ||
| 44 | 49 | ||
| 45 | - ph += (int64_t)pm1 >> 32; | ||
| 46 | - ph += (int64_t)pm2 >> 32; | ||
| 47 | - pm1 = (uint64_t)((uint32_t)pm1) + (uint64_t)((uint32_t)pm2) + (pl >> 32); | 50 | + a0 = a; |
| 51 | + a1 = a >> 32; | ||
| 48 | 52 | ||
| 49 | - *phigh = ph + ((int64_t)pm1 >> 32); | ||
| 50 | - *plow = (pm1 << 32) + (uint32_t)pl; | ||
| 51 | -#endif | 53 | + b0 = b; |
| 54 | + b1 = b >> 32; | ||
| 55 | + | ||
| 56 | + v = (uint64_t)a0 * (uint64_t)b0; | ||
| 57 | + *plow = v; | ||
| 58 | + *phigh = 0; | ||
| 59 | + | ||
| 60 | + v = (uint64_t)a0 * (uint64_t)b1; | ||
| 61 | + add128(plow, phigh, v << 32, v >> 32); | ||
| 62 | + | ||
| 63 | + v = (uint64_t)a1 * (uint64_t)b0; | ||
| 64 | + add128(plow, phigh, v << 32, v >> 32); | ||
| 65 | + | ||
| 66 | + v = (uint64_t)a1 * (uint64_t)b1; | ||
| 67 | + *phigh += v; | ||
| 52 | } | 68 | } |
| 53 | 69 | ||
| 70 | + | ||
| 54 | /* Unsigned 64x64 -> 128 multiplication */ | 71 | /* Unsigned 64x64 -> 128 multiplication */ |
| 55 | -void mulu64(uint64_t *phigh, uint64_t *plow, uint64_t a, uint64_t b) | 72 | +void mulu64 (uint64_t *plow, uint64_t *phigh, uint64_t a, uint64_t b) |
| 56 | { | 73 | { |
| 57 | #if defined(__x86_64__) | 74 | #if defined(__x86_64__) |
| 58 | __asm__ ("mul %0\n\t" | 75 | __asm__ ("mul %0\n\t" |
| 59 | : "=d" (*phigh), "=a" (*plow) | 76 | : "=d" (*phigh), "=a" (*plow) |
| 60 | - : "a" (a), "0" (b) | ||
| 61 | - ); | 77 | + : "a" (a), "0" (b)); |
| 62 | #else | 78 | #else |
| 63 | - uint64_t ph, pm1, pm2, pl; | ||
| 64 | - | ||
| 65 | - pl = (uint64_t)((uint32_t)a) * (uint64_t)((uint32_t)b); | ||
| 66 | - pm1 = (a >> 32) * (uint32_t)b; | ||
| 67 | - pm2 = (uint32_t)a * (b >> 32); | ||
| 68 | - ph = (a >> 32) * (b >> 32); | 79 | + mul64(plow, phigh, a, b); |
| 80 | +#endif | ||
| 81 | +#if defined(DEBUG_MULDIV) | ||
| 82 | + printf("mulu64: 0x%016llx * 0x%016llx = 0x%016llx%016llx\n", | ||
| 83 | + a, b, *phigh, *plow); | ||
| 84 | +#endif | ||
| 85 | +} | ||
| 69 | 86 | ||
| 70 | - ph += pm1 >> 32; | ||
| 71 | - ph += pm2 >> 32; | ||
| 72 | - pm1 = (uint64_t)((uint32_t)pm1) + (uint64_t)((uint32_t)pm2) + (pl >> 32); | 87 | +/* Signed 64x64 -> 128 multiplication */ |
| 88 | +void muls64 (uint64_t *plow, uint64_t *phigh, int64_t a, int64_t b) | ||
| 89 | +{ | ||
| 90 | +#if defined(__x86_64__) | ||
| 91 | + __asm__ ("imul %0\n\t" | ||
| 92 | + : "=d" (*phigh), "=a" (*plow) | ||
| 93 | + : "a" (a), "0" (b)); | ||
| 94 | +#else | ||
| 95 | + int sa, sb; | ||
| 73 | 96 | ||
| 74 | - *phigh = ph + (pm1 >> 32); | ||
| 75 | - *plow = (pm1 << 32) + (uint32_t)pl; | 97 | + sa = (a < 0); |
| 98 | + if (sa) | ||
| 99 | + a = -a; | ||
| 100 | + sb = (b < 0); | ||
| 101 | + if (sb) | ||
| 102 | + b = -b; | ||
| 103 | + mul64(plow, phigh, a, b); | ||
| 104 | + if (sa ^ sb) { | ||
| 105 | + neg128(plow, phigh); | ||
| 106 | + } | ||
| 107 | +#endif | ||
| 108 | +#if defined(DEBUG_MULDIV) | ||
| 109 | + printf("muls64: 0x%016llx * 0x%016llx = 0x%016llx%016llx\n", | ||
| 110 | + a, b, *phigh, *plow); | ||
| 76 | #endif | 111 | #endif |
| 77 | } | 112 | } |