/* Medium-level subroutines: convert bit-field store and extract
and shifts, multiplies and divides to rtl instructions.
Copyright (C) 1987, 1988, 1989, 1992, 1993, 1994, 1995, 1996, 1997, 1998,
- 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006
+ 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007
Free Software Foundation, Inc.
This file is part of GCC.
#include "real.h"
#include "recog.h"
#include "langhooks.h"
+#include "target.h"
static void store_fixed_bit_field (rtx, unsigned HOST_WIDE_INT,
unsigned HOST_WIDE_INT,
return op0;
}
+ /* See if we can get a better vector mode before extracting. */
+ if (VECTOR_MODE_P (GET_MODE (op0))
+ && !MEM_P (op0)
+ && GET_MODE_INNER (GET_MODE (op0)) != tmode)
+ {
+ enum machine_mode new_mode;
+ int nunits = GET_MODE_NUNITS (GET_MODE (op0));
+
+ if (GET_MODE_CLASS (tmode) == MODE_FLOAT)
+ new_mode = MIN_MODE_VECTOR_FLOAT;
+ else
+ new_mode = MIN_MODE_VECTOR_INT;
+
+ for (; new_mode != VOIDmode ; new_mode = GET_MODE_WIDER_MODE (new_mode))
+ if (GET_MODE_NUNITS (new_mode) == nunits
+ && GET_MODE_INNER (new_mode) == tmode
+ && targetm.vector_mode_supported_p (new_mode))
+ break;
+ if (new_mode != VOIDmode)
+ op0 = gen_lowpart (new_mode, op0);
+ }
+
/* Use vec_extract patterns for extracting parts of vectors whenever
available. */
if (VECTOR_MODE_P (GET_MODE (op0))
{
emit_insn (seq);
emit_insn (pat);
+ if (mode0 != mode)
+ return gen_lowpart (tmode, dest);
return dest;
}
}
&& GET_CODE (op1) == CONST_INT
&& INTVAL (op1) > 0
&& INTVAL (op1) < GET_MODE_BITSIZE (mode)
- && shift_cost[mode][INTVAL (op1)] > INTVAL (op1) * add_cost[mode])
+ && INTVAL (op1) < MAX_BITS_PER_WORD
+ && shift_cost[mode][INTVAL (op1)] > INTVAL (op1) * add_cost[mode]
+ && shift_cost[mode][INTVAL (op1)] != MAX_COST)
{
int i;
for (i = 0; i < INTVAL (op1); i++)
int opno;
enum machine_mode nmode;
- /* Avoid referencing memory over and over.
- For speed, but also for correctness when mem is volatile. */
- if (MEM_P (op0))
- op0 = force_reg (mode, op0);
+ /* Avoid referencing memory over and over and invalid sharing
+ on SUBREGs. */
+ op0 = force_reg (mode, op0);
/* ACCUM starts out either as OP0 or as a zero, depending on
the first operation. */
insn = get_last_insn ();
set_unique_reg_note (insn, REG_EQUAL,
- gen_rtx_MULT (nmode, tem, GEN_INT (val_so_far)));
+ gen_rtx_MULT (nmode, tem,
+ GEN_INT (val_so_far)));
}
if (variant == negate_variant)
int lgup, post_shift;
rtx mlr;
HOST_WIDE_INT d = INTVAL (op1);
- unsigned HOST_WIDE_INT abs_d = d >= 0 ? d : -d;
+ unsigned HOST_WIDE_INT abs_d;
+
+ /* Since d might be INT_MIN, we have to cast to
+ unsigned HOST_WIDE_INT before negating to avoid
+ undefined signed overflow. */
+ abs_d = (d >= 0
+ ? (unsigned HOST_WIDE_INT) d
+ : - (unsigned HOST_WIDE_INT) d);
/* n rem d = n rem -d */
if (rem_flag && d < 0)
case CONST_VECTOR:
{
- int i, units;
- rtx elt;
+ int units = CONST_VECTOR_NUNITS (x);
+ tree itype = TREE_TYPE (type);
tree t = NULL_TREE;
+ int i;
- 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);
+ rtx elt = CONST_VECTOR_ELT (x, i);
+ t = tree_cons (NULL_TREE, make_tree (itype, elt), t);
}
return build_vector (type, t);
GET_CODE (x) == ZERO_EXTEND);
return fold_convert (type, make_tree (t, XEXP (x, 0)));
+ case CONST:
+ return make_tree (type, XEXP (x, 0));
+
+ case SYMBOL_REF:
+ t = SYMBOL_REF_DECL (x);
+ if (t)
+ return fold_convert (type, build_fold_addr_expr (t));
+ /* else fall through. */
+
default:
t = build_decl (VAR_DECL, NULL_TREE, type);
return target;
}
\f
+/* Helper function for emit_store_flag. */
+static rtx
+emit_store_flag_1 (rtx target, rtx subtarget, enum machine_mode mode,
+ int normalizep)
+{
+ rtx op0;
+ enum machine_mode target_mode = GET_MODE (target);
+
+ /* If we are converting to a wider mode, first convert to
+ TARGET_MODE, then normalize. This produces better combining
+ opportunities on machines that have a SIGN_EXTRACT when we are
+ testing a single bit. This mostly benefits the 68k.
+
+ If STORE_FLAG_VALUE does not have the sign bit set when
+ interpreted in MODE, we can do this conversion as unsigned, which
+ is usually more efficient. */
+ if (GET_MODE_SIZE (target_mode) > GET_MODE_SIZE (mode))
+ {
+ convert_move (target, subtarget,
+ (GET_MODE_BITSIZE (mode) <= HOST_BITS_PER_WIDE_INT)
+ && 0 == (STORE_FLAG_VALUE
+ & ((HOST_WIDE_INT) 1
+ << (GET_MODE_BITSIZE (mode) -1))));
+ op0 = target;
+ mode = target_mode;
+ }
+ else
+ op0 = subtarget;
+
+ /* If we want to keep subexpressions around, don't reuse our last
+ target. */
+ if (optimize)
+ subtarget = 0;
+
+ /* Now normalize to the proper value in MODE. Sometimes we don't
+ have to do anything. */
+ if (normalizep == 0 || normalizep == STORE_FLAG_VALUE)
+ ;
+ /* STORE_FLAG_VALUE might be the most negative number, so write
+ the comparison this way to avoid a compiler-time warning. */
+ else if (- normalizep == STORE_FLAG_VALUE)
+ op0 = expand_unop (mode, neg_optab, op0, subtarget, 0);
+
+ /* We don't want to use STORE_FLAG_VALUE < 0 below since this makes
+ it hard to use a value of just the sign bit due to ANSI integer
+ constant typing rules. */
+ else if (GET_MODE_BITSIZE (mode) <= HOST_BITS_PER_WIDE_INT
+ && (STORE_FLAG_VALUE
+ & ((HOST_WIDE_INT) 1 << (GET_MODE_BITSIZE (mode) - 1))))
+ op0 = expand_shift (RSHIFT_EXPR, mode, op0,
+ size_int (GET_MODE_BITSIZE (mode) - 1), subtarget,
+ normalizep == 1);
+ else
+ {
+ gcc_assert (STORE_FLAG_VALUE & 1);
+
+ op0 = expand_and (mode, op0, const1_rtx, subtarget);
+ if (normalizep == -1)
+ op0 = expand_unop (mode, neg_optab, op0, op0, 0);
+ }
+
+ /* If we were converting to a smaller mode, do the conversion now. */
+ if (target_mode != mode)
+ {
+ convert_move (target, op0, 0);
+ return target;
+ }
+ else
+ return op0;
+}
+
/* Emit a store-flags instruction for comparison CODE on OP0 and OP1
and storing in TARGET. Normally return TARGET.
Return 0 if that cannot be done.
{
rtx op00, op01, op0both;
- /* Do a logical OR or AND of the two words and compare the result. */
+ /* Do a logical OR or AND of the two words and compare the
+ result. */
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,
op1 == const0_rtx ? ior_optab : and_optab,
- op00, op01, NULL_RTX, unsignedp, OPTAB_DIRECT);
+ op00, op01, NULL_RTX, unsignedp,
+ OPTAB_DIRECT);
if (op0both != 0)
return emit_store_flag (target, code, op0both, op1, word_mode,
/* 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));
+ 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. */
- icode = setcc_gen_code[(int) code];
-
/* If this is A < 0 or A >= 0, we can do this by taking the ones
complement of A (for GE) and shifting the sign bit to the low bit. */
if (op1 == const0_rtx && (code == LT || code == GE)
&& (normalizep || STORE_FLAG_VALUE == 1
|| (GET_MODE_BITSIZE (mode) <= HOST_BITS_PER_WIDE_INT
&& ((STORE_FLAG_VALUE & GET_MODE_MASK (mode))
- == (unsigned HOST_WIDE_INT) 1 << (GET_MODE_BITSIZE (mode) - 1)))))
+ == ((unsigned HOST_WIDE_INT) 1
+ << (GET_MODE_BITSIZE (mode) - 1))))))
{
subtarget = target;
return op0;
}
+ icode = setcc_gen_code[(int) code];
+
if (icode != CODE_FOR_nothing)
{
insn_operand_predicate_fn pred;
if (pattern)
{
emit_insn (pattern);
+ return emit_store_flag_1 (target, subtarget, compare_mode,
+ normalizep);
+ }
+ }
+ else
+ {
+ /* We don't have an scc insn, so try a cstore insn. */
- /* If we are converting to a wider mode, first convert to
- TARGET_MODE, then normalize. This produces better combining
- opportunities on machines that have a SIGN_EXTRACT when we are
- testing a single bit. This mostly benefits the 68k.
+ for (compare_mode = mode; compare_mode != VOIDmode;
+ compare_mode = GET_MODE_WIDER_MODE (compare_mode))
+ {
+ icode = cstore_optab->handlers[(int) compare_mode].insn_code;
+ if (icode != CODE_FOR_nothing)
+ break;
+ }
+
+ if (icode != CODE_FOR_nothing)
+ {
+ enum machine_mode result_mode
+ = insn_data[(int) icode].operand[0].mode;
+ rtx cstore_op0 = op0;
+ rtx cstore_op1 = op1;
+
+ do_pending_stack_adjust ();
+ last = get_last_insn ();
- If STORE_FLAG_VALUE does not have the sign bit set when
- interpreted in COMPARE_MODE, we can do this conversion as
- unsigned, which is usually more efficient. */
- if (GET_MODE_SIZE (target_mode) > GET_MODE_SIZE (compare_mode))
+ if (compare_mode != mode)
{
- convert_move (target, subtarget,
- (GET_MODE_BITSIZE (compare_mode)
- <= HOST_BITS_PER_WIDE_INT)
- && 0 == (STORE_FLAG_VALUE
- & ((HOST_WIDE_INT) 1
- << (GET_MODE_BITSIZE (compare_mode) -1))));
- op0 = target;
- compare_mode = target_mode;
+ cstore_op0 = convert_modes (compare_mode, mode, cstore_op0,
+ unsignedp);
+ cstore_op1 = convert_modes (compare_mode, mode, cstore_op1,
+ unsignedp);
}
- else
- op0 = subtarget;
+
+ if (!insn_data[(int) icode].operand[2].predicate (cstore_op0,
+ compare_mode))
+ cstore_op0 = copy_to_mode_reg (compare_mode, cstore_op0);
- /* If we want to keep subexpressions around, don't reuse our
- last target. */
+ if (!insn_data[(int) icode].operand[3].predicate (cstore_op1,
+ compare_mode))
+ cstore_op1 = copy_to_mode_reg (compare_mode, cstore_op1);
- if (optimize)
- subtarget = 0;
+ comparison = gen_rtx_fmt_ee (code, result_mode, cstore_op0,
+ cstore_op1);
+ subtarget = target;
- /* Now normalize to the proper value in COMPARE_MODE. Sometimes
- we don't have to do anything. */
- if (normalizep == 0 || normalizep == STORE_FLAG_VALUE)
- ;
- /* STORE_FLAG_VALUE might be the most negative number, so write
- the comparison this way to avoid a compiler-time warning. */
- else if (- normalizep == STORE_FLAG_VALUE)
- op0 = expand_unop (compare_mode, neg_optab, op0, subtarget, 0);
-
- /* We don't want to use STORE_FLAG_VALUE < 0 below since this
- makes it hard to use a value of just the sign bit due to
- ANSI integer constant typing rules. */
- else if (GET_MODE_BITSIZE (compare_mode) <= HOST_BITS_PER_WIDE_INT
- && (STORE_FLAG_VALUE
- & ((HOST_WIDE_INT) 1
- << (GET_MODE_BITSIZE (compare_mode) - 1))))
- op0 = expand_shift (RSHIFT_EXPR, compare_mode, op0,
- size_int (GET_MODE_BITSIZE (compare_mode) - 1),
- subtarget, normalizep == 1);
- else
- {
- gcc_assert (STORE_FLAG_VALUE & 1);
-
- op0 = expand_and (compare_mode, op0, const1_rtx, subtarget);
- if (normalizep == -1)
- op0 = expand_unop (compare_mode, neg_optab, op0, op0, 0);
- }
+ if (optimize || !(insn_data[(int) icode].operand[0].predicate
+ (subtarget, result_mode)))
+ subtarget = gen_reg_rtx (result_mode);
+
+ pattern = GEN_FCN (icode) (subtarget, comparison, cstore_op0,
+ cstore_op1);
- /* If we were converting to a smaller mode, do the
- conversion now. */
- if (target_mode != compare_mode)
+ if (pattern)
{
- convert_move (target, op0, 0);
- return target;
+ emit_insn (pattern);
+ return emit_store_flag_1 (target, subtarget, result_mode,
+ normalizep);
}
- else
- return op0;
}
}