From 98945935fc38f70e3dec29bde596891c456ef47a Mon Sep 17 00:00:00 2001 From: gjl Date: Fri, 21 Nov 2014 14:04:25 +0000 Subject: 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) (mul3, mul3, 3, 3) (3, round3): Fix input operands. * config/avr/avr-dimode.md (add3, sub3) (3, 3, cbranch4) (3, mulsidi3): Fix input operands. * config/avr/avr.md (mulqi3_call, mulhi3_call, mulsi3, mulpsi3) (mulusi3, mulssi3, mulohisi3, mulhisi3) (usmulhisi3, 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. git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@217922 138bc75d-0d04-0410-961f-82ee72b054a4 --- gcc/config/avr/avr.c | 109 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 109 insertions(+) (limited to 'gcc/config/avr/avr.c') diff --git a/gcc/config/avr/avr.c b/gcc/config/avr/avr.c index bbd8644e7bc..bc83adb7c3f 100644 --- a/gcc/config/avr/avr.c +++ b/gcc/config/avr/avr.c @@ -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 " " -- cgit v1.2.1