OSDN Git Service

* config/alpha/alpha.c: Include libfuncs.h
[pf3gnuchains/gcc-fork.git] / gcc / config / alpha / alpha.c
index fe515d4..0bf5294 100644 (file)
@@ -57,6 +57,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "tree-stdarg.h"
 #include "tm-constrs.h"
 #include "df.h"
+#include "libfuncs.h"
 
 /* Specify which cpu to schedule for.  */
 enum processor_type alpha_tune;
@@ -4779,6 +4780,9 @@ struct GTY(()) machine_function
 
   /* For TARGET_LD_BUGGY_LDGP.  */
   struct rtx_def *gp_save_rtx;
+
+  /* For VMS condition handlers.  */
+  bool uses_condition_handler;  
 };
 
 /* How to allocate a 'struct machine_function'.  */
@@ -4790,6 +4794,63 @@ alpha_init_machine_status (void)
                ggc_alloc_cleared (sizeof (struct machine_function)));
 }
 
+/* Support for frame based VMS condition handlers.  */
+
+/* A VMS condition handler may be established for a function with a call to
+   __builtin_establish_vms_condition_handler, and cancelled with a call to
+   __builtin_revert_vms_condition_handler.
+
+   The VMS Condition Handling Facility knows about the existence of a handler
+   from the procedure descriptor .handler field.  As the VMS native compilers,
+   we store the user specified handler's address at a fixed location in the
+   stack frame and point the procedure descriptor at a common wrapper which
+   fetches the real handler's address and issues an indirect call.
+
+   The indirection wrapper is "__gcc_shell_handler", provided by libgcc.
+
+   We force the procedure kind to PT_STACK, and the fixed frame location is
+   fp+8, just before the register save area. We use the handler_data field in
+   the procedure descriptor to state the fp offset at which the installed
+   handler address can be found.  */
+
+#define VMS_COND_HANDLER_FP_OFFSET 8
+
+/* Expand code to store the currently installed user VMS condition handler
+   into TARGET and install HANDLER as the new condition handler.  */
+
+void
+alpha_expand_builtin_establish_vms_condition_handler (rtx target, rtx handler)
+{
+  rtx handler_slot_address
+    = plus_constant (hard_frame_pointer_rtx, VMS_COND_HANDLER_FP_OFFSET);
+
+  rtx handler_slot
+    = gen_rtx_MEM (DImode, handler_slot_address);
+
+  emit_move_insn (target, handler_slot);
+  emit_move_insn (handler_slot, handler);
+
+  /* Notify the start/prologue/epilogue emitters that the condition handler
+     slot is needed.  In addition to reserving the slot space, this will force
+     the procedure kind to PT_STACK so ensure that the hard_frame_pointer_rtx
+     use above is correct.  */
+  cfun->machine->uses_condition_handler = true;
+}
+
+/* Expand code to store the current VMS condition handler into TARGET and
+   nullify it.  */
+
+void
+alpha_expand_builtin_revert_vms_condition_handler (rtx target)
+{
+  /* We implement this by establishing a null condition handler, with the tiny
+     side effect of setting uses_condition_handler.  This is a little bit
+     pessimistic if no actual builtin_establish call is ever issued, which is
+     not a real problem and expected never to happen anyway.  */
+
+  alpha_expand_builtin_establish_vms_condition_handler (target, const0_rtx);
+}
+
 /* Functions to save and restore alpha_return_addr_rtx.  */
 
 /* Start the ball rolling with RETURN_ADDR_RTX.  */
@@ -5491,6 +5552,35 @@ alpha_initialize_trampoline (rtx tramp, rtx fnaddr, rtx cxt,
   cxt = convert_memory_address (mode, cxt);
 #endif
 
+  if (TARGET_ABI_OPEN_VMS)
+    {
+      rtx temp1, traddr;
+      const char *fnname;
+      char *trname;
+
+      /* Construct the name of the trampoline entry point.  */
+      fnname = XSTR (fnaddr, 0);
+      trname = (char *) alloca (strlen (fnname) + 5);
+      strcpy (trname, fnname);
+      strcat (trname, "..tr");
+      traddr = gen_rtx_SYMBOL_REF
+       (mode, ggc_alloc_string (trname, strlen (trname) + 1));
+
+      /* Trampoline (or "bounded") procedure descriptor is constructed from
+        the function's procedure descriptor with certain fields zeroed IAW
+        the VMS calling standard. This is stored in the first quadword.  */
+      temp1 = force_reg (DImode, gen_rtx_MEM (DImode, fnaddr));
+      temp1 = expand_and (DImode, temp1,
+                         GEN_INT (0xffff0fff0000fff0), NULL_RTX);
+      addr = memory_address (mode, plus_constant (tramp, 0));
+      emit_move_insn (gen_rtx_MEM (DImode, addr), temp1);
+
+      /* Trampoline transfer address is stored in the second quadword
+        of the trampoline.  */
+      addr = memory_address (mode, plus_constant (tramp, 8));
+      emit_move_insn (gen_rtx_MEM (mode, addr), traddr);
+    }
+
   /* Store function address and CXT.  */
   addr = memory_address (mode, plus_constant (tramp, fnofs));
   emit_move_insn (gen_rtx_MEM (mode, addr), fnaddr);
@@ -6351,6 +6441,8 @@ enum alpha_builtin
   ALPHA_BUILTIN_RPCC,
   ALPHA_BUILTIN_THREAD_POINTER,
   ALPHA_BUILTIN_SET_THREAD_POINTER,
+  ALPHA_BUILTIN_ESTABLISH_VMS_CONDITION_HANDLER,
+  ALPHA_BUILTIN_REVERT_VMS_CONDITION_HANDLER,
 
   /* TARGET_MAX */
   ALPHA_BUILTIN_MINUB8,
@@ -6406,6 +6498,8 @@ static enum insn_code const code_for_builtin[ALPHA_BUILTIN_max] = {
   CODE_FOR_builtin_rpcc,
   CODE_FOR_load_tp,
   CODE_FOR_set_tp,
+  CODE_FOR_builtin_establish_vms_condition_handler,
+  CODE_FOR_builtin_revert_vms_condition_handler,
 
   /* TARGET_MAX */
   CODE_FOR_builtin_minub8,
@@ -6551,6 +6645,21 @@ alpha_init_builtins (void)
                               NULL, NULL);
   TREE_NOTHROW (decl) = 1;
 
+  if (TARGET_ABI_OPEN_VMS)
+    {
+      ftype = build_function_type_list (ptr_type_node, ptr_type_node,
+                                       NULL_TREE);
+      add_builtin_function ("__builtin_establish_vms_condition_handler", ftype,
+                           ALPHA_BUILTIN_ESTABLISH_VMS_CONDITION_HANDLER,
+                           BUILT_IN_MD, NULL, NULL_TREE);
+
+      ftype = build_function_type_list (ptr_type_node, void_type_node,
+                                       NULL_TREE);
+      add_builtin_function ("__builtin_revert_vms_condition_handler", ftype,
+                           ALPHA_BUILTIN_REVERT_VMS_CONDITION_HANDLER,
+                            BUILT_IN_MD, NULL, NULL_TREE);
+    }
+
   alpha_v8qi_u = build_vector_type (unsigned_intQI_type_node, 8);
   alpha_v8qi_s = build_vector_type (intQI_type_node, 8);
   alpha_v4hi_u = build_vector_type (unsigned_intHI_type_node, 4);
@@ -7280,7 +7389,10 @@ alpha_sa_size (void)
          if (! fixed_regs[i] && call_used_regs[i] && ! df_regs_ever_live_p (i))
            vms_save_fp_regno = i;
 
-      if (vms_save_fp_regno == -1 && alpha_procedure_type == PT_REGISTER)
+      /* A VMS condition handler requires a stack procedure in our
+        implementation. (not required by the calling standard).  */
+      if ((vms_save_fp_regno == -1 && alpha_procedure_type == PT_REGISTER)
+         || cfun->machine->uses_condition_handler)
        vms_base_regno = REG_PV, alpha_procedure_type = PT_STACK;
       else if (alpha_procedure_type == PT_NULL)
        vms_base_regno = REG_PV;
@@ -7289,9 +7401,10 @@ alpha_sa_size (void)
       vms_unwind_regno = (vms_base_regno == REG_PV
                          ? HARD_FRAME_POINTER_REGNUM : STACK_POINTER_REGNUM);
 
-      /* If this is a stack procedure, allow space for saving FP and RA.  */
+      /* If this is a stack procedure, allow space for saving FP, RA and
+        a condition handler slot if needed.  */
       if (alpha_procedure_type == PT_STACK)
-       sa_size += 2;
+       sa_size += 2 + cfun->machine->uses_condition_handler;
     }
   else
     {
@@ -7543,7 +7656,7 @@ alpha_expand_prologue (void)
                                 + crtl->args.pretend_args_size));
 
   if (TARGET_ABI_OPEN_VMS)
-    reg_offset = 8;
+    reg_offset = 8 + 8 * cfun->machine->uses_condition_handler;
   else
     reg_offset = ALPHA_ROUND (crtl->outgoing_args_size);
 
@@ -7838,6 +7951,7 @@ alpha_start_function (FILE *file, const char *fnname,
   /* Offset from base reg to register save area.  */
   HOST_WIDE_INT reg_offset;
   char *entry_label = (char *) alloca (strlen (fnname) + 6);
+  char *tramp_label = (char *) alloca (strlen (fnname) + 6);
   int i;
 
   /* Don't emit an extern directive for functions defined in the same file.  */
@@ -7880,7 +7994,7 @@ alpha_start_function (FILE *file, const char *fnname,
                                 + crtl->args.pretend_args_size));
 
   if (TARGET_ABI_OPEN_VMS)
-    reg_offset = 8;
+    reg_offset = 8 + 8 * cfun->machine->uses_condition_handler;
   else
     reg_offset = ALPHA_ROUND (crtl->outgoing_args_size);
 
@@ -7926,6 +8040,20 @@ alpha_start_function (FILE *file, const char *fnname,
          fputs ("..ng:\n", file);
        }
     }
+  /* Nested functions on VMS that are potentially called via trampoline
+     get a special transfer entry point that loads the called functions
+     procedure descriptor and static chain.  */
+   if (TARGET_ABI_OPEN_VMS
+       && !TREE_PUBLIC (decl)
+       && DECL_CONTEXT (decl)
+       && !TYPE_P (DECL_CONTEXT (decl)))
+     {
+       strcpy (tramp_label, fnname);
+       strcat (tramp_label, "..tr");
+       ASM_OUTPUT_LABEL (file, tramp_label);
+       fprintf (file, "\tldq $1,24($27)\n");
+       fprintf (file, "\tldq $27,16($27)\n");
+     }
 
   strcpy (entry_label, fnname);
   if (TARGET_ABI_OPEN_VMS)
@@ -8005,6 +8133,16 @@ alpha_start_function (FILE *file, const char *fnname,
     }
 
 #if TARGET_ABI_OPEN_VMS
+  /* If a user condition handler has been installed at some point, emit
+     the procedure descriptor bits to point the Condition Handling Facility
+     at the indirection wrapper, and state the fp offset at which the user
+     handler may be found.  */
+  if (cfun->machine->uses_condition_handler)
+    {
+      fprintf (file, "\t.handler __gcc_shell_handler\n");
+      fprintf (file, "\t.handler_data %d\n", VMS_COND_HANDLER_FP_OFFSET);
+    }
+
   /* Ifdef'ed cause link_section are only available then.  */
   switch_to_section (readonly_data_section);
   fprintf (file, "\t.align 3\n");
@@ -8076,7 +8214,7 @@ alpha_expand_epilogue (void)
   if (TARGET_ABI_OPEN_VMS)
     {
        if (alpha_procedure_type == PT_STACK)
-          reg_offset = 8;
+          reg_offset = 8 + 8 * cfun->machine->uses_condition_handler;
        else
           reg_offset = 0;
     }
@@ -8357,6 +8495,15 @@ alpha_end_function (FILE *file, const char *fnname, tree decl ATTRIBUTE_UNUSED)
     }
 }
 
+#if TARGET_ABI_OPEN_VMS
+void avms_asm_output_external (FILE *file, tree decl ATTRIBUTE_UNUSED, const char *name)
+{
+#ifdef DO_CRTL_NAMES
+  DO_CRTL_NAMES;
+#endif
+}
+#endif
+
 #if TARGET_ABI_OSF
 /* Emit a tail call to FUNCTION after adjusting THIS by DELTA.
 
@@ -9539,6 +9686,7 @@ enum reloc_kind {KIND_LINKAGE, KIND_CODEADDR};
 struct GTY(()) alpha_links
 {
   int num;
+  const char *target;
   rtx linkage;
   enum links_kind lkind;
   enum reloc_kind rkind;
@@ -9591,17 +9739,17 @@ alpha_arg_info_reg_val (CUMULATIVE_ARGS cum)
   return GEN_INT (regval);
 }
 \f
-/* Make (or fake) .linkage entry for function call.
-
-   IS_LOCAL is 0 if name is used in call, 1 if name is used in definition.
-
-   Return an SYMBOL_REF rtx for the linkage.  */
+/* Register the need for a (fake) .linkage entry for calls to function NAME.
+   IS_LOCAL is 1 if this is for a definition, 0 if this is for a real call.
+   Return a SYMBOL_REF suited to the call instruction.  */
 
 rtx
 alpha_need_linkage (const char *name, int is_local)
 {
   splay_tree_node node;
   struct alpha_links *al;
+  const char *target;
+  tree id;
 
   if (name[0] == '*')
     name++;
@@ -9656,19 +9804,18 @@ alpha_need_linkage (const char *name, int is_local)
   /* Assume external if no definition.  */
   al->lkind = (is_local ? KIND_UNUSED : KIND_EXTERN);
 
-  /* Ensure we have an IDENTIFIER so assemble_name can mark it used.  */
-  get_identifier (name);
+  /* Ensure we have an IDENTIFIER so assemble_name can mark it used
+     and find the ultimate alias target like assemble_name.  */
+  id = get_identifier (name);
+  target = NULL;
+  while (IDENTIFIER_TRANSPARENT_ALIAS (id))
+    {
+      id = TREE_CHAIN (id);
+      target = IDENTIFIER_POINTER (id);
+    }
 
-  /* Construct a SYMBOL_REF for us to call.  */
-  {
-    size_t name_len = strlen (name);
-    char *linksym = XALLOCAVEC (char, name_len + 6);
-    linksym[0] = '$';
-    memcpy (linksym + 1, name, name_len);
-    memcpy (linksym + 1 + name_len, "..lk", 5);
-    al->linkage = gen_rtx_SYMBOL_REF (Pmode,
-                                     ggc_alloc_string (linksym, name_len + 5));
-  }
+  al->target = target ? target : name;
+  al->linkage = gen_rtx_SYMBOL_REF (Pmode, name);
 
   splay_tree_insert (alpha_links_tree, (splay_tree_key) name,
                     (splay_tree_value) al);
@@ -9676,13 +9823,19 @@ alpha_need_linkage (const char *name, int is_local)
   return al->linkage;
 }
 
+/* Return a SYMBOL_REF representing the reference to the .linkage entry
+   of function FUNC built for calls made from CFUNDECL.  LFLAG is 1 if
+   this is the reference to the linkage pointer value, 0 if this is the
+   reference to the function entry value.  RFLAG is 1 if this a reduced
+   reference (code address only), 0 if this is a full reference.  */
+
 rtx
-alpha_use_linkage (rtx linkage, tree cfundecl, int lflag, int rflag)
+alpha_use_linkage (rtx func, tree cfundecl, int lflag, int rflag)
 {
   splay_tree_node cfunnode;
   struct alpha_funcs *cfaf;
   struct alpha_links *al;
-  const char *name = XSTR (linkage, 0);
+  const char *name = XSTR (func, 0);
 
   cfaf = (struct alpha_funcs *) 0;
   al = (struct alpha_links *) 0;
@@ -9707,7 +9860,6 @@ alpha_use_linkage (rtx linkage, tree cfundecl, int lflag, int rflag)
     {
       size_t name_len;
       size_t buflen;
-      char buf [512];
       char *linksym;
       splay_tree_node node = 0;
       struct alpha_links *anl;
@@ -9716,6 +9868,7 @@ alpha_use_linkage (rtx linkage, tree cfundecl, int lflag, int rflag)
        name++;
 
       name_len = strlen (name);
+      linksym = (char *) alloca (name_len + 50);
 
       al = (struct alpha_links *) ggc_alloc (sizeof (struct alpha_links));
       al->num = cfaf->num;
@@ -9725,12 +9878,11 @@ alpha_use_linkage (rtx linkage, tree cfundecl, int lflag, int rflag)
        {
          anl = (struct alpha_links *) node->value;
          al->lkind = anl->lkind;
+         name = anl->target;
        }
 
-      sprintf (buf, "$%d..%s..lk", cfaf->num, name);
-      buflen = strlen (buf);
-      linksym = XALLOCAVEC (char, buflen + 1);
-      memcpy (linksym, buf, buflen + 1);
+      sprintf (linksym, "$%d..%s..lk", cfaf->num, name);
+      buflen = strlen (linksym);
 
       al->linkage = gen_rtx_SYMBOL_REF
        (Pmode, ggc_alloc_string (linksym, buflen + 1));
@@ -9900,7 +10052,7 @@ alpha_need_linkage (const char *name ATTRIBUTE_UNUSED,
 }
 
 rtx
-alpha_use_linkage (rtx linkage ATTRIBUTE_UNUSED,
+alpha_use_linkage (rtx func ATTRIBUTE_UNUSED,
                   tree cfundecl ATTRIBUTE_UNUSED,
                   int lflag ATTRIBUTE_UNUSED,
                   int rflag ATTRIBUTE_UNUSED)
@@ -10711,6 +10863,11 @@ alpha_init_libfuncs (void)
       set_optab_libfunc (smod_optab, DImode, "OTS$REM_L");
       set_optab_libfunc (umod_optab, SImode, "OTS$REM_UI");
       set_optab_libfunc (umod_optab, DImode, "OTS$REM_UL");
+      abort_libfunc = init_one_libfunc ("decc$abort");
+      memcmp_libfunc = init_one_libfunc ("decc$memcmp");
+#ifdef MEM_LIBFUNCS_INIT
+      MEM_LIBFUNCS_INIT;
+#endif
     }
 }
 
@@ -10748,7 +10905,7 @@ alpha_init_libfuncs (void)
 
 /* Default unaligned ops are provided for ELF systems.  To get unaligned
    data for non-ELF systems, we have to turn off auto alignment.  */
-#ifndef OBJECT_FORMAT_ELF
+#if !defined (OBJECT_FORMAT_ELF) || TARGET_ABI_OPEN_VMS
 #undef TARGET_ASM_UNALIGNED_HI_OP
 #define TARGET_ASM_UNALIGNED_HI_OP "\t.align 0\n\t.word\t"
 #undef TARGET_ASM_UNALIGNED_SI_OP