This is the mail archive of the gdb@sources.redhat.com mailing list for the GDB project.


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

Re: C++ ptrmemfun break if FUNCTION_BOUNDARY < 2 * BITS_PER_UNIT


On Apr  6, 2001, Jim Wilson <wilson@cygnus.com> wrote:

>In article <ork84ys5bq.fsf@guarana.lsd.ic.unicamp.br> you write:

>> The C++ ABI v3 uses the least significant bit of the pfn to tell
>> non-virtual from virtual functions.

> There are also targets that use the low-order bit of the PC to determine
> processor mode.

Good point.  I think this is enough of a reason for us to have a
target configuration flag to switch between two different
representations of pointers to member functions.  I wonder how GDB is
going to be able to tell one representation from the other...  Perhaps
it's going to have to be hard-coded in GDB?

> This is also a problem for word addressable machines.  In that case, all
> bits of the address are significant, and there aren't any unused lower-bits
> that can be used by the C++ front end.

Here's the approach I propose to work around this problem.  I haven't
got to setting PTRMEMFUNC_VBIT_IN_DELTA for any targets.  Are there
any architectures supported by GCC other than MIPS and ARM that would
require this setting?  Should these be dependent on any particular
command-line flags (given that using the lowest bit of pfn is
certainly more efficient than having to shift delta)?

Is it safe to use arithmetic SHIFTs instead of letting the compiler
choose them instead of DIVs and MULTs?  For some reason, on
mn10300-elf, the div makes it to the generated code, which we
certainly don't want.

This was not thoroughly tested yet, as it's just a proposal of how to
approach the problem.  In case people agree this is the way to go,
I'll go ahead and test it on a few targets.  But something like this
should definitely go in 3.0, to avoid ABI changes in the future.

Index: gcc/ChangeLog
from  Alexandre Oliva  <aoliva@redhat.com>

	* tm.texi (PRTMEMFUNC_VBIT_IN_DELTA): Document.

Index: gcc/cp/ChangeLog
from  Alexandre Oliva  <aoliva@redhat.com>

	* cp-tree.h (ptrmemfunc_vbit_where): Declare it.
	* decl.c (ptrmemfunc_vbit_where): Define it.
	(init_decl_processing): Initialize it.
	* typeck.c (get_member_function_from_ptrfunc,
	build_ptrmemfunc, expand_ptrmemfunc_cst): Take it into account.

Index: gcc/tm.texi
===================================================================
RCS file: /cvs/gcc/egcs/gcc/tm.texi,v
retrieving revision 1.177
diff -u -p -r1.177 tm.texi
--- gcc/tm.texi 2001/04/03 15:05:32 1.177
+++ gcc/tm.texi 2001/04/09 15:05:33
@@ -1453,6 +1453,15 @@ label.
 On certain machines, it is important to have a separate label for each
 selector because this enables the linker to eliminate duplicate selectors.
 
+@findex PTRMEMFUNC_VBIT_IN_DELTA
+@item PTRMEMFUNC_VBIT_IN_DELTA
+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.  If this macro evaluates to non-zero, the C++ compiler
+will instead use the lowest bit of the delta field, and the actual delta
+will be shifted left by 1 bit.  This macro is implied if
+@code{FUNCTION_BOUNDARY} is smaller than 2 times @code{BITS_PER_UNIT}.
+
 @findex TARGET_BELL
 @item 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.594
diff -u -p -r1.594 cp-tree.h
--- gcc/cp/cp-tree.h 2001/04/06 06:33:07 1.594
+++ gcc/cp/cp-tree.h 2001/04/09 15:05:35
@@ -2667,7 +2667,20 @@ 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.  */
+extern
+enum ptrmemfunc_vbit_where_t
+{
+  ptrmemfunc_vbit_in_pfn,
+  ptrmemfunc_vbit_in_delta
+} ptrmemfunc_vbit_where;
 
 /* Get the POINTER_TYPE to the METHOD_TYPE associated with this
    pointer to member function.  TYPE_PTRMEMFUNC_P _must_ be true,
Index: gcc/cp/decl.c
===================================================================
RCS file: /cvs/gcc/egcs/gcc/cp/decl.c,v
retrieving revision 1.769
diff -u -p -r1.769 decl.c
--- gcc/cp/decl.c 2001/04/06 06:33:07 1.769
+++ gcc/cp/decl.c 2001/04/09 15:05:37
@@ -256,6 +256,9 @@ struct named_label_use_list
    in the TREE_PURPOSE slot.  */
 tree static_aggregates;
 
+/* Where to store the bit used to tell pointers to virtual from
+   non-virtual member functions.  */
+enum ptrmemfunc_vbit_where_t ptrmemfunc_vbit_where;
 /* -- end of C++ */
 
 /* A node for the integer constants 2, and 3.  */
@@ -6568,6 +6571,15 @@ init_decl_processing ()
 
   /* Show we use EH for cleanups.  */
   using_eh_for_cleanups ();
+
+  if (FUNCTION_BOUNDARY < 2 * BITS_PER_UNIT
+#ifdef PTRMEMFUNC_VBIT_IN_DELTA
+      || PTRMEMFUNC_VBIT_IN_DELTA
+#endif
+      )
+    ptrmemfunc_vbit_where = ptrmemfunc_vbit_in_delta;
+  else
+    ptrmemfunc_vbit_where = ptrmemfunc_vbit_in_pfn;
 
   valid_lang_attribute = cp_valid_lang_attribute;
 
Index: gcc/cp/typeck.c
===================================================================
RCS file: /cvs/gcc/egcs/gcc/cp/typeck.c,v
retrieving revision 1.342
diff -u -p -r1.342 typeck.c
--- gcc/cp/typeck.c 2001/03/06 20:45:05 1.342
+++ gcc/cp/typeck.c 2001/04/09 15:05:38
@@ -2872,6 +2872,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
@@ -2884,17 +2889,33 @@ 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);
+	  switch (ptrmemfunc_vbit_where)
+	    {
+	    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;
+
+	    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;
 
-      vtbl = convert_pointer_to (ptr_type_node, instance);
-      delta = cp_convert (ptrdiff_type_node,
-			  build_component_ref (function, delta_identifier,
-					       NULL_TREE, 0));
+	    default:
+	      abort ();
+	    }
+
       /* DELTA2 is the amount by which to adjust the `this' pointer
 	 to find the vtbl.  */
       delta2 = delta;
@@ -6082,6 +6103,8 @@ build_ptrmemfunc (type, pfn, force)
       npfn = build_component_ref (pfn, pfn_identifier, NULL_TREE, 0);
       delta = build_component_ref (pfn, delta_identifier, NULL_TREE, 0);
       delta = cp_convert (ptrdiff_type_node, delta);
+      if (ptrmemfunc_vbit_where == 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);
     }
@@ -6149,20 +6172,38 @@ expand_ptrmemfunc_cst (cst, delta, idx, 
       *delta = fold (build (PLUS_EXPR, TREE_TYPE (*delta),
 			    *delta, BINFO_OFFSET (binfo)));
 
-      /* Under the new ABI, we set PFN to the vtable offset, plus
-	 one, at which the function can be found.  */
-      *idx = NULL_TREE;
-      *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),
-			   *pfn));
-
       /* Offset from an object of PTR_CLASS to the vptr for ORIG_CLASS.  */
       *delta2 = fold (build (PLUS_EXPR, integer_type_node, *delta,
 			     get_vfield_offset (TYPE_BINFO (orig_class))));
+
+      /* Under the new ABI, we set PFN to the vtable offset, plus one
+	 (unless ptrmemfunc_vbit_in_delta), at which the function can
+	 be found.  */
+      *idx = NULL_TREE;
+      *pfn = DECL_VINDEX (fn);
+
+      switch (ptrmemfunc_vbit_where)
+	{
+	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 ();
+	}
+
+      *pfn = fold (build1 (NOP_EXPR, TYPE_PTRMEMFUNC_FN_TYPE (type),
+			   *pfn));
     }
 }
 

-- 
Alexandre Oliva   Enjoy Guarana', see http://www.ic.unicamp.br/~oliva/
Red Hat GCC Developer                  aoliva@{cygnus.com, redhat.com}
CS PhD student at IC-Unicamp        oliva@{lsd.ic.unicamp.br, gnu.org}
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]