OSDN Git Service

* pa.c (pa_asm_output_aligned_bss, pa_asm_output_aligned_common,
[pf3gnuchains/gcc-fork.git] / gcc / config / pa / pa.c
index da065ce..63eee3b 100644 (file)
@@ -48,9 +48,6 @@ Boston, MA 02111-1307, USA.  */
 #include "target.h"
 #include "target-def.h"
 
-#undef TARGET_SCHED_USE_DFA_PIPELINE_INTERFACE 
-#define TARGET_SCHED_USE_DFA_PIPELINE_INTERFACE hook_int_void_1
-
 /* Return nonzero if there is a bypass for the output of 
    OUT_INSN and the fp store IN_INSN.  */
 int
@@ -86,6 +83,7 @@ hppa_fpstore_bypass_p (rtx out_insn, rtx in_insn)
 #endif
 
 static void copy_reg_pointer (rtx, rtx);
+static void fix_range (const char *);
 static int hppa_address_cost (rtx);
 static bool hppa_rtx_costs (rtx, int, int, int *);
 static inline rtx force_mode (enum machine_mode, rtx);
@@ -143,24 +141,31 @@ static void output_deferred_plabels (void);
 static void pa_hpux_init_libfuncs (void);
 #endif
 static rtx pa_struct_value_rtx (tree, int);
+static bool pa_pass_by_reference (CUMULATIVE_ARGS *ca, enum machine_mode,
+                                 tree, bool);
+static struct machine_function * pa_init_machine_status (void);
+
 
 /* Save the operands last given to a compare for use when we
    generate a scc or bcc insn.  */
 rtx hppa_compare_op0, hppa_compare_op1;
 enum cmp_type hppa_branch_type;
 
-/* Which cpu we are scheduling for.  */
-enum processor_type pa_cpu;
-
-/* String to hold which cpu we are scheduling for.  */
-const char *pa_cpu_string;
-
 /* Which architecture we are generating code for.  */
 enum architecture_type pa_arch;
 
 /* String to hold which architecture we are generating code for.  */
 const char *pa_arch_string;
 
+/* String used with the -mfixed-range= option.  */
+const char *pa_fixed_range_string;
+
+/* Which cpu we are scheduling for.  */
+enum processor_type pa_cpu;
+
+/* String to hold which cpu we are scheduling for.  */
+const char *pa_cpu_string;
+
 /* Counts for the number of callee-saved general and floating point
    registers which were saved by the current function's prologue.  */
 static int gr_saved, fr_saved;
@@ -265,6 +270,10 @@ static size_t n_deferred_plabels = 0;
 #define TARGET_STRUCT_VALUE_RTX pa_struct_value_rtx
 #undef TARGET_RETURN_IN_MEMORY
 #define TARGET_RETURN_IN_MEMORY pa_return_in_memory
+#undef TARGET_MUST_PASS_IN_STACK
+#define TARGET_MUST_PASS_IN_STACK must_pass_in_stack_var_size
+#undef TARGET_PASS_BY_REFERENCE
+#define TARGET_PASS_BY_REFERENCE pa_pass_by_reference
 
 #undef TARGET_EXPAND_BUILTIN_SAVEREGS
 #define TARGET_EXPAND_BUILTIN_SAVEREGS hppa_builtin_saveregs
@@ -273,6 +282,79 @@ static size_t n_deferred_plabels = 0;
 
 struct gcc_target targetm = TARGET_INITIALIZER;
 \f
+/* Parse the -mfixed-range= option string.  */
+
+static void
+fix_range (const char *const_str)
+{
+  int i, first, last;
+  char *str, *dash, *comma;
+
+  /* str must be of the form REG1'-'REG2{,REG1'-'REG} where REG1 and
+     REG2 are either register names or register numbers.  The effect
+     of this option is to mark the registers in the range from REG1 to
+     REG2 as ``fixed'' so they won't be used by the compiler.  This is
+     used, e.g., to ensure that kernel mode code doesn't use f32-f127.  */
+
+  i = strlen (const_str);
+  str = (char *) alloca (i + 1);
+  memcpy (str, const_str, i + 1);
+
+  while (1)
+    {
+      dash = strchr (str, '-');
+      if (!dash)
+       {
+         warning ("value of -mfixed-range must have form REG1-REG2");
+         return;
+       }
+      *dash = '\0';
+
+      comma = strchr (dash + 1, ',');
+      if (comma)
+       *comma = '\0';
+
+      first = decode_reg_name (str);
+      if (first < 0)
+       {
+         warning ("unknown register name: %s", str);
+         return;
+       }
+
+      last = decode_reg_name (dash + 1);
+      if (last < 0)
+       {
+         warning ("unknown register name: %s", dash + 1);
+         return;
+       }
+
+      *dash = '-';
+
+      if (first > last)
+       {
+         warning ("%s-%s is an empty range", str, dash + 1);
+         return;
+       }
+
+      for (i = first; i <= last; ++i)
+       fixed_regs[i] = call_used_regs[i] = 1;
+
+      if (!comma)
+       break;
+
+      *comma = ',';
+      str = comma + 1;
+    }
+
+  /* Check if all floating point registers have been fixed.  */
+  for (i = FP_REG_FIRST; i <= FP_REG_LAST; i++)
+    if (!fixed_regs[i])
+      break;
+
+  if (i > FP_REG_LAST)
+    target_flags |= MASK_DISABLE_FPREGS;
+}
+
 void
 override_options (void)
 {
@@ -314,7 +396,7 @@ override_options (void)
       warning ("unknown -mschedule= option (%s).\nValid options are 700, 7100, 7100LC, 7200, 7300, and 8000\n", pa_cpu_string);
     }
 
-  /* Set the instruction set architecture.  */
+  /* Set the instruction architecture.  */
   if (pa_arch_string && ! strcmp (pa_arch_string, "1.0"))
     {
       pa_arch_string = "1.0";
@@ -339,6 +421,9 @@ override_options (void)
       warning ("unknown -march= option (%s).\nValid options are 1.0, 1.1, and 2.0\n", pa_arch_string);
     }
 
+  if (pa_fixed_range_string)
+    fix_range (pa_fixed_range_string);
+
   /* Unconditional branches in the delay slot are not compatible with dwarf2
      call frame information.  There is no benefit in using this optimization
      on PA8000 and later processors.  */
@@ -380,6 +465,8 @@ override_options (void)
       targetm.asm_out.unaligned_op.si = NULL;
       targetm.asm_out.unaligned_op.di = NULL;
     }
+
+  init_machine_status = pa_init_machine_status;
 }
 
 static void
@@ -391,6 +478,16 @@ pa_init_builtins (void)
 #endif
 }
 
+/* Function to init struct machine_function.
+   This will be called, via a pointer variable,
+   from push_function_context.  */
+
+static struct machine_function *
+pa_init_machine_status (void)
+{
+  return ggc_alloc_cleared (sizeof (machine_function));
+}
+
 /* If FROM is a probable pointer register, mark TO as a probable
    pointer register with the same pointer alignment as FROM.  */
 
@@ -4126,6 +4223,14 @@ pa_output_function_epilogue (FILE *file, HOST_WIDE_INT size ATTRIBUTE_UNUSED)
 
   fputs ("\t.EXIT\n\t.PROCEND\n", file);
 
+  if (TARGET_SOM && TARGET_GAS)
+    {
+      /* We done with this subspace except possibly for some additional
+        debug information.  Forget that we are in this subspace to ensure
+        that the next function is output in its own subspace.  */
+      forget_section ();
+    }
+
   if (INSN_ADDRESSES_SET_P ())
     {
       insn = get_last_nonnote_insn ();
@@ -5836,6 +5941,37 @@ secondary_reload_class (enum reg_class class, enum machine_mode mode, rtx in)
   return NO_REGS;
 }
 
+/* In the 32-bit runtime, arguments larger than eight bytes are passed
+   by invisible reference.  As a GCC extension, we also pass anything
+   with a zero or variable size by reference.
+
+   The 64-bit runtime does not describe passing any types by invisible
+   reference.  The internals of GCC can't currently handle passing
+   empty structures, and zero or variable length arrays when they are
+   not passed entirely on the stack or by reference.  Thus, as a GCC
+   extension, we pass these types by reference.  The HP compiler doesn't
+   support these types, so hopefully there shouldn't be any compatibility
+   issues.  This may have to be revisited when HP releases a C99 compiler
+   or updates the ABI.  */
+
+static bool
+pa_pass_by_reference (CUMULATIVE_ARGS *ca ATTRIBUTE_UNUSED,
+                     enum machine_mode mode, tree type,
+                     bool named ATTRIBUTE_UNUSED)
+{
+  HOST_WIDE_INT size;
+
+  if (type)
+    size = int_size_in_bytes (type);
+  else
+    size = GET_MODE_SIZE (mode);
+
+  if (TARGET_64BIT)
+    return size <= 0;
+  else
+    return size <= 0 || size > 8;
+}
+
 enum direction
 function_arg_padding (enum machine_mode mode, tree type)
 {
@@ -5954,26 +6090,10 @@ hppa_va_start (tree valist, rtx nextarg)
 static tree
 hppa_gimplify_va_arg_expr (tree valist, tree type, tree *pre_p, tree *post_p)
 {
-  bool indirect;
-
-  indirect = FUNCTION_ARG_PASS_BY_REFERENCE (dummy, TYPE_MODE (type), type, 0);
-
   if (TARGET_64BIT)
     {
-      /* Every argument in PA64 is supposed to be passed by value
-        (including large structs).  However, as a GCC extension, we
-        pass zero and variable sized arguments by reference.  Empty
-        structures are a GCC extension not supported by the HP
-        compilers.  Thus, passing them by reference isn't likely
-        to conflict with the ABI.  For variable sized arguments,
-        GCC doesn't have the infrastructure to allocate these to
-        registers.  */
       /* Args grow upward.  We can use the generic routines.  */
-
-      if (indirect)
-       return ind_gimplify_va_arg_expr (valist, type, pre_p, post_p);
-      else
-       return std_gimplify_va_arg_expr (valist, type, pre_p, post_p);
+      return std_gimplify_va_arg_expr (valist, type, pre_p, post_p);
     }
   else /* !TARGET_64BIT */
     {
@@ -5981,7 +6101,9 @@ hppa_gimplify_va_arg_expr (tree valist, tree type, tree *pre_p, tree *post_p)
       tree valist_type;
       tree t, u;
       unsigned int size, ofs;
+      bool indirect;
 
+      indirect = pass_by_reference (NULL, TYPE_MODE (type), type, 0);
       if (indirect)
        {
          type = ptr;
@@ -6829,7 +6951,7 @@ output_movb (rtx *operands, rtx insn, int which_alternative,
       if (get_attr_length (insn) == 8)
        return "{comb|cmpb},%S2 %%r0,%1,%3\n\tmtsar %r1";
       else
-       return "{comclr|cmpclr},%B2 %%r0,%1,%%r0\n\tbl %3\n\tmtsar %r1";
+       return "{comclr|cmpclr},%B2 %%r0,%1,%%r0\n\tb %3\n\tmtsar %r1";
     }
 }
 
@@ -7545,7 +7667,15 @@ output_indirect_call (rtx insn, rtx call_dest)
      No need to check target flags as the length uniquely identifies
      the remaining cases.  */
   if (attr_length_indirect_call (insn) == 8)
-    return ".CALL\tARGW0=GR\n\t{bl|b,l} $$dyncall,%%r2\n\tcopy %%r2,%%r31";
+    {
+      /* The HP linker substitutes a BLE for millicode calls using
+        the short PIC PCREL form.  Thus, we must use %r31 as the
+        link register when generating PA 1.x code.  */
+      if (TARGET_PA_20)
+       return ".CALL\tARGW0=GR\n\tb,l $$dyncall,%%r2\n\tcopy %%r2,%%r31";
+      else
+       return ".CALL\tARGW0=GR\n\tbl $$dyncall,%%r31\n\tcopy %%r31,%%r2";
+    }
 
   /* Long millicode call, but we are not generating PIC or portable runtime
      code.  */
@@ -7886,8 +8016,9 @@ pa_asm_output_mi_thunk (FILE *file, tree thunk_fndecl, HOST_WIDE_INT delta,
       fprintf (file, "\t.align 4\n");
       ASM_OUTPUT_LABEL (file, label);
       fprintf (file, "\t.word P'%s\n", fname);
-      function_section (thunk_fndecl);
     }
+  else if (TARGET_SOM && TARGET_GAS)
+    forget_section ();
 
   current_thunk_number++;
   nbytes = ((nbytes + FUNCTION_BOUNDARY / BITS_PER_UNIT - 1)
@@ -8038,6 +8169,79 @@ pa_asm_out_destructor (rtx symbol, int priority)
 }
 #endif
 
+/* This function places uninitialized global data in the bss section.
+   The ASM_OUTPUT_ALIGNED_BSS macro needs to be defined to call this
+   function on the SOM port to prevent uninitialized global data from
+   being placed in the data section.  */
+   
+void
+pa_asm_output_aligned_bss (FILE *stream,
+                          const char *name,
+                          unsigned HOST_WIDE_INT size,
+                          unsigned int align)
+{
+  bss_section ();
+  fprintf (stream, "\t.align %u\n", align / BITS_PER_UNIT);
+
+#ifdef ASM_OUTPUT_TYPE_DIRECTIVE
+  ASM_OUTPUT_TYPE_DIRECTIVE (stream, name, "object");
+#endif
+
+#ifdef ASM_OUTPUT_SIZE_DIRECTIVE
+  ASM_OUTPUT_SIZE_DIRECTIVE (stream, name, size);
+#endif
+
+  fprintf (stream, "\t.align %u\n", align / BITS_PER_UNIT);
+  ASM_OUTPUT_LABEL (stream, name);
+  fprintf (stream, "\t.block "HOST_WIDE_INT_PRINT_UNSIGNED"\n", size);
+}
+
+/* Both the HP and GNU assemblers under HP-UX provide a .comm directive
+   that doesn't allow the alignment of global common storage to be directly
+   specified.  The SOM linker aligns common storage based on the rounded
+   value of the NUM_BYTES parameter in the .comm directive.  It's not
+   possible to use the .align directive as it doesn't affect the alignment
+   of the label associated with a .comm directive.  */
+
+void
+pa_asm_output_aligned_common (FILE *stream,
+                             const char *name,
+                             unsigned HOST_WIDE_INT size,
+                             unsigned int align)
+{
+  bss_section ();
+
+  assemble_name (stream, name);
+  fprintf (stream, "\t.comm "HOST_WIDE_INT_PRINT_UNSIGNED"\n",
+           MAX (size, align / BITS_PER_UNIT));
+}
+
+/* We can't use .comm for local common storage as the SOM linker effectively
+   treats the symbol as universal and uses the same storage for local symbols
+   with the same name in different object files.  The .block directive
+   reserves an uninitialized block of storage.  However, it's not common
+   storage.  Fortunately, GCC never requests common storage with the same
+   name in any given translation unit.  */
+
+void
+pa_asm_output_aligned_local (FILE *stream,
+                            const char *name,
+                            unsigned HOST_WIDE_INT size,
+                            unsigned int align)
+{
+  bss_section ();
+  fprintf (stream, "\t.align %u\n", align / BITS_PER_UNIT);
+
+#ifdef LOCAL_ASM_OP
+  fprintf (stream, "%s", LOCAL_ASM_OP);
+  assemble_name (stream, name);
+  fprintf (stream, "\n");
+#endif
+
+  ASM_OUTPUT_LABEL (stream, name);
+  fprintf (stream, "\t.block "HOST_WIDE_INT_PRINT_UNSIGNED"\n", size);
+}
+
 /* Returns 1 if the 6 operands specified in OPERANDS are suitable for
    use in fmpysub instructions.  */
 int
@@ -8915,21 +9119,9 @@ function_arg (CUMULATIVE_ARGS *cum, enum machine_mode mode, tree type,
          /* Structures 5 to 8 bytes in size are passed in the general
             registers in the same manner as other non floating-point
             objects.  The data is right-justified and zero-extended
-            to 64 bits.
-
-            This is magic.  Normally, using a PARALLEL results in left
-            justified data on a big-endian target.  However, using a
-            single double-word register provides the required right
-            justification for 5 to 8 byte structures.  This has nothing
-            to do with the direction of padding specified for the argument.
-            It has to do with how the data is widened and shifted into
-            and from the register.
-
-            Aside from adding load_multiple and store_multiple patterns,
-            this is the only way that I have found to obtain right
-            justification of BLKmode data when it has a size greater
-            than one word.  Splitting the operation into two SImode loads
-            or returning a DImode REG results in left justified data.  */
+            to 64 bits.  This is opposite to the normal justification
+            used on big endian targets and requires special treatment.
+            We now define BLOCK_REG_PADDING to pad these objects.  */
          if (mode == BLKmode)
            {
              rtx loc = gen_rtx_EXPR_LIST (VOIDmode,
@@ -9047,6 +9239,58 @@ cmpib_comparison_operator (rtx op, enum machine_mode mode)
              || GET_CODE (op) == LEU));
 }
 
+#ifndef ONE_ONLY_TEXT_SECTION_ASM_OP
+#define ONE_ONLY_TEXT_SECTION_ASM_OP ""
+#endif
+
+#ifndef NEW_TEXT_SECTION_ASM_OP
+#define NEW_TEXT_SECTION_ASM_OP ""
+#endif
+
+#ifndef DEFAULT_TEXT_SECTION_ASM_OP
+#define DEFAULT_TEXT_SECTION_ASM_OP ""
+#endif
+
+/* Select and return a TEXT_SECTION_ASM_OP for the current function.
+
+   This function is only used with SOM.  Because we don't support
+   named subspaces, we can only create a new subspace or switch back
+   into the default text subspace.  */
+const char *
+som_text_section_asm_op (void)
+{
+  if (TARGET_SOM && TARGET_GAS)
+    {
+      if (cfun && !cfun->machine->in_nsubspa)
+       {
+         /* We only want to emit a .nsubspa directive once at the
+            start of the function.  */
+         cfun->machine->in_nsubspa = 1;
+
+         /* Create a new subspace for the text.  This provides
+            better stub placement and one-only functions.  */
+         if (cfun->decl
+             && DECL_ONE_ONLY (cfun->decl)
+             && !DECL_WEAK (cfun->decl))
+           return ONE_ONLY_TEXT_SECTION_ASM_OP;
+
+         return NEW_TEXT_SECTION_ASM_OP;
+       }
+      else
+       {
+         /* There isn't a current function or the body of the current
+            function has been completed.  So, we are changing to the
+            text section to output debugging information.  Do this in
+            the default text section.  We need to forget that we are
+            in the text section so that text_section will call us the
+            next time around.  */
+         forget_section ();
+       }
+    }
+
+  return DEFAULT_TEXT_SECTION_ASM_OP;
+}
+
 /* On hpux10, the linker will give an error if we have a reference
    in the read-only data section to a symbol defined in a shared
    library.  Therefore, expressions that might require a reloc can
@@ -9063,10 +9307,23 @@ pa_select_section (tree exp, int reloc,
       && (DECL_INITIAL (exp) == error_mark_node
           || TREE_CONSTANT (DECL_INITIAL (exp)))
       && !reloc)
-    readonly_data_section ();
+    {
+      if (TARGET_SOM
+         && DECL_ONE_ONLY (exp)
+         && !DECL_WEAK (exp))
+       one_only_readonly_data_section ();
+      else
+       readonly_data_section ();
+    }
   else if (TREE_CODE_CLASS (TREE_CODE (exp)) == 'c'
           && !reloc)
     readonly_data_section ();
+  else if (TARGET_SOM
+          && TREE_CODE (exp) == VAR_DECL
+          && DECL_ONE_ONLY (exp)
+          && !DECL_WEAK (exp)
+          && DECL_INITIAL (exp))
+    one_only_data_section ();
   else
     data_section ();
 }