summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorH. Peter Anvin <hpa@zytor.com>2007-10-13 05:42:43 (GMT)
committerH. Peter Anvin <hpa@zytor.com>2007-10-13 05:42:43 (GMT)
commit363fd5567167f40f4d625d5840955ca235673822 (patch)
tree90e9044cdafcdc66e10591d9d7909011671014ae
parent6caa498ab14f3b0bdd976bfdb0ce21debb1e8fa6 (diff)
downloadpbn-363fd5567167f40f4d625d5840955ca235673822.zip
pbn-363fd5567167f40f4d625d5840955ca235673822.tar.gz
pbn-363fd5567167f40f4d625d5840955ca235673822.tar.bz2
pbn-363fd5567167f40f4d625d5840955ca235673822.tar.xz
pbn_divs(): special hint of gcc on i386: generate divl
gcc on i386 won't generate divl for 64/32 -> 32 division. Since this is a particularly important platform for us (NASM) put in a specific hint for it.
-rw-r--r--pbn_divs.c24
1 files changed, 20 insertions, 4 deletions
diff --git a/pbn_divs.c b/pbn_divs.c
index e88e3a6..3ce8191 100644
--- a/pbn_divs.c
+++ b/pbn_divs.c
@@ -20,12 +20,20 @@
#include "pbnint.h"
+#if defined(__GNUC__) && defined(__i386__) && PBN_ATOM_BITS == 32
+/* gcc won't generate divl for 64/32 -> 32, so help it out */
+# define GCC_HACK
+#endif
+
int pbn_divs(struct pbn **qp, pbn_satom_t *rp, struct pbn *n, pbn_satom_t d)
{
int i;
int len;
struct pbn *q;
- pbn_2atom_t c;
+ pbn_atom_t c;
+#ifndef GCC_HACK
+ pbn_2atom_t cc;
+#endif
int minus;
if (d == 0) {
@@ -49,14 +57,22 @@ int pbn_divs(struct pbn **qp, pbn_satom_t *rp, struct pbn *n, pbn_satom_t d)
q->minus = minus;
c = 0;
+#ifdef GCC_HACK
+ for (i = len-1; i >= 0; i--) {
+ asm("divl %4"
+ : "=d" (c), "=a" (q->num[i])
+ : "d" (c), "a" (n->num[i]), "rm" (d));
+ }
+#else
for (i = len-1; i >= 0; i--) {
- c = (c << PBN_ATOM_BITS) + n->num[i];
+ cc = ((pbn_2atom_t)c << PBN_ATOM_BITS) + n->num[i];
/* N.B. the explicit casts allow some compilers to tell this is
a 2A:A -> A division operation. */
- q->num[i] = (pbn_atom_t)(c/d);
- c = (pbn_atom_t)(c%d);
+ q->num[i] = (pbn_atom_t)(cc/d);
+ c = (pbn_atom_t)(cc%d);
}
+#endif
pbn_free(n);