From 6bfa2cc1b1757ca919c796642fcb4ee2d7fe7fa7 Mon Sep 17 00:00:00 2001 From: rth Date: Fri, 21 Sep 2001 16:58:22 +0000 Subject: [PATCH] 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. git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@45733 138bc75d-0d04-0410-961f-82ee72b054a4 --- gcc/ChangeLog | 11 ++++ gcc/config/ia64/ia64.h | 18 +++++++ gcc/cp/ChangeLog | 10 ++++ gcc/cp/call.c | 2 +- gcc/cp/class.c | 48 +++++++++++++++-- gcc/cp/cp-tree.h | 1 + gcc/cp/decl2.c | 3 +- gcc/cp/typeck.c | 6 +++ gcc/defaults.h | 10 ++++ gcc/doc/tm.texi | 18 +++++++ gcc/expr.c | 5 ++ gcc/java/ChangeLog | 6 +++ gcc/java/class.c | 79 +++++++++++++++++++++++----- gcc/java/expr.c | 11 +++- gcc/testsuite/ChangeLog | 5 ++ gcc/testsuite/g++.old-deja/g++.abi/ptrmem.C | 18 +++++-- gcc/testsuite/g++.old-deja/g++.abi/vtable2.C | 19 +++++-- gcc/tree.def | 6 ++- gcc/varasm.c | 13 +++++ 19 files changed, 258 insertions(+), 31 deletions(-) diff --git a/gcc/ChangeLog b/gcc/ChangeLog index c1548ac..8aed647 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,14 @@ +2001-09-21 Richard Henderson + + * 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 diff --git a/gcc/config/ia64/ia64.h b/gcc/config/ia64/ia64.h index 737b1e7..ce8e7f1 100644 --- a/gcc/config/ia64/ia64.h +++ b/gcc/config/ia64/ia64.h @@ -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. */ diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index f5e7d63..25efd97 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,13 @@ +2001-09-21 Richard Henderson + + * 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 * decl.c (grokdeclarator): Use C syntax for attr_flags declaration. diff --git a/gcc/cp/call.c b/gcc/cp/call.c index 9caae4b..4273148 100644 --- a/gcc/cp/call.c +++ b/gcc/cp/call.c @@ -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)) diff --git a/gcc/cp/class.c b/gcc/cp/class.c index 0c106c3..ac71fc5 100644 --- a/gcc/cp/class.c +++ b/gcc/cp/class.c @@ -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 diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index 2662356..525750d 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -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)); diff --git a/gcc/cp/decl2.c b/gcc/cp/decl2.c index 28236ef..372b8ee 100644 --- a/gcc/cp/decl2.c +++ b/gcc/cp/decl2.c @@ -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; diff --git a/gcc/cp/typeck.c b/gcc/cp/typeck.c index 8a84565..54dc0ed 100644 --- a/gcc/cp/typeck.c +++ b/gcc/cp/typeck.c @@ -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); diff --git a/gcc/defaults.h b/gcc/defaults.h index 32dd3e8..f9fef20 100644 --- a/gcc/defaults.h +++ b/gcc/defaults.h @@ -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. */ diff --git a/gcc/doc/tm.texi b/gcc/doc/tm.texi index 721e161..cd4ec28 100644 --- a/gcc/doc/tm.texi +++ b/gcc/doc/tm.texi @@ -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 diff --git a/gcc/expr.c b/gcc/expr.c index b61fc17..7d23c7a 100644 --- a/gcc/expr.c +++ b/gcc/expr.c @@ -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); } diff --git a/gcc/java/ChangeLog b/gcc/java/ChangeLog index a2ba2a6..fcfb7eb 100644 --- a/gcc/java/ChangeLog +++ b/gcc/java/ChangeLog @@ -1,3 +1,9 @@ +2001-09-21 Richard Henderson + + * class.c (get_dispatch_table): Handle function descriptors. + (build_dtable_decl): Likewise. + * expr.c (build_invokevirtual): Likewise. + 2001-09-19 Alexandre Petit-Bianco * parse.h: (WFL_STRIP_BRACKET): Re-written using diff --git a/gcc/java/class.c b/gcc/java/class.c index 2e6eadf..260db75 100644 --- a/gcc/java/class.c +++ b/gcc/java/class.c @@ -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 diff --git a/gcc/java/expr.c b/gcc/java/expr.c index ff0a327..5481289 100644 --- a/gcc/java/expr.c +++ b/gcc/java/expr.c @@ -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; } diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 74508a6..ac98003 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,8 @@ +2001-09-21 Richard Henderson + + * 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 Table-driven attributes. diff --git a/gcc/testsuite/g++.old-deja/g++.abi/ptrmem.C b/gcc/testsuite/g++.old-deja/g++.abi/ptrmem.C index 6bef481..38f8177 100644 --- a/gcc/testsuite/g++.old-deja/g++.abi/ptrmem.C +++ b/gcc/testsuite/g++.old-deja/g++.abi/ptrmem.C @@ -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; diff --git a/gcc/testsuite/g++.old-deja/g++.abi/vtable2.C b/gcc/testsuite/g++.old-deja/g++.abi/vtable2.C index 5fe1e14..9847a15 100644 --- a/gcc/testsuite/g++.old-deja/g++.abi/vtable2.C +++ b/gcc/testsuite/g++.old-deja/g++.abi/vtable2.C @@ -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) */ diff --git a/gcc/tree.def b/gcc/tree.def index cd23dd3..4b155b0 100644 --- a/gcc/tree.def +++ b/gcc/tree.def @@ -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) diff --git a/gcc/varasm.c b/gcc/varasm.c index f00b596..72ec1a2 100644 --- a/gcc/varasm.c +++ b/gcc/varasm.c @@ -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: -- 2.7.4