#include "recog.h"
#include "langhooks.h"
-static void store_fixed_bit_field PARAMS ((rtx, unsigned HOST_WIDE_INT,
- unsigned HOST_WIDE_INT,
- unsigned HOST_WIDE_INT, rtx));
-static void store_split_bit_field PARAMS ((rtx, unsigned HOST_WIDE_INT,
- unsigned HOST_WIDE_INT, rtx));
-static rtx extract_fixed_bit_field PARAMS ((enum machine_mode, rtx,
- unsigned HOST_WIDE_INT,
- unsigned HOST_WIDE_INT,
- unsigned HOST_WIDE_INT,
- rtx, int));
-static rtx mask_rtx PARAMS ((enum machine_mode, int,
- int, int));
-static rtx lshift_value PARAMS ((enum machine_mode, rtx,
- int, int));
-static rtx extract_split_bit_field PARAMS ((rtx, unsigned HOST_WIDE_INT,
- unsigned HOST_WIDE_INT, int));
-static void do_cmp_and_jump PARAMS ((rtx, rtx, enum rtx_code,
- enum machine_mode, rtx));
+static void store_fixed_bit_field (rtx, unsigned HOST_WIDE_INT,
+ unsigned HOST_WIDE_INT,
+ unsigned HOST_WIDE_INT, rtx);
+static void store_split_bit_field (rtx, unsigned HOST_WIDE_INT,
+ unsigned HOST_WIDE_INT, rtx);
+static rtx extract_fixed_bit_field (enum machine_mode, rtx,
+ unsigned HOST_WIDE_INT,
+ 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, rtx, int, int);
+static rtx extract_split_bit_field (rtx, unsigned HOST_WIDE_INT,
+ unsigned HOST_WIDE_INT, int);
+static void do_cmp_and_jump (rtx, rtx, enum rtx_code, enum machine_mode, rtx);
/* Nonzero means divides or modulus operations are relatively cheap for
powers of two, so don't use branches; emit the operation instead.
static int mul_highpart_cost[NUM_MACHINE_MODES];
void
-init_expmed ()
+init_expmed (void)
{
rtx reg, shift_insn, shiftadd_insn, shiftsub_insn;
int dummy;
useful if X is a CONST_INT. */
rtx
-negate_rtx (mode, x)
- enum machine_mode mode;
- rtx x;
+negate_rtx (enum machine_mode mode, rtx x)
{
rtx result = simplify_unary_operation (NEG, mode, x, mode);
is false; else the mode of the specified operand. If OPNO is -1,
all the caller cares about is whether the insn is available. */
enum machine_mode
-mode_for_extraction (pattern, opno)
- enum extraction_pattern pattern;
- int opno;
+mode_for_extraction (enum extraction_pattern pattern, int opno)
{
const struct insn_data *data;
else, we use the mode of operand 3. */
rtx
-store_bit_field (str_rtx, bitsize, bitnum, fieldmode, value, total_size)
- rtx str_rtx;
- unsigned HOST_WIDE_INT bitsize;
- unsigned HOST_WIDE_INT bitnum;
- enum machine_mode fieldmode;
- rtx value;
- HOST_WIDE_INT total_size;
+store_bit_field (rtx str_rtx, unsigned HOST_WIDE_INT bitsize,
+ unsigned HOST_WIDE_INT bitnum, enum machine_mode fieldmode,
+ rtx value, HOST_WIDE_INT total_size)
{
unsigned int unit
= (GET_CODE (str_rtx) == MEM) ? BITS_PER_UNIT : BITS_PER_WORD;
VOIDmode, because that is what store_field uses to indicate that this
is a bit field, but passing VOIDmode to operand_subword_force will
result in an abort. */
- fieldmode = smallest_mode_for_size (nwords * BITS_PER_WORD, MODE_INT);
+ fieldmode = GET_MODE (value);
+ if (fieldmode == VOIDmode)
+ fieldmode = smallest_mode_for_size (nwords * BITS_PER_WORD, MODE_INT);
for (i = 0; i < nwords; i++)
{
store_bit_field (op0, MIN (BITS_PER_WORD,
bitsize - i * BITS_PER_WORD),
bitnum + bit_offset, word_mode,
- operand_subword_force (value, wordnum,
- (GET_MODE (value) == VOIDmode
- ? fieldmode
- : GET_MODE (value))),
+ operand_subword_force (value, wordnum, fieldmode),
total_size);
}
return value;
Note that protect_from_queue has already been done on OP0 and VALUE. */
static void
-store_fixed_bit_field (op0, offset, bitsize, bitpos, value)
- rtx op0;
- unsigned HOST_WIDE_INT offset, bitsize, bitpos;
- rtx value;
+store_fixed_bit_field (rtx op0, unsigned HOST_WIDE_INT offset,
+ unsigned HOST_WIDE_INT bitsize,
+ unsigned HOST_WIDE_INT bitpos, rtx value)
{
enum machine_mode mode;
unsigned int total_bits = BITS_PER_WORD;
This does not yet handle fields wider than BITS_PER_WORD. */
static void
-store_split_bit_field (op0, bitsize, bitpos, value)
- rtx op0;
- unsigned HOST_WIDE_INT bitsize, bitpos;
- rtx value;
+store_split_bit_field (rtx op0, unsigned HOST_WIDE_INT bitsize,
+ unsigned HOST_WIDE_INT bitpos, rtx value)
{
unsigned int unit;
unsigned int bitsdone = 0;
if they are equally easy. */
rtx
-extract_bit_field (str_rtx, bitsize, bitnum, unsignedp,
- target, mode, tmode, total_size)
- rtx str_rtx;
- unsigned HOST_WIDE_INT bitsize;
- unsigned HOST_WIDE_INT bitnum;
- int unsignedp;
- rtx target;
- enum machine_mode mode, tmode;
- HOST_WIDE_INT total_size;
+extract_bit_field (rtx str_rtx, unsigned HOST_WIDE_INT bitsize,
+ unsigned HOST_WIDE_INT bitnum, int unsignedp, rtx target,
+ enum machine_mode mode, enum machine_mode tmode,
+ HOST_WIDE_INT total_size)
{
unsigned int unit
= (GET_CODE (str_rtx) == MEM) ? BITS_PER_UNIT : BITS_PER_WORD;
If TARGET is not used, create a pseudo-reg of mode TMODE for the value. */
static rtx
-extract_fixed_bit_field (tmode, op0, offset, bitsize, bitpos,
- target, unsignedp)
- enum machine_mode tmode;
- rtx op0, target;
- unsigned HOST_WIDE_INT offset, bitsize, bitpos;
- int unsignedp;
+extract_fixed_bit_field (enum machine_mode tmode, rtx op0,
+ unsigned HOST_WIDE_INT offset,
+ unsigned HOST_WIDE_INT bitsize,
+ unsigned HOST_WIDE_INT bitpos, rtx target,
+ int unsignedp)
{
unsigned int total_bits = BITS_PER_WORD;
enum machine_mode mode;
BITSIZE+BITPOS is too small for MODE. */
static rtx
-mask_rtx (mode, bitpos, bitsize, complement)
- enum machine_mode mode;
- int bitpos, bitsize, complement;
+mask_rtx (enum machine_mode mode, int bitpos, int bitsize, int complement)
{
HOST_WIDE_INT masklow, maskhigh;
VALUE truncated to BITSIZE bits and then shifted left BITPOS bits. */
static rtx
-lshift_value (mode, value, bitpos, bitsize)
- enum machine_mode mode;
- rtx value;
- int bitpos, bitsize;
+lshift_value (enum machine_mode mode, rtx value, int bitpos, int bitsize)
{
unsigned HOST_WIDE_INT v = INTVAL (value);
HOST_WIDE_INT low, high;
UNSIGNEDP is 1 if should zero-extend the contents; else sign-extend. */
static rtx
-extract_split_bit_field (op0, bitsize, bitpos, unsignedp)
- rtx op0;
- unsigned HOST_WIDE_INT bitsize, bitpos;
- int unsignedp;
+extract_split_bit_field (rtx op0, unsigned HOST_WIDE_INT bitsize,
+ unsigned HOST_WIDE_INT bitpos, int unsignedp)
{
unsigned int unit;
unsigned int bitsdone = 0;
/* Add INC into TARGET. */
void
-expand_inc (target, inc)
- rtx target, inc;
+expand_inc (rtx target, rtx inc)
{
rtx value = expand_binop (GET_MODE (target), add_optab,
target, inc,
/* Subtract DEC from TARGET. */
void
-expand_dec (target, dec)
- rtx target, dec;
+expand_dec (rtx target, rtx dec)
{
rtx value = expand_binop (GET_MODE (target), sub_optab,
target, dec,
Return the rtx for where the value is. */
rtx
-expand_shift (code, mode, shifted, amount, target, unsignedp)
- enum tree_code code;
- enum machine_mode mode;
- rtx shifted;
- tree amount;
- rtx target;
- int unsignedp;
+expand_shift (enum tree_code code, enum machine_mode mode, rtx shifted,
+ tree amount, rtx target, int unsignedp)
{
rtx op1, temp = 0;
int left = (code == LSHIFT_EXPR || code == LROTATE_EXPR);
char log[MAX_BITS_PER_WORD];
};
-static void synth_mult PARAMS ((struct algorithm *,
- unsigned HOST_WIDE_INT,
- int));
-static unsigned HOST_WIDE_INT choose_multiplier PARAMS ((unsigned HOST_WIDE_INT,
- int, int,
- unsigned HOST_WIDE_INT *,
- int *, int *));
-static unsigned HOST_WIDE_INT invert_mod2n PARAMS ((unsigned HOST_WIDE_INT,
- int));
+static void synth_mult (struct algorithm *, unsigned HOST_WIDE_INT, int);
+static unsigned HOST_WIDE_INT choose_multiplier (unsigned HOST_WIDE_INT, int,
+ int, unsigned HOST_WIDE_INT *,
+ int *, int *);
+static unsigned HOST_WIDE_INT invert_mod2n (unsigned HOST_WIDE_INT, int);
/* Compute and return the best algorithm for multiplying by T.
The algorithm must cost less than cost_limit
If retval.cost >= COST_LIMIT, no algorithm was found and all
other field of the returned struct are undefined. */
static void
-synth_mult (alg_out, t, cost_limit)
- struct algorithm *alg_out;
- unsigned HOST_WIDE_INT t;
- int cost_limit;
+synth_mult (struct algorithm *alg_out, unsigned HOST_WIDE_INT t,
+ int cost_limit)
{
int m;
struct algorithm *alg_in, *best_alg;
/* We'll be needing a couple extra algorithm structures now. */
- alg_in = (struct algorithm *)alloca (sizeof (struct algorithm));
- best_alg = (struct algorithm *)alloca (sizeof (struct algorithm));
+ alg_in = alloca (sizeof (struct algorithm));
+ best_alg = alloca (sizeof (struct algorithm));
/* If we have a group of zero bits at the low-order part of T, try
multiplying by the remaining bits and then doing a shift. */
you should swap the two operands if OP0 would be constant. */
rtx
-expand_mult (mode, op0, op1, target, unsignedp)
- enum machine_mode mode;
- rtx op0, op1, target;
- int unsignedp;
+expand_mult (enum machine_mode mode, rtx op0, rtx op1, rtx target,
+ int unsignedp)
{
rtx const_op1 = op1;
insn = get_last_insn ();
set_unique_reg_note (insn,
- REG_EQUAL,
+ REG_EQUAL,
gen_rtx_MULT (nmode, tem,
- GEN_INT (val_so_far)));
+ GEN_INT (val_so_far)));
}
if (variant == negate_variant)
}
}
+ if (GET_CODE (op0) == CONST_DOUBLE)
+ {
+ rtx temp = op0;
+ op0 = op1;
+ op1 = temp;
+ }
+
+ /* Expand x*2.0 as x+x. */
+ if (GET_CODE (op1) == CONST_DOUBLE
+ && GET_MODE_CLASS (mode) == MODE_FLOAT)
+ {
+ REAL_VALUE_TYPE d;
+ REAL_VALUE_FROM_CONST_DOUBLE (d, op1);
+
+ if (REAL_VALUES_EQUAL (d, dconst2))
+ {
+ op0 = force_reg (GET_MODE (op0), op0);
+ return expand_binop (mode, add_optab, op0, op0,
+ target, unsignedp, OPTAB_LIB_WIDEN);
+ }
+ }
+
/* 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,
/* Return the smallest n such that 2**n >= X. */
int
-ceil_log2 (x)
- unsigned HOST_WIDE_INT x;
+ceil_log2 (unsigned HOST_WIDE_INT x)
{
return floor_log2 (x - 1) + 1;
}
static
unsigned HOST_WIDE_INT
-choose_multiplier (d, n, precision, multiplier_ptr, post_shift_ptr, lgup_ptr)
- unsigned HOST_WIDE_INT d;
- int n;
- int precision;
- unsigned HOST_WIDE_INT *multiplier_ptr;
- int *post_shift_ptr;
- int *lgup_ptr;
+choose_multiplier (unsigned HOST_WIDE_INT d, int n, int precision,
+ unsigned HOST_WIDE_INT *multiplier_ptr,
+ int *post_shift_ptr, int *lgup_ptr)
{
HOST_WIDE_INT mhigh_hi, mlow_hi;
unsigned HOST_WIDE_INT mhigh_lo, mlow_lo;
abort ();
if (mhigh_hi > 1 || mlow_hi > 1)
abort ();
- /* assert that mlow < mhigh. */
+ /* Assert that mlow < mhigh. */
if (! (mlow_hi < mhigh_hi || (mlow_hi == mhigh_hi && mlow_lo < mhigh_lo)))
abort ();
/* If precision == N, then mlow, mhigh exceed 2^N
(but they do not exceed 2^(N+1)). */
- /* Reduce to lowest terms */
+ /* Reduce to lowest terms. */
for (post_shift = lgup; post_shift > 0; post_shift--)
{
unsigned HOST_WIDE_INT ml_lo = (mlow_hi << (HOST_BITS_PER_WIDE_INT - 1)) | (mlow_lo >> 1);
congruent to 1 (mod 2**N). */
static unsigned HOST_WIDE_INT
-invert_mod2n (x, n)
- unsigned HOST_WIDE_INT x;
- int n;
+invert_mod2n (unsigned HOST_WIDE_INT x, int n)
{
/* Solve x*y == 1 (mod 2^n), where x is odd. Return y. */
MODE is the mode of operation. */
rtx
-expand_mult_highpart_adjust (mode, adj_operand, op0, op1, target, unsignedp)
- enum machine_mode mode;
- rtx adj_operand, op0, op1, target;
- int unsignedp;
+expand_mult_highpart_adjust (enum machine_mode mode, rtx adj_operand, rtx op0,
+ rtx op1, rtx target, int unsignedp)
{
rtx tem;
enum rtx_code adj_code = unsignedp ? PLUS : MINUS;
MAX_COST is the total allowed cost for the expanded RTL. */
rtx
-expand_mult_highpart (mode, op0, cnst1, target, unsignedp, max_cost)
- enum machine_mode mode;
- rtx op0, target;
- unsigned HOST_WIDE_INT cnst1;
- int unsignedp;
- int max_cost;
+expand_mult_highpart (enum machine_mode mode, rtx op0,
+ unsigned HOST_WIDE_INT cnst1, rtx target,
+ int unsignedp, int max_cost)
{
enum machine_mode wider_mode = GET_MODE_WIDER_MODE (mode);
optab mul_highpart_optab;
#define EXACT_POWER_OF_2_OR_ZERO_P(x) (((x) & ((x) - 1)) == 0)
rtx
-expand_divmod (rem_flag, code, mode, op0, op1, target, unsignedp)
- int rem_flag;
- enum tree_code code;
- enum machine_mode mode;
- rtx op0, op1, target;
- int unsignedp;
+expand_divmod (int rem_flag, enum tree_code code, enum machine_mode mode,
+ rtx op0, rtx op1, rtx target, int unsignedp)
{
enum machine_mode compute_mode;
rtx tquotient;
&& (set = single_set (insn)) != 0
&& SET_DEST (set) == quotient)
set_unique_reg_note (insn,
- REG_EQUAL,
+ REG_EQUAL,
gen_rtx_UDIV (compute_mode, op0, op1));
}
else /* TRUNC_DIV, signed */
&& abs_d < ((unsigned HOST_WIDE_INT) 1
<< (HOST_BITS_PER_WIDE_INT - 1)))
set_unique_reg_note (insn,
- REG_EQUAL,
+ REG_EQUAL,
gen_rtx_DIV (compute_mode,
op0,
GEN_INT
&& (set = single_set (insn)) != 0
&& SET_DEST (set) == quotient)
set_unique_reg_note (insn,
- REG_EQUAL,
+ REG_EQUAL,
gen_rtx_DIV (compute_mode, op0, op1));
}
break;
build_int_2 (pre_shift, 0), NULL_RTX, unsignedp);
quotient = expand_mult (compute_mode, t1,
gen_int_mode (ml, compute_mode),
- NULL_RTX, 0);
+ NULL_RTX, 1);
insn = get_last_insn ();
set_unique_reg_note (insn,
- REG_EQUAL,
+ REG_EQUAL,
gen_rtx_fmt_ee (unsignedp ? UDIV : DIV,
compute_mode,
op0, op1));
{
/* Try to produce the remainder without producing the quotient.
If we seem to have a divmod pattern that does not require widening,
- don't try widening here. We should really have an WIDEN argument
+ don't try widening here. We should really have a WIDEN argument
to expand_twoval_binop, since what we'd really like to do here is
1) try a mod insn in compute_mode
2) try a divmod insn in compute_mode
generated by loop.c. */
tree
-make_tree (type, x)
- tree type;
- rtx x;
+make_tree (tree type, rtx x)
{
tree t;
t = make_node (RTL_EXPR);
TREE_TYPE (t) = type;
-#ifdef POINTERS_EXTEND_UNSIGNED
/* If TYPE is a POINTER_TYPE, X might be Pmode with TYPE_MODE being
ptr_mode. So convert. */
- if (POINTER_TYPE_P (type) && GET_MODE (x) != TYPE_MODE (type))
+ if (POINTER_TYPE_P (type))
x = convert_memory_address (TYPE_MODE (type), x);
-#endif
RTL_EXPR_RTL (t) = x;
/* There are no insns to be output
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;
+const_mult_add_overflow_p (rtx x, rtx mult, rtx add, enum machine_mode mode, int unsignedp)
{
tree type, mult_type, add_type, result;
This may emit insns. */
rtx
-expand_mult_add (x, target, mult, add, mode, unsignedp)
- rtx x, target, mult, add;
- enum machine_mode mode;
- int unsignedp;
+expand_mult_add (rtx x, rtx target, rtx mult, rtx add, enum machine_mode mode,
+ int unsignedp)
{
tree type = (*lang_hooks.types.type_for_mode) (mode, unsignedp);
tree add_type = (GET_MODE (add) == VOIDmode
If TARGET is 0, a pseudo-register or constant is returned. */
rtx
-expand_and (mode, op0, op1, target)
- enum machine_mode mode;
- rtx op0, op1, target;
+expand_and (enum machine_mode mode, rtx op0, rtx op1, rtx target)
{
rtx tem = 0;
"raw" out of the scc insn. */
rtx
-emit_store_flag (target, code, op0, op1, mode, unsignedp, normalizep)
- rtx target;
- enum rtx_code code;
- rtx op0, op1;
- enum machine_mode mode;
- int unsignedp;
- int normalizep;
+emit_store_flag (rtx target, enum rtx_code code, rtx op0, rtx op1,
+ enum machine_mode mode, int unsignedp, int normalizep)
{
rtx subtarget;
enum insn_code icode;
{
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. */
/* Like emit_store_flag, but always succeeds. */
rtx
-emit_store_flag_force (target, code, op0, op1, mode, unsignedp, normalizep)
- rtx target;
- enum rtx_code code;
- rtx op0, op1;
- enum machine_mode mode;
- int unsignedp;
- int normalizep;
+emit_store_flag_force (rtx target, enum rtx_code code, rtx op0, rtx op1,
+ enum machine_mode mode, int unsignedp, int normalizep)
{
rtx tem, label;
be handled if needed). */
static void
-do_cmp_and_jump (arg1, arg2, op, mode, label)
- rtx arg1, arg2, label;
- enum rtx_code op;
- enum machine_mode mode;
+do_cmp_and_jump (rtx arg1, rtx arg2, enum rtx_code op, enum machine_mode mode,
+ rtx label)
{
/* If this mode is an integer too wide to compare properly,
compare word by word. Rely on cse to optimize constant cases. */