aboutsummaryrefslogtreecommitdiffstats
path: root/gcc-4.9/gcc/config/avr/avr.c
diff options
context:
space:
mode:
Diffstat (limited to 'gcc-4.9/gcc/config/avr/avr.c')
-rw-r--r--gcc-4.9/gcc/config/avr/avr.c109
1 files changed, 109 insertions, 0 deletions
diff --git a/gcc-4.9/gcc/config/avr/avr.c b/gcc-4.9/gcc/config/avr/avr.c
index fa979df46..4c65f5efa 100644
--- a/gcc-4.9/gcc/config/avr/avr.c
+++ b/gcc-4.9/gcc/config/avr/avr.c
@@ -11118,6 +11118,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 legitimate 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 " "