/* { dg-require-effective-target int32plus } */ typedef long unsigned int size_t; extern void *memset (void *__s, int __c, size_t __n) __attribute__ ((__nothrow__)) __attribute__ ((__nonnull__ (1))); static void encode (words, low, hi) long *words; unsigned long low; long hi; { words[0] = ((low) & (((unsigned long) 1 << (sizeof(unsigned long) / 2)) - 1)); words[1] = ((unsigned long) (low) >> sizeof(unsigned long) / 2); words[2] = ((hi) & (((unsigned long) 1 << (sizeof(unsigned long) / 2)) - 1)); words[3] = ((unsigned long) (hi) >> sizeof(unsigned long) / 2); } static void decode (words, low, hi) long *words; unsigned long *low; long *hi; { *low = words[0] + words[1] * ((unsigned long) 1 << sizeof(unsigned long) / 2); *hi = words[2] + words[3] * ((unsigned long) 1 << sizeof(unsigned long) / 2); } int neg_double (l1, h1, lv, hv) unsigned long l1; long h1; unsigned long *lv; long *hv; { if (l1 == 0) { *lv = 0; *hv = - h1; return (*hv & h1) < 0; } else { *lv = -l1; *hv = ~h1; return 0; } } int add_double (l1, h1, l2, h2, lv, hv) unsigned long l1, l2; long h1, h2; unsigned long *lv; long *hv; { unsigned long l; long h; l = l1 + l2; h = h1 + h2 + (l < l1); *lv = l; *hv = h; return ((~((h1) ^ (h2)) & ((h1) ^ (h))) < 0); } int mul_double (l1, h1, l2, h2, lv, hv) unsigned long l1, l2; long h1, h2; unsigned long *lv; long *hv; { long arg1[4]; long arg2[4]; long prod[4 * 2]; unsigned long carry; int i, j, k; unsigned long toplow, neglow; long tophigh, neghigh; encode (arg1, l1, h1); encode (arg2, l2, h2); memset ((char *) prod, 0, sizeof prod); for (i = 0; i < 4; i++) { carry = 0; for (j = 0; j < 4; j++) { k = i + j; carry += arg1[i] * arg2[j]; carry += prod[k]; prod[k] = ((carry) & (((unsigned long) 1 << (sizeof(unsigned long) / 2)) - 1)); carry = ((unsigned long) (carry) >> sizeof(unsigned long) / 2); } prod[i + 4] = carry; } decode (prod, lv, hv); decode (prod + 4, &toplow, &tophigh); if (h1 < 0) { neg_double (l2, h2, &neglow, &neghigh); add_double (neglow, neghigh, toplow, tophigh, &toplow, &tophigh); } if (h2 < 0) { neg_double (l1, h1, &neglow, &neghigh); add_double (neglow, neghigh, toplow, tophigh, &toplow, &tophigh); } return (*hv < 0 ? ~(toplow & tophigh) : toplow | tophigh) != 0; }