This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
Re: ABI change for ports with byte-aligned functions.
On May 11, 2001, Mark Mitchell <mark@codesourcery.com> 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
patch:
Index: gcc/ChangeLog
from Alexandre Oliva <aoliva@redhat.com>
* defaults (TARGET_PTRMEMFUNC_VBIT_LOCATION): Define.
* tm.texi (TARGET_PRTMEMFUNC_VBIT_LOCATION): Document.
Index: gcc/cp/ChangeLog
from Alexandre Oliva <aoliva@redhat.com>
* cp-tree.h (ptrmemfunc_vbit_where_t): Declare type.
* typeck.c (get_member_function_from_ptrfunc,
build_ptrmemfunc, expand_ptrmemfunc_cst): Take
TARGET_PTRMEMFUNC_VBIT_LOCATION into account.
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 { \
#define ASM_PREFERRED_EH_DATA_FORMAT(CODE,GLOBAL) DW_EH_PE_absptr
#endif
+/* 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. */
+#ifndef TARGET_PTRMEMFUNC_VBIT_LOCATION
+#define TARGET_PTRMEMFUNC_VBIT_LOCATION \
+ (FUNCTION_BOUNDARY >= 2 * BITS_PER_UNIT \
+ ? ptrmemfunc_vbit_in_pfn : ptrmemfunc_vbit_in_delta)
+#endif
+
#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.
+@findex TARGET_PTRMEMFUNC_VBIT_LOCATION
+@item TARGET_PTRMEMFUNC_VBIT_LOCATION
+The C++ compiler represents a pointer-to-member-function with a struct
+that looks like:
+
+@example
+ struct @{
+ union @{
+ void (*fn)();
+ ptrdiff_t vtable_index;
+ @};
+ ptrdiff_t delta;
+ @};
+@end example
+
+@noindent
+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
+@code{ptrmemfunc_vbit_in_delta}.
+
+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
+@code{ptrmemfunc_vbit_in_pfn}.
+
@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.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);
+ switch (TARGET_PTRMEMFUNC_VBIT_LOCATION)
+ {
+ 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);
+
+ switch (TARGET_PTRMEMFUNC_VBIT_LOCATION)
+ {
+ 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),
*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