Patch Detail
get:
Show a patch.
patch:
Update a patch.
put:
Update a patch.
GET /api/1.1/patches/2224765/?format=api
{ "id": 2224765, "url": "http://patchwork.ozlabs.org/api/1.1/patches/2224765/?format=api", "web_url": "http://patchwork.ozlabs.org/project/gcc/patch/3fe70005e9f2b334bc18674ea5d38349d10b458f.camel@tugraz.at/", "project": { "id": 17, "url": "http://patchwork.ozlabs.org/api/1.1/projects/17/?format=api", "name": "GNU Compiler Collection", "link_name": "gcc", "list_id": "gcc-patches.gcc.gnu.org", "list_email": "gcc-patches@gcc.gnu.org", "web_url": null, "scm_url": null, "webscm_url": null }, "msgid": "<3fe70005e9f2b334bc18674ea5d38349d10b458f.camel@tugraz.at>", "date": "2026-04-18T10:44:12", "name": "[RFC,C,v2] Built-in to access code pointer and static chain of nested function", "commit_ref": null, "pull_url": null, "state": "new", "archived": false, "hash": "fdd3d97bc0b6c6ffd5d812b313eede69b4f28844", "submitter": { "id": 85465, "url": "http://patchwork.ozlabs.org/api/1.1/people/85465/?format=api", "name": "Martin Uecker", "email": "uecker@tugraz.at" }, "delegate": null, "mbox": "http://patchwork.ozlabs.org/project/gcc/patch/3fe70005e9f2b334bc18674ea5d38349d10b458f.camel@tugraz.at/mbox/", "series": [ { "id": 500436, "url": "http://patchwork.ozlabs.org/api/1.1/series/500436/?format=api", "web_url": "http://patchwork.ozlabs.org/project/gcc/list/?series=500436", "date": "2026-04-18T10:44:12", "name": "[RFC,C,v2] Built-in to access code pointer and static chain of nested function", "version": 2, "mbox": "http://patchwork.ozlabs.org/series/500436/mbox/" } ], "comments": "http://patchwork.ozlabs.org/api/patches/2224765/comments/", "check": "pending", "checks": "http://patchwork.ozlabs.org/api/patches/2224765/checks/", "tags": {}, "headers": { "Return-Path": "<gcc-patches-bounces~incoming=patchwork.ozlabs.org@gcc.gnu.org>", "X-Original-To": [ "incoming@patchwork.ozlabs.org", "gcc-patches@gcc.gnu.org" ], "Delivered-To": [ "patchwork-incoming@legolas.ozlabs.org", "gcc-patches@gcc.gnu.org" ], "Authentication-Results": [ "legolas.ozlabs.org;\n\tdkim=pass (1024-bit key;\n unprotected) header.d=tugraz.at header.i=@tugraz.at header.a=rsa-sha256\n header.s=mailrelay header.b=GLB2gmAk;\n\tdkim-atps=neutral", "legolas.ozlabs.org;\n spf=pass (sender SPF authorized) smtp.mailfrom=gcc.gnu.org\n (client-ip=38.145.34.32; helo=vm01.sourceware.org;\n envelope-from=gcc-patches-bounces~incoming=patchwork.ozlabs.org@gcc.gnu.org;\n receiver=patchwork.ozlabs.org)", "sourceware.org;\n\tdkim=pass (1024-bit key,\n unprotected) header.d=tugraz.at header.i=@tugraz.at header.a=rsa-sha256\n header.s=mailrelay header.b=GLB2gmAk", "sourceware.org; dmarc=pass (p=quarantine dis=none)\n header.from=tugraz.at", "sourceware.org; spf=pass smtp.mailfrom=tugraz.at", "server2.sourceware.org;\n arc=none smtp.remote-ip=129.27.2.202" ], "Received": [ "from vm01.sourceware.org (vm01.sourceware.org [38.145.34.32])\n\t(using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits)\n\t key-exchange x25519 server-signature ECDSA (secp384r1) server-digest SHA384)\n\t(No client certificate requested)\n\tby legolas.ozlabs.org (Postfix) with ESMTPS id 4fyT0c3FGfz1yCv\n\tfor <incoming@patchwork.ozlabs.org>; Sat, 18 Apr 2026 20:45:03 +1000 (AEST)", "from vm01.sourceware.org (localhost [127.0.0.1])\n\tby sourceware.org (Postfix) with ESMTP id 8CD824AA394F\n\tfor <incoming@patchwork.ozlabs.org>; Sat, 18 Apr 2026 10:44:59 +0000 (GMT)", "from mailrelay.tugraz.at (mailrelay.tugraz.at [129.27.2.202])\n by sourceware.org (Postfix) with ESMTPS id 9704E4AA394F\n for <gcc-patches@gcc.gnu.org>; Sat, 18 Apr 2026 10:44:28 +0000 (GMT)", "from vra-172-68.tugraz.at (vra-172-68.tugraz.at [129.27.172.68])\n by mailrelay.tugraz.at (Postfix) with ESMTPSA id 4fySzd1l8Vz9rxN;\n Sat, 18 Apr 2026 12:44:13 +0200 (CEST)" ], "DKIM-Filter": [ "OpenDKIM Filter v2.11.0 sourceware.org 8CD824AA394F", "OpenDKIM Filter v2.11.0 sourceware.org 9704E4AA394F" ], "DMARC-Filter": "OpenDMARC Filter v1.4.2 sourceware.org 9704E4AA394F", "ARC-Filter": "OpenARC Filter v1.0.0 sourceware.org 9704E4AA394F", "ARC-Seal": "i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1776509070; cv=none;\n b=Ie0DqCBWO/fR4vIHBYOUGiE8V0Os8wSeGMQ6D03wJnG6+ZN9uhVBwT10EQSRyo0TwDG0+WDOvQ6H1Y2zCJf8/VlRx2Y4FwUCP7zEdt4ZSMPLDo3oyZfDbvxJIyHzsmVwu+GdqP5YDqQOhhcr5Ph47p+7/qbwxkkwo39H5HK9Hbo=", "ARC-Message-Signature": "i=1; a=rsa-sha256; d=sourceware.org; s=key;\n t=1776509070; c=relaxed/simple;\n bh=ZSOiLznSbHeebJ3l0m+SLrGqNrka3np0urDwXfxw4J0=;\n h=DKIM-Signature:Message-ID:Subject:From:To:Date:MIME-Version;\n b=FMw/FhrfT/F7ARAopnv1omIbA6/6dPk4QJ+NqWIrxlT98U6Cs2I98+5gEChJXj6B6anQGAbmKP0WY0V+xjbdGei1TMOXGiumUahJAv9nTBTMOBqmZmrxYFnsWuork3ZzDaArF463t3cySB/qQBmEdtF848hobG9USkaFmaIcKcg=", "ARC-Authentication-Results": "i=1; server2.sourceware.org", "DKIM-Signature": "v=1; a=rsa-sha256; c=relaxed/relaxed; d=tugraz.at;\n s=mailrelay; t=1776509053;\n bh=usWo/AFHhXqnHjbH12SRZUbXBQlketi9JgXeIAxp+L0=;\n h=Subject:From:To:Cc:Date;\n b=GLB2gmAk6kcaG+4ZuZW++LyIJNJicVZBM5H5EQTzDw4IuPaOKl56jnHrGXgXEZwgj\n TlLB6S3YzN5ZZLB2jzHeNf4tgI1PmaomCFnvcRE2Mnbm0lEul2SjUUyuZsJ9VGLktG\n EesYWsTb0mzljcFzlwwi7cDgV2195RwBC2ix77/k=", "Message-ID": "<3fe70005e9f2b334bc18674ea5d38349d10b458f.camel@tugraz.at>", "Subject": "[RFC C PATCH v2] Built-in to access code pointer and static chain\n of nested function", "From": "Martin Uecker <uecker@tugraz.at>", "To": "gcc-patches@gcc.gnu.org", "Cc": "Joseph Myers <josmyers@redhat.com>, Richard Biener <rguenther@suse.de>,\n Andrew Pinski <andrew.pinski@oss.qualcomm.com>, Jakub Jelinek\n <jakub@redhat.com>", "Date": "Sat, 18 Apr 2026 12:44:12 +0200", "Content-Type": "text/plain; charset=\"UTF-8\"", "Content-Transfer-Encoding": "quoted-printable", "User-Agent": "Evolution 3.56.2-0+deb13u1 ", "MIME-Version": "1.0", "X-TUG-Backscatter-control": "G/VXY7/6zeyuAY/PU2/0qw", "X-Scanned-By": "MIMEDefang 2.74 on 129.27.10.117", "X-BeenThere": "gcc-patches@gcc.gnu.org", "X-Mailman-Version": "2.1.30", "Precedence": "list", "List-Id": "Gcc-patches mailing list <gcc-patches.gcc.gnu.org>", "List-Unsubscribe": "<https://gcc.gnu.org/mailman/options/gcc-patches>,\n <mailto:gcc-patches-request@gcc.gnu.org?subject=unsubscribe>", "List-Archive": "<https://gcc.gnu.org/pipermail/gcc-patches/>", "List-Post": "<mailto:gcc-patches@gcc.gnu.org>", "List-Help": "<mailto:gcc-patches-request@gcc.gnu.org?subject=help>", "List-Subscribe": "<https://gcc.gnu.org/mailman/listinfo/gcc-patches>,\n <mailto:gcc-patches-request@gcc.gnu.org?subject=subscribe>", "Errors-To": "gcc-patches-bounces~incoming=patchwork.ozlabs.org@gcc.gnu.org" }, "content": "This is how this patch could look like with a single builtin that returns\nan anonymous structure. I named it __builtin_call_info which might be a bit\nnicer in combination with __builtin_call_with_static_chain. I also now fold\nthis in gimple-fold.cc for the trivial case where there is no static\nchain.\n\nBootstrapped and regression tested on x86_64. No AI was used.\n\nBest,\nMartin\n\n\n\n\n\n c: Built-in to access code pointer and static chain of nested function.\n \n This patch adds a new built-in, __builtin_call_info, to extract the code\n pointer and the static chain pointer from a (nested) function. Those can\n then be used to call the nested function using the existing built-in\n __builtin_call_with_static_chain. This feature can be used to avoid the\n creation of trampolines and often allows writing more efficient\n code, e.g. when trampolines prevent devirtualization (PR49666).\n \n gcc/ChangeLog:\n * builtins.def: Add new built-in.\n * builtin-types.def: Add new call info type.\n * tree.h: Add new call info type.\n * tree-core.h: Add new call info type.\n * tree.cc (build_common_tree_nodes): Build new call info type node.\n * builtins.cc (expand_builtin): Mark new case as unreachable.\n (is_simple_builtin): Add new built-in.\n * gimple-fold.cc (gimple_fold_builtin_call_info): New function.\n (gimple_fold_builtin) Expand new built-in for non-nested functions.\n * tree-nested.cc (convert_tramp_reference_stmt): Ingore new built-in.\n (convert_gimple_call): Expand built-in for nested functions.\n * tree-inline.cc (initialize_inlined_parameters): Replace\n assertion with error.\n \n gcc/doc/ChangeLog:\n * extend.texi: Document new built-in.\n \n gcc/testsuite/ChangeLog:\n * gcc.dg/builtin-call-info-1.c: New test.\n * gcc.dg/builtin-call-info-2.c: New test.\n * gcc.dg/builtin-call-info-3.c: New test.", "diff": "diff --git a/gcc/builtin-types.def b/gcc/builtin-types.def\nindex ab0cbc65cfc..1ca220d1ce1 100644\n--- a/gcc/builtin-types.def\n+++ b/gcc/builtin-types.def\n@@ -209,6 +209,8 @@ DEF_PRIMITIVE_TYPE (BT_DFLOAT64X, (dfloat64x_type_node\n DEF_PRIMITIVE_TYPE (BT_VALIST_REF, va_list_ref_type_node)\n DEF_PRIMITIVE_TYPE (BT_VALIST_ARG, va_list_arg_type_node)\n \n+DEF_PRIMITIVE_TYPE (BT_CALL_INFO, call_info_type_node)\n+\n DEF_PRIMITIVE_TYPE (BT_I1, builtin_type_for_size (BITS_PER_UNIT*1, 1))\n DEF_PRIMITIVE_TYPE (BT_I2, builtin_type_for_size (BITS_PER_UNIT*2, 1))\n DEF_PRIMITIVE_TYPE (BT_I4, builtin_type_for_size (BITS_PER_UNIT*4, 1))\n@@ -425,6 +427,7 @@ DEF_FUNCTION_TYPE_1 (BT_FN_UINT16_UINT32, BT_UINT16, BT_UINT32)\n DEF_FUNCTION_TYPE_1 (BT_FN_UINT32_UINT16, BT_UINT32, BT_UINT16)\n DEF_FUNCTION_TYPE_1 (BT_FN_INT_FENV_T_PTR, BT_INT, BT_FENV_T_PTR)\n DEF_FUNCTION_TYPE_1 (BT_FN_INT_CONST_FENV_T_PTR, BT_INT, BT_CONST_FENV_T_PTR)\n+DEF_FUNCTION_TYPE_1 (BT_FN_CALL_INFO_PTR, BT_CALL_INFO, BT_PTR)\n \n DEF_POINTER_TYPE (BT_PTR_FN_VOID_PTR, BT_FN_VOID_PTR)\n \ndiff --git a/gcc/builtins.cc b/gcc/builtins.cc\nindex 692e20088c2..efef8afce69 100644\n--- a/gcc/builtins.cc\n+++ b/gcc/builtins.cc\n@@ -8093,6 +8093,9 @@ expand_builtin (tree exp, rtx target, rtx subtarget, machine_mode mode,\n \texpand_builtin_return (expand_normal (CALL_EXPR_ARG (exp, 0)));\n return const0_rtx;\n \n+ case BUILT_IN_CALL_INFO:\n+ gcc_unreachable ();\n+\n case BUILT_IN_SAVEREGS:\n return expand_builtin_saveregs ();\n \n@@ -12311,6 +12314,7 @@ is_simple_builtin (tree decl)\n case BUILT_IN_STACK_SAVE:\n case BUILT_IN_STACK_RESTORE:\n case BUILT_IN_DWARF_CFA:\n+ case BUILT_IN_CALL_INFO:\n \t/* Exception state returns or moves registers around. */\n case BUILT_IN_EH_FILTER:\n case BUILT_IN_EH_POINTER:\ndiff --git a/gcc/builtins.def b/gcc/builtins.def\nindex 8ab0599b17f..1d5bff152e3 100644\n--- a/gcc/builtins.def\n+++ b/gcc/builtins.def\n@@ -1164,6 +1164,9 @@ DEF_BUILTIN_STUB (BUILT_IN_NONLOCAL_GOTO, \"__builtin_nonlocal_goto\")\n DEF_EXT_LIB_BUILTIN (BUILT_IN_GCC_NESTED_PTR_CREATED, \"__gcc_nested_func_ptr_created\", BT_FN_VOID_PTR_PTR_PTR, ATTR_NOTHROW_LIST)\n DEF_EXT_LIB_BUILTIN (BUILT_IN_GCC_NESTED_PTR_DELETED, \"__gcc_nested_func_ptr_deleted\", BT_FN_VOID, ATTR_NOTHROW_LIST)\n \n+/* Information needed to call (nested) functions. */\n+DEF_GCC_BUILTIN (BUILT_IN_CALL_INFO, \"call_info\", BT_FN_CALL_INFO_PTR, ATTR_NULL)\n+\n /* Implementing __builtin_setjmp. */\n DEF_BUILTIN_STUB (BUILT_IN_SETJMP_SETUP, \"__builtin_setjmp_setup\")\n DEF_BUILTIN_STUB (BUILT_IN_SETJMP_RECEIVER, \"__builtin_setjmp_receiver\")\ndiff --git a/gcc/doc/extend.texi b/gcc/doc/extend.texi\nindex 47b0bdf1340..2ddcd1f30d6 100644\n--- a/gcc/doc/extend.texi\n+++ b/gcc/doc/extend.texi\n@@ -16610,6 +16610,19 @@ This builtin can be used to call Go closures from C.\n \n @enddefbuiltin\n \n+@defbuiltin{@var{type} __builtin_call_info (@var{pointer_exp})}\n+\n+The @var{pointer_exp} expression must designate a function.\n+The result is a structure with two members of pointer type named @code{code}\n+and @code{chain}. @code{code} holds the static address of the function.\n+For a nested function, the address represents the address of the underlying\n+machine code and not of a trampoline that would otherwise be generated to\n+setup the static chain. @code{chain} is the chain pointer that that is\n+needed to call the function call in its current context, or a null pointer\n+if none is needed.\n+\n+@enddefbuiltin\n+\n @node Return Address\n @section Getting the Return or Frame Address of a Function\n \ndiff --git a/gcc/gimple-fold.cc b/gcc/gimple-fold.cc\nindex e9019e2c7bd..d8eceb080be 100644\n--- a/gcc/gimple-fold.cc\n+++ b/gcc/gimple-fold.cc\n@@ -5354,6 +5354,41 @@ gimple_fold_builtin_stdarg (gimple_stmt_iterator *gsi, gcall *call)\n }\n }\n \n+/* Fold __builtin_call_info builtin. This handles only the trivial\n+ left-over cases not processed in tree-nested.cc. */\n+\n+static bool\n+gimple_fold_builtin_call_info (gimple_stmt_iterator *gsi)\n+{\n+ gcall *stmt = as_a <gcall *>(gsi_stmt (*gsi));\n+ tree arg = gimple_call_arg (stmt, 0);\n+\n+ if (TREE_CODE (arg) != ADDR_EXPR || !DECL_P (TREE_OPERAND (arg, 0))\n+ || FUNCTION_DECL != TREE_CODE (TREE_OPERAND (arg, 0)))\n+ {\n+ error_at (gimple_location (stmt),\n+\t\t\"argument to %<__builtin_call_info%> must be a function\");\n+ return false;\n+ }\n+\n+ /* The case with static chain is handled in tree-nested.cc. */\n+ gcc_assert (!DECL_STATIC_CHAIN (TREE_OPERAND (arg, 0)));\n+\n+ tree fields = TYPE_FIELDS (call_info_type_node);\n+ tree ret = create_tmp_var (call_info_type_node);\n+ tree cref2 = build3 (COMPONENT_REF, TREE_TYPE (fields),\n+\t\t ret, fields, NULL_TREE);\n+ tree cref1 = build3 (COMPONENT_REF, TREE_TYPE (TREE_CHAIN (fields)),\n+\t\t ret, TREE_CHAIN (fields), NULL_TREE);\n+ gimple *g = gimple_build_assign (cref1, null_pointer_node);\n+ gsi_insert_before (gsi, g, GSI_SAME_STMT);\n+ g = gimple_build_assign (cref2, arg);\n+ gsi_insert_before (gsi, g, GSI_SAME_STMT);\n+\n+ replace_call_with_value (gsi, ret);\n+ return true;\n+}\n+\n /* Fold the non-target builtin at *GSI and return whether any simplification\n was made. */\n \n@@ -5530,6 +5565,9 @@ gimple_fold_builtin (gimple_stmt_iterator *gsi)\n case BUILT_IN_CONSTANT_P:\n return gimple_fold_builtin_constant_p (gsi);\n \n+ case BUILT_IN_CALL_INFO:\n+ return gimple_fold_builtin_call_info (gsi);\n+\n default:;\n }\n \ndiff --git a/gcc/testsuite/gcc.dg/builtin-call-info-1.c b/gcc/testsuite/gcc.dg/builtin-call-info-1.c\nnew file mode 100644\nindex 00000000000..24ac8b1ccf2\n--- /dev/null\n+++ b/gcc/testsuite/gcc.dg/builtin-call-info-1.c\n@@ -0,0 +1,26 @@\n+/* { dg-do run } */\n+/* { dg-options \"-Wtrampolines\" } */\n+\n+typedef typeof(__builtin_call_info(nullptr)) call_info_t;\n+\n+int apply(call_info_t c, int value)\n+{\n+\treturn __builtin_call_with_static_chain(((int(*)(int))c.code)(value), c.chain);\n+}\n+\n+int foo(int x)\n+{\n+\tint add(int y)\n+\t{\n+\t\treturn x + y;\n+\t}\n+\n+\treturn apply(__builtin_call_info(add), x);\n+}\n+\n+int main()\n+{\n+\tif (4 != foo(2))\n+\t\t__builtin_abort();\n+}\n+\ndiff --git a/gcc/testsuite/gcc.dg/builtin-call-info-2.c b/gcc/testsuite/gcc.dg/builtin-call-info-2.c\nnew file mode 100644\nindex 00000000000..0ec8d865971\n--- /dev/null\n+++ b/gcc/testsuite/gcc.dg/builtin-call-info-2.c\n@@ -0,0 +1,49 @@\n+/* { dg-do run } */\n+/* { dg-options \"-Wtrampolines\" } */\n+\n+/* Check that we get the expected pointers in\n+ different context. */\n+\n+int f(int x)\n+{\n+\tstatic typeof(__builtin_call_info(f)) c;\n+\tc = __builtin_call_info(f);\n+\n+\tif (f != c.code)\n+\t\t__builtin_abort();\n+\n+\tif ((void*)0 != c.chain)\n+\t\t__builtin_abort();\n+\n+\tint g(int y)\n+\t{\n+\t\tauto c2 = __builtin_call_info(g);\n+\n+\t\tif (c.code != c2.code)\n+\t\t\t__builtin_abort();\n+\t\t\n+\t\tif (c.chain != c2.chain)\n+\t\t\t__builtin_abort();\n+\t\n+\t\treturn x + y; \n+\t}\n+\n+\tc = __builtin_call_info(g);\n+\n+\treturn g(x);\n+}\n+\n+int main()\n+{\n+\tauto c = __builtin_call_info(f);\n+\n+\tif (f != c.code)\n+\t\t__builtin_abort();\n+\n+\tif ((void*)0 != c.chain)\n+\t\t__builtin_abort();\n+\n+\tif (6 != f(3))\n+\t\t__builtin_abort();\n+}\n+\ndiff --git a/gcc/testsuite/gcc.dg/builtin-call-info-3.c b/gcc/testsuite/gcc.dg/builtin-call-info-3.c\nnew file mode 100644\nindex 00000000000..5d78892fefb\n--- /dev/null\n+++ b/gcc/testsuite/gcc.dg/builtin-call-info-3.c\n@@ -0,0 +1,24 @@\n+/* { dg-do compile } */\n+/* { dg-options \"-O2 -Wtrampolines -Wreturn-local-addr\" } */\n+\n+\n+void * foo(int n)\n+{\n+\tint g(int x)\n+\t{\n+\t\treturn n + x;\n+\t}\n+\n+\treturn __builtin_call_info(g).code;\t// ok\n+}\n+\n+void * bar(int n)\n+{\n+\tint g(int x)\n+\t{\n+\t\treturn n + x;\n+\t}\n+\n+\treturn __builtin_call_info(g).chain;\t/* { dg-warning \"returns address of local variable\" } */\n+}\n+\ndiff --git a/gcc/tree-core.h b/gcc/tree-core.h\nindex 07e9318f5e8..0a3740b060a 100644\n--- a/gcc/tree-core.h\n+++ b/gcc/tree-core.h\n@@ -822,6 +822,7 @@ enum tree_index : unsigned {\n TI_FEXCEPT_T_PTR_TYPE,\n TI_CONST_FEXCEPT_T_PTR_TYPE,\n TI_POINTER_SIZED_TYPE,\n+ TI_CALL_INFO_TYPE,\n \n TI_DFLOAT32_TYPE,\n TI_DFLOAT64_TYPE,\ndiff --git a/gcc/tree-inline.cc b/gcc/tree-inline.cc\nindex 087fcc8a8b8..8f5701ab693 100644\n--- a/gcc/tree-inline.cc\n+++ b/gcc/tree-inline.cc\n@@ -3760,8 +3760,8 @@ initialize_inlined_parameters (copy_body_data *id, gimple *stmt,\n gcc_assert (fn != current_function_decl);\n if (p)\n {\n- /* No static chain? Seems like a bug in tree-nested.cc. */\n- gcc_assert (static_chain);\n+ if (!static_chain)\n+\terror (\"called function requires a static chain\");\n \n setup_one_parameter (id, p, static_chain, fn, bb, &vars);\n }\ndiff --git a/gcc/tree-nested.cc b/gcc/tree-nested.cc\nindex cdccc51d33e..0b0affe9a44 100644\n--- a/gcc/tree-nested.cc\n+++ b/gcc/tree-nested.cc\n@@ -36,6 +36,7 @@\n #include \"gimplify.h\"\n #include \"gimple-iterator.h\"\n #include \"gimple-walk.h\"\n+#include \"gimple-fold.h\"\n #include \"tree-cfg.h\"\n #include \"explow.h\"\n #include \"langhooks.h\"\n@@ -2882,6 +2883,11 @@ convert_tramp_reference_stmt (gimple_stmt_iterator *gsi, bool *handled_ops_p,\n {\n case GIMPLE_CALL:\n {\n+\ttree decl = gimple_call_fndecl (stmt);\n+\tif (decl && fndecl_built_in_p (decl, BUILT_IN_NORMAL)\n+\t && BUILT_IN_CALL_INFO == DECL_FUNCTION_CODE (decl))\n+\t break;\n+\n \t/* Only walk call arguments, lest we generate trampolines for\n \t direct calls. */\n \tunsigned long i, nargs = gimple_call_num_args (stmt);\n@@ -2994,11 +3000,52 @@ convert_gimple_call (gimple_stmt_iterator *gsi, bool *handled_ops_p,\n switch (gimple_code (stmt))\n {\n case GIMPLE_CALL:\n- if (gimple_call_chain (stmt))\n-\tbreak;\n decl = gimple_call_fndecl (stmt);\n if (!decl)\n \tbreak;\n+ if (fndecl_built_in_p (decl, BUILT_IN_NORMAL)\n+\t && DECL_FUNCTION_CODE (decl) == BUILT_IN_CALL_INFO)\n+\t{\n+\t tree d = gimple_call_arg (stmt, 0);\n+\t tree ret1 = null_pointer_node;\n+\t tree ret2 = null_pointer_node;\n+\t if (TREE_CODE (d) != ADDR_EXPR || !DECL_P (TREE_OPERAND (d, 0))\n+\t || FUNCTION_DECL != TREE_CODE (TREE_OPERAND (d, 0)))\n+\t {\n+\t error_at (gimple_location (stmt),\n+\t\t\t\"argument to %<__builtin_call_info%> \"\n+\t\t\t\"must be a function\");\n+\t }\n+\t else\n+\t {\n+\t decl = TREE_OPERAND (d, 0);\n+\t target_context = decl_function_context (decl);\n+\t if (target_context && DECL_STATIC_CHAIN (decl))\n+\t\t{\n+\t\t /* Return static chain. */\n+\t\t info->static_chain_added\n+\t\t |= (1 << (info->context != target_context));\n+\t\t ret1 = get_static_chain (info, target_context, &wi->gsi);\n+\t\t}\n+\t /* Return code pointer. */\n+\t ret2 = build_addr (TREE_OPERAND (d, 0));\n+\t TREE_NO_TRAMPOLINE (ret2) = 1;\n+\t }\n+\t tree fields = TYPE_FIELDS (call_info_type_node);\n+\t tree ret = create_tmp_var_for (info, call_info_type_node, NULL);\n+\t tree cref2 = build3 (COMPONENT_REF, TREE_TYPE (fields),\n+\t\t\t ret, fields, NULL_TREE);\n+\t tree cref1 = build3 (COMPONENT_REF, TREE_TYPE (TREE_CHAIN (fields)),\n+\t\t\t ret, TREE_CHAIN (fields), NULL_TREE);\n+\t gimple *assign = gimple_build_assign (cref1, ret1);\n+\t gsi_insert_before (gsi, assign, GSI_SAME_STMT);\n+\t assign = gimple_build_assign (cref2, ret2);\n+\t gsi_insert_before (gsi, assign, GSI_SAME_STMT);\n+\t replace_call_with_value (gsi, ret);\n+\t break;\n+\t}\n+ if (gimple_call_chain (stmt))\n+\tbreak;\n target_context = decl_function_context (decl);\n if (target_context && DECL_STATIC_CHAIN (decl))\n \t{\ndiff --git a/gcc/tree.cc b/gcc/tree.cc\nindex d0e745e8d28..38d0590a8c7 100644\n--- a/gcc/tree.cc\n+++ b/gcc/tree.cc\n@@ -9984,6 +9984,18 @@ build_common_tree_nodes (bool signed_char)\n va_list_type_node = t;\n }\n \n+ /* Create the call info type. */\n+ call_info_type_node = make_node (RECORD_TYPE);\n+ tree code_field = build_decl (BUILTINS_LOCATION, FIELD_DECL,\n+\t\t\t\tget_identifier (\"code\"), ptr_type_node);\n+ DECL_FIELD_CONTEXT (code_field) = call_info_type_node;\n+ tree data_field = build_decl (BUILTINS_LOCATION, FIELD_DECL,\n+\t\t\t\tget_identifier (\"chain\"), ptr_type_node);\n+ DECL_FIELD_CONTEXT (data_field) = call_info_type_node;\n+ TREE_CHAIN (code_field) = data_field;\n+ TYPE_FIELDS (call_info_type_node) = code_field;\n+ layout_type (call_info_type_node);\n+\n /* SCEV analyzer global shared trees. */\n chrec_dont_know = make_node (SCEV_NOT_KNOWN);\n TREE_TYPE (chrec_dont_know) = void_type_node;\ndiff --git a/gcc/tree.h b/gcc/tree.h\nindex 19bc67718d1..c63898f672c 100644\n--- a/gcc/tree.h\n+++ b/gcc/tree.h\n@@ -4665,6 +4665,7 @@ tree_strip_any_location_wrapper (tree exp)\n #define fexcept_t_ptr_type_node\t\tglobal_trees[TI_FEXCEPT_T_PTR_TYPE]\n #define const_fexcept_t_ptr_type_node\tglobal_trees[TI_CONST_FEXCEPT_T_PTR_TYPE]\n #define pointer_sized_int_node\t\tglobal_trees[TI_POINTER_SIZED_TYPE]\n+#define call_info_type_node\t\tglobal_trees[TI_CALL_INFO_TYPE]\n \n #define boolean_type_node\t\tglobal_trees[TI_BOOLEAN_TYPE]\n #define boolean_false_node\t\tglobal_trees[TI_BOOLEAN_FALSE]\n", "prefixes": [ "RFC", "C", "v2" ] }