Forward-port from 2014-10-30 4_9-branch r216934 PR target/63633

gcc/
	Forward-port from 2014-10-30 4_9-branch r216934
	PR target/63633
	* config/avr/avr-protos.h (regmask): New inline function.
	(avr_fix_inputs, avr_emit3_fix_outputs): New protos.
	* config/avr/avr.c (avr_fix_operands, avr_move_fixed_operands)
	(avr_fix_inputs, avr_emit3_fix_outputs): New functions.
	* config/avr/avr-fixed.md (mulqq3_nomul, muluqq3_nomul)
	(mul<ALL2QA>3, mul<ALL4A>3, <usdiv><ALL1Q>3, <usdiv><ALL2QA>3)
	(<usdiv><ALL4A>3, round<ALL124QA>3): Fix input operands.
	* config/avr/avr-dimode.md (add<ALL8>3, sub<ALL8>3)
	(<ss_addsub><ALL8S>3, <us_addsub><ALL8U>3, cbranch<ALL8>4)
	(<di_shifts><ALL8>3, <any_extend>mulsidi3): Fix input operands.
	* config/avr/avr.md (mulqi3_call, mulhi3_call, mulsi3, mulpsi3)
	(mulu<QIHI>si3, muls<QIHI>si3, mulohisi3, <any_extend>mulhisi3)
	(usmulhisi3, <any_extend>mulhi3_highpart, mulsqipsi3)
	(fmul, fmuls, fmulsu): Fix operands.  Turn insn into expander as
	needed.

gcc/testsuite/
	Forward-port from 2014-10-30 4_9-branch r216934
	PR target/63633
	* gcc.target/avr/torture/pr63633-ice-mult.c: New test.

From-SVN: r217922
This commit is contained in:
Georg-Johann Lay 2014-11-21 14:04:25 +00:00 committed by Georg-Johann Lay
parent 7697b16f45
commit 00e641f13e
7 changed files with 307 additions and 16 deletions

View File

@ -68,6 +68,7 @@
{
rtx acc_a = gen_rtx_REG (<MODE>mode, ACC_A);
avr_fix_inputs (operands, 1 << 2, regmask (<MODE>mode, ACC_A));
emit_move_insn (acc_a, operands[1]);
if (DImode == <MODE>mode
@ -145,6 +146,7 @@
{
rtx acc_a = gen_rtx_REG (<MODE>mode, ACC_A);
avr_fix_inputs (operands, 1 << 2, regmask (<MODE>mode, ACC_A));
emit_move_insn (acc_a, operands[1]);
if (const_operand (operands[2], GET_MODE (operands[2])))
@ -201,6 +203,7 @@
{
rtx acc_a = gen_rtx_REG (<MODE>mode, ACC_A);
avr_fix_inputs (operands, 1 << 2, regmask (<MODE>mode, ACC_A));
emit_move_insn (acc_a, operands[1]);
if (const_operand (operands[2], GET_MODE (operands[2])))
@ -249,6 +252,7 @@
{
rtx acc_a = gen_rtx_REG (<MODE>mode, ACC_A);
avr_fix_inputs (operands, 1 << 2, regmask (<MODE>mode, ACC_A));
emit_move_insn (acc_a, operands[1]);
if (const_operand (operands[2], GET_MODE (operands[2])))
@ -338,6 +342,7 @@
{
rtx acc_a = gen_rtx_REG (<MODE>mode, ACC_A);
avr_fix_inputs (operands, 1 << 2, regmask (<MODE>mode, ACC_A));
emit_move_insn (acc_a, operands[1]);
if (s8_operand (operands[2], VOIDmode))
@ -424,6 +429,7 @@
{
rtx acc_a = gen_rtx_REG (<MODE>mode, ACC_A);
avr_fix_inputs (operands, 1 << 2, regmask (<MODE>mode, ACC_A));
emit_move_insn (acc_a, operands[1]);
emit_move_insn (gen_rtx_REG (QImode, 16), operands[2]);
emit_insn (gen_<code_stdname><mode>3_insn ());
@ -457,6 +463,7 @@
(clobber (any_extend:SI (match_dup 1)))])]
"avr_have_dimode"
{
avr_fix_inputs (operands, 1 << 2, regmask (SImode, 22));
emit_move_insn (gen_rtx_REG (SImode, 22), operands[1]);
emit_move_insn (gen_rtx_REG (SImode, 18), operands[2]);
emit_insn (gen_<extend_u>mulsidi3_insn());

View File

@ -231,7 +231,11 @@
(clobber (reg:HI 24))])
(set (match_operand:QQ 0 "register_operand" "")
(reg:QQ 23))]
"!AVR_HAVE_MUL")
"!AVR_HAVE_MUL"
{
avr_fix_inputs (operands, 1 << 2, regmask (QQmode, 24));
})
(define_expand "muluqq3_nomul"
[(set (reg:UQQ 22)
@ -246,7 +250,10 @@
(clobber (reg:HI 22))])
(set (match_operand:UQQ 0 "register_operand" "")
(reg:UQQ 25))]
"!AVR_HAVE_MUL")
"!AVR_HAVE_MUL"
{
avr_fix_inputs (operands, 1 << 2, regmask (UQQmode, 22));
})
(define_insn "*mulqq3.call"
[(set (reg:QQ 23)
@ -274,7 +281,10 @@
(clobber (reg:HI 22))])
(set (match_operand:ALL2QA 0 "register_operand" "")
(reg:ALL2QA 24))]
"AVR_HAVE_MUL")
"AVR_HAVE_MUL"
{
avr_fix_inputs (operands, 1 << 2, regmask (<MODE>mode, 18));
})
;; "*mulhq3.call" "*muluhq3.call"
;; "*mulha3.call" "*muluha3.call"
@ -302,7 +312,10 @@
(reg:ALL4A 20)))
(set (match_operand:ALL4A 0 "register_operand" "")
(reg:ALL4A 24))]
"AVR_HAVE_MUL")
"AVR_HAVE_MUL"
{
avr_fix_inputs (operands, 1 << 2, regmask (<MODE>mode, 16));
})
;; "*mulsa3.call" "*mulusa3.call"
(define_insn "*mul<mode>3.call"
@ -330,7 +343,12 @@
(reg:ALL1Q 22)))
(clobber (reg:QI 25))])
(set (match_operand:ALL1Q 0 "register_operand" "")
(reg:ALL1Q 24))])
(reg:ALL1Q 24))]
""
{
avr_fix_inputs (operands, 1 << 2, regmask (<MODE>mode, 25));
})
;; "*divqq3.call" "*udivuqq3.call"
(define_insn "*<code><mode>3.call"
@ -356,7 +374,11 @@
(clobber (reg:HI 26))
(clobber (reg:QI 21))])
(set (match_operand:ALL2QA 0 "register_operand" "")
(reg:ALL2QA 24))])
(reg:ALL2QA 24))]
""
{
avr_fix_inputs (operands, 1 << 2, regmask (<MODE>mode, 26));
})
;; "*divhq3.call" "*udivuhq3.call"
;; "*divha3.call" "*udivuha3.call"
@ -385,7 +407,11 @@
(clobber (reg:HI 26))
(clobber (reg:HI 30))])
(set (match_operand:ALL4A 0 "register_operand" "")
(reg:ALL4A 22))])
(reg:ALL4A 22))]
""
{
avr_fix_inputs (operands, 1 << 2, regmask (<MODE>mode, 24));
})
;; "*divsa3.call" "*udivusa3.call"
(define_insn "*<code><mode>3.call"
@ -435,6 +461,7 @@
operands[3] = gen_rtx_REG (<MODE>mode, regno_out[(size_t) GET_MODE_SIZE (<MODE>mode)]);
operands[4] = gen_rtx_REG (<MODE>mode, regno_in[(size_t) GET_MODE_SIZE (<MODE>mode)]);
avr_fix_inputs (operands, 1 << 2, regmask (<MODE>mode, REGNO (operands[4])));
operands[5] = simplify_gen_subreg (QImode, force_reg (HImode, operands[2]), HImode, 0);
// $2 is no more needed, but is referenced for expand.
operands[2] = const0_rtx;

View File

@ -129,6 +129,15 @@ extern bool avr_load_libgcc_p (rtx);
extern bool avr_xload_libgcc_p (machine_mode);
extern rtx avr_eval_addr_attrib (rtx x);
static inline unsigned
regmask (machine_mode mode, unsigned regno)
{
return ((1u << GET_MODE_SIZE (mode)) - 1) << regno;
}
extern void avr_fix_inputs (rtx*, unsigned, unsigned);
extern bool avr_emit3_fix_outputs (rtx (*)(rtx,rtx,rtx), rtx*, unsigned, unsigned);
extern rtx lpm_reg_rtx;
extern rtx lpm_addr_reg_rtx;
extern rtx tmp_reg_rtx;

View File

@ -12201,6 +12201,115 @@ avr_convert_to_type (tree type, tree expr)
}
/* PR63633: The middle-end might come up with hard regs as input operands.
RMASK is a bit mask representing a subset of hard registers R0...R31:
Rn is an element of that set iff bit n of RMASK is set.
OPMASK describes a subset of OP[]: If bit n of OPMASK is 1 then
OP[n] has to be fixed; otherwise OP[n] is left alone.
For each element of OPMASK which is a hard register overlapping RMASK,
replace OP[n] with a newly created pseudo register
HREG == 0: Also emit a move insn that copies the contents of that
hard register into the new pseudo.
HREG != 0: Also set HREG[n] to the hard register. */
static void
avr_fix_operands (rtx *op, rtx *hreg, unsigned opmask, unsigned rmask)
{
for (; opmask; opmask >>= 1, op++)
{
rtx reg = *op;
if (hreg)
*hreg = NULL_RTX;
if ((opmask & 1)
&& REG_P (reg)
&& REGNO (reg) < FIRST_PSEUDO_REGISTER
// This hard-reg overlaps other prohibited hard regs?
&& (rmask & regmask (GET_MODE (reg), REGNO (reg))))
{
*op = gen_reg_rtx (GET_MODE (reg));
if (hreg == NULL)
emit_move_insn (*op, reg);
else
*hreg = reg;
}
if (hreg)
hreg++;
}
}
void
avr_fix_inputs (rtx *op, unsigned opmask, unsigned rmask)
{
avr_fix_operands (op, NULL, opmask, rmask);
}
/* Helper for the function below: If bit n of MASK is set and
HREG[n] != NULL, then emit a move insn to copy OP[n] to HREG[n].
Otherwise do nothing for that n. Return TRUE. */
static bool
avr_move_fixed_operands (rtx *op, rtx *hreg, unsigned mask)
{
for (; mask; mask >>= 1, op++, hreg++)
if ((mask & 1)
&& *hreg)
emit_move_insn (*hreg, *op);
return true;
}
/* PR63633: The middle-end might come up with hard regs as output operands.
GEN is a sequence generating function like gen_mulsi3 with 3 operands OP[].
RMASK is a bit mask representing a subset of hard registers R0...R31:
Rn is an element of that set iff bit n of RMASK is set.
OPMASK describes a subset of OP[]: If bit n of OPMASK is 1 then
OP[n] has to be fixed; otherwise OP[n] is left alone.
Emit the insn sequence as generated by GEN() with all elements of OPMASK
which are hard registers overlapping RMASK replaced by newly created
pseudo registers. After the sequence has been emitted, emit insns that
move the contents of respective pseudos to their hard regs. */
bool
avr_emit3_fix_outputs (rtx (*gen)(rtx,rtx,rtx), rtx *op,
unsigned opmask, unsigned rmask)
{
const int n = 3;
rtx hreg[n];
/* It is letigimate for GEN to call this function, and in order not to
get self-recursive we use the following static kludge. This is the
only way not to duplicate all expanders and to avoid ugly and
hard-to-maintain C-code instead of the much more appreciated RTL
representation as supplied by define_expand. */
static bool lock = false;
gcc_assert (opmask < (1u << n));
if (lock)
return false;
avr_fix_operands (op, hreg, opmask, rmask);
lock = true;
emit_insn (gen (op[0], op[1], op[2]));
lock = false;
return avr_move_fixed_operands (op, hreg, opmask);
}
/* Worker function for movmemhi expander.
XOP[0] Destination as MEM:BLK
XOP[1] Source " "

View File

@ -1548,7 +1548,11 @@
(set (reg:QI 22) (match_operand:QI 2 "register_operand" ""))
(parallel [(set (reg:QI 24) (mult:QI (reg:QI 24) (reg:QI 22)))
(clobber (reg:QI 22))])
(set (match_operand:QI 0 "register_operand" "") (reg:QI 24))])
(set (match_operand:QI 0 "register_operand" "") (reg:QI 24))]
""
{
avr_fix_inputs (operands, 1 << 2, regmask (QImode, 24));
})
(define_insn "*mulqi3_call"
[(set (reg:QI 24) (mult:QI (reg:QI 24) (reg:QI 22)))
@ -2276,7 +2280,13 @@
(parallel [(set (reg:HI 24) (mult:HI (reg:HI 24) (reg:HI 22)))
(clobber (reg:HI 22))
(clobber (reg:QI 21))])
(set (match_operand:HI 0 "register_operand" "") (reg:HI 24))])
(set (match_operand:HI 0 "register_operand" "")
(reg:HI 24))]
""
{
avr_fix_inputs (operands, (1 << 2), regmask (HImode, 24));
})
(define_insn "*mulhi3_call"
[(set (reg:HI 24) (mult:HI (reg:HI 24) (reg:HI 22)))
@ -2314,6 +2324,10 @@
emit_insn (gen_mulohisi3 (operands[0], operands[2], operands[1]));
DONE;
}
if (avr_emit3_fix_outputs (gen_mulsi3, operands, 1 << 0,
regmask (DImode, 18) | regmask (HImode, 26)))
DONE;
})
(define_insn_and_split "*mulsi3"
@ -2353,7 +2367,23 @@
;; "muluqisi3"
;; "muluhisi3"
(define_insn_and_split "mulu<mode>si3"
(define_expand "mulu<mode>si3"
[(parallel [(set (match_operand:SI 0 "pseudo_register_operand" "")
(mult:SI (zero_extend:SI (match_operand:QIHI 1 "pseudo_register_operand" ""))
(match_operand:SI 2 "pseudo_register_or_const_int_operand" "")))
(clobber (reg:HI 26))
(clobber (reg:DI 18))])]
"AVR_HAVE_MUL"
{
avr_fix_inputs (operands, (1 << 1) | (1 << 2), -1u);
if (avr_emit3_fix_outputs (gen_mulu<mode>si3, operands, 1 << 0,
regmask (DImode, 18) | regmask (HImode, 26)))
DONE;
})
;; "*muluqisi3"
;; "*muluhisi3"
(define_insn_and_split "*mulu<mode>si3"
[(set (match_operand:SI 0 "pseudo_register_operand" "=r")
(mult:SI (zero_extend:SI (match_operand:QIHI 1 "pseudo_register_operand" "r"))
(match_operand:SI 2 "pseudo_register_or_const_int_operand" "rn")))
@ -2389,7 +2419,23 @@
;; "mulsqisi3"
;; "mulshisi3"
(define_insn_and_split "muls<mode>si3"
(define_expand "muls<mode>si3"
[(parallel [(set (match_operand:SI 0 "pseudo_register_operand" "")
(mult:SI (sign_extend:SI (match_operand:QIHI 1 "pseudo_register_operand" ""))
(match_operand:SI 2 "pseudo_register_or_const_int_operand" "")))
(clobber (reg:HI 26))
(clobber (reg:DI 18))])]
"AVR_HAVE_MUL"
{
avr_fix_inputs (operands, (1 << 1) | (1 << 2), -1u);
if (avr_emit3_fix_outputs (gen_muls<mode>si3, operands, 1 << 0,
regmask (DImode, 18) | regmask (HImode, 26)))
DONE;
})
;; "*mulsqisi3"
;; "*mulshisi3"
(define_insn_and_split "*muls<mode>si3"
[(set (match_operand:SI 0 "pseudo_register_operand" "=r")
(mult:SI (sign_extend:SI (match_operand:QIHI 1 "pseudo_register_operand" "r"))
(match_operand:SI 2 "pseudo_register_or_const_int_operand" "rn")))
@ -2432,7 +2478,22 @@
;; One-extend operand 1
(define_insn_and_split "mulohisi3"
(define_expand "mulohisi3"
[(parallel [(set (match_operand:SI 0 "pseudo_register_operand" "")
(mult:SI (not:SI (zero_extend:SI
(not:HI (match_operand:HI 1 "pseudo_register_operand" ""))))
(match_operand:SI 2 "pseudo_register_or_const_int_operand" "")))
(clobber (reg:HI 26))
(clobber (reg:DI 18))])]
"AVR_HAVE_MUL"
{
avr_fix_inputs (operands, (1 << 1) | (1 << 2), -1u);
if (avr_emit3_fix_outputs (gen_mulohisi3, operands, 1 << 0,
regmask (DImode, 18) | regmask (HImode, 26)))
DONE;
})
(define_insn_and_split "*mulohisi3"
[(set (match_operand:SI 0 "pseudo_register_operand" "=r")
(mult:SI (not:SI (zero_extend:SI
(not:HI (match_operand:HI 1 "pseudo_register_operand" "r"))))
@ -2460,7 +2521,12 @@
(any_extend:SI (match_operand:HI 2 "register_operand" ""))))
(clobber (reg:HI 26))
(clobber (reg:DI 18))])]
"AVR_HAVE_MUL")
"AVR_HAVE_MUL"
{
if (avr_emit3_fix_outputs (gen_<extend_u>mulhisi3, operands, 1 << 0,
regmask (DImode, 18) | regmask (HImode, 26)))
DONE;
})
(define_expand "usmulhisi3"
[(parallel [(set (match_operand:SI 0 "register_operand" "")
@ -2468,7 +2534,12 @@
(sign_extend:SI (match_operand:HI 2 "register_operand" ""))))
(clobber (reg:HI 26))
(clobber (reg:DI 18))])]
"AVR_HAVE_MUL")
"AVR_HAVE_MUL"
{
if (avr_emit3_fix_outputs (gen_usmulhisi3, operands, 1 << 0,
regmask (DImode, 18) | regmask (HImode, 26)))
DONE;
})
;; "*uumulqihisi3" "*uumulhiqisi3" "*uumulhihisi3" "*uumulqiqisi3"
;; "*usmulqihisi3" "*usmulhiqisi3" "*usmulhihisi3" "*usmulqiqisi3"
@ -2540,7 +2611,10 @@
(clobber (reg:HI 22))])
(set (match_operand:HI 0 "register_operand" "")
(reg:HI 24))]
"AVR_HAVE_MUL")
"AVR_HAVE_MUL"
{
avr_fix_inputs (operands, 1 << 2, regmask (HImode, 18));
})
(define_insn "*mulsi3_call"
@ -2763,6 +2837,10 @@
emit_insn (gen_mulsqipsi3 (operands[0], reg, operands[1]));
DONE;
}
if (avr_emit3_fix_outputs (gen_mulpsi3, operands, 1u << 0,
regmask (DImode, 18) | regmask (HImode, 26)))
DONE;
})
(define_insn "*umulqihipsi3"
@ -2795,7 +2873,21 @@
[(set_attr "length" "7")
(set_attr "cc" "clobber")])
(define_insn_and_split "mulsqipsi3"
(define_expand "mulsqipsi3"
[(parallel [(set (match_operand:PSI 0 "pseudo_register_operand" "")
(mult:PSI (sign_extend:PSI (match_operand:QI 1 "pseudo_register_operand" ""))
(match_operand:PSI 2 "pseudo_register_or_const_int_operand""")))
(clobber (reg:HI 26))
(clobber (reg:DI 18))])]
"AVR_HAVE_MUL"
{
avr_fix_inputs (operands, (1 << 1) | (1 << 2), -1u);
if (avr_emit3_fix_outputs (gen_mulsqipsi3, operands, 1 << 0,
regmask (DImode, 18) | regmask (HImode, 26)))
DONE;
})
(define_insn_and_split "*mulsqipsi3"
[(set (match_operand:PSI 0 "pseudo_register_operand" "=r")
(mult:PSI (sign_extend:PSI (match_operand:QI 1 "pseudo_register_operand" "r"))
(match_operand:PSI 2 "pseudo_register_or_const_int_operand" "rn")))
@ -6134,6 +6226,7 @@
emit_insn (gen_fmul_insn (operand0, operand1, operand2));
DONE;
}
avr_fix_inputs (operands, 1 << 2, regmask (QImode, 24));
})
(define_insn "fmul_insn"
@ -6177,6 +6270,7 @@
emit_insn (gen_fmuls_insn (operand0, operand1, operand2));
DONE;
}
avr_fix_inputs (operands, 1 << 2, regmask (QImode, 24));
})
(define_insn "fmuls_insn"
@ -6220,6 +6314,7 @@
emit_insn (gen_fmulsu_insn (operand0, operand1, operand2));
DONE;
}
avr_fix_inputs (operands, 1 << 2, regmask (QImode, 24));
})
(define_insn "fmulsu_insn"

View File

@ -1,3 +1,10 @@
2014-11-21 Georg-Johann Lay <avr@gjlay.de>
Forward-port from 2014-10-30 4_9-branch r216934
PR target/63633
* gcc.target/avr/torture/pr63633-ice-mult.c: New test.
2014-11-21 Francois-Xavier Coudert <fxcoudert@gcc.gnu.org>
PR debug/63239

View File

@ -0,0 +1,37 @@
/* { dg-do compile } */
void ice_mult32 (int x)
{
register long reg __asm ("22");
__asm volatile (" " :: "r" (reg = 0x12345 * x));
}
void ice_mult24 (int x)
{
register __int24 reg __asm ("20");
__asm volatile (" " :: "r" (reg = 0x12345 * x));
}
void ice_sh24 (__int24 x)
{
register __int24 reg __asm ("20");
__asm volatile (" " :: "r" (reg = x << 3));
}
void ice_sh24b (__int24 x)
{
register __int24 reg __asm ("20");
__asm volatile (" " :: "r" (reg = x << 22));
}
void ice_s16s16 (int x)
{
register long reg __asm ("20");
__asm volatile (" " :: "r" (reg = (long) x*x));
}
void ice_u16s16 (int x)
{
register long reg __asm ("20");
__asm volatile (" " :: "r" (reg = (long) x*0x1234u));
}