OSDN Git Service

2004-07-19 Paolo Bonzini <bonzini@gnu.org>
[pf3gnuchains/gcc-fork.git] / gcc / config / pa / pa.c
index ccc8f28..bd8b0a4 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,30 @@ 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);
+
 
 /* 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 +269,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 +281,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 +395,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 +420,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.  */
@@ -5836,6 +5920,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,18 +6069,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)
     {
       /* 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 */
     {
@@ -5973,7 +6080,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;