From patchwork Thu Oct 7 22:14:27 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Siddhesh Poyarekar X-Patchwork-Id: 45974 Return-Path: X-Original-To: patchwork@sourceware.org Delivered-To: patchwork@sourceware.org Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id 0392E3858001 for ; Thu, 7 Oct 2021 22:16:50 +0000 (GMT) X-Original-To: gcc-patches@gcc.gnu.org Delivered-To: gcc-patches@gcc.gnu.org Received: from antelope.elm.relay.mailchannels.net (antelope.elm.relay.mailchannels.net [23.83.212.4]) by sourceware.org (Postfix) with ESMTPS id 010643857C5D for ; Thu, 7 Oct 2021 22:15:02 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.1 sourceware.org 010643857C5D Authentication-Results: sourceware.org; dmarc=none (p=none dis=none) header.from=gotplt.org Authentication-Results: sourceware.org; spf=pass smtp.mailfrom=gotplt.org X-Sender-Id: dreamhost|x-authsender|siddhesh@gotplt.org Received: from relay.mailchannels.net (localhost [127.0.0.1]) by relay.mailchannels.net (Postfix) with ESMTP id 823CB362007; Thu, 7 Oct 2021 22:15:01 +0000 (UTC) Received: from pdx1-sub0-mail-a17.g.dreamhost.com (100-96-18-141.trex.outbound.svc.cluster.local [100.96.18.141]) (Authenticated sender: dreamhost) by relay.mailchannels.net (Postfix) with ESMTPA id 0F7943619D2; Thu, 7 Oct 2021 22:15:01 +0000 (UTC) X-Sender-Id: dreamhost|x-authsender|siddhesh@gotplt.org Received: from pdx1-sub0-mail-a17.g.dreamhost.com (pop.dreamhost.com [64.90.62.162]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384) by 100.96.18.141 (trex/6.4.3); Thu, 07 Oct 2021 22:15:01 +0000 X-MC-Relay: Neutral X-MailChannels-SenderId: dreamhost|x-authsender|siddhesh@gotplt.org X-MailChannels-Auth-Id: dreamhost X-Eight-Exultant: 02ae02d461db395a_1633644901317_2194276729 X-MC-Loop-Signature: 1633644901316:1896629120 X-MC-Ingress-Time: 1633644901316 Received: from pdx1-sub0-mail-a17.g.dreamhost.com (localhost [127.0.0.1]) by pdx1-sub0-mail-a17.g.dreamhost.com (Postfix) with ESMTP id B8EC47F2D7; Thu, 7 Oct 2021 15:15:00 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha1; c=relaxed; d=gotplt.org; h=from:to:cc :subject:date:message-id:in-reply-to:references:mime-version :content-transfer-encoding; s=gotplt.org; bh=sI4Vw+f7DfsHfbUQw5c g3Gsvw/E=; b=xJSN6wRUQoSLYccUvRwDXguanM5/kqu+MmrNacNy1IawyzbKpvu /bIfZYVJUL26dpIB8qxiqzV0sOgLeoQ5R21Ri9PVsKBeHxso0k854oRLXNBKPOZM j9ibWPvJC3S/T5Gk+p0xaTAcAtLE2rzfVKhop97icKD0I8HYhU2oNkx0= Received: from rhbox.redhat.com (unknown [1.186.223.58]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) (Authenticated sender: siddhesh@gotplt.org) by pdx1-sub0-mail-a17.g.dreamhost.com (Postfix) with ESMTPSA id 041898348D; Thu, 7 Oct 2021 15:14:56 -0700 (PDT) X-DH-BACKEND: pdx1-sub0-mail-a17 From: Siddhesh Poyarekar To: gcc-patches@gcc.gnu.org Subject: [PATCH 3/8] tree-dynamic-object-size: Handle GIMPLE_PHI Date: Fri, 8 Oct 2021 03:44:27 +0530 Message-Id: <20211007221432.1029249-4-siddhesh@gotplt.org> X-Mailer: git-send-email 2.31.1 In-Reply-To: <20211007221432.1029249-1-siddhesh@gotplt.org> References: <20211007221432.1029249-1-siddhesh@gotplt.org> MIME-Version: 1.0 X-Spam-Status: No, score=-3037.9 required=5.0 tests=BAYES_00, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, GIT_PATCH_0, PDS_OTHER_BAD_TLD, RCVD_IN_DNSWL_NONE, RCVD_IN_MSPIKE_H2, SPF_HELO_NONE, SPF_PASS, TXREP autolearn=ham autolearn_force=no version=3.4.4 X-Spam-Checker-Version: SpamAssassin 3.4.4 (2020-01-24) on server2.sourceware.org X-BeenThere: gcc-patches@gcc.gnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Gcc-patches mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: jakub@redhat.com Errors-To: gcc-patches-bounces+patchwork=sourceware.org@gcc.gnu.org Sender: "Gcc-patches" Where the target object is a PHI node, set the size to be a PHI node with sizes of the target object. All object size information is now split into an SSA name and its size expression. This allows non-SSA size expressions to be evaluated all at once in the end and generated statements inserted into the right places before returning the SSA tree representing the size. This change also adds support for dependency loops since that is a common occurrence with PHI nodes. Dependency loop handling is single pass unlike tree-object-size due to the separation of size SSA names and actual expressions, which allow for placeholders and unresolved dependency loop counting in case of self-reference. The downside though is that if there's an unresolved dependency loop and the object size computation fails, all of the computations are scrapped. Ideally only computations involved in the unresolved dependency loop should be scrapped but I don't know if it's worth the extra state that would have to be managed. We could revisit this if it ends up being a bottleneck. gcc/ChangeLog: * tree-dynamic-object-size.c: Include gimplify-me.h. (object_size_info): New member deploop. (object_size_exprs): New vector of object size expressions. (emit_size_stmts, emit_size_phi_stmts, eval_size_expr, gimplify_size_exprs): New functions. (compute_builtin_dyn_object_size): New argument FUN. Grow object_size_exprs and call gimplify_size_exprs. (maybe_update_dependency_loop, cache_object_size, cache_object_size_copy): New functions. (set_object_size_ssa, call_object_size): Call cache_object_size_copy. (collect_object_sizes_for): Handle GIMPLE_PHI. (init_dynamic_object_sizes): Allocate object_size_exprs. (fini_dynamic_object_sizes): Deallocate object_size_exprs. * gcc/tree-dynamic-object-size.h (compute_builtin_dyn_object_size): New argument. gcc/testsuite/ChangeLog: * gcc.dg/builtin-dynamic-object-size-0.c (test_builtin_malloc_condphi, test_builtin_malloc_condphi2, test_builtin_malloc_condphi3, test_builtin_calloc_condphi, test_deploop): New tests. (main): Call them. Signed-off-by: Siddhesh Poyarekar --- .../gcc.dg/builtin-dynamic-object-size-0.c | 92 +++++++ gcc/tree-dynamic-object-size.c | 258 +++++++++++++++++- gcc/tree-dynamic-object-size.h | 3 +- 3 files changed, 339 insertions(+), 14 deletions(-) diff --git a/gcc/testsuite/gcc.dg/builtin-dynamic-object-size-0.c b/gcc/testsuite/gcc.dg/builtin-dynamic-object-size-0.c index 620e8cbc611..7098ef485c6 100644 --- a/gcc/testsuite/gcc.dg/builtin-dynamic-object-size-0.c +++ b/gcc/testsuite/gcc.dg/builtin-dynamic-object-size-0.c @@ -63,6 +63,48 @@ test_builtin_malloc_cond (int cond) return __builtin_dynamic_object_size (ret, 0); } +size_t +__attribute__ ((noinline)) +test_builtin_malloc_condphi (int cond) +{ + void *ret; + + if (cond) + ret = __builtin_malloc (32); + else + ret = __builtin_malloc (64); + + return __builtin_dynamic_object_size (ret, 0); +} + +size_t +__attribute__ ((noinline)) +test_builtin_malloc_condphi2 (int cond, size_t in) +{ + void *ret; + + if (cond) + ret = __builtin_malloc (in); + else + ret = __builtin_malloc (64); + + return __builtin_dynamic_object_size (ret, 0); +} + +size_t +__attribute__ ((noinline)) +test_builtin_malloc_condphi3 (int cond, size_t in, size_t in2) +{ + void *ret; + + if (cond) + ret = __builtin_malloc (in); + else + ret = __builtin_malloc (in2); + + return __builtin_dynamic_object_size (ret, 0); +} + /* Calloc-like allocator. */ size_t @@ -89,6 +131,21 @@ test_builtin_calloc_cond (int cond1, int cond2) return __builtin_dynamic_object_size (ret, 0); } +size_t +__attribute__ ((noinline)) +test_builtin_calloc_condphi (size_t cnt, size_t sz, int cond) +{ + struct + { + int a; + char b; + } bin[cnt]; + + char *ch = __builtin_calloc (cnt, sz); + + return __builtin_dynamic_object_size (cond ? ch : (void *) &bin, 0); +} + /* Passthrough functions. */ size_t @@ -120,6 +177,19 @@ test_dynarray_cond (int cond) return __builtin_dynamic_object_size (bin, 0); } +size_t +__attribute__ ((noinline)) +test_deploop (size_t sz, size_t cond) +{ + char *bin = __builtin_alloca (32); + + for (size_t i = 0; i < sz; i++) + if (i == cond) + bin = __builtin_alloca (sz); + + return __builtin_dynamic_object_size (bin, 0); +} + int main (int argc, char **argv) { @@ -141,6 +211,18 @@ main (int argc, char **argv) FAIL (); if (test_builtin_malloc_cond (0) != 64) FAIL (); + if (test_builtin_malloc_condphi (1) != 32) + FAIL (); + if (test_builtin_malloc_condphi (0) != 64) + FAIL (); + if (test_builtin_malloc_condphi2 (1, 128) != 128) + FAIL (); + if (test_builtin_malloc_condphi2 (0, 128) != 64) + FAIL (); + if (test_builtin_malloc_condphi3 (1, 128, 256) != 128) + FAIL (); + if (test_builtin_malloc_condphi3 (0, 128, 256) != 256) + FAIL (); if (test_calloc (2048, 4) != 2048 * 4) FAIL (); if (test_builtin_calloc (2048, 8) != 2048 * 8) @@ -149,6 +231,12 @@ main (int argc, char **argv) FAIL (); if (test_builtin_calloc_cond (1, 1) != 32 * 1024) FAIL (); + if (test_builtin_calloc_condphi (128, 1, 1) != 128) + FAIL (); + if (test_builtin_calloc_condphi (128, 1, 0) == 128) + FAIL (); + if (test_builtin_calloc_condphi (128, 1, 0) == -1) + FAIL (); if (test_passthrough (__builtin_strlen (argv[0]) + 1, argv[0]) != __builtin_strlen (argv[0]) + 1) FAIL (); @@ -158,6 +246,10 @@ main (int argc, char **argv) FAIL (); if (test_dynarray_cond (1) != 8) FAIL (); + if (test_deploop (128, 4) != 128) + FAIL (); + if (test_deploop (128, 129) != 32) + FAIL (); if (nfails > 0) __builtin_abort (); diff --git a/gcc/tree-dynamic-object-size.c b/gcc/tree-dynamic-object-size.c index 8e52dd46c03..483d6782d49 100644 --- a/gcc/tree-dynamic-object-size.c +++ b/gcc/tree-dynamic-object-size.c @@ -62,11 +62,14 @@ along with GCC; see the file COPYING3. If not see #include "attribs.h" #include "builtins.h" #include "print-tree.h" +#include "gimplify-me.h" struct object_size_info { + struct function *fun; int object_size_type; bitmap visited; + unsigned deploop; }; static tree alloc_object_size (const gcall *); @@ -78,9 +81,15 @@ static void collect_object_sizes_for (struct object_size_info *, tree); object_sizes[1] is upper bound for number of bytes till the end of the subobject (innermost array or field with address taken). object_sizes[2] is lower bound for number of bytes till the end of - the object and object_sizes[3] lower bound for subobject. */ + the object and object_sizes[3] lower bound for subobject. + + These are merely SSA names of the sizes. The actual size expressions are in + object_size_exprs and they need not be SSA. */ static vec object_sizes[4]; +/* The actual size expressions, indexed by the object SSA names. */ +static vecobject_size_exprs[4]; + /* Bitmaps what object sizes have been computed already. */ static bitmap computed[4]; @@ -166,13 +175,123 @@ pass_through_call (const gcall *call) return NULL_TREE; } +static void +emit_size_stmts (gimple *stmt, tree size_ssa, tree size_expr) +{ + gimple_seq seq = NULL; + + if (!is_gimple_variable (size_expr)) + size_expr = force_gimple_operand (size_expr, &seq, true, NULL); + + gassign *assign = gimple_build_assign (size_ssa, size_expr); + gimple_seq_add_stmt (&seq, assign); + + /* Define object size right after the object is defined. */ + gimple_stmt_iterator i = gsi_for_stmt (stmt); + gsi_insert_seq_after (&i, seq, GSI_CONTINUE_LINKING); +} + +static void +emit_size_phi_stmts (gimple *stmt, tree size_ssa, tree *sizes) +{ + gphi *newphi = create_phi_node (size_ssa, gimple_bb (stmt)); + gphi *obj_phi = as_a (stmt); + + for (unsigned i = 0; i < gimple_phi_num_args (stmt); i++) + { + if (!is_gimple_variable (sizes[i])) + { + gimple_seq seq; + edge e = gimple_phi_arg_edge (obj_phi, i); + sizes[i] = force_gimple_operand (sizes[i], &seq, true, NULL); + + /* Put the size definition before the last statement of the source + block of the PHI edge. This ensures that any branches at the end + of the source block remain the last statement. We are OK even if + the last statement is the definition of the object since it will + succeed any definitions that contribute to its size and the size + expression will succeed them too. */ + gimple_stmt_iterator gsi = gsi_last_bb (e->src); + gsi_insert_seq_before (&gsi, seq, GSI_CONTINUE_LINKING); + } + + add_phi_arg (newphi, sizes[i], + gimple_phi_arg_edge (obj_phi, i), + gimple_phi_arg_location (obj_phi, i)); + } +} + +static void +eval_size_expr (tree var, tree size, tree *size_expr) +{ + if (size_expr != NULL) + { + gcc_assert (*size_expr != error_mark_node); + + gimple *stmt = SSA_NAME_DEF_STMT (var); + + if (gimple_code (stmt) == GIMPLE_PHI) + { + emit_size_phi_stmts (stmt, size, size_expr); + delete[] size_expr; + } + else + { + emit_size_stmts (stmt, size, *size_expr); + delete size_expr; + } + } +} + +static void +gimplify_size_exprs (object_size_info *osi, tree ptr) +{ + bitmap_iterator bi; + unsigned i; + + /* If the size lookup was not successful and we were left with unresolved + loop dependencies, then invalidate all size computations. This is + suboptimal and should eventually try to remove only size expressions that + depend on the unresolved dependencies, but it's unclear whether + maintaining the extra state to manage that is worthwhile. */ + if (object_sizes[osi->object_size_type][SSA_NAME_VERSION (ptr)] == NULL_TREE + && osi->deploop) + { + for (int object_size_type = 0; object_size_type <= 3; object_size_type++) + { + EXECUTE_IF_SET_IN_BITMAP (computed[object_size_type], 0, i, bi) + { + release_ssa_name (object_sizes[object_size_type][i]); + if (gimple_code (SSA_NAME_DEF_STMT (ssa_name (i))) == GIMPLE_PHI + && object_size_exprs[object_size_type][i]) + delete [] object_size_exprs[object_size_type][i]; + else + delete object_size_exprs[object_size_type][i]; + object_size_exprs[object_size_type][i] = NULL; + } + bitmap_clear (computed[object_size_type]); + } + return; + } + + /* Gimplify and emit code for all computed size expressions. */ + for (int object_size_type = 0; object_size_type <= 3; object_size_type++) + EXECUTE_IF_SET_IN_BITMAP (computed[object_size_type], 0, i, bi) + { + eval_size_expr (ssa_name (i), object_sizes[object_size_type][i], + object_size_exprs[object_size_type][i]); + object_size_exprs[object_size_type][i] = NULL; + } +} + /* Compute object size estimate for PTR and set *PSIZE to the resulting value. OBJECT_SIZE_TYPE is the second argument to __builtin_dynamic_object_size. Returns true on success and false when the object size could not be determined. */ bool -compute_builtin_dyn_object_size (tree ptr, int object_size_type, tree *psize) +compute_builtin_dyn_object_size (tree ptr, int object_size_type, tree *psize, + struct function *fun) { gcc_assert (object_size_type >= 0 && object_size_type <= 3); @@ -195,7 +314,10 @@ compute_builtin_dyn_object_size (tree ptr, int object_size_type, tree *psize) unsigned int i; if (num_ssa_names > object_sizes[object_size_type].length ()) - object_sizes[object_size_type].safe_grow (num_ssa_names, true); + { + object_sizes[object_size_type].safe_grow (num_ssa_names, true); + object_size_exprs[object_size_type].safe_grow (num_ssa_names, true); + } if (dump_file) { fprintf (dump_file, "Computing %s dynamic %sobject size for ", @@ -206,9 +328,12 @@ compute_builtin_dyn_object_size (tree ptr, int object_size_type, tree *psize) } osi.visited = BITMAP_ALLOC (NULL); + osi.deploop = 0; osi.object_size_type = object_size_type; + osi.fun = fun != NULL ? fun : cfun; collect_object_sizes_for (&osi, ptr); + gimplify_size_exprs (&osi, ptr); /* Debugging dumps. */ if (dump_file) @@ -234,6 +359,73 @@ out: return *psize != NULL_TREE; } +static void +maybe_update_dependency_loop (struct object_size_info *osi, unsigned name, + tree sz) +{ + if (sz == error_mark_node) + osi->deploop++; + else if (object_sizes[osi->object_size_type][name] + && (*object_size_exprs[osi->object_size_type][name] + == error_mark_node)) + osi->deploop--; +} + +/* Add object size to the cache so that it can be reused. */ + +static void +cache_object_size (struct object_size_info *osi, unsigned name, tree *sz) +{ + int object_size_type = osi->object_size_type; + struct function *fun = osi->fun; + + gcc_assert (sz); + + maybe_update_dependency_loop (osi, name, *sz); + + /* Reuse SSA name if it was created for a dependency loop. */ + if (object_sizes[object_size_type][name] != NULL_TREE) + gcc_assert (*object_size_exprs[object_size_type][name] == error_mark_node); + else + object_sizes[object_size_type][name] = make_ssa_name_fn (fun, sizetype, 0); + object_size_exprs[object_size_type][name] = sz; + + if (dump_file && (dump_flags & TDF_DETAILS)) + { + fprintf (dump_file, "Caching size for "); + print_generic_expr (dump_file, ssa_name (name), dump_flags); + fprintf (dump_file, ":: Object size: "); + print_generic_expr (dump_file, object_sizes[object_size_type][name], + dump_flags); + fprintf (dump_file, " = "); + print_generic_expr (dump_file, + *object_size_exprs[object_size_type][name], + dump_flags); + fprintf (dump_file, "\n"); + } + + bitmap_set_bit (computed[object_size_type], name); +} + +/* Copy SZ and then call cache_object_size above. */ + +static void +cache_object_size_copy (struct object_size_info *osi, unsigned name, tree sz) +{ + int object_size_type = osi->object_size_type; + + if (sz == NULL_TREE) + { + if (object_sizes[object_size_type][name] != NULL_TREE) + release_ssa_name (object_sizes[object_size_type][name]); + object_sizes[object_size_type][name] = NULL_TREE; + object_size_exprs[object_size_type][name] = NULL; + bitmap_set_bit (computed[object_size_type], name); + return; + } + + cache_object_size (osi, name, new tree (sz)); +} /* Use size of ORIG for DEST and return it. */ @@ -241,8 +433,9 @@ static void set_object_size_ssa (struct object_size_info *osi, tree dest, tree orig) { collect_object_sizes_for (osi, orig); - object_sizes[osi->object_size_type][SSA_NAME_VERSION (dest)] = - object_sizes[osi->object_size_type][SSA_NAME_VERSION (orig)]; + + tree sz = object_sizes[osi->object_size_type][SSA_NAME_VERSION (orig)]; + cache_object_size_copy (osi, SSA_NAME_VERSION (dest), sz); } @@ -251,11 +444,10 @@ set_object_size_ssa (struct object_size_info *osi, tree dest, tree orig) static void call_object_size (struct object_size_info *osi, tree ptr, gcall *call) { - unsigned int varno = SSA_NAME_VERSION (ptr); - gcc_assert (is_gimple_call (call)); - object_sizes[osi->object_size_type][varno] = alloc_object_size (call); + cache_object_size_copy (osi, SSA_NAME_VERSION (ptr), + alloc_object_size (call)); } @@ -264,7 +456,9 @@ call_object_size (struct object_size_info *osi, tree ptr, gcall *call) - For allocation GIMPLE_CALL like malloc or calloc object size is the size of the allocation. - For a memcpy like GIMPLE_CALL that always returns one of its arguments, - the object size is object size of that argument. */ + the object size is object size of that argument. + - For GIMPLE_PHI, compute a PHI node with sizes of all branches in the PHI + node of the object. */ static void collect_object_sizes_for (struct object_size_info *osi, tree var) @@ -280,7 +474,10 @@ collect_object_sizes_for (struct object_size_info *osi, tree var) object_sizes[object_size_type][varno] = NULL_TREE; else { - /* No dependency loop handling at the moment. */ + /* Add an SSA name but mark the expression as being an error_mark_node. + When we go back up the stack, the error_mark_node should get + overwritten by a proper expression. */ + cache_object_size (osi, varno, &error_mark_node); if (dump_file && (dump_flags & TDF_DETAILS)) { fprintf (dump_file, "Found a dependency loop at "); @@ -315,18 +512,51 @@ collect_object_sizes_for (struct object_size_info *osi, tree var) break; } + case GIMPLE_PHI: + { + unsigned i, num_args = gimple_phi_num_args (stmt); + tree *sizes = new tree[num_args] (); + + /* Bail out if any of the PHI arguments are non-SSA expressions or + if size of an argument cannot be determined. */ + for (i = 0; i < gimple_phi_num_args (stmt); i++) + { + tree rhs = gimple_phi_arg_def (stmt, i); + + if (TREE_CODE (rhs) != SSA_NAME) + break; + + collect_object_sizes_for (osi, rhs); + tree sz = object_sizes[object_size_type][SSA_NAME_VERSION (rhs)]; + + if (sz == NULL_TREE) + break; + + sizes[i] = sz; + } + + /* Record all possible sizes to build our PHI node later. */ + if (i == gimple_phi_num_args (stmt)) + { + cache_object_size (osi, varno, sizes); + break; + } + else + delete[] sizes; + } + /* FALLTHROUGH */ + /* Bail out for all other cases. */ case GIMPLE_NOP: - case GIMPLE_PHI: case GIMPLE_ASSIGN: case GIMPLE_ASM: + cache_object_size_copy (osi, varno, NULL_TREE); break; default: gcc_unreachable (); } - - bitmap_set_bit (computed[object_size_type], varno); + gcc_assert (bitmap_bit_p (computed[object_size_type], varno)); } @@ -343,6 +573,7 @@ init_dynamic_object_sizes (void) for (object_size_type = 0; object_size_type <= 3; object_size_type++) { object_sizes[object_size_type].safe_grow (num_ssa_names, true); + object_size_exprs[object_size_type].safe_grow (num_ssa_names, true); computed[object_size_type] = BITMAP_ALLOC (NULL); } } @@ -358,6 +589,7 @@ fini_dynamic_object_sizes (void) for (object_size_type = 0; object_size_type <= 3; object_size_type++) { object_sizes[object_size_type].release (); + object_size_exprs[object_size_type].release (); BITMAP_FREE (computed[object_size_type]); } } diff --git a/gcc/tree-dynamic-object-size.h b/gcc/tree-dynamic-object-size.h index 145b4b88bca..a4e0236e43e 100644 --- a/gcc/tree-dynamic-object-size.h +++ b/gcc/tree-dynamic-object-size.h @@ -20,6 +20,7 @@ along with GCC; see the file COPYING3. If not see #ifndef GCC_TREE_DYNAMIC_OBJECT_SIZE_H #define GCC_TREE_DYNAMIC_OBJECT_SIZE_H -extern bool compute_builtin_dyn_object_size (tree, int, tree *); +extern bool compute_builtin_dyn_object_size (tree, int, tree *, + struct function * = NULL); #endif // GCC_TREE_DYNAMIC_OBJECT_SIZE_H