alpha.c (current_function_is_thunk): Don't check current_function_is_thunk.
authorRichard Henderson <rth@redhat.com>
Mon, 4 Feb 2002 17:44:26 +0000 (09:44 -0800)
committerRichard Henderson <rth@gcc.gnu.org>
Mon, 4 Feb 2002 17:44:26 +0000 (09:44 -0800)
        * config/alpha/alpha.c (current_function_is_thunk): Don't check
        current_function_is_thunk.
        (alpha_sa_mask): Distinguish between current_function_is_thunk
        called from ASM_OUTPUT_MI_THUNK and not.
        (alpha_does_function_need_gp): Thunks always need gp.
        (alpha_start_function, alpha_output_function_end_prologue): Likewise.
        (alpha_output_mi_thunk_osf): New.
        * config/alpha/alpha-protos.h: Update.
        * config/alpha/alpha.h (ASM_OUTPUT_MI_THUNK): New.

cp/
        * method.c (use_thunk): Always initialize the block tree.  Reindent.
        * semantics.c (expand_body): Emit thunks after function, not before.

From-SVN: r49484

gcc/ChangeLog
gcc/config/alpha/alpha-protos.h
gcc/config/alpha/alpha.c
gcc/config/alpha/alpha.h
gcc/cp/ChangeLog
gcc/cp/method.c
gcc/cp/semantics.c

index 102e0abf8ebb0b232cc4a8002f2f6dc430f63992..919a4081be80d5af355977f881fad046ebdc43bb 100644 (file)
@@ -1,3 +1,15 @@
+2002-02-04  Richard Henderson  <rth@redhat.com>
+
+       * config/alpha/alpha.c (current_function_is_thunk): Don't check
+       current_function_is_thunk.
+       (alpha_sa_mask): Distinguish between current_function_is_thunk
+       called from ASM_OUTPUT_MI_THUNK and not.
+       (alpha_does_function_need_gp): Thunks always need gp.
+       (alpha_start_function, alpha_output_function_end_prologue): Likewise.
+       (alpha_output_mi_thunk_osf): New.
+       * config/alpha/alpha-protos.h: Update.
+       * config/alpha/alpha.h (ASM_OUTPUT_MI_THUNK): New.
+
 2002-02-04  Richard Sandiford  <rsandifo@redhat.com>
 
        * c-typeck.c (build_c_cast): Warn when qualifiers are added to
index 2ff035092f2829d5f77f81349ff2e18ea728780c..957e5d9c7730d15435ec3fdefe86c05606438559 100644 (file)
@@ -163,6 +163,8 @@ extern rtx function_arg PARAMS ((CUMULATIVE_ARGS, enum machine_mode,
 #endif
 extern void alpha_start_function PARAMS ((FILE *, const char *, tree));
 extern void alpha_end_function PARAMS ((FILE *, const char *, tree));
+extern void alpha_output_mi_thunk_osf PARAMS ((FILE *, tree,
+                                              HOST_WIDE_INT, tree));
 extern void alpha_encode_section_info PARAMS ((tree));
 #endif /* TREE CODE */
 
index 0a1be015c3aaae48a177381fcf861ab312a558ff..9897077664fd025e7ebd5d335ad89c5e65da885f 100644 (file)
@@ -46,6 +46,7 @@ Boston, MA 02111-1307, USA.  */
 #include "tm_p.h"
 #include "target.h"
 #include "target-def.h"
+#include "debug.h"
 
 /* External data.  */
 extern int rtx_equal_function_value_matters;
@@ -4993,10 +4994,6 @@ alpha_ra_ever_killed ()
 {
   rtx top;
 
-#ifdef ASM_OUTPUT_MI_THUNK
-  if (current_function_is_thunk)
-    return 0;
-#endif
   if (!has_hard_reg_initial_val (Pmode, REG_RA))
     return regs_ever_live[REG_RA];
 
@@ -5859,43 +5856,48 @@ alpha_sa_mask (imaskP, fmaskP)
   unsigned long fmask = 0;
   unsigned int i;
 
-#ifdef ASM_OUTPUT_MI_THUNK
-  if (!current_function_is_thunk)
-#endif
+  /* Irritatingly, there are two kinds of thunks -- those created with
+     ASM_OUTPUT_MI_THUNK and those with DECL_THUNK_P that go through
+     the regular part of the compiler.  In the ASM_OUTPUT_MI_THUNK case
+     we don't have valid register life info, but assemble_start_function
+     wants to output .frame and .mask directives.  */
+  if (current_function_is_thunk && rtx_equal_function_value_matters)
     {
-      if (TARGET_ABI_OPEN_VMS && alpha_is_stack_procedure)
-       imask |= (1L << HARD_FRAME_POINTER_REGNUM);
+      *imaskP = 0;
+      *fmaskP = 0;
+      return;
+    }
 
-      /* One for every register we have to save.  */
-      for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
-       if (! fixed_regs[i] && ! call_used_regs[i]
-           && regs_ever_live[i] && i != REG_RA
-           && (!TARGET_ABI_UNICOSMK || i != HARD_FRAME_POINTER_REGNUM))
-         {
-           if (i < 32)
-             imask |= (1L << i);
-           else
-             fmask |= (1L << (i - 32));
-         }
+  if (TARGET_ABI_OPEN_VMS && alpha_is_stack_procedure)
+    imask |= (1L << HARD_FRAME_POINTER_REGNUM);
 
-      /* We need to restore these for the handler.  */
-      if (current_function_calls_eh_return)
-       {
-         for (i = 0; ; ++i)
-           {
-             unsigned regno = EH_RETURN_DATA_REGNO (i);
-             if (regno == INVALID_REGNUM)
-               break;
-             imask |= 1L << regno;
-           }
-       }
+  /* One for every register we have to save.  */
+  for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
+    if (! fixed_regs[i] && ! call_used_regs[i]
+       && regs_ever_live[i] && i != REG_RA
+       && (!TARGET_ABI_UNICOSMK || i != HARD_FRAME_POINTER_REGNUM))
+      {
+       if (i < 32)
+         imask |= (1L << i);
+       else
+         fmask |= (1L << (i - 32));
+      }
+
+  /* We need to restore these for the handler.  */
+  if (current_function_calls_eh_return)
+    for (i = 0; ; ++i)
+      {
+       unsigned regno = EH_RETURN_DATA_REGNO (i);
+       if (regno == INVALID_REGNUM)
+         break;
+       imask |= 1L << regno;
+      }
      
-      /* If any register spilled, then spill the return address also.  */
-      /* ??? This is required by the Digital stack unwind specification
-        and isn't needed if we're doing Dwarf2 unwinding.  */
-      if (imask || fmask || alpha_ra_ever_killed ())
-       imask |= (1L << REG_RA);
-    }
+  /* If any register spilled, then spill the return address also.  */
+  /* ??? This is required by the Digital stack unwind specification
+     and isn't needed if we're doing Dwarf2 unwinding.  */
+  if (imask || fmask || alpha_ra_ever_killed ())
+    imask |= (1L << REG_RA);
 
   *imaskP = imask;
   *fmaskP = fmask;
@@ -6043,10 +6045,8 @@ alpha_does_function_need_gp ()
   if (TARGET_PROFILING_NEEDS_GP && current_function_profile)
     return 1;
 
-#ifdef ASM_OUTPUT_MI_THUNK
   if (current_function_is_thunk)
     return 1;
-#endif
 
   /* If we need a GP (we have a LDSYM insn or a CALL_INSN), load it first. 
      Even if we are a static function, we still need to do this in case
@@ -6512,7 +6512,9 @@ alpha_start_function (file, fnname, decl)
 
       /* If the function needs GP, we'll write the "..ng" label there.
         Otherwise, do it here.  */
-      if (TARGET_ABI_OSF && ! alpha_function_needs_gp)
+      if (TARGET_ABI_OSF
+          && ! alpha_function_needs_gp
+         && ! current_function_is_thunk)
        {
          putc ('$', file);
          assemble_name (file, fnname);
@@ -6646,7 +6648,8 @@ alpha_output_function_end_prologue (file)
   else if (TARGET_ABI_WINDOWS_NT)
     fputs ("\t.prologue 0\n", file);
   else if (!flag_inhibit_size_directive)
-    fprintf (file, "\t.prologue %d\n", alpha_function_needs_gp);
+    fprintf (file, "\t.prologue %d\n",
+            alpha_function_needs_gp || current_function_is_thunk);
 }
 
 /* Write function epilogue.  */
@@ -6946,6 +6949,76 @@ alpha_end_function (file, fnname, decl)
       unicosmk_output_deferred_case_vectors (file);
     }
 }
+
+/* Emit a tail call to FUNCTION after adjusting THIS by DELTA. 
+
+   In order to avoid the hordes of differences between generated code
+   with and without TARGET_EXPLICIT_RELOCS, and to avoid duplicating
+   lots of code loading up large constants, generate rtl and emit it
+   instead of going straight to text.
+
+   Not sure why this idea hasn't been explored before...  */
+
+void
+alpha_output_mi_thunk_osf (file, thunk_fndecl, delta, function)
+     FILE *file;
+     tree thunk_fndecl ATTRIBUTE_UNUSED;
+     HOST_WIDE_INT delta;
+     tree function;
+{
+  HOST_WIDE_INT hi, lo;
+  rtx this, insn, funexp;
+
+  /* We always require a valid GP.  */
+  emit_insn (gen_prologue_ldgp ());
+  emit_note (NULL, NOTE_INSN_PROLOGUE_END);
+
+  /* Find the "this" pointer.  If the function returns a structure,
+     the structure return pointer is in $16.  */
+  if (aggregate_value_p (TREE_TYPE (TREE_TYPE (function))))
+    this = gen_rtx_REG (Pmode, 17);
+  else
+    this = gen_rtx_REG (Pmode, 16);
+
+  /* Add DELTA.  When possible we use ldah+lda.  Otherwise load the
+     entire constant for the add.  */
+  lo = ((delta & 0xffff) ^ 0x8000) - 0x8000;
+  hi = (((delta - lo) & 0xffffffff) ^ 0x80000000) - 0x80000000;
+  if (hi + lo == delta)
+    {
+      if (hi)
+       emit_insn (gen_adddi3 (this, this, GEN_INT (hi)));
+      if (lo)
+       emit_insn (gen_adddi3 (this, this, GEN_INT (lo)));
+    }
+  else
+    {
+      rtx tmp = alpha_emit_set_long_const (gen_rtx_REG (Pmode, 0),
+                                          delta, -(delta < 0));
+      emit_insn (gen_adddi3 (this, this, tmp));
+    }
+
+  /* Generate a tail call to the target function.  */
+  if (! TREE_USED (function))
+    {
+      assemble_external (function);
+      TREE_USED (function) = 1;
+    }
+  funexp = XEXP (DECL_RTL (function), 0);
+  funexp = gen_rtx_MEM (FUNCTION_MODE, funexp);
+  insn = emit_call_insn (gen_sibcall (funexp, const0_rtx));
+  SIBLING_CALL_P (insn) = 1;
+
+  /* Run just enough of rest_of_compilation to get the insns emitted.
+     There's not really enough bulk here to make other passes such as
+     instruction scheduling worth while.  Note that use_thunk calls
+     assemble_start_function and assemble_end_function.  */
+  insn = get_insns ();
+  shorten_branches (insn);
+  final_start_function (insn, file, 1);
+  final (insn, file, 1, 0);
+  final_end_function ();
+}
 \f
 /* Debugging support.  */
 
index 4e676f2da593e2d8c6136bd658fad11befbfcfa3..99ef24ea9769681aeba3b846883bab533ac7d1c3 100644 (file)
@@ -2236,3 +2236,8 @@ do {                                                      \
 
 /* Generate calls to memcpy, etc., not bcopy, etc.  */
 #define TARGET_MEM_FUNCTIONS 1
+
+/* Output code to add DELTA to the first argument, and then jump to FUNCTION.
+   Used for C++ multiple inheritance.  */
+#define ASM_OUTPUT_MI_THUNK(FILE, THUNK_FNDECL, DELTA, FUNCTION) \
+  alpha_output_mi_thunk_osf (FILE, THUNK_FNDECL, DELTA, FUNCTION)
index 6179739ddb819aab4d57a2552806505ad9a7923f..dfb3d4bdda296864004f4e390c0ebc88ea64e5ce 100644 (file)
@@ -1,3 +1,8 @@
+2002-02-04  Richard Henderson  <rth@redhat.com>
+
+       * method.c (use_thunk): Always initialize the block tree.  Reindent.
+       * semantics.c (expand_body): Emit thunks after function, not before.
+
 2002-02-04  Jason Merrill  <jason@redhat.com>
 
        * decl.c (start_function): Call cplus_decl_attributes immediately
index b0cc63a5c0f0644183a57e9f44e28405d60a7e61..52a6a8cf59d1b618e3cfd0ee3393eb3d5edc1b39 100644 (file)
@@ -392,6 +392,12 @@ use_thunk (thunk_fndecl, emit_p)
 
   push_to_top_level ();
 
+  /* The back-end expects DECL_INITIAL to contain a BLOCK, so we
+     create one.  */
+  DECL_INITIAL (thunk_fndecl) = make_node (BLOCK);
+  BLOCK_VARS (DECL_INITIAL (thunk_fndecl)) 
+    = DECL_ARGUMENTS (thunk_fndecl);
+
 #ifdef ASM_OUTPUT_MI_THUNK
   if (!vcall_offset)
     {
@@ -411,88 +417,83 @@ use_thunk (thunk_fndecl, emit_p)
     }
   else
 #endif /* ASM_OUTPUT_MI_THUNK */
-  {
-  /* If we don't have the necessary macro for efficient thunks, generate a
-     thunk function that just makes a call to the real function.
-     Unfortunately, this doesn't work for varargs.  */
-
-    tree a, t;
-
-    if (varargs_function_p (function))
-      error ("generic thunk code fails for method `%#D' which uses `...'",
-               function);
-
-    /* Set up clone argument trees for the thunk.  */
-    t = NULL_TREE;
-    for (a = DECL_ARGUMENTS (function); a; a = TREE_CHAIN (a))
-      {
-       tree x = copy_node (a);
-       TREE_CHAIN (x) = t;
-       DECL_CONTEXT (x) = thunk_fndecl;
-       t = x;
-      }
-    a = nreverse (t);
-    DECL_ARGUMENTS (thunk_fndecl) = a;
-    DECL_RESULT (thunk_fndecl) = NULL_TREE;
-
-    start_function (NULL_TREE, thunk_fndecl, NULL_TREE, SF_PRE_PARSED);
-    /* We don't bother with a body block for thunks.  */
-
-    /* Adjust the this pointer by the constant.  */
-    t = ssize_int (delta);
-    t = fold (build (PLUS_EXPR, TREE_TYPE (a), a, t));
-    /* If there's a vcall offset, look up that value in the vtable and
-       adjust the `this' pointer again.  */
-    if (vcall_offset && !integer_zerop (vcall_offset))
-      {
-       tree orig_this;
-
-       t = save_expr (t);
-       orig_this = t;
-       /* The vptr is always at offset zero in the object.  */
-       t = build1 (NOP_EXPR,
-                   build_pointer_type (build_pointer_type 
-                                       (vtable_entry_type)),
-                   t);
-       /* Form the vtable address.  */
-       t = build1 (INDIRECT_REF, TREE_TYPE (TREE_TYPE (t)), t);
-       /* Find the entry with the vcall offset.  */
-       t = build (PLUS_EXPR, TREE_TYPE (t), t, vcall_offset);
-       /* Calculate the offset itself.  */
-       t = build1 (INDIRECT_REF, TREE_TYPE (TREE_TYPE (t)), t);
-       /* Adjust the `this' pointer.  */
-       t = fold (build (PLUS_EXPR,
-                        TREE_TYPE (orig_this),
-                        orig_this,
-                        t));
-      }
-
-    /* Build up the call to the real function.  */
-    t = tree_cons (NULL_TREE, t, NULL_TREE);
-    for (a = TREE_CHAIN (a); a; a = TREE_CHAIN (a))
-      t = tree_cons (NULL_TREE, a, t);
-    t = nreverse (t);
-    t = build_call (function, t);
-    if (VOID_TYPE_P (TREE_TYPE (t)))
-      finish_expr_stmt (t);
-    else
-      finish_return_stmt (t);
+    {
+      /* If we don't have the necessary macro for efficient thunks, generate
+        a thunk function that just makes a call to the real function.
+        Unfortunately, this doesn't work for varargs.  */
 
-    /* The back-end expects DECL_INITIAL to contain a BLOCK, so we
-       create one.  */
-    DECL_INITIAL (thunk_fndecl) = make_node (BLOCK);
-    BLOCK_VARS (DECL_INITIAL (thunk_fndecl)) 
-      = DECL_ARGUMENTS (thunk_fndecl);
+      tree a, t;
 
-    /* Since we want to emit the thunk, we explicitly mark its name as
-       referenced.  */
-    TREE_SYMBOL_REFERENCED (DECL_ASSEMBLER_NAME (thunk_fndecl)) = 1;
+      if (varargs_function_p (function))
+       error ("generic thunk code fails for method `%#D' which uses `...'",
+              function);
 
-    /* But we don't want debugging information about it.  */
-    DECL_IGNORED_P (thunk_fndecl) = 1;
+      /* Set up clone argument trees for the thunk.  */
+      t = NULL_TREE;
+      for (a = DECL_ARGUMENTS (function); a; a = TREE_CHAIN (a))
+       {
+         tree x = copy_node (a);
+         TREE_CHAIN (x) = t;
+         DECL_CONTEXT (x) = thunk_fndecl;
+         t = x;
+       }
+      a = nreverse (t);
+      DECL_ARGUMENTS (thunk_fndecl) = a;
+      DECL_RESULT (thunk_fndecl) = NULL_TREE;
 
-    expand_body (finish_function (0));
-  }
+      start_function (NULL_TREE, thunk_fndecl, NULL_TREE, SF_PRE_PARSED);
+      /* We don't bother with a body block for thunks.  */
+
+      /* Adjust the this pointer by the constant.  */
+      t = ssize_int (delta);
+      t = fold (build (PLUS_EXPR, TREE_TYPE (a), a, t));
+
+      /* If there's a vcall offset, look up that value in the vtable and
+        adjust the `this' pointer again.  */
+      if (vcall_offset && !integer_zerop (vcall_offset))
+       {
+         tree orig_this;
+
+         t = save_expr (t);
+         orig_this = t;
+         /* The vptr is always at offset zero in the object.  */
+         t = build1 (NOP_EXPR,
+                     build_pointer_type (build_pointer_type 
+                                         (vtable_entry_type)),
+                     t);
+         /* Form the vtable address.  */
+         t = build1 (INDIRECT_REF, TREE_TYPE (TREE_TYPE (t)), t);
+         /* Find the entry with the vcall offset.  */
+         t = build (PLUS_EXPR, TREE_TYPE (t), t, vcall_offset);
+         /* Calculate the offset itself.  */
+         t = build1 (INDIRECT_REF, TREE_TYPE (TREE_TYPE (t)), t);
+         /* Adjust the `this' pointer.  */
+         t = fold (build (PLUS_EXPR,
+                          TREE_TYPE (orig_this),
+                          orig_this,
+                          t));
+       }
+
+      /* Build up the call to the real function.  */
+      t = tree_cons (NULL_TREE, t, NULL_TREE);
+      for (a = TREE_CHAIN (a); a; a = TREE_CHAIN (a))
+       t = tree_cons (NULL_TREE, a, t);
+      t = nreverse (t);
+      t = build_call (function, t);
+      if (VOID_TYPE_P (TREE_TYPE (t)))
+       finish_expr_stmt (t);
+      else
+       finish_return_stmt (t);
+
+      /* Since we want to emit the thunk, we explicitly mark its name as
+        referenced.  */
+      TREE_SYMBOL_REFERENCED (DECL_ASSEMBLER_NAME (thunk_fndecl)) = 1;
+
+      /* But we don't want debugging information about it.  */
+      DECL_IGNORED_P (thunk_fndecl) = 1;
+
+      expand_body (finish_function (0));
+    }
 
   pop_from_top_level ();
 }
index 7ac47a18b90f68b8394e63dc7398bd4257861b4e..cdc1178f338c40dd70d7feab2c8a6c306942b317 100644 (file)
@@ -2397,9 +2397,6 @@ expand_body (fn)
   if (DECL_EXTERNAL (fn))
     return;
 
-  /* Emit any thunks that should be emitted at the same time as FN.  */
-  emit_associated_thunks (fn);
-
   timevar_push (TV_INTEGRATION);
 
   /* Optimize the body of the function before expanding it.  */
@@ -2452,6 +2449,9 @@ expand_body (fn)
   extract_interface_info ();
 
   timevar_pop (TV_EXPAND);
+
+  /* Emit any thunks that should be emitted at the same time as FN.  */
+  emit_associated_thunks (fn);
 }
 
 /* Helper function for walk_tree, used by finish_function to override all