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]

ia64 c++ abi: descriptors in vtables


I'd appreciate it if some c++ folk would give this a once-over,
as I flailed about a bit trying to figure out how vtables for
virtual bases are constructed.  In particular, look at the comment
in add_vcall_offset_vtbl_entries_1.  I think I may just not 
understand what "vcall" means in this context.

The following is against mainline; very minor modifications are
required for the 3.0 branch.

I've not touched Java yet, though I plan to do so.


r~


	* defaults.h (TARGET_VTABLE_USES_DESCRIPTORS): New.
	* tree.def (FDESC_EXPR): New.
	* expr.c (expand_expr): Handle it.
	* varasm.c (initializer_constant_valid_p): Likewise.
	(output_constant): Likewise.

	* config/ia64/ia64.h (TARGET_VTABLE_USES_DESCRIPTORS): New.
	(ASM_OUTPUT_FDESC): New.

	* cp/call.c (build_over_call): Use build_vfn_ref.
	* cp/class.c (build_vfn_ref): New.
	(set_vindex): Account for TARGET_VTABLE_USES_DESCRIPTORS.
	(build_vtbl_initializer): Likewise.
	* cp/cp-tree.h (build_vfn_ref): Declare.
	* cp/decl2.c (mark_vtable_entries): Handle FDESC_EXPR.
	* cp/typeck.c (get_member_function_from_ptrfunc): Handle
	function descriptors.

	* g++.old-deja/g++.abi/ptrmem.C: Update for ia64 function descriptors.
	* g++.old-deja/g++.abi/vtable2.C: Likewise.

Index: gcc/defaults.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/defaults.h,v
retrieving revision 1.55
diff -c -p -d -r1.55 defaults.h
*** defaults.h	2001/08/22 14:34:56	1.55
--- defaults.h	2001/09/14 06:08:03
*************** do {								\
*** 358,363 ****
--- 358,373 ----
  #define PREFERRED_STACK_BOUNDARY STACK_BOUNDARY
  #endif
  
+ /* By default, the C++ compiler will use function addresses in the
+    vtable entries.  Setting this non-zero tells the compiler to use
+    function descriptors instead.  The value of this macro says how
+    many words wide the descriptor is (normally 2).  It is assumed 
+    that the address of a function descriptor may be treated as a
+    pointer to a function.  */
+ #ifndef TARGET_VTABLE_USES_DESCRIPTORS
+ #define TARGET_VTABLE_USES_DESCRIPTORS 0
+ #endif
+ 
  /* Select a format to encode pointers in exception handling data.  We
     prefer those that result in fewer dynamic relocations.  Assume no
     special support here and encode direct references.  */
Index: gcc/expr.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/expr.c,v
retrieving revision 1.351
diff -c -p -d -r1.351 expr.c
*** expr.c	2001/09/06 08:59:36	1.351
--- expr.c	2001/09/14 06:08:04
*************** expand_expr (exp, target, tmode, modifie
*** 8755,8760 ****
--- 8755,8765 ----
      case EXC_PTR_EXPR:
        return get_exception_pointer (cfun);
  
+     case FDESC_EXPR:
+       /* Function descriptors are not valid except for as
+ 	 initialization constants, and should not be expanded.  */
+       abort ();
+ 
      default:
        return (*lang_expand_expr) (exp, original_target, tmode, modifier);
      }
Index: gcc/tree.def
===================================================================
RCS file: /cvs/gcc/gcc/gcc/tree.def,v
retrieving revision 1.45
diff -c -p -d -r1.45 tree.def
*** tree.def	2001/09/06 23:49:38	1.45
--- tree.def	2001/09/14 06:08:04
*************** DEFTREECODE (ADDR_EXPR, "addr_expr", 'e'
*** 716,723 ****
  DEFTREECODE (REFERENCE_EXPR, "reference_expr", 'e', 1)
  
  /* Operand is a function constant; result is a function variable value
!    of typeEPmode.  Used only for languages that need static chains.  */
  DEFTREECODE (ENTRY_VALUE_EXPR, "entry_value_expr", 'e', 1)
  
  /* Given two real or integer operands of the same type,
     returns a complex value of the corresponding complex type.  */
--- 716,727 ----
  DEFTREECODE (REFERENCE_EXPR, "reference_expr", 'e', 1)
  
  /* Operand is a function constant; result is a function variable value
!    of type EPmode.  Used only for languages that need static chains.  */
  DEFTREECODE (ENTRY_VALUE_EXPR, "entry_value_expr", 'e', 1)
+ 
+ /* Operand0 is a function constant; result is part N of a function 
+    descriptor of type ptr_mode.  */
+ DEFTREECODE (FDESC_EXPR, "fdesc_expr", 'e', 2)
  
  /* Given two real or integer operands of the same type,
     returns a complex value of the corresponding complex type.  */
Index: gcc/varasm.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/varasm.c,v
retrieving revision 1.207
diff -c -p -d -r1.207 varasm.c
*** varasm.c	2001/09/13 14:37:12	1.207
--- varasm.c	2001/09/14 06:08:04
*************** initializer_constant_valid_p (value, end
*** 4277,4282 ****
--- 4277,4283 ----
        return null_pointer_node;
  
      case ADDR_EXPR:
+     case FDESC_EXPR:
        return staticp (TREE_OPERAND (value, 0)) ? TREE_OPERAND (value, 0) : 0;
  
      case NON_LVALUE_EXPR:
*************** output_constant (exp, size, align)
*** 4466,4471 ****
--- 4467,4484 ----
    if (TREE_CODE (exp) == CONSTRUCTOR && CONSTRUCTOR_ELTS (exp) == 0)
      {
        assemble_zeros (size);
+       return;
+     }
+ 
+   if (TREE_CODE (exp) == FDESC_EXPR)
+     {
+       HOST_WIDE_INT part = tree_low_cst (TREE_OPERAND (exp, 1), 0);
+       tree decl = TREE_OPERAND (exp, 0);
+ #ifdef ASM_OUTPUT_FDESC
+       ASM_OUTPUT_FDESC (asm_out_file, decl, part);
+ #else
+       abort ();
+ #endif
        return;
      }
  
Index: gcc/config/ia64/ia64.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/config/ia64/ia64.h,v
retrieving revision 1.87
diff -c -p -d -r1.87 ia64.h
*** ia64.h	2001/08/23 07:44:03	1.87
--- ia64.h	2001/09/14 06:08:04
*************** while (0)
*** 416,421 ****
--- 416,428 ----
  /* A code distinguishing the floating point format of the target machine.  */
  #define TARGET_FLOAT_FORMAT IEEE_FLOAT_FORMAT
  
+ /* By default, the C++ compiler will use function addresses in the
+    vtable entries.  Setting this non-zero tells the compiler to use
+    function descriptors instead.  The value of this macro says how
+    many words wide the descriptor is (normally 2).  It is assumed 
+    that the address of a function descriptor may be treated as a
+    pointer to a function.  */
+ #define TARGET_VTABLE_USES_DESCRIPTORS 2
  
  /* Layout of Source Language Data Types */
  
*************** do {									\
*** 1534,1539 ****
--- 1541,1557 ----
    fprintf (FILE, "\n");							\
  } while (0)
  
+ /* Output part N of a function descriptor for DECL.  For ia64, both
+    words are emitted with a single relocation, so ignore N > 0.  */
+ #define ASM_OUTPUT_FDESC(FILE, DECL, PART)				\
+ do {									\
+   if ((PART) == 0)							\
+     {									\
+       fputs ("\tdata16.ua @iplt(", FILE);				\
+       assemble_name (FILE, XSTR (XEXP (DECL_RTL (DECL), 0), 0));	\
+       fputs (")\n", FILE);						\
+     }									\
+ } while (0)
  
  /* Generating Code for Profiling.  */
  
Index: gcc/cp/call.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cp/call.c,v
retrieving revision 1.282
diff -c -p -d -r1.282 call.c
*** call.c	2001/09/04 12:21:32	1.282
--- call.c	2001/09/14 06:08:04
*************** build_over_call (cand, args, flags)
*** 4321,4327 ****
        if (DECL_CONTEXT (fn) && TYPE_JAVA_INTERFACE (DECL_CONTEXT (fn)))
  	fn = build_java_interface_fn_ref (fn, *p);
        else
! 	fn = build_vtbl_ref (build_indirect_ref (*p, 0), DECL_VINDEX (fn));
        TREE_TYPE (fn) = t;
      }
    else if (DECL_INLINE (fn))
--- 4321,4327 ----
        if (DECL_CONTEXT (fn) && TYPE_JAVA_INTERFACE (DECL_CONTEXT (fn)))
  	fn = build_java_interface_fn_ref (fn, *p);
        else
! 	fn = build_vfn_ref (build_indirect_ref (*p, 0), DECL_VINDEX (fn));
        TREE_TYPE (fn) = t;
      }
    else if (DECL_INLINE (fn))
Index: gcc/cp/class.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cp/class.c,v
retrieving revision 1.409
diff -c -p -d -r1.409 class.c
*** class.c	2001/09/06 09:41:29	1.409
--- class.c	2001/09/14 06:08:04
*************** build_vtable_entry_ref (basetype, idx)
*** 459,467 ****
  }
  
  /* Given an object INSTANCE, return an expression which yields the
!    virtual function vtable element corresponding to INDEX.  There are
!    many special 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)
--- 459,467 ----
  }
  
  /* Given an object INSTANCE, return an expression which yields the
!    vtable element corresponding to INDEX.  There are many special
!    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)
*************** build_vtbl_ref (instance, idx)
*** 543,548 ****
--- 543,566 ----
    return aref;
  }
  
+ /* Given an object INSTANCE, return an expression which yields a
+    function pointer corresponding to vtable element INDEX.  */
+ 
+ tree
+ 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;
+ }
+ 
  /* Return the name of the virtual function table (as an IDENTIFIER_NODE)
     for the given TYPE.  */
  
*************** set_vindex (decl, vfuns_p)
*** 823,829 ****
  {
    int vindex;
  
!   vindex = (*vfuns_p)++;
    DECL_VINDEX (decl) = build_shared_int_cst (vindex);
  }
  
--- 841,849 ----
  {
    int vindex;
  
!   vindex = *vfuns_p;
!   *vfuns_p += (TARGET_VTABLE_USES_DESCRIPTORS
! 	       ? TARGET_VTABLE_USES_DESCRIPTORS : 1);
    DECL_VINDEX (decl) = build_shared_int_cst (vindex);
  }
  
*************** build_vtbl_initializer (binfo, orig_binf
*** 7587,7593 ****
  	  }
  
        /* And add it to the chain of initializers.  */
!       vfun_inits = tree_cons (NULL_TREE, init, vfun_inits);
      }
  
    /* The initializers for virtual functions were built up in reverse
--- 7607,7631 ----
  	  }
  
        /* And add it to the chain of initializers.  */
!       if (TARGET_VTABLE_USES_DESCRIPTORS)
! 	{
! 	  int i;
! 	  if (init == size_zero_node)
! 	    for (i = 0; i < TARGET_VTABLE_USES_DESCRIPTORS; ++i)
! 	      vfun_inits = tree_cons (NULL_TREE, init, vfun_inits);
! 	  else
! 	    for (i = 0; i < TARGET_VTABLE_USES_DESCRIPTORS; ++i)
! 	      {
! 		tree fdesc = build (FDESC_EXPR, vfunc_ptr_type_node,
! 				    TREE_OPERAND (init, 0),
! 				    build_int_2 (i, 0));
! 		TREE_CONSTANT (fdesc) = 1;
! 
! 		vfun_inits = tree_cons (NULL_TREE, fdesc, vfun_inits);
! 	      }
! 	}
!       else
!         vfun_inits = tree_cons (NULL_TREE, init, vfun_inits);
      }
  
    /* The initializers for virtual functions were built up in reverse
*************** add_vcall_offset_vtbl_entries_1 (binfo, 
*** 7934,7939 ****
--- 7972,7978 ----
  
        /* The next vcall offset will be found at a more negative
  	 offset.  */
+       /* ??? Check TARGET_VTABLE_USES_DESCRIPTORS.  */
        vid->index = size_binop (MINUS_EXPR, vid->index, ssize_int (1));
  
        /* Keep track of this function.  */
Index: gcc/cp/cp-tree.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cp/cp-tree.h,v
retrieving revision 1.640
diff -c -p -d -r1.640 cp-tree.h
*** cp-tree.h	2001/09/06 08:59:38	1.640
--- cp-tree.h	2001/09/14 06:08:04
*************** extern tree perform_implicit_conversion 
*** 3527,3532 ****
--- 3527,3533 ----
  /* in class.c */
  extern tree build_vbase_path			PARAMS ((enum tree_code, tree, tree, tree, int));
  extern tree build_vtbl_ref			PARAMS ((tree, tree));
+ extern tree build_vfn_ref			PARAMS ((tree, tree));
  extern tree get_vtable_decl                     PARAMS ((tree, int));
  extern void add_method				PARAMS ((tree, tree, int));
  extern int currently_open_class			PARAMS ((tree));
Index: gcc/cp/decl2.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cp/decl2.c,v
retrieving revision 1.491
diff -c -p -d -r1.491 decl2.c
*** decl2.c	2001/09/12 16:25:07	1.491
--- decl2.c	2001/09/14 06:08:05
*************** mark_vtable_entries (decl)
*** 2169,2175 ****
        tree fnaddr = TREE_VALUE (entries);
        tree fn;
        
!       if (TREE_CODE (fnaddr) != ADDR_EXPR)
  	/* This entry is an offset: a virtual base class offset, a
  	   virtual call offset, an RTTI offset, etc.  */
  	continue;
--- 2169,2176 ----
        tree fnaddr = TREE_VALUE (entries);
        tree fn;
        
!       if (TREE_CODE (fnaddr) != ADDR_EXPR
! 	  && TREE_CODE (fnaddr) != FDESC_EXPR)
  	/* This entry is an offset: a virtual base class offset, a
  	   virtual call offset, an RTTI offset, etc.  */
  	continue;
Index: gcc/cp/typeck.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cp/typeck.c,v
retrieving revision 1.364
diff -c -p -d -r1.364 typeck.c
*** typeck.c	2001/08/24 12:07:46	1.364
--- typeck.c	2001/09/14 06:08:05
*************** get_member_function_from_ptrfunc (instan
*** 2910,2915 ****
--- 2910,2921 ----
        vtbl = build_indirect_ref (vtbl, NULL);
        e2 = build_array_ref (vtbl, idx);
  
+       /* When using function descriptors, the address of the
+ 	 vtable entry is treated as a function pointer.  */
+       if (TARGET_VTABLE_USES_DESCRIPTORS)
+ 	e2 = build1 (NOP_EXPR, TREE_TYPE (e2),
+ 		     build_unary_op (ADDR_EXPR, e2, /*noconvert=*/1));
+ 
        TREE_TYPE (e2) = TREE_TYPE (e3);
        e1 = build_conditional_expr (e1, e2, e3);
        
Index: gcc/testsuite/g++.old-deja/g++.abi/ptrmem.C
===================================================================
RCS file: /cvs/gcc/gcc/gcc/testsuite/g++.old-deja/g++.abi/ptrmem.C,v
retrieving revision 1.5
diff -c -p -d -r1.5 ptrmem.C
*** ptrmem.C	2001/06/10 21:50:47	1.5
--- ptrmem.C	2001/09/14 06:08:05
***************
*** 14,19 ****
--- 14,29 ----
  #define ADJUST_DELTA(delta, virt) (delta)
  #endif
  
+ /* IA64 uses function descriptors instead of function pointers in its
+    vtables, which means that we can't meaningfully compare them directly.  */
+ #if defined __ia64__
+ #define CMP_PTRFN(A, B)	(*(void **)(A) == *(void **)(B))
+ #define VPTE_SIZE	(16)
+ #else
+ #define CMP_PTRFN(A, B) ((A) == (B))
+ #define VPTE_SIZE	sizeof(void *)
+ #endif
+ 
  #if defined (__GXX_ABI_VERSION) && __GXX_ABI_VERSION >= 100
  
  // Check that pointers-to-member functions are represented correctly.
*************** main ()
*** 85,96 ****
    // There should be no adjustment for the `T' version, and an
    // appropriate adjustment for the `S' version.
    y = &T::f;
!   if (yp->ptr != ADJUST_PTRFN (&_ZN1T1fEv, 0))
      return 5;
    if (yp->adj != ADJUST_DELTA (0, 0))
      return 6;
    x = (sp) y;
!   if (xp->ptr != ADJUST_PTRFN (&_ZN1T1fEv, 0))
      return 7;
    if (xp->adj != ADJUST_DELTA (delta, 0))
      return 8;
--- 95,106 ----
    // There should be no adjustment for the `T' version, and an
    // appropriate adjustment for the `S' version.
    y = &T::f;
!   if (! CMP_PTRFN (yp->ptr, ADJUST_PTRFN (&_ZN1T1fEv, 0)))
      return 5;
    if (yp->adj != ADJUST_DELTA (0, 0))
      return 6;
    x = (sp) y;
!   if (! CMP_PTRFN (xp->ptr, ADJUST_PTRFN (&_ZN1T1fEv, 0)))
      return 7;
    if (xp->adj != ADJUST_DELTA (delta, 0))
      return 8;
*************** main ()
*** 99,110 ****
    // one.  `T::h' is in the second slot: the vtable pointer points to
    // the first virtual function.
    y = &T::h;
!   if (yp->ptr != ADJUST_PTRFN (sizeof (void *), 1))
      return 9;
    if (yp->adj != ADJUST_DELTA (0, 1))
      return 10;
    x = (sp) y;
!   if (xp->ptr != ADJUST_PTRFN (sizeof (void *), 1))
      return 11;
    if (xp->adj != ADJUST_DELTA (delta, 1))
      return 12;
--- 109,120 ----
    // one.  `T::h' is in the second slot: the vtable pointer points to
    // the first virtual function.
    y = &T::h;
!   if (yp->ptr != ADJUST_PTRFN (VPTE_SIZE, 1))
      return 9;
    if (yp->adj != ADJUST_DELTA (0, 1))
      return 10;
    x = (sp) y;
!   if (xp->ptr != ADJUST_PTRFN (VPTE_SIZE, 1))
      return 11;
    if (xp->adj != ADJUST_DELTA (delta, 1))
      return 12;
Index: gcc/testsuite/g++.old-deja/g++.abi/vtable2.C
===================================================================
RCS file: /cvs/gcc/gcc/gcc/testsuite/g++.old-deja/g++.abi/vtable2.C,v
retrieving revision 1.4
diff -c -p -d -r1.4 vtable2.C
*** vtable2.C	2001/05/25 01:30:56	1.4
--- vtable2.C	2001/09/14 06:08:05
*************** void _ZN2S32s3Ev ();
*** 127,132 ****
--- 127,141 ----
  void _ZN2S42s1Ev ();
  }
  
+ // IA-64 uses function descriptors not function pointers in its vtables.
+ #if defined __ia64__
+ #define CMP_VPTR(A, B)	(*(void **)(A) == *(void **)(B))
+ #define INC_VPTR(A)	((A) += 2)
+ #else
+ #define CMP_VPTR(A, B)	(*(A) == (ptrdiff_t)(B))
+ #define INC_VPTR(A)	((A) += 1)
+ #endif
+ 
  int main ()
  {
    S4 s4;
*************** int main ()
*** 148,157 ****
      return 4;
    // Skip the RTTI entry.
    vtbl++;
!   if (*vtbl++ != (ptrdiff_t) &_ZN2S32s3Ev)
      return 5;
!   if (*vtbl++ != (ptrdiff_t) &_ZN2S42s1Ev)
      return 6;
    // The S1 vbase offset.
    if (*vtbl++ != 0)
      return 7;
--- 157,168 ----
      return 4;
    // Skip the RTTI entry.
    vtbl++;
!   if (! CMP_VPTR (vtbl, &_ZN2S32s3Ev))
      return 5;
!   INC_VPTR (vtbl);
!   if (! CMP_VPTR (vtbl, &_ZN2S42s1Ev))
      return 6;
+   INC_VPTR (vtbl);
    // The S1 vbase offset.
    if (*vtbl++ != 0)
      return 7;
*************** int main ()
*** 169,176 ****
    // Skip the RTTI entry.
    vtbl++;
    // Skip the remaining virtual functions -- they are thunks.
!   vtbl++;
!   vtbl++;
  }
  
  #else /* !(defined (__GXX_ABI_VERSION) && __GXX_ABI_VERSION >= 100) */
--- 180,187 ----
    // Skip the RTTI entry.
    vtbl++;
    // Skip the remaining virtual functions -- they are thunks.
!   INC_VPTR (vtbl);
!   INC_VPTR (vtbl);
  }
  
  #else /* !(defined (__GXX_ABI_VERSION) && __GXX_ABI_VERSION >= 100) */


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