===================================================================
@@ -1054,6 +1054,8 @@ create_integer_operand (struct expand_op
create_expand_operand (op, EXPAND_INTEGER, GEN_INT (intval), VOIDmode, false);
}
+extern bool multiword_target_p (rtx);
+
extern bool maybe_legitimize_operands (enum insn_code icode,
unsigned int opno, unsigned int nops,
struct expand_operand *ops);
===================================================================
@@ -1342,7 +1342,7 @@ extract_bit_field_1 (rtx str_rtx, unsign
unsigned int nwords = (bitsize + (BITS_PER_WORD - 1)) / BITS_PER_WORD;
unsigned int i;
- if (target == 0 || !REG_P (target))
+ if (target == 0 || !REG_P (target) || !multiword_target_p (target))
target = gen_reg_rtx (mode);
/* Indicate for flow that the entire target reg is being set. */
===================================================================
@@ -1605,7 +1605,10 @@ expand_binop (enum machine_mode mode, op
/* If TARGET is the same as one of the operands, the REG_EQUAL note
won't be accurate, so use a new target. */
- if (target == 0 || target == op0 || target == op1)
+ if (target == 0
+ || target == op0
+ || target == op1
+ || !multiword_target_p (target))
target = gen_reg_rtx (mode);
start_sequence ();
@@ -1659,7 +1662,11 @@ expand_binop (enum machine_mode mode, op
opportunities, and second because if target and op0 happen to be MEMs
designating the same location, we would risk clobbering it too early
in the code sequence we generate below. */
- if (target == 0 || target == op0 || target == op1 || ! REG_P (target))
+ if (target == 0
+ || target == op0
+ || target == op1
+ || !REG_P (target)
+ || !multiword_target_p (target))
target = gen_reg_rtx (mode);
start_sequence ();
@@ -2481,7 +2488,7 @@ expand_doubleword_bswap (enum machine_mo
t0 = expand_unop (word_mode, bswap_optab,
operand_subword_force (op, 1, mode), NULL_RTX, true);
- if (target == 0)
+ if (target == 0 || !multiword_target_p (target))
target = gen_reg_rtx (mode);
if (REG_P (target))
emit_clobber (target);
@@ -2724,7 +2731,9 @@ expand_absneg_bit (enum rtx_code code, e
if (code == ABS)
mask = double_int_not (mask);
- if (target == 0 || target == op0)
+ if (target == 0
+ || target == op0
+ || (nwords > 1 && !multiword_target_p (target)))
target = gen_reg_rtx (mode);
if (nwords > 1)
@@ -2915,7 +2924,7 @@ expand_unop (enum machine_mode mode, opt
int i;
rtx insns;
- if (target == 0 || target == op0)
+ if (target == 0 || target == op0 || !multiword_target_p (target))
target = gen_reg_rtx (mode);
start_sequence ();
@@ -3386,7 +3395,10 @@ expand_copysign_bit (enum machine_mode m
mask = double_int_setbit (double_int_zero, bitpos);
- if (target == 0 || target == op0 || target == op1)
+ if (target == 0
+ || target == op0
+ || target == op1
+ || (nwords > 1 && !multiword_target_p (target)))
target = gen_reg_rtx (mode);
if (nwords > 1)
@@ -7001,6 +7013,23 @@ insn_operand_matches (enum insn_code ico
(operand, insn_data[(int) icode].operand[opno].mode)));
}
+/* TARGET is a target of a multiword operation that we are going to
+ implement as a series of word-mode operations. Return true if
+ TARGET is suitable for this purpose. */
+
+bool
+multiword_target_p (rtx target)
+{
+ enum machine_mode mode;
+ int i;
+
+ mode = GET_MODE (target);
+ for (i = 0; i < GET_MODE_SIZE (mode); i += UNITS_PER_WORD)
+ if (!validate_subreg (word_mode, mode, target, i))
+ return false;
+ return true;
+}
+
/* Like maybe_legitimize_operand, but do not change the code of the
current rtx value. */
===================================================================
@@ -0,0 +1,8 @@
+/* { dg-options "-mhard-float -mgp32 -O" } */
+register double g __asm__("$f20");
+
+NOMIPS16 void
+test (double a)
+{
+ g = -a;
+}