summaryrefslogtreecommitdiff
path: root/gcc/double-int.c
diff options
context:
space:
mode:
Diffstat (limited to 'gcc/double-int.c')
-rw-r--r--gcc/double-int.c112
1 files changed, 53 insertions, 59 deletions
diff --git a/gcc/double-int.c b/gcc/double-int.c
index 834eaf9d6c2..d0fde0ed89f 100644
--- a/gcc/double-int.c
+++ b/gcc/double-int.c
@@ -186,24 +186,22 @@ mul_double_with_sign (unsigned HOST_WIDE_INT l1, HOST_WIDE_INT h1,
return (*hv < 0 ? ~(toplow & tophigh) : toplow | tophigh) != 0;
}
-/* Shift the doubleword integer in L1, H1 left by COUNT places
- keeping only PREC bits of result.
- Shift right if COUNT is negative.
- ARITH nonzero specifies arithmetic shifting; otherwise use logical shift.
+/* Shift the doubleword integer in L1, H1 right by COUNT places
+ keeping only PREC bits of result. ARITH nonzero specifies
+ arithmetic shifting; otherwise use logical shift.
Store the value as two `HOST_WIDE_INT' pieces in *LV and *HV. */
-void
-lshift_double (unsigned HOST_WIDE_INT l1, HOST_WIDE_INT h1,
- HOST_WIDE_INT count, unsigned int prec,
- unsigned HOST_WIDE_INT *lv, HOST_WIDE_INT *hv, bool arith)
+static void
+rshift_double (unsigned HOST_WIDE_INT l1, HOST_WIDE_INT h1,
+ unsigned HOST_WIDE_INT count, unsigned int prec,
+ unsigned HOST_WIDE_INT *lv, HOST_WIDE_INT *hv,
+ bool arith)
{
unsigned HOST_WIDE_INT signmask;
- if (count < 0)
- {
- rshift_double (l1, h1, -count, prec, lv, hv, arith);
- return;
- }
+ signmask = (arith
+ ? -((unsigned HOST_WIDE_INT) h1 >> (HOST_BITS_PER_WIDE_INT - 1))
+ : 0);
if (SHIFT_COUNT_TRUNCATED)
count %= prec;
@@ -217,61 +215,58 @@ lshift_double (unsigned HOST_WIDE_INT l1, HOST_WIDE_INT h1,
}
else if (count >= HOST_BITS_PER_WIDE_INT)
{
- *hv = l1 << (count - HOST_BITS_PER_WIDE_INT);
- *lv = 0;
+ *hv = 0;
+ *lv = (unsigned HOST_WIDE_INT) h1 >> (count - HOST_BITS_PER_WIDE_INT);
}
else
{
- *hv = (((unsigned HOST_WIDE_INT) h1 << count)
- | (l1 >> (HOST_BITS_PER_WIDE_INT - count - 1) >> 1));
- *lv = l1 << count;
+ *hv = (unsigned HOST_WIDE_INT) h1 >> count;
+ *lv = ((l1 >> count)
+ | ((unsigned HOST_WIDE_INT) h1
+ << (HOST_BITS_PER_WIDE_INT - count - 1) << 1));
}
- /* Sign extend all bits that are beyond the precision. */
-
- signmask = -((prec > HOST_BITS_PER_WIDE_INT
- ? ((unsigned HOST_WIDE_INT) *hv
- >> (prec - HOST_BITS_PER_WIDE_INT - 1))
- : (*lv >> (prec - 1))) & 1);
+ /* Zero / sign extend all bits that are beyond the precision. */
- if (prec >= 2 * HOST_BITS_PER_WIDE_INT)
+ if (count >= prec)
+ {
+ *hv = signmask;
+ *lv = signmask;
+ }
+ else if ((prec - count) >= 2 * HOST_BITS_PER_WIDE_INT)
;
- else if (prec >= HOST_BITS_PER_WIDE_INT)
+ else if ((prec - count) >= HOST_BITS_PER_WIDE_INT)
{
- *hv &= ~((HOST_WIDE_INT) (-1) << (prec - HOST_BITS_PER_WIDE_INT));
- *hv |= signmask << (prec - HOST_BITS_PER_WIDE_INT);
+ *hv &= ~((HOST_WIDE_INT) (-1) << (prec - count - HOST_BITS_PER_WIDE_INT));
+ *hv |= signmask << (prec - count - HOST_BITS_PER_WIDE_INT);
}
else
{
*hv = signmask;
- *lv &= ~((unsigned HOST_WIDE_INT) (-1) << prec);
- *lv |= signmask << prec;
+ *lv &= ~((unsigned HOST_WIDE_INT) (-1) << (prec - count));
+ *lv |= signmask << (prec - count);
}
}
-/* Shift the doubleword integer in L1, H1 right by COUNT places
- keeping only PREC bits of result. Shift left if COUNT is negative.
+/* Shift the doubleword integer in L1, H1 left by COUNT places
+ keeping only PREC bits of result.
+ Shift right if COUNT is negative.
ARITH nonzero specifies arithmetic shifting; otherwise use logical shift.
Store the value as two `HOST_WIDE_INT' pieces in *LV and *HV. */
void
-rshift_double (unsigned HOST_WIDE_INT l1, HOST_WIDE_INT h1,
+lshift_double (unsigned HOST_WIDE_INT l1, HOST_WIDE_INT h1,
HOST_WIDE_INT count, unsigned int prec,
- unsigned HOST_WIDE_INT *lv, HOST_WIDE_INT *hv,
- bool arith)
+ unsigned HOST_WIDE_INT *lv, HOST_WIDE_INT *hv, bool arith)
{
unsigned HOST_WIDE_INT signmask;
if (count < 0)
{
- lshift_double (l1, h1, -count, prec, lv, hv, arith);
+ rshift_double (l1, h1, absu_hwi (count), prec, lv, hv, arith);
return;
}
- signmask = (arith
- ? -((unsigned HOST_WIDE_INT) h1 >> (HOST_BITS_PER_WIDE_INT - 1))
- : 0);
-
if (SHIFT_COUNT_TRUNCATED)
count %= prec;
@@ -284,36 +279,35 @@ rshift_double (unsigned HOST_WIDE_INT l1, HOST_WIDE_INT h1,
}
else if (count >= HOST_BITS_PER_WIDE_INT)
{
- *hv = 0;
- *lv = (unsigned HOST_WIDE_INT) h1 >> (count - HOST_BITS_PER_WIDE_INT);
+ *hv = l1 << (count - HOST_BITS_PER_WIDE_INT);
+ *lv = 0;
}
else
{
- *hv = (unsigned HOST_WIDE_INT) h1 >> count;
- *lv = ((l1 >> count)
- | ((unsigned HOST_WIDE_INT) h1
- << (HOST_BITS_PER_WIDE_INT - count - 1) << 1));
+ *hv = (((unsigned HOST_WIDE_INT) h1 << count)
+ | (l1 >> (HOST_BITS_PER_WIDE_INT - count - 1) >> 1));
+ *lv = l1 << count;
}
- /* Zero / sign extend all bits that are beyond the precision. */
+ /* Sign extend all bits that are beyond the precision. */
- if (count >= (HOST_WIDE_INT)prec)
- {
- *hv = signmask;
- *lv = signmask;
- }
- else if ((prec - count) >= 2 * HOST_BITS_PER_WIDE_INT)
+ signmask = -((prec > HOST_BITS_PER_WIDE_INT
+ ? ((unsigned HOST_WIDE_INT) *hv
+ >> (prec - HOST_BITS_PER_WIDE_INT - 1))
+ : (*lv >> (prec - 1))) & 1);
+
+ if (prec >= 2 * HOST_BITS_PER_WIDE_INT)
;
- else if ((prec - count) >= HOST_BITS_PER_WIDE_INT)
+ else if (prec >= HOST_BITS_PER_WIDE_INT)
{
- *hv &= ~((HOST_WIDE_INT) (-1) << (prec - count - HOST_BITS_PER_WIDE_INT));
- *hv |= signmask << (prec - count - HOST_BITS_PER_WIDE_INT);
+ *hv &= ~((HOST_WIDE_INT) (-1) << (prec - HOST_BITS_PER_WIDE_INT));
+ *hv |= signmask << (prec - HOST_BITS_PER_WIDE_INT);
}
else
{
*hv = signmask;
- *lv &= ~((unsigned HOST_WIDE_INT) (-1) << (prec - count));
- *lv |= signmask << (prec - count);
+ *lv &= ~((unsigned HOST_WIDE_INT) (-1) << prec);
+ *lv |= signmask << prec;
}
}
@@ -895,7 +889,7 @@ double_int
double_int_rshift (double_int a, HOST_WIDE_INT count, unsigned int prec, bool arith)
{
double_int ret;
- rshift_double (a.low, a.high, count, prec, &ret.low, &ret.high, arith);
+ lshift_double (a.low, a.high, -count, prec, &ret.low, &ret.high, arith);
return ret;
}