tree.def (FDESC_EXPR): New.

gcc/
        * tree.def (FDESC_EXPR): New.
        * expr.c (expand_expr): Handle it.
        * varasm.c (initializer_constant_valid_p): Likewise.
        (output_constant): Likewise.
        * defaults.h (TARGET_VTABLE_USES_DESCRIPTORS): New.
        * config/ia64/ia64.h (TARGET_VTABLE_USES_DESCRIPTORS): New.
        (ASM_OUTPUT_FDESC): New.
        * doc/tm.texi: Document the new macros.
gcc/cp/
        * class.c (set_vindex): Mind TARGET_VTABLE_USES_DESCRIPTORS.
        (build_vtbl_initializer): Likewise.
        (build_vfn_ref): New.
        * cp-tree.h: Declare it.
        * call.c (build_over_call): Use it.
        * decl2.c (mark_vtable_entries): Mark FDESC_EXPR.
        * typeck.c (get_member_function_from_ptrfunc): Mind descriptors.
gcc/java/
        * class.c (get_dispatch_table): Handle function descriptors.
        (build_dtable_decl): Likewise.
        * expr.c (build_invokevirtual): Likewise.
gcc/testsuite/
        * g++.old-deja/g++.abi/ptrmem.C: Update for ia64 c++ abi.
        * g++.old-deja/g++.abi/vtable2.C: Likewise.

From-SVN: r45733
This commit is contained in:
Richard Henderson 2001-09-21 09:58:22 -07:00 committed by Richard Henderson
parent 2e3b2d2c07
commit 6723181663
19 changed files with 258 additions and 31 deletions

View file

@ -1,3 +1,14 @@
2001-09-21 Richard Henderson <rth@redhat.com>
* tree.def (FDESC_EXPR): New.
* expr.c (expand_expr): Handle it.
* varasm.c (initializer_constant_valid_p): Likewise.
(output_constant): Likewise.
* defaults.h (TARGET_VTABLE_USES_DESCRIPTORS): New.
* config/ia64/ia64.h (TARGET_VTABLE_USES_DESCRIPTORS): New.
(ASM_OUTPUT_FDESC): New.
* doc/tm.texi: Document the new macros.
21-09-2001 Richard Earnshaw (reanrsha@arm.com)
* cfgcleanup.c (merge_blocks_move_successor_nojumps): Don't leave

View file

@ -416,6 +416,13 @@ while (0)
/* 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 */
@ -1534,6 +1541,17 @@ do { \
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. */

View file

@ -1,3 +1,13 @@
2001-09-21 Richard Henderson <rth@redhat.com>
* class.c (set_vindex): Mind TARGET_VTABLE_USES_DESCRIPTORS.
(build_vtbl_initializer): Likewise.
(build_vfn_ref): New.
* cp-tree.h: Declare it.
* call.c (build_over_call): Use it.
* decl2.c (mark_vtable_entries): Mark FDESC_EXPR.
* typeck.c (get_member_function_from_ptrfunc): Mind descriptors.
Fri Sep 21 08:16:19 2001 J"orn Rennecke <amylaar@redhat.com>
* decl.c (grokdeclarator): Use C syntax for attr_flags declaration.

View file

@ -4321,7 +4321,7 @@ build_over_call (cand, args, flags)
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));
fn = build_vfn_ref (build_indirect_ref (*p, 0), DECL_VINDEX (fn));
TREE_TYPE (fn) = t;
}
else if (DECL_INLINE (fn))

View file

@ -459,9 +459,9 @@ build_vtable_entry_ref (basetype, idx)
}
/* 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. */
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)
@ -543,6 +543,24 @@ build_vtbl_ref (instance, idx)
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. */
@ -823,7 +841,9 @@ set_vindex (decl, vfuns_p)
{
int vindex;
vindex = (*vfuns_p)++;
vindex = *vfuns_p;
*vfuns_p += (TARGET_VTABLE_USES_DESCRIPTORS
? TARGET_VTABLE_USES_DESCRIPTORS : 1);
DECL_VINDEX (decl) = build_shared_int_cst (vindex);
}
@ -7587,7 +7607,25 @@ build_vtbl_initializer (binfo, orig_binfo, t, rtti_binfo, non_fn_entries_p)
}
/* And add it to the chain of initializers. */
vfun_inits = tree_cons (NULL_TREE, init, vfun_inits);
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

View file

@ -3527,6 +3527,7 @@ extern tree perform_implicit_conversion PARAMS ((tree, tree));
/* 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));

View file

@ -2168,7 +2168,8 @@ mark_vtable_entries (decl)
tree fnaddr = TREE_VALUE (entries);
tree fn;
if (TREE_CODE (fnaddr) != ADDR_EXPR)
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;

View file

@ -2910,6 +2910,12 @@ get_member_function_from_ptrfunc (instance_ptrptr, function)
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);

View file

@ -358,6 +358,16 @@ do { \
#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. */

View file

@ -1597,6 +1597,18 @@ 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_VTABLE_USES_DESCRIPTORS
@item TARGET_VTABLE_USES_DESCRIPTORS
Normally, the C++ compiler uses function pointers in vtables. This
macro allows the target to change to use ``function descriptors''
instead. Function descriptors are found on targets for whom a
function pointer is actually a small data structure. Normally the
data structure consists of the actual code address plus a data
pointer to which the function's data is relative.
If vtables are used, the value of this macro should be the number
of words that the function descriptor occupies.
@end table
@node Escape Sequences
@ -6012,6 +6024,12 @@ If the assembler has a @code{.ascii} pseudo-op as found in the
Berkeley Unix assembler, do not define the macro
@code{ASM_OUTPUT_ASCII}.
@findex ASM_OUTPUT_FDESC
@item ASM_OUTPUT_FDESC (@var{stream}, @var{decl}, @var{n})
A C statement to output word @var{n} of a function descriptor for
@var{decl}. This must be defined if @code{TARGET_VTABLE_USES_DESCRIPTORS}
is defined, and is otherwise unused.
@findex CONSTANT_POOL_BEFORE_FUNCTION
@item CONSTANT_POOL_BEFORE_FUNCTION
You may define this macro as a C expression. You should define the

View file

@ -8757,6 +8757,11 @@ expand_expr (exp, target, tmode, modifier)
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);
}

View file

@ -1,3 +1,9 @@
2001-09-21 Richard Henderson <rth@redhat.com>
* class.c (get_dispatch_table): Handle function descriptors.
(build_dtable_decl): Likewise.
* expr.c (build_invokevirtual): Likewise.
2001-09-19 Alexandre Petit-Bianco <apbianco@redhat.com>
* parse.h: (WFL_STRIP_BRACKET): Re-written using

View file

@ -1372,9 +1372,11 @@ get_dispatch_table (type, this_class_addr)
{
int abstract_p = CLASS_ABSTRACT (TYPE_NAME (type));
tree vtable = get_dispatch_vector (type);
int i;
int i, j;
tree list = NULL_TREE;
int nvirtuals = TREE_VEC_LENGTH (vtable);
int arraysize;
for (i = nvirtuals; --i >= 0; )
{
tree method = TREE_VEC_ELT (vtable, i);
@ -1383,27 +1385,52 @@ get_dispatch_table (type, this_class_addr)
if (! abstract_p)
warning_with_decl (method,
"abstract method in non-abstract class");
method = null_pointer_node;
if (TARGET_VTABLE_USES_DESCRIPTORS)
for (j = 0; j < TARGET_VTABLE_USES_DESCRIPTORS; ++j)
list = tree_cons (NULL_TREE, null_pointer_node, list);
else
list = tree_cons (NULL_TREE, null_pointer_node, list);
}
else
{
if (!DECL_RTL_SET_P (method))
make_decl_rtl (method, NULL);
method = build1 (ADDR_EXPR, nativecode_ptr_type_node, method);
if (TARGET_VTABLE_USES_DESCRIPTORS)
for (j = 0; j < TARGET_VTABLE_USES_DESCRIPTORS; ++j)
{
tree fdesc = build (FDESC_EXPR, nativecode_ptr_type_node,
method, build_int_2 (j, 0));
TREE_CONSTANT (fdesc) = 1;
list = tree_cons (NULL_TREE, fdesc, list);
}
else
list = tree_cons (NULL_TREE,
build1 (ADDR_EXPR, nativecode_ptr_type_node,
method),
list);
}
list = tree_cons (NULL_TREE /*DECL_VINDEX (method) + 2*/,
method, list);
}
/* Dummy entry for compatibility with G++ -fvtable-thunks. When
using the Boehm GC we sometimes stash a GC type descriptor
there. We set the PURPOSE to NULL_TREE not to interfere (reset)
the emitted byte count during the output to the assembly file. */
list = tree_cons (NULL_TREE, get_boehm_type_descriptor (type),
list);
for (j = 1; j < TARGET_VTABLE_USES_DESCRIPTORS; ++j)
list = tree_cons (NULL_TREE, null_pointer_node, list);
list = tree_cons (NULL_TREE, get_boehm_type_descriptor (type), list);
for (j = 1; j < TARGET_VTABLE_USES_DESCRIPTORS; ++j)
list = tree_cons (NULL_TREE, null_pointer_node, list);
list = tree_cons (integer_zero_node, this_class_addr, list);
return build (CONSTRUCTOR, build_prim_array_type (nativecode_ptr_type_node,
nvirtuals + 2),
NULL_TREE, list);
arraysize = nvirtuals + 2;
if (TARGET_VTABLE_USES_DESCRIPTORS)
arraysize *= TARGET_VTABLE_USES_DESCRIPTORS;
return build (CONSTRUCTOR,
build_prim_array_type (nativecode_ptr_type_node, arraysize),
NULL_TREE, list);
}
void
@ -1733,13 +1760,37 @@ build_dtable_decl (type)
TYPE. */
if (current_class == type)
{
tree dummy = NULL_TREE, aomt, n;
tree dummy = NULL_TREE;
int n;
dtype = make_node (RECORD_TYPE);
PUSH_FIELD (dtype, dummy, "class", class_ptr_type);
n = build_int_2 (TREE_VEC_LENGTH (get_dispatch_vector (type)), 0);
aomt = build_array_type (ptr_type_node, build_index_type (n));
PUSH_FIELD (dtype, dummy, "methods", aomt);
for (n = 1; n < TARGET_VTABLE_USES_DESCRIPTORS; ++n)
{
tree tmp_field = build_decl (FIELD_DECL, NULL_TREE, ptr_type_node);
TREE_CHAIN (dummy) = tmp_field;
DECL_CONTEXT (tmp_field) = dtype;
DECL_ARTIFICIAL (tmp_field) = 1;
dummy = tmp_field;
}
PUSH_FIELD (dtype, dummy, "gc_descr", ptr_type_node);
for (n = 1; n < TARGET_VTABLE_USES_DESCRIPTORS; ++n)
{
tree tmp_field = build_decl (FIELD_DECL, NULL_TREE, ptr_type_node);
TREE_CHAIN (dummy) = tmp_field;
DECL_CONTEXT (tmp_field) = dtype;
DECL_ARTIFICIAL (tmp_field) = 1;
dummy = tmp_field;
}
n = TREE_VEC_LENGTH (get_dispatch_vector (type));
if (TARGET_VTABLE_USES_DESCRIPTORS)
n *= TARGET_VTABLE_USES_DESCRIPTORS;
PUSH_FIELD (dtype, dummy, "methods",
build_prim_array_type (nativecode_ptr_type_node, n));
layout_type (dtype);
}
else

View file

@ -1845,9 +1845,18 @@ build_invokevirtual (dtable, method)
method_index = size_binop (PLUS_EXPR, method_index, size_int (2));
method_index = size_binop (MULT_EXPR, method_index,
TYPE_SIZE_UNIT (nativecode_ptr_ptr_type_node));
if (TARGET_VTABLE_USES_DESCRIPTORS)
method_index = size_binop (MULT_EXPR, method_index,
size_int (TARGET_VTABLE_USES_DESCRIPTORS));
func = fold (build (PLUS_EXPR, nativecode_ptr_ptr_type_node, dtable,
convert (nativecode_ptr_ptr_type_node, method_index)));
func = build1 (INDIRECT_REF, nativecode_ptr_type_node, func);
if (TARGET_VTABLE_USES_DESCRIPTORS)
func = build1 (NOP_EXPR, nativecode_ptr_type_node, func);
else
func = build1 (INDIRECT_REF, nativecode_ptr_type_node, func);
return func;
}

View file

@ -1,3 +1,8 @@
2001-09-21 Richard Henderson <rth@redhat.com>
* g++.old-deja/g++.abi/ptrmem.C: Update for ia64 c++ abi.
* g++.old-deja/g++.abi/vtable2.C: Likewise.
2001-09-21 Joseph S. Myers <jsm28@cam.ac.uk>
Table-driven attributes.

View file

@ -14,6 +14,16 @@
#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.
@ -85,12 +95,12 @@ main ()
// 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))
if (! CMP_PTRFN (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))
if (! CMP_PTRFN (xp->ptr, ADJUST_PTRFN (&_ZN1T1fEv, 0)))
return 7;
if (xp->adj != ADJUST_DELTA (delta, 0))
return 8;
@ -99,12 +109,12 @@ main ()
// 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))
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 (sizeof (void *), 1))
if (xp->ptr != ADJUST_PTRFN (VPTE_SIZE, 1))
return 11;
if (xp->adj != ADJUST_DELTA (delta, 1))
return 12;

View file

@ -127,6 +127,15 @@ void _ZN2S32s3Ev ();
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;
@ -148,10 +157,12 @@ int main ()
return 4;
// Skip the RTTI entry.
vtbl++;
if (*vtbl++ != (ptrdiff_t) &_ZN2S32s3Ev)
if (! CMP_VPTR (vtbl, &_ZN2S32s3Ev))
return 5;
if (*vtbl++ != (ptrdiff_t) &_ZN2S42s1Ev)
INC_VPTR (vtbl);
if (! CMP_VPTR (vtbl, &_ZN2S42s1Ev))
return 6;
INC_VPTR (vtbl);
// The S1 vbase offset.
if (*vtbl++ != 0)
return 7;
@ -169,8 +180,8 @@ int main ()
// Skip the RTTI entry.
vtbl++;
// Skip the remaining virtual functions -- they are thunks.
vtbl++;
vtbl++;
INC_VPTR (vtbl);
INC_VPTR (vtbl);
}
#else /* !(defined (__GXX_ABI_VERSION) && __GXX_ABI_VERSION >= 100) */

View file

@ -716,9 +716,13 @@ DEFTREECODE (ADDR_EXPR, "addr_expr", 'e', 1)
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. */
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. */
DEFTREECODE (COMPLEX_EXPR, "complex_expr", '2', 2)

View file

@ -4277,6 +4277,7 @@ initializer_constant_valid_p (value, endtype)
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:
@ -4469,6 +4470,18 @@ output_constant (exp, size, align)
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;
}
switch (code)
{
case CHAR_TYPE: