+2013-09-20 DJ Delorie <dj@redhat.com>
+ Nick Clifton <nickc@redhat.com>
+
+ * config/rl78/rl78.c: Various whitespace and comment tweaks.
+ (need_to_save): Save bank 0 on interrupts.
+ (characterize_address): Strip far address wrappers.
+ (rl78_as_legitimate_address): Likewise.
+ (transcode_memory_rtx): Likewise.
+ (rl78_peep_movhi_p): Disable this peephole after devirt.
+ (rl78_propogate_register_origins): Forget all origins when a
+ CLOBBER is seen.
+ * config/rl78/rl78-virt.md: Various whitespace tweaks.
+ * config/rl78/rl78-real.md: Various whitespace tweaks. Additional
+ peephole2's.
+ * config/rl78/rl78.md (sel_rb): Disable for G10 just in case.
+ * config/rl78/rl78-expand.md (movqi): Check for subregs of consts.
+ * config/rl78/rl78.h (LINK_SPEC): Pass -gc-sections unless
+ relocating.
+ * config/rl78/constraints.md: Various whitespace and paren tweaks.
+
2013-09-20 John David Anglin <danglin@gcc.gnu.org>
* config/pa/pa.md: In "scc" insn patterns, change output template to
Integer constant equal to 8."
(and (match_code "const_int")
(match_test "IN_RANGE (ival, 8, 8)")))
+
(define_constraint "Iv16"
"@internal
Integer constant equal to 16."
(and (match_code "const_int")
(match_test "IN_RANGE (ival, 16, 16)")))
+
(define_constraint "Iv24"
"@internal
Integer constant equal to 24."
Integer constant in the range 9 @dots{} 15 (for shifts)."
(and (match_code "const_int")
(match_test "IN_RANGE (ival, 9, 15)")))
+
(define_constraint "Is17"
"@internal
Integer constant in the range 17 @dots{} 23 (for shifts)."
(and (match_code "const_int")
(match_test "IN_RANGE (ival, 17, 23)")))
+
(define_constraint "Is25"
"@internal
Integer constant in the range 25 @dots{} 31 (for shifts)."
)
(define_memory_constraint "Wab"
"es:[addr]"
- (match_test "rl78_es_addr (op) && satisfies_constraint_Cab (rl78_es_base (op))
+ (match_test "(rl78_es_addr (op) && satisfies_constraint_Cab (rl78_es_base (op)))
|| satisfies_constraint_Cab (op)")
)
)
(define_memory_constraint "Wbc"
"es:word16[BC]"
- (match_test "rl78_es_addr (op) && satisfies_constraint_Cbc (rl78_es_base (op))
+ (match_test "(rl78_es_addr (op) && satisfies_constraint_Cbc (rl78_es_base (op)))
|| satisfies_constraint_Cbc (op)")
)
)
(define_memory_constraint "Wde"
"es:[DE]"
- (match_test "rl78_es_addr (op) && satisfies_constraint_Cde (rl78_es_base (op))
+ (match_test "(rl78_es_addr (op) && satisfies_constraint_Cde (rl78_es_base (op)))
|| satisfies_constraint_Cde (op)")
)
)
(define_memory_constraint "Wca"
"es:[AX..HL] for calls"
- (match_test "rl78_es_addr (op) && satisfies_constraint_Cca (rl78_es_base (op))
+ (match_test "(rl78_es_addr (op) && satisfies_constraint_Cca (rl78_es_base (op)))
|| satisfies_constraint_Cca (op)")
)
"[AX..HL,r8-r31] for calls"
(and (match_code "mem")
(and (match_code "reg" "0")
- (match_test "REGNO (XEXP (op, 0)) < 31")))
+ (match_test "REGNO (XEXP (op, 0)) < 32")))
)
(define_memory_constraint "Wcv"
- "es:[AX..HL,r8-r23] for calls"
- (match_test "rl78_es_addr (op) && satisfies_constraint_Ccv (rl78_es_base (op))
+ "es:[AX..HL,r8-r31] for calls"
+ (match_test "(rl78_es_addr (op) && satisfies_constraint_Ccv (rl78_es_base (op)))
|| satisfies_constraint_Ccv (op)")
)
)
(define_memory_constraint "Wd2"
"es:word16[DE]"
- (match_test "rl78_es_addr (op) && satisfies_constraint_Cd2 (rl78_es_base (op))
+ (match_test "(rl78_es_addr (op) && satisfies_constraint_Cd2 (rl78_es_base (op)))
|| satisfies_constraint_Cd2 (op)")
)
)
(define_memory_constraint "Whl"
"es:[HL]"
- (match_test "rl78_es_addr (op) && satisfies_constraint_Chl (rl78_es_base (op))
+ (match_test "(rl78_es_addr (op) && satisfies_constraint_Chl (rl78_es_base (op)))
|| satisfies_constraint_Chl (op)")
)
)
(define_memory_constraint "Wh1"
"es:byte8[HL]"
- (match_test "rl78_es_addr (op) && satisfies_constraint_Ch1 (rl78_es_base (op))
+ (match_test "(rl78_es_addr (op) && satisfies_constraint_Ch1 (rl78_es_base (op)))
|| satisfies_constraint_Ch1 (op)")
)
)
(define_memory_constraint "Whb"
"es:[HL+B]"
- (match_test "rl78_es_addr (op) && satisfies_constraint_Chb (rl78_es_base (op))
+ (match_test "(rl78_es_addr (op) && satisfies_constraint_Chb (rl78_es_base (op)))
|| satisfies_constraint_Chb (op)")
)
)
(define_memory_constraint "Ws1"
"es:word8[SP]"
- (match_test "rl78_es_addr (op) && satisfies_constraint_Cs1 (rl78_es_base (op))
+ (match_test "(rl78_es_addr (op) && satisfies_constraint_Cs1 (rl78_es_base (op)))
|| satisfies_constraint_Cs1 (op)")
)
&& GET_CODE (XEXP (XEXP (XEXP (operand1, 0), 0), 0)) == SYMBOL_REF)
FAIL;
- /* Similarly for (SUBREG (CONST (PLUS (SYMBOL_REF)))).
- cf. g++.dg/abi/packed.C. */
- if (GET_CODE (operand1) == SUBREG
- && GET_CODE (XEXP (operand1, 0)) == CONST
- && GET_CODE (XEXP (XEXP (operand1, 0), 0)) == PLUS
- && GET_CODE (XEXP (XEXP (XEXP (operand1, 0), 0), 0)) == SYMBOL_REF)
- FAIL;
-
if (CONST_INT_P (operand1) && ! IN_RANGE (INTVAL (operand1), (-1 << 8) + 1, (1 << 8) - 1))
FAIL;
}
call\t%A1"
)
-(define_insn "cbranchqi4_real_signed"
+(define_insn "*cbranchqi4_real_signed"
[(set (pc) (if_then_else
(match_operator 0 "rl78_cmp_operator_signed"
[(match_operand:QI 1 "general_operand" "A,A,A")
cmp\t%1, %2 \;xor1 CY,%1.7\;xor1 CY,%2.7\;sk%c0 \;br\t!!%3"
)
-
(define_insn "*cbranchqi4_real"
[(set (pc) (if_then_else
(match_operator 0 "rl78_cmp_operator_real"
cmp\t%1, %2 \;sk%c0 \;br\t!!%3"
)
-(define_insn "cbranchhi4_real_signed"
+(define_insn "*cbranchhi4_real_signed"
[(set (pc) (if_then_else
(match_operator 0 "rl78_cmp_operator_signed"
[(match_operand:HI 1 "general_operand" "A,A,A,vR")
"cmpw\t%1, %2 \;sk%c0 \;br\t!!%3"
)
-(define_insn "cbranchsi4_real_lt"
+(define_insn "*cbranchsi4_real_lt"
[(set (pc) (if_then_else
(lt (match_operand:SI 0 "general_operand" "U,vWabWhlWh1")
(const_int 0))
mov1 CY,%E0.7 \;sknc \;br\t!!%1"
)
-(define_insn "cbranchsi4_real_ge"
+(define_insn "*cbranchsi4_real_ge"
[(set (pc) (if_then_else
(ge (match_operand:SI 0 "general_operand" "U,vWabWhlWh1")
(const_int 0))
mov1 CY,%E0.7 \;skc \;br\t!!%1"
)
-(define_insn "cbranchsi4_real_signed"
+(define_insn "*cbranchsi4_real_signed"
[(set (pc) (if_then_else
(match_operator 0 "rl78_cmp_operator_signed"
[(match_operand:SI 1 "nonimmediate_operand" "vU,vU,vU")
movw ax,%H1 \;cmpw ax, %H2 \;xor1 CY,a.7\;xor1 CY,%E2.7\;movw ax,%h1 \;sknz \;cmpw ax, %h2 \;sk%c0 \;br\t!!%3"
)
-(define_insn "cbranchsi4_real"
+(define_insn "*cbranchsi4_real"
[(set (pc) (if_then_else
(match_operator 0 "rl78_cmp_operator_real"
[(match_operand:SI 1 "general_operand" "vUi")
;; in the peephole not matching and the optimization being missed.
(define_peephole2
- [(set (match_operand:QI 1 "register_operand") (reg:QI A_REG))
- (set (match_dup 1) (and:QI (match_dup 1) (match_operand 2 "immediate_operand")))
- (set (pc) (if_then_else (eq (match_dup 1) (const_int 0))
- (label_ref (match_operand 3 ""))
+ [(set (match_operand:QI 0 "register_operand") (reg:QI A_REG))
+ (set (match_dup 0) (and:QI (match_dup 0) (match_operand 1 "immediate_operand")))
+ (set (pc) (if_then_else (eq (match_dup 0) (const_int 0))
+ (label_ref (match_operand 2 ""))
+ (pc)))]
+ "peep2_regno_dead_p (3, REGNO (operands[0]))
+ && exact_log2 (INTVAL (operands[1])) >= 0"
+ [(set (pc) (if_then_else (eq (and (reg:QI A_REG) (match_dup 1)) (const_int 0))
+ (label_ref (match_dup 2))
(pc)))]
- "peep2_regno_dead_p (3, REGNO (operands[1]))
- && exact_log2 (INTVAL (operands[2])) >= 0"
- [(set (pc) (if_then_else (eq (and (reg:QI A_REG) (match_dup 2)) (const_int 0))
- (label_ref (match_dup 3)) (pc)))]
)
(define_peephole2
- [(set (match_operand:QI 1 "register_operand") (reg:QI A_REG))
- (set (match_dup 1) (and:QI (match_dup 1) (match_operand 2 "immediate_operand")))
- (set (pc) (if_then_else (ne (match_dup 1) (const_int 0))
- (label_ref (match_operand 3 ""))
+ [(set (match_operand:QI 0 "register_operand") (reg:QI A_REG))
+ (set (match_dup 0) (and:QI (match_dup 0) (match_operand 1 "immediate_operand")))
+ (set (pc) (if_then_else (ne (match_dup 0) (const_int 0))
+ (label_ref (match_operand 2 ""))
(pc)))]
- "peep2_regno_dead_p (3, REGNO (operands[1]))
- && exact_log2 (INTVAL (operands[2])) >= 0"
- [(set (pc) (if_then_else (ne (and (reg:QI A_REG) (match_dup 2)) (const_int 0))
- (label_ref (match_dup 3)) (pc)))]
+ "peep2_regno_dead_p (3, REGNO (operands[0]))
+ && exact_log2 (INTVAL (operands[1])) >= 0"
+ [(set (pc) (if_then_else (ne (and (reg:QI A_REG) (match_dup 1)) (const_int 0))
+ (label_ref (match_dup 2))
+ (pc)))]
+ )
+
+;; Eliminate needless register copies.
+(define_peephole2
+ [(set (match_operand:HI 0 "register_operand") (match_operand:HI 1 "register_operand"))
+ (set (match_operand:HI 2 "register_operand") (match_dup 0))]
+ "peep2_regno_dead_p (2, REGNO (operands[0]))
+ && (REGNO (operands[1]) < 8 || REGNO (operands[2]) < 8)"
+ [(set (match_dup 2) (match_dup 1))]
+ )
+
+;; Eliminate needless register copying when performing bit manipulations.
+(define_peephole2
+ [(set (match_operand:QI 0 "register_operand") (reg:QI A_REG))
+ (set (match_dup 0) (ior:QI (match_dup 0) (match_operand 1 "immediate_operand")))
+ (set (reg:QI A_REG) (match_dup 0))]
+ "peep2_regno_dead_p (3, REGNO (operands[0]))"
+ [(set (reg:QI A_REG) (ior:QI (reg:QI A_REG) (match_dup 1)))]
+ )
+
+(define_peephole2
+ [(set (match_operand:QI 0 "register_operand") (reg:QI A_REG))
+ (set (match_dup 0) (xor:QI (match_dup 0) (match_operand 1 "immediate_operand")))
+ (set (reg:QI A_REG) (match_dup 0))]
+ "peep2_regno_dead_p (3, REGNO (operands[0]))"
+ [(set (reg:QI A_REG) (xor:QI (reg:QI A_REG) (match_dup 1)))]
+ )
+
+(define_peephole2
+ [(set (match_operand:QI 0 "register_operand") (reg:QI A_REG))
+ (set (match_dup 0) (and:QI (match_dup 0) (match_operand 1 "immediate_operand")))
+ (set (reg:QI A_REG) (match_dup 0))]
+ "peep2_regno_dead_p (3, REGNO (operands[0]))"
+ [(set (reg:QI A_REG) (and:QI (reg:QI A_REG) (match_dup 1)))]
)
[(set_attr "valloc" "op1")]
)
-(define_insn "cbranchqi4_virt_signed"
+(define_insn "*cbranchqi4_virt_signed"
[(set (pc) (if_then_else
(match_operator 0 "rl78_cmp_operator_signed"
[(match_operand:QI 1 "general_operand" "vim")
[(set_attr "valloc" "cmp")]
)
-(define_insn "cbranchhi4_virt_signed"
+(define_insn "*cbranchhi4_virt_signed"
[(set (pc) (if_then_else
(match_operator 0 "rl78_cmp_operator_signed"
[(match_operand:HI 1 "general_operand" "vim")
[(set_attr "valloc" "cmp")]
)
-(define_insn "cbranchsi4_virt"
+(define_insn "*cbranchsi4_virt"
[(set (pc) (if_then_else
(match_operator 0 "rl78_cmp_operator"
[(match_operand:SI 1 "general_operand" "vim")
return new pass_rl78_devirt (ctxt);
}
+/* Redundant move elimination pass. Must be run after the basic block
+ reordering pass for the best effect. */
+
static unsigned int
move_elim_pass (void)
{
if (TARGET_ALLREGS)
{
int i;
- for (i=24; i<32; i++)
+
+ for (i = 24; i < 32; i++)
fixed_regs[i] = 0;
}
}
}
}
+/* Generate code to move an SImode value. */
void
rl78_split_movsi (rtx *operands)
{
op00 = rl78_subreg (HImode, operands[0], SImode, 0);
op02 = rl78_subreg (HImode, operands[0], SImode, 2);
+
if (GET_CODE (operands[1]) == CONST
|| GET_CODE (operands[1]) == SYMBOL_REF)
{
}
}
-
/* Used by various two-operand expanders which cannot accept all
operands in the "far" namespace. Force some such operands into
registers so that each pattern has at most one far operand. */
{
if (is_interrupt_func (cfun->decl))
{
+ /* We don't know what devirt will need */
+ if (regno < 8)
+ return true;
+
/* We don't need to save registers that have
been reserved for interrupt handlers. */
if (regno > 23)
*index = NULL_RTX;
*addend = NULL_RTX;
+ if (GET_CODE (x) == UNSPEC
+ && XINT (x, 1) == UNS_ES_ADDR)
+ x = XVECEXP (x, 0, 1);
+
if (GET_CODE (x) == REG)
{
*base = x;
bool strict ATTRIBUTE_UNUSED, addr_space_t as ATTRIBUTE_UNUSED)
{
rtx base, index, addend;
+ bool is_far_addr = false;
if (GET_CODE (x) == UNSPEC
&& XINT (x, 1) == UNS_ES_ADDR)
- x = XVECEXP (x, 0, 1);
+ {
+ x = XVECEXP (x, 0, 1);
+ is_far_addr = true;
+ }
if (as == ADDR_SPACE_GENERIC
- && GET_MODE (x) == SImode)
+ && (GET_MODE (x) == SImode || is_far_addr))
return false;
if (! characterize_address (x, &base, &index, &addend))
emit_move_insn (gen_rtx_REG (HImode, 0), gen_rtx_REG (HImode, i*2));
F (emit_insn (gen_push (gen_rtx_REG (HImode, 0))));
}
- else {
- int need_bank = i/4;
- if (need_bank != rb)
- {
- emit_insn (gen_sel_rb (GEN_INT (need_bank)));
- rb = need_bank;
- }
- F (emit_insn (gen_push (gen_rtx_REG (HImode, i*2))));
- }
+ else
+ {
+ int need_bank = i/4;
+
+ if (need_bank != rb)
+ {
+ emit_insn (gen_sel_rb (GEN_INT (need_bank)));
+ rb = need_bank;
+ }
+ F (emit_insn (gen_push (gen_rtx_REG (HImode, i*2))));
+ }
}
+
if (rb != 0)
emit_insn (gen_sel_rb (GEN_INT (0)));
/* (set (op0) (op1))
(set (op2) (op3)) */
+ if (! rl78_virt_insns_ok ())
+ return false;
+
#if DEBUG_PEEP
fprintf (stderr, "\033[33m");
debug_rtx (operands[0]);
/* Return a string describing content INDEX in mode MODE.
WARNING: Can return a pointer to a static buffer. */
-
static const char *
get_content_name (unsigned char index, enum machine_mode mode)
{
/* We need to detect far addresses that haven't been
converted to es/lo16 format. */
for (i=0; i<recog_data.n_operands; i++)
- if (GET_CODE (OP(i)) == MEM
- && GET_MODE (XEXP (OP(i), 0)) == SImode
- && GET_CODE (XEXP (OP(i), 0)) != UNSPEC)
+ if (GET_CODE (OP (i)) == MEM
+ && GET_MODE (XEXP (OP (i), 0)) == SImode
+ && GET_CODE (XEXP (OP (i), 0)) != UNSPEC)
return false;
return true;
else
{
/* We need to re-recog the insn with virtual registers to get
- the operands */
+ the operands. */
cfun->machine->virt_insns_ok = 1;
if (recog (pattern, insn, 0) > -1)
{
#endif
/* Registers into which we move the contents of virtual registers. */
-#define X gen_rtx_REG (QImode, 0)
-#define A gen_rtx_REG (QImode, 1)
-#define C gen_rtx_REG (QImode, 2)
-#define B gen_rtx_REG (QImode, 3)
-#define E gen_rtx_REG (QImode, 4)
-#define D gen_rtx_REG (QImode, 5)
-#define L gen_rtx_REG (QImode, 6)
-#define H gen_rtx_REG (QImode, 7)
-
-#define AX gen_rtx_REG (HImode, 0)
-#define BC gen_rtx_REG (HImode, 2)
-#define DE gen_rtx_REG (HImode, 4)
-#define HL gen_rtx_REG (HImode, 6)
+#define X gen_rtx_REG (QImode, X_REG)
+#define A gen_rtx_REG (QImode, A_REG)
+#define C gen_rtx_REG (QImode, C_REG)
+#define B gen_rtx_REG (QImode, B_REG)
+#define E gen_rtx_REG (QImode, E_REG)
+#define D gen_rtx_REG (QImode, D_REG)
+#define L gen_rtx_REG (QImode, L_REG)
+#define H gen_rtx_REG (QImode, H_REG)
+
+#define AX gen_rtx_REG (HImode, AX_REG)
+#define BC gen_rtx_REG (HImode, BC_REG)
+#define DE gen_rtx_REG (HImode, DE_REG)
+#define HL gen_rtx_REG (HImode, HL_REG)
/* Returns TRUE if R is a virtual register. */
-static bool
+static inline bool
is_virtual_register (rtx r)
{
return (GET_CODE (r) == REG
else
add_postponed_content_update (to, from);
}
+
return before ? to : from;
}
if (GET_MODE (XEXP (m, 0)) == SImode)
{
+ rtx new_m;
rtx seg = rl78_hi8 (XEXP (m, 0));
+
#if DEBUG_ALLOC
fprintf (stderr, "setting ES:\n");
debug_rtx(seg);
emit_insn_before (EM (gen_movqi_es (A)), before);
record_content (A, NULL_RTX);
- m = change_address (m, GET_MODE (m), rl78_lo16 (XEXP (m, 0)));
+ new_m = gen_rtx_MEM (GET_MODE (m), rl78_lo16 (XEXP (m, 0)));
+ MEM_COPY_ATTRIBUTES (new_m, m);
+ m = new_m;
need_es = 1;
}
/* Copy SRC to accumulator (A or AX), placing any generated insns
before BEFORE. Returns accumulator RTX. */
-
static rtx
move_to_acc (int opno, rtx before)
{
/* Copy accumulator (A or AX) to DEST, placing any generated insns
after AFTER. Returns accumulator RTX. */
-
static rtx
move_from_acc (unsigned int opno, rtx after)
{
/* Copy accumulator (A or AX) to REGNO, placing any generated insns
before BEFORE. Returns reg RTX. */
-
static rtx
move_acc_to_reg (rtx acc, int regno, rtx before)
{
/* Copy SRC to X, placing any generated insns before BEFORE.
Returns X RTX. */
-
static rtx
move_to_x (int opno, rtx before)
{
if (mode == QImode || ! is_virtual_register (OP (opno)))
{
OP (opno) = move_to_acc (opno, before);
- OP (opno) = move_acc_to_reg (OP(opno), X_REG, before);
+ OP (opno) = move_acc_to_reg (OP (opno), X_REG, before);
return reg;
}
return gen_and_emit_move (reg, src, before, true);
}
-/* Copy OP(opno) to H or HL, placing any generated insns before BEFORE.
+/* Copy OP (opno) to H or HL, placing any generated insns before BEFORE.
Returns H/HL RTX. */
-
static rtx
move_to_hl (int opno, rtx before)
{
return gen_and_emit_move (reg, src, before, true);
}
-/* Copy OP(opno) to E or DE, placing any generated insns before BEFORE.
+/* Copy OP (opno) to E or DE, placing any generated insns before BEFORE.
Returns E/DE RTX. */
-
static rtx
move_to_de (int opno, rtx before)
{
}
}
-
OP (0) = move_from_acc (0, insn);
tmp_id = get_max_insn_count ();
}
/* Devirtualize an insn of the form SET (PC) (MEM/REG). */
-
static void
rl78_alloc_physical_registers_ro1 (rtx insn)
{
}
/* Devirtualize a compare insn. */
-
static void
rl78_alloc_physical_registers_cmp (rtx insn)
{
OP (1) = transcode_memory_rtx (OP (1), DE, insn);
OP (2) = transcode_memory_rtx (OP (2), HL, insn);
- /* HI compares have to have OP(1) in AX, but QI
+ /* HI compares have to have OP (1) in AX, but QI
compares do not, so it is worth checking here. */
MAYBE_OK (insn);
- /* For an HImode compare, OP(1) must always be in AX.
- But if OP(1) is a REG (and not AX), then we can avoid
- a reload of OP(1) if we reload OP(2) into AX and invert
+ /* For an HImode compare, OP (1) must always be in AX.
+ But if OP (1) is a REG (and not AX), then we can avoid
+ a reload of OP (1) if we reload OP (2) into AX and invert
the comparison. */
if (REG_P (OP (1))
&& REGNO (OP (1)) != AX_REG
}
/* Like op2, but AX = A op X. */
-
static void
rl78_alloc_physical_registers_umul (rtx insn)
{
which ++;
}
}
+
MUST_BE_OK (insn);
}
else
process_postponed_content_update ();
}
+
#if DEBUG_ALLOC
fprintf (stderr, "\033[0m");
#endif
}
}
}
+ else if (GET_CODE (pat) == CLOBBER)
+ {
+ if (REG_P (XEXP (pat, 0)))
+ {
+ unsigned int reg = REGNO (XEXP (pat, 0));
+
+ origins[reg] = reg;
+ age[reg] = 0;
+ }
+ }
}
}
}
return HImode;
}
+\f
struct gcc_target targetm = TARGET_INITIALIZER;
#include "gt-rl78.h"
#undef LINK_SPEC
#define LINK_SPEC "\
%{mrelax:-relax} \
+%{!r:--gc-sections} \
"
#undef LIB_SPEC
(define_insn "sel_rb"
[(unspec_volatile [(match_operand 0 "immediate_operand" "")] UNS_SET_RB)]
- ""
+ "!TARGET_G10"
"sel\trb%u0"
)