From 078c8b08a0a0d7db27f491a4212957c967619f67 Mon Sep 17 00:00:00 2001 From: "J\"orn Rennecke" Date: Thu, 10 Jun 2004 18:14:53 +0000 Subject: [PATCH] sh.c (dump_table): New argument start. * sh.c (dump_table): New argument start. Changed caller. (fixup_mova): New function. (find_barrier): Use it. (sh_reorg): Likewise. Check for CODE_FOR_casesi_worker_2. If the label a mova refers to is above the mova itself, change the mova into a load. * sh.md (*casesi_worker): Rename to: (casesi_worker_1). (casesi_worker_2): New insn. From-SVN: r82932 --- gcc/ChangeLog | 12 ++++++ gcc/config/sh/sh.c | 98 +++++++++++++++++++++++++++++++++++++++------ gcc/config/sh/sh.md | 40 +++++++++++++++++- 3 files changed, 137 insertions(+), 13 deletions(-) diff --git a/gcc/ChangeLog b/gcc/ChangeLog index ed2a94b93a6..ef9d7a37620 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,15 @@ +2004-06-10 J"orn Rennecke + + * sh.c (dump_table): New argument start. Changed caller. + (fixup_mova): New function. + (find_barrier): Use it. + (sh_reorg): Likewise. Check for CODE_FOR_casesi_worker_2. + If the label a mova refers to is above the mova itself, change + the mova into a load. + * sh.md (*casesi_worker): Rename to: + (casesi_worker_1). + (casesi_worker_2): New insn. + 2004-06-10 Jason Merrill * target.h (struct gcc_target): Change gimplify_va_arg_expr diff --git a/gcc/config/sh/sh.c b/gcc/config/sh/sh.c index 128954316ca..d70178bf495 100644 --- a/gcc/config/sh/sh.c +++ b/gcc/config/sh/sh.c @@ -200,7 +200,7 @@ static int branch_dest (rtx); static void force_into (rtx, rtx); static void print_slot (rtx); static rtx add_constant (rtx, enum machine_mode, rtx); -static void dump_table (rtx); +static void dump_table (rtx, rtx); static int hi_const (rtx); static int broken_move (rtx); static int mova_p (rtx); @@ -2756,11 +2756,16 @@ add_constant (rtx x, enum machine_mode mode, rtx last_value) return lab; } -/* Output the literal table. */ +/* Output the literal table. START, if nonzero, is the first instruction + this table is needed for, and also indicates that there is at least one + casesi_worker_2 instruction; We have to emit the operand3 labels from + these insns at a 4-byte aligned position. BARRIER is the barrier + after which we are to place the table. */ static void -dump_table (rtx scan) +dump_table (rtx start, rtx barrier) { + rtx scan = barrier; int i; int need_align = 1; rtx lab, ref; @@ -2795,6 +2800,20 @@ dump_table (rtx scan) need_align = 1; + if (start) + { + scan = emit_insn_after (gen_align_4 (), scan); + need_align = 0; + for (; start != barrier; start = NEXT_INSN (start)) + if (GET_CODE (start) == INSN + && recog_memoized (start) == CODE_FOR_casesi_worker_2) + { + rtx src = SET_SRC (XVECEXP (PATTERN (start), 0, 0)); + rtx lab = XEXP (XVECEXP (src, 0, 3), 0); + + scan = emit_label_after (lab, scan); + } + } if (TARGET_FMOVD && TARGET_ALIGN_DOUBLE && have_df) { rtx align_insn = NULL_RTX; @@ -2995,6 +3014,46 @@ mova_p (rtx insn) && GET_CODE (XVECEXP (SET_SRC (PATTERN (insn)), 0, 0)) == LABEL_REF); } +/* Fix up a mova from a switch that went out of range. */ +static void +fixup_mova (rtx mova) +{ + if (! flag_pic) + { + SET_SRC (PATTERN (mova)) = XVECEXP (SET_SRC (PATTERN (mova)), 0, 0); + INSN_CODE (mova) = -1; + } + else + { + rtx worker = mova; + rtx lab = gen_label_rtx (); + rtx wpat, wpat0, wpat1, wsrc, diff; + + do + { + worker = NEXT_INSN (worker); + if (! worker + || GET_CODE (worker) == CODE_LABEL + || GET_CODE (worker) == JUMP_INSN) + abort (); + } while (recog_memoized (worker) != CODE_FOR_casesi_worker_1); + wpat = PATTERN (worker); + wpat0 = XVECEXP (wpat, 0, 0); + wpat1 = XVECEXP (wpat, 0, 1); + wsrc = SET_SRC (wpat0); + PATTERN (worker) = (gen_casesi_worker_2 + (SET_DEST (wpat0), XVECEXP (wsrc, 0, 1), + XEXP (XVECEXP (wsrc, 0, 2), 0), lab, + XEXP (wpat1, 0))); + INSN_CODE (worker) = -1; + diff = gen_rtx_MINUS (Pmode, XVECEXP (SET_SRC (PATTERN (mova)), 0, 0), + gen_rtx_LABEL_REF (Pmode, lab)); + diff = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, diff), UNSPEC_PIC); + SET_SRC (PATTERN (mova)) = gen_rtx_CONST (Pmode, diff); + INSN_CODE (mova) = -1; + } +} + /* Find the last barrier from insn FROM which is close enough to hold the constant pool. If we can't find one, then create one near the end of the range. */ @@ -3186,8 +3245,7 @@ find_barrier (int num_mova, rtx mova, rtx from) { /* Try as we might, the leading mova is out of range. Change it into a load (which will become a pcload) and retry. */ - SET_SRC (PATTERN (mova)) = XVECEXP (SET_SRC (PATTERN (mova)), 0, 0); - INSN_CODE (mova) = -1; + fixup_mova (mova); return find_barrier (0, 0, mova); } else @@ -4099,7 +4157,20 @@ sh_reorg (void) { if (mova_p (insn)) { - if (! num_mova++) + /* ??? basic block reordering can move a switch table dispatch + below the switch table. Check if that has happened. + We only have the addresses available when optimizing; but then, + this check shouldn't be needed when not optimizing. */ + rtx label_ref = XVECEXP (SET_SRC (PATTERN (insn)), 0, 0); + if (optimize + && (INSN_ADDRESSES (INSN_UID (insn)) + > INSN_ADDRESSES (INSN_UID (XEXP (label_ref, 0))))) + { + /* Change the mova into a load. + broken_move will then return true for it. */ + fixup_mova (insn); + } + else if (! num_mova++) mova = insn; } else if (GET_CODE (insn) == JUMP_INSN @@ -4124,19 +4195,20 @@ sh_reorg (void) { /* Change the mova into a load, and restart scanning there. broken_move will then return true for mova. */ - SET_SRC (PATTERN (mova)) - = XVECEXP (SET_SRC (PATTERN (mova)), 0, 0); - INSN_CODE (mova) = -1; + fixup_mova (mova); insn = mova; } } - if (broken_move (insn)) + if (broken_move (insn) + || (GET_CODE (insn) == INSN + && recog_memoized (insn) == CODE_FOR_casesi_worker_2)) { rtx scan; /* Scan ahead looking for a barrier to stick the constant table behind. */ rtx barrier = find_barrier (num_mova, mova, insn); rtx last_float_move = NULL_RTX, last_float = 0, *last_float_addr = NULL; + int need_aligned_label = 0; if (num_mova && ! mova_p (mova)) { @@ -4150,6 +4222,9 @@ sh_reorg (void) { if (GET_CODE (scan) == CODE_LABEL) last_float = 0; + if (GET_CODE (scan) == INSN + && recog_memoized (scan) == CODE_FOR_casesi_worker_2) + need_aligned_label = 1; if (broken_move (scan)) { rtx *patp = &PATTERN (scan), pat = *patp; @@ -4180,7 +4255,6 @@ sh_reorg (void) } dst = gen_rtx_REG (HImode, REGNO (dst) + offset); } - if (GET_CODE (dst) == REG && FP_ANY_REGISTER_P (REGNO (dst))) { /* This must be an insn that clobbers r0. */ @@ -4257,7 +4331,7 @@ sh_reorg (void) INSN_CODE (scan) = -1; } } - dump_table (barrier); + dump_table (need_aligned_label ? insn : 0, barrier); insn = barrier; } } diff --git a/gcc/config/sh/sh.md b/gcc/config/sh/sh.md index 174ae609578..d8ea00ca77a 100644 --- a/gcc/config/sh/sh.md +++ b/gcc/config/sh/sh.md @@ -7110,7 +7110,7 @@ mov.l\\t1f,r0\\n\\ (clobber (match_dup 3))])] "if (GET_CODE (operands[2]) == CODE_LABEL) LABEL_NUSES (operands[2])++;") -(define_insn "*casesi_worker" +(define_insn "casesi_worker_1" [(set (match_operand:SI 0 "register_operand" "=r,r") (unspec:SI [(reg:SI R0_REG) (match_operand:SI 1 "register_operand" "0,r") @@ -7140,6 +7140,44 @@ mov.l\\t1f,r0\\n\\ }" [(set_attr "length" "4")]) +(define_insn "casesi_worker_2" + [(set (match_operand:SI 0 "register_operand" "=r,r") + (unspec:SI [(reg:SI R0_REG) + (match_operand:SI 1 "register_operand" "0,r") + (label_ref (match_operand 2 "" "")) + (label_ref (match_operand 3 "" ""))] UNSPEC_CASESI)) + (clobber (match_operand:SI 4 "" "=X,1"))] + "TARGET_SH2 && reload_completed && flag_pic" + "* +{ + rtx diff_vec = PATTERN (next_real_insn (operands[2])); + char *load; + + if (GET_CODE (diff_vec) != ADDR_DIFF_VEC) + abort (); + + switch (GET_MODE (diff_vec)) + { + case SImode: + output_asm_insn (\"shll2 %1\", operands); + load = \"mov.l @(r0,%1),%0\"; break; + case HImode: + output_asm_insn (\"add %1,%1\", operands); + load = \"mov.w @(r0,%1),%0\"; break; + case QImode: + if (ADDR_DIFF_VEC_FLAGS (diff_vec).offset_unsigned) + load = \"mov.b @(r0,%1),%0\;extu.b %0,%0\"; + else + load = \"mov.b @(r0,%1),%0\"; + break; + default: + abort (); + } + output_asm_insn (\"add\tr0,%1\;mova\t%O3,r0\\n\", operands); + return load; +}" + [(set_attr "length" "8")]) + (define_insn "casesi_shift_media" [(set (match_operand:DI 0 "arith_reg_operand" "=r") (ashift:DI (match_operand:DI 1 "arith_reg_operand" "r") -- 2.30.2