This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
[IFUNC]: Support overloaded IFUNC member function
- From: "H.J. Lu" <hongjiu dot lu at intel dot com>
- To: gcc-patches at gcc dot gnu dot org
- Date: Sun, 5 Jul 2009 14:58:36 -0700
- Subject: [IFUNC]: Support overloaded IFUNC member function
- Reply-to: "H.J. Lu" <hjl dot tools at gmail dot com>
I am checking in this patch into ifunc branch to support overloaded
IFUNC member function.
H.J.
----
Index: testsuite/ChangeLog.ifunc
===================================================================
--- testsuite/ChangeLog.ifunc (revision 149181)
+++ testsuite/ChangeLog.ifunc (working copy)
@@ -1,3 +1,9 @@
+2009-07-05 H.J. Lu <hongjiu.lu@intel.com>
+
+ * g++.dg/torture/ifunc-21.C: New.
+ * g++.dg/torture/ifunc-22.C: Likewise.
+ * g++.dg/torture/ifunc-23.C: Likewise.
+
2009-06-28 H.J. Lu <hongjiu.lu@intel.com>
PR c/40528
Index: testsuite/g++.dg/torture/ifunc-21.C
===================================================================
--- testsuite/g++.dg/torture/ifunc-21.C (revision 0)
+++ testsuite/g++.dg/torture/ifunc-21.C (revision 0)
@@ -0,0 +1,46 @@
+/* { dg-do compile { target i?86-*-linux* x86_64-*-linux* } } */
+/* { dg-options "-Wall -Wextra" } */
+
+class ifunc
+{
+private:
+ static int foo1 (int);
+ static int foo1 (float);
+
+public:
+ static int foo (int);
+ static int foo (float);
+};
+
+int
+__attribute__ ((ifunc))
+ifunc::foo (int)
+{
+ return &ifunc::foo1;
+}
+
+int
+__attribute__ ((ifunc))
+ifunc::foo (float)
+{
+ return &ifunc::foo1;
+}
+
+int
+bar (int x)
+{
+ return ifunc::foo (x);
+}
+
+int
+bar (float x)
+{
+ return ifunc::foo (x);
+}
+
+/* { dg-final { scan-assembler-not ".type\[ \]\+_ZN5ifunc3fooEf, .function" } } */
+/* { dg-final { scan-assembler-not ".type\[ \]\+_ZN5ifunc3fooEi, .function" } } */
+/* { dg-final { scan-assembler "(call|jmp)\[ \]\+_ZN5ifunc3fooEi" } } */
+/* { dg-final { scan-assembler "(call|jmp)\[ \]\+_ZN5ifunc3fooEf" } } */
+/* { dg-final { scan-assembler ".type\[ \]\+_ZN5ifunc3fooEi, .gnu_indirect_function" } } */
+/* { dg-final { scan-assembler ".type\[ \]\+_ZN5ifunc3fooEf, .gnu_indirect_function" } } */
Index: testsuite/g++.dg/torture/ifunc-23.C
===================================================================
--- testsuite/g++.dg/torture/ifunc-23.C (revision 0)
+++ testsuite/g++.dg/torture/ifunc-23.C (revision 0)
@@ -0,0 +1,48 @@
+/* { dg-do compile { target i?86-*-linux* x86_64-*-linux* } } */
+/* { dg-options "-Wall -Wextra" } */
+
+class ifunc
+{
+private:
+ void foo1 (int);
+ void foo1 (float);
+
+public:
+ void foo (int);
+ void foo (float);
+ void bar (int);
+ void bar (float);
+};
+
+void
+__attribute__ ((ifunc))
+ifunc::foo (int)
+{
+ return &ifunc::foo1;
+}
+
+void
+__attribute__ ((ifunc))
+ifunc::foo (float)
+{
+ return &ifunc::foo1;
+}
+
+void
+ifunc::bar (int x)
+{
+ foo (x);
+}
+
+void
+ifunc::bar (float x)
+{
+ foo (x);
+}
+
+/* { dg-final { scan-assembler-not ".type\[ \]\+_ZN5ifunc3fooEi, .function" } } */
+/* { dg-final { scan-assembler-not ".type\[ \]\+_ZN5ifunc3fooEf, .function" } } */
+/* { dg-final { scan-assembler "(call|jmp)\[ \]\+_ZN5ifunc3fooEi" } } */
+/* { dg-final { scan-assembler "(call|jmp)\[ \]\+_ZN5ifunc3fooEf" } } */
+/* { dg-final { scan-assembler ".type\[ \]\+_ZN5ifunc3fooEi, .gnu_indirect_function" } } */
+/* { dg-final { scan-assembler ".type\[ \]\+_ZN5ifunc3fooEf, .gnu_indirect_function" } } */
Index: testsuite/g++.dg/torture/ifunc-22.C
===================================================================
--- testsuite/g++.dg/torture/ifunc-22.C (revision 0)
+++ testsuite/g++.dg/torture/ifunc-22.C (revision 0)
@@ -0,0 +1,48 @@
+/* { dg-do compile { target i?86-*-linux* x86_64-*-linux* } } */
+/* { dg-options "-Wall -Wextra" } */
+
+class ifunc
+{
+private:
+ int foo1 (int);
+ int foo1 (float);
+
+public:
+ int foo (int);
+ int foo (float);
+ int bar (int);
+ int bar (float);
+};
+
+int
+__attribute__ ((ifunc))
+ifunc::foo (int)
+{
+ return &ifunc::foo1;
+}
+
+int
+__attribute__ ((ifunc))
+ifunc::foo (float)
+{
+ return &ifunc::foo1;
+}
+
+int
+ifunc::bar (int x)
+{
+ return foo (x);
+}
+
+int
+ifunc::bar (float x)
+{
+ return foo (x);
+}
+
+/* { dg-final { scan-assembler-not ".type\[ \]\+_ZN5ifunc3fooEi, .function" } } */
+/* { dg-final { scan-assembler-not ".type\[ \]\+_ZN5ifunc3fooEf, .function" } } */
+/* { dg-final { scan-assembler "(call|jmp)\[ \]\+_ZN5ifunc3fooEi" } } */
+/* { dg-final { scan-assembler "(call|jmp)\[ \]\+" } } */
+/* { dg-final { scan-assembler ".type\[ \]\+_ZN5ifunc3fooEi, .gnu_indirect_function" } } */
+/* { dg-final { scan-assembler ".type\[ \]\+_ZN5ifunc3fooEf, .gnu_indirect_function" } } */
Index: cp/typeck.c
===================================================================
--- cp/typeck.c (revision 149181)
+++ cp/typeck.c (working copy)
@@ -4786,6 +4786,17 @@ cp_build_unary_op (enum tree_code code,
if (TREE_CODE (argtype) == POINTER_TYPE
&& TREE_CODE (TREE_TYPE (argtype)) == METHOD_TYPE)
{
+ if (current_function_decl != NULL
+ && DECL_IS_IFUNC (current_function_decl)
+ && DECL_NONSTATIC_MEMBER_FUNCTION_P (current_function_decl)
+ && (TYPE_MAIN_VARIANT (argtype)
+ == TYPE_MAIN_VARIANT (function_return_type (current_function_decl))))
+ {
+ /* IFUNC member function returns the address of another
+ non-static member function. */
+ return val;
+ }
+
build_ptrmemfunc_type (argtype);
val = build_ptrmemfunc (argtype, val, 0,
/*c_cast_p=*/false);
Index: cp/class.c
===================================================================
--- cp/class.c (revision 149181)
+++ cp/class.c (working copy)
@@ -5992,17 +5992,24 @@ resolve_address_of_overloaded_function (
int is_ptrmem = 0;
int is_reference = 0;
+ int is_ifunc;
/* We store the matches in a TREE_LIST rooted here. The functions
are the TREE_PURPOSE, not the TREE_VALUE, in this list, for easy
interoperability with most_specialized_instantiation. */
tree matches = NULL_TREE;
tree fn;
+ is_ifunc = (current_function_decl != NULL
+ && DECL_IS_IFUNC (current_function_decl)
+ && DECL_NONSTATIC_MEMBER_FUNCTION_P (current_function_decl));
+
/* By the time we get here, we should be seeing only real
pointer-to-member types, not the internal POINTER_TYPE to
- METHOD_TYPE representation. */
+ METHOD_TYPE representation unless it is in an IFUNC member
+ function. */
gcc_assert (TREE_CODE (target_type) != POINTER_TYPE
- || TREE_CODE (TREE_TYPE (target_type)) != METHOD_TYPE);
+ || TREE_CODE (TREE_TYPE (target_type)) != METHOD_TYPE
+ || is_ifunc);
gcc_assert (is_overloaded_fn (overload));
@@ -6019,6 +6026,8 @@ resolve_address_of_overloaded_function (
target_type = build_reference_type (target_type);
is_reference = 1;
}
+ else if (is_ifunc && TYPE_PTRMEMIFUNC_P (target_type))
+ /* This is OK. */;
else
{
if (flags & tf_error)
@@ -6046,7 +6055,7 @@ resolve_address_of_overloaded_function (
continue;
if ((TREE_CODE (TREE_TYPE (fn)) == METHOD_TYPE)
- != is_ptrmem)
+ != (is_ptrmem | is_ifunc))
/* We're looking for a non-static member, and this isn't
one, or vice versa. */
continue;
@@ -6250,7 +6259,9 @@ resolve_address_of_overloaded_function (
perform_or_defer_access_check (access_path, fn, fn);
}
- if (TYPE_PTRFN_P (target_type) || TYPE_PTRMEMFUNC_P (target_type))
+ if (TYPE_PTRFN_P (target_type)
+ || TYPE_PTRMEMFUNC_P (target_type)
+ || (is_ifunc && TYPE_PTRMEMIFUNC_P (target_type)))
return cp_build_unary_op (ADDR_EXPR, fn, 0, flags);
else
{
Index: cp/call.c
===================================================================
--- cp/call.c (revision 149181)
+++ cp/call.c (working copy)
@@ -710,7 +710,12 @@ standard_conversion (tree to, tree from,
to = strip_top_quals (to);
from = strip_top_quals (from);
- if ((TYPE_PTRFN_P (to) || TYPE_PTRMEMFUNC_P (to))
+ if ((TYPE_PTRFN_P (to)
+ || TYPE_PTRMEMFUNC_P (to)
+ || (current_function_decl != NULL
+ && DECL_IS_IFUNC (current_function_decl)
+ && DECL_NONSTATIC_MEMBER_FUNCTION_P (current_function_decl)
+ && TYPE_PTRMEMIFUNC_P (to)))
&& expr && type_unknown_p (expr))
{
tsubst_flags_t tflags = tf_conv;
Index: cp/cp-tree.h
===================================================================
--- cp/cp-tree.h (revision 149181)
+++ cp/cp-tree.h (working copy)
@@ -2909,6 +2909,12 @@ more_aggr_init_expr_args_p (const aggr_i
(TREE_CODE (NODE) == REFERENCE_TYPE \
&& TREE_CODE (TREE_TYPE (NODE)) == FUNCTION_TYPE)
+/* Returns true if NODE is a pointer to a member function inside
+ the IFUNC function body. */
+#define TYPE_PTRMEMIFUNC_P(NODE) \
+ (TREE_CODE (NODE) == POINTER_TYPE \
+ && TREE_CODE (TREE_TYPE (NODE)) == METHOD_TYPE)
+
/* Nonzero for _TYPE node means that this type is a pointer to member
function type. */
#define TYPE_PTRMEMFUNC_P(NODE) \
Index: cp/ChangeLog.ifunc
===================================================================
--- cp/ChangeLog.ifunc (revision 149181)
+++ cp/ChangeLog.ifunc (working copy)
@@ -1,3 +1,13 @@
+2009-07-05 H.J. Lu <hongjiu.lu@intel.com>
+
+ * call.c (standard_conversion): Support IFUNC member function.
+ * class.c (resolve_address_of_overloaded_function): Likewise.
+
+ * cp-tree.h (TYPE_PTRMEMIFUNC_P): New.
+
+ * typeck.c (cp_build_unary_op): Take the address of non-static
+ overloaded member function for IFUNC member function.
+
2009-06-28 H.J. Lu <hongjiu.lu@intel.com>
PR c/40528