]> gcc.gnu.org Git - gcc.git/blobdiff - gcc/config/rs6000/rs6000.c
(output_prolog): Fix error in loading size of large stack frames.
[gcc.git] / gcc / config / rs6000 / rs6000.c
index 74f785988295d576f9101893948c5f58b905c93f..4a92acb6e07937a0ca292cdfccb67f9329a009e7 100644 (file)
@@ -1,6 +1,6 @@
 /* Subroutines used for code generation on IBM RS/6000.
-   Copyright (C) 1991, 1993 Free Software Foundation, Inc.
-   Contributed by Richard Kenner (kenner@nyu.edu)
+   Copyright (C) 1991, 1993, 1994 Free Software Foundation, Inc.
+   Contributed by Richard Kenner (kenner@vlsi1.ultra.nyu.edu)
 
 This file is part of GNU CC.
 
@@ -55,6 +55,8 @@ int rs6000_trunc_used;
 
 static int trunc_defined;
 
+/* Set to non-zero once AIX common-mode calls have been defined.  */
+static int common_mode_defined;
 /* Save information from a "cmpxx" operation until the branch or scc is
    emitted.  */
 
@@ -69,6 +71,14 @@ rs6000_override_options ()
 {
   int i;
 
+  /* Simplify the entries below by making a mask for any POWER
+     variant and any PowerPC variant.  */
+
+#define POWER_MASKS (MASK_POWER | MASK_POWER2)
+#define POWERPC_MASKS (MASK_POWERPC | MASK_PPC_GPOPT \
+                      | MASK_PPC_GFXOPT | MASK_POWERPC64)
+#define POWERPC_OPT_MASKS (MASK_PPC_GPOPT | MASK_PPC_GFXOPT)
+
   static struct ptt
     {
       char *name;              /* Canonical processor name.  */
@@ -76,30 +86,67 @@ rs6000_override_options ()
       int target_enable;       /* Target flags to enable.  */
       int target_disable;      /* Target flags to disable.  */
     } processor_target_table[]
-      = {{"all", PROCESSOR_DEFAULT,
-           0, MASK_POWER | MASK_POWERPC | MASK_POWERPC64},
+      = {{"common", PROCESSOR_COMMON, 0, POWER_MASKS | POWERPC_MASKS},
+        {"power", PROCESSOR_POWER,
+           MASK_POWER,
+           MASK_POWER2 | POWERPC_MASKS | MASK_NEW_MNEMONICS},
+        {"powerpc", PROCESSOR_POWERPC,
+           MASK_POWERPC | MASK_NEW_MNEMONICS,
+           POWER_MASKS | POWERPC_OPT_MASKS | MASK_POWERPC64},
         {"rios", PROCESSOR_RIOS1,
-           MASK_POWER, MASK_POWERPC | MASK_POWERPC64},
+           MASK_POWER,
+           MASK_POWER2 | POWERPC_MASKS | MASK_NEW_MNEMONICS},
         {"rios1", PROCESSOR_RIOS1,
-           MASK_POWER, MASK_POWERPC | MASK_POWERPC64},
+           MASK_POWER,
+           MASK_POWER2 | POWERPC_MASKS | MASK_NEW_MNEMONICS},
+        {"rsc", PROCESSOR_PPC601,
+           MASK_POWER,
+           MASK_POWER2 | POWERPC_MASKS | MASK_NEW_MNEMONICS},
+        {"rsc1", PROCESSOR_PPC601,
+           MASK_POWER,
+           MASK_POWER2 | POWERPC_MASKS | MASK_NEW_MNEMONICS},
         {"rios2", PROCESSOR_RIOS2,
-           MASK_POWER, MASK_POWERPC | MASK_POWERPC64},
+           MASK_POWER | MASK_POWER2,
+           POWERPC_MASKS | MASK_NEW_MNEMONICS},
         {"601", PROCESSOR_PPC601,
-           MASK_POWER | MASK_POWERPC | MASK_NEW_MNEMONICS, MASK_POWERPC64},
+           MASK_POWER | MASK_POWERPC | MASK_NEW_MNEMONICS,
+           MASK_POWER2 | POWERPC_OPT_MASKS | MASK_POWERPC64},
         {"mpc601", PROCESSOR_PPC601,
-           MASK_POWER | MASK_POWERPC | MASK_NEW_MNEMONICS, MASK_POWERPC64},
+           MASK_POWER | MASK_POWERPC | MASK_NEW_MNEMONICS,
+           MASK_POWER2 | POWERPC_OPT_MASKS | MASK_POWERPC64},
+        {"ppc601", PROCESSOR_PPC601,
+           MASK_POWER | MASK_POWERPC | MASK_NEW_MNEMONICS,
+           MASK_POWER2 | POWERPC_OPT_MASKS | MASK_POWERPC64},
         {"603", PROCESSOR_PPC603,
-           MASK_POWERPC | MASK_NEW_MNEMONICS, MASK_POWER | MASK_POWERPC64},
+           MASK_POWERPC | MASK_PPC_GFXOPT | MASK_NEW_MNEMONICS,
+           POWER_MASKS | MASK_PPC_GPOPT | MASK_POWERPC64},
         {"mpc603", PROCESSOR_PPC603,
-           MASK_POWERPC | MASK_NEW_MNEMONICS, MASK_POWER | MASK_POWERPC64},
+           MASK_POWERPC | MASK_PPC_GFXOPT | MASK_NEW_MNEMONICS,
+           POWER_MASKS | MASK_PPC_GPOPT | MASK_POWERPC64},
+        {"ppc603", PROCESSOR_PPC603,
+           MASK_POWERPC | MASK_PPC_GFXOPT | MASK_NEW_MNEMONICS,
+           POWER_MASKS | MASK_PPC_GPOPT | MASK_POWERPC64},
         {"604", PROCESSOR_PPC604,
-           MASK_POWERPC | MASK_NEW_MNEMONICS, MASK_POWER | MASK_POWERPC64},
+           MASK_POWERPC | MASK_PPC_GFXOPT | MASK_NEW_MNEMONICS,
+           POWER_MASKS | MASK_PPC_GPOPT | MASK_POWERPC64},
         {"mpc604", PROCESSOR_PPC604,
-           MASK_POWERPC | MASK_NEW_MNEMONICS, MASK_POWER | MASK_POWERPC64},
+           MASK_POWERPC | MASK_PPC_GFXOPT | MASK_NEW_MNEMONICS,
+           POWER_MASKS | MASK_PPC_GPOPT | MASK_POWERPC64},
+        {"ppc604", PROCESSOR_PPC604,
+           MASK_POWERPC | MASK_PPC_GFXOPT | MASK_NEW_MNEMONICS,
+           POWER_MASKS | MASK_PPC_GPOPT | MASK_POWERPC64},
         {"620", PROCESSOR_PPC620,
-           MASK_POWERPC | MASK_POWERPC64 | MASK_NEW_MNEMONICS, MASK_POWER},
+           (MASK_POWERPC | POWERPC_OPT_MASKS | MASK_POWERPC64
+            | MASK_NEW_MNEMONICS),
+             POWER_MASKS},
         {"mpc620", PROCESSOR_PPC620,
-           MASK_POWERPC | MASK_POWERPC64 | MASK_NEW_MNEMONICS, MASK_POWER}};
+           (MASK_POWERPC | POWERPC_OPT_MASKS | MASK_POWERPC64
+            | MASK_NEW_MNEMONICS),
+             POWER_MASKS},
+        {"ppc620", PROCESSOR_PPC620,
+           (MASK_POWERPC | POWERPC_OPT_MASKS | MASK_POWERPC64
+            | MASK_NEW_MNEMONICS),
+             POWER_MASKS}};
 
   int ptt_size = sizeof (processor_target_table) / sizeof (struct ptt);
 
@@ -260,13 +307,9 @@ reg_or_cint_operand (op, mode)
      return GET_CODE (op) == CONST_INT || gpc_reg_operand (op, mode);
 }
 
-/* Return 1 if the operand is a CONST_DOUBLE and it can be put into a
-   register with one instruction per word.  For SFmode, this means  that
-   the low 16-bits are zero.  For DFmode, it means the low 16-bits of
-   the first word are zero and the high 16 bits of the second word
-   are zero (usually all bits in the low-order word will be zero).
-
-   We only do this if we can safely read CONST_DOUBLE_{LOW,HIGH}.  */
+/* Return 1 if the operand is a CONST_DOUBLE and it can be put into a register
+   with one instruction per word.  We only do this if we can safely read
+   CONST_DOUBLE_{LOW,HIGH}.  */
 
 int
 easy_fp_constant (op, mode)
@@ -283,12 +326,11 @@ easy_fp_constant (op, mode)
   high = operand_subword (op, 0, 0, mode);
   low = operand_subword (op, 1, 0, mode);
 
-  if (high == 0 || GET_CODE (high) != CONST_INT || (INTVAL (high) & 0xffff))
+  if (high == 0 || ! input_operand (high, word_mode))
     return 0;
 
   return (mode == SFmode
-         || (low != 0 && GET_CODE (low) == CONST_INT
-             && (INTVAL (low) & 0xffff0000) == 0));
+         || (low != 0 && input_operand (low, word_mode)));
 }
       
 /* Return 1 if the operand is either a floating-point register, a pseudo
@@ -802,9 +844,9 @@ print_operand (file, x, code)
   switch (code)
     {
     case '.':
-      /* Write out the bit number for "cror" after a call.   This differs
-        between AIX 3.2 and earlier versions.  */
-      fprintf (file, "%d", RS6000_CROR_BIT_NUMBER);
+      /* Write out an instruction after the call which may be replaced
+        with glue code by the loader.  This depends on the AIX version.  */
+      asm_fprintf (file, RS6000_CALL_GLUE);
       return;
 
     case 'A':
@@ -868,7 +910,7 @@ print_operand (file, x, code)
        output_operand_lossage ("invalid %%E value");
 
       fprintf(file, "%d", 4 * (REGNO (x) - 68) + 3);
-      break;
+      return;
 
     case 'f':
       /* X is a CR register.  Print the shift count needed to move it
@@ -1229,7 +1271,7 @@ print_operand (file, x, code)
        }
       else
        output_addr_const (file, x);
-      break;
+      return;
 
     default:
       output_operand_lossage ("invalid %%xn code");
@@ -1396,9 +1438,21 @@ output_prolog (file, size)
   /* Write .extern for truncation routines, if needed.  */
   if (rs6000_trunc_used && ! trunc_defined)
     {
-      fprintf (file, "\t.extern .itrunc\n\t.extern .uitrunc\n");
+      fprintf (file, "\t.extern .%s\n\t.extern .%s\n",
+              RS6000_ITRUNC, RS6000_UITRUNC);
       trunc_defined = 1;
     }
+  /* Write .extern for AIX common mode routines, if needed.  */
+  if (! TARGET_POWER && ! TARGET_POWERPC && ! common_mode_defined)
+    {
+      fputs ("\t.extern __mulh\n", file);
+      fputs ("\t.extern __mull\n", file);
+      fputs ("\t.extern __divss\n", file);
+      fputs ("\t.extern __divus\n", file);
+      fputs ("\t.extern __quoss\n", file);
+      fputs ("\t.extern __quous\n", file);
+      common_mode_defined = 1;
+    }
 
   /* If we have to call a function to save fpr's, or if we are doing profiling,
      then we will be using LR.  */
@@ -1407,58 +1461,78 @@ output_prolog (file, size)
 
   /* If we use the link register, get it into r0.  */
   if (regs_ever_live[65])
-    fprintf (file, "\tmflr 0\n");
+    asm_fprintf (file, "\tmflr 0\n");
 
   /* If we need to save CR, put it into r12.  */
   if (must_save_cr ())
-    fprintf (file, "\tmfcr 12\n");
+    asm_fprintf (file, "\tmfcr 12\n");
 
   /* Do any required saving of fpr's.  If only one or two to save, do it
      ourself.  Otherwise, call function.  Note that since they are statically
      linked, we do not need a nop following them.  */
   if (first_fp_reg == 62)
-    fprintf (file, "\tstfd 30,-16(1)\n\tstfd 31,-8(1)\n");
+    asm_fprintf (file, "\tstfd 30,-16(1)\n\tstfd 31,-8(1)\n");
   else if (first_fp_reg == 63)
-    fprintf (file, "\tstfd 31,-8(1)\n");
+    asm_fprintf (file, "\tstfd 31,-8(1)\n");
   else if (first_fp_reg != 64)
-    fprintf (file, "\tbl ._savef%d\n", first_fp_reg - 32);
+    asm_fprintf (file, "\tbl ._savef%d\n", first_fp_reg - 32);
 
   /* Now save gpr's.  */
-  if (first_reg == 31)
-    fprintf (file, "\tst 31,%d(1)\n", -4 - (64 - first_fp_reg) * 8);
+  if (! TARGET_POWER || first_reg == 31)
+    {
+      int regno, loc;
+
+      for (regno = first_reg,
+          loc = - (32 - first_reg) * 4 - (64 - first_fp_reg) * 8;
+          regno < 32;
+          regno++, loc += 4)
+       asm_fprintf (file, "\t{st|stw} %d,%d(1)\n", regno, loc);
+    }
+
   else if (first_reg != 32)
-    fprintf (file, "\tstm %d,%d(1)\n", first_reg,
+    asm_fprintf (file, "\t{stm|stmw} %d,%d(1)\n", first_reg,
             - (32 - first_reg) * 4 - (64 - first_fp_reg) * 8);
 
   /* Save lr if we used it.  */
   if (regs_ever_live[65])
-    fprintf (file, "\tst 0,8(1)\n");
+    asm_fprintf (file, "\t{st|stw} 0,8(1)\n");
 
   /* Save CR if we use any that must be preserved.  */
   if (must_save_cr ())
-    fprintf (file, "\tst 12,4(1)\n");
+    asm_fprintf (file, "\t{st|stw} 12,4(1)\n");
 
   /* Update stack and set back pointer.  */
   if (must_push)
     {
       if (total_size < 32767)
-       fprintf (file, "\tstu 1,%d(1)\n", - total_size);
+       asm_fprintf (file, "\t{stu|stwu} 1,%d(1)\n", - total_size);
       else
        {
-         fprintf (file, "\tcau 0,0,%d\n\toril 0,0,%d\n",
+         asm_fprintf (file, "\t{cau 0,0,%d|lis 0,%d}\n\t{oril|ori} 0,0,%d\n",
                   (total_size >> 16) & 0xffff, total_size & 0xffff);
-         fprintf (file, "\tsf 12,0,1\n\tst 1,0(12)\n\toril 1,12,0\n");
+         if (TARGET_POWERPC)
+           asm_fprintf (file, "\tsubf 12,0,1\n");
+         else
+           asm_fprintf (file, "\t{sf|subfc} 12,0,1\n");
+         asm_fprintf (file, "\t{st|stw} 1,0(12)\n\tmr 1,12\n");
        }
     }
 
   /* Set frame pointer, if needed.  */
   if (frame_pointer_needed)
-    fprintf (file, "\toril 31,1,0\n");
+    asm_fprintf (file, "\tmr 31,1\n");
 
   /* If TARGET_MINIMAL_TOC, and the constant pool is needed, then load the
      TOC_TABLE address into register 30.  */
   if (TARGET_MINIMAL_TOC && get_pool_size () != 0)
-    fprintf (file, "\tl 30,LCTOC..0(2)\n");
+    {
+      char buf[100];
+
+      ASM_GENERATE_INTERNAL_LABEL (buf, "LCTOC", 0);
+      asm_fprintf (file, "\t{l|lwz} 30,");
+      assemble_name (file, buf);
+      asm_fprintf (file, "(2)\n");
+    }
 }
 
 /* Write function epilogue.  */
@@ -1489,222 +1563,248 @@ output_epilog (file, size)
         we know what size to update it with.  */
       if (frame_pointer_needed || current_function_calls_alloca
          || total_size > 32767)
-       fprintf (file, "\tl 1,0(1)\n");
+       asm_fprintf (file, "\t{l|lwz} 1,0(1)\n");
       else if (must_push)
-       fprintf (file, "\tai 1,1,%d\n", total_size);
+       asm_fprintf (file, "\t{cal 1,%d(1)|addi 1,1,%d}\n", total_size);
 
       /* Get the old lr if we saved it.  */
       if (regs_ever_live[65])
-       fprintf (file, "\tl 0,8(1)\n");
+       asm_fprintf (file, "\t{l|lwz} 0,8(1)\n");
 
       /* Get the old cr if we saved it.  */
       if (must_save_cr ())
-       fprintf (file, "\tl 12,4(1)\n");
+       asm_fprintf (file, "\t{l|lwz} 12,4(1)\n");
 
       /* Set LR here to try to overlap restores below.  */
       if (regs_ever_live[65])
-       fprintf (file, "\tmtlr 0\n");
+       asm_fprintf (file, "\tmtlr 0\n");
 
       /* Restore gpr's.  */
-      if (first_reg == 31)
-       fprintf (file, "\tl 31,%d(1)\n", -4 - (64 - first_fp_reg) * 8);
+      if (! TARGET_POWER || first_reg == 31)
+       {
+         int regno, loc;
+
+         for (regno = first_reg,
+              loc = - (32 - first_reg) * 4 - (64 - first_fp_reg) * 8;
+              regno < 32;
+              regno++, loc += 4)
+           asm_fprintf (file, "\t{l|lwz} %d,%d(1)\n", regno, loc);
+       }
+
       else if (first_reg != 32)
-       fprintf (file, "\tlm %d,%d(1)\n", first_reg,
-                - (32 - first_reg) * 4 - (64 - first_fp_reg) * 8);
+       asm_fprintf (file, "\t{lm|lmw} %d,%d(1)\n", first_reg,
+            - (32 - first_reg) * 4 - (64 - first_fp_reg) * 8);
 
       /* Restore fpr's if we can do it without calling a function.  */
       if (first_fp_reg == 62)
-       fprintf (file, "\tlfd 30,-16(1)\n\tlfd 31,-8(1)\n");
+       asm_fprintf (file, "\tlfd 30,-16(1)\n\tlfd 31,-8(1)\n");
       else if (first_fp_reg == 63)
-       fprintf (file, "\tlfd 31,-8(1)\n");
+       asm_fprintf (file, "\tlfd 31,-8(1)\n");
 
       /* If we saved cr, restore it here.  Just those of cr2, cr3, and cr4
         that were used.  */
       if (must_save_cr ())
-       fprintf (file, "\tmtcrf %d,12\n",
-                (regs_ever_live[70] != 0) * 0x20
-                + (regs_ever_live[71] != 0) * 0x10
-                + (regs_ever_live[72] != 0) * 0x8);
+       asm_fprintf (file, "\tmtcrf %d,12\n",
+                    (regs_ever_live[70] != 0) * 0x20
+                    + (regs_ever_live[71] != 0) * 0x10
+                    + (regs_ever_live[72] != 0) * 0x8);
 
       /* If we have to restore more than two FP registers, branch to the
         restore function.  It will return to our caller.  */
       if (first_fp_reg < 62)
-       fprintf (file, "\tb ._restf%d\n", first_fp_reg - 32);
+       asm_fprintf (file, "\tb ._restf%d\n", first_fp_reg - 32);
       else
-       fprintf (file, "\tbr\n");
+       asm_fprintf (file, "\t{br|blr}\n");
     }
 
   /* Output a traceback table here.  See /usr/include/sys/debug.h for info
-     on its format.  */
-  {
-    char *fname = XSTR (XEXP (DECL_RTL (current_function_decl), 0), 0);
-    int fixed_parms, float_parms, parm_info;
-    int i;
-
-    /* Need label immediately before tbtab, so we can compute its offset
-       from the function start.  */
-    if (*fname == '*')
-      ++fname;
-    fprintf (file, "LT..");
-    ASM_OUTPUT_LABEL (file, fname);
-
-    /* The .tbtab pseudo-op can only be used for the first eight
-       expressions, since it can't handle the possibly variable length
-       fields that follow.  However, if you omit the optional fields,
-       the assembler outputs zeros for all optional fields anyways, giving each
-       variable length field is minimum length (as defined in sys/debug.h).
-       Thus we can not use the .tbtab pseudo-op at all.  */
-
-    /* An all-zero word flags the start of the tbtab, for debuggers that have
-       to find it by searching forward from the entry point or from the
-       current pc.  */
-    fprintf (file, "\t.long 0\n");
-
-    /* Tbtab format type.  Use format type 0.  */
-    fprintf (file, "\t.byte 0,");
-
-    /* Language type.  Unfortunately, there doesn't seem to be any official way
-       to get this info, so we use language_string.  C is 0.  C++ is 9.
-       No number defined for Obj-C, so use the value for C for now.  */
-    if (! strcmp (language_string, "GNU C")
-       || ! strcmp (language_string, "GNU Obj-C"))
-      i = 0;
-    else if (! strcmp (language_string, "GNU F77"))
-      i = 1;
-    else if (! strcmp (language_string, "GNU Ada"))
-      i = 3;
-    else if (! strcmp (language_string, "GNU PASCAL"))
-      i = 2;
-    else if (! strcmp (language_string, "GNU C++"))
-      i = 9;
-    else
-      abort ();
-    fprintf (file, "%d,", i);
-
-    /* 8 single bit fields: global linkage (not set for C extern linkage,
-       apparently a PL/I convention?), out-of-line epilogue/prologue, offset
-       from start of procedure stored in tbtab, internal function, function
-       has controlled storage, function has no toc, function uses fp,
-       function logs/aborts fp operations.  */
-    /* Assume that fp operations are used if any fp reg must be saved.  */
-    fprintf (file, "%d,", (1 << 5) | ((first_fp_reg != 64) << 1));
-
-    /* 6 bitfields: function is interrupt handler, name present in proc table,
-       function calls alloca, on condition directives (controls stack walks,
-       3 bits), saves condition reg, saves link reg.  */
-    /* The `function calls alloca' bit seems to be set whenever reg 31 is
-       set up as a frame pointer, even when there is no alloca call.  */
-    fprintf (file, "%d,",
-            ((1 << 6) | (frame_pointer_needed << 5)
-             | (must_save_cr () << 1) | (regs_ever_live[65])));
-
-    /* 3 bitfields: saves backchain, spare bit, number of fpr saved
-       (6 bits).  */
-    fprintf (file, "%d,",
-            (must_push << 7) | (64 - first_fp_reg_to_save ()));
-
-    /* 2 bitfields: spare bits (2 bits), number of gpr saved (6 bits).  */
-    fprintf (file, "%d,", (32 - first_reg_to_save ()));
-
+     on its format.
+
+     We don't output a traceback table if -finhibit-size-directive was
+     used.  The documentation for -finhibit-size-directive reads
+     ``don't output a @code{.size} assembler directive, or anything
+     else that would cause trouble if the function is split in the
+     middle, and the two halves are placed at locations far apart in
+     memory.''  The traceback table has this property, since it
+     includes the offset from the start of the function to the
+     traceback table itself.  */
+  if (! flag_inhibit_size_directive)
     {
-      /* Compute the parameter info from the function decl argument list.  */
-      tree decl;
-      int next_parm_info_bit;
-
-      next_parm_info_bit = 31;
-      parm_info = 0;
-      fixed_parms = 0;
-      float_parms = 0;
-
-      for (decl = DECL_ARGUMENTS (current_function_decl);
-          decl; decl = TREE_CHAIN (decl))
-       {
-         rtx parameter = DECL_INCOMING_RTL (decl);
-         enum machine_mode mode = GET_MODE (parameter);
-
-         if (GET_CODE (parameter) == REG)
-           {
-             if (GET_MODE_CLASS (mode) == MODE_FLOAT)
-               {
-                 int bits;
-
-                 float_parms++;
-
-                 if (mode == SFmode)
-                   bits = 0x2;
-                 else if (mode == DFmode)
-                   bits = 0x3;
-                 else
-                   abort ();
-
-                 /* If only one bit will fit, don't or in this entry.  */
-                 if (next_parm_info_bit > 0)
-                   parm_info |= (bits << (next_parm_info_bit - 1));
-                 next_parm_info_bit -= 2;
-               }
-             else
-               {
-                 fixed_parms += ((GET_MODE_SIZE (mode) + (UNITS_PER_WORD - 1))
-                                 / UNITS_PER_WORD);
-                 next_parm_info_bit -= 1;
-               }
-           }
-       }
+      char *fname = XSTR (XEXP (DECL_RTL (current_function_decl), 0), 0);
+      int fixed_parms, float_parms, parm_info;
+      int i;
+
+      /* Need label immediately before tbtab, so we can compute its offset
+        from the function start.  */
+      if (*fname == '*')
+       ++fname;
+      ASM_OUTPUT_INTERNAL_LABEL_PREFIX (file, "LT");
+      ASM_OUTPUT_LABEL (file, fname);
+
+      /* The .tbtab pseudo-op can only be used for the first eight
+        expressions, since it can't handle the possibly variable
+        length fields that follow.  However, if you omit the optional
+        fields, the assembler outputs zeros for all optional fields
+        anyways, giving each variable length field is minimum length
+        (as defined in sys/debug.h).  Thus we can not use the .tbtab
+        pseudo-op at all.  */
+
+      /* An all-zero word flags the start of the tbtab, for debuggers
+        that have to find it by searching forward from the entry
+        point or from the current pc.  */
+      fprintf (file, "\t.long 0\n");
+
+      /* Tbtab format type.  Use format type 0.  */
+      fprintf (file, "\t.byte 0,");
+
+      /* Language type.  Unfortunately, there doesn't seem to be any
+        official way to get this info, so we use language_string.  C
+        is 0.  C++ is 9.  No number defined for Obj-C, so use the
+        value for C for now.  */
+      if (! strcmp (language_string, "GNU C")
+         || ! strcmp (language_string, "GNU Obj-C"))
+       i = 0;
+      else if (! strcmp (language_string, "GNU F77"))
+       i = 1;
+      else if (! strcmp (language_string, "GNU Ada"))
+       i = 3;
+      else if (! strcmp (language_string, "GNU PASCAL"))
+       i = 2;
+      else if (! strcmp (language_string, "GNU C++"))
+       i = 9;
+      else
+       abort ();
+      fprintf (file, "%d,", i);
+
+      /* 8 single bit fields: global linkage (not set for C extern linkage,
+        apparently a PL/I convention?), out-of-line epilogue/prologue, offset
+        from start of procedure stored in tbtab, internal function, function
+        has controlled storage, function has no toc, function uses fp,
+        function logs/aborts fp operations.  */
+      /* Assume that fp operations are used if any fp reg must be saved.  */
+      fprintf (file, "%d,", (1 << 5) | ((first_fp_reg != 64) << 1));
+
+      /* 6 bitfields: function is interrupt handler, name present in
+        proc table, function calls alloca, on condition directives
+        (controls stack walks, 3 bits), saves condition reg, saves
+        link reg.  */
+      /* The `function calls alloca' bit seems to be set whenever reg 31 is
+        set up as a frame pointer, even when there is no alloca call.  */
+      fprintf (file, "%d,",
+              ((1 << 6) | (frame_pointer_needed << 5)
+               | (must_save_cr () << 1) | (regs_ever_live[65])));
+
+      /* 3 bitfields: saves backchain, spare bit, number of fpr saved
+        (6 bits).  */
+      fprintf (file, "%d,",
+              (must_push << 7) | (64 - first_fp_reg_to_save ()));
+
+      /* 2 bitfields: spare bits (2 bits), number of gpr saved (6 bits).  */
+      fprintf (file, "%d,", (32 - first_reg_to_save ()));
+
+      {
+       /* Compute the parameter info from the function decl argument
+          list.  */
+       tree decl;
+       int next_parm_info_bit;
+
+       next_parm_info_bit = 31;
+       parm_info = 0;
+       fixed_parms = 0;
+       float_parms = 0;
+
+       for (decl = DECL_ARGUMENTS (current_function_decl);
+            decl; decl = TREE_CHAIN (decl))
+         {
+           rtx parameter = DECL_INCOMING_RTL (decl);
+           enum machine_mode mode = GET_MODE (parameter);
+
+           if (GET_CODE (parameter) == REG)
+             {
+               if (GET_MODE_CLASS (mode) == MODE_FLOAT)
+                 {
+                   int bits;
+
+                   float_parms++;
+
+                   if (mode == SFmode)
+                     bits = 0x2;
+                   else if (mode == DFmode)
+                     bits = 0x3;
+                   else
+                     abort ();
+
+                   /* If only one bit will fit, don't or in this entry.  */
+                   if (next_parm_info_bit > 0)
+                     parm_info |= (bits << (next_parm_info_bit - 1));
+                   next_parm_info_bit -= 2;
+                 }
+               else
+                 {
+                   fixed_parms += ((GET_MODE_SIZE (mode)
+                                    + (UNITS_PER_WORD - 1))
+                                   / UNITS_PER_WORD);
+                   next_parm_info_bit -= 1;
+                 }
+             }
+         }
+      }
+
+      /* Number of fixed point parameters.  */
+      /* This is actually the number of words of fixed point parameters; thus
+        an 8 byte struct counts as 2; and thus the maximum value is 8.  */
+      fprintf (file, "%d,", fixed_parms);
+
+      /* 2 bitfields: number of floating point parameters (7 bits), parameters
+        all on stack.  */
+      /* This is actually the number of fp registers that hold parameters;
+        and thus the maximum value is 13.  */
+      /* Set parameters on stack bit if parameters are not in their original
+        registers, regardless of whether they are on the stack?  Xlc
+        seems to set the bit when not optimizing.  */
+      fprintf (file, "%d\n", ((float_parms << 1) | (! optimize)));
+
+      /* Optional fields follow.  Some are variable length.  */
+
+      /* Parameter types, left adjusted bit fields: 0 fixed, 10 single float,
+        11 double float.  */
+      /* There is an entry for each parameter in a register, in the order that
+        they occur in the parameter list.  Any intervening arguments on the
+        stack are ignored.  If the list overflows a long (max possible length
+        34 bits) then completely leave off all elements that don't fit.  */
+      /* Only emit this long if there was at least one parameter.  */
+      if (fixed_parms || float_parms)
+       fprintf (file, "\t.long %d\n", parm_info);
+
+      /* Offset from start of code to tb table.  */
+      fprintf (file, "\t.long ");
+      ASM_OUTPUT_INTERNAL_LABEL_PREFIX (file, "LT");
+      RS6000_OUTPUT_BASENAME (file, fname);
+      fprintf (file, "-.");
+      RS6000_OUTPUT_BASENAME (file, fname);
+      fprintf (file, "\n");
+
+      /* Interrupt handler mask.  */
+      /* Omit this long, since we never set the interrupt handler bit
+        above.  */
+
+      /* Number of CTL (controlled storage) anchors.  */
+      /* Omit this long, since the has_ctl bit is never set above.  */
+
+      /* Displacement into stack of each CTL anchor.  */
+      /* Omit this list of longs, because there are no CTL anchors.  */
+
+      /* Length of function name.  */
+      fprintf (file, "\t.short %d\n", strlen (fname));
+
+      /* Function name.  */
+      assemble_string (fname, strlen (fname));
+
+      /* Register for alloca automatic storage; this is always reg 31.
+        Only emit this if the alloca bit was set above.  */
+      if (frame_pointer_needed)
+       fprintf (file, "\t.byte 31\n");
     }
-
-    /* Number of fixed point parameters.  */
-    /* This is actually the number of words of fixed point parameters; thus
-       an 8 byte struct counts as 2; and thus the maximum value is 8.  */
-    fprintf (file, "%d,", fixed_parms);
-
-    /* 2 bitfields: number of floating point parameters (7 bits), parameters
-       all on stack.  */
-    /* This is actually the number of fp registers that hold parameters;
-       and thus the maximum value is 13.  */
-    /* Set parameters on stack bit if parameters are not in their original
-       registers, regardless of whether they are on the stack?  Xlc
-       seems to set the bit when not optimizing.  */
-    fprintf (file, "%d\n", ((float_parms << 1) | (! optimize)));
-
-    /* Optional fields follow.  Some are variable length.  */
-
-    /* Parameter types, left adjusted bit fields: 0 fixed, 10 single float,
-       11 double float.  */
-    /* There is an entry for each parameter in a register, in the order that
-       they occur in the parameter list.  Any intervening arguments on the
-       stack are ignored.  If the list overflows a long (max possible length
-       34 bits) then completely leave off all elements that don't fit.  */
-    /* Only emit this long if there was at least one parameter.  */
-    if (fixed_parms || float_parms)
-      fprintf (file, "\t.long %d\n", parm_info);
-
-    /* Offset from start of code to tb table.  */
-    fprintf (file, "\t.long LT..");
-    RS6000_OUTPUT_BASENAME (file, fname);
-    fprintf (file, "-.");
-    RS6000_OUTPUT_BASENAME (file, fname);
-    fprintf (file, "\n");
-
-    /* Interrupt handler mask.  */
-    /* Omit this long, since we never set the interrupt handler bit above.  */
-
-    /* Number of CTL (controlled storage) anchors.  */
-    /* Omit this long, since the has_ctl bit is never set above.  */
-
-    /* Displacement into stack of each CTL anchor.  */
-    /* Omit this list of longs, because there are no CTL anchors.  */
-
-    /* Length of function name.  */
-    fprintf (file, "\t.short %d\n", strlen (fname));
-
-    /* Function name.  */
-    assemble_string (fname, strlen (fname));
-
-    /* Register for alloca automatic storage; this is always reg 31.
-       Only emit this if the alloca bit was set above.  */
-    if (frame_pointer_needed)
-      fprintf (file, "\t.byte 31\n");
-  }
 }
 \f
 /* Output a TOC entry.  We derive the entry name from what is
@@ -1924,11 +2024,26 @@ output_function_profiler (file, labelno)
   /* The last used parameter register.  */
   int last_parm_reg;
   int i, j;
+  char buf[100];
 
   /* Set up a TOC entry for the profiler label.  */
   toc_section ();
-  fprintf (file, "LPC..%d:\n\t.tc\tLP..%d[TC],LP..%d\n",
-          labelno, labelno, labelno);
+  ASM_OUTPUT_INTERNAL_LABEL (file, "LPC", labelno);
+  ASM_GENERATE_INTERNAL_LABEL (buf, "LP", labelno);
+  if (TARGET_MINIMAL_TOC)
+    {
+      fprintf (file, "\t.long ");
+      assemble_name (file, buf);
+      fprintf (file, "\n");
+    }
+  else
+    {
+      fprintf (file, "\t.tc\t");
+      assemble_name (file, buf);
+      fprintf (file, "[TC],");
+      assemble_name (file, buf);
+      fprintf (file, "\n");
+    }
   text_section ();
 
   /* Figure out last used parameter register.  The proper thing to do is
@@ -1948,10 +2063,47 @@ output_function_profiler (file, labelno)
 
   /* Load location address into r3, and call mcount.  */
 
-  fprintf (file, "\tl 3,LPC..%d(2)\n\tbl .mcount\n", labelno);
+  ASM_GENERATE_INTERNAL_LABEL (buf, "LPC", labelno);
+  fprintf (file, "\tl 3,");
+  assemble_name (file, buf);
+  fprintf (file, "(2)\n\tbl .mcount\n");
 
   /* Restore parameter registers.  */
 
   for (i = 3, j = 30; i <= last_parm_reg; i++, j--)
     fprintf (file, "\tai %d,%d,0\n", i, j);
 }
+
+/* Adjust the cost of a scheduling dependency.  Return the new cost of
+   a dependency LINK or INSN on DEP_INSN.  COST is the current cost.  */
+
+int
+rs6000_adjust_cost (insn, link, dep_insn, cost)
+     rtx insn;
+     rtx link;
+     rtx dep_insn;
+     int cost;
+{
+  if (! recog_memoized (insn))
+    return 0;
+
+  if (REG_NOTE_KIND (link) != 0)
+    return 0;
+
+  if (REG_NOTE_KIND (link) == 0)
+    {
+      /* Data dependency; DEP_INSN writes a register that INSN reads some
+        cycles later.  */
+
+      /* Tell the first scheduling pass about the latency between a mtctr
+        and bctr (and mtlr and br/blr).  The first scheduling pass will not
+        know about this latency since the mtctr instruction, which has the
+        latency associated to it, will be generated by reload.  */
+      if (get_attr_type (insn) == TYPE_JMPREG)
+       return TARGET_POWER ? 5 : 4;
+
+      /* Fall out to return default cost.  */
+    }
+
+  return cost;
+}
This page took 0.049539 seconds and 5 git commands to generate.