(arm_select): Declare and initialize.
authorRichard Earnshaw <erich@gnu.org>
Sat, 4 May 1996 16:13:28 +0000 (16:13 +0000)
committerRichard Earnshaw <erich@gnu.org>
Sat, 4 May 1996 16:13:28 +0000 (16:13 +0000)
(all_procs): Add arm7100.
(arm_override_options): Parse arm_select structure to determine selected
architecture and tuning parameters.
(output_option, output_options): New functions.
(arm_canonicalize_comparison): New function.
(arm_gen_movstrqi): Don't add a writeback of the index registers for the
last instructions.
(arm_select_cc_mode): Detect case where mode is carry out of unsigned
arithmetic.
(output_lcomm_directive): Use bss_section (), and use alignment rather than
rounding.
(get_arm_condition_code): Handle CC_Cmode.
(final_prescan_insn): Avoid boundary case where we would occasionally
inline MAX_INSNS_SKIPPED+1 insns.  Allow call_insns to be inlined in APCS_32
mode if they are the last insn in the block.

From-SVN: r11921

gcc/config/arm/arm.c

index fcb7f8390910c23fbdb7977a6f7b5da97152ce0a..5f59a0c9116ea8c75fa48b34af8490d2fbe9b509 100644 (file)
@@ -130,6 +130,14 @@ static enum arm_cond_code get_arm_condition_code ();
 \f
 /* Initialization code */
 
+struct arm_cpu_select arm_select[3] =
+{
+  /* switch    name,           tune    arch */
+  { (char *)0, "--with-cpu=",  1,      1 },
+  { (char *)0, "-mcpu=",       1,      1 },
+  { (char *)0, "-mtune=",      1,      0 },
+};
+
 #define FL_CO_PROC    0x01            /* Has external co-processor bus */
 #define FL_FAST_MULT  0x02            /* Fast multiply */
 #define FL_MODE26     0x04            /* 26-bit mode support */
@@ -167,6 +175,7 @@ static struct processors all_procs[] =
   {"arm700i",  PROCESSOR_ARM7, FL_CO_PROC | FL_MODE32 | FL_MODE26},
   {"arm710",   PROCESSOR_ARM7, FL_MODE32 | FL_MODE26},
   {"arm710c",  PROCESSOR_ARM7, FL_MODE32 | FL_MODE26},
+  {"arm7100",  PROCESSOR_ARM7, FL_MODE32 | FL_MODE26},
   {"arm7500",  PROCESSOR_ARM7, FL_MODE32 | FL_MODE26},
   {"arm7tdmi", PROCESSOR_ARM7, (FL_CO_PROC | FL_FAST_MULT | FL_MODE32
                                 | FL_ARCH4 | FL_THUMB)},
@@ -179,6 +188,35 @@ void
 arm_override_options ()
 {
   int arm_thumb_aware = 0;
+  int flags = 0;
+  int i;
+  struct arm_cpu_select *ptr;
+
+  arm_cpu = PROCESSOR_DEFAULT;
+  arm_select[0].string = TARGET_CPU_DEFAULT;
+
+  for (i = 0; i < sizeof (arm_select) / sizeof (arm_select[0]); i++)
+    {
+      ptr = &arm_select[i];
+      if (ptr->string != (char *)0 && ptr->string[0] != '\0')
+        {
+         struct processors *sel;
+
+          for (sel = all_procs; sel->name != NULL; sel++)
+            if (! strcmp (ptr->string, sel->name))
+              {
+                if (ptr->set_tune_p)
+                  arm_cpu = sel->type;
+
+                if (ptr->set_arch_p)
+                 flags = sel->flags;
+                break;
+              }
+
+          if (sel->name == NULL)
+            error ("bad value (%s) for %s switch", ptr->string, ptr->name);
+        }
+    }
 
   if (write_symbols != NO_DEBUG && flag_omit_frame_pointer)
     warning ("-g with -fomit-frame-pointer may not give sensible debugging");
@@ -188,22 +226,18 @@ arm_override_options ()
 
   if (TARGET_6)
     {
-      warning ("Option '-m6' deprecated.  Use: '-mapcs-32' or -mcpu-<proc>");
+      warning ("Option '-m6' deprecated.  Use: '-mapcs-32' or -mcpu=<proc>");
       target_flags |= ARM_FLAG_APCS_32;
       arm_cpu = PROCESSOR_ARM6;
     }
 
   if (TARGET_3)
     {
-      warning ("Option '-m3' deprecated.  Use: '-mapcs-26' or -mcpu-<proc>");
+      warning ("Option '-m3' deprecated.  Use: '-mapcs-26' or -mcpu=<proc>");
       target_flags &= ~ARM_FLAG_APCS_32;
       arm_cpu = PROCESSOR_ARM2;
     }
 
-  if ((TARGET_3 || TARGET_6) && target_cpu_name != NULL)
-    fatal ("Incompatible mix of old and new options.  -m%d and -mcpu-%s",
-          TARGET_3 ? 3 : 6, target_cpu_name);
-
   if (TARGET_APCS_REENT && flag_pic)
     fatal ("-fpic and -mapcs-reent are incompatible");
 
@@ -222,43 +256,18 @@ arm_override_options ()
       target_flags |= ARM_FLAG_APCS_FRAME;
     }
 
-  arm_cpu = TARGET_6 ? PROCESSOR_ARM6: PROCESSOR_ARM2;
   arm_fpu = FP_HARD;
 
-  if (target_cpu_name != NULL)
-    {
-      char *c = target_cpu_name;
-      struct processors *proc;
-
-      /* Match against the supported types.  */
-      for (proc = all_procs; proc->name != NULL; proc++)
-       {
-         if (strcmp (proc->name, c) == 0)
-           break;
-       }
-
-      if (proc->name)
-       {
-         arm_cpu = proc->type;
-
-         /* Default value for floating point code... if no co-processor
-            bus, then schedule for emulated floating point.  Otherwise,
-            assume the user has an FPA, unless overridden with -mfpe-...  */
-         if (proc->flags & FL_CO_PROC == 0)
-           arm_fpu = FP_SOFT3;
-         else
-           arm_fpu = FP_HARD;
-         arm_fast_multiply = (proc->flags & FL_FAST_MULT) != 0;
-         arm_arch4 = (proc->flags & FL_ARCH4) != 0;
-         arm_thumb_aware = (proc->flags & FL_THUMB) != 0;
-         /* Processors with a load delay slot can load constants faster,
-            from the pool than it takes to construct them, so reduce the
-            complexity of the constant that we will try to generate
-            inline.  */
-       }
-      else
-       fatal ("Unrecognized cpu type: %s", target_cpu_name);
-    }
+  /* Default value for floating point code... if no co-processor
+     bus, then schedule for emulated floating point.  Otherwise,
+     assume the user has an FPA, unless overridden with -mfpe-...  */
+  if (flags & FL_CO_PROC == 0)
+    arm_fpu = FP_SOFT3;
+  else
+    arm_fpu = FP_HARD;
+  arm_fast_multiply = (flags & FL_FAST_MULT) != 0;
+  arm_arch4 = (flags & FL_ARCH4) != 0;
+  arm_thumb_aware = (flags & FL_THUMB) != 0;
 
   if (target_fpe_name)
     {
@@ -288,6 +297,97 @@ arm_override_options ()
   arm_prog_mode = TARGET_APCS_32 ? PROG_MODE_PROG32 : PROG_MODE_PROG26;
 }
 
+#define MAX_LINE 79
+
+struct asm_option
+{
+  char *string;
+  int *variable;
+  int on_value;
+};
+
+static int
+output_option (file, type, name, pos)
+     FILE *file;
+     char *type;
+     char *name;
+     int pos;
+{
+  int type_len = strlen (type);
+  int name_len = strlen (name);
+
+  if (1 + type_len + name_len + pos > MAX_LINE)
+    {
+      fprintf (file, "\n%s %s%s", ASM_COMMENT_START, type, name);
+      return 3 + type_len + name_len;
+    }
+  fprintf (file, " %s%s", type, name);
+  return pos + 1 + type_len + name_len;
+}
+
+static struct { char *name; int value; } m_options[] = TARGET_SWITCHES;
+extern char *version_string, *language_string;
+
+void
+output_options (file, f_options, f_len, W_options, W_len)
+     FILE *file;
+     struct asm_option *f_options;
+     int f_len;
+     struct asm_option *W_options;
+     int W_len;
+{
+  int j;
+  int flags = target_flags;
+  int pos = 32767;
+
+  fprintf (file, "%s %s %s", ASM_COMMENT_START, language_string,
+          version_string);
+
+  if (optimize)
+    {
+      char opt_string[20];
+      sprintf (opt_string, "%d", optimize);
+      pos = output_option (file, "-O", opt_string, pos);
+    }
+
+  if (profile_flag)
+    pos = output_option (file, "-p", "", pos);
+
+  if (inhibit_warnings)
+    pos = output_option (file, "-w", "", pos);
+
+  for (j = 0; j < f_len; j++)
+    {
+      if (*f_options[j].variable == f_options[j].on_value)
+       pos = output_option (file, "-f", f_options[j].string, pos);
+    }
+
+  for (j = 0; j < W_len; j++)
+    {
+      if (*W_options[j].variable == W_options[j].on_value)
+       pos = output_option (file, "-W", W_options[j].string, pos);
+    }
+
+  for (j = 0; j < sizeof m_options / sizeof m_options[0]; j++)
+    {
+      if (m_options[j].name[0] != '\0'
+         && m_options[j].value > 0
+         && ((m_options[j].value & flags) == m_options[j].value))
+       {
+         pos = output_option (file, "-m", m_options[j].name, pos);
+         flags &= ~ m_options[j].value;
+       }
+    }
+
+  for (j = 0; j < sizeof (arm_select) / sizeof(arm_select[0]); j++)
+    if (arm_select[j].string != (char *)0)
+      pos = output_option (file, arm_select[j].name, arm_select[j].string,
+                          pos);
+
+  fputs ("\n\n", file);
+}
+
+
 \f
 /* Return 1 if it is possible to return using a single instruction */
 
@@ -960,6 +1060,70 @@ arm_gen_constant (code, mode, val, target, source, subtargets, generate)
   return insns;
 }
 
+/* Canonicalize a comparison so that we are more likely to recognize it.
+   This can be done for a few constant compares, where we can make the
+   immediate value easier to load.  */
+enum rtx_code
+arm_canonicalize_comparison (code, op1)
+     enum rtx_code code;
+     rtx *op1;
+{
+  HOST_WIDE_INT i = INTVAL (*op1);
+
+  switch (code)
+    {
+    case EQ:
+    case NE:
+      return code;
+
+    case GT:
+    case LE:
+      if (i != (1 << (HOST_BITS_PER_WIDE_INT - 1) - 1)
+         && (const_ok_for_arm (i+1) || const_ok_for_arm (- (i+1))))
+       {
+         *op1 = GEN_INT (i+1);
+         return code == GT ? GE : LT;
+       }
+      break;
+
+    case GE:
+    case LT:
+      if (i != (1 << (HOST_BITS_PER_WIDE_INT - 1))
+         && (const_ok_for_arm (i-1) || const_ok_for_arm (- (i-1))))
+       {
+         *op1 = GEN_INT (i-1);
+         return code == GE ? GT : LE;
+       }
+      break;
+
+    case GTU:
+    case LEU:
+      if (i != ~0
+         && (const_ok_for_arm (i+1) || const_ok_for_arm (- (i+1))))
+       {
+         *op1 = GEN_INT (i + 1);
+         return code == GTU ? GEU : LTU;
+       }
+      break;
+
+    case GEU:
+    case LTU:
+      if (i != 0
+         && (const_ok_for_arm (i - 1) || const_ok_for_arm (- (i - 1))))
+       {
+         *op1 = GEN_INT (i - 1);
+         return code == GEU ? GTU : LEU;
+       }
+      break;
+
+    default:
+      abort ();
+    }
+
+  return code;
+}
+       
+
 /* Handle aggregates that are not laid out in a BLKmode element.
    This is a sub-element of RETURN_IN_MEMORY.  */
 int
@@ -2491,20 +2655,27 @@ arm_gen_movstrqi (operands)
 
   for (i = 0; in_words_to_go >= 2; i+=4)
     {
-      emit_insn (arm_gen_load_multiple (0, (in_words_to_go > 4 
-                                           ? 4 : in_words_to_go),
-                                        src, TRUE, TRUE));
+      if (in_words_to_go > 4)
+       emit_insn (arm_gen_load_multiple (0, 4, src, TRUE, TRUE));
+      else
+       emit_insn (arm_gen_load_multiple (0, in_words_to_go, src, TRUE, 
+                                         FALSE));
+
       if (out_words_to_go)
        {
-         if (out_words_to_go != 1)
-           emit_insn (arm_gen_store_multiple (0, (out_words_to_go > 4
-                                                  ? 4 : out_words_to_go),
-                                              dst, TRUE, TRUE));
+         if (out_words_to_go > 4)
+           emit_insn (arm_gen_store_multiple (0, 4, dst, TRUE, TRUE));
+         else if (out_words_to_go != 1)
+           emit_insn (arm_gen_store_multiple (0, out_words_to_go,
+                                              dst, TRUE, 
+                                              (last_bytes == 0
+                                               ? FALSE : TRUE)));
          else
            {
              emit_move_insn (gen_rtx (MEM, SImode, dst),
                              gen_rtx (REG, SImode, 0));
-             emit_insn (gen_addsi3 (dst, dst, GEN_INT (4)));
+             if (last_bytes != 0)
+               emit_insn (gen_addsi3 (dst, dst, GEN_INT (4)));
            }
        }
 
@@ -2533,7 +2704,6 @@ arm_gen_movstrqi (operands)
        abort ();
 
       part_bytes_reg = copy_to_mode_reg (SImode, gen_rtx (MEM, SImode, src));
-      emit_insn (gen_addsi3 (src, src, GEN_INT (4)));
     }
 
   if (BYTES_BIG_ENDIAN && last_bytes)
@@ -2571,10 +2741,11 @@ arm_gen_movstrqi (operands)
 
          emit_move_insn (gen_rtx (MEM, QImode, dst),
                          gen_rtx (SUBREG, QImode, part_bytes_reg, 0));
-         emit_insn (gen_addsi3 (dst, dst, const1_rtx));
          if (--last_bytes)
            {
              rtx tmp = gen_reg_rtx (SImode);
+
+             emit_insn (gen_addsi3 (dst, dst, const1_rtx));
              emit_insn (gen_lshrsi3 (tmp, part_bytes_reg, GEN_INT (8)));
              part_bytes_reg = tmp;
            }
@@ -2787,6 +2958,11 @@ arm_select_cc_mode (op, x, y)
   if (GET_MODE (x) == QImode && (op == EQ || op == NE))
     return CC_Zmode;
 
+  if (GET_MODE (x) == SImode && (op == LTU || op == GEU)
+      && GET_CODE (x) == PLUS
+      && (rtx_equal_p (XEXP (x, 0), y) || rtx_equal_p (XEXP (x, 1), y)))
+    return CC_Cmode;
+
   return CCmode;
 }
 
@@ -4845,18 +5021,15 @@ arm_asm_output_label (stream, name)
    define STATIC COMMON space but merely STATIC BSS space.  */
 
 void
-output_lcomm_directive (stream, name, size, rounded)
+output_lcomm_directive (stream, name, size, align)
      FILE *stream;
      char *name;
-     int size, rounded;
+     int size, align;
 {
-  fprintf (stream, "\n\t.bss\t%s .lcomm\n", ASM_COMMENT_START);
-  assemble_name (stream, name);
-  fprintf (stream, ":\t.space\t%d\n", rounded);
-  if (in_text_section ())
-    fputs ("\n\t.text\n", stream);
-  else
-    fputs ("\n\t.data\n", stream);
+  bss_section ();
+  ASM_OUTPUT_ALIGN (stream, floor_log2 (align / BITS_PER_UNIT));
+  ARM_OUTPUT_LABEL (stream, name);
+  fprintf (stream, "\t.space\t%d\n", size);
 }
 \f
 /* A finite state machine takes care of noticing whether or not instructions
@@ -4972,6 +5145,14 @@ get_arm_condition_code (comparison)
        default: abort ();
        }
 
+    case CC_Cmode:
+      switch (comp_code)
+      {
+      case LTU: return ARM_CS;
+      case GEU: return ARM_CC;
+      default: abort ();
+      }
+      
     case CCmode:
       switch (comp_code)
        {
@@ -5096,7 +5277,8 @@ final_prescan_insn (insn, opvec, noperands)
       || (GET_CODE (body) == SET && GET_CODE (SET_DEST (body)) == PC
          && GET_CODE (SET_SRC (body)) == IF_THEN_ELSE))
     {
-      int insns_skipped = 0, fail = FALSE, succeed = FALSE;
+      int insns_skipped;
+      int fail = FALSE, succeed = FALSE;
       /* Flag which part of the IF_THEN_ELSE is the LABEL_REF.  */
       int then_not_else = TRUE;
       rtx this_insn = start_insn, label = 0;
@@ -5137,8 +5319,7 @@ final_prescan_insn (insn, opvec, noperands)
         insns are okay, and the label or unconditional branch to the same
         label is not too far away, succeed.  */
       for (insns_skipped = 0;
-          !fail && !succeed && insns_skipped < MAX_INSNS_SKIPPED;
-          insns_skipped++)
+          !fail && !succeed && insns_skipped++ < MAX_INSNS_SKIPPED;)
        {
          rtx scanbody;
 
@@ -5193,7 +5374,29 @@ final_prescan_insn (insn, opvec, noperands)
              /* If using 32-bit addresses the cc is not preserved over
                 calls */
              if (TARGET_APCS_32)
-               fail = TRUE;
+               {
+                 /* Succeed if the following insn is the target label,
+                    or if the following two insns are a barrier and
+                    the target label.  */
+                 this_insn = next_nonnote_insn (this_insn);
+                 if (this_insn && GET_CODE (this_insn) == BARRIER)
+                   this_insn = next_nonnote_insn (this_insn);
+
+                 if (this_insn && this_insn == label
+                     && insns_skipped < MAX_INSNS_SKIPPED)
+                   {
+                     if (jump_clobbers)
+                       {
+                         arm_ccfsm_state = 2;
+                         this_insn = next_nonnote_insn (this_insn);
+                       }
+                     else
+                       arm_ccfsm_state = 1;
+                     succeed = TRUE;
+                   }
+                 else
+                   fail = TRUE;
+               }
              break;
 
            case JUMP_INSN: