mn10300.c: Include cfgloop.h.
authorNick Clifton <nickc@redhat.com>
Wed, 4 May 2011 10:08:09 +0000 (10:08 +0000)
committerNick Clifton <nickc@gcc.gnu.org>
Wed, 4 May 2011 10:08:09 +0000 (10:08 +0000)
* config/mn10300/mn10300.c: Include cfgloop.h.
(DUMP): New macro.
(mn10300_insert_setlb_lcc): New function.  Inserts a SETLB and a
Lcc or a FLcc insn into the instruction stream.
(mn10300_block_contains_call): New function.  Returns true if the
given basic block contains a CALL insn.
(mn10300_loop_contains_call_insn): New function.  Returns true if
the given loop contains a CALL insn.
(mn10300_scan_for_setlb_lcc): New function.  Finds opportunities
to use the SETLB and Lcc or FLcc insns.
(mn10300_reorg): Invoke mn10300_scan_for_setlb_lcc when optimizing.
(TARGET_FLAGS): Add MASK_ALLOW_SETLB.
* config/mn10300/mn10300.opt (msetlb): New option.  Used to
disable the SETLB optimization.
* config/mn10300/mn10300.h (TARGET_CPU_CPP_BUILTINS): Add
__SETLB__ or __NO_SETLB__.
* config/mn10300/mn10300.md (UNSPEC_SETLB): New constant.
(movsf_internal): Handle MDR register.
(cmpsi): Make visible.
(setlb): New pattern.
(Lcc): New pattern.
(FLcc): New pattern.

From-SVN: r173362

gcc/ChangeLog
gcc/config/mn10300/mn10300.c
gcc/config/mn10300/mn10300.h
gcc/config/mn10300/mn10300.md
gcc/config/mn10300/mn10300.opt

index 97c6bcb1cfd19fb65aab66f6a8c1c45c5ee31848..6f30c3113acf706471fb0188049b983463a1e79f 100644 (file)
@@ -1,3 +1,28 @@
+2011-05-04  Nick Clifton  <nickc@redhat.com>
+
+       * config/mn10300/mn10300.c: Include cfgloop.h.
+       (DUMP): New macro.
+       (mn10300_insert_setlb_lcc): New function.  Inserts a SETLB and a
+       Lcc or a FLcc insn into the instruction stream.
+       (mn10300_block_contains_call): New function.  Returns true if the
+       given basic block contains a CALL insn.
+       (mn10300_loop_contains_call_insn): New function.  Returns true if
+       the given loop contains a CALL insn.
+       (mn10300_scan_for_setlb_lcc): New function.  Finds opportunities
+       to use the SETLB and Lcc or FLcc insns.
+       (mn10300_reorg): Invoke mn10300_scan_for_setlb_lcc when optimizing.
+       (TARGET_FLAGS): Add MASK_ALLOW_SETLB.
+       * config/mn10300/mn10300.opt (msetlb): New option.  Used to
+       disable the SETLB optimization.
+       * config/mn10300/mn10300.h (TARGET_CPU_CPP_BUILTINS): Add
+       __SETLB__ or __NO_SETLB__.
+       * config/mn10300/mn10300.md (UNSPEC_SETLB): New constant.
+       (movsf_internal): Handle MDR register.
+       (cmpsi): Make visible.
+       (setlb): New pattern.
+       (Lcc): New pattern.
+       (FLcc): New pattern.
+
 2011-05-04  Uros Bizjak  <ubizjak@gmail.com>
 
        PR target/48860
index 1bae9f30eef083bcaf0f2109e24e97504a4f8ff3..53714673ac8faa60f42312bcaf5f1eb8c3cfb164 100644 (file)
@@ -45,6 +45,7 @@
 #include "target-def.h"
 #include "df.h"
 #include "opts.h"
+#include "cfgloop.h"
 
 /* This is used in the am33_2.0-linux-gnu port, in which global symbol
    names are not prefixed by underscores, to tell whether to prefix a
@@ -3129,11 +3130,188 @@ mn10300_bundle_liw (void)
     }
 }
 
+#define DUMP(reason, insn)                     \
+  do                                           \
+    {                                          \
+      if (dump_file)                           \
+       {                                       \
+         fprintf (dump_file, reason "\n");     \
+         if (insn != NULL_RTX)                 \
+           print_rtl_single (dump_file, insn); \
+         fprintf(dump_file, "\n");             \
+       }                                       \
+    }                                          \
+  while (0)
+
+/* Replace the BRANCH insn with a Lcc insn that goes to LABEL.
+   Insert a SETLB insn just before LABEL.  */
+
+static void
+mn10300_insert_setlb_lcc (rtx label, rtx branch)
+{
+  rtx lcc, comparison, cmp_reg;
+
+  if (LABEL_NUSES (label) > 1)
+    {
+      rtx insn;
+
+      /* This label is used both as an entry point to the loop
+        and as a loop-back point for the loop.  We need to separate
+        these two functions so that the SETLB happens upon entry,
+        but the loop-back does not go to the SETLB instruction.  */
+      DUMP ("Inserting SETLB insn after:", label);
+      insn = emit_insn_after (gen_setlb (), label);
+      label = gen_label_rtx ();
+      emit_label_after (label, insn);
+      DUMP ("Created new loop-back label:", label);
+    }
+  else
+    {
+      DUMP ("Inserting SETLB insn before:", label);
+      emit_insn_before (gen_setlb (), label);
+    }
+
+  comparison = XEXP (SET_SRC (PATTERN (branch)), 0);
+  cmp_reg = XEXP (comparison, 0);
+  gcc_assert (REG_P (cmp_reg));
+
+  /* If the comparison has not already been split out of the branch
+     then do so now.  */
+  gcc_assert (REGNO (cmp_reg) == CC_REG);
+
+  if (GET_MODE (cmp_reg) == CC_FLOATmode)
+    lcc = gen_FLcc (comparison, label);
+  else
+    lcc = gen_Lcc (comparison, label);    
+
+  lcc = emit_jump_insn_before (lcc, branch);
+  mark_jump_label (XVECEXP (PATTERN (lcc), 0, 0), lcc, 0);
+  DUMP ("Replacing branch insn...", branch);
+  DUMP ("... with Lcc insn:", lcc);  
+  delete_insn (branch);
+}
+
+static bool
+mn10300_block_contains_call (struct basic_block_def * block)
+{
+  rtx insn;
+
+  FOR_BB_INSNS (block, insn)
+    if (CALL_P (insn))
+      return true;
+
+  return false;
+}
+
+static bool
+mn10300_loop_contains_call_insn (loop_p loop)
+{
+  basic_block * bbs;
+  bool result = false;
+  unsigned int i;
+
+  bbs = get_loop_body (loop);
+
+  for (i = 0; i < loop->num_nodes; i++)
+    if (mn10300_block_contains_call (bbs[i]))
+      {
+       result = true;
+       break;
+      }
+
+  free (bbs);
+  return result;
+}
+
+static void
+mn10300_scan_for_setlb_lcc (void)
+{
+  struct loops loops;
+  loop_iterator liter;
+  loop_p loop;
+
+  DUMP ("Looking for loops that can use the SETLB insn", NULL_RTX);
+
+  df_analyze ();
+  compute_bb_for_insn ();
+
+  /* Find the loops.  */
+  if (flow_loops_find (& loops) < 1)
+    DUMP ("No loops found", NULL_RTX);
+  current_loops = & loops;
+
+  /* FIXME: For now we only investigate innermost loops.  In practice however
+     if an inner loop is not suitable for use with the SETLB/Lcc insns, it may
+     be the case that its parent loop is suitable.  Thus we should check all
+     loops, but work from the innermost outwards.  */
+  FOR_EACH_LOOP (liter, loop, LI_ONLY_INNERMOST)
+    {
+      const char * reason = NULL;
+
+      /* Check to see if we can modify this loop.  If we cannot
+        then set 'reason' to describe why it could not be done.  */
+      if (loop->latch == NULL)
+       reason = "it contains multiple latches";
+      else if (loop->header != loop->latch)
+       /* FIXME: We could handle loops that span multiple blocks,
+          but this requires a lot more work tracking down the branches
+          that need altering, so for now keep things simple.  */
+       reason = "the loop spans multiple blocks";
+      else if (mn10300_loop_contains_call_insn (loop))
+       reason = "it contains CALL insns";
+      else
+       {
+         rtx branch = BB_END (loop->latch);
+
+         gcc_assert (JUMP_P (branch));
+         if (single_set (branch) == NULL_RTX || ! any_condjump_p (branch))
+           /* We cannot optimize tablejumps and the like.  */
+           /* FIXME: We could handle unconditional jumps.  */
+           reason = "it is not a simple loop";
+         else
+           {
+             rtx label;
+
+             if (dump_file)
+               flow_loop_dump (loop, dump_file, NULL, 0);
+
+             label = BB_HEAD (loop->header);
+             gcc_assert (LABEL_P (label));
+
+             mn10300_insert_setlb_lcc (label, branch);
+           }
+       }
+
+      if (dump_file && reason != NULL)
+       fprintf (dump_file, "Loop starting with insn %d is not suitable because %s\n",
+                INSN_UID (BB_HEAD (loop->header)),
+                reason);
+    }
+
+#if 0 /* FIXME: We should free the storage we allocated, but
+        for some unknown reason this leads to seg-faults.  */
+  FOR_EACH_LOOP (liter, loop, 0)
+    free_simple_loop_desc (loop);
+
+  flow_loops_free (current_loops);
+#endif
+
+  current_loops = NULL;
+
+  df_finish_pass (false);  
+
+  DUMP ("SETLB scan complete", NULL_RTX);
+}
+
 static void
 mn10300_reorg (void)
 {
-  if (TARGET_AM33)
+  /* These are optimizations, so only run them if optimizing.  */
+  if (TARGET_AM33 && (optimize > 0 || optimize_size))
     {
+      if (TARGET_ALLOW_SETLB)
+       mn10300_scan_for_setlb_lcc ();
+
       if (TARGET_ALLOW_LIW)
        mn10300_bundle_liw ();
     }
@@ -3171,7 +3349,7 @@ mn10300_reorg (void)
 #define TARGET_ASM_OUTPUT_ADDR_CONST_EXTRA mn10300_asm_output_addr_const_extra
 
 #undef  TARGET_DEFAULT_TARGET_FLAGS
-#define TARGET_DEFAULT_TARGET_FLAGS MASK_MULT_BUG | MASK_PTR_A0D0 | MASK_ALLOW_LIW
+#define TARGET_DEFAULT_TARGET_FLAGS MASK_MULT_BUG | MASK_PTR_A0D0 | MASK_ALLOW_LIW | MASK_ALLOW_SETLB
 #undef  TARGET_HANDLE_OPTION
 #define TARGET_HANDLE_OPTION mn10300_handle_option
 #undef  TARGET_OPTION_OVERRIDE
index a0e17d845db2ffb67c355b7ad40cb5bec3e52147..a15615653b5cc59c3e503091b3e88b79d6fbfcad 100644 (file)
@@ -54,6 +54,8 @@
       builtin_define (TARGET_ALLOW_LIW ?       \
                      "__LIW__" : "__NO_LIW__");\
                                                \
+      builtin_define (TARGET_ALLOW_SETLB  ?    \
+                     "__SETLB__" : "__NO_SETLB__");\
     }                                          \
   while (0)
 
index f3f23e7fa3770fafb61b138edc3634ba66780baa..81e4a4153d8009d037e9e778cf36fbf37f0660dc 100644 (file)
@@ -42,6 +42,8 @@
 
   ;; This is used to encode LIW patterns.
   (UNSPEC_LIW          8)
+  ;; This is for the low overhead loop instructions.
+  (UNSPEC_SETLB         9)
 ])
 
 (include "predicates.md")
 })
 
 (define_insn "*movsf_internal"
-  [(set (match_operand:SF 0 "nonimmediate_operand" "=rf,r,f,r,f,r,f,r,m,f,Q")
-       (match_operand:SF 1 "general_operand"      "  0,F,F,r,f,f,r,m,r,Q,f"))]
+  [(set (match_operand:SF 0 "nonimmediate_operand" "=rf,r,f,r,f,r,f,r,m,f,Q,z,d")
+       (match_operand:SF 1 "general_operand"      "  0,F,F,r,f,f,r,m,r,Q,f,d,z"))]
   "TARGET_AM33_2
    && (register_operand (operands[0], SFmode)
        || register_operand (operands[1], SFmode))"
     case 3:
     case 7:
     case 8:
+    case 11:
+    case 12:
       return "mov %1,%0";
     case 2:
     case 4:
                                (const_int 13) (const_int 24))
                  (if_then_else (eq_attr "cpu" "am34")
                                (const_int 13) (const_int 24))
+                 (const_int 22)
+                 (const_int 22)
                 ])]
 )
 
   DONE;
 })
 
-(define_insn "*cmpsi"
+(define_insn "cmpsi"
   [(set (reg CC_REG)
        (compare (match_operand:SI 0 "register_operand"  "r,r,r")
                 (match_operand:SI 1 "nonmemory_operand" "r,O,i")))]
   [(set (attr "timings") (if_then_else (eq_attr "cpu" "am34")
                                       (const_int 13) (const_int 12)))]
 )
+
+;; Note - in theory the doloop patterns could be used here to express
+;; the SETLB and Lcc instructions.  In practice this does not work because
+;; the acceptable forms of the doloop patterns do not include UNSPECs
+;; and without them gcc's basic block reordering code can duplicate the
+;; doloop_end pattern, leading to bogus multiple decrements of the loop
+;; counter. 
+
+(define_insn "setlb"
+  [(unspec [(const_int 0)] UNSPEC_SETLB)]
+  "TARGET_AM33 && TARGET_ALLOW_SETLB"
+  "setlb"
+)
+
+(define_insn "Lcc"
+  [(set (pc)
+       (if_then_else (match_operator 0 "comparison_operator"
+                     [(reg:CC CC_REG) (const_int 0)])
+                     (label_ref (match_operand 1 "" ""))
+                     (pc)))
+   (unspec [(const_int 1)] UNSPEC_SETLB)]
+  "TARGET_AM33 && TARGET_ALLOW_SETLB"
+  "L%b0 # loop back to: %1"
+)
+
+(define_insn "FLcc"
+  [(set (pc)
+       (if_then_else (match_operator 0 "comparison_operator"
+                     [(reg:CC_FLOAT CC_REG) (const_int 0)])
+                     (label_ref (match_operand 1 "" ""))
+                     (pc)))
+   (unspec [(const_int 2)] UNSPEC_SETLB)]
+  "TARGET_AM33_2 && TARGET_ALLOW_SETLB"
+  "FL%b0 # loop back to: %1"
+  [(set (attr "timings") (if_then_else (eq_attr "cpu" "am34") (const_int 44) (const_int 11)))]
+)
index 676e434e0ef19e6a4a5662ccff56fbda9ac7d3f5..ba67582f4f299555df2e70983b5987715619c811 100644 (file)
@@ -61,3 +61,7 @@ Return pointers in both a0 and d0
 mliw
 Target Report Mask(ALLOW_LIW)
 Allow gcc to generate LIW instructions
+
+msetlb
+Target Report Mask(ALLOW_SETLB)
+Allow gcc to generate the SETLB and Lcc instructions