sh.c (dump_table): New argument start.
authorJ"orn Rennecke <joern.rennecke@superh.com>
Thu, 10 Jun 2004 18:14:53 +0000 (18:14 +0000)
committerJoern Rennecke <amylaar@gcc.gnu.org>
Thu, 10 Jun 2004 18:14:53 +0000 (19:14 +0100)
* 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
gcc/config/sh/sh.c
gcc/config/sh/sh.md

index ed2a94b93a6498bd3198b089d051e7e71eb48f99..ef9d7a37620b467f2b2951aed2ede3e7a8dfd8c7 100644 (file)
@@ -1,3 +1,15 @@
+2004-06-10  J"orn Rennecke <joern.rennecke@superh.com>
+
+       * 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  <jason@redhat.com>
 
        * target.h (struct gcc_target): Change gimplify_va_arg_expr 
index 128954316cac777924294907478bac130aa529ac..d70178bf4958e0493bf44940f0bd4a2bf9332047 100644 (file)
@@ -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;
        }
     }
index 174ae609578228d6c367e4940a9c09bee5b0df5b..d8ea00ca77a4c86b24958882a4c6b752b62acacf 100644 (file)
@@ -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")