You should have received a copy of the GNU General Public License
along with GCC; see the file COPYING. If not, write to the Free
-Software Foundation, 59 Temple Place - Suite 330, Boston, MA
-02111-1307, USA. */
+Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301, USA. */
#include "config.h"
}
}
- if (flag_force_mem)
- {
- 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.
|| (offset * BITS_PER_UNIT % bitsize == 0
&& MEM_ALIGN (op0) % GET_MODE_BITSIZE (fieldmode) == 0))))
{
- if (GET_MODE (op0) != fieldmode)
- {
- if (MEM_P (op0))
- op0 = adjust_address (op0, fieldmode, offset);
- else
- op0 = simplify_gen_subreg (fieldmode, op0, GET_MODE (op0),
- byte_offset);
- }
+ if (MEM_P (op0))
+ op0 = adjust_address (op0, fieldmode, offset);
+ else if (GET_MODE (op0) != fieldmode)
+ op0 = simplify_gen_subreg (fieldmode, op0, GET_MODE (op0),
+ byte_offset);
emit_move_insn (op0, value);
return value;
}
if (HAVE_insv
&& GET_MODE (value) != BLKmode
&& !(bitsize == 1 && GET_CODE (value) == CONST_INT)
- /* Ensure insv's size is wide enough for this field. */
- && (GET_MODE_BITSIZE (op_mode) >= bitsize)
+ && bitsize > 0
+ && GET_MODE_BITSIZE (op_mode) >= bitsize
&& ! ((REG_P (op0) || GET_CODE (op0) == SUBREG)
&& (bitsize + bitpos > GET_MODE_BITSIZE (op_mode))))
{
/* If this machine's insv can only insert into a register, copy OP0
into a register and save it back later. */
- /* This used to check flag_force_mem, but that was a serious
- de-optimization now that flag_force_mem is enabled by -O2. */
if (MEM_P (op0)
&& ! ((*insn_data[(int) CODE_FOR_insv].operand[0].predicate)
(op0, VOIDmode)))
/* Now clear the chosen bits in OP0,
except that if VALUE is -1 we need not bother. */
- subtarget = (REG_P (op0) || ! flag_force_mem) ? op0 : 0;
+ subtarget = op0;
if (! all_one)
{
if (unsignedp)
{
if (HAVE_extzv
- && (GET_MODE_BITSIZE (extzv_mode) >= bitsize)
+ && bitsize > 0
+ && GET_MODE_BITSIZE (extzv_mode) >= bitsize
&& ! ((REG_P (op0) || GET_CODE (op0) == SUBREG)
&& (bitsize + bitpos > GET_MODE_BITSIZE (extzv_mode))))
{
xbitpos = bitnum % unit;
xop0 = adjust_address (xop0, bestmode, xoffset);
+ /* Make sure register is big enough for the whole field. */
+ if (xoffset * BITS_PER_UNIT + unit
+ < offset * BITS_PER_UNIT + bitsize)
+ goto extzv_loses;
+
/* Fetch it to a register in that size. */
xop0 = force_reg (bestmode, xop0);
unit = GET_MODE_BITSIZE (maxmode);
- if (xtarget == 0
- || (flag_force_mem && MEM_P (xtarget)))
+ if (xtarget == 0)
xtarget = xspec_target = gen_reg_rtx (tmode);
if (GET_MODE (xtarget) != maxmode)
else
{
if (HAVE_extv
- && (GET_MODE_BITSIZE (extv_mode) >= bitsize)
+ && bitsize > 0
+ && GET_MODE_BITSIZE (extv_mode) >= bitsize
&& ! ((REG_P (op0) || GET_CODE (op0) == SUBREG)
&& (bitsize + bitpos > GET_MODE_BITSIZE (extv_mode))))
{
xbitpos = bitnum % unit;
xop0 = adjust_address (xop0, bestmode, xoffset);
+ /* Make sure register is big enough for the whole field. */
+ if (xoffset * BITS_PER_UNIT + unit
+ < offset * BITS_PER_UNIT + bitsize)
+ goto extv_loses;
+
/* Fetch it to a register in that size. */
xop0 = force_reg (bestmode, xop0);
unit = GET_MODE_BITSIZE (maxmode);
- if (xtarget == 0
- || (flag_force_mem && MEM_P (xtarget)))
+ if (xtarget == 0)
xtarget = xspec_target = gen_reg_rtx (tmode);
if (GET_MODE (xtarget) != maxmode)
shifted = force_reg (mode, shifted);
temp = expand_shift (left ? LSHIFT_EXPR : RSHIFT_EXPR,
- mode, shifted, new_amount, subtarget, 1);
+ mode, shifted, new_amount, 0, 1);
temp1 = expand_shift (left ? RSHIFT_EXPR : LSHIFT_EXPR,
- mode, shifted, other_amount, 0, 1);
+ mode, shifted, other_amount, subtarget, 1);
return expand_binop (mode, ior_optab, temp, temp1, target,
unsignedp, methods);
}
temp = expand_binop (mode,
left ? rotl_optab : rotr_optab,
shifted, op1, target, unsignedp, methods);
-
- /* If we don't have the rotate, but we are rotating by a constant
- that is in range, try a rotate in the opposite direction. */
-
- if (temp == 0 && GET_CODE (op1) == CONST_INT
- && INTVAL (op1) > 0
- && (unsigned int) INTVAL (op1) < GET_MODE_BITSIZE (mode))
- temp = expand_binop (mode,
- left ? rotr_optab : rotl_optab,
- shifted,
- GEN_INT (GET_MODE_BITSIZE (mode)
- - INTVAL (op1)),
- target, unsignedp, methods);
}
else if (unsignedp)
temp = expand_binop (mode,
return temp;
}
\f
-enum alg_code { alg_unknown, alg_zero, alg_m, alg_shift,
- alg_add_t_m2, alg_sub_t_m2,
- alg_add_factor, alg_sub_factor,
- alg_add_t2_m, alg_sub_t2_m };
+enum alg_code {
+ alg_unknown,
+ alg_zero,
+ alg_m, alg_shift,
+ alg_add_t_m2,
+ alg_sub_t_m2,
+ alg_add_factor,
+ alg_sub_factor,
+ alg_add_t2_m,
+ alg_sub_t2_m,
+ alg_impossible
+};
/* This structure holds the "cost" of a multiply sequence. The
"cost" field holds the total rtx_cost of every operator in the
/* The best multiplication algorithm for t. */
enum alg_code alg;
+
+ /* The cost of multiplication if ALG_CODE is not alg_impossible.
+ Otherwise, the cost within which multiplication by T is
+ impossible. */
+ struct mult_cost cost;
};
/* The number of cache/hash entries. */
&& alg_hash[hash_index].mode == mode
&& alg_hash[hash_index].alg != alg_unknown)
{
- cache_hit = true;
cache_alg = alg_hash[hash_index].alg;
- switch (cache_alg)
+
+ if (cache_alg == alg_impossible)
{
- case alg_shift:
- goto do_alg_shift;
+ /* The cache tells us that it's impossible to synthesize
+ multiplication by T within alg_hash[hash_index].cost. */
+ if (!CHEAPER_MULT_COST (&alg_hash[hash_index].cost, cost_limit))
+ /* COST_LIMIT is at least as restrictive as the one
+ recorded in the hash table, in which case we have no
+ hope of synthesizing a multiplication. Just
+ return. */
+ return;
+
+ /* If we get here, COST_LIMIT is less restrictive than the
+ one recorded in the hash table, so we may be able to
+ synthesize a multiplication. Proceed as if we didn't
+ have the cache entry. */
+ }
+ else
+ {
+ if (CHEAPER_MULT_COST (cost_limit, &alg_hash[hash_index].cost))
+ /* The cached algorithm shows that this multiplication
+ requires more cost than COST_LIMIT. Just return. This
+ way, we don't clobber this cache entry with
+ alg_impossible but retain useful information. */
+ return;
- case alg_add_t_m2:
- case alg_sub_t_m2:
- goto do_alg_addsub_t_m2;
+ cache_hit = true;
- case alg_add_factor:
- case alg_sub_factor:
- goto do_alg_addsub_factor;
+ switch (cache_alg)
+ {
+ case alg_shift:
+ goto do_alg_shift;
- case alg_add_t2_m:
- goto do_alg_add_t2_m;
+ case alg_add_t_m2:
+ case alg_sub_t_m2:
+ goto do_alg_addsub_t_m2;
- case alg_sub_t2_m:
- goto do_alg_sub_t2_m;
+ case alg_add_factor:
+ case alg_sub_factor:
+ goto do_alg_addsub_factor;
- default:
- gcc_unreachable ();
+ case alg_add_t2_m:
+ goto do_alg_add_t2_m;
+
+ case alg_sub_t2_m:
+ goto do_alg_sub_t2_m;
+
+ default:
+ gcc_unreachable ();
+ }
}
}
done:
/* If best_cost has not decreased, we have not found any algorithm. */
if (!CHEAPER_MULT_COST (&best_cost, cost_limit))
- return;
+ {
+ /* We failed to find an algorithm. Record alg_impossible for
+ this case (that is, <T, MODE, COST_LIMIT>) so that next time
+ we are asked to find an algorithm for T within the same or
+ lower COST_LIMIT, we can immediately return to the
+ caller. */
+ alg_hash[hash_index].t = t;
+ alg_hash[hash_index].mode = mode;
+ alg_hash[hash_index].alg = alg_impossible;
+ alg_hash[hash_index].cost = *cost_limit;
+ return;
+ }
/* Cache the result. */
if (!cache_hit)
alg_hash[hash_index].t = t;
alg_hash[hash_index].mode = mode;
alg_hash[hash_index].alg = best_alg->op[best_alg->ops];
+ alg_hash[hash_index].cost.cost = best_cost.cost;
+ alg_hash[hash_index].cost.latency = best_cost.latency;
}
/* If we are getting a too long sequence for `struct algorithm'
/* These are the operations that are potentially turned into a sequence
of shifts and additions. */
- if (GET_MODE_CLASS (mode) == MODE_INT
+ if (SCALAR_INT_MODE_P (mode)
&& (unsignedp || !flag_trapv))
{
HOST_WIDE_INT coeff = 0;
+ rtx fake_reg = gen_raw_REG (mode, LAST_VIRTUAL_REGISTER + 1);
/* synth_mult does an `unsigned int' multiply. As long as the mode is
less than or equal in size to `unsigned int' this doesn't matter.
&& GET_MODE_BITSIZE (mode) > HOST_BITS_PER_WIDE_INT)
{
/* Its safe to use -INTVAL (op1) even for INT_MIN, as the
- result is interpreted as an unsigned coefficient. */
- max_cost = rtx_cost (gen_rtx_MULT (mode, op0, op1), SET)
+ result is interpreted as an unsigned coefficient.
+ Exclude cost of op0 from max_cost to match the cost
+ calculation of the synth_mult. */
+ max_cost = rtx_cost (gen_rtx_MULT (mode, fake_reg, op1), SET)
- neg_cost[mode];
if (max_cost > 0
&& choose_mult_variant (mode, -INTVAL (op1), &algorithm,
build_int_cst (NULL_TREE, floor_log2 (coeff)),
target, unsignedp);
- max_cost = rtx_cost (gen_rtx_MULT (mode, op0, op1), SET);
+ /* Exclude cost of op0 from max_cost to match the cost
+ calculation of the synth_mult. */
+ max_cost = rtx_cost (gen_rtx_MULT (mode, fake_reg, op1), SET);
if (choose_mult_variant (mode, coeff, &algorithm, &variant,
max_cost))
return expand_mult_const (mode, op0, coeff, target,
/* 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. */
- t->decl.rtl = x;
+ t->decl_with_rtl.rtl = x;
return t;
}