This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

C++ PATCH: PR 11326


This patch fixes PR c++/1326, an Itanium-specific bug in the C++ ABI.

The C++ ABI specifically requires that on Itanium the struture return
parameter for classes with non-trivial copy constructors or
destructors be passed in out0, rather than in r8, which is where it
passed otherwise.  (The rationale for this, I believe, is to make it
easier to write C functions that implement C++ interfaces.)  

HP's compiler correctly implements this rule.

Tested on ia64-hp-hpux11.22, applied on the mainline and on the 3.4
branch as soon as I finish testing the minor variations required
there.

--
Mark Mitchell
CodeSourcery, LLC
mark@codesourcery.com

2004-02-17  Mark Mitchell  <mark@codesourcery.com>

	PR c++/11326
	* c-common.c (flag_abi_version): Remove.
	* c-common.h (flag_abi_version): Likewise.
	* c-opts.c (c_common_handle_option): Remove OPT_fabi_version case.
	* c.opt (fabi-version): Remove.
	* calls.c (expand_call): Always pass a function type to
	struct_value_rtx.  Use convert_memory_address.
	* common.opt (fabi-version): Add it.
	* flags.h (flag_abi_version): Likewise.
	(abi_version_at_least): New macro.
	* opts.c (common_handle_option): Add OPT_fabi_version.
	* toplev.c (flag_abi_version): Define it.
	* config/ia64/ia64.c (ia64_struct_retval_addr_is_first_parm_p):
	New function.
	(ia64_output_mi_thunk): Use it.
	(ia64_struct_value_rtx): Likewise.

2004-02-17  Mark Mitchell  <mark@codesourcery.com>

	PR c++/11326
	* cp-tree.h (abi_version_at_least): Remove.
	* mangle.c: Include flags.h.

2004-02-17  Mark Mitchell  <mark@codesourcery.com>

	PR c++/11326
	* g++.dg/abi/structret1.C: New test.

Index: c-common.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/c-common.c,v
retrieving revision 1.483
diff -c -5 -p -r1.483 c-common.c
*** c-common.c	11 Feb 2004 01:55:28 -0000	1.483
--- c-common.c	17 Feb 2004 18:13:13 -0000
*************** int flag_permissive;
*** 597,623 ****
     doesn't match the specification.  Zero means to treat them as
     assertions and optimize accordingly, but not check them.  */
  
  int flag_enforce_eh_specs = 1;
  
- /*  The version of the C++ ABI in use.  The following values are
-     allowed:
- 
-     0: The version of the ABI believed most conformant with the
-        C++ ABI specification.  This ABI may change as bugs are
-        discovered and fixed.  Therefore, 0 will not necessarily
-        indicate the same ABI in different versions of G++.
- 
-     1: The version of the ABI first used in G++ 3.2.
- 
-     2: The version of the ABI first used in G++ 3.4.
- 
-     Additional positive integers will be assigned as new versions of
-     the ABI become the default version of the ABI.  */
- 
- int flag_abi_version = 2;
- 
  /* Nonzero means warn about things that will change when compiling
     with an ABI-compliant compiler.  */
  
  int warn_abi = 0;
  
--- 597,606 ----
Index: c-common.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/c-common.h,v
retrieving revision 1.221
diff -c -5 -p -r1.221 c-common.h
*** c-common.h	15 Feb 2004 14:30:38 -0000	1.221
--- c-common.h	17 Feb 2004 18:13:14 -0000
*************** extern int flag_permissive;
*** 758,782 ****
     doesn't match the specification.  Zero means to treat them as
     assertions and optimize accordingly, but not check them.  */
  
  extern int flag_enforce_eh_specs;
  
- /*  The version of the C++ ABI in use.  The following values are
-     allowed:
- 
-     0: The version of the ABI believed most conformant with the 
-        C++ ABI specification.  This ABI may change as bugs are
-        discovered and fixed.  Therefore, 0 will not necessarily
-        indicate the same ABI in different versions of G++.
- 
-     1: The version of the ABI first used in G++ 3.2.
- 
-     Additional positive integers will be assigned as new versions of
-     the ABI become the default version of the ABI.  */
- 
- extern int flag_abi_version;
- 
  /* Nonzero means warn about things that will change when compiling
     with an ABI-compliant compiler.  */
  
  extern int warn_abi;
  
--- 758,767 ----
Index: c-opts.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/c-opts.c,v
retrieving revision 1.102
diff -c -5 -p -r1.102 c-opts.c
*** c-opts.c	10 Feb 2004 18:18:55 -0000	1.102
--- c-opts.c	17 Feb 2004 18:13:14 -0000
*************** c_common_handle_option (size_t scode, co
*** 690,703 ****
      case OPT_fxref:
      case OPT_fvtable_gc:
        warning ("switch \"%s\" is no longer supported", option->opt_text);
        break;
  
-     case OPT_fabi_version_:
-       flag_abi_version = value;
-       break;
- 
      case OPT_faccess_control:
        flag_access_control = value;
        break;
  
      case OPT_fasm:
--- 690,699 ----
Index: c.opt
===================================================================
RCS file: /cvs/gcc/gcc/gcc/c.opt,v
retrieving revision 1.18
diff -c -5 -p -r1.18 c.opt
*** c.opt	2 Feb 2004 20:20:49 -0000	1.18
--- c.opt	17 Feb 2004 18:13:14 -0000
*************** A synonym for -std=c89.  In a future ver
*** 409,421 ****
  
  d
  C ObjC C++ ObjC++ Joined
  ; Documented in common.opt.  FIXME - what about -dI, -dD, -dN and -dD?
  
- fabi-version=
- C++ ObjC++ Joined UInteger
- 
  faccess-control
  C++ ObjC++
  Enforce class member access control semantics
  
  fall-virtual
--- 409,418 ----
Index: calls.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/calls.c,v
retrieving revision 1.319
diff -c -5 -p -r1.319 calls.c
*** calls.c	6 Feb 2004 06:18:11 -0000	1.319
--- calls.c	17 Feb 2004 18:13:16 -0000
*************** expand_call (tree exp, rtx target, int i
*** 2078,2087 ****
--- 2078,2089 ----
    tree funtype;
    tree type_arg_types;
    /* Declaration of the function being called,
       or 0 if the function is computed (not known by name).  */
    tree fndecl = 0;
+   /* The type of the function being called.  */
+   tree fntype;
    rtx insn;
    int try_tail_call = 1;
    int try_tail_recursion = 1;
    int pass;
  
*************** expand_call (tree exp, rtx target, int i
*** 2186,2195 ****
--- 2188,2198 ----
       As a result, decide whether this is a call to an integrable function.  */
  
    fndecl = get_callee_fndecl (exp);
    if (fndecl)
      {
+       fntype = TREE_TYPE (fndecl);
        if (!flag_no_inline
  	  && fndecl != current_function_decl
  	  && DECL_INLINE (fndecl)
  	  && DECL_SAVED_INSNS (fndecl)
  	  && DECL_SAVED_INSNS (fndecl)->inlinable)
*************** expand_call (tree exp, rtx target, int i
*** 2221,2239 ****
  
    /* If we don't have specific function to call, see if we have a
       attributes set in the type.  */
    else
      {
        if (ignore
! 	  && lookup_attribute ("warn_unused_result",
! 			       TYPE_ATTRIBUTES (TREE_TYPE (TREE_TYPE (p)))))
  	warning ("ignoring return value of function "
  		 "declared with attribute warn_unused_result");
!       flags |= flags_from_decl_or_type (TREE_TYPE (TREE_TYPE (p)));
      }
  
!   struct_value = targetm.calls.struct_value_rtx (fndecl ? TREE_TYPE (fndecl) : 0, 0);
  
    /* Warn if this value is an aggregate type,
       regardless of which calling convention we are using for it.  */
    if (warn_aggregate_return && AGGREGATE_TYPE_P (TREE_TYPE (exp)))
      warning ("function call has aggregate value");
--- 2224,2242 ----
  
    /* If we don't have specific function to call, see if we have a
       attributes set in the type.  */
    else
      {
+       fntype = TREE_TYPE (TREE_TYPE (p));
        if (ignore
! 	  && lookup_attribute ("warn_unused_result", TYPE_ATTRIBUTES (fntype)))
  	warning ("ignoring return value of function "
  		 "declared with attribute warn_unused_result");
!       flags |= flags_from_decl_or_type (fntype);
      }
  
!   struct_value = targetm.calls.struct_value_rtx (fntype, 0);
  
    /* Warn if this value is an aggregate type,
       regardless of which calling convention we are using for it.  */
    if (warn_aggregate_return && AGGREGATE_TYPE_P (TREE_TYPE (exp)))
      warning ("function call has aggregate value");
*************** expand_call (tree exp, rtx target, int i
*** 2383,2393 ****
  	 register in some cases.  */
        rtx temp = (GET_CODE (structure_value_addr) != REG
  		  || (ACCUMULATE_OUTGOING_ARGS
  		      && stack_arg_under_construction
  		      && structure_value_addr == virtual_outgoing_args_rtx)
! 		  ? copy_addr_to_reg (structure_value_addr)
  		  : structure_value_addr);
  
        actparms
  	= tree_cons (error_mark_node,
  		     make_tree (build_pointer_type (TREE_TYPE (funtype)),
--- 2386,2397 ----
  	 register in some cases.  */
        rtx temp = (GET_CODE (structure_value_addr) != REG
  		  || (ACCUMULATE_OUTGOING_ARGS
  		      && stack_arg_under_construction
  		      && structure_value_addr == virtual_outgoing_args_rtx)
! 		  ? copy_addr_to_reg (convert_memory_address 
! 				      (Pmode, structure_value_addr))
  		  : structure_value_addr);
  
        actparms
  	= tree_cons (error_mark_node,
  		     make_tree (build_pointer_type (TREE_TYPE (funtype)),
Index: common.opt
===================================================================
RCS file: /cvs/gcc/gcc/gcc/common.opt,v
retrieving revision 1.26
diff -c -5 -p -r1.26 common.opt
*** common.opt	6 Feb 2004 20:03:40 -0000	1.26
--- common.opt	17 Feb 2004 18:13:16 -0000
*************** fPIC
*** 177,186 ****
--- 177,189 ----
  Common
  
  fPIE
  Common
  
+ fabi-version=
+ Common Joined UInteger
+ 
  falign-functions
  Common
  Align the start of functions
  
  falign-functions=
Index: flags.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/flags.h,v
retrieving revision 1.129
diff -c -5 -p -r1.129 flags.h
*** flags.h	6 Feb 2004 20:03:41 -0000	1.129
--- flags.h	17 Feb 2004 18:13:17 -0000
*************** extern int flag_var_tracking;
*** 729,738 ****
--- 729,759 ----
  /* A string that's used when a random name is required.  NULL means
     to make it really random.  */
  
  extern const char *flag_random_seed;
  
+ /*  The version of the C++ ABI in use.  The following values are
+     allowed:
+ 
+     0: The version of the ABI believed most conformant with the 
+        C++ ABI specification.  This ABI may change as bugs are
+        discovered and fixed.  Therefore, 0 will not necessarily
+        indicate the same ABI in different versions of G++.
+ 
+     1: The version of the ABI first used in G++ 3.2.
+ 
+     Additional positive integers will be assigned as new versions of
+     the ABI become the default version of the ABI.  */
+ 
+ extern int flag_abi_version;
+ 
+ /* Returns TRUE if generated code should match ABI version N or
+    greater is in use.  */
+ 
+ #define abi_version_at_least(N) \
+   (flag_abi_version == 0 || flag_abi_version >= (N))
+ 
  /* True if the given mode has a NaN representation and the treatment of
     NaN operands is important.  Certain optimizations, such as folding
     x * 0 into x, are not correct for NaN operands, and are normally
     disabled for modes with NaNs.  The user can ask for them to be
     done anyway using the -funsafe-math-optimizations switch.  */
Index: opts.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/opts.c,v
retrieving revision 1.54
diff -c -5 -p -r1.54 opts.c
*** opts.c	6 Feb 2004 20:03:42 -0000	1.54
--- opts.c	17 Feb 2004 18:13:17 -0000
*************** common_handle_option (size_t scode, cons
*** 831,840 ****
--- 831,844 ----
  
      case OPT_fPIE:
        flag_pie = value + value;
        break;
  
+     case OPT_fabi_version_:
+       flag_abi_version = value;
+       break;
+ 
      case OPT_falign_functions:
        align_functions = !value;
        break;
  
      case OPT_falign_functions_:
Index: toplev.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/toplev.c,v
retrieving revision 1.876
diff -c -5 -p -r1.876 toplev.c
*** toplev.c	12 Feb 2004 21:42:26 -0000	1.876
--- toplev.c	17 Feb 2004 18:13:17 -0000
*************** int flag_wrapv = 0;
*** 1014,1023 ****
--- 1014,1040 ----
  int flag_evaluation_order = 0;
  
  /* Add or remove a leading underscore from user symbols.  */
  int flag_leading_underscore = -1;
  
+ /*  The version of the C++ ABI in use.  The following values are
+     allowed:
+ 
+     0: The version of the ABI believed most conformant with the
+        C++ ABI specification.  This ABI may change as bugs are
+        discovered and fixed.  Therefore, 0 will not necessarily
+        indicate the same ABI in different versions of G++.
+ 
+     1: The version of the ABI first used in G++ 3.2.
+ 
+     2: The version of the ABI first used in G++ 3.4.
+ 
+     Additional positive integers will be assigned as new versions of
+     the ABI become the default version of the ABI.  */
+ 
+ int flag_abi_version = 2;
+ 
  /* The user symbol prefix after having resolved same.  */
  const char *user_label_prefix;
  
  static const param_info lang_independent_params[] = {
  #define DEFPARAM(ENUM, OPTION, HELP, DEFAULT) \
Index: config/ia64/ia64.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/config/ia64/ia64.c,v
retrieving revision 1.275
diff -c -5 -p -r1.275 ia64.c
*** config/ia64/ia64.c	15 Feb 2004 14:53:40 -0000	1.275
--- config/ia64/ia64.c	17 Feb 2004 18:13:19 -0000
*************** static unsigned int
*** 8800,8809 ****
--- 8800,8830 ----
  ia64_rwreloc_section_type_flags (tree decl, const char *name, int reloc)
  {
    return default_section_type_flags_1 (decl, name, reloc, true);
  }
  
+ /* Returns true if FNTYPE (a FUNCTION_TYPE or a METHOD_TYPE) returns a
+    structure type and that the address of that type should be passed
+    in out0, rather than in r8.  */
+ 
+ static bool
+ ia64_struct_retval_addr_is_first_parm_p (tree fntype)
+ {
+   tree ret_type = TREE_TYPE (fntype);
+ 
+   /* The Itanium C++ ABI requires that out0, rather than r8, be used
+      as the structure return address parameter, if the return value
+      type has a non-trivial copy constructor or destructor.  It is not
+      clear if this same convention should be used for other
+      programming languages.  Until G++ 3.4, we incorrectly used r8 for
+      these return values.  */
+   return (abi_version_at_least (2)
+ 	  && ret_type
+ 	  && TYPE_MODE (ret_type) == BLKmode 
+ 	  && TREE_ADDRESSABLE (ret_type)
+ 	  && strcmp (lang_hooks.name, "GNU C++") == 0);
+ }
  
  /* Output the assembler code for a thunk function.  THUNK_DECL is the
     declaration for the thunk function itself, FUNCTION is the decl for
     the target function.  DELTA is an immediate constant offset to be
     added to THIS.  If VCALL_OFFSET is nonzero, the word at
*************** static void
*** 8813,8822 ****
--- 8834,8845 ----
  ia64_output_mi_thunk (FILE *file, tree thunk ATTRIBUTE_UNUSED,
  		      HOST_WIDE_INT delta, HOST_WIDE_INT vcall_offset,
  		      tree function)
  {
    rtx this, insn, funexp;
+   unsigned int this_parmno;
+   unsigned int this_regno;
  
    reload_completed = 1;
    epilogue_completed = 1;
    no_new_pseudos = 1;
  
*************** ia64_output_mi_thunk (FILE *file, tree t
*** 8826,8845 ****
    memset (&current_frame_info, 0, sizeof (current_frame_info));
    current_frame_info.spill_cfa_off = -16;
    current_frame_info.n_input_regs = 1;
    current_frame_info.need_regstk = (TARGET_REG_NAMES != 0);
  
-   if (!TARGET_REG_NAMES)
-     reg_names[IN_REG (0)] = ia64_reg_numbers[0];
- 
    /* Mark the end of the (empty) prologue.  */
    emit_note (NOTE_INSN_PROLOGUE_END);
  
!   this = gen_rtx_REG (Pmode, IN_REG (0));
    if (TARGET_ILP32)
      {
!       rtx tmp = gen_rtx_REG (ptr_mode, IN_REG (0));
        REG_POINTER (tmp) = 1;
        if (delta && CONST_OK_FOR_I (delta))
  	{
  	  emit_insn (gen_ptr_extend_plus_imm (this, tmp, GEN_INT (delta)));
  	  delta = 0;
--- 8849,8875 ----
    memset (&current_frame_info, 0, sizeof (current_frame_info));
    current_frame_info.spill_cfa_off = -16;
    current_frame_info.n_input_regs = 1;
    current_frame_info.need_regstk = (TARGET_REG_NAMES != 0);
  
    /* Mark the end of the (empty) prologue.  */
    emit_note (NOTE_INSN_PROLOGUE_END);
  
!   /* Figure out whether "this" will be the first parameter (the
!      typical case) or the second parameter (as happens when the
!      virtual function returns certain class objects).  */
!   this_parmno
!     = (ia64_struct_retval_addr_is_first_parm_p (TREE_TYPE (thunk))
!        ? 1 : 0);
!   this_regno = IN_REG (this_parmno);
!   if (!TARGET_REG_NAMES)
!     reg_names[this_regno] = ia64_reg_numbers[this_parmno];
! 
!   this = gen_rtx_REG (Pmode, this_regno);
    if (TARGET_ILP32)
      {
!       rtx tmp = gen_rtx_REG (ptr_mode, this_regno);
        REG_POINTER (tmp) = 1;
        if (delta && CONST_OK_FOR_I (delta))
  	{
  	  emit_insn (gen_ptr_extend_plus_imm (this, tmp, GEN_INT (delta)));
  	  delta = 0;
*************** ia64_output_mi_thunk (FILE *file, tree t
*** 8943,8954 ****
  }
  
  /* Worker function for TARGET_STRUCT_VALUE_RTX.  */
  
  static rtx
! ia64_struct_value_rtx (tree fntype ATTRIBUTE_UNUSED,
  		       int incoming ATTRIBUTE_UNUSED)
  {
    return gen_rtx_REG (Pmode, GR_REG (8));
  }
  
  #include "gt-ia64.h"
--- 8973,8986 ----
  }
  
  /* Worker function for TARGET_STRUCT_VALUE_RTX.  */
  
  static rtx
! ia64_struct_value_rtx (tree fntype,
  		       int incoming ATTRIBUTE_UNUSED)
  {
+   if (ia64_struct_retval_addr_is_first_parm_p (fntype))
+     return NULL_RTX;
    return gen_rtx_REG (Pmode, GR_REG (8));
  }
  
  #include "gt-ia64.h"
Index: cp/cp-tree.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cp/cp-tree.h,v
retrieving revision 1.953
diff -c -5 -p -r1.953 cp-tree.h
*** cp/cp-tree.h	14 Feb 2004 00:49:12 -0000	1.953
--- cp/cp-tree.h	17 Feb 2004 18:13:20 -0000
*************** struct diagnostic_context;
*** 211,226 ****
  #define RECORD_OR_UNION_TYPE_CHECK(NODE)		(NODE)
  #define BOUND_TEMPLATE_TEMPLATE_PARM_TYPE_CHECK(NODE)	(NODE)
  
  #endif
  
- /* Returns TRUE if generated code should match ABI version N or
-    greater is in use.  */
- 
- #define abi_version_at_least(N) \
-   (flag_abi_version == 0 || flag_abi_version >= (N))
- 
  
  /* Language-dependent contents of an identifier.  */
  
  struct lang_identifier GTY(())
  {
--- 211,220 ----
Index: cp/mangle.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cp/mangle.c,v
retrieving revision 1.97
diff -c -5 -p -r1.97 mangle.c
*** cp/mangle.c	29 Jan 2004 16:47:12 -0000	1.97
--- cp/mangle.c	17 Feb 2004 18:13:20 -0000
***************
*** 56,65 ****
--- 56,66 ----
  #include "cp-tree.h"
  #include "real.h"
  #include "obstack.h"
  #include "toplev.h"
  #include "varray.h"
+ #include "flags.h"
  
  /* Debugging support.  */
  
  /* Define DEBUG_MANGLE to enable very verbose trace messages.  */
  #ifndef DEBUG_MANGLE
Index: testsuite/g++.dg/abi/structret1.C
===================================================================
RCS file: testsuite/g++.dg/abi/structret1.C
diff -N testsuite/g++.dg/abi/structret1.C
*** /dev/null	1 Jan 1970 00:00:00 -0000
--- testsuite/g++.dg/abi/structret1.C	17 Feb 2004 18:13:23 -0000
***************
*** 0 ****
--- 1,31 ----
+ // { dg-do run { target ia64-*-* } }
+ // { dg-options "-fabi-version=0" }
+ 
+ extern "C" void abort ();
+ 
+ struct ConstructedObject {
+   ConstructedObject() {};
+   ~ConstructedObject() {};
+   ConstructedObject(const ConstructedObject &from) {};
+ };
+ 
+ struct FrameworkObject {
+   ConstructedObject action();
+ };
+ 
+ ConstructedObject FrameworkObject::action() {
+   void *r32, *r33;
+ 
+   asm("mov %0 = r32\nmov %1 = r33" : "=r"(r32), "=r"(r33) : );
+   if (this != r33) {
+     abort ();
+   }
+ }
+ 
+ int main()
+ {
+   FrameworkObject slawa;
+   slawa.action();
+   return 0;
+ }
+ 


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]