/* 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, 2007, 2008, 2009
+ 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010
Free Software Foundation, Inc.
This file is part of GCC.
always get higher addresses. */
int inner_mode_size = GET_MODE_SIZE (GET_MODE (SUBREG_REG (op0)));
int outer_mode_size = GET_MODE_SIZE (GET_MODE (op0));
-
+
byte_offset = 0;
/* Paradoxical subregs need special handling on big endian machines. */
and we will need the original value of op0 if insv fails. */
xop0 = gen_rtx_SUBREG (op_mode, SUBREG_REG (xop0), SUBREG_BYTE (xop0));
if (REG_P (xop0) && GET_MODE (xop0) != op_mode)
- xop0 = gen_rtx_SUBREG (op_mode, xop0, 0);
+ xop0 = gen_lowpart_SUBREG (op_mode, xop0);
/* If the destination is a paradoxical subreg such that we need a
truncate to the inner mode, perform the insertion on a temporary and
/* If op0 is a register, we need it in EXT_MODE to make it
acceptable to the format of ext(z)v. */
if (REG_P (xop0) && GET_MODE (xop0) != ext_mode)
- xop0 = gen_rtx_SUBREG (ext_mode, xop0, 0);
+ xop0 = gen_lowpart_SUBREG (ext_mode, xop0);
if (MEM_P (xop0))
/* Get ref to first byte containing part of the field. */
xop0 = adjust_address (xop0, byte_mode, xoffset);
static rtx
mask_rtx (enum machine_mode mode, int bitpos, int bitsize, int complement)
{
- HOST_WIDE_INT masklow, maskhigh;
-
- if (bitsize == 0)
- masklow = 0;
- else if (bitpos < HOST_BITS_PER_WIDE_INT)
- masklow = (HOST_WIDE_INT) -1 << bitpos;
- else
- masklow = 0;
-
- 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
- maskhigh = (HOST_WIDE_INT) -1 << (bitpos - HOST_BITS_PER_WIDE_INT);
+ double_int mask;
- if (bitsize == 0)
- maskhigh = 0;
- else if (bitpos + bitsize > HOST_BITS_PER_WIDE_INT)
- maskhigh &= ((unsigned HOST_WIDE_INT) -1
- >> (2 * HOST_BITS_PER_WIDE_INT - bitpos - bitsize));
- else
- maskhigh = 0;
+ mask = double_int_mask (bitsize);
+ mask = double_int_lshift (mask, bitpos, HOST_BITS_PER_DOUBLE_INT, false);
if (complement)
- {
- maskhigh = ~maskhigh;
- masklow = ~masklow;
- }
+ mask = double_int_not (mask);
- return immed_double_const (masklow, maskhigh, mode);
+ return immed_double_int_const (mask, mode);
}
/* Return a constant integer (CONST_INT or CONST_DOUBLE) rtx with the value
static rtx
lshift_value (enum machine_mode mode, rtx value, int bitpos, int bitsize)
{
- unsigned HOST_WIDE_INT v = INTVAL (value);
- HOST_WIDE_INT low, high;
-
- if (bitsize < HOST_BITS_PER_WIDE_INT)
- v &= ~((HOST_WIDE_INT) -1 << bitsize);
-
- if (bitpos < HOST_BITS_PER_WIDE_INT)
- {
- low = v << bitpos;
- high = (bitpos > 0 ? (v >> (HOST_BITS_PER_WIDE_INT - bitpos)) : 0);
- }
- else
- {
- low = 0;
- high = v << (bitpos - HOST_BITS_PER_WIDE_INT);
- }
+ double_int val;
+
+ val = double_int_zext (uhwi_to_double_int (INTVAL (value)), bitsize);
+ val = double_int_lshift (val, bitpos, HOST_BITS_PER_DOUBLE_INT, false);
- return immed_double_const (low, high, mode);
+ return immed_double_int_const (val, mode);
}
\f
/* Extract a bit field that is split across two words
Otherwise, the cost within which multiplication by T is
impossible. */
struct mult_cost cost;
-
+
/* OPtimized for speed? */
bool speed;
};
target, unsignedp);
}
}
-
+
/* We used to test optimize here, on the grounds that it's better to
produce a smaller program when -O is not used. But this causes
such a terrible slowdown sometimes that it seems better to always
gcc_assert (op0);
return op0;
}
+
+/* Perform a widening multiplication and return an rtx for the result.
+ MODE is mode of value; OP0 and OP1 are what to multiply (rtx's);
+ TARGET is a suggestion for where to store the result (an rtx).
+ THIS_OPTAB is the optab we should use, it must be either umul_widen_optab
+ or smul_widen_optab.
+
+ We check specially for a constant integer as OP1, comparing the
+ cost of a widening multiply against the cost of a sequence of shifts
+ and adds. */
+
+rtx
+expand_widening_mult (enum machine_mode mode, rtx op0, rtx op1, rtx target,
+ int unsignedp, optab this_optab)
+{
+ bool speed = optimize_insn_for_speed_p ();
+
+ if (CONST_INT_P (op1)
+ && (INTVAL (op1) >= 0
+ || GET_MODE_BITSIZE (mode) <= HOST_BITS_PER_WIDE_INT))
+ {
+ HOST_WIDE_INT coeff = INTVAL (op1);
+ int max_cost;
+ enum mult_variant variant;
+ struct algorithm algorithm;
+
+ /* Special case powers of two. */
+ if (EXACT_POWER_OF_2_OR_ZERO_P (coeff))
+ {
+ op0 = convert_to_mode (mode, op0, this_optab == umul_widen_optab);
+ return expand_shift (LSHIFT_EXPR, mode, op0,
+ build_int_cst (NULL_TREE, floor_log2 (coeff)),
+ target, unsignedp);
+ }
+
+ /* Exclude cost of op0 from max_cost to match the cost
+ calculation of the synth_mult. */
+ max_cost = mul_widen_cost[speed][mode];
+ if (choose_mult_variant (mode, coeff, &algorithm, &variant,
+ max_cost))
+ {
+ op0 = convert_to_mode (mode, op0, this_optab == umul_widen_optab);
+ return expand_mult_const (mode, op0, coeff, target,
+ &algorithm, variant);
+ }
+ }
+ return expand_binop (mode, this_optab, op0, op1, target,
+ unsignedp, OPTAB_LIB_WIDEN);
+}
\f
/* Return the smallest n such that 2**n >= X. */
cnst1 = INTVAL (op1) & GET_MODE_MASK (mode);
- /* We can't optimize modes wider than BITS_PER_WORD.
- ??? We might be able to perform double-word arithmetic if
+ /* We can't optimize modes wider than BITS_PER_WORD.
+ ??? We might be able to perform double-word arithmetic if
mode == word_mode, however all the cost calculations in
synth_mult etc. assume single-word operations. */
if (GET_MODE_BITSIZE (wider_mode) > BITS_PER_WORD)
else if (d == -1)
quotient = expand_unop (compute_mode, neg_optab, op0,
tquotient, 0);
- else if (abs_d == (unsigned HOST_WIDE_INT) 1 << (size - 1))
+ else if (HOST_BITS_PER_WIDE_INT >= size
+ && abs_d == (unsigned HOST_WIDE_INT) 1 << (size - 1))
{
/* This case is not handled correctly below. */
quotient = emit_store_flag (tquotient, EQ, op0, op1,
if (!remainder)
{
remainder = gen_reg_rtx (compute_mode);
- if (!expand_twoval_binop_libfunc
+ if (!expand_twoval_binop_libfunc
(unsignedp ? udivmod_optab : sdivmod_optab,
op0, op1,
NULL_RTX, remainder,
&& (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_DOUBLE:
if (GET_MODE (x) == VOIDmode)
t = build_int_cst_wide (type,
default:
t = build_decl (RTL_LOCATION (x), VAR_DECL, NULL_TREE, type);
- /* If TYPE is a POINTER_TYPE, X might be Pmode with TYPE_MODE being
- ptr_mode. So convert. */
+ /* If TYPE is a POINTER_TYPE, we might need to convert X from
+ address mode to pointer mode. */
if (POINTER_TYPE_P (type))
- x = convert_memory_address (TYPE_MODE (type), x);
+ x = convert_memory_address_addr_space
+ (TYPE_MODE (type), x, TYPE_ADDR_SPACE (TREE_TYPE (type)));
/* Note that we do *not* use SET_DECL_RTL here, because we do not
want set_decl_rtl to go adjusting REG_ATTRS for this temporary. */
target_mode = result_mode;
if (!target)
target = gen_reg_rtx (target_mode);
-
+
if (optimize
|| !(insn_data[(int) icode].operand[0].predicate (target, result_mode)))
subtarget = gen_reg_rtx (result_mode);
|| (! HONOR_NANS (mode) && (code == LTGT || code == UNEQ))
|| (! HONOR_SNANS (mode) && (code == EQ || code == NE))))
{
+ int want_add = ((STORE_FLAG_VALUE == 1 && normalizep == -1)
+ || (STORE_FLAG_VALUE == -1 && normalizep == 1));
+
/* For the reverse comparison, use either an addition or a XOR. */
- if ((STORE_FLAG_VALUE == 1 && normalizep == -1)
- || (STORE_FLAG_VALUE == -1 && normalizep == 1))
+ if (want_add
+ && rtx_cost (GEN_INT (normalizep), PLUS,
+ optimize_insn_for_speed_p ()) == 0)
{
tem = emit_store_flag_1 (subtarget, rcode, op0, op1, mode, 0,
STORE_FLAG_VALUE, target_mode);
GEN_INT (normalizep),
target, 0, OPTAB_WIDEN);
}
- else
+ else if (!want_add
+ && rtx_cost (trueval, XOR,
+ optimize_insn_for_speed_p ()) == 0)
{
tem = emit_store_flag_1 (subtarget, rcode, op0, op1, mode, 0,
normalizep, target_mode);
/* Cannot split ORDERED and UNORDERED, only try the above trick. */
if (code == ORDERED || code == UNORDERED)
return 0;
-
+
and_them = split_comparison (code, mode, &first_code, &code);
/* If there are no NaNs, the first comparison should always fall through.
tem = expand_binop (mode, sub_optab, op0, op1, subtarget, 1,
OPTAB_WIDEN);
if (tem != 0)
- tem = emit_store_flag_1 (target, code, tem, const0_rtx,
- mode, unsignedp, normalizep, target_mode);
+ tem = emit_store_flag (target, code, tem, const0_rtx,
+ mode, unsignedp, normalizep);
if (tem != 0)
return tem;
&& GET_MODE_SIZE (mode) < UNITS_PER_WORD
&& op1 == const0_rtx))
{
+ int want_add = ((STORE_FLAG_VALUE == 1 && normalizep == -1)
+ || (STORE_FLAG_VALUE == -1 && normalizep == 1));
+
/* Again, for the reverse comparison, use either an addition or a XOR. */
- if ((STORE_FLAG_VALUE == 1 && normalizep == -1)
- || (STORE_FLAG_VALUE == -1 && normalizep == 1))
+ if (want_add
+ && rtx_cost (GEN_INT (normalizep), PLUS,
+ optimize_insn_for_speed_p ()) == 0)
{
tem = emit_store_flag_1 (subtarget, rcode, op0, op1, mode, 0,
STORE_FLAG_VALUE, target_mode);
tem = expand_binop (target_mode, add_optab, tem,
GEN_INT (normalizep), target, 0, OPTAB_WIDEN);
}
- else
+ else if (!want_add
+ && rtx_cost (trueval, XOR,
+ optimize_insn_for_speed_p ()) == 0)
{
tem = emit_store_flag_1 (subtarget, rcode, op0, op1, mode, 0,
normalizep, target_mode);
/* If this failed, we have to do this with set/compare/jump/set code.
For foo != 0, if foo is in OP0, just replace it with 1 if nonzero. */
trueval = normalizep ? GEN_INT (normalizep) : const1_rtx;
- if (code == NE
+ if (code == NE
&& GET_MODE_CLASS (mode) == MODE_INT
&& REG_P (target)
&& op0 == target
{
label = gen_label_rtx ();
do_compare_rtx_and_jump (target, const0_rtx, EQ, unsignedp,
- mode, NULL_RTX, NULL_RTX, label);
+ mode, NULL_RTX, NULL_RTX, label, -1);
emit_move_insn (target, trueval);
emit_label (label);
return target;
emit_move_insn (target, trueval);
label = gen_label_rtx ();
do_compare_rtx_and_jump (op0, op1, code, unsignedp, mode, NULL_RTX,
- NULL_RTX, label);
+ NULL_RTX, label, -1);
emit_move_insn (target, falseval);
emit_label (label);
{
int unsignedp = (op == LTU || op == LEU || op == GTU || op == GEU);
do_compare_rtx_and_jump (arg1, arg2, op, unsignedp, mode,
- NULL_RTX, NULL_RTX, label);
+ NULL_RTX, NULL_RTX, label, -1);
}