summaryrefslogtreecommitdiff
path: root/gcc/expmed.c
diff options
context:
space:
mode:
Diffstat (limited to 'gcc/expmed.c')
-rw-r--r--gcc/expmed.c160
1 files changed, 52 insertions, 108 deletions
diff --git a/gcc/expmed.c b/gcc/expmed.c
index c5123cbbe81..cca7a0df9fb 100644
--- a/gcc/expmed.c
+++ b/gcc/expmed.c
@@ -56,7 +56,6 @@ static void store_split_bit_field (rtx, unsigned HOST_WIDE_INT,
static rtx extract_fixed_bit_field (enum machine_mode, rtx,
unsigned HOST_WIDE_INT,
unsigned HOST_WIDE_INT, rtx, int);
-static rtx mask_rtx (enum machine_mode, int, int, int);
static rtx lshift_value (enum machine_mode, unsigned HOST_WIDE_INT, int);
static rtx extract_split_bit_field (rtx, unsigned HOST_WIDE_INT,
unsigned HOST_WIDE_INT, int);
@@ -64,6 +63,19 @@ static void do_cmp_and_jump (rtx, rtx, enum rtx_code, enum machine_mode, rtx);
static rtx expand_smod_pow2 (enum machine_mode, rtx, HOST_WIDE_INT);
static rtx expand_sdiv_pow2 (enum machine_mode, rtx, HOST_WIDE_INT);
+/* Return a constant integer mask value of mode MODE with BITSIZE ones
+ followed by BITPOS zeros, or the complement of that if COMPLEMENT.
+ The mask is truncated if necessary to the width of mode MODE. The
+ mask is zero-extended if BITSIZE+BITPOS is too small for MODE. */
+
+static inline rtx
+mask_rtx (enum machine_mode mode, int bitpos, int bitsize, bool complement)
+{
+ return immed_wide_int_const
+ (wi::shifted_mask (bitpos, bitsize, complement,
+ GET_MODE_PRECISION (mode)), mode);
+}
+
/* Test whether a value is zero of a power of two. */
#define EXACT_POWER_OF_2_OR_ZERO_P(x) \
(((x) & ((x) - (unsigned HOST_WIDE_INT) 1)) == 0)
@@ -1817,26 +1829,6 @@ extract_fixed_bit_field (enum machine_mode tmode, rtx op0,
return expand_shift (RSHIFT_EXPR, mode, op0,
GET_MODE_BITSIZE (mode) - bitsize, target, 0);
}
-
-/* Return a constant integer (CONST_INT or CONST_DOUBLE) mask value
- of mode MODE with BITSIZE ones followed by BITPOS zeros, or the
- complement of that if COMPLEMENT. The mask is truncated if
- necessary to the width of mode MODE. The mask is zero-extended if
- BITSIZE+BITPOS is too small for MODE. */
-
-static rtx
-mask_rtx (enum machine_mode mode, int bitpos, int bitsize, int complement)
-{
- double_int mask;
-
- mask = double_int::mask (bitsize);
- mask = mask.llshift (bitpos, HOST_BITS_PER_DOUBLE_INT);
-
- if (complement)
- mask = ~mask;
-
- return immed_double_int_const (mask, mode);
-}
/* Return a constant integer (CONST_INT or CONST_DOUBLE) rtx with the value
VALUE << BITPOS. */
@@ -1845,12 +1837,7 @@ static rtx
lshift_value (enum machine_mode mode, unsigned HOST_WIDE_INT value,
int bitpos)
{
- double_int val;
-
- val = double_int::from_uhwi (value);
- val = val.llshift (bitpos, HOST_BITS_PER_DOUBLE_INT);
-
- return immed_double_int_const (val, mode);
+ return immed_wide_int_const (wi::lshift (value, bitpos), mode);
}
/* Extract a bit field that is split across two words
@@ -3078,38 +3065,22 @@ expand_mult (enum machine_mode mode, rtx op0, rtx op1, rtx target,
only if the constant value exactly fits in an `unsigned int' without
any truncation. This means that multiplying by negative values does
not work; results are off by 2^32 on a 32 bit machine. */
-
if (CONST_INT_P (scalar_op1))
{
coeff = INTVAL (scalar_op1);
is_neg = coeff < 0;
}
+#if TARGET_SUPPORTS_WIDE_INT
+ else if (CONST_WIDE_INT_P (scalar_op1))
+#else
else if (CONST_DOUBLE_AS_INT_P (scalar_op1))
+#endif
{
- /* If we are multiplying in DImode, it may still be a win
- to try to work with shifts and adds. */
- if (CONST_DOUBLE_HIGH (scalar_op1) == 0
- && (CONST_DOUBLE_LOW (scalar_op1) > 0
- || (CONST_DOUBLE_LOW (scalar_op1) < 0
- && EXACT_POWER_OF_2_OR_ZERO_P
- (CONST_DOUBLE_LOW (scalar_op1)))))
- {
- coeff = CONST_DOUBLE_LOW (scalar_op1);
- is_neg = false;
- }
- else if (CONST_DOUBLE_LOW (scalar_op1) == 0)
- {
- coeff = CONST_DOUBLE_HIGH (scalar_op1);
- if (EXACT_POWER_OF_2_OR_ZERO_P (coeff))
- {
- int shift = floor_log2 (coeff) + HOST_BITS_PER_WIDE_INT;
- if (shift < HOST_BITS_PER_DOUBLE_INT - 1
- || mode_bitsize <= HOST_BITS_PER_DOUBLE_INT)
- return expand_shift (LSHIFT_EXPR, mode, op0,
- shift, target, unsignedp);
- }
- goto skip_synth;
- }
+ int shift = wi::exact_log2 (std::make_pair (scalar_op1, mode));
+ /* Perfect power of 2 (other than 1, which is handled above). */
+ if (shift > 0)
+ return expand_shift (LSHIFT_EXPR, mode, op0,
+ shift, target, unsignedp);
else
goto skip_synth;
}
@@ -3286,7 +3257,6 @@ choose_multiplier (unsigned HOST_WIDE_INT d, int n, int precision,
unsigned HOST_WIDE_INT *multiplier_ptr,
int *post_shift_ptr, int *lgup_ptr)
{
- double_int mhigh, mlow;
int lgup, post_shift;
int pow, pow2;
@@ -3298,23 +3268,13 @@ choose_multiplier (unsigned HOST_WIDE_INT d, int n, int precision,
pow = n + lgup;
pow2 = n + lgup - precision;
- /* We could handle this with some effort, but this case is much
- better handled directly with a scc insn, so rely on caller using
- that. */
- gcc_assert (pow != HOST_BITS_PER_DOUBLE_INT);
-
/* mlow = 2^(N + lgup)/d */
- double_int val = double_int_zero.set_bit (pow);
- mlow = val.div (double_int::from_uhwi (d), true, TRUNC_DIV_EXPR);
+ wide_int val = wi::set_bit_in_zero (pow, HOST_BITS_PER_DOUBLE_INT);
+ wide_int mlow = wi::udiv_trunc (val, d);
/* mhigh = (2^(N + lgup) + 2^(N + lgup - precision))/d */
- val |= double_int_zero.set_bit (pow2);
- mhigh = val.div (double_int::from_uhwi (d), true, TRUNC_DIV_EXPR);
-
- gcc_assert (!mhigh.high || val.high - d < d);
- gcc_assert (mhigh.high <= 1 && mlow.high <= 1);
- /* Assert that mlow < mhigh. */
- gcc_assert (mlow.ult (mhigh));
+ val |= wi::set_bit_in_zero (pow2, HOST_BITS_PER_DOUBLE_INT);
+ wide_int mhigh = wi::udiv_trunc (val, d);
/* If precision == N, then mlow, mhigh exceed 2^N
(but they do not exceed 2^(N+1)). */
@@ -3322,14 +3282,15 @@ choose_multiplier (unsigned HOST_WIDE_INT d, int n, int precision,
/* Reduce to lowest terms. */
for (post_shift = lgup; post_shift > 0; post_shift--)
{
- int shft = HOST_BITS_PER_WIDE_INT - 1;
- unsigned HOST_WIDE_INT ml_lo = (mlow.high << shft) | (mlow.low >> 1);
- unsigned HOST_WIDE_INT mh_lo = (mhigh.high << shft) | (mhigh.low >> 1);
+ unsigned HOST_WIDE_INT ml_lo = wi::extract_uhwi (mlow, 1,
+ HOST_BITS_PER_WIDE_INT);
+ unsigned HOST_WIDE_INT mh_lo = wi::extract_uhwi (mhigh, 1,
+ HOST_BITS_PER_WIDE_INT);
if (ml_lo >= mh_lo)
break;
- mlow = double_int::from_uhwi (ml_lo);
- mhigh = double_int::from_uhwi (mh_lo);
+ mlow = wi::uhwi (ml_lo, HOST_BITS_PER_DOUBLE_INT);
+ mhigh = wi::uhwi (mh_lo, HOST_BITS_PER_DOUBLE_INT);
}
*post_shift_ptr = post_shift;
@@ -3337,13 +3298,13 @@ choose_multiplier (unsigned HOST_WIDE_INT d, int n, int precision,
if (n < HOST_BITS_PER_WIDE_INT)
{
unsigned HOST_WIDE_INT mask = ((unsigned HOST_WIDE_INT) 1 << n) - 1;
- *multiplier_ptr = mhigh.low & mask;
- return mhigh.low >= mask;
+ *multiplier_ptr = mhigh.to_uhwi () & mask;
+ return mhigh.to_uhwi () >= mask;
}
else
{
- *multiplier_ptr = mhigh.low;
- return mhigh.high;
+ *multiplier_ptr = mhigh.to_uhwi ();
+ return wi::extract_uhwi (mhigh, HOST_BITS_PER_WIDE_INT, 1);
}
}
@@ -3610,9 +3571,9 @@ expmed_mult_highpart (enum machine_mode mode, rtx op0, rtx op1,
static rtx
expand_smod_pow2 (enum machine_mode mode, rtx op0, HOST_WIDE_INT d)
{
- unsigned HOST_WIDE_INT masklow, maskhigh;
rtx result, temp, shift, label;
int logd;
+ int prec = GET_MODE_PRECISION (mode);
logd = floor_log2 (d);
result = gen_reg_rtx (mode);
@@ -3625,8 +3586,8 @@ expand_smod_pow2 (enum machine_mode mode, rtx op0, HOST_WIDE_INT d)
mode, 0, -1);
if (signmask)
{
+ HOST_WIDE_INT masklow = ((HOST_WIDE_INT) 1 << logd) - 1;
signmask = force_reg (mode, signmask);
- masklow = ((HOST_WIDE_INT) 1 << logd) - 1;
shift = GEN_INT (GET_MODE_BITSIZE (mode) - logd);
/* Use the rtx_cost of a LSHIFTRT instruction to determine
@@ -3673,19 +3634,11 @@ expand_smod_pow2 (enum machine_mode mode, rtx op0, HOST_WIDE_INT d)
modulus. By including the signbit in the operation, many targets
can avoid an explicit compare operation in the following comparison
against zero. */
-
- masklow = ((HOST_WIDE_INT) 1 << logd) - 1;
- if (GET_MODE_BITSIZE (mode) <= HOST_BITS_PER_WIDE_INT)
- {
- masklow |= HOST_WIDE_INT_M1U << (GET_MODE_BITSIZE (mode) - 1);
- maskhigh = -1;
- }
- else
- maskhigh = HOST_WIDE_INT_M1U
- << (GET_MODE_BITSIZE (mode) - HOST_BITS_PER_WIDE_INT - 1);
+ wide_int mask = wi::mask (logd, false, prec);
+ mask = wi::set_bit (mask, prec - 1);
temp = expand_binop (mode, and_optab, op0,
- immed_double_const (masklow, maskhigh, mode),
+ immed_wide_int_const (mask, mode),
result, 1, OPTAB_LIB_WIDEN);
if (temp != result)
emit_move_insn (result, temp);
@@ -3695,10 +3648,10 @@ expand_smod_pow2 (enum machine_mode mode, rtx op0, HOST_WIDE_INT d)
temp = expand_binop (mode, sub_optab, result, const1_rtx, result,
0, OPTAB_LIB_WIDEN);
- masklow = HOST_WIDE_INT_M1U << logd;
- maskhigh = -1;
+
+ mask = wi::mask (logd, true, prec);
temp = expand_binop (mode, ior_optab, temp,
- immed_double_const (masklow, maskhigh, mode),
+ immed_wide_int_const (mask, mode),
result, 1, OPTAB_LIB_WIDEN);
temp = expand_binop (mode, add_optab, temp, const1_rtx, result,
0, OPTAB_LIB_WIDEN);
@@ -4942,24 +4895,15 @@ make_tree (tree type, rtx x)
switch (GET_CODE (x))
{
case CONST_INT:
- {
- HOST_WIDE_INT hi = 0;
-
- if (INTVAL (x) < 0
- && !(TYPE_UNSIGNED (type)
- && (GET_MODE_BITSIZE (TYPE_MODE (type))
- < HOST_BITS_PER_WIDE_INT)))
- hi = -1;
-
- t = build_int_cst_wide (type, INTVAL (x), hi);
-
- return t;
- }
+ case CONST_WIDE_INT:
+ t = wide_int_to_tree (type, std::make_pair (x, TYPE_MODE (type)));
+ return t;
case CONST_DOUBLE:
- if (GET_MODE (x) == VOIDmode)
- t = build_int_cst_wide (type,
- CONST_DOUBLE_LOW (x), CONST_DOUBLE_HIGH (x));
+ if (TARGET_SUPPORTS_WIDE_INT == 0 && GET_MODE (x) == VOIDmode)
+ t = wide_int_to_tree (type,
+ wide_int::from_array (&CONST_DOUBLE_LOW (x), 2,
+ HOST_BITS_PER_WIDE_INT * 2));
else
{
REAL_VALUE_TYPE d;