rtx xop0 = op0;
rtx last = get_last_insn ();
rtx pat;
+ bool copy_back = false;
/* Add OFFSET into OP0's address. */
if (MEM_P (xop0))
if (REG_P (xop0) && GET_MODE (xop0) != op_mode)
xop0 = gen_rtx_SUBREG (op_mode, xop0, 0);
+ /* If the destination is a paradoxical subreg such that we need a
+ truncate to the inner mode, perform the insertion on a temporary and
+ truncate the result to the original destination. Note that we can't
+ just truncate the paradoxical subreg as (truncate:N (subreg:W (reg:N
+ X) 0)) is (reg:N X). */
+ if (GET_CODE (xop0) == SUBREG
+ && REG_P (SUBREG_REG (xop0))
+ && (!TRULY_NOOP_TRUNCATION
+ (GET_MODE_BITSIZE (GET_MODE (SUBREG_REG (xop0))),
+ GET_MODE_BITSIZE (op_mode))))
+ {
+ rtx tem = gen_reg_rtx (op_mode);
+ emit_move_insn (tem, xop0);
+ xop0 = tem;
+ copy_back = true;
+ }
+
/* On big-endian machines, we count bits from the most significant.
If the bit field insn does not, we must invert. */
{
emit_insn (pat);
- /* If the mode of the insertion is wider than the mode of the
- target register we created a paradoxical subreg for the
- target. Truncate the paradoxical subreg of the target to
- itself properly. */
- if (!TRULY_NOOP_TRUNCATION (GET_MODE_BITSIZE (GET_MODE (op0)),
- GET_MODE_BITSIZE (op_mode))
- && (REG_P (xop0)
- || GET_CODE (xop0) == SUBREG))
- convert_move (op0, xop0, true);
+ if (copy_back)
+ convert_move (op0, xop0, true);
return true;
}
delete_insns_since (last);
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. */
static rtx
emit_cstore (rtx target, enum insn_code icode, enum rtx_code code,
enum machine_mode mode, enum machine_mode compare_mode,
- int unsignedp, rtx x, rtx y, int normalizep)
+ int unsignedp, rtx x, rtx y, int normalizep,
+ enum machine_mode target_mode)
{
rtx op0, last, comparison, subtarget, pattern;
- enum machine_mode target_mode;
enum machine_mode result_mode = insn_data[(int) icode].operand[0].mode;
last = get_last_insn ();
return NULL_RTX;
}
- if (!target
- || optimize
+ if (target_mode == VOIDmode)
+ 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);
else
return NULL_RTX;
emit_insn (pattern);
- if (!target)
- target = gen_reg_rtx (GET_MODE (subtarget));
- 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
static rtx
emit_store_flag_1 (rtx target, enum rtx_code code, rtx op0, rtx op1,
- enum machine_mode mode, int unsignedp, int normalizep)
+ enum machine_mode mode, int unsignedp, int normalizep,
+ enum machine_mode target_mode)
{
rtx subtarget;
enum insn_code icode;
enum machine_mode compare_mode;
- enum machine_mode target_mode = target ? GET_MODE (target) : VOIDmode;
enum mode_class mclass;
enum rtx_code scode;
rtx tem;
if (tem != 0)
tem = emit_store_flag (NULL_RTX, code, tem, op1, word_mode,
- unsignedp, normalizep);
+ unsignedp, normalizep);
}
else if ((code == LT || code == GE) && op1 == const0_rtx)
{
if (tem)
{
- if (target_mode == VOIDmode)
+ if (target_mode == VOIDmode || GET_MODE (tem) == target_mode)
return tem;
+ if (!target)
+ target = gen_reg_rtx (target_mode);
convert_move (target, tem,
- 0 == (STORE_FLAG_VALUE
+ 0 == ((normalizep ? normalizep : STORE_FLAG_VALUE)
& ((HOST_WIDE_INT) 1
<< (GET_MODE_BITSIZE (word_mode) -1))));
return target;
{
do_pending_stack_adjust ();
tem = emit_cstore (target, icode, code, mode, compare_mode,
- unsignedp, op0, op1, normalizep);
+ unsignedp, op0, op1, normalizep, target_mode);
if (tem)
return tem;
if (GET_MODE_CLASS (mode) == MODE_FLOAT)
{
tem = emit_cstore (target, icode, scode, mode, compare_mode,
- unsignedp, op1, op0, normalizep);
+ unsignedp, op1, op0, normalizep, target_mode);
if (tem)
return tem;
}
rtx subtarget;
rtx tem, last, trueval;
- tem = emit_store_flag_1 (target, code, op0, op1, mode, unsignedp, normalizep);
+ tem = emit_store_flag_1 (target, code, op0, op1, mode, unsignedp, normalizep,
+ target_mode);
if (tem)
return tem;
|| (! 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);
+ STORE_FLAG_VALUE, target_mode);
if (tem)
return 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);
+ normalizep, target_mode);
if (tem)
return expand_binop (target_mode, xor_optab, tem, trueval,
target, INTVAL (trueval) >= 0, OPTAB_WIDEN);
if (!HONOR_NANS (mode))
{
gcc_assert (first_code == (and_them ? ORDERED : UNORDERED));
- return emit_store_flag_1 (target, code, op0, op1, mode, 0, normalizep);
+ return emit_store_flag_1 (target, code, op0, op1, mode, 0, normalizep,
+ target_mode);
}
#ifdef HAVE_conditional_move
/* Try using a setcc instruction for ORDERED/UNORDERED, followed by a
conditional move. */
- tem = emit_store_flag_1 (subtarget, first_code, op0, op1, mode, 0, normalizep);
+ tem = emit_store_flag_1 (subtarget, first_code, op0, op1, mode, 0,
+ normalizep, target_mode);
if (tem == 0)
return 0;
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);
+ 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);
+ STORE_FLAG_VALUE, target_mode);
if (tem != 0)
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);
+ normalizep, target_mode);
if (tem != 0)
tem = expand_binop (target_mode, xor_optab, tem, trueval, target,
INTVAL (trueval) >= 0, OPTAB_WIDEN);