summaryrefslogtreecommitdiffstats
path: root/contrib/gcc/expmed.c
diff options
context:
space:
mode:
authorobrien <obrien@FreeBSD.org>2002-05-09 20:02:13 +0000
committerobrien <obrien@FreeBSD.org>2002-05-09 20:02:13 +0000
commitc8f5fc7032940ad6633f932ac40cade82ec4d0cc (patch)
tree29a0f0a6c79a69ecc64f612947a0fe5904311713 /contrib/gcc/expmed.c
parentc9ab9ae440a8066b2c2b85b157b1fdadcf09916a (diff)
downloadFreeBSD-src-c8f5fc7032940ad6633f932ac40cade82ec4d0cc.zip
FreeBSD-src-c8f5fc7032940ad6633f932ac40cade82ec4d0cc.tar.gz
Gcc 3.1.0 pre-release from the FSF anoncvs repo on 9-May-2002 15:57:15 EDT.
Diffstat (limited to 'contrib/gcc/expmed.c')
-rw-r--r--contrib/gcc/expmed.c204
1 files changed, 122 insertions, 82 deletions
diff --git a/contrib/gcc/expmed.c b/contrib/gcc/expmed.c
index 53ff05b..7836de7 100644
--- a/contrib/gcc/expmed.c
+++ b/contrib/gcc/expmed.c
@@ -54,7 +54,7 @@ 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
- powers of two, so don't use branches; emit the operation instead.
+ 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. */
@@ -299,6 +299,7 @@ store_bit_field (str_rtx, bitsize, bitnum, fieldmode, value, total_size)
unsigned HOST_WIDE_INT offset = bitnum / unit;
unsigned HOST_WIDE_INT bitpos = bitnum % unit;
rtx op0 = str_rtx;
+ int byte_offset;
enum machine_mode op_mode = mode_for_extraction (EP_insv, 3);
@@ -324,7 +325,12 @@ store_bit_field (str_rtx, bitsize, bitnum, fieldmode, value, total_size)
value = protect_from_queue (value, 0);
if (flag_force_mem)
- value = force_not_mem (value);
+ {
+ int old_generating_concat_p = generating_concat_p;
+ generating_concat_p = 0;
+ value = force_not_mem (value);
+ generating_concat_p = old_generating_concat_p;
+ }
/* If the target is a register, overwriting the entire object, or storing
a full-word or multi-word field can be done with just a SUBREG.
@@ -332,12 +338,16 @@ store_bit_field (str_rtx, bitsize, bitnum, fieldmode, value, total_size)
If the target is memory, storing any naturally aligned field can be
done with a simple store. For targets that support fast unaligned
memory, any naturally sized, unit aligned field can be done directly. */
-
+
+ byte_offset = (bitnum % BITS_PER_WORD) / BITS_PER_UNIT
+ + (offset * UNITS_PER_WORD);
+
if (bitpos == 0
&& bitsize == GET_MODE_BITSIZE (fieldmode)
&& (GET_CODE (op0) != MEM
- ? (GET_MODE_SIZE (fieldmode) >= UNITS_PER_WORD
+ ? ((GET_MODE_SIZE (fieldmode) >= UNITS_PER_WORD
|| GET_MODE_SIZE (GET_MODE (op0)) == GET_MODE_SIZE (fieldmode))
+ && 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))))
@@ -357,9 +367,7 @@ store_bit_field (str_rtx, bitsize, bitnum, fieldmode, value, total_size)
abort ();
}
if (GET_CODE (op0) == REG)
- op0 = gen_rtx_SUBREG (fieldmode, op0,
- (bitnum % BITS_PER_WORD) / BITS_PER_UNIT
- + (offset * UNITS_PER_WORD));
+ op0 = gen_rtx_SUBREG (fieldmode, op0, byte_offset);
else
op0 = adjust_address (op0, fieldmode, offset);
}
@@ -384,6 +392,15 @@ store_bit_field (str_rtx, bitsize, bitnum, fieldmode, value, total_size)
}
}
+ /* We may be accessing data outside the field, which means
+ we can alias adjacent data. */
+ if (GET_CODE (op0) == MEM)
+ {
+ op0 = shallow_copy_rtx (op0);
+ set_mem_alias_set (op0, 0);
+ set_mem_expr (op0, 0);
+ }
+
/* If OP0 is a register, BITPOS must count within a word.
But as we have it, it counts within whatever size OP0 now has.
On a bigendian machine, these are not the same, so convert. */
@@ -516,12 +533,9 @@ store_bit_field (str_rtx, bitsize, bitnum, fieldmode, value, total_size)
corresponding size. This can occur on a machine with 64 bit registers
that uses SFmode for float. This can also occur for unaligned float
structure fields. */
- if (GET_MODE_CLASS (GET_MODE (value)) == MODE_FLOAT)
- {
- if (GET_CODE (value) != REG)
- value = copy_to_reg (value);
- value = gen_rtx_SUBREG (word_mode, value, 0);
- }
+ if (GET_MODE_CLASS (GET_MODE (value)) != MODE_INT
+ && GET_MODE_CLASS (GET_MODE (value)) != MODE_PARTIAL_INT)
+ value = gen_lowpart (word_mode, value);
/* Now OFFSET is nonzero only if OP0 is memory
and is therefore always measured in bytes. */
@@ -573,7 +587,7 @@ store_bit_field (str_rtx, bitsize, bitnum, fieldmode, value, total_size)
&& GET_MODE_BITSIZE (bestmode) > MEM_ALIGN (op0)))
goto insv_loses;
- /* Adjust address to point to the containing unit of that mode.
+ /* Adjust address to point to the containing unit of that mode.
Compute offset as multiple of this unit, counting in bytes. */
unit = GET_MODE_BITSIZE (bestmode);
offset = (bitnum / unit) * GET_MODE_SIZE (bestmode);
@@ -627,8 +641,17 @@ store_bit_field (str_rtx, bitsize, bitnum, fieldmode, value, total_size)
if we must narrow it, be sure we do it correctly. */
if (GET_MODE_SIZE (GET_MODE (value)) < GET_MODE_SIZE (maxmode))
- value1 = simplify_gen_subreg (maxmode, value1,
- GET_MODE (value1), 0);
+ {
+ rtx tmp;
+
+ tmp = simplify_subreg (maxmode, value1, GET_MODE (value), 0);
+ if (! tmp)
+ tmp = simplify_gen_subreg (maxmode,
+ force_reg (GET_MODE (value),
+ value1),
+ GET_MODE (value), 0);
+ value1 = tmp;
+ }
else
value1 = gen_lowpart (maxmode, value1);
}
@@ -709,7 +732,7 @@ store_fixed_bit_field (op0, offset, bitsize, bitpos, value)
{
/* Get the proper mode to use for this field. We want a mode that
includes the entire field. If such a mode would be larger than
- a word, we won't be doing the extraction the normal way.
+ a word, we won't be doing the extraction the normal way.
We don't want a mode bigger than the destination. */
mode = GET_MODE (op0);
@@ -1055,10 +1078,19 @@ extract_bit_field (str_rtx, bitsize, bitnum, unsignedp,
}
}
+ /* We may be accessing data outside the field, which means
+ we can alias adjacent data. */
+ if (GET_CODE (op0) == MEM)
+ {
+ op0 = shallow_copy_rtx (op0);
+ set_mem_alias_set (op0, 0);
+ 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. */
-
+
/* If OP0 is a register, BITPOS must count within a word.
But as we have it, it counts within whatever size OP0 now has.
On a bigendian machine, these are not the same, so convert. */
@@ -1125,7 +1157,7 @@ extract_bit_field (str_rtx, bitsize, bitnum, unsignedp,
}
/* Handle fields bigger than a word. */
-
+
if (bitsize > BITS_PER_WORD)
{
/* Here we transfer the words of the field
@@ -1197,14 +1229,14 @@ extract_bit_field (str_rtx, bitsize, bitnum, unsignedp,
build_int_2 (GET_MODE_BITSIZE (mode) - bitsize, 0),
NULL_RTX, 0);
}
-
+
/* From here on we know the desired field is smaller than a word. */
/* Check if there is a correspondingly-sized integer field, so we can
safely extract it as one size of integer, if necessary; then
truncate or extend to the size that is wanted; then use SUBREGs or
convert_to_mode to get one of the modes we really wanted. */
-
+
int_mode = int_mode_for_mode (tmode);
if (int_mode == BLKmode)
int_mode = int_mode_for_mode (mode);
@@ -1363,7 +1395,7 @@ extract_bit_field (str_rtx, bitsize, bitnum, unsignedp,
}
else
extzv_loses:
- target = extract_fixed_bit_field (int_mode, op0, offset, bitsize,
+ target = extract_fixed_bit_field (int_mode, op0, offset, bitsize,
bitpos, target, 1);
}
else
@@ -1489,10 +1521,10 @@ extract_bit_field (str_rtx, bitsize, bitnum, unsignedp,
target = extract_fixed_bit_field (int_mode, op0, offset, bitsize,
bitpos, target, 0);
}
- }
+ }
else
extv_loses:
- target = extract_fixed_bit_field (int_mode, op0, offset, bitsize,
+ target = extract_fixed_bit_field (int_mode, op0, offset, bitsize,
bitpos, target, 0);
}
if (target == spec_target)
@@ -1504,14 +1536,13 @@ extract_bit_field (str_rtx, bitsize, bitnum, unsignedp,
/* If the target mode is floating-point, first convert to the
integer mode of that size and then access it as a floating-point
value via a SUBREG. */
- if (GET_MODE_CLASS (tmode) == MODE_FLOAT)
+ if (GET_MODE_CLASS (tmode) != MODE_INT
+ && GET_MODE_CLASS (tmode) != MODE_PARTIAL_INT)
{
target = convert_to_mode (mode_for_size (GET_MODE_BITSIZE (tmode),
MODE_INT, 0),
target, unsignedp);
- if (GET_CODE (target) != REG)
- target = copy_to_reg (target);
- return gen_rtx_SUBREG (tmode, target, 0);
+ return gen_lowpart (tmode, target);
}
else
return convert_to_mode (tmode, target, unsignedp);
@@ -1657,7 +1688,7 @@ extract_fixed_bit_field (tmode, op0, offset, bitsize, bitpos,
}
return expand_shift (RSHIFT_EXPR, mode, op0,
- build_int_2 (GET_MODE_BITSIZE (mode) - bitsize, 0),
+ build_int_2 (GET_MODE_BITSIZE (mode) - bitsize, 0),
target, 0);
}
@@ -1682,7 +1713,7 @@ mask_rtx (mode, bitpos, bitsize, complement)
if (bitpos + bitsize < HOST_BITS_PER_WIDE_INT)
masklow &= ((unsigned HOST_WIDE_INT) -1
>> (HOST_BITS_PER_WIDE_INT - bitpos - bitsize));
-
+
if (bitpos <= HOST_BITS_PER_WIDE_INT)
maskhigh = -1;
else
@@ -1972,7 +2003,7 @@ expand_shift (code, mode, shifted, amount, target, unsignedp)
&& (unsigned int) INTVAL (op1) < GET_MODE_BITSIZE (mode))
temp = expand_binop (mode,
left ? rotr_optab : rotl_optab,
- shifted,
+ shifted,
GEN_INT (GET_MODE_BITSIZE (mode)
- INTVAL (op1)),
target, unsignedp, methods);
@@ -2003,7 +2034,7 @@ expand_shift (code, mode, shifted, amount, target, unsignedp)
}
/* We used to try extzv here for logical right shifts, but that was
- only useful for one machine, the VAX, and caused poor code
+ only useful for one machine, the VAX, and caused poor code
generation there for lshrdi3, so the code was deleted and a
define_expand for lshrsi3 was added to vax.md. */
}
@@ -2144,7 +2175,7 @@ synth_mult (alg_out, t, cost_limit)
for (w = 1; (w & t) != 0; w <<= 1)
;
/* If T was -1, then W will be zero after the loop. This is another
- case where T ends with ...111. Handling this with (T + 1) and
+ case where T ends with ...111. Handling this with (T + 1) and
subtract 1 produces slightly better code and results in algorithm
selection much faster than treating it like the ...0111 case
below. */
@@ -2424,7 +2455,7 @@ expand_mult (mode, op0, op1, target, unsignedp)
&& ! preserve)
? target : 0;
rtx accum_target = preserve ? 0 : accum;
-
+
switch (alg.op[opno])
{
case alg_shift:
@@ -2506,7 +2537,7 @@ expand_mult (mode, op0, op1, target, unsignedp)
}
insn = get_last_insn ();
- set_unique_reg_note (insn,
+ set_unique_reg_note (insn,
REG_EQUAL,
gen_rtx_MULT (nmode, tem,
GEN_INT (val_so_far)));
@@ -2532,7 +2563,7 @@ expand_mult (mode, op0, op1, target, unsignedp)
/* This used to use umul_optab if unsigned, but for non-widening multiply
there is no difference between signed and unsigned. */
- op0 = expand_binop (mode,
+ op0 = expand_binop (mode,
! unsignedp
&& flag_trapv && (GET_MODE_CLASS(mode) == MODE_INT)
? smulv_optab : smul_optab,
@@ -2714,7 +2745,7 @@ expand_mult_highpart_adjust (mode, adj_operand, op0, op1, target, unsignedp)
tem = expand_shift (RSHIFT_EXPR, mode, op0,
build_int_2 (GET_MODE_BITSIZE (mode) - 1, 0),
NULL_RTX, 0);
- tem = expand_and (tem, op1, NULL_RTX);
+ tem = expand_and (mode, tem, op1, NULL_RTX);
adj_operand
= force_operand (gen_rtx_fmt_ee (adj_code, mode, adj_operand, tem),
adj_operand);
@@ -2722,7 +2753,7 @@ expand_mult_highpart_adjust (mode, adj_operand, op0, op1, target, unsignedp)
tem = expand_shift (RSHIFT_EXPR, mode, op1,
build_int_2 (GET_MODE_BITSIZE (mode) - 1, 0),
NULL_RTX, 0);
- tem = expand_and (tem, op0, NULL_RTX);
+ tem = expand_and (mode, tem, op0, NULL_RTX);
target = force_operand (gen_rtx_fmt_ee (adj_code, mode, adj_operand, tem),
target);
@@ -2760,15 +2791,12 @@ expand_mult_highpart (mode, op0, cnst1, target, unsignedp, max_cost)
op1 = GEN_INT (trunc_int_for_mode (cnst1, mode));
- if (GET_MODE_BITSIZE (wider_mode) <= HOST_BITS_PER_INT)
- wide_op1 = op1;
- else
- wide_op1
- = immed_double_const (cnst1,
- (unsignedp
- ? (HOST_WIDE_INT) 0
- : -(cnst1 >> (HOST_BITS_PER_WIDE_INT - 1))),
- wider_mode);
+ wide_op1
+ = immed_double_const (cnst1,
+ (unsignedp
+ ? (HOST_WIDE_INT) 0
+ : -(cnst1 >> (HOST_BITS_PER_WIDE_INT - 1))),
+ wider_mode);
/* expand_mult handles constant multiplication of word_mode
or narrower. It does a poor job for large modes. */
@@ -2823,7 +2851,7 @@ expand_mult_highpart (mode, op0, cnst1, target, unsignedp, max_cost)
{
op1 = force_reg (mode, op1);
goto try;
- }
+ }
/* Try widening the mode and perform a non-widening multiplication. */
moptab = smul_optab;
@@ -3230,7 +3258,7 @@ expand_divmod (rem_flag, code, mode, op0, op1, target, unsignedp)
if (insn != last
&& (set = single_set (insn)) != 0
&& SET_DEST (set) == quotient)
- set_unique_reg_note (insn,
+ set_unique_reg_note (insn,
REG_EQUAL,
gen_rtx_UDIV (compute_mode, op0, op1));
}
@@ -3318,7 +3346,7 @@ expand_divmod (rem_flag, code, mode, op0, op1, target, unsignedp)
&& SET_DEST (set) == quotient
&& abs_d < ((unsigned HOST_WIDE_INT) 1
<< (HOST_BITS_PER_WIDE_INT - 1)))
- set_unique_reg_note (insn,
+ set_unique_reg_note (insn,
REG_EQUAL,
gen_rtx_DIV (compute_mode,
op0,
@@ -3409,7 +3437,7 @@ expand_divmod (rem_flag, code, mode, op0, op1, target, unsignedp)
if (insn != last
&& (set = single_set (insn)) != 0
&& SET_DEST (set) == quotient)
- set_unique_reg_note (insn,
+ set_unique_reg_note (insn,
REG_EQUAL,
gen_rtx_DIV (compute_mode, op0, op1));
}
@@ -3902,7 +3930,7 @@ expand_divmod (rem_flag, code, mode, op0, op1, target, unsignedp)
emit_label (label);
}
return gen_lowpart (mode, rem_flag ? remainder : quotient);
-
+
default:
abort ();
}
@@ -4041,39 +4069,57 @@ make_tree (type, x)
}
return t;
-
+
+ case CONST_VECTOR:
+ {
+ int i, units;
+ rtx elt;
+ tree t = NULL_TREE;
+
+ units = CONST_VECTOR_NUNITS (x);
+
+ /* Build a tree with vector elements. */
+ for (i = units - 1; i >= 0; --i)
+ {
+ elt = CONST_VECTOR_ELT (x, i);
+ t = tree_cons (NULL_TREE, make_tree (type, elt), t);
+ }
+
+ return build_vector (type, t);
+ }
+
case PLUS:
return fold (build (PLUS_EXPR, type, make_tree (type, XEXP (x, 0)),
make_tree (type, XEXP (x, 1))));
-
+
case MINUS:
return fold (build (MINUS_EXPR, type, make_tree (type, XEXP (x, 0)),
make_tree (type, XEXP (x, 1))));
-
+
case NEG:
return fold (build1 (NEGATE_EXPR, type, make_tree (type, XEXP (x, 0))));
case MULT:
return fold (build (MULT_EXPR, type, make_tree (type, XEXP (x, 0)),
make_tree (type, XEXP (x, 1))));
-
+
case ASHIFT:
return fold (build (LSHIFT_EXPR, type, make_tree (type, XEXP (x, 0)),
make_tree (type, XEXP (x, 1))));
-
+
case LSHIFTRT:
return fold (convert (type,
build (RSHIFT_EXPR, unsigned_type (type),
make_tree (unsigned_type (type),
XEXP (x, 0)),
make_tree (type, XEXP (x, 1)))));
-
+
case ASHIFTRT:
return fold (convert (type,
build (RSHIFT_EXPR, signed_type (type),
make_tree (signed_type (type), XEXP (x, 0)),
make_tree (type, XEXP (x, 1)))));
-
+
case DIV:
if (TREE_CODE (type) != REAL_TYPE)
t = signed_type (type);
@@ -4141,23 +4187,16 @@ expand_mult_add (x, target, mult, add, mode, unsignedp)
If TARGET is 0, a pseudo-register or constant is returned. */
rtx
-expand_and (op0, op1, target)
+expand_and (mode, op0, op1, target)
+ enum machine_mode mode;
rtx op0, op1, target;
{
- enum machine_mode mode = VOIDmode;
- rtx tem;
+ rtx tem = 0;
- if (GET_MODE (op0) != VOIDmode)
- mode = GET_MODE (op0);
- else if (GET_MODE (op1) != VOIDmode)
- mode = GET_MODE (op1);
-
- if (mode != VOIDmode)
+ if (GET_MODE (op0) == VOIDmode && GET_MODE (op1) == VOIDmode)
+ tem = simplify_binary_operation (AND, mode, op0, op1);
+ if (tem == 0)
tem = expand_binop (mode, and_optab, op0, op1, target, 0, OPTAB_LIB_WIDEN);
- else if (GET_CODE (op0) == CONST_INT && GET_CODE (op1) == CONST_INT)
- tem = GEN_INT (INTVAL (op0) & INTVAL (op1));
- else
- abort ();
if (target == 0)
target = tem;
@@ -4171,7 +4210,7 @@ expand_and (op0, op1, target)
Return 0 if that cannot be done.
MODE is the mode to use for OP0 and OP1 should they be CONST_INTs. If
- it is VOIDmode, they cannot both be CONST_INT.
+ it is VOIDmode, they cannot both be CONST_INT.
UNSIGNEDP is for the case where we have to widen the operands
to perform the operation. It says to use zero-extension.
@@ -4219,7 +4258,7 @@ emit_store_flag (target, code, op0, op1, mode, unsignedp, normalizep)
if (mode == VOIDmode)
mode = GET_MODE (op0);
- /* For some comparisons with 1 and -1, we can convert this to
+ /* For some comparisons with 1 and -1, we can convert this to
comparisons with zero. This will often produce more opportunities for
store-flag insns. */
@@ -4257,7 +4296,8 @@ emit_store_flag (target, code, op0, op1, mode, unsignedp, normalizep)
the comparison into one involving a single word. */
if (GET_MODE_BITSIZE (mode) == BITS_PER_WORD * 2
&& GET_MODE_CLASS (mode) == MODE_INT
- && op1 == const0_rtx)
+ && op1 == const0_rtx
+ && (GET_CODE (op0) != MEM || ! MEM_VOLATILE_P (op0)))
{
if (code == EQ || code == NE)
{
@@ -4415,14 +4455,14 @@ emit_store_flag (target, code, op0, op1, mode, unsignedp, normalizep)
subtarget, normalizep == 1);
else if (STORE_FLAG_VALUE & 1)
{
- op0 = expand_and (op0, const1_rtx, subtarget);
+ op0 = expand_and (compare_mode, op0, const1_rtx, subtarget);
if (normalizep == -1)
op0 = expand_unop (compare_mode, neg_optab, op0, op0, 0);
}
else
abort ();
- /* If we were converting to a smaller mode, do the
+ /* If we were converting to a smaller mode, do the
conversion now. */
if (target_mode != compare_mode)
{
@@ -4467,7 +4507,7 @@ emit_store_flag (target, code, op0, op1, mode, unsignedp, normalizep)
return tem;
}
- /* Some other cases we can do are EQ, NE, LE, and GT comparisons with
+ /* Some other cases we can do are EQ, NE, LE, and GT comparisons with
the constant zero. Reject all other comparisons at this point. Only
do LE and GT if branches are expensive since they are expensive on
2-operand machines. */
@@ -4529,22 +4569,22 @@ emit_store_flag (target, code, op0, op1, mode, unsignedp, normalizep)
tem = expand_binop (mode, sub_optab, tem, op0, subtarget, 0,
OPTAB_WIDEN);
}
-
+
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
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.
+ normalize with a shift, if needed.
Two operations that can do the above actions are ABS and FFS, so try
them. If that doesn't work, and MODE is smaller than a full word,
we can use zero-extension to the wider mode (an unsigned conversion)
as the operation. */
- /* Note that ABS doesn't yield a positive number for INT_MIN, but
- that is compensated by the subsequent overflow when subtracting
+ /* Note that ABS doesn't yield a positive number for INT_MIN, but
+ that is compensated by the subsequent overflow when subtracting
one / negating. */
if (abs_optab->handlers[(int) mode].insn_code != CODE_FOR_nothing)
OpenPOWER on IntegriCloud