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]

cleanup vtable gc


At present, the c++ front end does ugly things with asm statements
to smuggle assembly directives through to the back end.  Additionally,
the asm statements use constraints that are not portable across
different architectures, which causes unnecessary failures on e.g.
alpha and ia64.

This promotes these operations to first-class citizens supported by
varasm.c and other levels of the IL.


r~


        * rtl.h (REG_VTABLE_REF): New.
        * rtl.c (reg_note_name): Add it.
        * combine.c (distribute_notes): Handle it.
        * final.c (final_scan_insn): Handle it.
        * tree.def (VTABLE_REF): New.
        * expr.c (expand_expr): Handle it.
        * varasm.c (assemble_vtable_entry, assemble_vtable_inherit): New.
        * output.h: Declare them.

cp/
        * class.c (build_vtable_entry_ref): Create a VTABLE_REF instead
        of an asm statement.
        (build_vtbl_ref_1): Split out from build_vtbl_ref.
        (build_vfn_ref): Use it to handle vtable descriptors before
        calling build_vtable_entry_ref.
        * decl2.c (output_vtable_inherit): Use assemble_vtable_inherit.

testsuite/
        * g++.old-deja/g++.other/crash18.C: Add -S to options.

Index: combine.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/combine.c,v
retrieving revision 1.238
diff -c -p -d -r1.238 combine.c
*** combine.c	2001/10/11 06:55:16	1.238
--- combine.c	2001/10/11 18:36:04
*************** distribute_notes (notes, from_insn, i3, 
*** 11952,11957 ****
--- 11952,11963 ----
  	  place = i3;
  	  break;
  
+ 	case REG_VTABLE_REF:
+ 	  /* ??? Should remain with *a particular* memory load.  Given the
+ 	     nature of vtable data, the last insn seems relatively safe.  */
+ 	  place = i3;
+ 	  break;
+ 
  	case REG_NON_LOCAL_GOTO:
  	  if (GET_CODE (i3) == JUMP_INSN)
  	    place = i3;
Index: expr.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/expr.c,v
retrieving revision 1.358
diff -c -p -d -r1.358 expr.c
*** expr.c	2001/10/11 03:15:34	1.358
--- expr.c	2001/10/11 18:36:05
*************** expand_expr (exp, target, tmode, modifie
*** 7211,7216 ****
--- 7211,7253 ----
  	return target;
        }
  
+     case VTABLE_REF:
+       {
+ 	rtx insn, before = get_last_insn (), vtbl_ref;
+ 
+ 	/* Evaluate the interior expression.  */
+ 	subtarget = expand_expr (TREE_OPERAND (exp, 0), target,
+ 				 tmode, modifier);
+ 
+ 	/* Get or create an instruction off which to hang a note.  */
+ 	if (REG_P (subtarget))
+ 	  {
+ 	    target = subtarget;
+ 	    insn = get_last_insn ();
+ 	    if (insn == before)
+ 	      abort ();
+ 	    if (! INSN_P (insn))
+ 	      insn = prev_nonnote_insn (insn);
+ 	  }
+ 	else
+ 	  {
+ 	    target = gen_reg_rtx (GET_MODE (subtarget));
+ 	    insn = emit_move_insn (target, subtarget);
+ 	  }
+ 
+ 	/* Collect the data for the note.  */
+ 	vtbl_ref = XEXP (DECL_RTL (TREE_OPERAND (exp, 1)), 0);
+ 	vtbl_ref = plus_constant (vtbl_ref,
+ 				  tree_low_cst (TREE_OPERAND (exp, 2), 0));
+ 	/* Discard the initial CONST that was added.  */
+ 	vtbl_ref = XEXP (vtbl_ref, 0);
+ 
+ 	REG_NOTES (insn)
+ 	  = gen_rtx_EXPR_LIST (REG_VTABLE_REF, vtbl_ref, REG_NOTES (insn));
+ 
+ 	return target;
+       }
+ 
        /* Intended for a reference to a buffer of a file-object in Pascal.
  	 But it's not certain that a special tree code will really be
  	 necessary for these.  INDIRECT_REF might work for them.  */
Index: final.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/final.c,v
retrieving revision 1.207
diff -c -p -d -r1.207 final.c
*** final.c	2001/10/11 03:15:37	1.207
--- final.c	2001/10/11 18:36:06
*************** final_scan_insn (insn, file, optimize, p
*** 2375,2383 ****
  	rtx body = PATTERN (insn);
  	int insn_code_number;
  	const char *template;
- #ifdef HAVE_cc0
  	rtx note;
- #endif
  
  	/* An INSN, JUMP_INSN or CALL_INSN.
  	   First check for special kinds that recog doesn't recognize.  */
--- 2375,2381 ----
*************** final_scan_insn (insn, file, optimize, p
*** 2799,2805 ****
  	    if (next != 0 && next != NEXT_INSN (insn))
  	      {
  		rtx prev = PREV_INSN (insn);
- 		rtx note;
  
  		for (note = NEXT_INSN (insn); note != next;
  		     note = NEXT_INSN (note))
--- 2797,2802 ----
*************** final_scan_insn (insn, file, optimize, p
*** 2952,2957 ****
--- 2949,2960 ----
  	/* Mark this insn as having been output.  */
  	INSN_DELETED_P (insn) = 1;
  #endif
+ 
+ 	/* Emit information for vtable gc.  */
+ 	note = find_reg_note (insn, REG_VTABLE_REF, NULL_RTX);
+ 	if (note)
+ 	  assemble_vtable_entry (XEXP (XEXP (note, 0), 0),
+ 				 INTVAL (XEXP (XEXP (note, 0), 1)));
  
  	current_output_insn = debug_insn = 0;
        }
Index: output.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/output.h,v
retrieving revision 1.81
diff -c -p -d -r1.81 output.h
*** output.h	2001/10/09 14:03:11	1.81
--- output.h	2001/10/11 18:36:06
*************** extern void default_named_section_asm_ou
*** 497,499 ****
--- 497,504 ----
  							       int));
  extern void default_ctor_section_asm_out_constructor PARAMS ((struct rtx_def *,
  							      int));
+ 
+ /* Emit data for vtable gc for GNU binutils.  */
+ extern void assemble_vtable_entry PARAMS ((struct rtx_def *, HOST_WIDE_INT));
+ extern void assemble_vtable_inherit PARAMS ((struct rtx_def *,
+ 					     struct rtx_def *));
Index: rtl.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/rtl.c,v
retrieving revision 1.100
diff -c -p -d -r1.100 rtl.c
*** rtl.c	2001/10/11 03:16:04	1.100
--- rtl.c	2001/10/11 18:36:06
*************** const char * const reg_note_name[] =
*** 281,287 ****
    "REG_EXEC_COUNT", "REG_NOALIAS", "REG_SAVE_AREA", "REG_BR_PRED",
    "REG_FRAME_RELATED_EXPR", "REG_EH_CONTEXT", "REG_EH_REGION",
    "REG_SAVE_NOTE", "REG_MAYBE_DEAD", "REG_NORETURN",
!   "REG_NON_LOCAL_GOTO", "REG_SETJMP", "REG_ALWAYS_RETURN"
  };
  
  
--- 281,288 ----
    "REG_EXEC_COUNT", "REG_NOALIAS", "REG_SAVE_AREA", "REG_BR_PRED",
    "REG_FRAME_RELATED_EXPR", "REG_EH_CONTEXT", "REG_EH_REGION",
    "REG_SAVE_NOTE", "REG_MAYBE_DEAD", "REG_NORETURN",
!   "REG_NON_LOCAL_GOTO", "REG_SETJMP", "REG_ALWAYS_RETURN",
!   "REG_VTABLE_REF"
  };
  
  
Index: rtl.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/rtl.h,v
retrieving revision 1.304
diff -c -p -d -r1.304 rtl.h
*** rtl.h	2001/10/11 12:43:43	1.304
--- rtl.h	2001/10/11 18:36:06
*************** enum reg_note
*** 579,585 ****
    REG_SETJMP,
  
    /* Indicate calls that always returns.  */
!   REG_ALWAYS_RETURN
  };
  
  /* The base value for branch probability notes.  */
--- 579,589 ----
    REG_SETJMP,
  
    /* Indicate calls that always returns.  */
!   REG_ALWAYS_RETURN,
! 
!   /* Indicate that the memory load references a vtable.  The expression
!      is of the form (plus (symbol_ref vtable_sym) (const_int offset)).  */
!   REG_VTABLE_REF
  };
  
  /* The base value for branch probability notes.  */
Index: tree.def
===================================================================
RCS file: /cvs/gcc/gcc/gcc/tree.def,v
retrieving revision 1.46
diff -c -p -d -r1.46 tree.def
*** tree.def	2001/09/21 16:58:19	1.46
--- tree.def	2001/10/11 18:36:06
*************** DEFTREECODE (ARRAY_REF, "array_ref", 'r'
*** 374,379 ****
--- 374,386 ----
     of the range is taken from the type of the expression.  */
  DEFTREECODE (ARRAY_RANGE_REF, "array_range_ref", 'r', 2)
  
+ /* Vtable indexing.  Carries data useful for emitting information
+    for vtable garbage collection.
+    Operand 0: an array_ref (or equivalent expression)
+    Operand 1: the vtable base (must be a var_decl)
+    Operand 2: index into vtable (must be an integer_cst).  */
+ DEFTREECODE (VTABLE_REF, "vtable_ref", 'r', 3)
+ 
  /* Constructor: return an aggregate value made from specified components.
     In C, this is used only for structure and array initializers.
     Also used for SET_TYPE in Chill (and potentially Pascal).
Index: varasm.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/varasm.c,v
retrieving revision 1.217
diff -c -p -d -r1.217 varasm.c
*** varasm.c	2001/10/11 03:16:13	1.217
--- varasm.c	2001/10/11 18:36:07
*************** default_pe_asm_named_section (name, flag
*** 5297,5299 ****
--- 5297,5328 ----
  	       (flags & SECTION_CODE ? "discard" : "same_size"));
      }
  }
+ 
+ /* Used for vtable gc in GNU binutils.  Record that the pointer at OFFSET
+    from SYMBOL is used in all classes derived from SYMBOL.  */
+ 
+ void
+ assemble_vtable_entry (symbol, offset)
+      rtx symbol;
+      HOST_WIDE_INT offset;
+ {
+   fputs ("\t.vtable_entry ", asm_out_file);
+   output_addr_const (asm_out_file, symbol);
+   fputs (", ", asm_out_file);
+   fprintf (asm_out_file, HOST_WIDE_INT_PRINT_DEC, offset);
+   fputc ('\n', asm_out_file);
+ }
+ 
+ /* Used for vtable gc in GNU binutils.  Record the class heirarchy by noting
+    that the vtable symbol CHILD is derived from the vtable symbol PARENT.  */
+ 
+ void
+ assemble_vtable_inherit (child, parent)
+      rtx child, parent;
+ {
+   fputs ("\t.vtable_inherit ", asm_out_file);
+   output_addr_const (asm_out_file, child);
+   fputs (", ", asm_out_file);
+   output_addr_const (asm_out_file, parent);
+   fputc ('\n', asm_out_file);
+ }
Index: cp/class.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cp/class.c,v
retrieving revision 1.412
diff -c -p -d -r1.412 class.c
*** class.c	2001/10/07 16:50:54	1.412
--- class.c	2001/10/11 18:36:09
*************** static tree add_implicitly_declared_memb
*** 134,140 ****
  static tree fixed_type_or_null PARAMS ((tree, int *, int *));
  static tree resolve_address_of_overloaded_function PARAMS ((tree, tree, int,
  							  int, int, tree));
! static void build_vtable_entry_ref PARAMS ((tree, tree));
  static tree build_vtbl_initializer PARAMS ((tree, tree, tree, tree, int *));
  static int count_fields PARAMS ((tree));
  static int add_fields_to_vec PARAMS ((tree, tree, int));
--- 134,141 ----
  static tree fixed_type_or_null PARAMS ((tree, int *, int *));
  static tree resolve_address_of_overloaded_function PARAMS ((tree, tree, int,
  							  int, int, tree));
! static tree build_vtable_entry_ref PARAMS ((tree, tree, tree));
! static tree build_vtbl_ref_1 PARAMS ((tree, tree));
  static tree build_vtbl_initializer PARAMS ((tree, tree, tree, tree, int *));
  static int count_fields PARAMS ((tree));
  static int add_fields_to_vec PARAMS ((tree, tree, int));
*************** build_vbase_path (code, type, expr, path
*** 424,461 ****
  
  /* Virtual function things.  */
  
! /* We want to give the assembler the vtable identifier as well as
!    the offset to the function pointer.  So we generate
  
!    __asm__ __volatile__ (".vtable_entry %c0, %c1"
!       : : "s"(&class_vtable),
!           "i"((long)&vtbl[idx].pfn - (long)&vtbl[0])); */
  
! static void
! build_vtable_entry_ref (basetype, idx)
!      tree basetype, idx;
! {
!   static const char asm_stmt[] = ".vtable_entry %c0, %c1";
!   tree s, i, i2;
!   tree vtable = get_vtbl_decl_for_binfo (TYPE_BINFO (basetype));
!   tree first_fn = TYPE_BINFO_VTABLE (basetype);
  
!   s = build_unary_op (ADDR_EXPR, vtable, 0);
!   s = build_tree_list (build_string (1, "s"), s);
  
!   i = build_array_ref (first_fn, idx);
!   /* We must not convert to ptrdiff_type node here, since this could widen
!      from a partial to an integral node, which would create a
!      convert_expression that would be in the way of any simplifications.  */
!   i = build_c_cast (string_type_node, build_unary_op (ADDR_EXPR, i, 0));
!   i2 = build_array_ref (vtable, build_int_2 (0,0));
!   i2 = build_c_cast (string_type_node, build_unary_op (ADDR_EXPR, i2, 0));
!   i = cp_build_binary_op (MINUS_EXPR, i, i2);
!   i = build_tree_list (build_string (1, "i"), i);
  
!   finish_asm_stmt (ridpointers[RID_VOLATILE],
! 		   build_string (sizeof(asm_stmt)-1, asm_stmt),
! 		   NULL_TREE, chainon (s, i), NULL_TREE);
  }
  
  /* Given an object INSTANCE, return an expression which yields the
--- 425,455 ----
  
  /* Virtual function things.  */
  
! static tree
! build_vtable_entry_ref (array_ref, instance, idx)
!      tree array_ref, instance, idx;
! {
!   tree i, i2, vtable, first_fn, basetype;
  
!   basetype = TREE_TYPE (instance);
!   if (TREE_CODE (basetype) == REFERENCE_TYPE)
!     basetype = TREE_TYPE (basetype);
  
!   vtable = get_vtbl_decl_for_binfo (TYPE_BINFO (basetype));
!   first_fn = TYPE_BINFO_VTABLE (basetype);
  
!   i = fold (build_array_ref (first_fn, idx));
!   i = fold (build_c_cast (ptrdiff_type_node,
! 			  build_unary_op (ADDR_EXPR, i, 0)));
!   i2 = fold (build_array_ref (vtable, build_int_2 (0,0)));
!   i2 = fold (build_c_cast (ptrdiff_type_node,
! 			   build_unary_op (ADDR_EXPR, i2, 0)));
!   i = fold (cp_build_binary_op (MINUS_EXPR, i, i2));
  
!   if (TREE_CODE (i) != INTEGER_CST)
!     abort ();
  
!   return build (VTABLE_REF, TREE_TYPE (array_ref), array_ref, vtable, i);
  }
  
  /* Given an object INSTANCE, return an expression which yields the
*************** build_vtable_entry_ref (basetype, idx)
*** 463,470 ****
     cases for INSTANCE which we take care of here, mainly to avoid
     creating extra tree nodes when we don't have to.  */
  
! tree
! build_vtbl_ref (instance, idx)
       tree instance, idx;
  {
    tree vtbl, aref;
--- 457,464 ----
     cases for INSTANCE which we take care of here, mainly to avoid
     creating extra tree nodes when we don't have to.  */
  
! static tree
! build_vtbl_ref_1 (instance, idx)
       tree instance, idx;
  {
    tree vtbl, aref;
*************** build_vtbl_ref (instance, idx)
*** 535,548 ****
  
    assemble_external (vtbl);
  
-   if (flag_vtable_gc)
-     build_vtable_entry_ref (basetype, idx);
- 
    aref = build_array_ref (vtbl, idx);
  
    return aref;
  }
  
  /* Given an object INSTANCE, return an expression which yields a
     function pointer corresponding to vtable element INDEX.  */
  
--- 529,551 ----
  
    assemble_external (vtbl);
  
    aref = build_array_ref (vtbl, idx);
  
    return aref;
  }
  
+ tree
+ build_vtbl_ref (instance, idx)
+      tree instance, idx;
+ {
+   tree aref = build_vtbl_ref_1 (instance, idx);
+ 
+   if (flag_vtable_gc)
+     aref = build_vtable_entry_ref (aref, instance, idx);
+ 
+   return aref;
+ }
+ 
  /* Given an object INSTANCE, return an expression which yields a
     function pointer corresponding to vtable element INDEX.  */
  
*************** tree
*** 550,562 ****
  build_vfn_ref (instance, idx)
       tree instance, idx;
  {
!   tree aref = build_vtbl_ref (instance, idx);
  
    /* When using function descriptors, the address of the
       vtable entry is treated as a function pointer.  */
    if (TARGET_VTABLE_USES_DESCRIPTORS)
!     return build1 (NOP_EXPR, TREE_TYPE (aref),
  		   build_unary_op (ADDR_EXPR, aref, /*noconvert=*/1));
  
    return aref;
  }
--- 553,568 ----
  build_vfn_ref (instance, idx)
       tree instance, idx;
  {
!   tree aref = build_vtbl_ref_1 (instance, idx);
  
    /* When using function descriptors, the address of the
       vtable entry is treated as a function pointer.  */
    if (TARGET_VTABLE_USES_DESCRIPTORS)
!     aref = build1 (NOP_EXPR, TREE_TYPE (aref),
  		   build_unary_op (ADDR_EXPR, aref, /*noconvert=*/1));
+ 
+   if (flag_vtable_gc)
+     aref = build_vtable_entry_ref (aref, instance, idx);
  
    return aref;
  }
Index: cp/decl2.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cp/decl2.c,v
retrieving revision 1.495
diff -c -p -d -r1.495 decl2.c
*** decl2.c	2001/10/05 02:48:46	1.495
--- decl2.c	2001/10/11 18:36:10
*************** output_vtable_inherit (vars)
*** 2406,2428 ****
       tree vars;
  {
    tree parent;
!   rtx op[2];
  
!   op[0] = XEXP (DECL_RTL (vars), 0);	  /* strip the mem ref  */
  
    parent = binfo_for_vtable (vars);
  
    if (parent == TYPE_BINFO (DECL_CONTEXT (vars)))
!     op[1] = const0_rtx;
    else if (parent)
      {
        parent = get_vtbl_decl_for_binfo (TYPE_BINFO (BINFO_TYPE (parent)));
!       op[1] = XEXP (DECL_RTL (parent), 0);  /* strip the mem ref  */
      }
    else
      my_friendly_abort (980826);
  
!   output_asm_insn (".vtable_inherit %c0, %c1", op);
  }
  
  static int
--- 2406,2428 ----
       tree vars;
  {
    tree parent;
!   rtx child_rtx, parent_rtx;
  
!   child_rtx = XEXP (DECL_RTL (vars), 0);	  /* strip the mem ref  */
  
    parent = binfo_for_vtable (vars);
  
    if (parent == TYPE_BINFO (DECL_CONTEXT (vars)))
!     parent_rtx = const0_rtx;
    else if (parent)
      {
        parent = get_vtbl_decl_for_binfo (TYPE_BINFO (BINFO_TYPE (parent)));
!       parent_rtx = XEXP (DECL_RTL (parent), 0);  /* strip the mem ref  */
      }
    else
      my_friendly_abort (980826);
  
!   assemble_vtable_inherit (child_rtx, parent_rtx);
  }
  
  static int
Index: testsuite/g++.old-deja/g++.other/crash18.C
===================================================================
RCS file: /cvs/gcc/gcc/gcc/testsuite/g++.old-deja/g++.other/crash18.C,v
retrieving revision 1.5
diff -c -p -d -r1.5 crash18.C
*** crash18.C	2001/05/21 15:55:40	1.5
--- crash18.C	2001/10/11 18:36:10
***************
*** 1,5 ****
  // Build don't link:
! // Special g++ Options: -fvtable-gc
  // Origin: Mark Mitchell <mitchell@codesourcery.com>
  
  struct S {
--- 1,5 ----
  // Build don't link:
! // Special g++ Options: -fvtable-gc -S
  // Origin: Mark Mitchell <mitchell@codesourcery.com>
  
  struct S {


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