This is the mail archive of the 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]

Re: ABI change for ports with byte-aligned functions.

On May 11, 2001, Mark Mitchell <> wrote:

> Yes, this is OK, with a couple of minor changes:

> There's no need to retest after making these changes, except that
> doing `make info' would be good to make sure that I didn't screw up
> the docs.

Here's the patch I'm checking in, after reverting Geoff's related

Index: gcc/ChangeLog
from  Alexandre Oliva  <>


Index: gcc/cp/ChangeLog
from  Alexandre Oliva  <>

	* cp-tree.h (ptrmemfunc_vbit_where_t): Declare type.
	* typeck.c (get_member_function_from_ptrfunc,
	build_ptrmemfunc, expand_ptrmemfunc_cst): Take

Index: gcc/defaults.h
RCS file: /cvs/gcc/egcs/gcc/defaults.h,v
retrieving revision 1.37
diff -u -p -r1.37 defaults.h
--- gcc/defaults.h 2001/05/12 06:03:19 1.37
+++ gcc/defaults.h 2001/05/12 10:38:39
@@ -325,5 +325,16 @@ do {								\
+/* By default, the C++ compiler will use the lowest bit of the pointer
+   to function to indicate a pointer-to-member-function points to a
+   virtual member function.  However, if FUNCTION_BOUNDARY indicates
+   function addresses aren't always even, the lowest bit of the delta
+   field will be used.  */
+   ? ptrmemfunc_vbit_in_pfn : ptrmemfunc_vbit_in_delta)
 #endif  /* GCC_DEFAULTS_H */
Index: gcc/tm.texi
RCS file: /cvs/gcc/egcs/gcc/tm.texi,v
retrieving revision 1.185
diff -u -p -r1.185 tm.texi
--- gcc/tm.texi 2001/05/12 06:03:20 1.185
+++ gcc/tm.texi 2001/05/12 10:38:40
@@ -1451,6 +1451,45 @@ label.
 On certain machines, it is important to have a separate label for each
 selector because this enables the linker to eliminate duplicate selectors.
+The C++ compiler represents a pointer-to-member-function with a struct
+that looks like:
+  struct @{
+    union @{
+      void (*fn)();
+      ptrdiff_t vtable_index;
+    @};
+    ptrdiff_t delta;
+  @};
+@end example
+The C++ compiler must use one bit to indicate whether the function that
+will be called through a pointer-to-member-function is virtual.
+Normally, we assume that the low-order bit of a function pointer must
+always be zero.  Then, by ensuring that the vtable_index is odd, we can
+distinguish which variant of the union is in use.  But, on some
+platforms function pointers can be odd, and so this doesn't work.  In
+that case, we use the low-order bit of the @code{delta} field, and shift
+the remainder of the @code{delta} field to the left.
+GCC will automatically make the right selection about where to store
+this bit using the @code{FUNCTION_BOUNDARY} setting for your platform.
+However, some platforms such as ARM/Thumb have @code{FUNCTION_BOUNDARY}
+set such that functions always start at even addresses, but the lowest
+bit of pointers to functions indicate whether the function at that
+address is in ARM or Thumb mode.  If this is the case of your
+architecture, you should define this macro to
+In general, you should not have to define this macro.  On architectures
+in which function addresses are always even, according to
+@code{FUNCTION_BOUNDARY}, GCC will automatically define this macro to
 @findex TARGET_BELL
 A C constant expression for the integer value for escape sequence
Index: gcc/cp/cp-tree.h
RCS file: /cvs/gcc/egcs/gcc/cp/cp-tree.h,v
retrieving revision 1.611
diff -u -p -r1.611 cp-tree.h
--- gcc/cp/cp-tree.h 2001/05/12 10:37:48 1.611
+++ gcc/cp/cp-tree.h 2001/05/12 10:38:41
@@ -2673,7 +2673,19 @@ extern int flag_new_for_scope;
    (We don't need DELTA2, because the vtable is always the first thing
    in the object.)  If the function is virtual, then PFN is one plus
    twice the index into the vtable; otherwise, it is just a pointer to
-   the function.  */
+   the function.
+   Unfortunately, using the lowest bit of PFN doesn't work in
+   architectures that don't impose alignment requirements on function
+   addresses, or that use the lowest bit to tell one ISA from another,
+   for example.  For such architectures, we use the lowest bit of
+   DELTA instead of the lowest bit of the PFN, and DELTA will be
+   multiplied by 2.  */
+enum ptrmemfunc_vbit_where_t
+  ptrmemfunc_vbit_in_pfn,
+  ptrmemfunc_vbit_in_delta
 /* Get the POINTER_TYPE to the METHOD_TYPE associated with this
    pointer to member function.  TYPE_PTRMEMFUNC_P _must_ be true,
Index: gcc/cp/typeck.c
RCS file: /cvs/gcc/egcs/gcc/cp/typeck.c,v
retrieving revision 1.347
diff -u -p -r1.347 typeck.c
--- gcc/cp/typeck.c 2001/05/12 10:37:48 1.347
+++ gcc/cp/typeck.c 2001/05/12 10:38:42
@@ -2894,6 +2894,11 @@ get_member_function_from_ptrfunc (instan
       e3 = PFN_FROM_PTRMEMFUNC (function);
+      vtbl = convert_pointer_to (ptr_type_node, instance);
+      delta = cp_convert (ptrdiff_type_node,
+			  build_component_ref (function, delta_identifier,
+					       NULL_TREE, 0));
       /* This used to avoid checking for virtual functions if basetype
 	 has no virtual functions, according to an earlier ANSI draft.
 	 With the final ISO C++ rules, such an optimization is
@@ -2906,14 +2911,31 @@ get_member_function_from_ptrfunc (instan
 	 load-with-sign-extend, while the second used normal load then
 	 shift to sign-extend.  An optimizer flaw, perhaps, but it's
 	 easier to make this change.  */
-      idx = cp_build_binary_op (TRUNC_DIV_EXPR, 
-				build1 (NOP_EXPR, vtable_index_type, e3),
-				TYPE_SIZE_UNIT (vtable_entry_type));
-      e1 = cp_build_binary_op (BIT_AND_EXPR,
-			       build1 (NOP_EXPR, vtable_index_type, e3),
-			       integer_one_node);
+	{
+	case ptrmemfunc_vbit_in_pfn:
+	  idx = cp_build_binary_op (TRUNC_DIV_EXPR, 
+				    build1 (NOP_EXPR, vtable_index_type, e3),
+				    TYPE_SIZE_UNIT (vtable_entry_type));
+	  e1 = cp_build_binary_op (BIT_AND_EXPR,
+				   build1 (NOP_EXPR, vtable_index_type, e3),
+				   integer_one_node);
+	  break;
-      vtbl = convert_pointer_to (ptr_type_node, instance);
+	case ptrmemfunc_vbit_in_delta:
+	  idx = build1 (NOP_EXPR, vtable_index_type, e3);
+	  e1 = cp_build_binary_op (BIT_AND_EXPR,
+				   delta, integer_one_node);
+	  delta = cp_build_binary_op (RSHIFT_EXPR,
+				      build1 (NOP_EXPR, vtable_index_type,
+					      delta),
+				      integer_one_node);
+	  break;
+	default:
+	  abort ();
+	}
       delta = cp_convert (ptrdiff_type_node,
 			  build_component_ref (function, delta_identifier,
 					       NULL_TREE, 0));
@@ -6085,6 +6107,8 @@ build_ptrmemfunc (type, pfn, force)
       /* Under the new ABI, the conversion is easy.  Just adjust
 	 the DELTA field.  */
       delta = cp_convert (ptrdiff_type_node, delta);
+      if (TARGET_PTRMEMFUNC_VBIT_LOCATION == ptrmemfunc_vbit_in_delta)
+	n = cp_build_binary_op (LSHIFT_EXPR, n, integer_one_node);
       delta = cp_build_binary_op (PLUS_EXPR, delta, n);
       return build_ptrmemfunc1 (to_type, delta, npfn);
@@ -6145,14 +6169,33 @@ expand_ptrmemfunc_cst (cst, delta, pfn)
       tree binfo = binfo_or_else (orig_class, fn_class);
       *delta = fold (build (PLUS_EXPR, TREE_TYPE (*delta),
 			    *delta, BINFO_OFFSET (binfo)));
+      /* Under the new ABI, we set PFN to the vtable offset at
+	 which the function can be found, plus one (unless
+	 ptrmemfunc_vbit_in_delta, in which case delta is shifted
+	 left, and then incremented).  */
+      *pfn = DECL_VINDEX (fn);
+	{
+	case ptrmemfunc_vbit_in_pfn:
+	  *pfn = fold (build (MULT_EXPR, integer_type_node, *pfn,
+			      TYPE_SIZE_UNIT (vtable_entry_type)));
+	  *pfn = fold (build (PLUS_EXPR, integer_type_node, *pfn,
+			      integer_one_node));
+	  break;
+	case ptrmemfunc_vbit_in_delta:
+	  *delta = fold (build (LSHIFT_EXPR, TREE_TYPE (*delta),
+				*delta, integer_one_node));
+	  *delta = fold (build (PLUS_EXPR, TREE_TYPE (*delta),
+				*delta, integer_one_node));
+	  break;
+	default:
+	  abort ();
+	}
-      /* Under the new ABI, we set PFN to the vtable offset, plus
-	 one, at which the function can be found.  */
-      *pfn = fold (build (MULT_EXPR, integer_type_node,
-			  DECL_VINDEX (fn), 
-			  TYPE_SIZE_UNIT (vtable_entry_type)));
-      *pfn = fold (build (PLUS_EXPR, integer_type_node, *pfn,
-			  integer_one_node));
       *pfn = fold (build1 (NOP_EXPR, TYPE_PTRMEMFUNC_FN_TYPE (type),

Alexandre Oliva   Enjoy Guarana', see
Red Hat GCC Developer                  aoliva@{,}
CS PhD student at IC-Unicamp        oliva@{,}
Free Software Evangelist    *Please* write to mailing lists, not to me

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