summaryrefslogtreecommitdiffstats
path: root/contrib/gcc/expmed.c
diff options
context:
space:
mode:
authorkan <kan@FreeBSD.org>2003-07-11 03:40:53 +0000
committerkan <kan@FreeBSD.org>2003-07-11 03:40:53 +0000
commitb2a8872fbe1ec1c49094559ac7b78e6ea4ab7180 (patch)
treef6b0610f4a17fd26aa234354f050080f789861a4 /contrib/gcc/expmed.c
parent52e69d78eee5612ac195e0701a5cebe40d1ab0e1 (diff)
downloadFreeBSD-src-b2a8872fbe1ec1c49094559ac7b78e6ea4ab7180.zip
FreeBSD-src-b2a8872fbe1ec1c49094559ac7b78e6ea4ab7180.tar.gz
Gcc 3.3.1-pre as of 2003-07-11.
Diffstat (limited to 'contrib/gcc/expmed.c')
-rw-r--r--contrib/gcc/expmed.c190
1 files changed, 114 insertions, 76 deletions
diff --git a/contrib/gcc/expmed.c b/contrib/gcc/expmed.c
index ce89335..2274bda 100644
--- a/contrib/gcc/expmed.c
+++ b/contrib/gcc/expmed.c
@@ -33,6 +33,7 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA
#include "optabs.h"
#include "real.h"
#include "recog.h"
+#include "langhooks.h"
static void store_fixed_bit_field PARAMS ((rtx, unsigned HOST_WIDE_INT,
unsigned HOST_WIDE_INT,
@@ -53,7 +54,7 @@ static rtx extract_split_bit_field PARAMS ((rtx, unsigned HOST_WIDE_INT,
static void do_cmp_and_jump PARAMS ((rtx, rtx, enum rtx_code,
enum machine_mode, rtx));
-/* Non-zero means divides or modulus operations are relatively cheap for
+/* Nonzero means divides or modulus operations are relatively cheap for
powers of two, so don't use branches; emit the operation instead.
Usually, this will mean that the MD file will emit non-branch
sequences. */
@@ -103,16 +104,15 @@ static int mul_highpart_cost[NUM_MACHINE_MODES];
void
init_expmed ()
{
- /* This is "some random pseudo register" for purposes of calling recog
- to see what insns exist. */
- rtx reg = gen_rtx_REG (word_mode, 10000);
- rtx shift_insn, shiftadd_insn, shiftsub_insn;
+ rtx reg, shift_insn, shiftadd_insn, shiftsub_insn;
int dummy;
int m;
enum machine_mode mode, wider_mode;
start_sequence ();
+ /* This is "some random pseudo register" for purposes of calling recog
+ to see what insns exist. */
reg = gen_rtx_REG (word_mode, 10000);
zero_cost = rtx_cost (const0_rtx, 0);
@@ -143,19 +143,18 @@ init_expmed ()
for (m = 1; m < MAX_BITS_PER_WORD; m++)
{
+ rtx c_int = GEN_INT ((HOST_WIDE_INT) 1 << m);
shift_cost[m] = shiftadd_cost[m] = shiftsub_cost[m] = 32000;
XEXP (SET_SRC (PATTERN (shift_insn)), 1) = GEN_INT (m);
if (recog (PATTERN (shift_insn), shift_insn, &dummy) >= 0)
shift_cost[m] = rtx_cost (SET_SRC (PATTERN (shift_insn)), SET);
- XEXP (XEXP (SET_SRC (PATTERN (shiftadd_insn)), 0), 1)
- = GEN_INT ((HOST_WIDE_INT) 1 << m);
+ XEXP (XEXP (SET_SRC (PATTERN (shiftadd_insn)), 0), 1) = c_int;
if (recog (PATTERN (shiftadd_insn), shiftadd_insn, &dummy) >= 0)
shiftadd_cost[m] = rtx_cost (SET_SRC (PATTERN (shiftadd_insn)), SET);
- XEXP (XEXP (SET_SRC (PATTERN (shiftsub_insn)), 0), 1)
- = GEN_INT ((HOST_WIDE_INT) 1 << m);
+ XEXP (XEXP (SET_SRC (PATTERN (shiftsub_insn)), 0), 1) = c_int;
if (recog (PATTERN (shiftsub_insn), shiftsub_insn, &dummy) >= 0)
shiftsub_cost[m] = rtx_cost (SET_SRC (PATTERN (shiftsub_insn)), SET);
}
@@ -347,7 +346,7 @@ store_bit_field (str_rtx, bitsize, bitnum, fieldmode, value, total_size)
&& (GET_CODE (op0) != MEM
? ((GET_MODE_SIZE (fieldmode) >= UNITS_PER_WORD
|| GET_MODE_SIZE (GET_MODE (op0)) == GET_MODE_SIZE (fieldmode))
- && byte_offset % GET_MODE_SIZE (fieldmode) == 0)
+ && byte_offset % GET_MODE_SIZE (fieldmode) == 0)
: (! SLOW_UNALIGNED_ACCESS (fieldmode, MEM_ALIGN (op0))
|| (offset * BITS_PER_UNIT % bitsize == 0
&& MEM_ALIGN (op0) % GET_MODE_BITSIZE (fieldmode) == 0))))
@@ -535,7 +534,9 @@ store_bit_field (str_rtx, bitsize, bitnum, fieldmode, value, total_size)
structure fields. */
if (GET_MODE_CLASS (GET_MODE (value)) != MODE_INT
&& GET_MODE_CLASS (GET_MODE (value)) != MODE_PARTIAL_INT)
- value = gen_lowpart (word_mode, value);
+ value = gen_lowpart ((GET_MODE (value) == VOIDmode
+ ? word_mode : int_mode_for_mode (GET_MODE (value))),
+ value);
/* Now OFFSET is nonzero only if OP0 is memory
and is therefore always measured in bytes. */
@@ -656,7 +657,7 @@ store_bit_field (str_rtx, bitsize, bitnum, fieldmode, value, total_size)
value1 = gen_lowpart (maxmode, value1);
}
else if (GET_CODE (value) == CONST_INT)
- value1 = GEN_INT (trunc_int_for_mode (INTVAL (value), maxmode));
+ value1 = gen_int_mode (INTVAL (value), maxmode);
else if (!CONSTANT_P (value))
/* Parse phase is supposed to make VALUE's data type
match that of the component reference, which is a type
@@ -675,7 +676,7 @@ store_bit_field (str_rtx, bitsize, bitnum, fieldmode, value, total_size)
if (pat)
emit_insn (pat);
else
- {
+ {
delete_insns_since (last);
store_fixed_bit_field (op0, offset, bitsize, bitpos, value);
}
@@ -737,8 +738,8 @@ store_fixed_bit_field (op0, offset, bitsize, bitpos, value)
mode = GET_MODE (op0);
if (GET_MODE_BITSIZE (mode) == 0
- || GET_MODE_BITSIZE (mode) > GET_MODE_BITSIZE (word_mode))
- mode = word_mode;
+ || GET_MODE_BITSIZE (mode) > GET_MODE_BITSIZE (word_mode))
+ mode = word_mode;
mode = get_best_mode (bitsize, bitpos + offset * BITS_PER_UNIT,
MEM_ALIGN (op0), mode, MEM_VOLATILE_P (op0));
@@ -1032,25 +1033,15 @@ extract_bit_field (str_rtx, bitsize, bitnum, unsignedp,
if (tmode == VOIDmode)
tmode = mode;
+
while (GET_CODE (op0) == SUBREG)
{
- int outer_size = GET_MODE_BITSIZE (GET_MODE (op0));
- int inner_size = GET_MODE_BITSIZE (GET_MODE (SUBREG_REG (op0)));
-
- offset += SUBREG_BYTE (op0) / UNITS_PER_WORD;
-
- inner_size = MIN (inner_size, BITS_PER_WORD);
-
- if (BYTES_BIG_ENDIAN && (outer_size < inner_size))
+ bitpos += SUBREG_BYTE (op0) * BITS_PER_UNIT;
+ if (bitpos > unit)
{
- bitpos += inner_size - outer_size;
- if (bitpos > unit)
- {
- offset += (bitpos / unit);
- bitpos %= unit;
- }
+ offset += (bitpos / unit);
+ bitpos %= unit;
}
-
op0 = SUBREG_REG (op0);
}
@@ -1087,9 +1078,13 @@ extract_bit_field (str_rtx, bitsize, bitnum, unsignedp,
set_mem_expr (op0, 0);
}
- /* ??? We currently assume TARGET is at least as big as BITSIZE.
- If that's wrong, the solution is to test for it and set TARGET to 0
- if needed. */
+ /* Extraction of a full-word or multi-word value from a structure
+ in a register or aligned memory can be done with just a SUBREG.
+ A subword value in the least significant part of a register
+ can also be extracted with a SUBREG. For this, we need the
+ byte offset of the value in op0. */
+
+ byte_offset = bitpos / BITS_PER_UNIT + offset * UNITS_PER_WORD;
/* If OP0 is a register, BITPOS must count within a word.
But as we have it, it counts within whatever size OP0 now has.
@@ -1099,18 +1094,13 @@ extract_bit_field (str_rtx, bitsize, bitnum, unsignedp,
&& unit > GET_MODE_BITSIZE (GET_MODE (op0)))
bitpos += unit - GET_MODE_BITSIZE (GET_MODE (op0));
- /* Extracting a full-word or multi-word value
- from a structure in a register or aligned memory.
- This can be done with just SUBREG.
- So too extracting a subword value in
- the least significant part of the register. */
-
- byte_offset = (bitnum % BITS_PER_WORD) / BITS_PER_UNIT
- + (offset * UNITS_PER_WORD);
+ /* ??? We currently assume TARGET is at least as big as BITSIZE.
+ If that's wrong, the solution is to test for it and set TARGET to 0
+ if needed. */
mode1 = (VECTOR_MODE_P (tmode)
- ? mode
- : mode_for_size (bitsize, GET_MODE_CLASS (tmode), 0));
+ ? mode
+ : mode_for_size (bitsize, GET_MODE_CLASS (tmode), 0));
if (((GET_CODE (op0) != MEM
&& TRULY_NOOP_TRUNCATION (GET_MODE_BITSIZE (mode),
@@ -1928,12 +1918,12 @@ expand_shift (code, mode, shifted, amount, target, unsignedp)
if (SHIFT_COUNT_TRUNCATED)
{
if (GET_CODE (op1) == CONST_INT
- && ((unsigned HOST_WIDE_INT) INTVAL (op1) >=
+ && ((unsigned HOST_WIDE_INT) INTVAL (op1) >=
(unsigned HOST_WIDE_INT) GET_MODE_BITSIZE (mode)))
- op1 = GEN_INT ((unsigned HOST_WIDE_INT) INTVAL (op1)
+ op1 = GEN_INT ((unsigned HOST_WIDE_INT) INTVAL (op1)
% GET_MODE_BITSIZE (mode));
else if (GET_CODE (op1) == SUBREG
- && SUBREG_BYTE (op1) == 0)
+ && subreg_lowpart_p (op1))
op1 = SUBREG_REG (op1);
}
#endif
@@ -2566,8 +2556,8 @@ expand_mult (mode, op0, op1, target, unsignedp)
there is no difference between signed and unsigned. */
op0 = expand_binop (mode,
! unsignedp
- && flag_trapv && (GET_MODE_CLASS(mode) == MODE_INT)
- ? smulv_optab : smul_optab,
+ && flag_trapv && (GET_MODE_CLASS(mode) == MODE_INT)
+ ? smulv_optab : smul_optab,
op0, op1, target, unsignedp, OPTAB_LIB_WIDEN);
if (op0 == 0)
abort ();
@@ -2790,7 +2780,7 @@ expand_mult_highpart (mode, op0, cnst1, target, unsignedp, max_cost)
if (size > HOST_BITS_PER_WIDE_INT)
abort ();
- op1 = GEN_INT (trunc_int_for_mode (cnst1, mode));
+ op1 = gen_int_mode (cnst1, mode);
wide_op1
= immed_double_const (cnst1,
@@ -2932,7 +2922,7 @@ expand_mult_highpart (mode, op0, cnst1, target, unsignedp, max_cost)
the result is exact for inputs up to 0x1fffffff.
The input range can be reduced by using cross-sum rules.
For odd divisors >= 3, the following table gives right shift counts
- so that if an number is shifted by an integer multiple of the given
+ so that if a number is shifted by an integer multiple of the given
amount, the remainder stays the same:
2, 4, 3, 6, 10, 12, 4, 8, 18, 6, 11, 20, 18, 0, 5, 10, 12, 0, 12, 20,
14, 12, 23, 21, 8, 0, 20, 18, 0, 0, 6, 12, 0, 22, 0, 18, 20, 30, 0, 0,
@@ -3012,9 +3002,9 @@ expand_divmod (rem_flag, code, mode, op0, op1, target, unsignedp)
if (! unsignedp && op1 == constm1_rtx)
{
if (rem_flag)
- return const0_rtx;
+ return const0_rtx;
return expand_unop (mode, flag_trapv && GET_MODE_CLASS(mode) == MODE_INT
- ? negv_optab : neg_optab, op0, target, 0);
+ ? negv_optab : neg_optab, op0, target, 0);
}
if (target
@@ -3277,7 +3267,7 @@ expand_divmod (rem_flag, code, mode, op0, op1, target, unsignedp)
if (rem_flag && d < 0)
{
d = abs_d;
- op1 = GEN_INT (trunc_int_for_mode (abs_d, compute_mode));
+ op1 = gen_int_mode (abs_d, compute_mode);
}
if (d == 1)
@@ -3316,8 +3306,8 @@ expand_divmod (rem_flag, code, mode, op0, op1, target, unsignedp)
t1 = copy_to_mode_reg (compute_mode, op0);
do_cmp_and_jump (t1, const0_rtx, GE,
compute_mode, label);
- expand_inc (t1, GEN_INT (trunc_int_for_mode
- (abs_d - 1, compute_mode)));
+ expand_inc (t1, gen_int_mode (abs_d - 1,
+ compute_mode));
emit_label (label);
quotient = expand_shift (RSHIFT_EXPR, compute_mode, t1,
build_int_2 (lgup, 0),
@@ -3857,8 +3847,7 @@ expand_divmod (rem_flag, code, mode, op0, op1, target, unsignedp)
t1 = expand_shift (RSHIFT_EXPR, compute_mode, op0,
build_int_2 (pre_shift, 0), NULL_RTX, unsignedp);
quotient = expand_mult (compute_mode, t1,
- GEN_INT (trunc_int_for_mode
- (ml, compute_mode)),
+ gen_int_mode (ml, compute_mode),
NULL_RTX, 0);
insn = get_last_insn ();
@@ -4112,21 +4101,22 @@ make_tree (type, x)
make_tree (type, XEXP (x, 1))));
case LSHIFTRT:
+ t = (*lang_hooks.types.unsigned_type) (type);
return fold (convert (type,
- build (RSHIFT_EXPR, unsigned_type (type),
- make_tree (unsigned_type (type),
- XEXP (x, 0)),
+ build (RSHIFT_EXPR, t,
+ make_tree (t, XEXP (x, 0)),
make_tree (type, XEXP (x, 1)))));
case ASHIFTRT:
+ t = (*lang_hooks.types.signed_type) (type);
return fold (convert (type,
- build (RSHIFT_EXPR, signed_type (type),
- make_tree (signed_type (type), XEXP (x, 0)),
+ build (RSHIFT_EXPR, t,
+ make_tree (t, XEXP (x, 0)),
make_tree (type, XEXP (x, 1)))));
case DIV:
if (TREE_CODE (type) != REAL_TYPE)
- t = signed_type (type);
+ t = (*lang_hooks.types.signed_type) (type);
else
t = type;
@@ -4135,7 +4125,7 @@ make_tree (type, x)
make_tree (t, XEXP (x, 0)),
make_tree (t, XEXP (x, 1)))));
case UDIV:
- t = unsigned_type (type);
+ t = (*lang_hooks.types.unsigned_type) (type);
return fold (convert (type,
build (TRUNC_DIV_EXPR, t,
make_tree (t, XEXP (x, 0)),
@@ -4143,7 +4133,8 @@ make_tree (type, x)
case SIGN_EXTEND:
case ZERO_EXTEND:
- t = type_for_mode (GET_MODE (XEXP (x, 0)), GET_CODE (x) == ZERO_EXTEND);
+ t = (*lang_hooks.types.type_for_mode) (GET_MODE (XEXP (x, 0)),
+ GET_CODE (x) == ZERO_EXTEND);
return fold (convert (type, make_tree (t, XEXP (x, 0))));
default:
@@ -4165,12 +4156,50 @@ make_tree (type, x)
}
}
+/* Check whether the multiplication X * MULT + ADD overflows.
+ X, MULT and ADD must be CONST_*.
+ MODE is the machine mode for the computation.
+ X and MULT must have mode MODE. ADD may have a different mode.
+ So can X (defaults to same as MODE).
+ UNSIGNEDP is nonzero to do unsigned multiplication. */
+
+bool
+const_mult_add_overflow_p (x, mult, add, mode, unsignedp)
+ rtx x, mult, add;
+ enum machine_mode mode;
+ int unsignedp;
+{
+ tree type, mult_type, add_type, result;
+
+ type = (*lang_hooks.types.type_for_mode) (mode, unsignedp);
+
+ /* In order to get a proper overflow indication from an unsigned
+ type, we have to pretend that it's a sizetype. */
+ mult_type = type;
+ if (unsignedp)
+ {
+ mult_type = copy_node (type);
+ TYPE_IS_SIZETYPE (mult_type) = 1;
+ }
+
+ add_type = (GET_MODE (add) == VOIDmode ? mult_type
+ : (*lang_hooks.types.type_for_mode) (GET_MODE (add), unsignedp));
+
+ result = fold (build (PLUS_EXPR, mult_type,
+ fold (build (MULT_EXPR, mult_type,
+ make_tree (mult_type, x),
+ make_tree (mult_type, mult))),
+ make_tree (add_type, add)));
+
+ return TREE_CONSTANT_OVERFLOW (result);
+}
+
/* Return an rtx representing the value of X * MULT + ADD.
TARGET is a suggestion for where to store the result (an rtx).
MODE is the machine mode for the computation.
X and MULT must have mode MODE. ADD may have a different mode.
So can X (defaults to same as MODE).
- UNSIGNEDP is non-zero to do unsigned multiplication.
+ UNSIGNEDP is nonzero to do unsigned multiplication.
This may emit insns. */
rtx
@@ -4179,9 +4208,10 @@ expand_mult_add (x, target, mult, add, mode, unsignedp)
enum machine_mode mode;
int unsignedp;
{
- tree type = type_for_mode (mode, unsignedp);
+ tree type = (*lang_hooks.types.type_for_mode) (mode, unsignedp);
tree add_type = (GET_MODE (add) == VOIDmode
- ? type : type_for_mode (GET_MODE (add), unsignedp));
+ ? type: (*lang_hooks.types.type_for_mode) (GET_MODE (add),
+ unsignedp));
tree result = fold (build (PLUS_EXPR, type,
fold (build (MULT_EXPR, type,
make_tree (type, x),
@@ -4311,19 +4341,27 @@ emit_store_flag (target, code, op0, op1, mode, unsignedp, normalizep)
{
if (code == EQ || code == NE)
{
+ rtx op00, op01, op0both;
+
/* Do a logical OR of the two words and compare the result. */
- rtx op0h = gen_highpart (word_mode, op0);
- rtx op0l = gen_lowpart (word_mode, op0);
- rtx op0both = expand_binop (word_mode, ior_optab, op0h, op0l,
- NULL_RTX, unsignedp, OPTAB_DIRECT);
+ op00 = simplify_gen_subreg (word_mode, op0, mode, 0);
+ op01 = simplify_gen_subreg (word_mode, op0, mode, UNITS_PER_WORD);
+ op0both = expand_binop (word_mode, ior_optab, op00, op01,
+ NULL_RTX, unsignedp, OPTAB_DIRECT);
if (op0both != 0)
return emit_store_flag (target, code, op0both, op1, word_mode,
unsignedp, normalizep);
}
else if (code == LT || code == GE)
- /* If testing the sign bit, can just test on high word. */
- return emit_store_flag (target, code, gen_highpart (word_mode, op0),
- op1, word_mode, unsignedp, normalizep);
+ {
+ rtx op0h;
+
+ /* If testing the sign bit, can just test on high word. */
+ op0h = simplify_gen_subreg (word_mode, op0, mode,
+ subreg_highpart_offset (word_mode, mode));
+ return emit_store_flag (target, code, op0h, op1, word_mode,
+ unsignedp, normalizep);
+ }
}
/* From now on, we won't change CODE, so set ICODE now. */
@@ -4583,7 +4621,7 @@ emit_store_flag (target, code, op0, op1, mode, unsignedp, normalizep)
if (code == EQ || code == NE)
{
/* For EQ or NE, one way to do the comparison is to apply an operation
- that converts the operand into a positive number if it is non-zero
+ that converts the operand into a positive number if it is nonzero
or zero if it was originally zero. Then, for EQ, we subtract 1 and
for NE we negate. This puts the result in the sign bit. Then we
normalize with a shift, if needed.
OpenPOWER on IntegriCloud