From patchwork Tue Nov 9 19:01: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: 47322 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 A32B2385842B for ; Tue, 9 Nov 2021 19:02:39 +0000 (GMT) X-Original-To: gcc-patches@gcc.gnu.org Delivered-To: gcc-patches@gcc.gnu.org Received: from cross.elm.relay.mailchannels.net (cross.elm.relay.mailchannels.net [23.83.212.46]) by sourceware.org (Postfix) with ESMTPS id 49C773858405 for ; Tue, 9 Nov 2021 19:01:54 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.1 sourceware.org 49C773858405 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 6E72821D3F; Tue, 9 Nov 2021 19:01:52 +0000 (UTC) Received: from pdx1-sub0-mail-a306.dreamhost.com (100-96-99-51.trex.outbound.svc.cluster.local [100.96.99.51]) (Authenticated sender: dreamhost) by relay.mailchannels.net (Postfix) with ESMTPA id D4E3D21F5C; Tue, 9 Nov 2021 19:01:51 +0000 (UTC) X-Sender-Id: dreamhost|x-authsender|siddhesh@gotplt.org Received: from pdx1-sub0-mail-a306.dreamhost.com (pop.dreamhost.com [64.90.62.162]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384) by 100.96.99.51 (trex/6.4.3); Tue, 09 Nov 2021 19:01:52 +0000 X-MC-Relay: Neutral X-MailChannels-SenderId: dreamhost|x-authsender|siddhesh@gotplt.org X-MailChannels-Auth-Id: dreamhost X-Illegal-Glossy: 220884514604c7a8_1636484512181_2144236021 X-MC-Loop-Signature: 1636484512181:3562045799 X-MC-Ingress-Time: 1636484512181 Received: from rhbox.redhat.com (unknown [1.186.121.127]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256) (No client certificate requested) (Authenticated sender: siddhesh@gotplt.org) by pdx1-sub0-mail-a306.dreamhost.com (Postfix) with ESMTPSA id 4Hpclx66kkz1Wf; Tue, 9 Nov 2021 11:01:49 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha1; c=relaxed/relaxed; d=gotplt.org; s=gotplt.org; t=1636484511; bh=hk9oqj3FdvJ+2ygLnSmISmtYXUo=; h=From:To:Cc:Subject:Date:Content-Transfer-Encoding; b=Hx0mGkJJicNyFb4QcsQcqyhtF8m5N/nJq6pWgW3E4KetA3WsVN6w2FFOyECkXGRwr g/0NOVGMOrJS3+WurfPGOVuo7HvxRfN/5qgnF/1NtiUtfntlqD33FvVL5pU2vuChWG AI0/qwx0fWPHut58CAfRAn0urCPYiKObdXY6GHJI= From: Siddhesh Poyarekar To: gcc-patches@gcc.gnu.org Subject: [PATCH 01/10] tree-object-size: Replace magic numbers with enums Date: Wed, 10 Nov 2021 00:31:27 +0530 Message-Id: <20211109190137.1107736-2-siddhesh@gotplt.org> X-Mailer: git-send-email 2.31.1 In-Reply-To: <20211109190137.1107736-1-siddhesh@gotplt.org> References: <20211109190137.1107736-1-siddhesh@gotplt.org> MIME-Version: 1.0 X-Spam-Status: No, score=-3035.9 required=5.0 tests=BAYES_00, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, GIT_PATCH_0, RCVD_IN_BARRACUDACENTRAL, RCVD_IN_BL_SPAMCOP_NET, RCVD_IN_DNSWL_NONE, RCVD_IN_MSPIKE_H4, RCVD_IN_MSPIKE_WL, RCVD_IN_SBL, 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" A simple cleanup to allow inserting dynamic size code more easily. gcc/ChangeLog: * tree-object-size.c: New enum. (object_sizes, computed, addr_object_size, compute_builtin_object_size, init_object_sizes, fini_object_sizes, object_sizes_execute): Replace magic numbers with enums. Signed-off-by: Siddhesh Poyarekar --- gcc/tree-object-size.c | 47 +++++++++++++++++++++++++----------------- 1 file changed, 28 insertions(+), 19 deletions(-) diff --git a/gcc/tree-object-size.c b/gcc/tree-object-size.c index 4334e05ef70..f70f95a7b29 100644 --- a/gcc/tree-object-size.c +++ b/gcc/tree-object-size.c @@ -45,6 +45,13 @@ struct object_size_info unsigned int *stack, *tos; }; +enum +{ + OST_SUBOBJECT = 1, + OST_MINIMUM = 2, + OST_END = 4, +}; + static tree compute_object_offset (const_tree, const_tree); static bool addr_object_size (struct object_size_info *, const_tree, int, unsigned HOST_WIDE_INT *); @@ -67,10 +74,10 @@ static void check_for_plus_in_loops_1 (struct object_size_info *, tree, 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. */ -static vec object_sizes[4]; +static vec object_sizes[OST_END]; /* Bitmaps what object sizes have been computed already. */ -static bitmap computed[4]; +static bitmap computed[OST_END]; /* Maximum value of offset we consider to be addition. */ static unsigned HOST_WIDE_INT offset_limit; @@ -227,11 +234,11 @@ addr_object_size (struct object_size_info *osi, const_tree ptr, { unsigned HOST_WIDE_INT sz; - if (!osi || (object_size_type & 1) != 0 + if (!osi || (object_size_type & OST_SUBOBJECT) != 0 || TREE_CODE (TREE_OPERAND (pt_var, 0)) != SSA_NAME) { compute_builtin_object_size (TREE_OPERAND (pt_var, 0), - object_size_type & ~1, &sz); + object_size_type & ~OST_SUBOBJECT, &sz); } else { @@ -266,7 +273,7 @@ addr_object_size (struct object_size_info *osi, const_tree ptr, } else if (DECL_P (pt_var)) { - pt_var_size = decl_init_size (pt_var, object_size_type & 2); + pt_var_size = decl_init_size (pt_var, object_size_type & OST_MINIMUM); if (!pt_var_size) return false; } @@ -287,7 +294,7 @@ addr_object_size (struct object_size_info *osi, const_tree ptr, { tree var; - if (object_size_type & 1) + if (object_size_type & OST_SUBOBJECT) { var = TREE_OPERAND (ptr, 0); @@ -528,7 +535,7 @@ bool compute_builtin_object_size (tree ptr, int object_size_type, unsigned HOST_WIDE_INT *psize) { - gcc_assert (object_size_type >= 0 && object_size_type <= 3); + gcc_assert (object_size_type >= 0 && object_size_type < OST_END); /* Set to unknown and overwrite just before returning if the size could be determined. */ @@ -546,7 +553,7 @@ compute_builtin_object_size (tree ptr, int object_size_type, if (computed[object_size_type] == NULL) { - if (optimize || object_size_type & 1) + if (optimize || object_size_type & OST_SUBOBJECT) return false; /* When not optimizing, rather than failing, make a small effort @@ -586,8 +593,8 @@ compute_builtin_object_size (tree ptr, int object_size_type, if (dump_file) { fprintf (dump_file, "Computing %s %sobject size for ", - (object_size_type & 2) ? "minimum" : "maximum", - (object_size_type & 1) ? "sub" : ""); + (object_size_type & OST_MINIMUM) ? "minimum" : "maximum", + (object_size_type & OST_SUBOBJECT) ? "sub" : ""); print_generic_expr (dump_file, ptr, dump_flags); fprintf (dump_file, ":\n"); } @@ -679,8 +686,9 @@ compute_builtin_object_size (tree ptr, int object_size_type, fprintf (dump_file, ": %s %sobject size " HOST_WIDE_INT_PRINT_UNSIGNED "\n", - (object_size_type & 2) ? "minimum" : "maximum", - (object_size_type & 1) ? "sub" : "", + ((object_size_type & OST_MINIMUM) ? "minimum" + : "maximum"), + (object_size_type & OST_SUBOBJECT) ? "sub" : "", object_sizes[object_size_type][i]); } } @@ -1238,7 +1246,7 @@ init_object_sizes (void) if (computed[0]) return; - for (object_size_type = 0; object_size_type <= 3; object_size_type++) + for (object_size_type = 0; object_size_type < OST_END; object_size_type++) { object_sizes[object_size_type].safe_grow (num_ssa_names, true); computed[object_size_type] = BITMAP_ALLOC (NULL); @@ -1255,7 +1263,7 @@ fini_object_sizes (void) { int object_size_type; - for (object_size_type = 0; object_size_type <= 3; object_size_type++) + for (object_size_type = 0; object_size_type < OST_END; object_size_type++) { object_sizes[object_size_type].release (); BITMAP_FREE (computed[object_size_type]); @@ -1302,7 +1310,7 @@ object_sizes_execute (function *fun, bool insert_min_max_p) { unsigned HOST_WIDE_INT object_size_type = tree_to_uhwi (ost); tree ptr = gimple_call_arg (call, 0); - if ((object_size_type == 1 || object_size_type == 3) + if ((object_size_type & OST_SUBOBJECT) && (TREE_CODE (ptr) == ADDR_EXPR || TREE_CODE (ptr) == SSA_NAME)) { @@ -1315,7 +1323,8 @@ object_sizes_execute (function *fun, bool insert_min_max_p) tree tem = make_ssa_name (type); gimple_call_set_lhs (call, tem); enum tree_code code - = object_size_type == 1 ? MIN_EXPR : MAX_EXPR; + = (object_size_type & OST_MINIMUM + ? MAX_EXPR : MIN_EXPR); tree cst = build_int_cstu (type, bytes); gimple *g = gimple_build_assign (lhs, code, tem, cst); @@ -1336,11 +1345,11 @@ object_sizes_execute (function *fun, bool insert_min_max_p) { unsigned HOST_WIDE_INT object_size_type = tree_to_uhwi (ost); - if (object_size_type < 2) + if (object_size_type & OST_MINIMUM) + result = build_zero_cst (size_type_node); + else if (object_size_type < OST_END) result = fold_convert (size_type_node, integer_minus_one_node); - else if (object_size_type < 4) - result = build_zero_cst (size_type_node); } if (!result) From patchwork Tue Nov 9 19:01:28 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Siddhesh Poyarekar X-Patchwork-Id: 47323 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 841F1385781E for ; Tue, 9 Nov 2021 19:03:09 +0000 (GMT) X-Original-To: gcc-patches@gcc.gnu.org Delivered-To: gcc-patches@gcc.gnu.org Received: from cyan.elm.relay.mailchannels.net (cyan.elm.relay.mailchannels.net [23.83.212.47]) by sourceware.org (Postfix) with ESMTPS id BB4463858027 for ; Tue, 9 Nov 2021 19:01:56 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.1 sourceware.org BB4463858027 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 6915A361DDF; Tue, 9 Nov 2021 19:01:54 +0000 (UTC) Received: from pdx1-sub0-mail-a306.dreamhost.com (100-96-18-144.trex.outbound.svc.cluster.local [100.96.18.144]) (Authenticated sender: dreamhost) by relay.mailchannels.net (Postfix) with ESMTPA id EC8A13619FC; Tue, 9 Nov 2021 19:01:53 +0000 (UTC) X-Sender-Id: dreamhost|x-authsender|siddhesh@gotplt.org Received: from pdx1-sub0-mail-a306.dreamhost.com (pop.dreamhost.com [64.90.62.162]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384) by 100.96.18.144 (trex/6.4.3); Tue, 09 Nov 2021 19:01:54 +0000 X-MC-Relay: Neutral X-MailChannels-SenderId: dreamhost|x-authsender|siddhesh@gotplt.org X-MailChannels-Auth-Id: dreamhost X-Skirt-Wiry: 393060a86563605d_1636484514232_3573939760 X-MC-Loop-Signature: 1636484514232:2955145764 X-MC-Ingress-Time: 1636484514232 Received: from rhbox.redhat.com (unknown [1.186.121.127]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256) (No client certificate requested) (Authenticated sender: siddhesh@gotplt.org) by pdx1-sub0-mail-a306.dreamhost.com (Postfix) with ESMTPSA id 4Hpcm01YJ2z2n; Tue, 9 Nov 2021 11:01:51 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha1; c=relaxed/relaxed; d=gotplt.org; s=gotplt.org; t=1636484513; bh=A/OkS89QN1wbnF7MU/Oa9JmrJqI=; h=From:To:Cc:Subject:Date:Content-Transfer-Encoding; b=AM+BZzlJ8ZJBayTkYAAIfxy/QE1j7+uJI5abJXgKzwyDVhB3S2ACUzp6amBNH+8rx F2Z/ubQ9EypV5cTtp6NxzeST8SyCCMZ5SgyHKXKmiKYdRzzKDO2CHlaTkbsqaUu1aw LOW3XRDJr2ZHYlVUMcyUkINVAMlayQ8o6Ncojmuo= From: Siddhesh Poyarekar To: gcc-patches@gcc.gnu.org Subject: [PATCH 02/10] tree-object-size: Abstract object_sizes array Date: Wed, 10 Nov 2021 00:31:28 +0530 Message-Id: <20211109190137.1107736-3-siddhesh@gotplt.org> X-Mailer: git-send-email 2.31.1 In-Reply-To: <20211109190137.1107736-1-siddhesh@gotplt.org> References: <20211109190137.1107736-1-siddhesh@gotplt.org> MIME-Version: 1.0 X-Spam-Status: No, score=-3038.0 required=5.0 tests=BAYES_00, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, GIT_PATCH_0, RCVD_IN_BARRACUDACENTRAL, RCVD_IN_DNSWL_NONE, RCVD_IN_MSPIKE_H2, RCVD_IN_SBL, 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" Put all accesses to object_sizes behind functions so that we can add dynamic capability more easily. gcc/ChangeLog: * tree-object-size.c (object_sizes_grow, object_sizes_release, object_sizes_unknown_p, object_sizes_get, object_size_set_force, object_sizes_set): New functions. (addr_object_size, compute_builtin_object_size, expr_object_size, call_object_size, unknown_object_size, merge_object_sizes, plus_stmt_object_size, cond_expr_object_size, collect_object_sizes_for, check_for_plus_in_loops_1, init_object_sizes, fini_object_sizes): Adjust. Signed-off-by: Siddhesh Poyarekar --- gcc/tree-object-size.c | 176 +++++++++++++++++++++++------------------ 1 file changed, 97 insertions(+), 79 deletions(-) diff --git a/gcc/tree-object-size.c b/gcc/tree-object-size.c index f70f95a7b29..7a22539cc43 100644 --- a/gcc/tree-object-size.c +++ b/gcc/tree-object-size.c @@ -88,6 +88,71 @@ unknown (int object_size_type) return ((unsigned HOST_WIDE_INT) -((object_size_type >> 1) ^ 1)); } +/* Grow object_sizes[OBJECT_SIZE_TYPE] to num_ssa_names. */ + +static inline void +object_sizes_grow (int object_size_type) +{ + if (num_ssa_names > object_sizes[object_size_type].length ()) + object_sizes[object_size_type].safe_grow (num_ssa_names, true); +} + +/* Release object_sizes[OBJECT_SIZE_TYPE]. */ + +static inline void +object_sizes_release (int object_size_type) +{ + object_sizes[object_size_type].release (); +} + +/* Return true if object_sizes[OBJECT_SIZE_TYPE][VARNO] is unknown. */ + +static inline bool +object_sizes_unknown_p (int object_size_type, unsigned varno) +{ + return (object_sizes[object_size_type][varno] + == unknown (object_size_type)); +} + +/* Return size for VARNO corresponding to OSI. */ + +static inline unsigned HOST_WIDE_INT +object_sizes_get (struct object_size_info *osi, unsigned varno) +{ + return object_sizes[osi->object_size_type][varno]; +} + +/* Set size for VARNO corresponding to OSI to VAL. */ + +static inline bool +object_sizes_set_force (struct object_size_info *osi, unsigned varno, + unsigned HOST_WIDE_INT val) +{ + object_sizes[osi->object_size_type][varno] = val; + return true; +} + +/* Set size for VARNO corresponding to OSI to VAL if it is the new minimum or + maximum. */ + +static inline bool +object_sizes_set (struct object_size_info *osi, unsigned varno, + unsigned HOST_WIDE_INT val) +{ + int object_size_type = osi->object_size_type; + if ((object_size_type & OST_MINIMUM) == 0) + { + if (object_sizes[object_size_type][varno] < val) + return object_sizes_set_force (osi, varno, val); + } + else + { + if (object_sizes[object_size_type][varno] > val) + return object_sizes_set_force (osi, varno, val); + } + return false; +} + /* Initialize OFFSET_LIMIT variable. */ static void init_offset_limit (void) @@ -247,7 +312,7 @@ addr_object_size (struct object_size_info *osi, const_tree ptr, collect_object_sizes_for (osi, var); if (bitmap_bit_p (computed[object_size_type], SSA_NAME_VERSION (var))) - sz = object_sizes[object_size_type][SSA_NAME_VERSION (var)]; + sz = object_sizes_get (osi, SSA_NAME_VERSION (var)); else sz = unknown (object_size_type); } @@ -582,14 +647,14 @@ compute_builtin_object_size (tree ptr, int object_size_type, return false; } + struct object_size_info osi; + osi.object_size_type = object_size_type; if (!bitmap_bit_p (computed[object_size_type], SSA_NAME_VERSION (ptr))) { - struct object_size_info osi; bitmap_iterator bi; 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_grow (object_size_type); if (dump_file) { fprintf (dump_file, "Computing %s %sobject size for ", @@ -601,7 +666,6 @@ compute_builtin_object_size (tree ptr, int object_size_type, osi.visited = BITMAP_ALLOC (NULL); osi.reexamine = BITMAP_ALLOC (NULL); - osi.object_size_type = object_size_type; osi.depths = NULL; osi.stack = NULL; osi.tos = NULL; @@ -678,8 +742,7 @@ compute_builtin_object_size (tree ptr, int object_size_type, if (dump_file) { EXECUTE_IF_SET_IN_BITMAP (osi.visited, 0, i, bi) - if (object_sizes[object_size_type][i] - != unknown (object_size_type)) + if (!object_sizes_unknown_p (object_size_type, i)) { print_generic_expr (dump_file, ssa_name (i), dump_flags); @@ -689,7 +752,7 @@ compute_builtin_object_size (tree ptr, int object_size_type, ((object_size_type & OST_MINIMUM) ? "minimum" : "maximum"), (object_size_type & OST_SUBOBJECT) ? "sub" : "", - object_sizes[object_size_type][i]); + object_sizes_get (&osi, i)); } } @@ -697,7 +760,7 @@ compute_builtin_object_size (tree ptr, int object_size_type, BITMAP_FREE (osi.visited); } - *psize = object_sizes[object_size_type][SSA_NAME_VERSION (ptr)]; + *psize = object_sizes_get (&osi, SSA_NAME_VERSION (ptr)); return *psize != unknown (object_size_type); } @@ -710,8 +773,7 @@ expr_object_size (struct object_size_info *osi, tree ptr, tree value) unsigned int varno = SSA_NAME_VERSION (ptr); unsigned HOST_WIDE_INT bytes; - gcc_assert (object_sizes[object_size_type][varno] - != unknown (object_size_type)); + gcc_assert (!object_sizes_unknown_p (object_size_type, varno)); gcc_assert (osi->pass == 0); if (TREE_CODE (value) == WITH_SIZE_EXPR) @@ -726,16 +788,7 @@ expr_object_size (struct object_size_info *osi, tree ptr, tree value) else bytes = unknown (object_size_type); - if ((object_size_type & 2) == 0) - { - if (object_sizes[object_size_type][varno] < bytes) - object_sizes[object_size_type][varno] = bytes; - } - else - { - if (object_sizes[object_size_type][varno] > bytes) - object_sizes[object_size_type][varno] = bytes; - } + object_sizes_set (osi, varno, bytes); } @@ -750,22 +803,12 @@ call_object_size (struct object_size_info *osi, tree ptr, gcall *call) gcc_assert (is_gimple_call (call)); - gcc_assert (object_sizes[object_size_type][varno] - != unknown (object_size_type)); + gcc_assert (!object_sizes_unknown_p (object_size_type, varno)); gcc_assert (osi->pass == 0); bytes = alloc_object_size (call, object_size_type); - if ((object_size_type & 2) == 0) - { - if (object_sizes[object_size_type][varno] < bytes) - object_sizes[object_size_type][varno] = bytes; - } - else - { - if (object_sizes[object_size_type][varno] > bytes) - object_sizes[object_size_type][varno] = bytes; - } + object_sizes_set (osi, varno, bytes); } @@ -776,12 +819,11 @@ unknown_object_size (struct object_size_info *osi, tree ptr) { int object_size_type = osi->object_size_type; unsigned int varno = SSA_NAME_VERSION (ptr); - unsigned HOST_WIDE_INT bytes = unknown (object_size_type); - gcc_checking_assert (object_sizes[object_size_type][varno] != bytes); + gcc_checking_assert (!object_sizes_unknown_p (object_size_type, varno)); gcc_checking_assert (osi->pass == 0); - object_sizes[object_size_type][varno] = bytes; + object_sizes_set (osi, varno, unknown (object_size_type)); } @@ -796,38 +838,24 @@ merge_object_sizes (struct object_size_info *osi, tree dest, tree orig, unsigned int varno = SSA_NAME_VERSION (dest); unsigned HOST_WIDE_INT orig_bytes; - if (object_sizes[object_size_type][varno] == unknown (object_size_type)) + if (object_sizes_unknown_p (object_size_type, varno)) return false; if (offset >= offset_limit) { - object_sizes[object_size_type][varno] = unknown (object_size_type); + object_sizes_set (osi, varno, unknown (object_size_type)); return false; } if (osi->pass == 0) collect_object_sizes_for (osi, orig); - orig_bytes = object_sizes[object_size_type][SSA_NAME_VERSION (orig)]; + orig_bytes = object_sizes_get (osi, SSA_NAME_VERSION (orig)); if (orig_bytes != unknown (object_size_type)) orig_bytes = (offset > orig_bytes) ? HOST_WIDE_INT_0U : orig_bytes - offset; - if ((object_size_type & 2) == 0) - { - if (object_sizes[object_size_type][varno] < orig_bytes) - { - object_sizes[object_size_type][varno] = orig_bytes; - osi->changed = true; - } - } - else - { - if (object_sizes[object_size_type][varno] > orig_bytes) - { - object_sizes[object_size_type][varno] = orig_bytes; - osi->changed = true; - } - } + osi->changed = object_sizes_set (osi, varno, orig_bytes); + return bitmap_bit_p (osi->reexamine, SSA_NAME_VERSION (orig)); } @@ -859,7 +887,7 @@ plus_stmt_object_size (struct object_size_info *osi, tree var, gimple *stmt) else gcc_unreachable (); - if (object_sizes[object_size_type][varno] == unknown (object_size_type)) + if (object_sizes_unknown_p (object_size_type, varno)) return false; /* Handle PTR + OFFSET here. */ @@ -890,16 +918,7 @@ plus_stmt_object_size (struct object_size_info *osi, tree var, gimple *stmt) else bytes = unknown (object_size_type); - if ((object_size_type & 2) == 0) - { - if (object_sizes[object_size_type][varno] < bytes) - object_sizes[object_size_type][varno] = bytes; - } - else - { - if (object_sizes[object_size_type][varno] > bytes) - object_sizes[object_size_type][varno] = bytes; - } + object_sizes_set (osi, varno, bytes); return false; } @@ -918,7 +937,7 @@ cond_expr_object_size (struct object_size_info *osi, tree var, gimple *stmt) gcc_assert (gimple_assign_rhs_code (stmt) == COND_EXPR); - if (object_sizes[object_size_type][varno] == unknown (object_size_type)) + if (object_sizes_unknown_p (object_size_type, varno)) return false; then_ = gimple_assign_rhs2 (stmt); @@ -929,7 +948,7 @@ cond_expr_object_size (struct object_size_info *osi, tree var, gimple *stmt) else expr_object_size (osi, var, then_); - if (object_sizes[object_size_type][varno] == unknown (object_size_type)) + if (object_sizes_unknown_p (object_size_type, varno)) return reexamine; if (TREE_CODE (else_) == SSA_NAME) @@ -975,8 +994,9 @@ collect_object_sizes_for (struct object_size_info *osi, tree var) { if (bitmap_set_bit (osi->visited, varno)) { - object_sizes[object_size_type][varno] - = (object_size_type & 2) ? -1 : 0; + /* Initialize to 0 for maximum size and M1U for minimum size so that + it gets immediately overridden. */ + object_sizes_set_force (osi, varno, unknown (object_size_type ^ 2)); } else { @@ -1047,7 +1067,7 @@ collect_object_sizes_for (struct object_size_info *osi, tree var) case GIMPLE_ASM: /* Pointers defined by __asm__ statements can point anywhere. */ - object_sizes[object_size_type][varno] = unknown (object_size_type); + object_sizes_set (osi, varno, unknown (object_size_type)); break; case GIMPLE_NOP: @@ -1056,7 +1076,7 @@ collect_object_sizes_for (struct object_size_info *osi, tree var) expr_object_size (osi, var, SSA_NAME_VAR (var)); else /* Uninitialized SSA names point nowhere. */ - object_sizes[object_size_type][varno] = unknown (object_size_type); + object_sizes_set (osi, varno, unknown (object_size_type)); break; case GIMPLE_PHI: @@ -1067,8 +1087,7 @@ collect_object_sizes_for (struct object_size_info *osi, tree var) { tree rhs = gimple_phi_arg (stmt, i)->def; - if (object_sizes[object_size_type][varno] - == unknown (object_size_type)) + if (object_sizes_unknown_p (object_size_type, varno)) break; if (TREE_CODE (rhs) == SSA_NAME) @@ -1083,8 +1102,7 @@ collect_object_sizes_for (struct object_size_info *osi, tree var) gcc_unreachable (); } - if (! reexamine - || object_sizes[object_size_type][varno] == unknown (object_size_type)) + if (! reexamine || object_sizes_unknown_p (object_size_type, varno)) { bitmap_set_bit (computed[object_size_type], varno); bitmap_clear_bit (osi->reexamine, varno); @@ -1124,7 +1142,7 @@ check_for_plus_in_loops_1 (struct object_size_info *osi, tree var, --sp; bitmap_clear_bit (osi->reexamine, *sp); bitmap_set_bit (computed[osi->object_size_type], *sp); - object_sizes[osi->object_size_type][*sp] = 0; + object_sizes_set_force (osi, *sp, 0); if (*sp == varno) break; } @@ -1248,7 +1266,7 @@ init_object_sizes (void) for (object_size_type = 0; object_size_type < OST_END; object_size_type++) { - object_sizes[object_size_type].safe_grow (num_ssa_names, true); + object_sizes_grow (object_size_type); computed[object_size_type] = BITMAP_ALLOC (NULL); } @@ -1265,7 +1283,7 @@ fini_object_sizes (void) for (object_size_type = 0; object_size_type < OST_END; object_size_type++) { - object_sizes[object_size_type].release (); + object_sizes_release (object_size_type); BITMAP_FREE (computed[object_size_type]); } } From patchwork Tue Nov 9 19:01:29 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Siddhesh Poyarekar X-Patchwork-Id: 47324 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 973DA385BF83 for ; Tue, 9 Nov 2021 19:03:46 +0000 (GMT) X-Original-To: gcc-patches@gcc.gnu.org Delivered-To: gcc-patches@gcc.gnu.org Received: from butterfly.birch.relay.mailchannels.net (butterfly.birch.relay.mailchannels.net [23.83.209.27]) by sourceware.org (Postfix) with ESMTPS id C8A013858018 for ; Tue, 9 Nov 2021 19:02:00 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.1 sourceware.org C8A013858018 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 DAB15920ABF; Tue, 9 Nov 2021 19:01:57 +0000 (UTC) Received: from pdx1-sub0-mail-a306.dreamhost.com (100-96-11-8.trex.outbound.svc.cluster.local [100.96.11.8]) (Authenticated sender: dreamhost) by relay.mailchannels.net (Postfix) with ESMTPA id 00312921E9A; Tue, 9 Nov 2021 19:01:56 +0000 (UTC) X-Sender-Id: dreamhost|x-authsender|siddhesh@gotplt.org Received: from pdx1-sub0-mail-a306.dreamhost.com (pop.dreamhost.com [64.90.62.162]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384) by 100.96.11.8 (trex/6.4.3); Tue, 09 Nov 2021 19:01:57 +0000 X-MC-Relay: Neutral X-MailChannels-SenderId: dreamhost|x-authsender|siddhesh@gotplt.org X-MailChannels-Auth-Id: dreamhost X-Army-Spot: 55ca409d717c58dd_1636484517395_940328468 X-MC-Loop-Signature: 1636484517395:3405290793 X-MC-Ingress-Time: 1636484517395 Received: from rhbox.redhat.com (unknown [1.186.121.127]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256) (No client certificate requested) (Authenticated sender: siddhesh@gotplt.org) by pdx1-sub0-mail-a306.dreamhost.com (Postfix) with ESMTPSA id 4Hpcm24CKKz2n; Tue, 9 Nov 2021 11:01:54 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha1; c=relaxed/relaxed; d=gotplt.org; s=gotplt.org; t=1636484516; bh=pkAIYTEhLzmlgF67QnsBoN86GrA=; h=From:To:Cc:Subject:Date:Content-Transfer-Encoding; b=jWfBFVM1r1BG/RwbEsx6aXPjpI++kFZfCGnW7ieTvxpMRPEfNgO29qGEuCty7Ft5O zKWU0zn8qGFSnwWg9L3Yu4TxvFmwUvnr1wCNPWDkROpq7UlsYzXxUdB9DsvAvr0AWC Gd4DQji9t9+EE7azMTbM0Ze8OzO8ZMYicWCI1u9o= From: Siddhesh Poyarekar To: gcc-patches@gcc.gnu.org Subject: [PATCH 03/10] tree-object-size: Use tree instead of HOST_WIDE_INT Date: Wed, 10 Nov 2021 00:31:29 +0530 Message-Id: <20211109190137.1107736-4-siddhesh@gotplt.org> X-Mailer: git-send-email 2.31.1 In-Reply-To: <20211109190137.1107736-1-siddhesh@gotplt.org> References: <20211109190137.1107736-1-siddhesh@gotplt.org> MIME-Version: 1.0 X-Spam-Status: No, score=-3038.0 required=5.0 tests=BAYES_00, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, GIT_PATCH_0, RCVD_IN_BARRACUDACENTRAL, RCVD_IN_DNSWL_NONE, RCVD_IN_MSPIKE_H3, RCVD_IN_MSPIKE_WL, RCVD_IN_SBL, 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" Transform tree-object-size to operate on tree objects instead of host wide integers. This makes it easier to extend to dynamic expressions for object sizes. The compute_builtin_object_size interface also now returns a tree expression instead of HOST_WIDE_INT, so callers have been adjusted to account for that. gcc/ChangeLog: * tree-object-size.h (compute_builtin_object_size): Return tree instead of HOST_WIDE_INT. * builtins.c (fold_builtin_object_size): Adjust. * gimple-fold.c (gimple_fold_builtin_strncat): Likewise. * ubsan.c (instrument_object_size): Likewise. * tree-object-size.c (object_sizes): Change type to vec. (initval): New function. (unknown): Use it. (size_unknown_p, size_initval, size_unknown): New functions. (object_sizes_unknown_p): Use it. (object_sizes_get): Return tree. (object_sizes_initialize): Rename from object_sizes_set_force and set VAL parameter type as tree. (object_sizes_set): Set VAL parameter type as tree and adjust implementation. (size_for_offset): New function. (addr_object_size): Change PSIZE parameter to tree and adjust implementation. (alloc_object_size): Return tree. (compute_builtin_object_size): Return tree in PSIZE. (expr_object_size, call_object_size, unknown_object_size): Adjust for object_sizes_set change. (merge_object_sizes): Set OFFSET type to tree and adjust implementation. (plus_stmt_object_size, cond_expr_object_size, collect_object_sizes_for, check_for_plus_in_loops_1): Adjust for change of type from HOST_WIDE_INT to tree. (object_sizes_execute): Adjust for type change to tree. Signed-off-by: Siddhesh Poyarekar --- gcc/builtins.c | 10 +- gcc/gimple-fold.c | 9 +- gcc/tree-object-size.c | 253 ++++++++++++++++++++++------------------- gcc/tree-object-size.h | 2 +- gcc/ubsan.c | 46 ++++---- 5 files changed, 168 insertions(+), 152 deletions(-) diff --git a/gcc/builtins.c b/gcc/builtins.c index 384864bfb3a..d2e6d95a175 100644 --- a/gcc/builtins.c +++ b/gcc/builtins.c @@ -10226,7 +10226,7 @@ maybe_emit_sprintf_chk_warning (tree exp, enum built_in_function fcode) static tree fold_builtin_object_size (tree ptr, tree ost) { - unsigned HOST_WIDE_INT bytes; + tree bytes; int object_size_type; if (!validate_arg (ptr, POINTER_TYPE) @@ -10251,17 +10251,15 @@ fold_builtin_object_size (tree ptr, tree ost) if (TREE_CODE (ptr) == ADDR_EXPR) { compute_builtin_object_size (ptr, object_size_type, &bytes); - if (wi::fits_to_tree_p (bytes, size_type_node)) - return build_int_cstu (size_type_node, bytes); + return fold_convert (size_type_node, bytes); } else if (TREE_CODE (ptr) == SSA_NAME) { /* If object size is not known yet, delay folding until later. Maybe subsequent passes will help determining it. */ - if (compute_builtin_object_size (ptr, object_size_type, &bytes) - && wi::fits_to_tree_p (bytes, size_type_node)) - return build_int_cstu (size_type_node, bytes); + if (compute_builtin_object_size (ptr, object_size_type, &bytes)) + return fold_convert (size_type_node, bytes); } return NULL_TREE; diff --git a/gcc/gimple-fold.c b/gcc/gimple-fold.c index 6e25a7c05db..cbd0fb08f80 100644 --- a/gcc/gimple-fold.c +++ b/gcc/gimple-fold.c @@ -2486,13 +2486,14 @@ gimple_fold_builtin_strncat (gimple_stmt_iterator *gsi) if (cmpsrc < 0) return false; - unsigned HOST_WIDE_INT dstsize; + tree dstsize; bool nowarn = warning_suppressed_p (stmt, OPT_Wstringop_overflow_); - if (!nowarn && compute_builtin_object_size (dst, 1, &dstsize)) + if (!nowarn && compute_builtin_object_size (dst, 1, &dstsize) + && tree_fits_uhwi_p (dstsize)) { - int cmpdst = compare_tree_int (len, dstsize); + int cmpdst = compare_tree_int (len, tree_to_uhwi (dstsize)); if (cmpdst >= 0) { @@ -2509,7 +2510,7 @@ gimple_fold_builtin_strncat (gimple_stmt_iterator *gsi) "destination size") : G_("%qD specified bound %E exceeds " "destination size %wu"), - fndecl, len, dstsize); + fndecl, len, tree_to_uhwi (dstsize)); if (nowarn) suppress_warning (stmt, OPT_Wstringop_overflow_); } diff --git a/gcc/tree-object-size.c b/gcc/tree-object-size.c index 7a22539cc43..4b9c45c6af2 100644 --- a/gcc/tree-object-size.c +++ b/gcc/tree-object-size.c @@ -54,13 +54,12 @@ enum static tree compute_object_offset (const_tree, const_tree); static bool addr_object_size (struct object_size_info *, - const_tree, int, unsigned HOST_WIDE_INT *); -static unsigned HOST_WIDE_INT alloc_object_size (const gcall *, int); + const_tree, int, tree *); +static tree alloc_object_size (const gcall *, int); static tree pass_through_call (const gcall *); static void collect_object_sizes_for (struct object_size_info *, tree); static void expr_object_size (struct object_size_info *, tree, tree); -static bool merge_object_sizes (struct object_size_info *, tree, tree, - unsigned HOST_WIDE_INT); +static bool merge_object_sizes (struct object_size_info *, tree, tree, tree); static bool plus_stmt_object_size (struct object_size_info *, tree, gimple *); static bool cond_expr_object_size (struct object_size_info *, tree, gimple *); static void init_offset_limit (void); @@ -74,7 +73,7 @@ static void check_for_plus_in_loops_1 (struct object_size_info *, tree, 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. */ -static vec object_sizes[OST_END]; +static vec object_sizes[OST_END]; /* Bitmaps what object sizes have been computed already. */ static bitmap computed[OST_END]; @@ -82,10 +81,47 @@ static bitmap computed[OST_END]; /* Maximum value of offset we consider to be addition. */ static unsigned HOST_WIDE_INT offset_limit; +/* Initial value of object sizes; zero for maximum and SIZE_MAX for minimum + object size. */ + +static inline unsigned HOST_WIDE_INT +initval (int object_size_type) +{ + return (unsigned HOST_WIDE_INT) -popcount_hwi (object_size_type + & OST_MINIMUM); +} + +/* Unknown object size value; it's the opposite of initval. */ + static inline unsigned HOST_WIDE_INT unknown (int object_size_type) { - return ((unsigned HOST_WIDE_INT) -((object_size_type >> 1) ^ 1)); + return ~initval (object_size_type); +} + +/* Return true if VAL is represents an unknown size for OBJECT_SIZE_TYPE. */ + +static inline bool +size_unknown_p (tree val, int object_size_type) +{ + return (tree_fits_uhwi_p (val) + && tree_to_uhwi (val) == unknown (object_size_type)); +} + +/* Return a tree with initial value for OBJECT_SIZE_TYPE. */ + +static inline tree +size_initval (int object_size_type) +{ + return size_int (initval (object_size_type)); +} + +/* Return a tree with unknown value for OBJECT_SIZE_TYPE. */ + +static inline tree +size_unknown (int object_size_type) +{ + return size_int (unknown (object_size_type)); } /* Grow object_sizes[OBJECT_SIZE_TYPE] to num_ssa_names. */ @@ -110,13 +146,13 @@ object_sizes_release (int object_size_type) static inline bool object_sizes_unknown_p (int object_size_type, unsigned varno) { - return (object_sizes[object_size_type][varno] - == unknown (object_size_type)); + return size_unknown_p (object_sizes[object_size_type][varno], + object_size_type); } /* Return size for VARNO corresponding to OSI. */ -static inline unsigned HOST_WIDE_INT +static inline tree object_sizes_get (struct object_size_info *osi, unsigned varno) { return object_sizes[osi->object_size_type][varno]; @@ -124,33 +160,32 @@ object_sizes_get (struct object_size_info *osi, unsigned varno) /* Set size for VARNO corresponding to OSI to VAL. */ -static inline bool -object_sizes_set_force (struct object_size_info *osi, unsigned varno, - unsigned HOST_WIDE_INT val) +static inline void +object_sizes_initialize (struct object_size_info *osi, unsigned varno, + tree val = NULL_TREE) { - object_sizes[osi->object_size_type][varno] = val; - return true; + int object_size_type = osi->object_size_type; + + if (!val) + val = size_initval (object_size_type); + object_sizes[object_size_type][varno] = val; } /* Set size for VARNO corresponding to OSI to VAL if it is the new minimum or maximum. */ static inline bool -object_sizes_set (struct object_size_info *osi, unsigned varno, - unsigned HOST_WIDE_INT val) +object_sizes_set (struct object_size_info *osi, unsigned varno, tree val) { int object_size_type = osi->object_size_type; - if ((object_size_type & OST_MINIMUM) == 0) - { - if (object_sizes[object_size_type][varno] < val) - return object_sizes_set_force (osi, varno, val); - } - else - { - if (object_sizes[object_size_type][varno] > val) - return object_sizes_set_force (osi, varno, val); - } - return false; + tree oldval = object_sizes[object_size_type][varno]; + + enum tree_code code = object_size_type & OST_MINIMUM ? MIN_EXPR : MAX_EXPR; + + if (compare_tree_int (oldval, initval (object_size_type)) != 0) + val = size_binop (code, val, oldval); + object_sizes[object_size_type][varno] = val; + return tree_int_cst_compare (val, oldval) != 0; } /* Initialize OFFSET_LIMIT variable. */ @@ -164,6 +199,13 @@ init_offset_limit (void) offset_limit /= 2; } +/* Bytes at end of the object with SZ from offset OFFSET. */ + +static tree +size_for_offset (tree sz, tree offset) +{ + return size_binop (MINUS_EXPR, size_binop (MAX_EXPR, sz, offset), offset); +} /* Compute offset of EXPR within VAR. Return error_mark_node if unknown. */ @@ -274,11 +316,11 @@ decl_init_size (tree decl, bool min) /* Compute __builtin_object_size for PTR, which is a ADDR_EXPR. OBJECT_SIZE_TYPE is the second argument from __builtin_object_size. - If unknown, return unknown (object_size_type). */ + If unknown, return size_unknown (object_size_type). */ static bool addr_object_size (struct object_size_info *osi, const_tree ptr, - int object_size_type, unsigned HOST_WIDE_INT *psize) + int object_size_type, tree *psize) { tree pt_var, pt_var_size = NULL_TREE, var_size, bytes; @@ -286,7 +328,7 @@ addr_object_size (struct object_size_info *osi, const_tree ptr, /* Set to unknown and overwrite just before returning if the size could be determined. */ - *psize = unknown (object_size_type); + *psize = size_unknown (object_size_type); pt_var = TREE_OPERAND (ptr, 0); while (handled_component_p (pt_var)) @@ -297,7 +339,7 @@ addr_object_size (struct object_size_info *osi, const_tree ptr, if (TREE_CODE (pt_var) == MEM_REF) { - unsigned HOST_WIDE_INT sz; + tree sz; if (!osi || (object_size_type & OST_SUBOBJECT) != 0 || TREE_CODE (TREE_OPERAND (pt_var, 0)) != SSA_NAME) @@ -314,27 +356,22 @@ addr_object_size (struct object_size_info *osi, const_tree ptr, SSA_NAME_VERSION (var))) sz = object_sizes_get (osi, SSA_NAME_VERSION (var)); else - sz = unknown (object_size_type); + sz = size_unknown (object_size_type); } - if (sz != unknown (object_size_type)) + if (!size_unknown_p (sz, object_size_type)) { - offset_int mem_offset; - if (mem_ref_offset (pt_var).is_constant (&mem_offset)) - { - offset_int dsz = wi::sub (sz, mem_offset); - if (wi::neg_p (dsz)) - sz = 0; - else if (wi::fits_uhwi_p (dsz)) - sz = dsz.to_uhwi (); - else - sz = unknown (object_size_type); - } + tree offset = TREE_OPERAND (pt_var, 1); + if (TREE_CODE (offset) != INTEGER_CST + || TREE_CODE (sz) != INTEGER_CST) + sz = size_unknown (object_size_type); else - sz = unknown (object_size_type); + sz = size_for_offset (sz, offset); } - if (sz != unknown (object_size_type) && sz < offset_limit) - pt_var_size = size_int (sz); + if (!size_unknown_p (sz, object_size_type) + && TREE_CODE (sz) == INTEGER_CST + && compare_tree_int (sz, offset_limit) < 0) + pt_var_size = sz; } else if (DECL_P (pt_var)) { @@ -350,8 +387,7 @@ addr_object_size (struct object_size_info *osi, const_tree ptr, if (pt_var_size) { /* Validate the size determined above. */ - if (!tree_fits_uhwi_p (pt_var_size) - || tree_to_uhwi (pt_var_size) >= offset_limit) + if (compare_tree_int (pt_var_size, offset_limit) >= 0) return false; } @@ -502,22 +538,17 @@ addr_object_size (struct object_size_info *osi, const_tree ptr, else bytes = pt_var_size; - if (tree_fits_uhwi_p (bytes)) - { - *psize = tree_to_uhwi (bytes); - return true; - } - - return false; + *psize = bytes; + return true; } /* Compute __builtin_object_size for CALL, which is a GIMPLE_CALL. Handles calls to functions declared with attribute alloc_size. OBJECT_SIZE_TYPE is the second argument from __builtin_object_size. - If unknown, return unknown (object_size_type). */ + If unknown, return size_unknown (object_size_type). */ -static unsigned HOST_WIDE_INT +static tree alloc_object_size (const gcall *call, int object_size_type) { gcc_assert (is_gimple_call (call)); @@ -529,7 +560,7 @@ alloc_object_size (const gcall *call, int object_size_type) calltype = gimple_call_fntype (call); if (!calltype) - return unknown (object_size_type); + return size_unknown (object_size_type); /* Set to positions of alloc_size arguments. */ int arg1 = -1, arg2 = -1; @@ -549,7 +580,7 @@ alloc_object_size (const gcall *call, int object_size_type) || (arg2 >= 0 && (arg2 >= (int)gimple_call_num_args (call) || TREE_CODE (gimple_call_arg (call, arg2)) != INTEGER_CST))) - return unknown (object_size_type); + return size_unknown (object_size_type); tree bytes = NULL_TREE; if (arg2 >= 0) @@ -559,10 +590,7 @@ alloc_object_size (const gcall *call, int object_size_type) else if (arg1 >= 0) bytes = fold_convert (sizetype, gimple_call_arg (call, arg1)); - if (bytes && tree_fits_uhwi_p (bytes)) - return tree_to_uhwi (bytes); - - return unknown (object_size_type); + return bytes; } @@ -598,13 +626,13 @@ pass_through_call (const gcall *call) bool compute_builtin_object_size (tree ptr, int object_size_type, - unsigned HOST_WIDE_INT *psize) + tree *psize) { gcc_assert (object_size_type >= 0 && object_size_type < OST_END); /* Set to unknown and overwrite just before returning if the size could be determined. */ - *psize = unknown (object_size_type); + *psize = size_unknown (object_size_type); if (! offset_limit) init_offset_limit (); @@ -638,8 +666,7 @@ compute_builtin_object_size (tree ptr, int object_size_type, psize)) { /* Return zero when the offset is out of bounds. */ - unsigned HOST_WIDE_INT off = tree_to_shwi (offset); - *psize = off < *psize ? *psize - off : 0; + *psize = size_for_offset (*psize, offset); return true; } } @@ -747,12 +774,13 @@ compute_builtin_object_size (tree ptr, int object_size_type, print_generic_expr (dump_file, ssa_name (i), dump_flags); fprintf (dump_file, - ": %s %sobject size " - HOST_WIDE_INT_PRINT_UNSIGNED "\n", + ": %s %sobject size ", ((object_size_type & OST_MINIMUM) ? "minimum" : "maximum"), - (object_size_type & OST_SUBOBJECT) ? "sub" : "", - object_sizes_get (&osi, i)); + (object_size_type & OST_SUBOBJECT) ? "sub" : ""); + print_generic_expr (dump_file, object_sizes_get (&osi, i), + dump_flags); + fprintf (dump_file, "\n"); } } @@ -761,7 +789,7 @@ compute_builtin_object_size (tree ptr, int object_size_type, } *psize = object_sizes_get (&osi, SSA_NAME_VERSION (ptr)); - return *psize != unknown (object_size_type); + return !size_unknown_p (*psize, object_size_type); } /* Compute object_sizes for PTR, defined to VALUE, which is not an SSA_NAME. */ @@ -771,7 +799,7 @@ expr_object_size (struct object_size_info *osi, tree ptr, tree value) { int object_size_type = osi->object_size_type; unsigned int varno = SSA_NAME_VERSION (ptr); - unsigned HOST_WIDE_INT bytes; + tree bytes; gcc_assert (!object_sizes_unknown_p (object_size_type, varno)); gcc_assert (osi->pass == 0); @@ -786,7 +814,7 @@ expr_object_size (struct object_size_info *osi, tree ptr, tree value) if (TREE_CODE (value) == ADDR_EXPR) addr_object_size (osi, value, object_size_type, &bytes); else - bytes = unknown (object_size_type); + bytes = size_unknown (object_size_type); object_sizes_set (osi, varno, bytes); } @@ -799,16 +827,13 @@ call_object_size (struct object_size_info *osi, tree ptr, gcall *call) { int object_size_type = osi->object_size_type; unsigned int varno = SSA_NAME_VERSION (ptr); - unsigned HOST_WIDE_INT bytes; gcc_assert (is_gimple_call (call)); gcc_assert (!object_sizes_unknown_p (object_size_type, varno)); gcc_assert (osi->pass == 0); - bytes = alloc_object_size (call, object_size_type); - - object_sizes_set (osi, varno, bytes); + object_sizes_set (osi, varno, alloc_object_size (call, object_size_type)); } @@ -823,7 +848,7 @@ unknown_object_size (struct object_size_info *osi, tree ptr) gcc_checking_assert (!object_sizes_unknown_p (object_size_type, varno)); gcc_checking_assert (osi->pass == 0); - object_sizes_set (osi, varno, unknown (object_size_type)); + object_sizes_set (osi, varno, size_unknown (object_size_type)); } @@ -832,17 +857,17 @@ unknown_object_size (struct object_size_info *osi, tree ptr) static bool merge_object_sizes (struct object_size_info *osi, tree dest, tree orig, - unsigned HOST_WIDE_INT offset) + tree offset) { int object_size_type = osi->object_size_type; unsigned int varno = SSA_NAME_VERSION (dest); - unsigned HOST_WIDE_INT orig_bytes; + tree orig_bytes; if (object_sizes_unknown_p (object_size_type, varno)) return false; - if (offset >= offset_limit) + if (compare_tree_int (offset, offset_limit) >= 0) { - object_sizes_set (osi, varno, unknown (object_size_type)); + object_sizes_set (osi, varno, size_unknown (object_size_type)); return false; } @@ -850,9 +875,8 @@ merge_object_sizes (struct object_size_info *osi, tree dest, tree orig, collect_object_sizes_for (osi, orig); orig_bytes = object_sizes_get (osi, SSA_NAME_VERSION (orig)); - if (orig_bytes != unknown (object_size_type)) - orig_bytes = (offset > orig_bytes) - ? HOST_WIDE_INT_0U : orig_bytes - offset; + if (!size_unknown_p (orig_bytes, object_size_type)) + orig_bytes = size_for_offset (orig_bytes, offset); osi->changed = object_sizes_set (osi, varno, orig_bytes); @@ -869,7 +893,7 @@ plus_stmt_object_size (struct object_size_info *osi, tree var, gimple *stmt) { int object_size_type = osi->object_size_type; unsigned int varno = SSA_NAME_VERSION (var); - unsigned HOST_WIDE_INT bytes; + tree bytes; tree op0, op1; if (gimple_assign_rhs_code (stmt) == POINTER_PLUS_EXPR) @@ -895,28 +919,22 @@ plus_stmt_object_size (struct object_size_info *osi, tree var, gimple *stmt) && (TREE_CODE (op0) == SSA_NAME || TREE_CODE (op0) == ADDR_EXPR)) { - if (! tree_fits_uhwi_p (op1)) - bytes = unknown (object_size_type); - else if (TREE_CODE (op0) == SSA_NAME) - return merge_object_sizes (osi, var, op0, tree_to_uhwi (op1)); + if (TREE_CODE (op0) == SSA_NAME) + return merge_object_sizes (osi, var, op0, op1); else { - unsigned HOST_WIDE_INT off = tree_to_uhwi (op1); - /* op0 will be ADDR_EXPR here. */ addr_object_size (osi, op0, object_size_type, &bytes); - if (bytes == unknown (object_size_type)) + if (size_unknown_p (bytes, object_size_type)) ; - else if (off > offset_limit) - bytes = unknown (object_size_type); - else if (off > bytes) - bytes = 0; + else if (compare_tree_int (op1, offset_limit) > 0) + bytes = size_unknown (object_size_type); else - bytes -= off; + bytes = size_for_offset (bytes, op1); } } else - bytes = unknown (object_size_type); + bytes = size_unknown (object_size_type); object_sizes_set (osi, varno, bytes); return false; @@ -944,7 +962,7 @@ cond_expr_object_size (struct object_size_info *osi, tree var, gimple *stmt) else_ = gimple_assign_rhs3 (stmt); if (TREE_CODE (then_) == SSA_NAME) - reexamine |= merge_object_sizes (osi, var, then_, 0); + reexamine |= merge_object_sizes (osi, var, then_, size_int (0)); else expr_object_size (osi, var, then_); @@ -952,7 +970,7 @@ cond_expr_object_size (struct object_size_info *osi, tree var, gimple *stmt) return reexamine; if (TREE_CODE (else_) == SSA_NAME) - reexamine |= merge_object_sizes (osi, var, else_, 0); + reexamine |= merge_object_sizes (osi, var, else_, size_int (0)); else expr_object_size (osi, var, else_); @@ -969,11 +987,11 @@ cond_expr_object_size (struct object_size_info *osi, tree var, gimple *stmt) object size is object size of the first operand minus the constant. If the constant is bigger than the number of remaining bytes until the end of the object, object size is 0, but if it is instead a pointer - subtraction, object size is unknown (object_size_type). + subtraction, object size is size_unknown (object_size_type). To differentiate addition from subtraction, ADDR_EXPR returns - unknown (object_size_type) for all objects bigger than half of the address - space, and constants less than half of the address space are considered - addition, while bigger constants subtraction. + size_unknown (object_size_type) for all objects bigger than half of the + address space, and constants less than half of the address space are + considered addition, while bigger constants subtraction. For a memcpy like GIMPLE_CALL that always returns one of its arguments, the object size is object size of that argument. Otherwise, object size is the maximum of object sizes of variables @@ -996,7 +1014,7 @@ collect_object_sizes_for (struct object_size_info *osi, tree var) { /* Initialize to 0 for maximum size and M1U for minimum size so that it gets immediately overridden. */ - object_sizes_set_force (osi, varno, unknown (object_size_type ^ 2)); + object_sizes_initialize (osi, varno); } else { @@ -1039,7 +1057,7 @@ collect_object_sizes_for (struct object_size_info *osi, tree var) { if (TREE_CODE (rhs) == SSA_NAME && POINTER_TYPE_P (TREE_TYPE (rhs))) - reexamine = merge_object_sizes (osi, var, rhs, 0); + reexamine = merge_object_sizes (osi, var, rhs, size_int (0)); else expr_object_size (osi, var, rhs); } @@ -1056,7 +1074,7 @@ collect_object_sizes_for (struct object_size_info *osi, tree var) { if (TREE_CODE (arg) == SSA_NAME && POINTER_TYPE_P (TREE_TYPE (arg))) - reexamine = merge_object_sizes (osi, var, arg, 0); + reexamine = merge_object_sizes (osi, var, arg, size_int (0)); else expr_object_size (osi, var, arg); } @@ -1067,7 +1085,7 @@ collect_object_sizes_for (struct object_size_info *osi, tree var) case GIMPLE_ASM: /* Pointers defined by __asm__ statements can point anywhere. */ - object_sizes_set (osi, varno, unknown (object_size_type)); + object_sizes_set (osi, varno, size_unknown (object_size_type)); break; case GIMPLE_NOP: @@ -1076,7 +1094,7 @@ collect_object_sizes_for (struct object_size_info *osi, tree var) expr_object_size (osi, var, SSA_NAME_VAR (var)); else /* Uninitialized SSA names point nowhere. */ - object_sizes_set (osi, varno, unknown (object_size_type)); + object_sizes_set (osi, varno, size_unknown (object_size_type)); break; case GIMPLE_PHI: @@ -1091,7 +1109,7 @@ collect_object_sizes_for (struct object_size_info *osi, tree var) break; if (TREE_CODE (rhs) == SSA_NAME) - reexamine |= merge_object_sizes (osi, var, rhs, 0); + reexamine |= merge_object_sizes (osi, var, rhs, size_int (0)); else if (osi->pass == 0) expr_object_size (osi, var, rhs); } @@ -1142,7 +1160,7 @@ check_for_plus_in_loops_1 (struct object_size_info *osi, tree var, --sp; bitmap_clear_bit (osi->reexamine, *sp); bitmap_set_bit (computed[osi->object_size_type], *sp); - object_sizes_set_force (osi, *sp, 0); + object_sizes_set (osi, *sp, size_int (0)); if (*sp == varno) break; } @@ -1333,17 +1351,16 @@ object_sizes_execute (function *fun, bool insert_min_max_p) || TREE_CODE (ptr) == SSA_NAME)) { tree type = TREE_TYPE (lhs); - unsigned HOST_WIDE_INT bytes; + tree bytes; if (compute_builtin_object_size (ptr, object_size_type, - &bytes) - && wi::fits_to_tree_p (bytes, type)) + &bytes)) { tree tem = make_ssa_name (type); gimple_call_set_lhs (call, tem); enum tree_code code = (object_size_type & OST_MINIMUM ? MAX_EXPR : MIN_EXPR); - tree cst = build_int_cstu (type, bytes); + tree cst = fold_convert (type, bytes); gimple *g = gimple_build_assign (lhs, code, tem, cst); gsi_insert_after (&i, g, GSI_NEW_STMT); diff --git a/gcc/tree-object-size.h b/gcc/tree-object-size.h index ef18aea50db..b2d6a58324c 100644 --- a/gcc/tree-object-size.h +++ b/gcc/tree-object-size.h @@ -22,7 +22,7 @@ along with GCC; see the file COPYING3. If not see extern void init_object_sizes (void); extern void fini_object_sizes (void); -extern bool compute_builtin_object_size (tree, int, unsigned HOST_WIDE_INT *); +extern bool compute_builtin_object_size (tree, int, tree *); extern tree decl_init_size (tree, bool); #endif // GCC_TREE_OBJECT_SIZE_H diff --git a/gcc/ubsan.c b/gcc/ubsan.c index ba9adf0ad96..2b1b7571e25 100644 --- a/gcc/ubsan.c +++ b/gcc/ubsan.c @@ -2160,33 +2160,33 @@ instrument_object_size (gimple_stmt_iterator *gsi, tree t, bool is_lhs) if (decl_p) base_addr = build1 (ADDR_EXPR, build_pointer_type (TREE_TYPE (base)), base); - unsigned HOST_WIDE_INT size; - if (compute_builtin_object_size (base_addr, 0, &size)) - sizet = build_int_cst (sizetype, size); - else if (optimize) - { - if (LOCATION_LOCUS (loc) == UNKNOWN_LOCATION) - loc = input_location; - /* Generate __builtin_object_size call. */ - sizet = builtin_decl_explicit (BUILT_IN_OBJECT_SIZE); - sizet = build_call_expr_loc (loc, sizet, 2, base_addr, - integer_zero_node); - sizet = force_gimple_operand_gsi (gsi, sizet, false, NULL_TREE, true, - GSI_SAME_STMT); - /* If the call above didn't end up being an integer constant, go one - statement back and get the __builtin_object_size stmt. Save it, - we might need it later. */ - if (SSA_VAR_P (sizet)) + if (!compute_builtin_object_size (base_addr, 0, &sizet)) + { + if (optimize) { - gsi_prev (gsi); - bos_stmt = gsi_stmt (*gsi); + if (LOCATION_LOCUS (loc) == UNKNOWN_LOCATION) + loc = input_location; + /* Generate __builtin_object_size call. */ + sizet = builtin_decl_explicit (BUILT_IN_OBJECT_SIZE); + sizet = build_call_expr_loc (loc, sizet, 2, base_addr, + integer_zero_node); + sizet = force_gimple_operand_gsi (gsi, sizet, false, NULL_TREE, true, + GSI_SAME_STMT); + /* If the call above didn't end up being an integer constant, go one + statement back and get the __builtin_object_size stmt. Save it, + we might need it later. */ + if (SSA_VAR_P (sizet)) + { + gsi_prev (gsi); + bos_stmt = gsi_stmt (*gsi); - /* Move on to where we were. */ - gsi_next (gsi); + /* Move on to where we were. */ + gsi_next (gsi); + } } + else + return; } - else - return; /* Generate UBSAN_OBJECT_SIZE (ptr, ptr+sizeof(*ptr)-base, objsize, ckind) call. */ From patchwork Tue Nov 9 19:01:30 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Siddhesh Poyarekar X-Patchwork-Id: 47325 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 440B03857C42 for ; Tue, 9 Nov 2021 19:04:24 +0000 (GMT) X-Original-To: gcc-patches@gcc.gnu.org Delivered-To: gcc-patches@gcc.gnu.org Received: from giraffe.ash.relay.mailchannels.net (giraffe.ash.relay.mailchannels.net [23.83.222.69]) by sourceware.org (Postfix) with ESMTPS id AFAEC3857C70 for ; Tue, 9 Nov 2021 19:02:03 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.1 sourceware.org AFAEC3857C70 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 B4B584020B8; Tue, 9 Nov 2021 19:01:59 +0000 (UTC) Received: from pdx1-sub0-mail-a306.dreamhost.com (100-96-17-28.trex.outbound.svc.cluster.local [100.96.17.28]) (Authenticated sender: dreamhost) by relay.mailchannels.net (Postfix) with ESMTPA id 4F3C640228F; Tue, 9 Nov 2021 19:01:59 +0000 (UTC) X-Sender-Id: dreamhost|x-authsender|siddhesh@gotplt.org Received: from pdx1-sub0-mail-a306.dreamhost.com (pop.dreamhost.com [64.90.62.162]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384) by 100.96.17.28 (trex/6.4.3); Tue, 09 Nov 2021 19:01:59 +0000 X-MC-Relay: Neutral X-MailChannels-SenderId: dreamhost|x-authsender|siddhesh@gotplt.org X-MailChannels-Auth-Id: dreamhost X-Scare-Oafish: 70ef8b465c32cefd_1636484519591_674680650 X-MC-Loop-Signature: 1636484519591:1832417153 X-MC-Ingress-Time: 1636484519590 Received: from rhbox.redhat.com (unknown [1.186.121.127]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256) (No client certificate requested) (Authenticated sender: siddhesh@gotplt.org) by pdx1-sub0-mail-a306.dreamhost.com (Postfix) with ESMTPSA id 4Hpcm52kRSz1WX; Tue, 9 Nov 2021 11:01:57 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha1; c=relaxed/relaxed; d=gotplt.org; s=gotplt.org; t=1636484519; bh=9mPf+lU152stQVnGxmXBU8B6jHI=; h=From:To:Cc:Subject:Date:Content-Transfer-Encoding; b=htAPm0qmYFSnWsid//qGb+xCyxStwzLI0dzwpGvtPoPKxQdJB5Z0n5Hjsg6hh145t p9/gwmcLRQ5VdoLGav7cW4Cz6l2B9oO01fcEOQqGfHmiTUa5vgEyKRTCr9EpJyQC1d 0eACArfNuaKQl/IksRTnt0Kl1AKQWN8zvPi3NpTw= From: Siddhesh Poyarekar To: gcc-patches@gcc.gnu.org Subject: [PATCH 04/10] tree-object-size: Single pass dependency loop resolution Date: Wed, 10 Nov 2021 00:31:30 +0530 Message-Id: <20211109190137.1107736-5-siddhesh@gotplt.org> X-Mailer: git-send-email 2.31.1 In-Reply-To: <20211109190137.1107736-1-siddhesh@gotplt.org> References: <20211109190137.1107736-1-siddhesh@gotplt.org> MIME-Version: 1.0 X-Spam-Status: No, score=-3038.0 required=5.0 tests=BAYES_00, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, GIT_PATCH_0, RCVD_IN_BARRACUDACENTRAL, RCVD_IN_DNSWL_NONE, RCVD_IN_MSPIKE_H3, RCVD_IN_MSPIKE_WL, RCVD_IN_SBL, 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" Use SSA names as placeholders self-referencing variables to generate expressions for object sizes and then reduce those size expressions to constants instead of repeatedly walking through statements. This change also makes sure that object sizes for an SSA name are updated at most twice, once if there is a dependency loop and then the final time upon computation of object size. Iteration to deduce the final size is now done on the size expressions instead of walking through the object references. Added test to include a case where __builtin_object_size incorrectly returned the minimum object size as zero. gcc/ChangeLog: * tree-object-size.c (struct object_size_info): Remove pass, changed, depths, stack and tos. Add tempsize_objs. (OST_TREE_CODE): New macro. (expr_object_size, merge_object_sizes, plus_stmt_object_size, cond_expr_object_size): Return tree and don't pass pointer tree. (object_sizes_set): Return void. Adjust implementation to hold placeholder SSA names and their values in different slots. (addr_object_size): Adjust for single pass. (reducing_size, estimate_size, resolve_dependency_loops): New functions. (compute_builtin_object_size): Call them. (make_tempsize): New function. (collect_object_sizes_for): Use it. Update object_sizes at most twice. (check_for_plus_in_loops, check_for_plus_in_loops_1): Remove functions. gcc/testsuite/ChangeLog: * gcc.dg/builtin-object-size-1.c (test6): New test for passthrough. * gcc.dg/builtin-object-size-2.c: Likewise. * gcc.dg/builtin-object-size-3.c: Likewise. * gcc.dg/builtin-object-size-4.c: Likewise. Signed-off-by: Siddhesh Poyarekar --- gcc/testsuite/gcc.dg/builtin-object-size-1.c | 16 + gcc/testsuite/gcc.dg/builtin-object-size-2.c | 16 + gcc/testsuite/gcc.dg/builtin-object-size-3.c | 16 + gcc/testsuite/gcc.dg/builtin-object-size-4.c | 16 + gcc/tree-object-size.c | 724 +++++++++---------- 5 files changed, 424 insertions(+), 364 deletions(-) diff --git a/gcc/testsuite/gcc.dg/builtin-object-size-1.c b/gcc/testsuite/gcc.dg/builtin-object-size-1.c index 8cdae49a6b1..b270e8d8827 100644 --- a/gcc/testsuite/gcc.dg/builtin-object-size-1.c +++ b/gcc/testsuite/gcc.dg/builtin-object-size-1.c @@ -376,6 +376,7 @@ test6 (size_t x) { struct T { char buf[64]; char buf2[64]; } t; char *p = &t.buf[8]; + char *r = t.buf2; size_t i; for (i = 0; i < x; ++i) @@ -383,6 +384,21 @@ test6 (size_t x) if (__builtin_object_size (p, 0) != sizeof (t) - 8) abort (); memset (p, ' ', sizeof (t) - 8 - 4 * 4); + p = &t.buf[8]; + for (i = 0; i < x; i++) + { + r = __builtin_memcpy (r, t.buf, i); + p = r + 1; + } + if (__builtin_object_size (p, 0) != sizeof (t) - 8) + abort (); + for (i = 0; i < x; i++) + { + r = __builtin_mempcpy (r, t.buf, i); + p = r + 1; + } + if (__builtin_object_size (p, 0) != -1) + abort (); } void diff --git a/gcc/testsuite/gcc.dg/builtin-object-size-2.c b/gcc/testsuite/gcc.dg/builtin-object-size-2.c index ad2dd296a9a..ea11a17b6d8 100644 --- a/gcc/testsuite/gcc.dg/builtin-object-size-2.c +++ b/gcc/testsuite/gcc.dg/builtin-object-size-2.c @@ -335,6 +335,7 @@ test5 (size_t x) { struct T { char buf[64]; char buf2[64]; } t; char *p = &t.buf[8]; + char *r = t.buf2; size_t i; for (i = 0; i < x; ++i) @@ -342,6 +343,21 @@ test5 (size_t x) if (__builtin_object_size (p, 1) != sizeof (t.buf) - 8) abort (); memset (p, ' ', sizeof (t.buf) - 8 - 4 * 4); + p = &t.buf[8]; + for (i = 0; i < x; i++) + { + r = __builtin_memcpy (r, t.buf, i); + p = r + 1; + } + if (__builtin_object_size (p, 1) != sizeof (t.buf2) - 1) + abort (); + for (i = 0; i < x; i++) + { + r = __builtin_mempcpy (r, t.buf, i); + p = r + 1; + } + if (__builtin_object_size (p, 1) != -1) + abort (); } void diff --git a/gcc/testsuite/gcc.dg/builtin-object-size-3.c b/gcc/testsuite/gcc.dg/builtin-object-size-3.c index d5ca5047ee9..2d68925077e 100644 --- a/gcc/testsuite/gcc.dg/builtin-object-size-3.c +++ b/gcc/testsuite/gcc.dg/builtin-object-size-3.c @@ -382,6 +382,7 @@ test6 (size_t x) { struct T { char buf[64]; char buf2[64]; } t; char *p = &t.buf[8]; + char *r = t.buf2; size_t i; for (i = 0; i < x; ++i) @@ -389,6 +390,21 @@ test6 (size_t x) if (__builtin_object_size (p, 2) != 0) abort (); memset (p, ' ', sizeof (t) - 8 - 4 * 4); + p = &t.buf[8]; + for (i = 0; i < x; i++) + { + r = __builtin_memcpy (r, t.buf, i); + p = r + 1; + } + if (__builtin_object_size (p, 2) != sizeof (t.buf2) - 1) + abort (); + for (i = 0; i < x; i++) + { + r = __builtin_mempcpy (r, t.buf, i); + p = r + 1; + } + if (__builtin_object_size (p, 2) != 0) + abort (); } void diff --git a/gcc/testsuite/gcc.dg/builtin-object-size-4.c b/gcc/testsuite/gcc.dg/builtin-object-size-4.c index 9f159e36a0f..dd7f6d7336d 100644 --- a/gcc/testsuite/gcc.dg/builtin-object-size-4.c +++ b/gcc/testsuite/gcc.dg/builtin-object-size-4.c @@ -348,6 +348,7 @@ test5 (size_t x) { struct T { char buf[64]; char buf2[64]; } t; char *p = &t.buf[8]; + char *r = t.buf2; size_t i; for (i = 0; i < x; ++i) @@ -355,6 +356,21 @@ test5 (size_t x) if (__builtin_object_size (p, 3) != 0) abort (); memset (p, ' ', sizeof (t.buf) - 8 - 4 * 4); + p = &t.buf[8]; + for (i = 0; i < x; i++) + { + r = __builtin_memcpy (r, t.buf, i); + p = r + 1; + } + if (__builtin_object_size (p, 3) != sizeof (t.buf) - 8) + abort (); + for (i = 0; i < x; i++) + { + r = __builtin_mempcpy (r, t.buf, i); + p = r + 1; + } + if (__builtin_object_size (p, 3) != 0) + abort (); } void diff --git a/gcc/tree-object-size.c b/gcc/tree-object-size.c index 4b9c45c6af2..e48120559d3 100644 --- a/gcc/tree-object-size.c +++ b/gcc/tree-object-size.c @@ -38,11 +38,8 @@ along with GCC; see the file COPYING3. If not see struct object_size_info { int object_size_type; - unsigned char pass; - bool changed; bitmap visited, reexamine; - unsigned int *depths; - unsigned int *stack, *tos; + vec tempsize_objs; }; enum @@ -52,27 +49,41 @@ enum OST_END = 4, }; +#define OST_TREE_CODE(_ost) ((_ost) & OST_MINIMUM ? MIN_EXPR : MAX_EXPR) + static tree compute_object_offset (const_tree, const_tree); static bool addr_object_size (struct object_size_info *, const_tree, int, tree *); static tree alloc_object_size (const gcall *, int); static tree pass_through_call (const gcall *); static void collect_object_sizes_for (struct object_size_info *, tree); -static void expr_object_size (struct object_size_info *, tree, tree); -static bool merge_object_sizes (struct object_size_info *, tree, tree, tree); -static bool plus_stmt_object_size (struct object_size_info *, tree, gimple *); -static bool cond_expr_object_size (struct object_size_info *, tree, gimple *); +static tree expr_object_size (struct object_size_info *, tree); +static tree ssa_object_size (struct object_size_info *, tree, tree); +static tree plus_stmt_object_size (struct object_size_info *, gimple *); +static tree cond_expr_object_size (struct object_size_info *, gimple *); static void init_offset_limit (void); -static void check_for_plus_in_loops (struct object_size_info *, tree); -static void check_for_plus_in_loops_1 (struct object_size_info *, tree, - unsigned int); /* object_sizes[0] is upper bound for number of bytes till the end of the object. 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. + + Each array contains sizes subscripted by an SSA name version, which could be + of two types and correspondingly, their values have special properties: + + When the SSA name is an object: + - The value is either a constant or a gimple variable that is the size of + the object. + - If the value is an SSA variable, it could be a placeholder SSA name, which + again is a subscript in object_sizes. + + When the SSA name is a placeholder: + - The name version is also set in the osi.reexamine bitmap + - The value at its index in osi.tempsize_objs is the SSA name version of the + object whose size it is. + - Its value in object_sizes is an expression that evaluates to the size. */ static vec object_sizes[OST_END]; /* Bitmaps what object sizes have been computed already. */ @@ -174,18 +185,33 @@ object_sizes_initialize (struct object_size_info *osi, unsigned varno, /* Set size for VARNO corresponding to OSI to VAL if it is the new minimum or maximum. */ -static inline bool +static inline void object_sizes_set (struct object_size_info *osi, unsigned varno, tree val) { int object_size_type = osi->object_size_type; - tree oldval = object_sizes[object_size_type][varno]; - - enum tree_code code = object_size_type & OST_MINIMUM ? MIN_EXPR : MAX_EXPR; - - if (compare_tree_int (oldval, initval (object_size_type)) != 0) - val = size_binop (code, val, oldval); - object_sizes[object_size_type][varno] = val; - return tree_int_cst_compare (val, oldval) != 0; + tree curval = object_sizes[object_size_type][varno]; + + /* Object size is set at most twice, once to put in an SSA name to resolve + dependency loops and the second time to set the final size. */ + gcc_checking_assert (TREE_CODE (curval) == SSA_NAME + || (tree_fits_uhwi_p (curval) + && !compare_tree_int (curval, + initval (object_size_type)))); + + /* For self-referencing objects, update the element that the size SSA name + refers to, not the object SSA name, except if the size is unknown, in + which case we update both. */ + if (TREE_CODE (curval) == SSA_NAME + && bitmap_bit_p (osi->reexamine, SSA_NAME_VERSION (curval)) + && (TREE_CODE (val) != SSA_NAME + || SSA_NAME_VERSION (curval) != SSA_NAME_VERSION (val))) + { + object_sizes[object_size_type][SSA_NAME_VERSION (curval)] = val; + if (size_unknown_p (val, object_size_type)) + object_sizes[object_size_type][varno] = val; + } + else + object_sizes[object_size_type][varno] = val; } /* Initialize OFFSET_LIMIT variable. */ @@ -350,8 +376,7 @@ addr_object_size (struct object_size_info *osi, const_tree ptr, else { tree var = TREE_OPERAND (pt_var, 0); - if (osi->pass == 0) - collect_object_sizes_for (osi, var); + collect_object_sizes_for (osi, var); if (bitmap_bit_p (computed[object_size_type], SSA_NAME_VERSION (var))) sz = object_sizes_get (osi, SSA_NAME_VERSION (var)); @@ -616,6 +641,190 @@ pass_through_call (const gcall *call) return NULL_TREE; } +/* Recursively look for presence of ORIG in EXPR. Return true if it was found + and there was a MINUS_EXPR in the pathway. */ + +static bool +reducing_size (tree orig, tree expr, bool found_minus) +{ + switch (TREE_CODE (expr)) + { + case SSA_NAME: + if (SSA_NAME_VERSION (orig) == SSA_NAME_VERSION (expr)) + return found_minus; + return false; + case MIN_EXPR: + case MAX_EXPR: + return (reducing_size (orig, TREE_OPERAND (expr, 0), found_minus) + || reducing_size (orig, TREE_OPERAND (expr, 1), found_minus)); + case PLUS_EXPR: + /* Negative object offsets are not supported. */ + gcc_checking_assert (TREE_CODE (TREE_OPERAND (expr, 1)) == INTEGER_CST); + gcc_checking_assert (compare_tree_int (TREE_OPERAND (expr, 1), + offset_limit) > 0); + /* Fall through. */ + case MINUS_EXPR: + gcc_checking_assert (TREE_CODE (TREE_OPERAND (expr, 1)) == INTEGER_CST); + if (reducing_size (orig, TREE_OPERAND (expr, 0), true)) + return true; + /* Fall through. */ + case INTEGER_CST: + default: + return false; + } +} + +/* Return a constant size estimate for the input SZEXPR and update it with a + simplified expression. */ + +static tree +estimate_size (object_size_info *osi, tree size) +{ + enum tree_code code = TREE_CODE (size); + int object_size_type = osi->object_size_type; + + switch (code) + { + case SSA_NAME: + { + unsigned num = SSA_NAME_VERSION (size); + if (!bitmap_bit_p (osi->reexamine, num)) + return size; + return object_sizes_get (osi, osi->tempsize_objs[num]); + } + case MIN_EXPR: + case MAX_EXPR: + { + tree op0 = estimate_size (osi, TREE_OPERAND (size, 0)); + tree op1 = estimate_size (osi, TREE_OPERAND (size, 1)); + if (size_unknown_p (op0, object_size_type) + || size_unknown_p (op1, object_size_type)) + return size_unknown (object_size_type); + return size_binop (code, op0, op1); + } + case MINUS_EXPR: + case PLUS_EXPR: + { + tree ret = estimate_size (osi, TREE_OPERAND (size, 0)); + + if (size_unknown_p (ret, object_size_type)) + return size_unknown (object_size_type); + + tree off = TREE_OPERAND (size, 1); + gcc_checking_assert (TREE_CODE (off) == INTEGER_CST); + + if (code == PLUS_EXPR) + off = fold_build1 (NEGATE_EXPR, sizetype, off); + + if (tree_fits_uhwi_p (ret) && tree_int_cst_le (ret, off)) + return size_int (0); + return size_binop (MINUS_EXPR, ret, off); + } + case INTEGER_CST: + default: + return size; + } +} + +/* Replace dependency loop SSA names with their actual values. */ + +static void +resolve_dependency_loops (struct object_size_info *osi) +{ + bitmap_iterator bi; + unsigned int i; + int object_size_type = osi->object_size_type; + + /* Step 1: Update the self-referencing sizes until they don't + change anymore. */ + bool changed; + bitmap tempsize_free = BITMAP_ALLOC (NULL); + do + { + changed = false; + bitmap_and_compl_into (osi->reexamine, tempsize_free); + EXECUTE_IF_SET_IN_BITMAP (osi->reexamine, 0, i, bi) + { + unsigned varno = osi->tempsize_objs[i]; + + tree cur = object_sizes_get (osi, varno); + + if (size_unknown_p (cur, object_size_type)) + { + bitmap_set_bit (tempsize_free, i); + continue; + } + + tree szexpr = object_sizes_get (osi, i); + + /* First run, initialize. */ + if (TREE_CODE (cur) == SSA_NAME) + { + if (reducing_size (cur, szexpr, false)) + { + cur = size_int (0); + object_sizes_initialize (osi, varno, cur); + if (object_size_type & OST_MINIMUM) + bitmap_set_bit (tempsize_free, i); + } + else + { + cur = size_initval (object_size_type); + object_sizes_initialize (osi, varno, cur); + } + changed = true; + } + + tree sz = estimate_size (osi, szexpr); + + /* It depends on some self-referencing size that has not been + initialized yet. */ + if (TREE_CODE (sz) != INTEGER_CST) + continue; + + if (size_unknown_p (sz, object_size_type)) + bitmap_set_bit (tempsize_free, i); + /* If we have a new estimate, then update it. */ + if (tree_int_cst_compare (cur, sz) != 0) + { + object_sizes_initialize (osi, varno, sz); + changed = true; + } + } + } + while (changed); + + /* Now we only need to dump and free all SSAs. */ + bitmap_ior_into_and_free (osi->reexamine, &tempsize_free); + if (dump_file && (dump_flags & TDF_DETAILS)) + { + fprintf (dump_file, "After dependency resolution:\n"); + EXECUTE_IF_SET_IN_BITMAP (osi->reexamine, 0, i, bi) + { + fprintf (dump_file, " "); + print_generic_expr (dump_file, ssa_name (i), dump_flags); + fprintf (dump_file, ": "); + print_generic_expr (dump_file, + object_sizes_get (osi, osi->tempsize_objs[i]), + dump_flags); + fprintf (dump_file, "\n"); + } + } + + /* Step 2: Update all remaining non-constant sizes. */ + EXECUTE_IF_SET_IN_BITMAP (computed[object_size_type], 0, i, bi) + { + tree szexpr = object_sizes_get (osi, i); + if (TREE_CODE (szexpr) == INTEGER_CST) + continue; + tree sz = estimate_size (osi, szexpr); + object_sizes_initialize (osi, i, sz); + } + + /* Release all the SSA names we created. */ + EXECUTE_IF_SET_IN_BITMAP (osi->reexamine, 0, i, bi) + release_ssa_name (ssa_name (i)); +} /* Compute __builtin_object_size value for PTR and set *PSIZE to the resulting value. If the declared object is known and PDECL @@ -693,77 +902,11 @@ compute_builtin_object_size (tree ptr, int object_size_type, osi.visited = BITMAP_ALLOC (NULL); osi.reexamine = BITMAP_ALLOC (NULL); - osi.depths = NULL; - osi.stack = NULL; - osi.tos = NULL; - - /* First pass: walk UD chains, compute object sizes that - can be computed. osi.reexamine bitmap at the end will - contain what variables were found in dependency cycles - and therefore need to be reexamined. */ - osi.pass = 0; - osi.changed = false; + osi.tempsize_objs.create (0); collect_object_sizes_for (&osi, ptr); - /* Second pass: keep recomputing object sizes of variables - that need reexamination, until no object sizes are - increased or all object sizes are computed. */ - if (! bitmap_empty_p (osi.reexamine)) - { - bitmap reexamine = BITMAP_ALLOC (NULL); - - /* If looking for minimum instead of maximum object size, - detect cases where a pointer is increased in a loop. - Although even without this detection pass 2 would eventually - terminate, it could take a long time. If a pointer is - increasing this way, we need to assume 0 object size. - E.g. p = &buf[0]; while (cond) p = p + 4; */ - if (object_size_type & 2) - { - osi.depths = XCNEWVEC (unsigned int, num_ssa_names); - osi.stack = XNEWVEC (unsigned int, num_ssa_names); - osi.tos = osi.stack; - osi.pass = 1; - /* collect_object_sizes_for is changing - osi.reexamine bitmap, so iterate over a copy. */ - bitmap_copy (reexamine, osi.reexamine); - EXECUTE_IF_SET_IN_BITMAP (reexamine, 0, i, bi) - if (bitmap_bit_p (osi.reexamine, i)) - check_for_plus_in_loops (&osi, ssa_name (i)); - - free (osi.depths); - osi.depths = NULL; - free (osi.stack); - osi.stack = NULL; - osi.tos = NULL; - } - - do - { - osi.pass = 2; - osi.changed = false; - /* collect_object_sizes_for is changing - osi.reexamine bitmap, so iterate over a copy. */ - bitmap_copy (reexamine, osi.reexamine); - EXECUTE_IF_SET_IN_BITMAP (reexamine, 0, i, bi) - if (bitmap_bit_p (osi.reexamine, i)) - { - collect_object_sizes_for (&osi, ssa_name (i)); - if (dump_file && (dump_flags & TDF_DETAILS)) - { - fprintf (dump_file, "Reexamining "); - print_generic_expr (dump_file, ssa_name (i), - dump_flags); - fprintf (dump_file, "\n"); - } - } - } - while (osi.changed); - - BITMAP_FREE (reexamine); - } - EXECUTE_IF_SET_IN_BITMAP (osi.reexamine, 0, i, bi) - bitmap_set_bit (computed[object_size_type], i); + if (!bitmap_empty_p (osi.reexamine)) + resolve_dependency_loops (&osi); /* Debugging dumps. */ if (dump_file) @@ -784,6 +927,7 @@ compute_builtin_object_size (tree ptr, int object_size_type, } } + osi.tempsize_objs.release (); BITMAP_FREE (osi.reexamine); BITMAP_FREE (osi.visited); } @@ -792,107 +936,107 @@ compute_builtin_object_size (tree ptr, int object_size_type, return !size_unknown_p (*psize, object_size_type); } +/* Make a temporary placeholder variable for size. */ + +static tree +make_tempsize (struct object_size_info *osi, unsigned varno) +{ + tree ssa = make_ssa_name (sizetype); + unsigned ssano = SSA_NAME_VERSION (ssa); + + if (dump_file) + { + print_generic_expr (dump_file, ssa_name (varno), dump_flags); + fprintf (dump_file, ": Making temp SSA name: "); + print_generic_expr (dump_file, ssa, dump_flags); + fprintf (dump_file, "\n"); + } + + object_sizes_grow (osi->object_size_type); + if (osi->tempsize_objs.length () < num_ssa_names) + osi->tempsize_objs.safe_grow (num_ssa_names); + + bitmap_set_bit (osi->reexamine, ssano); + osi->tempsize_objs[ssano] = varno; + + return ssa; +} + /* Compute object_sizes for PTR, defined to VALUE, which is not an SSA_NAME. */ -static void -expr_object_size (struct object_size_info *osi, tree ptr, tree value) +static tree +expr_object_size (struct object_size_info *osi, tree value) { int object_size_type = osi->object_size_type; - unsigned int varno = SSA_NAME_VERSION (ptr); tree bytes; - gcc_assert (!object_sizes_unknown_p (object_size_type, varno)); - gcc_assert (osi->pass == 0); - if (TREE_CODE (value) == WITH_SIZE_EXPR) value = TREE_OPERAND (value, 0); - /* Pointer variables should have been handled by merge_object_sizes. */ + /* Pointer variables should have been handled by ssa_object_size. */ gcc_assert (TREE_CODE (value) != SSA_NAME || !POINTER_TYPE_P (TREE_TYPE (value))); - if (TREE_CODE (value) == ADDR_EXPR) - addr_object_size (osi, value, object_size_type, &bytes); - else - bytes = size_unknown (object_size_type); + if (TREE_CODE (value) == ADDR_EXPR + && addr_object_size (osi, value, object_size_type, &bytes)) + return bytes; - object_sizes_set (osi, varno, bytes); + return size_unknown (object_size_type); } /* Compute object_sizes for PTR, defined to the result of a call. */ -static void -call_object_size (struct object_size_info *osi, tree ptr, gcall *call) +static tree +call_object_size (struct object_size_info *osi, gcall *call) { int object_size_type = osi->object_size_type; - unsigned int varno = SSA_NAME_VERSION (ptr); gcc_assert (is_gimple_call (call)); - gcc_assert (!object_sizes_unknown_p (object_size_type, varno)); - gcc_assert (osi->pass == 0); - - object_sizes_set (osi, varno, alloc_object_size (call, object_size_type)); + return alloc_object_size (call, object_size_type); } /* Compute object_sizes for PTR, defined to an unknown value. */ -static void -unknown_object_size (struct object_size_info *osi, tree ptr) +static tree +unknown_object_size (struct object_size_info *osi) { int object_size_type = osi->object_size_type; - unsigned int varno = SSA_NAME_VERSION (ptr); - - gcc_checking_assert (!object_sizes_unknown_p (object_size_type, varno)); - gcc_checking_assert (osi->pass == 0); - - object_sizes_set (osi, varno, size_unknown (object_size_type)); + return size_unknown (object_size_type); } -/* Merge object sizes of ORIG + OFFSET into DEST. Return true if - the object size might need reexamination later. */ +/* Return object size of ORIG + OFFSET. */ -static bool -merge_object_sizes (struct object_size_info *osi, tree dest, tree orig, - tree offset) +static tree +ssa_object_size (struct object_size_info *osi, tree orig, tree offset) { int object_size_type = osi->object_size_type; - unsigned int varno = SSA_NAME_VERSION (dest); tree orig_bytes; - if (object_sizes_unknown_p (object_size_type, varno)) - return false; if (compare_tree_int (offset, offset_limit) >= 0) - { - object_sizes_set (osi, varno, size_unknown (object_size_type)); - return false; - } + return size_unknown (object_size_type); - if (osi->pass == 0) - collect_object_sizes_for (osi, orig); + collect_object_sizes_for (osi, orig); orig_bytes = object_sizes_get (osi, SSA_NAME_VERSION (orig)); - if (!size_unknown_p (orig_bytes, object_size_type)) + if (!size_unknown_p (orig_bytes, object_size_type) + && !integer_zerop (offset)) orig_bytes = size_for_offset (orig_bytes, offset); - osi->changed = object_sizes_set (osi, varno, orig_bytes); - - return bitmap_bit_p (osi->reexamine, SSA_NAME_VERSION (orig)); + return orig_bytes; } /* Compute object_sizes for VAR, defined to the result of an assignment - with operator POINTER_PLUS_EXPR. Return true if the object size might - need reexamination later. */ + with operator POINTER_PLUS_EXPR. */ -static bool -plus_stmt_object_size (struct object_size_info *osi, tree var, gimple *stmt) +static tree +plus_stmt_object_size (struct object_size_info *osi, gimple *stmt) { int object_size_type = osi->object_size_type; - unsigned int varno = SSA_NAME_VERSION (var); tree bytes; tree op0, op1; @@ -911,16 +1055,13 @@ plus_stmt_object_size (struct object_size_info *osi, tree var, gimple *stmt) else gcc_unreachable (); - if (object_sizes_unknown_p (object_size_type, varno)) - return false; - /* Handle PTR + OFFSET here. */ if (TREE_CODE (op1) == INTEGER_CST && (TREE_CODE (op0) == SSA_NAME || TREE_CODE (op0) == ADDR_EXPR)) { if (TREE_CODE (op0) == SSA_NAME) - return merge_object_sizes (osi, var, op0, op1); + bytes = ssa_object_size (osi, op0, op1); else { /* op0 will be ADDR_EXPR here. */ @@ -929,52 +1070,43 @@ plus_stmt_object_size (struct object_size_info *osi, tree var, gimple *stmt) ; else if (compare_tree_int (op1, offset_limit) > 0) bytes = size_unknown (object_size_type); - else + else if (!integer_zerop (op1)) bytes = size_for_offset (bytes, op1); } } else bytes = size_unknown (object_size_type); - object_sizes_set (osi, varno, bytes); - return false; + return bytes; } /* Compute object_sizes for VAR, defined at STMT, which is - a COND_EXPR. Return true if the object size might need reexamination - later. */ + a COND_EXPR. */ -static bool -cond_expr_object_size (struct object_size_info *osi, tree var, gimple *stmt) +static tree +cond_expr_object_size (struct object_size_info *osi, gimple *stmt) { tree then_, else_; int object_size_type = osi->object_size_type; - unsigned int varno = SSA_NAME_VERSION (var); - bool reexamine = false; + tree thenbytes, elsebytes; gcc_assert (gimple_assign_rhs_code (stmt) == COND_EXPR); - if (object_sizes_unknown_p (object_size_type, varno)) - return false; - then_ = gimple_assign_rhs2 (stmt); else_ = gimple_assign_rhs3 (stmt); if (TREE_CODE (then_) == SSA_NAME) - reexamine |= merge_object_sizes (osi, var, then_, size_int (0)); + thenbytes = ssa_object_size (osi, then_, size_int (0)); else - expr_object_size (osi, var, then_); - - if (object_sizes_unknown_p (object_size_type, varno)) - return reexamine; + thenbytes = expr_object_size (osi, then_); if (TREE_CODE (else_) == SSA_NAME) - reexamine |= merge_object_sizes (osi, var, else_, size_int (0)); + elsebytes = ssa_object_size (osi, else_, size_int (0)); else - expr_object_size (osi, var, else_); + elsebytes = expr_object_size (osi, else_); - return reexamine; + return size_binop (OST_TREE_CODE (object_size_type), thenbytes, elsebytes); } /* Compute object sizes for VAR. @@ -1003,32 +1135,36 @@ collect_object_sizes_for (struct object_size_info *osi, tree var) int object_size_type = osi->object_size_type; unsigned int varno = SSA_NAME_VERSION (var); gimple *stmt; - bool reexamine; + tree res; if (bitmap_bit_p (computed[object_size_type], varno)) return; - if (osi->pass == 0) + /* We want to evaluate the self-referencing object only once. */ + if (bitmap_set_bit (osi->visited, varno)) { - if (bitmap_set_bit (osi->visited, varno)) + /* Initialize to 0 for maximum size and M1U for minimum size so that + it gets immediately overridden. */ + object_sizes_initialize (osi, varno); + } + else + { + /* Found a dependency loop. Mark it for later resolution. */ + if (dump_file && (dump_flags & TDF_DETAILS)) { - /* Initialize to 0 for maximum size and M1U for minimum size so that - it gets immediately overridden. */ - object_sizes_initialize (osi, varno); + fprintf (dump_file, "Found a dependency loop at "); + print_generic_expr (dump_file, var, dump_flags); + fprintf (dump_file, "\n"); } - else + res = object_sizes_get (osi, varno); + if (TREE_CODE (res) != SSA_NAME) + res = make_tempsize (osi, varno); + else if (dump_file) { - /* Found a dependency loop. Mark the variable for later - re-examination. */ - bitmap_set_bit (osi->reexamine, varno); - if (dump_file && (dump_flags & TDF_DETAILS)) - { - fprintf (dump_file, "Found a dependency loop at "); - print_generic_expr (dump_file, var, dump_flags); - fprintf (dump_file, "\n"); - } - return; + fprintf (dump_file, " temp name already assigned: "); + print_generic_expr (dump_file, res, dump_flags); } + goto out; } if (dump_file && (dump_flags & TDF_DETAILS)) @@ -1039,192 +1175,86 @@ collect_object_sizes_for (struct object_size_info *osi, tree var) } stmt = SSA_NAME_DEF_STMT (var); - reexamine = false; switch (gimple_code (stmt)) { case GIMPLE_ASSIGN: { tree rhs = gimple_assign_rhs1 (stmt); - if (gimple_assign_rhs_code (stmt) == POINTER_PLUS_EXPR + if (gimple_assign_rhs_code (stmt) == POINTER_PLUS_EXPR || (gimple_assign_rhs_code (stmt) == ADDR_EXPR && TREE_CODE (TREE_OPERAND (rhs, 0)) == MEM_REF)) - reexamine = plus_stmt_object_size (osi, var, stmt); + res = plus_stmt_object_size (osi, stmt); else if (gimple_assign_rhs_code (stmt) == COND_EXPR) - reexamine = cond_expr_object_size (osi, var, stmt); - else if (gimple_assign_single_p (stmt) - || gimple_assign_unary_nop_p (stmt)) - { - if (TREE_CODE (rhs) == SSA_NAME - && POINTER_TYPE_P (TREE_TYPE (rhs))) - reexamine = merge_object_sizes (osi, var, rhs, size_int (0)); - else - expr_object_size (osi, var, rhs); - } - else - unknown_object_size (osi, var); - break; + res = cond_expr_object_size (osi, stmt); + else if (gimple_assign_single_p (stmt) + || gimple_assign_unary_nop_p (stmt)) + { + if (TREE_CODE (rhs) == SSA_NAME + && POINTER_TYPE_P (TREE_TYPE (rhs))) + res = ssa_object_size (osi, rhs, size_int (0)); + else + res = expr_object_size (osi, rhs); + } + else + res = unknown_object_size (osi); + break; } case GIMPLE_CALL: { gcall *call_stmt = as_a (stmt); - tree arg = pass_through_call (call_stmt); - if (arg) - { - if (TREE_CODE (arg) == SSA_NAME - && POINTER_TYPE_P (TREE_TYPE (arg))) - reexamine = merge_object_sizes (osi, var, arg, size_int (0)); - else - expr_object_size (osi, var, arg); - } - else - call_object_size (osi, var, call_stmt); + tree arg = pass_through_call (call_stmt); + if (arg) + { + if (TREE_CODE (arg) == SSA_NAME + && POINTER_TYPE_P (TREE_TYPE (arg))) + res = ssa_object_size (osi, arg, size_int (0)); + else + res = expr_object_size (osi, arg); + } + else + res = call_object_size (osi, call_stmt); break; } case GIMPLE_ASM: /* Pointers defined by __asm__ statements can point anywhere. */ - object_sizes_set (osi, varno, size_unknown (object_size_type)); + res = size_unknown (object_size_type); break; case GIMPLE_NOP: if (SSA_NAME_VAR (var) && TREE_CODE (SSA_NAME_VAR (var)) == PARM_DECL) - expr_object_size (osi, var, SSA_NAME_VAR (var)); + res = expr_object_size (osi, SSA_NAME_VAR (var)); else /* Uninitialized SSA names point nowhere. */ - object_sizes_set (osi, varno, size_unknown (object_size_type)); + res = size_unknown (object_size_type); break; case GIMPLE_PHI: { unsigned i; + res = size_initval (object_size_type); + for (i = 0; i < gimple_phi_num_args (stmt); i++) { tree rhs = gimple_phi_arg (stmt, i)->def; + tree phires; if (object_sizes_unknown_p (object_size_type, varno)) break; if (TREE_CODE (rhs) == SSA_NAME) - reexamine |= merge_object_sizes (osi, var, rhs, size_int (0)); - else if (osi->pass == 0) - expr_object_size (osi, var, rhs); - } - break; - } - - default: - gcc_unreachable (); - } - - if (! reexamine || object_sizes_unknown_p (object_size_type, varno)) - { - bitmap_set_bit (computed[object_size_type], varno); - bitmap_clear_bit (osi->reexamine, varno); - } - else - { - bitmap_set_bit (osi->reexamine, varno); - if (dump_file && (dump_flags & TDF_DETAILS)) - { - fprintf (dump_file, "Need to reexamine "); - print_generic_expr (dump_file, var, dump_flags); - fprintf (dump_file, "\n"); - } - } -} + phires = ssa_object_size (osi, rhs, size_int (0)); + else + phires = expr_object_size (osi, rhs); + res = size_binop (OST_TREE_CODE (object_size_type), res, phires); -/* Helper function for check_for_plus_in_loops. Called recursively - to detect loops. */ - -static void -check_for_plus_in_loops_1 (struct object_size_info *osi, tree var, - unsigned int depth) -{ - gimple *stmt = SSA_NAME_DEF_STMT (var); - unsigned int varno = SSA_NAME_VERSION (var); - - if (osi->depths[varno]) - { - if (osi->depths[varno] != depth) - { - unsigned int *sp; - - /* Found a loop involving pointer addition. */ - for (sp = osi->tos; sp > osi->stack; ) - { - --sp; - bitmap_clear_bit (osi->reexamine, *sp); - bitmap_set_bit (computed[osi->object_size_type], *sp); - object_sizes_set (osi, *sp, size_int (0)); - if (*sp == varno) - break; - } - } - return; - } - else if (! bitmap_bit_p (osi->reexamine, varno)) - return; - - osi->depths[varno] = depth; - *osi->tos++ = varno; - - switch (gimple_code (stmt)) - { - - case GIMPLE_ASSIGN: - { - if ((gimple_assign_single_p (stmt) - || gimple_assign_unary_nop_p (stmt)) - && TREE_CODE (gimple_assign_rhs1 (stmt)) == SSA_NAME) - { - tree rhs = gimple_assign_rhs1 (stmt); - - check_for_plus_in_loops_1 (osi, rhs, depth); - } - else if (gimple_assign_rhs_code (stmt) == POINTER_PLUS_EXPR) - { - tree basevar = gimple_assign_rhs1 (stmt); - tree cst = gimple_assign_rhs2 (stmt); - - gcc_assert (TREE_CODE (cst) == INTEGER_CST); - - check_for_plus_in_loops_1 (osi, basevar, - depth + !integer_zerop (cst)); - } - else - gcc_unreachable (); - break; - } - - case GIMPLE_CALL: - { - gcall *call_stmt = as_a (stmt); - tree arg = pass_through_call (call_stmt); - if (arg) - { - if (TREE_CODE (arg) == SSA_NAME) - check_for_plus_in_loops_1 (osi, arg, depth); - else - gcc_unreachable (); - } - break; - } - - case GIMPLE_PHI: - { - unsigned i; - - for (i = 0; i < gimple_phi_num_args (stmt); i++) - { - tree rhs = gimple_phi_arg (stmt, i)->def; - - if (TREE_CODE (rhs) == SSA_NAME) - check_for_plus_in_loops_1 (osi, rhs, depth); + if (size_unknown_p (phires, object_size_type)) + break; } break; } @@ -1232,43 +1262,9 @@ check_for_plus_in_loops_1 (struct object_size_info *osi, tree var, default: gcc_unreachable (); } - - osi->depths[varno] = 0; - osi->tos--; -} - - -/* Check if some pointer we are computing object size of is being increased - within a loop. If yes, assume all the SSA variables participating in - that loop have minimum object sizes 0. */ - -static void -check_for_plus_in_loops (struct object_size_info *osi, tree var) -{ - gimple *stmt = SSA_NAME_DEF_STMT (var); - - /* NOTE: In the pre-tuples code, we handled a CALL_EXPR here, - and looked for a POINTER_PLUS_EXPR in the pass-through - argument, if any. In GIMPLE, however, such an expression - is not a valid call operand. */ - - if (is_gimple_assign (stmt) - && gimple_assign_rhs_code (stmt) == POINTER_PLUS_EXPR) - { - tree basevar = gimple_assign_rhs1 (stmt); - tree cst = gimple_assign_rhs2 (stmt); - - gcc_assert (TREE_CODE (cst) == INTEGER_CST); - - if (integer_zerop (cst)) - return; - - osi->depths[SSA_NAME_VERSION (basevar)] = 1; - *osi->tos++ = SSA_NAME_VERSION (basevar); - check_for_plus_in_loops_1 (osi, var, 2); - osi->depths[SSA_NAME_VERSION (basevar)] = 0; - osi->tos--; - } + bitmap_set_bit (computed[object_size_type], varno); +out: + object_sizes_set (osi, varno, res); } From patchwork Tue Nov 9 19:01:31 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Siddhesh Poyarekar X-Patchwork-Id: 47327 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 8E6A3385B83B for ; Tue, 9 Nov 2021 19:05:30 +0000 (GMT) X-Original-To: gcc-patches@gcc.gnu.org Delivered-To: gcc-patches@gcc.gnu.org Received: from fossa.birch.relay.mailchannels.net (fossa.birch.relay.mailchannels.net [23.83.209.62]) by sourceware.org (Postfix) with ESMTPS id D41FA3857813 for ; Tue, 9 Nov 2021 19:02:10 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.1 sourceware.org D41FA3857813 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 78FD0121B3E; Tue, 9 Nov 2021 19:02:02 +0000 (UTC) Received: from pdx1-sub0-mail-a306.dreamhost.com (100-96-11-8.trex.outbound.svc.cluster.local [100.96.11.8]) (Authenticated sender: dreamhost) by relay.mailchannels.net (Postfix) with ESMTPA id 94259121901; Tue, 9 Nov 2021 19:02:01 +0000 (UTC) X-Sender-Id: dreamhost|x-authsender|siddhesh@gotplt.org Received: from pdx1-sub0-mail-a306.dreamhost.com (pop.dreamhost.com [64.90.62.162]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384) by 100.96.11.8 (trex/6.4.3); Tue, 09 Nov 2021 19:02:02 +0000 X-MC-Relay: Neutral X-MailChannels-SenderId: dreamhost|x-authsender|siddhesh@gotplt.org X-MailChannels-Auth-Id: dreamhost X-Bitter-Turn: 5110562e5225e78b_1636484521926_2449727254 X-MC-Loop-Signature: 1636484521925:1612969436 X-MC-Ingress-Time: 1636484521925 Received: from rhbox.redhat.com (unknown [1.186.121.127]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256) (No client certificate requested) (Authenticated sender: siddhesh@gotplt.org) by pdx1-sub0-mail-a306.dreamhost.com (Postfix) with ESMTPSA id 4Hpcm75nQ9z2n; Tue, 9 Nov 2021 11:01:59 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha1; c=relaxed/relaxed; d=gotplt.org; s=gotplt.org; t=1636484521; bh=6Nb+gAENYJkCKdOe+JMKZTC/X8k=; h=From:To:Cc:Subject:Date:Content-Transfer-Encoding; b=odWW+y1AvW8kXxgBGGCNjdDJVDZOX2xanCY3YpZV/yhzhRkg9m20rvanOCUqAQq7v CJpdbjpFFb+JJIiskh3aB86wA5frcqaiUzKTZ6dBCeR62hu+QhT8gh22UxkiRT8Oaw kiXK8zwxtzEcRhDios3rFWiygCHQoBrSiJxusefU= From: Siddhesh Poyarekar To: gcc-patches@gcc.gnu.org Subject: [PATCH 05/10] __builtin_dynamic_object_size: Recognize builtin Date: Wed, 10 Nov 2021 00:31:31 +0530 Message-Id: <20211109190137.1107736-6-siddhesh@gotplt.org> X-Mailer: git-send-email 2.31.1 In-Reply-To: <20211109190137.1107736-1-siddhesh@gotplt.org> References: <20211109190137.1107736-1-siddhesh@gotplt.org> MIME-Version: 1.0 X-Spam-Status: No, score=-3028.0 required=5.0 tests=BAYES_00, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, GIT_PATCH_0, RCVD_IN_BARRACUDACENTRAL, RCVD_IN_DNSWL_NONE, RCVD_IN_MSPIKE_H2, RCVD_IN_SBL, SPF_HELO_NONE, SPF_PASS, TXREP, UNWANTED_LANGUAGE_BODY 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" Recognize the __builtin_dynamic_object_size builtin and add paths in the object size path to deal with it, but treat it like __builtin_object_size for now. Also add tests to provide the same testing coverage for the new builtin name. gcc/ChangeLog: * builtins.def (BUILT_IN_DYNAMIC_OBJECT_SIZE): New builtin. * tree-object-size.h (compute_builtin_object_size): Add new argument dynamic. * builtins.c (expand_builtin, fold_builtin_2): Handle it. (fold_builtin_object_size): Handle new builtin and adjust for change to compute_builtin_object_size. * tree-object-size.c: Include builtins.h. (OST_DYNAMIC): New enum value. (compute_builtin_object_size): Add new argument dynamic. (addr_object_size): Adjust. (early_object_sizes_execute_one, dynamic_object_sizes_execute_one): New functions. (object_sizes_execute): Rename insert_min_max_p argument to early. Handle BUILT_IN_DYNAMIC_OBJECT_SIZE and call the new functions. doc/extend.texi (__builtin_dynamic_object_size): Document new builtin. gcc/testsuite/ChangeLog: * g++.dg/ext/builtin-dynamic-object-size1.C: New test. * g++.dg/ext/builtin-dynamic-object-size2.C: Likewise. * gcc.dg/builtin-dynamic-alloc-size.c: Likewise. * gcc.dg/builtin-dynamic-object-size-1.c: Likewise. * gcc.dg/builtin-dynamic-object-size-10.c: Likewise. * gcc.dg/builtin-dynamic-object-size-11.c: Likewise. * gcc.dg/builtin-dynamic-object-size-12.c: Likewise. * gcc.dg/builtin-dynamic-object-size-13.c: Likewise. * gcc.dg/builtin-dynamic-object-size-14.c: Likewise. * gcc.dg/builtin-dynamic-object-size-15.c: Likewise. * gcc.dg/builtin-dynamic-object-size-16.c: Likewise. * gcc.dg/builtin-dynamic-object-size-17.c: Likewise. * gcc.dg/builtin-dynamic-object-size-18.c: Likewise. * gcc.dg/builtin-dynamic-object-size-19.c: Likewise. * gcc.dg/builtin-dynamic-object-size-2.c: Likewise. * gcc.dg/builtin-dynamic-object-size-3.c: Likewise. * gcc.dg/builtin-dynamic-object-size-4.c: Likewise. * gcc.dg/builtin-dynamic-object-size-5.c: Likewise. * gcc.dg/builtin-dynamic-object-size-6.c: Likewise. * gcc.dg/builtin-dynamic-object-size-7.c: Likewise. * gcc.dg/builtin-dynamic-object-size-8.c: Likewise. * gcc.dg/builtin-dynamic-object-size-9.c: Likewise. * gcc.dg/builtin-object-size-16.c: Adjust to allow inclusion from builtin-dynamic-object-size-16.c. * gcc.dg/builtin-object-size-17.c: Likewise. Signed-off-by: Siddhesh Poyarekar --- gcc/builtins.c | 14 +- gcc/builtins.def | 1 + gcc/doc/extend.texi | 13 ++ .../g++.dg/ext/builtin-dynamic-object-size1.C | 5 + .../g++.dg/ext/builtin-dynamic-object-size2.C | 5 + .../gcc.dg/builtin-dynamic-alloc-size.c | 7 + .../gcc.dg/builtin-dynamic-object-size-1.c | 6 + .../gcc.dg/builtin-dynamic-object-size-10.c | 9 ++ .../gcc.dg/builtin-dynamic-object-size-11.c | 7 + .../gcc.dg/builtin-dynamic-object-size-12.c | 5 + .../gcc.dg/builtin-dynamic-object-size-13.c | 5 + .../gcc.dg/builtin-dynamic-object-size-14.c | 5 + .../gcc.dg/builtin-dynamic-object-size-15.c | 5 + .../gcc.dg/builtin-dynamic-object-size-16.c | 7 + .../gcc.dg/builtin-dynamic-object-size-17.c | 8 + .../gcc.dg/builtin-dynamic-object-size-18.c | 8 + .../gcc.dg/builtin-dynamic-object-size-19.c | 104 ++++++++++++ .../gcc.dg/builtin-dynamic-object-size-2.c | 6 + .../gcc.dg/builtin-dynamic-object-size-3.c | 6 + .../gcc.dg/builtin-dynamic-object-size-4.c | 6 + .../gcc.dg/builtin-dynamic-object-size-5.c | 7 + .../gcc.dg/builtin-dynamic-object-size-6.c | 5 + .../gcc.dg/builtin-dynamic-object-size-7.c | 5 + .../gcc.dg/builtin-dynamic-object-size-8.c | 5 + .../gcc.dg/builtin-dynamic-object-size-9.c | 5 + gcc/testsuite/gcc.dg/builtin-object-size-16.c | 2 + gcc/testsuite/gcc.dg/builtin-object-size-17.c | 2 + gcc/tree-object-size.c | 152 ++++++++++++++---- gcc/tree-object-size.h | 3 +- 29 files changed, 377 insertions(+), 41 deletions(-) create mode 100644 gcc/testsuite/g++.dg/ext/builtin-dynamic-object-size1.C create mode 100644 gcc/testsuite/g++.dg/ext/builtin-dynamic-object-size2.C create mode 100644 gcc/testsuite/gcc.dg/builtin-dynamic-alloc-size.c create mode 100644 gcc/testsuite/gcc.dg/builtin-dynamic-object-size-1.c create mode 100644 gcc/testsuite/gcc.dg/builtin-dynamic-object-size-10.c create mode 100644 gcc/testsuite/gcc.dg/builtin-dynamic-object-size-11.c create mode 100644 gcc/testsuite/gcc.dg/builtin-dynamic-object-size-12.c create mode 100644 gcc/testsuite/gcc.dg/builtin-dynamic-object-size-13.c create mode 100644 gcc/testsuite/gcc.dg/builtin-dynamic-object-size-14.c create mode 100644 gcc/testsuite/gcc.dg/builtin-dynamic-object-size-15.c create mode 100644 gcc/testsuite/gcc.dg/builtin-dynamic-object-size-16.c create mode 100644 gcc/testsuite/gcc.dg/builtin-dynamic-object-size-17.c create mode 100644 gcc/testsuite/gcc.dg/builtin-dynamic-object-size-18.c create mode 100644 gcc/testsuite/gcc.dg/builtin-dynamic-object-size-19.c create mode 100644 gcc/testsuite/gcc.dg/builtin-dynamic-object-size-2.c create mode 100644 gcc/testsuite/gcc.dg/builtin-dynamic-object-size-3.c create mode 100644 gcc/testsuite/gcc.dg/builtin-dynamic-object-size-4.c create mode 100644 gcc/testsuite/gcc.dg/builtin-dynamic-object-size-5.c create mode 100644 gcc/testsuite/gcc.dg/builtin-dynamic-object-size-6.c create mode 100644 gcc/testsuite/gcc.dg/builtin-dynamic-object-size-7.c create mode 100644 gcc/testsuite/gcc.dg/builtin-dynamic-object-size-8.c create mode 100644 gcc/testsuite/gcc.dg/builtin-dynamic-object-size-9.c diff --git a/gcc/builtins.c b/gcc/builtins.c index d2e6d95a175..9135d553c87 100644 --- a/gcc/builtins.c +++ b/gcc/builtins.c @@ -178,7 +178,7 @@ static rtx expand_builtin_memory_chk (tree, rtx, machine_mode, enum built_in_function); static void maybe_emit_chk_warning (tree, enum built_in_function); static void maybe_emit_sprintf_chk_warning (tree, enum built_in_function); -static tree fold_builtin_object_size (tree, tree); +static tree fold_builtin_object_size (tree, tree, enum built_in_function); unsigned HOST_WIDE_INT target_newline; unsigned HOST_WIDE_INT target_percent; @@ -7880,6 +7880,7 @@ expand_builtin (tree exp, rtx target, rtx subtarget, machine_mode mode, return const0_rtx; case BUILT_IN_OBJECT_SIZE: + case BUILT_IN_DYNAMIC_OBJECT_SIZE: return expand_builtin_object_size (exp); case BUILT_IN_MEMCPY_CHK: @@ -9286,7 +9287,8 @@ fold_builtin_2 (location_t loc, tree expr, tree fndecl, tree arg0, tree arg1) break; case BUILT_IN_OBJECT_SIZE: - return fold_builtin_object_size (arg0, arg1); + case BUILT_IN_DYNAMIC_OBJECT_SIZE: + return fold_builtin_object_size (arg0, arg1, fcode); case BUILT_IN_ATOMIC_ALWAYS_LOCK_FREE: return fold_builtin_atomic_always_lock_free (arg0, arg1); @@ -10224,7 +10226,7 @@ maybe_emit_sprintf_chk_warning (tree exp, enum built_in_function fcode) if possible. */ static tree -fold_builtin_object_size (tree ptr, tree ost) +fold_builtin_object_size (tree ptr, tree ost, enum built_in_function fcode) { tree bytes; int object_size_type; @@ -10250,7 +10252,8 @@ fold_builtin_object_size (tree ptr, tree ost) if (TREE_CODE (ptr) == ADDR_EXPR) { - compute_builtin_object_size (ptr, object_size_type, &bytes); + compute_builtin_object_size (ptr, object_size_type, &bytes, + fcode == BUILT_IN_DYNAMIC_OBJECT_SIZE); return fold_convert (size_type_node, bytes); } else if (TREE_CODE (ptr) == SSA_NAME) @@ -10258,7 +10261,8 @@ fold_builtin_object_size (tree ptr, tree ost) /* If object size is not known yet, delay folding until later. Maybe subsequent passes will help determining it. */ - if (compute_builtin_object_size (ptr, object_size_type, &bytes)) + if (compute_builtin_object_size (ptr, object_size_type, &bytes, + fcode == BUILT_IN_DYNAMIC_OBJECT_SIZE)) return fold_convert (size_type_node, bytes); } diff --git a/gcc/builtins.def b/gcc/builtins.def index 45a09b4d42d..2b2c46e9df6 100644 --- a/gcc/builtins.def +++ b/gcc/builtins.def @@ -972,6 +972,7 @@ DEF_BUILTIN_STUB (BUILT_IN_STRNCMP_EQ, "__builtin_strncmp_eq") /* Object size checking builtins. */ DEF_GCC_BUILTIN (BUILT_IN_OBJECT_SIZE, "object_size", BT_FN_SIZE_CONST_PTR_INT, ATTR_CONST_NOTHROW_LEAF_LIST) +DEF_GCC_BUILTIN (BUILT_IN_DYNAMIC_OBJECT_SIZE, "dynamic_object_size", BT_FN_SIZE_CONST_PTR_INT, ATTR_NOTHROW_LEAF_LIST) DEF_EXT_LIB_BUILTIN (BUILT_IN_MEMCPY_CHK, "__memcpy_chk", BT_FN_PTR_PTR_CONST_PTR_SIZE_SIZE, ATTR_NOTHROW_NONNULL_LEAF) DEF_EXT_LIB_BUILTIN (BUILT_IN_MEMMOVE_CHK, "__memmove_chk", BT_FN_PTR_PTR_CONST_PTR_SIZE_SIZE, ATTR_NOTHROW_NONNULL_LEAF) DEF_EXT_LIB_BUILTIN (BUILT_IN_MEMPCPY_CHK, "__mempcpy_chk", BT_FN_PTR_PTR_CONST_PTR_SIZE_SIZE, ATTR_RETNONNULL_NOTHROW_LEAF) diff --git a/gcc/doc/extend.texi b/gcc/doc/extend.texi index eee4c6737bb..7fe244ce3c8 100644 --- a/gcc/doc/extend.texi +++ b/gcc/doc/extend.texi @@ -12712,6 +12712,7 @@ __atomic_store_n(&lockvar, 0, __ATOMIC_RELEASE|__ATOMIC_HLE_RELEASE); @node Object Size Checking @section Object Size Checking Built-in Functions @findex __builtin_object_size +@findex __builtin_dynamic_object_size @findex __builtin___memcpy_chk @findex __builtin___mempcpy_chk @findex __builtin___memmove_chk @@ -12779,6 +12780,18 @@ assert (__builtin_object_size (q, 1) == sizeof (var.b)); @end smallexample @end deftypefn +@deftypefn {Built-in Function} {size_t} __builtin_dynamic_object_size (const void * @var{ptr}, int @var{type}) +is similar to @code{__builtin_object_size} in that it returns a number of bytes +from @var{ptr} to the end of the object @var{ptr} pointer points to, except +that the size returned may not be a constant. This results in successful +evaluation of object size estimates in a wider range of use cases and can be +more precise than @code{__builtin_object_size}, but it incurs a performance +penalty since it may add a runtime overhead on size computation. Semantics of +@var{type} as well as return values in case it is not possible to determine +which objects @var{ptr} points to at compile time are the same as in the case +of @code{__builtin_object_size}. +@end deftypefn + There are built-in functions added for many common string operation functions, e.g., for @code{memcpy} @code{__builtin___memcpy_chk} built-in is provided. This built-in has an additional last argument, diff --git a/gcc/testsuite/g++.dg/ext/builtin-dynamic-object-size1.C b/gcc/testsuite/g++.dg/ext/builtin-dynamic-object-size1.C new file mode 100644 index 00000000000..b11ac200751 --- /dev/null +++ b/gcc/testsuite/g++.dg/ext/builtin-dynamic-object-size1.C @@ -0,0 +1,5 @@ +// { dg-do run } +// { dg-options "-O2" } + +#define __builtin_object_size __builtin_dynamic_object_size +#include "builtin-object-size1.C" diff --git a/gcc/testsuite/g++.dg/ext/builtin-dynamic-object-size2.C b/gcc/testsuite/g++.dg/ext/builtin-dynamic-object-size2.C new file mode 100644 index 00000000000..6e52cf38533 --- /dev/null +++ b/gcc/testsuite/g++.dg/ext/builtin-dynamic-object-size2.C @@ -0,0 +1,5 @@ +// { dg-do run } +// { dg-options "-O2" } + +#define __builtin_object_size __builtin_dynamic_object_size +#include "builtin-object-size2.C" diff --git a/gcc/testsuite/gcc.dg/builtin-dynamic-alloc-size.c b/gcc/testsuite/gcc.dg/builtin-dynamic-alloc-size.c new file mode 100644 index 00000000000..9d0eadd6be4 --- /dev/null +++ b/gcc/testsuite/gcc.dg/builtin-dynamic-alloc-size.c @@ -0,0 +1,7 @@ +/* { dg-do compile } + { dg-require-effective-target alloca } + { dg-additional-options "-O2 -fdump-tree-optimized" } */ + +#define __builtin_object_size __builtin_dynamic_object_size +#include "builtin-alloc-size.c" +/* { dg-final { scan-tree-dump-not "abort" "optimized" } } */ diff --git a/gcc/testsuite/gcc.dg/builtin-dynamic-object-size-1.c b/gcc/testsuite/gcc.dg/builtin-dynamic-object-size-1.c new file mode 100644 index 00000000000..7cc8b1c9488 --- /dev/null +++ b/gcc/testsuite/gcc.dg/builtin-dynamic-object-size-1.c @@ -0,0 +1,6 @@ +/* { dg-do run } */ +/* { dg-options "-O2" } */ +/* { dg-require-effective-target alloca } */ + +#define __builtin_object_size __builtin_dynamic_object_size +#include "builtin-object-size-1.c" diff --git a/gcc/testsuite/gcc.dg/builtin-dynamic-object-size-10.c b/gcc/testsuite/gcc.dg/builtin-dynamic-object-size-10.c new file mode 100644 index 00000000000..bc880a589ae --- /dev/null +++ b/gcc/testsuite/gcc.dg/builtin-dynamic-object-size-10.c @@ -0,0 +1,9 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -fdump-tree-early_objsz-details" } */ +// { dg-skip-if "packed attribute missing for drone_source_packet" { "epiphany-*-*" } } + +#define __builtin_object_size __builtin_dynamic_object_size +#include "builtin-object-size-10.c" + +/* { dg-final { scan-tree-dump "maximum object size 21" "early_objsz" } } */ +/* { dg-final { scan-tree-dump "maximum subobject size 16" "early_objsz" } } */ diff --git a/gcc/testsuite/gcc.dg/builtin-dynamic-object-size-11.c b/gcc/testsuite/gcc.dg/builtin-dynamic-object-size-11.c new file mode 100644 index 00000000000..65dcec9fcae --- /dev/null +++ b/gcc/testsuite/gcc.dg/builtin-dynamic-object-size-11.c @@ -0,0 +1,7 @@ +/* PR48985 */ +/* { dg-do run } */ +/* { dg-options "-std=gnu89" } */ +/* { dg-skip-if "packed attribute missing for struct s" { "epiphany-*-*" } } */ + +#define __builtin_object_size __builtin_dynamic_object_size +#include "builtin-object-size-11.c" diff --git a/gcc/testsuite/gcc.dg/builtin-dynamic-object-size-12.c b/gcc/testsuite/gcc.dg/builtin-dynamic-object-size-12.c new file mode 100644 index 00000000000..f0ce050a943 --- /dev/null +++ b/gcc/testsuite/gcc.dg/builtin-dynamic-object-size-12.c @@ -0,0 +1,5 @@ +/* { dg-do run } */ +/* { dg-options "-O2" } */ + +#define __builtin_object_size __builtin_dynamic_object_size +#include "builtin-object-size-12.c" diff --git a/gcc/testsuite/gcc.dg/builtin-dynamic-object-size-13.c b/gcc/testsuite/gcc.dg/builtin-dynamic-object-size-13.c new file mode 100644 index 00000000000..555e23522dc --- /dev/null +++ b/gcc/testsuite/gcc.dg/builtin-dynamic-object-size-13.c @@ -0,0 +1,5 @@ +/* { dg-do run } */ +/* { dg-options "-O2" } */ + +#define __builtin_object_size __builtin_dynamic_object_size +#include "builtin-object-size-13.c" diff --git a/gcc/testsuite/gcc.dg/builtin-dynamic-object-size-14.c b/gcc/testsuite/gcc.dg/builtin-dynamic-object-size-14.c new file mode 100644 index 00000000000..26207200191 --- /dev/null +++ b/gcc/testsuite/gcc.dg/builtin-dynamic-object-size-14.c @@ -0,0 +1,5 @@ +/* { dg-do run } */ +/* { dg-options "-O2" } */ + +#define __builtin_object_size __builtin_dynamic_object_size +#include "builtin-object-size-14.c" diff --git a/gcc/testsuite/gcc.dg/builtin-dynamic-object-size-15.c b/gcc/testsuite/gcc.dg/builtin-dynamic-object-size-15.c new file mode 100644 index 00000000000..cd8a941438d --- /dev/null +++ b/gcc/testsuite/gcc.dg/builtin-dynamic-object-size-15.c @@ -0,0 +1,5 @@ +/* { dg-do run } */ +/* { dg-options "-O2" } */ + +#define __builtin_object_size __builtin_dynamic_object_size +#include "builtin-object-size-15.c" diff --git a/gcc/testsuite/gcc.dg/builtin-dynamic-object-size-16.c b/gcc/testsuite/gcc.dg/builtin-dynamic-object-size-16.c new file mode 100644 index 00000000000..5aa256dec1a --- /dev/null +++ b/gcc/testsuite/gcc.dg/builtin-dynamic-object-size-16.c @@ -0,0 +1,7 @@ +/* { dg-do run } */ +/* { dg-options "-O0" } */ + +#define DYNAMIC_OBJECT_SIZE +#define __builtin_object_size __builtin_dynamic_object_size +char ax2[]; /* { dg-warning "assumed to have one element" } */ +#include "builtin-object-size-16.c" diff --git a/gcc/testsuite/gcc.dg/builtin-dynamic-object-size-17.c b/gcc/testsuite/gcc.dg/builtin-dynamic-object-size-17.c new file mode 100644 index 00000000000..f4c4b0fbc7a --- /dev/null +++ b/gcc/testsuite/gcc.dg/builtin-dynamic-object-size-17.c @@ -0,0 +1,8 @@ +/* { dg-do compile } */ +/* { dg-options "-O0 -fdump-tree-ssa" } */ + +#define DYNAMIC_OBJECT_SIZE +char ax2[]; /* { dg-warning "assumed to have one element" } */ +#define __builtin_object_size __builtin_dynamic_object_size +#include "builtin-object-size-17.c" +/* { dg-final { scan-tree-dump-not "failure_on_line" "ssa" } } */ diff --git a/gcc/testsuite/gcc.dg/builtin-dynamic-object-size-18.c b/gcc/testsuite/gcc.dg/builtin-dynamic-object-size-18.c new file mode 100644 index 00000000000..70c1ebcff21 --- /dev/null +++ b/gcc/testsuite/gcc.dg/builtin-dynamic-object-size-18.c @@ -0,0 +1,8 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -fdump-tree-optimized" } */ +/* __stpncpy_chk could return buf up to buf + 64, so + the minimum object size might be far smaller than 64. */ +/* { dg-final { scan-tree-dump-not "return 64;" "optimized" } } */ + +#define __builtin_object_size __builtin_dynamic_object_size +#include "builtin-object-size-18.c" diff --git a/gcc/testsuite/gcc.dg/builtin-dynamic-object-size-19.c b/gcc/testsuite/gcc.dg/builtin-dynamic-object-size-19.c new file mode 100644 index 00000000000..44141a38607 --- /dev/null +++ b/gcc/testsuite/gcc.dg/builtin-dynamic-object-size-19.c @@ -0,0 +1,104 @@ +/* PR tree-optimization/88372 - alloc_size attribute is ignored + on function pointers { dg-do compile } + { dg-options "-O2 -fdump-tree-optimized" } */ + +#define __builtin_object_size __builtin_dynamic_object_size +#include "builtin-object-size-18.c" + +typedef __SIZE_TYPE__ size_t; + +#define ATTR(...) __attribute__ ((__VA_ARGS__)) +#define CONCAT(x, y) x ## y +#define CAT(x, y) CONCAT (x, y) +#define FAILNAME(name) CAT (call_ ## name ##_on_line_, __LINE__) + +#define FAIL(name) do { \ + extern void FAILNAME (name) (void); \ + FAILNAME (name)(); \ + } while (0) + +/* Macro to emit a call to function named + call_in_true_branch_not_eliminated_on_line_NNN() + for each call that's expected to be eliminated. The dg-final + scan-tree-dump-time directive at the bottom of the test verifies + that no such call appears in output. */ +#define ELIM(expr) \ + if (!(expr)) FAIL (in_true_branch_not_eliminated); else (void)0 + +void sink (void*); + +#define T(alloc, n) do { \ + void *p = alloc; \ + sink (p); \ + ELIM (n == __builtin_object_size (p, 0)); \ + ELIM (n == __builtin_object_size (p, 1)); \ + ELIM (n == __builtin_object_size (p, 2)); \ + ELIM (n == __builtin_object_size (p, 3)); \ + } while (0) + + +ATTR (alloc_size (1)) void* (*alloc_1_x)(size_t, size_t); +ATTR (alloc_size (2)) void* (*alloc_x_2)(size_t, size_t); + +/* Verify that things work when attribute alloc_size is applied + to a typedef that is then used to declared a pointer. */ +typedef ATTR (alloc_size (1, 2)) void* (alloc_1_2_t)(size_t, size_t); + +void test_alloc_ptr (alloc_1_2_t *alloc_1_2) +{ + T (alloc_1_x (0, 0), 0); + T (alloc_1_x (1, 0), 1); + T (alloc_1_x (3, 0), 3); + T (alloc_1_x (9, 5), 9); + + T (alloc_x_2 (0, 0), 0); + T (alloc_x_2 (1, 0), 0); + T (alloc_x_2 (0, 1), 1); + T (alloc_x_2 (9, 5), 5); + + T (alloc_1_2 (0, 0), 0); + T (alloc_1_2 (1, 0), 0); + T (alloc_1_2 (0, 1), 0); + T (alloc_1_2 (9, 5), 45); +} + +/* Verify that object size is detected even in indirect calls via + function pointers to built-in allocation functions, even without + explicit use of attribute alloc_size on the pointers. */ + +typedef void *(allocfn_1) (size_t); +typedef void *(allocfn_1_2) (size_t, size_t); + +static inline void * +call_alloc (allocfn_1 *fn1, allocfn_1_2 *fn2, size_t n1, size_t n2) +{ + return fn1 ? fn1 (n1) : fn2 (n1, n2); +} + +static inline void * +call_malloc (size_t n) +{ + return call_alloc (__builtin_malloc, 0, n, 0); +} + +static inline void * +call_calloc (size_t n1, size_t n2) +{ + return call_alloc (0, __builtin_calloc, n1, n2); +} + +void test_builtin_ptr (void) +{ + T (call_malloc (0), 0); + T (call_malloc (1), 1); + T (call_malloc (9), 9); + + T (call_calloc (0, 0), 0); + T (call_calloc (0, 1), 0); + T (call_calloc (1, 0), 0); + T (call_calloc (1, 1), 1); + T (call_calloc (1, 3), 3); + T (call_calloc (2, 3), 6); +} + +/* { dg-final { scan-tree-dump-not "not_eliminated" "optimized" } } */ diff --git a/gcc/testsuite/gcc.dg/builtin-dynamic-object-size-2.c b/gcc/testsuite/gcc.dg/builtin-dynamic-object-size-2.c new file mode 100644 index 00000000000..267dbf48ca7 --- /dev/null +++ b/gcc/testsuite/gcc.dg/builtin-dynamic-object-size-2.c @@ -0,0 +1,6 @@ +/* { dg-do run } */ +/* { dg-options "-O2" } */ +/* { dg-require-effective-target alloca } */ + +#define __builtin_object_size __builtin_dynamic_object_size +#include "builtin-object-size-2.c" diff --git a/gcc/testsuite/gcc.dg/builtin-dynamic-object-size-3.c b/gcc/testsuite/gcc.dg/builtin-dynamic-object-size-3.c new file mode 100644 index 00000000000..fb9dc56da7e --- /dev/null +++ b/gcc/testsuite/gcc.dg/builtin-dynamic-object-size-3.c @@ -0,0 +1,6 @@ +/* { dg-do run } */ +/* { dg-options "-O2" } */ +/* { dg-require-effective-target alloca } */ + +#define __builtin_object_size __builtin_dynamic_object_size +#include "builtin-object-size-3.c" diff --git a/gcc/testsuite/gcc.dg/builtin-dynamic-object-size-4.c b/gcc/testsuite/gcc.dg/builtin-dynamic-object-size-4.c new file mode 100644 index 00000000000..870548b4206 --- /dev/null +++ b/gcc/testsuite/gcc.dg/builtin-dynamic-object-size-4.c @@ -0,0 +1,6 @@ +/* { dg-do run } */ +/* { dg-options "-O2" } */ +/* { dg-require-effective-target alloca } */ + +#define __builtin_object_size __builtin_dynamic_object_size +#include "builtin-object-size-4.c" diff --git a/gcc/testsuite/gcc.dg/builtin-dynamic-object-size-5.c b/gcc/testsuite/gcc.dg/builtin-dynamic-object-size-5.c new file mode 100644 index 00000000000..698b03c34be --- /dev/null +++ b/gcc/testsuite/gcc.dg/builtin-dynamic-object-size-5.c @@ -0,0 +1,7 @@ +/* { dg-do compile { target i?86-*-linux* i?86-*-gnu* x86_64-*-linux* } } */ +/* { dg-options "-O2" } */ + +#define __builtin_object_size __builtin_dynamic_object_size +#include "builtin-object-size-5.c" + +/* { dg-final { scan-assembler-not "abort" } } */ diff --git a/gcc/testsuite/gcc.dg/builtin-dynamic-object-size-6.c b/gcc/testsuite/gcc.dg/builtin-dynamic-object-size-6.c new file mode 100644 index 00000000000..6a275ce5b37 --- /dev/null +++ b/gcc/testsuite/gcc.dg/builtin-dynamic-object-size-6.c @@ -0,0 +1,5 @@ +/* { dg-do run } */ +/* { dg-options "-O2" } */ + +#define __builtin_object_size __builtin_dynamic_object_size +#include "builtin-object-size-6.c" diff --git a/gcc/testsuite/gcc.dg/builtin-dynamic-object-size-7.c b/gcc/testsuite/gcc.dg/builtin-dynamic-object-size-7.c new file mode 100644 index 00000000000..e2a65994687 --- /dev/null +++ b/gcc/testsuite/gcc.dg/builtin-dynamic-object-size-7.c @@ -0,0 +1,5 @@ +/* { dg-do run } */ +/* { dg-options "-O2" } */ + +#define __builtin_object_size __builtin_dynamic_object_size +#include "builtin-object-size-7.c" diff --git a/gcc/testsuite/gcc.dg/builtin-dynamic-object-size-8.c b/gcc/testsuite/gcc.dg/builtin-dynamic-object-size-8.c new file mode 100644 index 00000000000..e7af383d9b6 --- /dev/null +++ b/gcc/testsuite/gcc.dg/builtin-dynamic-object-size-8.c @@ -0,0 +1,5 @@ +/* { dg-do run } */ +/* { dg-options "-O2" } */ + +#define __builtin_object_size __builtin_dynamic_object_size +#include "builtin-object-size-8.c" diff --git a/gcc/testsuite/gcc.dg/builtin-dynamic-object-size-9.c b/gcc/testsuite/gcc.dg/builtin-dynamic-object-size-9.c new file mode 100644 index 00000000000..19021bc2ce9 --- /dev/null +++ b/gcc/testsuite/gcc.dg/builtin-dynamic-object-size-9.c @@ -0,0 +1,5 @@ +/* { dg-do run } */ +/* { dg-options "-O2" } */ + +#define __builtin_object_size __builtin_dynamic_object_size +#include "builtin-object-size-9.c" diff --git a/gcc/testsuite/gcc.dg/builtin-object-size-16.c b/gcc/testsuite/gcc.dg/builtin-object-size-16.c index 48229390bfd..a4557fbb1fb 100644 --- a/gcc/testsuite/gcc.dg/builtin-object-size-16.c +++ b/gcc/testsuite/gcc.dg/builtin-object-size-16.c @@ -54,7 +54,9 @@ static int nfails; typedef __SIZE_TYPE__ size_t; extern char ax[]; +#ifndef DYNAMIC_OBJECT_SIZE char ax2[]; /* { dg-warning "assumed to have one element" } */ +#endif extern char a0[0]; static char a1[1]; diff --git a/gcc/testsuite/gcc.dg/builtin-object-size-17.c b/gcc/testsuite/gcc.dg/builtin-object-size-17.c index 0497bbf4505..09552a8a963 100644 --- a/gcc/testsuite/gcc.dg/builtin-object-size-17.c +++ b/gcc/testsuite/gcc.dg/builtin-object-size-17.c @@ -49,7 +49,9 @@ typedef __SIZE_TYPE__ size_t; extern char ax[]; +#ifndef DYNAMIC_OBJECT_SIZE char ax2[]; /* { dg-warning "assumed to have one element" } */ +#endif extern char a0[0]; static char a1[1]; diff --git a/gcc/tree-object-size.c b/gcc/tree-object-size.c index e48120559d3..983df24719e 100644 --- a/gcc/tree-object-size.c +++ b/gcc/tree-object-size.c @@ -34,6 +34,7 @@ along with GCC; see the file COPYING3. If not see #include "tree-cfg.h" #include "stringpool.h" #include "attribs.h" +#include "builtins.h" struct object_size_info { @@ -46,7 +47,8 @@ enum { OST_SUBOBJECT = 1, OST_MINIMUM = 2, - OST_END = 4, + OST_DYNAMIC = 4, + OST_END = 8, }; #define OST_TREE_CODE(_ost) ((_ost) & OST_MINIMUM ? MIN_EXPR : MAX_EXPR) @@ -371,7 +373,8 @@ addr_object_size (struct object_size_info *osi, const_tree ptr, || TREE_CODE (TREE_OPERAND (pt_var, 0)) != SSA_NAME) { compute_builtin_object_size (TREE_OPERAND (pt_var, 0), - object_size_type & ~OST_SUBOBJECT, &sz); + object_size_type & OST_MINIMUM, &sz, + object_size_type & OST_DYNAMIC); } else { @@ -835,9 +838,10 @@ resolve_dependency_loops (struct object_size_info *osi) bool compute_builtin_object_size (tree ptr, int object_size_type, - tree *psize) + tree *psize, bool dynamic) { gcc_assert (object_size_type >= 0 && object_size_type < OST_END); + object_size_type |= dynamic ? OST_DYNAMIC : 0; /* Set to unknown and overwrite just before returning if the size could be determined. */ @@ -871,8 +875,10 @@ compute_builtin_object_size (tree ptr, int object_size_type, ptr = gimple_assign_rhs1 (def); if (tree_fits_shwi_p (offset) - && compute_builtin_object_size (ptr, object_size_type, - psize)) + && compute_builtin_object_size (ptr, + (object_size_type + & ~OST_DYNAMIC), + psize, dynamic)) { /* Return zero when the offset is out of bounds. */ *psize = size_for_offset (*psize, offset); @@ -893,8 +899,9 @@ compute_builtin_object_size (tree ptr, int object_size_type, object_sizes_grow (object_size_type); if (dump_file) { - fprintf (dump_file, "Computing %s %sobject size for ", + fprintf (dump_file, "Computing %s %s%sobject size for ", (object_size_type & OST_MINIMUM) ? "minimum" : "maximum", + dynamic ? "dynamic " : "", (object_size_type & OST_SUBOBJECT) ? "sub" : ""); print_generic_expr (dump_file, ptr, dump_flags); fprintf (dump_file, ":\n"); @@ -917,9 +924,10 @@ compute_builtin_object_size (tree ptr, int object_size_type, print_generic_expr (dump_file, ssa_name (i), dump_flags); fprintf (dump_file, - ": %s %sobject size ", + ": %s %s%sobject size ", ((object_size_type & OST_MINIMUM) ? "minimum" : "maximum"), + dynamic ? "dynamic " : "", (object_size_type & OST_SUBOBJECT) ? "sub" : ""); print_generic_expr (dump_file, object_sizes_get (&osi, i), dump_flags); @@ -1310,8 +1318,80 @@ do_valueize (tree t) return t; } +/* Process a __builtin_object_size or __builtin_dynamic_object_size call in + CALL early before any object information is lost due to optimization. + Insert a MIN or MAX expression of the result and __builtin_object_size at I + so that it may be processed in the second pass. */ + +static void +early_object_sizes_execute_one (gimple_stmt_iterator *i, gimple *call) +{ + tree ost = gimple_call_arg (call, 1); + tree lhs = gimple_call_lhs (call); + gcc_assert (lhs != NULL_TREE); + + if (tree_fits_uhwi_p (ost)) + { + unsigned HOST_WIDE_INT object_size_type = tree_to_uhwi (ost); + tree ptr = gimple_call_arg (call, 0); + if ((object_size_type == 1 || object_size_type == 3) + && (TREE_CODE (ptr) == ADDR_EXPR || TREE_CODE (ptr) == SSA_NAME)) + { + tree type = TREE_TYPE (lhs); + tree bytes; + if (compute_builtin_object_size (ptr, object_size_type, &bytes)) + { + tree tem = make_ssa_name (type); + gimple_call_set_lhs (call, tem); + enum tree_code code + = object_size_type & OST_MINIMUM ? MAX_EXPR : MIN_EXPR; + tree cst = fold_convert (type, bytes); + gimple *g = gimple_build_assign (lhs, code, tem, cst); + gsi_insert_after (i, g, GSI_NEW_STMT); + update_stmt (call); + } + } + } +} + +/* Attempt to fold one __builtin_dynamic_object_size call in CALL into an + expression and insert it at I. Return true if it succeeds. */ + +static bool +dynamic_object_sizes_execute_one (gimple_stmt_iterator *i, gimple *call) +{ + unsigned numargs = gimple_call_num_args (call); + tree *args = XALLOCAVEC (tree, numargs); + args[0] = gimple_call_arg (call, 0); + args[1] = gimple_call_arg (call, 1); + + location_t loc = EXPR_LOC_OR_LOC (args[0], input_location); + tree result_type = gimple_call_return_type (as_a (call)); + tree result = fold_builtin_call_array (loc, result_type, + gimple_call_fn (call), numargs, args); + + if (result) + { + /* fold_builtin_call_array may wrap the result inside a + NOP_EXPR. */ + STRIP_NOPS (result); + gimplify_and_update_call_from_tree (i, result); + + if (dump_file && (dump_flags & TDF_DETAILS)) + { + fprintf (dump_file, "Simplified (dynamic)\n "); + print_gimple_stmt (dump_file, call, 0, dump_flags); + fprintf (dump_file, " to "); + print_generic_expr (dump_file, result); + fprintf (dump_file, "\n"); + } + return true; + } + return false; +} + static unsigned int -object_sizes_execute (function *fun, bool insert_min_max_p) +object_sizes_execute (function *fun, bool early) { basic_block bb; FOR_EACH_BB_FN (bb, fun) @@ -1320,8 +1400,12 @@ object_sizes_execute (function *fun, bool insert_min_max_p) for (i = gsi_start_bb (bb); !gsi_end_p (i); gsi_next (&i)) { tree result; + bool dynamic = false; + gimple *call = gsi_stmt (i); - if (!gimple_call_builtin_p (call, BUILT_IN_OBJECT_SIZE)) + if (gimple_call_builtin_p (call, BUILT_IN_DYNAMIC_OBJECT_SIZE)) + dynamic = true; + else if (!gimple_call_builtin_p (call, BUILT_IN_OBJECT_SIZE)) continue; tree lhs = gimple_call_lhs (call); @@ -1330,41 +1414,39 @@ object_sizes_execute (function *fun, bool insert_min_max_p) init_object_sizes (); - /* If insert_min_max_p, only attempt to fold + /* If early, only attempt to fold __builtin_object_size (x, 1) and __builtin_object_size (x, 3), and rather than folding the builtin to the constant if any, create a MIN_EXPR or MAX_EXPR of the __builtin_object_size call result and the computed constant. */ - if (insert_min_max_p) + if (early) { - tree ost = gimple_call_arg (call, 1); - if (tree_fits_uhwi_p (ost)) + early_object_sizes_execute_one (&i, call); + continue; + } + + if (dynamic) + { + bool done = dynamic_object_sizes_execute_one (&i, call); + if (done || early) + continue; + else { - unsigned HOST_WIDE_INT object_size_type = tree_to_uhwi (ost); - tree ptr = gimple_call_arg (call, 0); - if ((object_size_type & OST_SUBOBJECT) - && (TREE_CODE (ptr) == ADDR_EXPR - || TREE_CODE (ptr) == SSA_NAME)) + /* If we could not find a suitable size expression, lower to + __builtin_object_size so that we may at least get a + constant lower or higher estimate. */ + tree bosfn = builtin_decl_implicit (BUILT_IN_OBJECT_SIZE); + gimple_call_set_fndecl (call, bosfn); + update_stmt (call); + + if (dump_file && (dump_flags & TDF_DETAILS)) { - tree type = TREE_TYPE (lhs); - tree bytes; - if (compute_builtin_object_size (ptr, object_size_type, - &bytes)) - { - tree tem = make_ssa_name (type); - gimple_call_set_lhs (call, tem); - enum tree_code code - = (object_size_type & OST_MINIMUM - ? MAX_EXPR : MIN_EXPR); - tree cst = fold_convert (type, bytes); - gimple *g - = gimple_build_assign (lhs, code, tem, cst); - gsi_insert_after (&i, g, GSI_NEW_STMT); - update_stmt (call); - } + print_generic_expr (dump_file, gimple_call_arg (call, 0), + dump_flags); + fprintf (dump_file, + ": Retrying as __builtin_object_size\n"); } } - continue; } result = gimple_fold_stmt_to_constant (call, do_valueize); diff --git a/gcc/tree-object-size.h b/gcc/tree-object-size.h index b2d6a58324c..edc7b573cc5 100644 --- a/gcc/tree-object-size.h +++ b/gcc/tree-object-size.h @@ -22,7 +22,8 @@ along with GCC; see the file COPYING3. If not see extern void init_object_sizes (void); extern void fini_object_sizes (void); -extern bool compute_builtin_object_size (tree, int, tree *); +extern bool compute_builtin_object_size (tree, int, tree *, + bool dynamic = false); extern tree decl_init_size (tree, bool); #endif // GCC_TREE_OBJECT_SIZE_H From patchwork Tue Nov 9 19:01:32 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Siddhesh Poyarekar X-Patchwork-Id: 47328 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 D89E83858404 for ; Tue, 9 Nov 2021 19:06:07 +0000 (GMT) X-Original-To: gcc-patches@gcc.gnu.org Delivered-To: gcc-patches@gcc.gnu.org Received: from giant.ash.relay.mailchannels.net (giant.ash.relay.mailchannels.net [23.83.222.68]) by sourceware.org (Postfix) with ESMTPS id B9F423857C60 for ; Tue, 9 Nov 2021 19:02:12 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.1 sourceware.org B9F423857C60 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 2FEF3342DC0; Tue, 9 Nov 2021 19:02:09 +0000 (UTC) Received: from pdx1-sub0-mail-a306.dreamhost.com (100-96-17-28.trex.outbound.svc.cluster.local [100.96.17.28]) (Authenticated sender: dreamhost) by relay.mailchannels.net (Postfix) with ESMTPA id CB198342CC0; Tue, 9 Nov 2021 19:02:03 +0000 (UTC) X-Sender-Id: dreamhost|x-authsender|siddhesh@gotplt.org Received: from pdx1-sub0-mail-a306.dreamhost.com (pop.dreamhost.com [64.90.62.162]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384) by 100.96.17.28 (trex/6.4.3); Tue, 09 Nov 2021 19:02:09 +0000 X-MC-Relay: Neutral X-MailChannels-SenderId: dreamhost|x-authsender|siddhesh@gotplt.org X-MailChannels-Auth-Id: dreamhost X-Absorbed-Left: 5b148cd43c218174_1636484529002_4268973158 X-MC-Loop-Signature: 1636484529002:238601578 X-MC-Ingress-Time: 1636484529002 Received: from rhbox.redhat.com (unknown [1.186.121.127]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256) (No client certificate requested) (Authenticated sender: siddhesh@gotplt.org) by pdx1-sub0-mail-a306.dreamhost.com (Postfix) with ESMTPSA id 4Hpcm9729Hz1WX; Tue, 9 Nov 2021 11:02:01 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha1; c=relaxed/relaxed; d=gotplt.org; s=gotplt.org; t=1636484523; bh=EP15VczHotRyxjt/NeE9RSZx4BE=; h=From:To:Cc:Subject:Date:Content-Transfer-Encoding; b=MXigowzCpzx645S3xBlQqjiMbMJPBhkr2w6tH+1tdZy2QYaQFf5AemV1fQJFVZoWf PcmpAuQPmnb/+GCfxiBNbt3Jq7JvkbVQQHvoIJTD8ZAz2R9oqjZLsXOCGjtmiTW7VK H+qRh0QNcG6JNwAXs0fmZc+gdWc661ubtGjJ/BEc= From: Siddhesh Poyarekar To: gcc-patches@gcc.gnu.org Subject: [PATCH 06/10] tree-object-size: Support dynamic sizes in conditions Date: Wed, 10 Nov 2021 00:31:32 +0530 Message-Id: <20211109190137.1107736-7-siddhesh@gotplt.org> X-Mailer: git-send-email 2.31.1 In-Reply-To: <20211109190137.1107736-1-siddhesh@gotplt.org> References: <20211109190137.1107736-1-siddhesh@gotplt.org> MIME-Version: 1.0 X-Spam-Status: No, score=-3038.0 required=5.0 tests=BAYES_00, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, GIT_PATCH_0, RCVD_IN_BARRACUDACENTRAL, RCVD_IN_DNSWL_NONE, RCVD_IN_MSPIKE_H2, RCVD_IN_SBL, 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" Handle GIMPLE_PHI and conditionals specially for dynamic objects, returning PHI/conditional expressions instead of just a MIN/MAX estimate. This makes the returned object size variable for loops and conditionals, so tests need to be adjusted to look for precise size in some cases. builtin-dynamic-object-size-5.c had to be modified to only look for success in maximum object size case and skip over the minimum object size tests because the result is no longer a compile time constant. I also added some simple tests to exercise conditionals with dynamic object sizes. gcc/ChangeLog: * tree-object-size.c: Include gimplify-me.h. (struct object_size_info): New member phiresults. (estimate_size): New argument visitlog. Handle newly inserted PHI nodes. (get_insertion_point, gimplify_size_expressions): New functions. (compute_builtin_object_size): Call gimplify_size_expressions. (make_or_get_tempsize): New function. (cond_expr_object_size): Return COND_EXPR for dynamic sizes. (phi_object_size, phi_dynamic_object_size): New functions. (collect_object_sizes_for): Call them. (object_sizes_execute): Don't insert min/max for dynamic sizes. gcc/testsuite/ChangeLog: * gcc.dg/builtin-dynamic-object-size-0.c: New file. * gcc.dg/builtin-dynamic-object-size-10.c: Adjust expected output. * gcc.dg/builtin-dynamic-object-size-1.c (DYNAMIC_OBJECT_SIZE): New macro. * gcc.dg/builtin-dynamic-object-size-2.c (DYNAMIC_OBJECT_SIZE): Likewise. * gcc.dg/builtin-dynamic-object-size-3.c (DYNAMIC_OBJECT_SIZE): Likewise. * gcc.dg/builtin-dynamic-object-size-4.c (DYNAMIC_OBJECT_SIZE): Likewise. * gcc.dg/builtin-dynamic-object-size-5.c (DYNAMIC_OBJECT_SIZE): Likewise. * gcc.dg/builtin-object-size-1.c [DYNAMIC_OBJECT_SIZE]: Alter expected results for dynamic object size. * gcc.dg/builtin-object-size-2.c [DYNAMIC_OBJECT_SIZE]: Likewise. * gcc.dg/builtin-object-size-3.c [DYNAMIC_OBJECT_SIZE]: Likewise. * gcc.dg/builtin-object-size-4.c [DYNAMIC_OBJECT_SIZE]: Likewise. * gcc.dg/builtin-object-size-5.c [DYNAMIC_OBJECT_SIZE]: Likewise. Signed-off-by: Siddhesh Poyarekar --- .../gcc.dg/builtin-dynamic-object-size-0.c | 72 ++++ .../gcc.dg/builtin-dynamic-object-size-1.c | 1 + .../gcc.dg/builtin-dynamic-object-size-10.c | 4 +- .../gcc.dg/builtin-dynamic-object-size-2.c | 1 + .../gcc.dg/builtin-dynamic-object-size-3.c | 1 + .../gcc.dg/builtin-dynamic-object-size-4.c | 1 + .../gcc.dg/builtin-dynamic-object-size-5.c | 1 + gcc/testsuite/gcc.dg/builtin-object-size-1.c | 109 +++++- gcc/testsuite/gcc.dg/builtin-object-size-2.c | 77 +++++ gcc/testsuite/gcc.dg/builtin-object-size-3.c | 105 ++++++ gcc/testsuite/gcc.dg/builtin-object-size-4.c | 68 ++++ gcc/testsuite/gcc.dg/builtin-object-size-5.c | 12 + gcc/tree-object-size.c | 315 +++++++++++++++--- 13 files changed, 725 insertions(+), 42 deletions(-) create mode 100644 gcc/testsuite/gcc.dg/builtin-dynamic-object-size-0.c diff --git a/gcc/testsuite/gcc.dg/builtin-dynamic-object-size-0.c b/gcc/testsuite/gcc.dg/builtin-dynamic-object-size-0.c new file mode 100644 index 00000000000..ddedf6a49bd --- /dev/null +++ b/gcc/testsuite/gcc.dg/builtin-dynamic-object-size-0.c @@ -0,0 +1,72 @@ +/* { dg-do run } */ +/* { dg-options "-O2" } */ + +typedef __SIZE_TYPE__ size_t; +#define abort __builtin_abort + +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_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); +} + +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 (64); + + return __builtin_dynamic_object_size (bin, 0); +} + +unsigned nfails = 0; + +#define FAIL() ({ \ + __builtin_printf ("Failure at line: %d\n", __LINE__); \ + nfails++; \ +}) + +int +main (int argc, char **argv) +{ + if (test_builtin_malloc_condphi (1) != 32) + FAIL (); + if (test_builtin_malloc_condphi (0) != 64) + FAIL (); + if (test_builtin_calloc_condphi (128, 1, 0) == 128) + FAIL (); + if (test_deploop (128, 129) != 32) + FAIL (); + + if (nfails > 0) + __builtin_abort (); + + return 0; +} diff --git a/gcc/testsuite/gcc.dg/builtin-dynamic-object-size-1.c b/gcc/testsuite/gcc.dg/builtin-dynamic-object-size-1.c index 7cc8b1c9488..2c7d2128913 100644 --- a/gcc/testsuite/gcc.dg/builtin-dynamic-object-size-1.c +++ b/gcc/testsuite/gcc.dg/builtin-dynamic-object-size-1.c @@ -2,5 +2,6 @@ /* { dg-options "-O2" } */ /* { dg-require-effective-target alloca } */ +#define DYNAMIC_OBJECT_SIZE #define __builtin_object_size __builtin_dynamic_object_size #include "builtin-object-size-1.c" diff --git a/gcc/testsuite/gcc.dg/builtin-dynamic-object-size-10.c b/gcc/testsuite/gcc.dg/builtin-dynamic-object-size-10.c index bc880a589ae..e234467d6d0 100644 --- a/gcc/testsuite/gcc.dg/builtin-dynamic-object-size-10.c +++ b/gcc/testsuite/gcc.dg/builtin-dynamic-object-size-10.c @@ -5,5 +5,5 @@ #define __builtin_object_size __builtin_dynamic_object_size #include "builtin-object-size-10.c" -/* { dg-final { scan-tree-dump "maximum object size 21" "early_objsz" } } */ -/* { dg-final { scan-tree-dump "maximum subobject size 16" "early_objsz" } } */ +/* { dg-final { scan-tree-dump "maximum dynamic object size 21" "early_objsz" } } */ +/* { dg-final { scan-tree-dump "maximum dynamic subobject size 16" "early_objsz" } } */ diff --git a/gcc/testsuite/gcc.dg/builtin-dynamic-object-size-2.c b/gcc/testsuite/gcc.dg/builtin-dynamic-object-size-2.c index 267dbf48ca7..2f07534c11b 100644 --- a/gcc/testsuite/gcc.dg/builtin-dynamic-object-size-2.c +++ b/gcc/testsuite/gcc.dg/builtin-dynamic-object-size-2.c @@ -2,5 +2,6 @@ /* { dg-options "-O2" } */ /* { dg-require-effective-target alloca } */ +#define DYNAMIC_OBJECT_SIZE #define __builtin_object_size __builtin_dynamic_object_size #include "builtin-object-size-2.c" diff --git a/gcc/testsuite/gcc.dg/builtin-dynamic-object-size-3.c b/gcc/testsuite/gcc.dg/builtin-dynamic-object-size-3.c index fb9dc56da7e..29b5b358845 100644 --- a/gcc/testsuite/gcc.dg/builtin-dynamic-object-size-3.c +++ b/gcc/testsuite/gcc.dg/builtin-dynamic-object-size-3.c @@ -2,5 +2,6 @@ /* { dg-options "-O2" } */ /* { dg-require-effective-target alloca } */ +#define DYNAMIC_OBJECT_SIZE #define __builtin_object_size __builtin_dynamic_object_size #include "builtin-object-size-3.c" diff --git a/gcc/testsuite/gcc.dg/builtin-dynamic-object-size-4.c b/gcc/testsuite/gcc.dg/builtin-dynamic-object-size-4.c index 870548b4206..5ff1f16c978 100644 --- a/gcc/testsuite/gcc.dg/builtin-dynamic-object-size-4.c +++ b/gcc/testsuite/gcc.dg/builtin-dynamic-object-size-4.c @@ -2,5 +2,6 @@ /* { dg-options "-O2" } */ /* { dg-require-effective-target alloca } */ +#define DYNAMIC_OBJECT_SIZE #define __builtin_object_size __builtin_dynamic_object_size #include "builtin-object-size-4.c" diff --git a/gcc/testsuite/gcc.dg/builtin-dynamic-object-size-5.c b/gcc/testsuite/gcc.dg/builtin-dynamic-object-size-5.c index 698b03c34be..2438a26d920 100644 --- a/gcc/testsuite/gcc.dg/builtin-dynamic-object-size-5.c +++ b/gcc/testsuite/gcc.dg/builtin-dynamic-object-size-5.c @@ -1,6 +1,7 @@ /* { dg-do compile { target i?86-*-linux* i?86-*-gnu* x86_64-*-linux* } } */ /* { dg-options "-O2" } */ +#define DYNAMIC_OBJECT_SIZE #define __builtin_object_size __builtin_dynamic_object_size #include "builtin-object-size-5.c" diff --git a/gcc/testsuite/gcc.dg/builtin-object-size-1.c b/gcc/testsuite/gcc.dg/builtin-object-size-1.c index b270e8d8827..76df4c96271 100644 --- a/gcc/testsuite/gcc.dg/builtin-object-size-1.c +++ b/gcc/testsuite/gcc.dg/builtin-object-size-1.c @@ -42,9 +42,17 @@ test1 (void *q, int x) abort (); if (__builtin_object_size (q, 0) != (size_t) -1) abort (); +#ifdef DYNAMIC_OBJECT_SIZE + if (__builtin_object_size (r, 0) + != (x < 0 + ? sizeof (a) - __builtin_offsetof (struct A, a) - 9 + : sizeof (a) - __builtin_offsetof (struct A, c) - 1)) + abort (); +#else if (__builtin_object_size (r, 0) != sizeof (a) - __builtin_offsetof (struct A, a) - 9) abort (); +#endif if (x < 6) r = &w[2].a[1]; else @@ -58,9 +66,17 @@ test1 (void *q, int x) if (__builtin_object_size (&y.b, 0) != sizeof (a) - __builtin_offsetof (struct A, b)) abort (); +#ifdef DYNAMIC_OBJECT_SIZE + if (__builtin_object_size (r, 0) + != (x < 6 + ? 2 * sizeof (w[0]) - __builtin_offsetof (struct A, a) - 1 + : sizeof (a) - __builtin_offsetof (struct A, a) - 6)) + abort (); +#else if (__builtin_object_size (r, 0) != 2 * sizeof (w[0]) - __builtin_offsetof (struct A, a) - 1) abort (); +#endif if (x < 20) r = malloc (30); else @@ -165,6 +181,7 @@ test2 (void) struct B { char buf1[10]; char buf2[10]; } a; char *r, buf3[20]; int i; + size_t res; if (sizeof (a) != 20) return; @@ -181,7 +198,24 @@ test2 (void) else if (i == l1 + 2) r = &a.buf1[9]; } - if (__builtin_object_size (r, 0) != 20) +#ifdef DYNAMIC_OBJECT_SIZE + res = sizeof (buf3); + + for (i = 0; i < 4; ++i) + { + if (i == l1 - 1) + res = sizeof (a) - __builtin_offsetof (struct B, buf1) - 1; + else if (i == l1) + res = sizeof (a) - __builtin_offsetof (struct B, buf2) - 7; + else if (i == l1 + 1) + res = sizeof (buf3) - 5; + else if (i == l1 + 2) + res = sizeof (a) - __builtin_offsetof (struct B, buf1) - 9; + } +#else + res = 20; +#endif + if (__builtin_object_size (r, 0) != res) abort (); r = &buf3[20]; for (i = 0; i < 4; ++i) @@ -195,13 +229,45 @@ test2 (void) else if (i == l1 + 2) r = &a.buf1[9]; } - if (__builtin_object_size (r, 0) != 15) +#ifdef DYNAMIC_OBJECT_SIZE + res = sizeof (buf3) - 20; + + for (i = 0; i < 4; ++i) + { + if (i == l1 - 1) + res = sizeof (a) - __builtin_offsetof (struct B, buf1) - 7; + else if (i == l1) + res = sizeof (a) - __builtin_offsetof (struct B, buf2) - 7; + else if (i == l1 + 1) + res = sizeof (buf3) - 5; + else if (i == l1 + 2) + res = sizeof (a) - __builtin_offsetof (struct B, buf1) - 9; + } + if (__builtin_object_size (r, 0) != res) + abort (); +#else + res = 15; +#endif + if (__builtin_object_size (r, 0) != res) abort (); r += 8; +#ifdef DYNAMIC_OBJECT_SIZE + res -= 8; + if (__builtin_object_size (r, 0) != res) + abort (); + if (res >= 6) + { + if (__builtin_object_size (r + 6, 0) != res - 6) + abort (); + } + else if (__builtin_object_size (r + 6, 0) != 0) + abort (); +#else if (__builtin_object_size (r, 0) != 7) abort (); if (__builtin_object_size (r + 6, 0) != 1) abort (); +#endif r = &buf3[18]; for (i = 0; i < 4; ++i) { @@ -214,8 +280,31 @@ test2 (void) else if (i == l1 + 2) r = &a.buf1[4]; } +#ifdef DYNAMIC_OBJECT_SIZE + res = sizeof (buf3) - 18; + + for (i = 0; i < 4; ++i) + { + if (i == l1 - 1) + res = sizeof (a) - __builtin_offsetof (struct B, buf1) - 9; + else if (i == l1) + res = sizeof (a) - __builtin_offsetof (struct B, buf2) - 9; + else if (i == l1 + 1) + res = sizeof (buf3) - 5; + else if (i == l1 + 2) + res = sizeof (a) - __builtin_offsetof (struct B, buf1) - 4; + } + if (res >= 12) + { + if (__builtin_object_size (r + 12, 0) != res - 12) + abort (); + } + else if (__builtin_object_size (r + 12, 0) != 0) + abort (); +#else if (__builtin_object_size (r + 12, 0) != 4) abort (); +#endif } void @@ -358,6 +447,10 @@ test5 (size_t x) for (i = 0; i < x; ++i) p = p + 4; +#ifdef DYNAMIC_OBJECT_SIZE + if (__builtin_object_size (p, 0) != sizeof (buf) - 8 - 4 * x) + abort (); +#else /* My understanding of ISO C99 6.5.6 is that a conforming program will not end up with p equal to &buf[0] through &buf[7], i.e. calling this function with say @@ -367,6 +460,7 @@ test5 (size_t x) it would be 64 (or conservative (size_t) -1 == unknown). */ if (__builtin_object_size (p, 0) != sizeof (buf) - 8) abort (); +#endif memset (p, ' ', sizeof (buf) - 8 - 4 * 4); } @@ -381,8 +475,13 @@ test6 (size_t x) for (i = 0; i < x; ++i) p = p + 4; +#ifdef DYNAMIC_OBJECT_SIZE + if (__builtin_object_size (p, 0) != sizeof (t) - 8 - 4 * x) + abort (); +#else if (__builtin_object_size (p, 0) != sizeof (t) - 8) abort (); +#endif memset (p, ' ', sizeof (t) - 8 - 4 * 4); p = &t.buf[8]; for (i = 0; i < x; i++) @@ -390,8 +489,14 @@ test6 (size_t x) r = __builtin_memcpy (r, t.buf, i); p = r + 1; } +#ifdef DYNAMIC_OBJECT_SIZE + if (__builtin_object_size (p, 0) + != ((x > 0) ? sizeof (t.buf2) - 1 : sizeof (t) - 8)) + abort (); +#else if (__builtin_object_size (p, 0) != sizeof (t) - 8) abort (); +#endif for (i = 0; i < x; i++) { r = __builtin_mempcpy (r, t.buf, i); diff --git a/gcc/testsuite/gcc.dg/builtin-object-size-2.c b/gcc/testsuite/gcc.dg/builtin-object-size-2.c index ea11a17b6d8..c395d2e95b3 100644 --- a/gcc/testsuite/gcc.dg/builtin-object-size-2.c +++ b/gcc/testsuite/gcc.dg/builtin-object-size-2.c @@ -43,8 +43,15 @@ test1 (void *q, int x) abort (); if (__builtin_object_size (q, 1) != (size_t) -1) abort (); +#ifdef DYNAMIC_OBJECT_SIZE + if (x < 0 + ? __builtin_object_size (r, 1) != sizeof (a.a) - 9 + : __builtin_object_size (r, 1) != sizeof (a.c) - 1) + abort (); +#else if (__builtin_object_size (r, 1) != sizeof (a.c) - 1) abort (); +#endif if (x < 6) r = &w[2].a[1]; else @@ -55,8 +62,15 @@ test1 (void *q, int x) abort (); if (__builtin_object_size (&y.b, 1) != sizeof (a.b)) abort (); +#ifdef DYNAMIC_OBJECT_SIZE + if (x < 6 + ? __builtin_object_size (r, 1) != sizeof (a.a) - 1 + : __builtin_object_size (r, 1) != sizeof (a.a) - 6) + abort (); +#else if (__builtin_object_size (r, 1) != sizeof (a.a) - 1) abort (); +#endif if (x < 20) r = malloc (30); else @@ -185,6 +199,9 @@ test2 (void) struct B { char buf1[10]; char buf2[10]; } a; char *r, buf3[20]; int i; +#ifdef DYNAMIC_OBJECT_SIZE + size_t dyn_res; +#endif if (sizeof (a) != 20) return; @@ -201,8 +218,26 @@ test2 (void) else if (i == l1 + 2) r = &a.buf1[9]; } +#ifdef DYNAMIC_OBJECT_SIZE + dyn_res = sizeof (buf3); + + for (i = 0; i < 4; ++i) + { + if (i == l1 - 1) + dyn_res = sizeof (a.buf1) - 1; + else if (i == l1) + dyn_res = sizeof (a.buf2) - 7; + else if (i == l1 + 1) + dyn_res = sizeof (buf3) - 5; + else if (i == l1 + 2) + dyn_res = sizeof (a.buf1) - 9; + } + if (__builtin_object_size (r, 1) != dyn_res) + abort (); +#else if (__builtin_object_size (r, 1) != sizeof (buf3)) abort (); +#endif r = &buf3[20]; for (i = 0; i < 4; ++i) { @@ -215,13 +250,50 @@ test2 (void) else if (i == l1 + 2) r = &a.buf1[9]; } +#ifdef DYNAMIC_OBJECT_SIZE + dyn_res = sizeof (buf3) - 20; + + for (i = 0; i < 4; ++i) + { + if (i == l1 - 1) + dyn_res = sizeof (a.buf1) - 7; + else if (i == l1) + dyn_res = sizeof (a.buf2) - 7; + else if (i == l1 + 1) + dyn_res = sizeof (buf3) - 5; + else if (i == l1 + 2) + dyn_res = sizeof (a.buf1) - 9; + } + if (__builtin_object_size (r, 1) != dyn_res) + abort (); +#else if (__builtin_object_size (r, 1) != sizeof (buf3) - 5) abort (); +#endif r += 8; +#ifdef DYNAMIC_OBJECT_SIZE + if (dyn_res >= 8) + { + dyn_res -= 8; + if (__builtin_object_size (r, 1) != dyn_res) + abort (); + + if (dyn_res >= 6) + { + if (__builtin_object_size (r + 6, 1) != dyn_res - 6) + abort (); + } + else if (__builtin_object_size (r + 6, 1) != 0) + abort (); + } + else if (__builtin_object_size (r, 1) != 0) + abort (); +#else if (__builtin_object_size (r, 1) != sizeof (buf3) - 13) abort (); if (__builtin_object_size (r + 6, 1) != sizeof (buf3) - 19) abort (); +#endif } void @@ -340,8 +412,13 @@ test5 (size_t x) for (i = 0; i < x; ++i) p = p + 4; +#ifdef DYNAMIC_OBJECT_SIZE + if (__builtin_object_size (p, 1) != sizeof (t.buf) - 8 - 4 * x) + abort (); +#else if (__builtin_object_size (p, 1) != sizeof (t.buf) - 8) abort (); +#endif memset (p, ' ', sizeof (t.buf) - 8 - 4 * 4); p = &t.buf[8]; for (i = 0; i < x; i++) diff --git a/gcc/testsuite/gcc.dg/builtin-object-size-3.c b/gcc/testsuite/gcc.dg/builtin-object-size-3.c index 2d68925077e..ccdc6ef8cc8 100644 --- a/gcc/testsuite/gcc.dg/builtin-object-size-3.c +++ b/gcc/testsuite/gcc.dg/builtin-object-size-3.c @@ -71,23 +71,45 @@ test1 (void *q, int x) r = malloc (30); else r = calloc (2, 14); +#ifdef DYNAMIC_OBJECT_SIZE + if (__builtin_object_size (r, 2) != (x < 20 ? 30 : 2 * 14)) + abort (); +#else if (__builtin_object_size (r, 2) != 2 * 14) abort (); +#endif if (x < 30) r = malloc (sizeof (a)); else r = &a.a[3]; +#ifdef DYNAMIC_OBJECT_SIZE + size_t objsz = (x < 30 ? sizeof (a) + : sizeof (a) - __builtin_offsetof (struct A, a) - 3); + if (__builtin_object_size (r, 2) != objsz) + abort (); +#else if (__builtin_object_size (r, 2) != sizeof (a) - __builtin_offsetof (struct A, a) - 3) abort (); +#endif r = memcpy (r, "a", 2); +#ifdef DYNAMIC_OBJECT_SIZE + if (__builtin_object_size (r, 2) != objsz) + abort (); +#else if (__builtin_object_size (r, 2) != sizeof (a) - __builtin_offsetof (struct A, a) - 3) abort (); +#endif r = memcpy (r + 2, "b", 2) + 2; +#ifdef DYNAMIC_OBJECT_SIZE + if (__builtin_object_size (r, 2) != objsz - 4) + abort (); +#else if (__builtin_object_size (r, 2) != sizeof (a) - __builtin_offsetof (struct A, a) - 3 - 4) abort (); +#endif r = &a.a[4]; r = memset (r, 'a', 2); if (__builtin_object_size (r, 2) @@ -164,6 +186,9 @@ test2 (void) struct B { char buf1[10]; char buf2[10]; } a; char *r, buf3[20]; int i; +#ifdef DYNAMIC_OBJECT_SIZE + size_t dyn_res; +#endif if (sizeof (a) != 20) return; @@ -180,8 +205,26 @@ test2 (void) else if (i == l1 + 2) r = &a.buf1[9]; } +#ifdef DYNAMIC_OBJECT_SIZE + dyn_res = sizeof (buf3); + + for (i = 0; i < 4; ++i) + { + if (i == l1 - 1) + dyn_res = sizeof (a) - __builtin_offsetof (struct B, buf1) - 1; + else if (i == l1) + dyn_res = sizeof (a) - __builtin_offsetof (struct B, buf2) - 7; + else if (i == l1 + 1) + dyn_res = sizeof (buf3) - 5; + else if (i == l1 + 2) + dyn_res = sizeof (a) - __builtin_offsetof (struct B, buf1) - 9; + } + if (__builtin_object_size (r, 2) != dyn_res) + abort (); +#else if (__builtin_object_size (r, 2) != 3) abort (); +#endif r = &buf3[20]; for (i = 0; i < 4; ++i) { @@ -208,13 +251,44 @@ test2 (void) else if (i == l1 + 2) r = &a.buf1[4]; } +#ifdef DYNAMIC_OBJECT_SIZE + dyn_res = sizeof (buf3) - 2; + + for (i = 0; i < 4; ++i) + { + if (i == l1 - 1) + dyn_res = sizeof (a) - __builtin_offsetof (struct B, buf1) - 1; + else if (i == l1) + dyn_res = sizeof (a) - __builtin_offsetof (struct B, buf1) - 2; + else if (i == l1 + 1) + dyn_res = sizeof (buf3) - 5; + else if (i == l1 + 2) + dyn_res = sizeof (a) - __builtin_offsetof (struct B, buf1) - 4; + } + if (__builtin_object_size (r, 2) != dyn_res) + abort (); +#else if (__builtin_object_size (r, 2) != 15) abort (); +#endif r += 8; +#ifdef DYNAMIC_OBJECT_SIZE + dyn_res -= 8; + if (__builtin_object_size (r, 2) != dyn_res) + abort (); + if (dyn_res >= 6) + { + if (__builtin_object_size (r + 6, 2) != dyn_res - 6) + abort (); + } + else if (__builtin_object_size (r + 6, 2) != 0) + abort (); +#else if (__builtin_object_size (r, 2) != 7) abort (); if (__builtin_object_size (r + 6, 2) != 1) abort (); +#endif r = &buf3[18]; for (i = 0; i < 4; ++i) { @@ -227,8 +301,31 @@ test2 (void) else if (i == l1 + 2) r = &a.buf1[4]; } +#ifdef DYNAMIC_OBJECT_SIZE + dyn_res = sizeof (buf3) - 18; + + for (i = 0; i < 4; ++i) + { + if (i == l1 - 1) + dyn_res = sizeof (a) - __builtin_offsetof (struct B, buf1) - 9; + else if (i == l1) + dyn_res = sizeof (a) - __builtin_offsetof (struct B, buf2) - 9; + else if (i == l1 + 1) + dyn_res = sizeof (buf3) - 5; + else if (i == l1 + 2) + dyn_res = sizeof (a) - __builtin_offsetof (struct B, buf1) - 4; + } + if (dyn_res >= 12) + { + if (__builtin_object_size (r + 12, 2) != dyn_res - 12) + abort (); + } + else if (__builtin_object_size (r + 12, 2) != 0) + abort (); +#else if (__builtin_object_size (r + 12, 2) != 0) abort (); +#endif } void @@ -371,7 +468,11 @@ test5 (size_t x) for (i = 0; i < x; ++i) p = p + 4; +#ifdef DYNAMIC_OBJECT_SIZE + if (__builtin_object_size (p, 2) != sizeof (buf) - 8 - 4 * x) +#else if (__builtin_object_size (p, 2) != 0) +#endif abort (); memset (p, ' ', sizeof (buf) - 8 - 4 * 4); } @@ -387,7 +488,11 @@ test6 (size_t x) for (i = 0; i < x; ++i) p = p + 4; +#ifdef DYNAMIC_OBJECT_SIZE + if (__builtin_object_size (p, 2) != sizeof (t) - 8 - 4 * x) +#else if (__builtin_object_size (p, 2) != 0) +#endif abort (); memset (p, ' ', sizeof (t) - 8 - 4 * 4); p = &t.buf[8]; diff --git a/gcc/testsuite/gcc.dg/builtin-object-size-4.c b/gcc/testsuite/gcc.dg/builtin-object-size-4.c index dd7f6d7336d..002512d38ab 100644 --- a/gcc/testsuite/gcc.dg/builtin-object-size-4.c +++ b/gcc/testsuite/gcc.dg/builtin-object-size-4.c @@ -43,7 +43,12 @@ test1 (void *q, int x) abort (); if (__builtin_object_size (q, 3) != 0) abort (); +#ifdef DYNAMIC_OBJECT_SIZE + if (__builtin_object_size (r, 3) + != (x < 0 ? sizeof (a.a) - 9 : sizeof (a.c) - 1)) +#else if (__builtin_object_size (r, 3) != sizeof (a.a) - 9) +#endif abort (); if (x < 6) r = &w[2].a[1]; @@ -55,31 +60,57 @@ test1 (void *q, int x) abort (); if (__builtin_object_size (&y.b, 3) != sizeof (a.b)) abort (); +#ifdef DYNAMIC_OBJECT_SIZE + if (__builtin_object_size (r, 3) + != (x < 6 ? sizeof (w[2].a) - 1 : sizeof (a.a) - 6)) +#else if (__builtin_object_size (r, 3) != sizeof (a.a) - 6) +#endif abort (); if (x < 20) r = malloc (30); else r = calloc (2, 16); +#ifdef DYNAMIC_OBJECT_SIZE + if (__builtin_object_size (r, 3) != (x < 20 ? 30 : 2 * 16)) +#else if (__builtin_object_size (r, 3) != 30) +#endif abort (); if (x < 20) r = malloc (30); else r = calloc (2, 14); +#ifdef DYNAMIC_OBJECT_SIZE + if (__builtin_object_size (r, 3) != (x < 20 ? 30 : 2 * 14)) +#else if (__builtin_object_size (r, 3) != 2 * 14) +#endif abort (); if (x < 30) r = malloc (sizeof (a)); else r = &a.a[3]; +#ifdef DYNAMIC_OBJECT_SIZE + size_t objsz = x < 30 ? sizeof (a) : sizeof (a.a) - 3; + if (__builtin_object_size (r, 3) != objsz) +#else if (__builtin_object_size (r, 3) != sizeof (a.a) - 3) +#endif abort (); r = memcpy (r, "a", 2); +#ifdef DYNAMIC_OBJECT_SIZE + if (__builtin_object_size (r, 3) != objsz) +#else if (__builtin_object_size (r, 3) != sizeof (a.a) - 3) +#endif abort (); r = memcpy (r + 2, "b", 2) + 2; +#ifdef DYNAMIC_OBJECT_SIZE + if (__builtin_object_size (r, 3) != objsz - 4) +#else if (__builtin_object_size (r, 3) != sizeof (a.a) - 3 - 4) +#endif abort (); r = &a.a[4]; r = memset (r, 'a', 2); @@ -184,6 +215,9 @@ test2 (void) struct B { char buf1[10]; char buf2[10]; } a; char *r, buf3[20]; int i; +#ifdef DYNAMIC_OBJECT_SIZE + size_t dyn_res = 0; +#endif if (sizeof (a) != 20) return; @@ -228,13 +262,38 @@ test2 (void) else if (i == l1 + 2) r = &a.buf1[2]; } +#ifdef DYNAMIC_OBJECT_SIZE + dyn_res = sizeof (buf3) - 1; + + for (i = 0; i < 4; ++i) + { + if (i == l1 - 1) + dyn_res = sizeof (a.buf1) - 6; + else if (i == l1) + dyn_res = sizeof (a.buf2) - 4; + else if (i == l1 + 1) + dyn_res = sizeof (buf3) - 5; + else if (i == l1 + 2) + dyn_res = sizeof (a.buf1) - 2; + } + if (__builtin_object_size (r, 3) != dyn_res) + abort (); +#else if (__builtin_object_size (r, 3) != sizeof (a.buf1) - 6) abort (); +#endif r += 2; +#ifdef DYNAMIC_OBJECT_SIZE + if (__builtin_object_size (r, 3) != dyn_res - 2) + abort (); + if (__builtin_object_size (r + 1, 3) != dyn_res - 3) + abort (); +#else if (__builtin_object_size (r, 3) != sizeof (a.buf1) - 6 - 2) abort (); if (__builtin_object_size (r + 1, 3) != sizeof (a.buf1) - 6 - 3) abort (); +#endif } void @@ -353,7 +412,11 @@ test5 (size_t x) for (i = 0; i < x; ++i) p = p + 4; +#ifdef DYNAMIC_OBJECT_SIZE + if (__builtin_object_size (p, 3) != sizeof (t.buf) - 8 - 4 * x) +#else if (__builtin_object_size (p, 3) != 0) +#endif abort (); memset (p, ' ', sizeof (t.buf) - 8 - 4 * 4); p = &t.buf[8]; @@ -362,7 +425,12 @@ test5 (size_t x) r = __builtin_memcpy (r, t.buf, i); p = r + 1; } +#ifdef DYNAMIC_OBJECT_SIZE + if (__builtin_object_size (p, 3) + != (x > 0 ? sizeof (t.buf2) - 1 : sizeof (t.buf) - 8)) +#else if (__builtin_object_size (p, 3) != sizeof (t.buf) - 8) +#endif abort (); for (i = 0; i < x; i++) { diff --git a/gcc/testsuite/gcc.dg/builtin-object-size-5.c b/gcc/testsuite/gcc.dg/builtin-object-size-5.c index 7c274cdfd42..dd19747c97a 100644 --- a/gcc/testsuite/gcc.dg/builtin-object-size-5.c +++ b/gcc/testsuite/gcc.dg/builtin-object-size-5.c @@ -1,5 +1,7 @@ /* { dg-do compile { target i?86-*-linux* i?86-*-gnu* x86_64-*-linux* } } */ /* { dg-options "-O2" } */ +/* For dynamic object sizes we 'succeed' if the returned size is known for + maximum object size. */ typedef __SIZE_TYPE__ size_t; extern void abort (void); @@ -13,7 +15,11 @@ test1 (size_t x) for (i = 0; i < x; ++i) p = p + 4; +#ifdef DYNAMIC_OBJECT_SIZE + if (__builtin_object_size (p, 0) == -1) +#else if (__builtin_object_size (p, 0) != sizeof (buf) - 8) +#endif abort (); } @@ -25,10 +31,15 @@ test2 (size_t x) for (i = 0; i < x; ++i) p = p + 4; +#ifdef DYNAMIC_OBJECT_SIZE + if (__builtin_object_size (p, 1) == -1) +#else if (__builtin_object_size (p, 1) != sizeof (buf) - 8) +#endif abort (); } +#ifndef DYNAMIC_OBJECT_SIZE void test3 (size_t x) { @@ -52,5 +63,6 @@ test4 (size_t x) if (__builtin_object_size (p, 3) != 0) abort (); } +#endif /* { dg-final { scan-assembler-not "abort" } } */ diff --git a/gcc/tree-object-size.c b/gcc/tree-object-size.c index 983df24719e..33598ddc91c 100644 --- a/gcc/tree-object-size.c +++ b/gcc/tree-object-size.c @@ -35,11 +35,12 @@ along with GCC; see the file COPYING3. If not see #include "stringpool.h" #include "attribs.h" #include "builtins.h" +#include "gimplify-me.h" struct object_size_info { int object_size_type; - bitmap visited, reexamine; + bitmap visited, reexamine, phiresults; vec tempsize_objs; }; @@ -681,7 +682,7 @@ reducing_size (tree orig, tree expr, bool found_minus) simplified expression. */ static tree -estimate_size (object_size_info *osi, tree size) +estimate_size (object_size_info *osi, tree size, bitmap *visitlog = NULL) { enum tree_code code = TREE_CODE (size); int object_size_type = osi->object_size_type; @@ -691,15 +692,38 @@ estimate_size (object_size_info *osi, tree size) case SSA_NAME: { unsigned num = SSA_NAME_VERSION (size); - if (!bitmap_bit_p (osi->reexamine, num)) + if (!bitmap_bit_p (osi->reexamine, num) + || (visitlog && !bitmap_set_bit (*visitlog, num))) return size; + gimple *stmt = SSA_NAME_DEF_STMT (size); + if (stmt) + { + /* Only the PHI results are added to gimple. */ + gcc_checking_assert (gimple_code (stmt) == GIMPLE_PHI); + gcc_checking_assert (osi->object_size_type & OST_DYNAMIC); + unsigned i, num_args = gimple_phi_num_args (stmt); + + gcc_checking_assert (num_args > 0); + for (i = 0; i < num_args; i++) + { + tree rhs = gimple_phi_arg_def (stmt, i); + + if (TREE_CODE (rhs) == SSA_NAME + && bitmap_bit_p (osi->reexamine, SSA_NAME_VERSION (rhs))) + rhs = estimate_size (osi, rhs, visitlog); + + if (size_unknown_p (rhs, object_size_type)) + return size_unknown (object_size_type); + } + return size; + } return object_sizes_get (osi, osi->tempsize_objs[num]); } case MIN_EXPR: case MAX_EXPR: { - tree op0 = estimate_size (osi, TREE_OPERAND (size, 0)); - tree op1 = estimate_size (osi, TREE_OPERAND (size, 1)); + tree op0 = estimate_size (osi, TREE_OPERAND (size, 0), visitlog); + tree op1 = estimate_size (osi, TREE_OPERAND (size, 1), visitlog); if (size_unknown_p (op0, object_size_type) || size_unknown_p (op1, object_size_type)) return size_unknown (object_size_type); @@ -708,7 +732,7 @@ estimate_size (object_size_info *osi, tree size) case MINUS_EXPR: case PLUS_EXPR: { - tree ret = estimate_size (osi, TREE_OPERAND (size, 0)); + tree ret = estimate_size (osi, TREE_OPERAND (size, 0), visitlog); if (size_unknown_p (ret, object_size_type)) return size_unknown (object_size_type); @@ -821,6 +845,7 @@ resolve_dependency_loops (struct object_size_info *osi) if (TREE_CODE (szexpr) == INTEGER_CST) continue; tree sz = estimate_size (osi, szexpr); + gcc_checking_assert (TREE_CODE (sz) == INTEGER_CST); object_sizes_initialize (osi, i, sz); } @@ -829,6 +854,109 @@ resolve_dependency_loops (struct object_size_info *osi) release_ssa_name (ssa_name (i)); } +static void +get_insertion_point (struct object_size_info *osi, unsigned ssano, + gimple_stmt_iterator *gsi) +{ + unsigned varno = osi->tempsize_objs[ssano]; + gimple *stmt = SSA_NAME_DEF_STMT (ssa_name (varno)); + + switch (gimple_code (stmt)) + { + case GIMPLE_NOP: + *gsi = gsi_start_bb (single_succ (ENTRY_BLOCK_PTR_FOR_FN (cfun))); + break; + case GIMPLE_PHI: + { + gimple *size_stmt = SSA_NAME_DEF_STMT (object_sizes_get (osi, + varno)); + + for (unsigned i = 0; i < gimple_phi_num_args (stmt); i++) + { + tree rhs = gimple_phi_arg_def (size_stmt, i); + if (TREE_CODE (rhs) == SSA_NAME + && SSA_NAME_VERSION (rhs) == ssano) + { + edge e = gimple_phi_arg_edge (as_a (stmt), i); + *gsi = gsi_last_bb (e->src); + break; + } + } + break; + } + default: + *gsi = gsi_for_stmt (stmt); + } +} + +static void +gimplify_size_expressions (object_size_info *osi) +{ + int object_size_type = osi->object_size_type; + bitmap_iterator bi; + unsigned int i; + bool changed; + + /* Step 1: Propagate unknowns into expressions. */ + bitmap tempsize_free = BITMAP_ALLOC (NULL); + do + { + changed = false; + EXECUTE_IF_SET_IN_BITMAP (osi->reexamine, 0, i, bi) + { + unsigned varno = osi->tempsize_objs[i]; + + tree cur = object_sizes_get (osi, varno); + + if (size_unknown_p (cur, object_size_type)) + { + bitmap_set_bit (tempsize_free, i); + continue; + } + + tree szexpr = object_sizes_get (osi, i); + bitmap visitlog = BITMAP_ALLOC (NULL); + tree sz = estimate_size (osi, szexpr, &visitlog); + + if (size_unknown_p (sz, object_size_type)) + { + gimple *stmt = SSA_NAME_DEF_STMT (cur); + if (stmt) + { + gimple_stmt_iterator gsi = gsi_for_stmt (stmt); + remove_phi_node (&gsi, true); + } + bitmap_set_bit (tempsize_free, i); + object_sizes_initialize (osi, varno, sz); + changed = true; + } + } + bitmap_and_compl_into (osi->reexamine, tempsize_free); + } + while (changed); + + /* Expand all size expressions to put their definitions close to the objects + for whom size is being computed. */ + bitmap_and_compl_into (osi->reexamine, osi->phiresults); + EXECUTE_IF_SET_IN_BITMAP (osi->reexamine, 0, i, bi) + { + gimple_stmt_iterator gsi; + gimple_seq seq = NULL; + tree size_expr = object_sizes_get (osi, i); + + size_expr = size_binop (MODIFY_EXPR, ssa_name (i), size_expr); + force_gimple_operand (size_expr, &seq, true, NULL); + + get_insertion_point (osi, i, &gsi); + gsi_insert_seq_before (&gsi, seq, GSI_CONTINUE_LINKING); + } + + EXECUTE_IF_SET_IN_BITMAP (tempsize_free, 0, i, bi) + release_ssa_name (ssa_name (i)); + + BITMAP_FREE (tempsize_free); +} + /* Compute __builtin_object_size value for PTR and set *PSIZE to the resulting value. If the declared object is known and PDECL is nonnull, sets *PDECL to the object's DECL. OBJECT_SIZE_TYPE @@ -909,11 +1037,17 @@ compute_builtin_object_size (tree ptr, int object_size_type, osi.visited = BITMAP_ALLOC (NULL); osi.reexamine = BITMAP_ALLOC (NULL); + osi.phiresults = BITMAP_ALLOC (NULL); osi.tempsize_objs.create (0); collect_object_sizes_for (&osi, ptr); if (!bitmap_empty_p (osi.reexamine)) - resolve_dependency_loops (&osi); + { + if (dynamic) + gimplify_size_expressions (&osi); + else + resolve_dependency_loops (&osi); + } /* Debugging dumps. */ if (dump_file) @@ -936,6 +1070,7 @@ compute_builtin_object_size (tree ptr, int object_size_type, } osi.tempsize_objs.release (); + BITMAP_FREE (osi.phiresults); BITMAP_FREE (osi.reexamine); BITMAP_FREE (osi.visited); } @@ -970,6 +1105,24 @@ make_tempsize (struct object_size_info *osi, unsigned varno) return ssa; } +/* Get the temp size variable if it exists for the object with VARNO as ssa + name version and if it doesn't exist, create one. */ + +static tree +make_or_get_tempsize (struct object_size_info *osi, unsigned varno) +{ + tree ssa = object_sizes_get (osi, varno); + if (TREE_CODE (ssa) != SSA_NAME) + ssa = make_tempsize (osi, varno); + else if (dump_file) + { + fprintf (dump_file, " temp name already assigned: "); + print_generic_expr (dump_file, ssa, dump_flags); + fprintf (dump_file, "\n"); + } + return ssa; +} + /* Compute object_sizes for PTR, defined to VALUE, which is not an SSA_NAME. */ static tree @@ -1114,9 +1267,112 @@ cond_expr_object_size (struct object_size_info *osi, gimple *stmt) else elsebytes = expr_object_size (osi, else_); + if (size_unknown_p (thenbytes, object_size_type) + || size_unknown_p (elsebytes, object_size_type)) + return size_unknown (object_size_type); + + if (object_size_type & OST_DYNAMIC) + return fold_build3 (COND_EXPR, sizetype, gimple_assign_rhs1 (stmt), + thenbytes, elsebytes); + return size_binop (OST_TREE_CODE (object_size_type), thenbytes, elsebytes); } +static tree +phi_object_size (struct object_size_info *osi, gimple *stmt) +{ + int object_size_type = osi->object_size_type; + unsigned i; + + tree res = size_initval (object_size_type); + + for (i = 0; i < gimple_phi_num_args (stmt); i++) + { + tree rhs = gimple_phi_arg (stmt, i)->def; + tree phires; + + if (TREE_CODE (rhs) == SSA_NAME) + phires = ssa_object_size (osi, rhs, size_int (0)); + else + phires = expr_object_size (osi, rhs); + + res = size_binop (OST_TREE_CODE (object_size_type), res, phires); + + if (size_unknown_p (phires, object_size_type)) + break; + } + return res; +} + +static tree +phi_dynamic_object_size (struct object_size_info *osi, tree var) +{ + int object_size_type = osi->object_size_type; + unsigned int varno = SSA_NAME_VERSION (var); + gimple *stmt = SSA_NAME_DEF_STMT (var); + unsigned i, num_args = gimple_phi_num_args (stmt); + tree res; + + vec sizes; + sizes.create (0); + sizes.safe_grow (num_args); + + /* Bail out if the size of any of the PHI arguments cannot be + determined. */ + for (i = 0; i < num_args; i++) + { + tree rhs = gimple_phi_arg_def (stmt, i); + tree sz; + + if (TREE_CODE (rhs) != SSA_NAME) + sz = expr_object_size (osi, rhs); + else + sz = ssa_object_size (osi, rhs, size_int (0)); + + if (size_unknown_p (sz, object_size_type)) + break; + + sizes[i] = sz; + } + + if (i == num_args) + { + res = make_or_get_tempsize (osi, varno); + bitmap_set_bit (osi->phiresults, SSA_NAME_VERSION (res)); + object_sizes_initialize (osi, SSA_NAME_VERSION (res), res); + + gphi *phi = create_phi_node (res, 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])) + { + tree ssa = make_tempsize (osi, varno); + object_sizes_initialize (osi, SSA_NAME_VERSION (ssa), sizes[i]); + sizes[i] = ssa; + } + + add_phi_arg (phi, sizes[i], + gimple_phi_arg_edge (obj_phi, i), + gimple_phi_arg_location (obj_phi, i)); + } + + if (dump_file) + { + print_generic_expr (dump_file, var, dump_flags); + fprintf (dump_file, ": PHI Node with result: "); + print_gimple_stmt (dump_file, phi, dump_flags); + } + } + else + res = size_unknown (object_size_type); + + sizes.release (); + + return res; +} + /* Compute object sizes for VAR. For ADDR_EXPR an object size is the number of remaining bytes to the end of the object (where what is considered an object depends on @@ -1164,14 +1420,7 @@ collect_object_sizes_for (struct object_size_info *osi, tree var) print_generic_expr (dump_file, var, dump_flags); fprintf (dump_file, "\n"); } - res = object_sizes_get (osi, varno); - if (TREE_CODE (res) != SSA_NAME) - res = make_tempsize (osi, varno); - else if (dump_file) - { - fprintf (dump_file, " temp name already assigned: "); - print_generic_expr (dump_file, res, dump_flags); - } + res = make_or_get_tempsize (osi, varno); goto out; } @@ -1242,34 +1491,24 @@ collect_object_sizes_for (struct object_size_info *osi, tree var) case GIMPLE_PHI: { - unsigned i; - - res = size_initval (object_size_type); - - for (i = 0; i < gimple_phi_num_args (stmt); i++) - { - tree rhs = gimple_phi_arg (stmt, i)->def; - tree phires; - - if (object_sizes_unknown_p (object_size_type, varno)) - break; - - if (TREE_CODE (rhs) == SSA_NAME) - phires = ssa_object_size (osi, rhs, size_int (0)); - else - phires = expr_object_size (osi, rhs); - - res = size_binop (OST_TREE_CODE (object_size_type), res, phires); - - if (size_unknown_p (phires, object_size_type)) - break; - } + if (object_size_type & OST_DYNAMIC) + res = phi_dynamic_object_size (osi, var); + else + res = phi_object_size (osi, stmt); break; } default: gcc_unreachable (); } + + if ((object_size_type & OST_DYNAMIC) + && TREE_CODE (res) != INTEGER_CST && !is_gimple_variable (res)) + { + tree ssa = make_or_get_tempsize (osi, varno); + object_sizes_initialize (osi, SSA_NAME_VERSION (ssa), res); + res = ssa; + } bitmap_set_bit (computed[object_size_type], varno); out: object_sizes_set (osi, varno, res); @@ -1419,7 +1658,7 @@ object_sizes_execute (function *fun, bool early) and rather than folding the builtin to the constant if any, create a MIN_EXPR or MAX_EXPR of the __builtin_object_size call result and the computed constant. */ - if (early) + if (early && !dynamic) { early_object_sizes_execute_one (&i, call); continue; From patchwork Tue Nov 9 19:01:33 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Siddhesh Poyarekar X-Patchwork-Id: 47326 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 4A8B1385782F for ; Tue, 9 Nov 2021 19:05:00 +0000 (GMT) X-Original-To: gcc-patches@gcc.gnu.org Delivered-To: gcc-patches@gcc.gnu.org Received: from black.elm.relay.mailchannels.net (black.elm.relay.mailchannels.net [23.83.212.19]) by sourceware.org (Postfix) with ESMTPS id 9923E3857C62 for ; Tue, 9 Nov 2021 19:02:11 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.1 sourceware.org 9923E3857C62 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 93D28401D9D; Tue, 9 Nov 2021 19:02:09 +0000 (UTC) Received: from pdx1-sub0-mail-a306.dreamhost.com (100-96-18-144.trex.outbound.svc.cluster.local [100.96.18.144]) (Authenticated sender: dreamhost) by relay.mailchannels.net (Postfix) with ESMTPA id 3AF7A402371; Tue, 9 Nov 2021 19:02:06 +0000 (UTC) X-Sender-Id: dreamhost|x-authsender|siddhesh@gotplt.org Received: from pdx1-sub0-mail-a306.dreamhost.com (pop.dreamhost.com [64.90.62.162]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384) by 100.96.18.144 (trex/6.4.3); Tue, 09 Nov 2021 19:02:09 +0000 X-MC-Relay: Neutral X-MailChannels-SenderId: dreamhost|x-authsender|siddhesh@gotplt.org X-MailChannels-Auth-Id: dreamhost X-Troubled-Thread: 5aa333f9317bab2b_1636484529395_1969003793 X-MC-Loop-Signature: 1636484529395:4095114563 X-MC-Ingress-Time: 1636484529395 Received: from rhbox.redhat.com (unknown [1.186.121.127]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256) (No client certificate requested) (Authenticated sender: siddhesh@gotplt.org) by pdx1-sub0-mail-a306.dreamhost.com (Postfix) with ESMTPSA id 4HpcmD2Gwpz2n; Tue, 9 Nov 2021 11:02:03 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha1; c=relaxed/relaxed; d=gotplt.org; s=gotplt.org; t=1636484525; bh=ZdpVP14DZ7qiGsjrQp7qnTlUm+s=; h=From:To:Cc:Subject:Date:Content-Transfer-Encoding; b=DY5MbAFDjWQXEFplja/p05Yb9yBP+jCQLB34fOnZBu0WpOU8fonNxP6df2h7Ei4qz LbEDmfbcp21ZVbJ4qiHrJZNnxLIFsAyIavZZG5ih3bC6ClB8+qeJxSJh0WPbjF4T8O GIUFKa2v5/wasulknEswg4LKFvZxuKKkTcwah4Iw= From: Siddhesh Poyarekar To: gcc-patches@gcc.gnu.org Subject: [PATCH 07/10] tree-object-size: Handle function parameters Date: Wed, 10 Nov 2021 00:31:33 +0530 Message-Id: <20211109190137.1107736-8-siddhesh@gotplt.org> X-Mailer: git-send-email 2.31.1 In-Reply-To: <20211109190137.1107736-1-siddhesh@gotplt.org> References: <20211109190137.1107736-1-siddhesh@gotplt.org> MIME-Version: 1.0 X-Spam-Status: No, score=-3038.0 required=5.0 tests=BAYES_00, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, GIT_PATCH_0, RCVD_IN_BARRACUDACENTRAL, RCVD_IN_DNSWL_NONE, RCVD_IN_MSPIKE_H4, RCVD_IN_MSPIKE_WL, RCVD_IN_SBL, 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" Handle hints provided by __attribute__ ((access (...))) to compute dynamic sizes for objects. gcc/ChangeLog: * tree-object-size.c: Include tree-dfa.h. (parm_object_size): New function. (collect_object_sizes_for): Call it. gcc/testsuite/ChangeLog: * gcc.dg/builtin-dynamic-object-size-0.c (test_parmsz_simple): New function. (main): Call it. Signed-off-by: Siddhesh Poyarekar --- .../gcc.dg/builtin-dynamic-object-size-0.c | 10 ++++ gcc/tree-object-size.c | 55 ++++++++++++++++++- 2 files changed, 64 insertions(+), 1 deletion(-) 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 ddedf6a49bd..80896d54693 100644 --- a/gcc/testsuite/gcc.dg/builtin-dynamic-object-size-0.c +++ b/gcc/testsuite/gcc.dg/builtin-dynamic-object-size-0.c @@ -46,6 +46,13 @@ test_deploop (size_t sz, size_t cond) return __builtin_dynamic_object_size (bin, 0); } +size_t +__attribute__ ((access (__read_write__, 1, 2))) +test_parmsz_simple (void *obj, size_t sz) +{ + return __builtin_dynamic_object_size (obj, 0); +} + unsigned nfails = 0; #define FAIL() ({ \ @@ -64,6 +71,9 @@ main (int argc, char **argv) FAIL (); if (test_deploop (128, 129) != 32) FAIL (); + if (test_parmsz_simple (argv[0], __builtin_strlen (argv[0]) + 1) + != __builtin_strlen (argv[0]) + 1) + FAIL (); if (nfails > 0) __builtin_abort (); diff --git a/gcc/tree-object-size.c b/gcc/tree-object-size.c index 33598ddc91c..5a80432d40c 100644 --- a/gcc/tree-object-size.c +++ b/gcc/tree-object-size.c @@ -32,6 +32,7 @@ along with GCC; see the file COPYING3. If not see #include "gimple-fold.h" #include "gimple-iterator.h" #include "tree-cfg.h" +#include "tree-dfa.h" #include "stringpool.h" #include "attribs.h" #include "builtins.h" @@ -1373,6 +1374,58 @@ phi_dynamic_object_size (struct object_size_info *osi, tree var) return res; } +/* Find size of an object passed as a parameter to the function. */ + +static tree +parm_object_size (struct object_size_info *osi, tree var) +{ + int object_size_type = osi->object_size_type; + tree parm = SSA_NAME_VAR (var); + + if (dump_file) + { + fprintf (dump_file, "Object is a parameter: "); + print_generic_expr (dump_file, parm, dump_flags); + fprintf (dump_file, " which is %s a pointer type\n", + POINTER_TYPE_P (TREE_TYPE (parm)) ? "" : "not"); + } + + if (!(object_size_type & OST_DYNAMIC) || !POINTER_TYPE_P (TREE_TYPE (parm))) + return expr_object_size (osi, parm); + + /* Look for access attribute. */ + rdwr_map rdwr_idx; + + tree fndecl = cfun->decl; + const attr_access *access = get_parm_access (rdwr_idx, parm, fndecl); + tree typesize = TYPE_SIZE_UNIT (TREE_TYPE (TREE_TYPE (parm))); + + if (access && access->sizarg != UINT_MAX) + { + tree fnargs = DECL_ARGUMENTS (fndecl); + tree arg = NULL_TREE; + unsigned argpos = 0; + + /* Walk through the parameters to pick the size parameter and safely + scale it by the type size. */ + for (arg = fnargs; argpos != access->sizarg && arg; + arg = TREE_CHAIN (arg), ++argpos); + + if (arg != NULL_TREE && INTEGRAL_TYPE_P (TREE_TYPE (arg))) + { + tree sz = get_or_create_ssa_default_def (cfun, arg); + if (sz != NULL_TREE) + { + sz = fold_convert (sizetype, sz); + if (typesize) + sz = size_binop (MULT_EXPR, sz, typesize); + return sz; + } + } + } + return size_unknown (object_size_type); +} + /* Compute object sizes for VAR. For ADDR_EXPR an object size is the number of remaining bytes to the end of the object (where what is considered an object depends on @@ -1483,7 +1536,7 @@ collect_object_sizes_for (struct object_size_info *osi, tree var) case GIMPLE_NOP: if (SSA_NAME_VAR (var) && TREE_CODE (SSA_NAME_VAR (var)) == PARM_DECL) - res = expr_object_size (osi, SSA_NAME_VAR (var)); + res = parm_object_size (osi, var); else /* Uninitialized SSA names point nowhere. */ res = size_unknown (object_size_type); From patchwork Tue Nov 9 19:01:34 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Siddhesh Poyarekar X-Patchwork-Id: 47331 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 D4746385C404 for ; Tue, 9 Nov 2021 19:07:51 +0000 (GMT) X-Original-To: gcc-patches@gcc.gnu.org Delivered-To: gcc-patches@gcc.gnu.org Received: from eastern.birch.relay.mailchannels.net (eastern.birch.relay.mailchannels.net [23.83.209.55]) by sourceware.org (Postfix) with ESMTPS id 532D73857C4E for ; Tue, 9 Nov 2021 19:02:20 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.1 sourceware.org 532D73857C4E 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 B03ED342D9B; Tue, 9 Nov 2021 19:02:18 +0000 (UTC) Received: from pdx1-sub0-mail-a306.dreamhost.com (100-96-3-13.trex.outbound.svc.cluster.local [100.96.3.13]) (Authenticated sender: dreamhost) by relay.mailchannels.net (Postfix) with ESMTPA id 5D3BB342DB6; Tue, 9 Nov 2021 19:02:08 +0000 (UTC) X-Sender-Id: dreamhost|x-authsender|siddhesh@gotplt.org Received: from pdx1-sub0-mail-a306.dreamhost.com (pop.dreamhost.com [64.90.62.162]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384) by 100.96.3.13 (trex/6.4.3); Tue, 09 Nov 2021 19:02:18 +0000 X-MC-Relay: Neutral X-MailChannels-SenderId: dreamhost|x-authsender|siddhesh@gotplt.org X-MailChannels-Auth-Id: dreamhost X-Slimy-Cold: 015085ad2040de6c_1636484528639_1489592288 X-MC-Loop-Signature: 1636484528639:76505160 X-MC-Ingress-Time: 1636484528639 Received: from rhbox.redhat.com (unknown [1.186.121.127]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256) (No client certificate requested) (Authenticated sender: siddhesh@gotplt.org) by pdx1-sub0-mail-a306.dreamhost.com (Postfix) with ESMTPSA id 4HpcmG42hzz1Wf; Tue, 9 Nov 2021 11:02:06 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha1; c=relaxed/relaxed; d=gotplt.org; s=gotplt.org; t=1636484528; bh=rfCRbVhSS7iHn81UnMsY+4NkUC4=; h=From:To:Cc:Subject:Date:Content-Transfer-Encoding; b=sd44C5oxs9H0cDatAK6NCVIhOCwpl+KVS42vmU44gdsmDxDZnypsls8o7RY6WIDNO dqpMcei1jcFR6ZtcqEO3mLdh3S+pWx+gLs+HnlBQnwZcp5hWadpEnoccC8HyJ86QAy d6GNmUPp3qzTpu2lmxU3wILsOZbMpEdP5aXRHoT4= From: Siddhesh Poyarekar To: gcc-patches@gcc.gnu.org Subject: [PATCH 08/10] tree-object-size: Handle GIMPLE_CALL Date: Wed, 10 Nov 2021 00:31:34 +0530 Message-Id: <20211109190137.1107736-9-siddhesh@gotplt.org> X-Mailer: git-send-email 2.31.1 In-Reply-To: <20211109190137.1107736-1-siddhesh@gotplt.org> References: <20211109190137.1107736-1-siddhesh@gotplt.org> MIME-Version: 1.0 X-Spam-Status: No, score=-3038.0 required=5.0 tests=BAYES_00, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, GIT_PATCH_0, RCVD_IN_BARRACUDACENTRAL, RCVD_IN_DNSWL_NONE, RCVD_IN_MSPIKE_H2, RCVD_IN_SBL, 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" Handle non-constant expressions in GIMPLE_CALL arguments. Also handle alloca. gcc/ChangeLog: * tree-object-size.c (alloc_object_size): Make and return non-constant size expression. (call_object_size): Return expression or unknown based on whether dynamic object size is requested. gcc/testsuite/ChangeLog: * gcc.dg/builtin-dynamic-object-size-0.c: Add new tests. * gcc.dg/builtin-object-size-1.c (test1) [DYNAMIC_OBJECT_SIZE]: Alter expected result for dynamic object size. * gcc.dg/builtin-object-size-2.c (test1) [DYNAMIC_OBJECT_SIZE]: Likewise. * gcc.dg/builtin-object-size-3.c (test1) [DYNAMIC_OBJECT_SIZE]: Likewise. * gcc.dg/builtin-object-size-4.c (test1) [DYNAMIC_OBJECT_SIZE]: Likewise. Signed-off-by: Siddhesh Poyarekar --- .../gcc.dg/builtin-dynamic-object-size-0.c | 227 +++++++++++++++++- gcc/testsuite/gcc.dg/builtin-object-size-1.c | 7 + gcc/testsuite/gcc.dg/builtin-object-size-2.c | 14 ++ gcc/testsuite/gcc.dg/builtin-object-size-3.c | 7 + gcc/testsuite/gcc.dg/builtin-object-size-4.c | 14 ++ gcc/tree-object-size.c | 26 +- 6 files changed, 285 insertions(+), 10 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 80896d54693..4ad49a51878 100644 --- a/gcc/testsuite/gcc.dg/builtin-dynamic-object-size-0.c +++ b/gcc/testsuite/gcc.dg/builtin-dynamic-object-size-0.c @@ -4,12 +4,71 @@ typedef __SIZE_TYPE__ size_t; #define abort __builtin_abort +void * +__attribute__ ((alloc_size (1))) +__attribute__ ((__nothrow__ , __leaf__)) +__attribute__ ((noinline)) +alloc_func (size_t sz) +{ + return __builtin_malloc (sz); +} + +void * +__attribute__ ((alloc_size (1, 2))) +__attribute__ ((__nothrow__ , __leaf__)) +__attribute__ ((noinline)) +calloc_func (size_t cnt, size_t sz) +{ + return __builtin_calloc (cnt, sz); +} + +void * +__attribute__ ((noinline)) +unknown_allocator (size_t cnt, size_t sz) +{ + return __builtin_calloc (cnt, sz); +} + +size_t +__attribute__ ((noinline)) +test_unknown (size_t cnt, size_t sz) +{ + void *ret = unknown_allocator (cnt, sz); + return __builtin_dynamic_object_size (ret, 0); +} + +/* Malloc-like allocator. */ + +size_t +__attribute__ ((noinline)) +test_malloc (size_t sz) +{ + void *ret = alloc_func (sz); + return __builtin_dynamic_object_size (ret, 0); +} + +size_t +__attribute__ ((noinline)) +test_builtin_malloc (size_t sz) +{ + void *ret = __builtin_malloc (sz); + return __builtin_dynamic_object_size (ret, 0); +} + +size_t +__attribute__ ((noinline)) +test_builtin_malloc_cond (int cond) +{ + void *ret = __builtin_malloc (cond ? 32 : 64); + 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 @@ -18,6 +77,79 @@ test_builtin_malloc_condphi (int cond) 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); +} + +size_t +__attribute__ ((noinline)) +test_builtin_malloc_condphi4 (size_t sz, int cond) +{ + char *a = __builtin_malloc (sz); + char b[sz / 2]; + + return __builtin_dynamic_object_size (cond ? b : (void *) &a, 0); +} + +size_t +__attribute__ ((noinline)) +test_builtin_malloc_condphi5 (size_t sz, int cond, char *c) +{ + char *a = __builtin_malloc (sz); + + return __builtin_dynamic_object_size (cond ? c : (void *) &a, 0); +} + +/* Calloc-like allocator. */ + +size_t +__attribute__ ((noinline)) +test_calloc (size_t cnt, size_t sz) +{ + void *ret = calloc_func (cnt, sz); + return __builtin_dynamic_object_size (ret, 0); +} + +size_t +__attribute__ ((noinline)) +test_builtin_calloc (size_t cnt, size_t sz) +{ + void *ret = __builtin_calloc (cnt, sz); + return __builtin_dynamic_object_size (ret, 0); +} + +size_t +__attribute__ ((noinline)) +test_builtin_calloc_cond (int cond1, int cond2) +{ + void *ret = __builtin_calloc (cond1 ? 32 : 64, cond2 ? 1024 : 16); + return __builtin_dynamic_object_size (ret, 0); +} + size_t __attribute__ ((noinline)) test_builtin_calloc_condphi (size_t cnt, size_t sz, int cond) @@ -33,6 +165,47 @@ test_builtin_calloc_condphi (size_t cnt, size_t sz, int cond) return __builtin_dynamic_object_size (cond ? ch : (void *) &bin, 0); } +/* Passthrough functions. */ + +size_t +__attribute__ ((noinline)) +test_passthrough (size_t sz, char *in) +{ + char *bin = __builtin_malloc (sz); + char *dest = __builtin_memcpy (bin, in, sz); + + return __builtin_dynamic_object_size (dest, 0); +} + +size_t +__attribute__ ((noinline)) +test_passthrough_nonssa (char *in) +{ + char bin[__builtin_strlen (in) + 1]; + char *dest = __builtin_memcpy (bin, in, __builtin_strlen (in) + 1); + + return __builtin_dynamic_object_size (dest, 0); +} + +/* Variable length arrays. */ +size_t +__attribute__ ((noinline)) +test_dynarray (size_t sz) +{ + char bin[sz]; + + return __builtin_dynamic_object_size (bin, 0); +} + +size_t +__attribute__ ((noinline)) +test_dynarray_cond (int cond) +{ + char bin[cond ? 8 : 16]; + + return __builtin_dynamic_object_size (bin, 0); +} + size_t __attribute__ ((noinline)) test_deploop (size_t sz, size_t cond) @@ -41,7 +214,7 @@ test_deploop (size_t sz, size_t cond) for (size_t i = 0; i < sz; i++) if (i == cond) - bin = __builtin_alloca (64); + bin = __builtin_alloca (sz); return __builtin_dynamic_object_size (bin, 0); } @@ -63,12 +236,62 @@ unsigned nfails = 0; int main (int argc, char **argv) { + size_t outsz = test_unknown (32, 42); + if (outsz != -1 && outsz != 32) + FAIL (); + if (test_malloc (2048) != 2048) + FAIL (); + if (test_builtin_malloc (2048) != 2048) + FAIL (); + if (test_builtin_malloc_cond (1) != 32) + 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_builtin_malloc_condphi4 (128, 1) != 64) + FAIL (); + if (test_builtin_malloc_condphi4 (128, 0) != sizeof (void *)) + FAIL (); + if (test_builtin_malloc_condphi5 (128, 0, argv[0]) != -1) + FAIL (); + if (test_calloc (2048, 4) != 2048 * 4) + FAIL (); + if (test_builtin_calloc (2048, 8) != 2048 * 8) + FAIL (); + if (test_builtin_calloc_cond (0, 0) != 64 * 16) + 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 (); + if (test_passthrough_nonssa (argv[0]) != __builtin_strlen (argv[0]) + 1) + FAIL (); + if (test_dynarray (__builtin_strlen (argv[0])) != __builtin_strlen (argv[0])) + FAIL (); + if (test_dynarray_cond (0) != 16) + FAIL (); + if (test_dynarray_cond (1) != 8) + FAIL (); + if (test_deploop (128, 4) != 128) + FAIL (); if (test_deploop (128, 129) != 32) FAIL (); if (test_parmsz_simple (argv[0], __builtin_strlen (argv[0]) + 1) diff --git a/gcc/testsuite/gcc.dg/builtin-object-size-1.c b/gcc/testsuite/gcc.dg/builtin-object-size-1.c index 76df4c96271..606141f9405 100644 --- a/gcc/testsuite/gcc.dg/builtin-object-size-1.c +++ b/gcc/testsuite/gcc.dg/builtin-object-size-1.c @@ -135,10 +135,17 @@ test1 (void *q, int x) abort (); if (__builtin_object_size (&extb[5], 0) != sizeof (extb) - 5) abort (); +#ifdef DYNAMIC_OBJECT_SIZE + if (__builtin_object_size (var, 0) != x + 10) + abort (); + if (__builtin_object_size (var + 10, 0) != x) + abort (); +#else if (__builtin_object_size (var, 0) != (size_t) -1) abort (); if (__builtin_object_size (var + 10, 0) != (size_t) -1) abort (); +#endif if (__builtin_object_size (&var[5], 0) != (size_t) -1) abort (); if (__builtin_object_size (zerol, 0) != 0) diff --git a/gcc/testsuite/gcc.dg/builtin-object-size-2.c b/gcc/testsuite/gcc.dg/builtin-object-size-2.c index c395d2e95b3..57fd17d5a45 100644 --- a/gcc/testsuite/gcc.dg/builtin-object-size-2.c +++ b/gcc/testsuite/gcc.dg/builtin-object-size-2.c @@ -137,16 +137,30 @@ test1 (void *q, int x) abort (); if (__builtin_object_size (&extc[5].c[3], 1) != (size_t) -1) abort (); +#ifdef DYNAMIC_OBJECT_SIZE + if (__builtin_object_size (var, 1) != x + 10) + abort (); + if (__builtin_object_size (var + 10, 1) != x) + abort (); +#else if (__builtin_object_size (var, 1) != (size_t) -1) abort (); if (__builtin_object_size (var + 10, 1) != (size_t) -1) abort (); +#endif if (__builtin_object_size (&var[5], 1) != (size_t) -1) abort (); +#ifdef DYNAMIC_OBJECT_SIZE + if (__builtin_object_size (vara, 1) != (x + 10) * sizeof (struct A)) + abort (); + if (__builtin_object_size (vara + 10, 1) != x * sizeof (struct A)) + abort (); +#else if (__builtin_object_size (vara, 1) != (size_t) -1) abort (); if (__builtin_object_size (vara + 10, 1) != (size_t) -1) abort (); +#endif if (__builtin_object_size (&vara[5], 1) != (size_t) -1) abort (); if (__builtin_object_size (&vara[0].a, 1) != sizeof (vara[0].a)) diff --git a/gcc/testsuite/gcc.dg/builtin-object-size-3.c b/gcc/testsuite/gcc.dg/builtin-object-size-3.c index ccdc6ef8cc8..5b323ca3527 100644 --- a/gcc/testsuite/gcc.dg/builtin-object-size-3.c +++ b/gcc/testsuite/gcc.dg/builtin-object-size-3.c @@ -140,10 +140,17 @@ test1 (void *q, int x) abort (); if (__builtin_object_size (&extb[5], 2) != sizeof (extb) - 5) abort (); +#ifdef DYNAMIC_OBJECT_SIZE + if (__builtin_object_size (var, 2) != x + 10) + abort (); + if (__builtin_object_size (var + 10, 2) != x) + abort (); +#else if (__builtin_object_size (var, 2) != 0) abort (); if (__builtin_object_size (var + 10, 2) != 0) abort (); +#endif if (__builtin_object_size (&var[5], 2) != 0) abort (); if (__builtin_object_size (zerol, 2) != 0) diff --git a/gcc/testsuite/gcc.dg/builtin-object-size-4.c b/gcc/testsuite/gcc.dg/builtin-object-size-4.c index 002512d38ab..2d222301eff 100644 --- a/gcc/testsuite/gcc.dg/builtin-object-size-4.c +++ b/gcc/testsuite/gcc.dg/builtin-object-size-4.c @@ -150,16 +150,30 @@ test1 (void *q, int x) abort (); if (__builtin_object_size (&extc[5].c[3], 3) != 0) abort (); +#ifdef DYNAMIC_OBJECT_SIZE + if (__builtin_object_size (var, 3) != x + 10) + abort (); + if (__builtin_object_size (var + 10, 3) != x) + abort (); +#else if (__builtin_object_size (var, 3) != 0) abort (); if (__builtin_object_size (var + 10, 3) != 0) abort (); +#endif if (__builtin_object_size (&var[5], 3) != 0) abort (); +#ifdef DYNAMIC_OBJECT_SIZE + if (__builtin_object_size (vara, 3) != (x + 10) * sizeof (struct A)) + abort (); + if (__builtin_object_size (vara + 10, 3) != x * sizeof (struct A)) + abort (); +#else if (__builtin_object_size (vara, 3) != 0) abort (); if (__builtin_object_size (vara + 10, 3) != 0) abort (); +#endif if (__builtin_object_size (&vara[5], 3) != 0) abort (); if (__builtin_object_size (&vara[0].a, 3) != sizeof (vara[0].a)) diff --git a/gcc/tree-object-size.c b/gcc/tree-object-size.c index 5a80432d40c..d5b0c8226f0 100644 --- a/gcc/tree-object-size.c +++ b/gcc/tree-object-size.c @@ -584,7 +584,8 @@ alloc_object_size (const gcall *call, int object_size_type) gcc_assert (is_gimple_call (call)); tree calltype; - if (tree callfn = gimple_call_fndecl (call)) + tree callfn = gimple_call_fndecl (call); + if (callfn) calltype = TREE_TYPE (callfn); else calltype = gimple_call_fntype (call); @@ -604,12 +605,13 @@ alloc_object_size (const gcall *call, int object_size_type) if (TREE_CHAIN (p)) arg2 = TREE_INT_CST_LOW (TREE_VALUE (TREE_CHAIN (p)))-1; } + else if (gimple_call_builtin_p (call, BUILT_IN_NORMAL) + && callfn && ALLOCA_FUNCTION_CODE_P (DECL_FUNCTION_CODE (callfn))) + arg1 = 0; - if (arg1 < 0 || arg1 >= (int)gimple_call_num_args (call) - || TREE_CODE (gimple_call_arg (call, arg1)) != INTEGER_CST - || (arg2 >= 0 - && (arg2 >= (int)gimple_call_num_args (call) - || TREE_CODE (gimple_call_arg (call, arg2)) != INTEGER_CST))) + /* Non-const arguments are OK here, let the caller handle constness. */ + if (arg1 < 0 || arg1 >= (int) gimple_call_num_args (call) + || arg2 >= (int) gimple_call_num_args (call)) return size_unknown (object_size_type); tree bytes = NULL_TREE; @@ -620,7 +622,10 @@ alloc_object_size (const gcall *call, int object_size_type) else if (arg1 >= 0) bytes = fold_convert (sizetype, gimple_call_arg (call, arg1)); - return bytes; + if (bytes) + return STRIP_NOPS (bytes); + + return size_unknown (object_size_type); } @@ -1156,7 +1161,12 @@ call_object_size (struct object_size_info *osi, gcall *call) gcc_assert (is_gimple_call (call)); - return alloc_object_size (call, object_size_type); + tree bytes = alloc_object_size (call, object_size_type); + + if ((object_size_type & OST_DYNAMIC) || TREE_CODE (bytes) == INTEGER_CST) + return bytes; + + return size_unknown (object_size_type); } From patchwork Tue Nov 9 19:01:35 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Siddhesh Poyarekar X-Patchwork-Id: 47330 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 606B7385E00D for ; Tue, 9 Nov 2021 19:07:15 +0000 (GMT) X-Original-To: gcc-patches@gcc.gnu.org Delivered-To: gcc-patches@gcc.gnu.org Received: from eggs.gnu.org (eggs.gnu.org [209.51.188.92]) by sourceware.org (Postfix) with ESMTPS id 4E1CD3858020 for ; Tue, 9 Nov 2021 19:02:20 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.1 sourceware.org 4E1CD3858020 Authentication-Results: sourceware.org; dmarc=none (p=none dis=none) header.from=gotplt.org Authentication-Results: sourceware.org; spf=fail smtp.mailfrom=gotplt.org Received: from antelope.elm.relay.mailchannels.net ([23.83.212.4]:62989) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1mkWNs-0008Hq-3k for gcc-patches@gcc.gnu.org; Tue, 09 Nov 2021 14:02:19 -0500 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 CDAF0402131; Tue, 9 Nov 2021 19:02:11 +0000 (UTC) Received: from pdx1-sub0-mail-a306.dreamhost.com (100-96-133-198.trex.outbound.svc.cluster.local [100.96.133.198]) (Authenticated sender: dreamhost) by relay.mailchannels.net (Postfix) with ESMTPA id 11FFD4022F1; Tue, 9 Nov 2021 19:02:11 +0000 (UTC) X-Sender-Id: dreamhost|x-authsender|siddhesh@gotplt.org Received: from pdx1-sub0-mail-a306.dreamhost.com (pop.dreamhost.com [64.90.62.162]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384) by 100.96.133.198 (trex/6.4.3); Tue, 09 Nov 2021 19:02:11 +0000 X-MC-Relay: Neutral X-MailChannels-SenderId: dreamhost|x-authsender|siddhesh@gotplt.org X-MailChannels-Auth-Id: dreamhost X-White-Shoe: 606e60af18309de0_1636484531420_1323757841 X-MC-Loop-Signature: 1636484531420:1065136300 X-MC-Ingress-Time: 1636484531419 Received: from rhbox.redhat.com (unknown [1.186.121.127]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256) (No client certificate requested) (Authenticated sender: siddhesh@gotplt.org) by pdx1-sub0-mail-a306.dreamhost.com (Postfix) with ESMTPSA id 4HpcmK0rcnz1Wh; Tue, 9 Nov 2021 11:02:08 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha1; c=relaxed/relaxed; d=gotplt.org; s=gotplt.org; t=1636484530; bh=fgUBvOUoKj0BqtqVAxrz+qf6sk4=; h=From:To:Cc:Subject:Date:Content-Transfer-Encoding; b=EHrw4rwOj8/B2g5SyhdZg+w5jx3stioFcXzswrUWKMKrwM4szLDPW4a4nZtuip1S7 bm5EC/pnYPRuH/n17fFtBNKAAyXxxWmDcvWOBIcT2QMKGGvSAo7kIi4WiuT44oicuK HLzJZCaEDZ8AtfyZvmcbA1+Crpxb3t9087Mrg6sw= From: Siddhesh Poyarekar To: gcc-patches@gcc.gnu.org Subject: [PATCH 09/10] tree-object-size: Dynamic sizes for ADDR_EXPR Date: Wed, 10 Nov 2021 00:31:35 +0530 Message-Id: <20211109190137.1107736-10-siddhesh@gotplt.org> X-Mailer: git-send-email 2.31.1 In-Reply-To: <20211109190137.1107736-1-siddhesh@gotplt.org> References: <20211109190137.1107736-1-siddhesh@gotplt.org> MIME-Version: 1.0 Received-SPF: pass client-ip=23.83.212.4; envelope-from=siddhesh@gotplt.org; helo=antelope.elm.relay.mailchannels.net X-Spam_score_int: -19 X-Spam_score: -2.0 X-Spam_bar: -- X-Spam_report: (-2.0 / 5.0 requ) BAYES_00=-1.9, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, RCVD_IN_DNSWL_NONE=-0.0001, RCVD_IN_MSPIKE_H2=-0.001, RCVD_IN_SBL=0.141, SPF_HELO_NONE=0.001, SPF_PASS=-0.001 autolearn=no autolearn_force=no X-Spam_action: no action X-Spam-Status: No, score=-3038.5 required=5.0 tests=BAYES_00, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, GIT_PATCH_0, RCVD_IN_BARRACUDACENTRAL, RCVD_IN_SBL, SPF_FAIL, SPF_HELO_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" Allow dynamic expressions from ADDR_EXPR for __builtin_dynamic_object_size. Offsets in objects still need to be constant for now because offset computation need more validation to support, e.g. negative offsets with dynamic sizes. gcc/ChangeLog: * tree-object-size.c (size_known_p): New function. (addr_object_size): Build dynamic expressions for object sizes. (estimate_size): Limit PLUS_EXPR rewriting to static object sizes. (call_object_size): Call size_known_p. gcc/testsuite/ChangeLog: * gcc.dg/builtin-dynamic-object-size-0.c: Add new tests. * gcc.dg/builtin-object-size-1.c (test1) [DYNAMIC_OBJECT_SIZE]: Adjust expected output for dynamic object sizes. * gcc.dg/builtin-object-size-2.c (test1) [DYNAMIC_OBJECT_SIZE]: Likewise. * gcc.dg/builtin-object-size-3.c (test1) [DYNAMIC_OBJECT_SIZE]: Likewise. * gcc.dg/builtin-object-size-4.c (test1) [DYNAMIC_OBJECT_SIZE]: Likewise. Signed-off-by: Siddhesh Poyarekar --- .../gcc.dg/builtin-dynamic-object-size-0.c | 71 ++++++++++++++ gcc/testsuite/gcc.dg/builtin-object-size-1.c | 30 +++++- gcc/testsuite/gcc.dg/builtin-object-size-2.c | 43 +++++++-- gcc/testsuite/gcc.dg/builtin-object-size-3.c | 25 ++++- gcc/testsuite/gcc.dg/builtin-object-size-4.c | 17 ++-- gcc/tree-object-size.c | 93 +++++++++++-------- 6 files changed, 221 insertions(+), 58 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 4ad49a51878..a1db63b2d45 100644 --- a/gcc/testsuite/gcc.dg/builtin-dynamic-object-size-0.c +++ b/gcc/testsuite/gcc.dg/builtin-dynamic-object-size-0.c @@ -219,6 +219,60 @@ test_deploop (size_t sz, size_t cond) return __builtin_dynamic_object_size (bin, 0); } +/* Address expressions. */ + +struct dynarray_struct +{ + long a; + char c[16]; + int b; +}; + +size_t +__attribute__ ((noinline)) +test_dynarray_struct (size_t sz, size_t off) +{ + struct dynarray_struct bin[sz]; + + return __builtin_dynamic_object_size (&bin[off].c, 0); +} + +size_t +__attribute__ ((noinline)) +test_dynarray_struct_subobj (size_t sz, size_t off) +{ + struct dynarray_struct bin[sz]; + + return __builtin_dynamic_object_size (&bin[off].c[4], 1); +} + +size_t +__attribute__ ((noinline)) +test_dynarray_struct_subobj2 (size_t sz, size_t off, size_t *objsz) +{ + struct dynarray_struct2 + { + long a; + int b; + char c[sz]; + }; + + struct dynarray_struct2 bin; + + *objsz = sizeof (bin); + + return __builtin_dynamic_object_size (&bin.c[off], 1); +} + +size_t +__attribute__ ((noinline)) +test_substring (size_t sz, size_t off) +{ + char str[sz]; + + return __builtin_dynamic_object_size (&str[off], 0); +} + size_t __attribute__ ((access (__read_write__, 1, 2))) test_parmsz_simple (void *obj, size_t sz) @@ -286,6 +340,23 @@ main (int argc, char **argv) FAIL (); if (test_dynarray (__builtin_strlen (argv[0])) != __builtin_strlen (argv[0])) FAIL (); + if (test_dynarray_struct (42, 4) != + ((42 - 4) * sizeof (struct dynarray_struct) + - __builtin_offsetof (struct dynarray_struct, c))) + FAIL (); + if (test_dynarray_struct (42, 48) != 0) + FAIL (); + if (test_substring (128, 4) != 128 - 4) + FAIL (); + if (test_substring (128, 142) != 0) + FAIL (); + if (test_dynarray_struct_subobj (42, 4) != 16 - 4) + FAIL (); + if (test_dynarray_struct_subobj (42, 48) != 0) + FAIL (); + size_t objsz = 0; + if (test_dynarray_struct_subobj2 (42, 4, &objsz) != objsz - 4 - 12) + FAIL (); if (test_dynarray_cond (0) != 16) FAIL (); if (test_dynarray_cond (1) != 8) diff --git a/gcc/testsuite/gcc.dg/builtin-object-size-1.c b/gcc/testsuite/gcc.dg/builtin-object-size-1.c index 606141f9405..ba5a34c1f8e 100644 --- a/gcc/testsuite/gcc.dg/builtin-object-size-1.c +++ b/gcc/testsuite/gcc.dg/builtin-object-size-1.c @@ -81,30 +81,56 @@ test1 (void *q, int x) r = malloc (30); else r = calloc (2, 16); +#ifdef DYNAMIC_OBJECT_SIZE + if (__builtin_object_size (r, 0) != (x < 20 ? 30 : 2 * 16)) + abort (); +#else /* We may duplicate this test onto the two exit paths. On one path the size will be 32, the other it will be 30. If we don't duplicate this test, then the size will be 32. */ if (__builtin_object_size (r, 0) != 2 * 16 && __builtin_object_size (r, 0) != 30) abort (); +#endif if (x < 20) r = malloc (30); else r = calloc (2, 14); +#ifdef DYNAMIC_OBJECT_SIZE + if (__builtin_object_size (r, 0) != (x < 20 ? 30 : 2 * 14)) + abort (); +#else if (__builtin_object_size (r, 0) != 30) abort (); +#endif if (x < 30) r = malloc (sizeof (a)); else r = &a.a[3]; +#ifdef DYNAMIC_OBJECT_SIZE + if (__builtin_object_size (r, 0) != (x < 30 ? sizeof (a) : sizeof (a) - 3)) + abort (); +#else if (__builtin_object_size (r, 0) != sizeof (a)) abort (); +#endif r = memcpy (r, "a", 2); +#ifdef DYNAMIC_OBJECT_SIZE + if (__builtin_object_size (r, 0) != (x < 30 ? sizeof (a) : sizeof (a) - 3)) + abort (); +#else if (__builtin_object_size (r, 0) != sizeof (a)) abort (); +#endif r = memcpy (r + 2, "b", 2) + 2; +#ifdef DYNAMIC_OBJECT_SIZE + if (__builtin_object_size (r, 0) + != (x < 30 ? sizeof (a) - 4 : sizeof (a) - 7)) + abort (); +#else if (__builtin_object_size (r, 0) != sizeof (a) - 4) abort (); +#endif r = &a.a[4]; r = memset (r, 'a', 2); if (__builtin_object_size (r, 0) @@ -140,14 +166,16 @@ test1 (void *q, int x) abort (); if (__builtin_object_size (var + 10, 0) != x) abort (); + if (__builtin_object_size (&var[5], 0) != x + 5) + abort (); #else if (__builtin_object_size (var, 0) != (size_t) -1) abort (); if (__builtin_object_size (var + 10, 0) != (size_t) -1) abort (); -#endif if (__builtin_object_size (&var[5], 0) != (size_t) -1) abort (); +#endif if (__builtin_object_size (zerol, 0) != 0) abort (); if (__builtin_object_size (&zerol, 0) != 0) diff --git a/gcc/testsuite/gcc.dg/builtin-object-size-2.c b/gcc/testsuite/gcc.dg/builtin-object-size-2.c index 57fd17d5a45..4af30e8c580 100644 --- a/gcc/testsuite/gcc.dg/builtin-object-size-2.c +++ b/gcc/testsuite/gcc.dg/builtin-object-size-2.c @@ -75,30 +75,56 @@ test1 (void *q, int x) r = malloc (30); else r = calloc (2, 16); +#ifdef DYNAMIC_OBJECT_SIZE + if (__builtin_object_size (r, 1) != (x < 20 ? 30 : 2 * 16)) + abort (); +#else /* We may duplicate this test onto the two exit paths. On one path the size will be 32, the other it will be 30. If we don't duplicate this test, then the size will be 32. */ if (__builtin_object_size (r, 1) != 2 * 16 && __builtin_object_size (r, 1) != 30) abort (); +#endif if (x < 20) r = malloc (30); else r = calloc (2, 14); +#ifdef DYNAMIC_OBJECT_SIZE + if (__builtin_object_size (r, 1) != (x < 20 ? 30 : 2 * 14)) + abort (); +#else if (__builtin_object_size (r, 1) != 30) abort (); +#endif if (x < 30) r = malloc (sizeof (a)); else r = &a.a[3]; +#ifdef DYNAMIC_OBJECT_SIZE + if (__builtin_object_size (r, 1) != (x < 30 ? sizeof (a) : sizeof (a) - 3)) + abort (); +#else if (__builtin_object_size (r, 1) != sizeof (a)) abort (); +#endif r = memcpy (r, "a", 2); +#ifdef DYNAMIC_OBJECT_SIZE + if (__builtin_object_size (r, 1) != (x < 30 ? sizeof (a) : sizeof (a) - 3)) + abort (); +#else if (__builtin_object_size (r, 1) != sizeof (a)) abort (); +#endif r = memcpy (r + 2, "b", 2) + 2; +#ifdef DYNAMIC_OBJECT_SIZE + if (__builtin_object_size (r, 0) + != (x < 30 ? sizeof (a) - 4 : sizeof (a) - 7)) + abort (); +#else if (__builtin_object_size (r, 1) != sizeof (a) - 4) abort (); +#endif r = &a.a[4]; r = memset (r, 'a', 2); if (__builtin_object_size (r, 1) != sizeof (a.a) - 4) @@ -142,27 +168,28 @@ test1 (void *q, int x) abort (); if (__builtin_object_size (var + 10, 1) != x) abort (); + if (__builtin_object_size (&var[5], 1) != x + 5) + abort (); + if (__builtin_object_size (vara, 1) != (x + 10) * sizeof (struct A)) + abort (); + if (__builtin_object_size (vara + 10, 1) != x * sizeof (struct A)) + abort (); + if (__builtin_object_size (&vara[5], 1) != (x + 5) * sizeof (struct A)) + abort (); #else if (__builtin_object_size (var, 1) != (size_t) -1) abort (); if (__builtin_object_size (var + 10, 1) != (size_t) -1) abort (); -#endif if (__builtin_object_size (&var[5], 1) != (size_t) -1) abort (); -#ifdef DYNAMIC_OBJECT_SIZE - if (__builtin_object_size (vara, 1) != (x + 10) * sizeof (struct A)) - abort (); - if (__builtin_object_size (vara + 10, 1) != x * sizeof (struct A)) - abort (); -#else if (__builtin_object_size (vara, 1) != (size_t) -1) abort (); if (__builtin_object_size (vara + 10, 1) != (size_t) -1) abort (); -#endif if (__builtin_object_size (&vara[5], 1) != (size_t) -1) abort (); +#endif if (__builtin_object_size (&vara[0].a, 1) != sizeof (vara[0].a)) abort (); if (__builtin_object_size (&vara[10].a[0], 1) != sizeof (vara[0].a)) diff --git a/gcc/testsuite/gcc.dg/builtin-object-size-3.c b/gcc/testsuite/gcc.dg/builtin-object-size-3.c index 5b323ca3527..ce4418e785b 100644 --- a/gcc/testsuite/gcc.dg/builtin-object-size-3.c +++ b/gcc/testsuite/gcc.dg/builtin-object-size-3.c @@ -42,9 +42,17 @@ test1 (void *q, int x) abort (); if (__builtin_object_size (q, 2) != 0) abort (); +#ifdef DYNAMIC_OBJECT_SIZE + if (__builtin_object_size (r, 2) + != (x < 0 + ? sizeof (a) - __builtin_offsetof (struct A, a) - 9 + : sizeof (a) - __builtin_offsetof (struct A, c) - 1)) + abort (); +#else if (__builtin_object_size (r, 2) != sizeof (a) - __builtin_offsetof (struct A, c) - 1) abort (); +#endif if (x < 6) r = &w[2].a[1]; else @@ -58,15 +66,28 @@ test1 (void *q, int x) if (__builtin_object_size (&y.b, 2) != sizeof (a) - __builtin_offsetof (struct A, b)) abort (); +#ifdef DYNAMIC_OBJECT_SIZE + if (__builtin_object_size (r, 2) + != (x < 6 + ? 2 * sizeof (w[0]) - __builtin_offsetof (struct A, a) - 1 + : sizeof (a) - __builtin_offsetof (struct A, a) - 6)) + abort (); +#else if (__builtin_object_size (r, 2) != sizeof (a) - __builtin_offsetof (struct A, a) - 6) abort (); +#endif if (x < 20) r = malloc (30); else r = calloc (2, 16); +#ifdef DYNAMIC_OBJECT_SIZE + if (__builtin_object_size (r, 2) != (x < 20 ? 30 : 2 * 16)) + abort (); +#else if (__builtin_object_size (r, 2) != 30) abort (); +#endif if (x < 20) r = malloc (30); else @@ -145,14 +166,16 @@ test1 (void *q, int x) abort (); if (__builtin_object_size (var + 10, 2) != x) abort (); + if (__builtin_object_size (&var[5], 2) != x + 5) + abort (); #else if (__builtin_object_size (var, 2) != 0) abort (); if (__builtin_object_size (var + 10, 2) != 0) abort (); -#endif if (__builtin_object_size (&var[5], 2) != 0) abort (); +#endif if (__builtin_object_size (zerol, 2) != 0) abort (); if (__builtin_object_size (&zerol, 2) != 0) diff --git a/gcc/testsuite/gcc.dg/builtin-object-size-4.c b/gcc/testsuite/gcc.dg/builtin-object-size-4.c index 2d222301eff..81e0255dcc4 100644 --- a/gcc/testsuite/gcc.dg/builtin-object-size-4.c +++ b/gcc/testsuite/gcc.dg/builtin-object-size-4.c @@ -155,27 +155,28 @@ test1 (void *q, int x) abort (); if (__builtin_object_size (var + 10, 3) != x) abort (); + if (__builtin_object_size (&var[5], 3) != x + 5) + abort (); + if (__builtin_object_size (vara, 3) != (x + 10) * sizeof (struct A)) + abort (); + if (__builtin_object_size (vara + 10, 3) != x * sizeof (struct A)) + abort (); + if (__builtin_object_size (&vara[5], 3) != (x + 5) * sizeof (struct A)) + abort (); #else if (__builtin_object_size (var, 3) != 0) abort (); if (__builtin_object_size (var + 10, 3) != 0) abort (); -#endif if (__builtin_object_size (&var[5], 3) != 0) abort (); -#ifdef DYNAMIC_OBJECT_SIZE - if (__builtin_object_size (vara, 3) != (x + 10) * sizeof (struct A)) - abort (); - if (__builtin_object_size (vara + 10, 3) != x * sizeof (struct A)) - abort (); -#else if (__builtin_object_size (vara, 3) != 0) abort (); if (__builtin_object_size (vara + 10, 3) != 0) abort (); -#endif if (__builtin_object_size (&vara[5], 3) != 0) abort (); +#endif if (__builtin_object_size (&vara[0].a, 3) != sizeof (vara[0].a)) abort (); if (__builtin_object_size (&vara[10].a[0], 3) != sizeof (vara[0].a)) diff --git a/gcc/tree-object-size.c b/gcc/tree-object-size.c index d5b0c8226f0..865fc3feea5 100644 --- a/gcc/tree-object-size.c +++ b/gcc/tree-object-size.c @@ -123,6 +123,16 @@ size_unknown_p (tree val, int object_size_type) && tree_to_uhwi (val) == unknown (object_size_type)); } +/* Return true if VAL is represents a known size for OBJECT_SIZE_TYPE. */ + +static inline bool +size_known_p (tree val, int object_size_type) +{ + return (!size_unknown_p (val, object_size_type) + && ((object_size_type & OST_DYNAMIC) + || TREE_CODE (val) == INTEGER_CST)); +} + /* Return a tree with initial value for OBJECT_SIZE_TYPE. */ static inline tree @@ -391,16 +401,15 @@ addr_object_size (struct object_size_info *osi, const_tree ptr, if (!size_unknown_p (sz, object_size_type)) { tree offset = TREE_OPERAND (pt_var, 1); - if (TREE_CODE (offset) != INTEGER_CST - || TREE_CODE (sz) != INTEGER_CST) + if (TREE_CODE (offset) != INTEGER_CST) sz = size_unknown (object_size_type); else sz = size_for_offset (sz, offset); } if (!size_unknown_p (sz, object_size_type) - && TREE_CODE (sz) == INTEGER_CST - && compare_tree_int (sz, offset_limit) < 0) + && (TREE_CODE (sz) != INTEGER_CST + || compare_tree_int (sz, offset_limit) < 0)) pt_var_size = sz; } else if (DECL_P (pt_var)) @@ -416,8 +425,9 @@ addr_object_size (struct object_size_info *osi, const_tree ptr, if (pt_var_size) { - /* Validate the size determined above. */ - if (compare_tree_int (pt_var_size, offset_limit) >= 0) + /* Validate the size determined above if it is a constant. */ + if (TREE_CODE (pt_var_size) == INTEGER_CST + && compare_tree_int (pt_var_size, offset_limit) >= 0) return false; } @@ -441,7 +451,7 @@ addr_object_size (struct object_size_info *osi, const_tree ptr, var = TREE_OPERAND (var, 0); if (! TYPE_SIZE_UNIT (TREE_TYPE (var)) || ! tree_fits_uhwi_p (TYPE_SIZE_UNIT (TREE_TYPE (var))) - || (pt_var_size + || (pt_var_size && TREE_CODE (pt_var_size) == INTEGER_CST && tree_int_cst_lt (pt_var_size, TYPE_SIZE_UNIT (TREE_TYPE (var))))) var = pt_var; @@ -455,17 +465,11 @@ addr_object_size (struct object_size_info *osi, const_tree ptr, switch (TREE_CODE (v)) { case ARRAY_REF: - if (TYPE_SIZE_UNIT (TREE_TYPE (TREE_OPERAND (v, 0))) - && TREE_CODE (TREE_OPERAND (v, 1)) == INTEGER_CST) + if (TYPE_SIZE_UNIT (TREE_TYPE (TREE_OPERAND (v, 0)))) { tree domain = TYPE_DOMAIN (TREE_TYPE (TREE_OPERAND (v, 0))); - if (domain - && TYPE_MAX_VALUE (domain) - && TREE_CODE (TYPE_MAX_VALUE (domain)) - == INTEGER_CST - && tree_int_cst_lt (TREE_OPERAND (v, 1), - TYPE_MAX_VALUE (domain))) + if (domain && TYPE_MAX_VALUE (domain)) { v = NULL_TREE; break; @@ -532,20 +536,20 @@ addr_object_size (struct object_size_info *osi, const_tree ptr, var = pt_var; if (var != pt_var) - var_size = TYPE_SIZE_UNIT (TREE_TYPE (var)); + { + var_size = TYPE_SIZE_UNIT (TREE_TYPE (var)); + if (!TREE_CONSTANT (var_size)) + var_size = get_or_create_ssa_default_def (cfun, var_size); + if (!var_size) + return false; + } else if (!pt_var_size) return false; else var_size = pt_var_size; bytes = compute_object_offset (TREE_OPERAND (ptr, 0), var); if (bytes != error_mark_node) - { - if (TREE_CODE (bytes) == INTEGER_CST - && tree_int_cst_lt (var_size, bytes)) - bytes = size_zero_node; - else - bytes = size_binop (MINUS_EXPR, var_size, bytes); - } + bytes = size_for_offset (var_size, bytes); if (var != pt_var && pt_var_size && TREE_CODE (pt_var) == MEM_REF @@ -554,11 +558,7 @@ addr_object_size (struct object_size_info *osi, const_tree ptr, tree bytes2 = compute_object_offset (TREE_OPERAND (ptr, 0), pt_var); if (bytes2 != error_mark_node) { - if (TREE_CODE (bytes2) == INTEGER_CST - && tree_int_cst_lt (pt_var_size, bytes2)) - bytes2 = size_zero_node; - else - bytes2 = size_binop (MINUS_EXPR, pt_var_size, bytes2); + bytes2 = size_for_offset (pt_var_size, bytes2); bytes = size_binop (MIN_EXPR, bytes, bytes2); } } @@ -568,8 +568,13 @@ addr_object_size (struct object_size_info *osi, const_tree ptr, else bytes = pt_var_size; - *psize = bytes; - return true; + if (size_known_p (bytes, object_size_type)) + { + *psize = bytes; + return true; + } + + return false; } @@ -739,19 +744,27 @@ estimate_size (object_size_info *osi, tree size, bitmap *visitlog = NULL) case PLUS_EXPR: { tree ret = estimate_size (osi, TREE_OPERAND (size, 0), visitlog); + tree off = TREE_OPERAND (size, 1); if (size_unknown_p (ret, object_size_type)) return size_unknown (object_size_type); - tree off = TREE_OPERAND (size, 1); - gcc_checking_assert (TREE_CODE (off) == INTEGER_CST); - - if (code == PLUS_EXPR) - off = fold_build1 (NEGATE_EXPR, sizetype, off); - - if (tree_fits_uhwi_p (ret) && tree_int_cst_le (ret, off)) - return size_int (0); - return size_binop (MINUS_EXPR, ret, off); + /* We don't need this for dynamic object sizes because we don't make + reducing estimates like in case of static sizes. Instead, we + return an expression that gives the precise size after a specific + number of iterations, reducing to zero at runtime if the pointer + being evaluated overflows. */ + if (!(object_size_type & OST_DYNAMIC)) + { + gcc_checking_assert (TREE_CODE (off) == INTEGER_CST); + if (code == PLUS_EXPR) + { + off = fold_build1 (NEGATE_EXPR, sizetype, off); + ret = size_binop (MAX_EXPR, ret, off); + code = MINUS_EXPR; + } + } + return size_binop (code, ret, off); } case INTEGER_CST: default: @@ -1163,7 +1176,7 @@ call_object_size (struct object_size_info *osi, gcall *call) tree bytes = alloc_object_size (call, object_size_type); - if ((object_size_type & OST_DYNAMIC) || TREE_CODE (bytes) == INTEGER_CST) + if (size_known_p (bytes, object_size_type)) return bytes; return size_unknown (object_size_type); From patchwork Tue Nov 9 19:01:36 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Siddhesh Poyarekar X-Patchwork-Id: 47329 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 67D82385AC1B for ; Tue, 9 Nov 2021 19:06:44 +0000 (GMT) X-Original-To: gcc-patches@gcc.gnu.org Delivered-To: gcc-patches@gcc.gnu.org Received: from hamster.birch.relay.mailchannels.net (hamster.birch.relay.mailchannels.net [23.83.209.80]) by sourceware.org (Postfix) with ESMTPS id 80A703857C7B for ; Tue, 9 Nov 2021 19:02:17 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.1 sourceware.org 80A703857C7B 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 15F17121BDE; Tue, 9 Nov 2021 19:02:14 +0000 (UTC) Received: from pdx1-sub0-mail-a306.dreamhost.com (100-96-18-144.trex.outbound.svc.cluster.local [100.96.18.144]) (Authenticated sender: dreamhost) by relay.mailchannels.net (Postfix) with ESMTPA id 4BA7E12169C; Tue, 9 Nov 2021 19:02:13 +0000 (UTC) X-Sender-Id: dreamhost|x-authsender|siddhesh@gotplt.org Received: from pdx1-sub0-mail-a306.dreamhost.com (pop.dreamhost.com [64.90.62.162]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384) by 100.96.18.144 (trex/6.4.3); Tue, 09 Nov 2021 19:02:14 +0000 X-MC-Relay: Neutral X-MailChannels-SenderId: dreamhost|x-authsender|siddhesh@gotplt.org X-MailChannels-Auth-Id: dreamhost X-Spicy-Abiding: 75eca1533b440910_1636484533694_3173258182 X-MC-Loop-Signature: 1636484533694:2809167630 X-MC-Ingress-Time: 1636484533694 Received: from rhbox.redhat.com (unknown [1.186.121.127]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256) (No client certificate requested) (Authenticated sender: siddhesh@gotplt.org) by pdx1-sub0-mail-a306.dreamhost.com (Postfix) with ESMTPSA id 4HpcmM3Xn4z2n; Tue, 9 Nov 2021 11:02:11 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha1; c=relaxed/relaxed; d=gotplt.org; s=gotplt.org; t=1636484533; bh=GGoQvcxJsqK7S51WhBy/iK1Gbss=; h=From:To:Cc:Subject:Date:Content-Transfer-Encoding; b=HwDGgpokoNl5eNltB39kT9e24MWzSYkaH0xLQKYedgMHFBRkPUArzIDJKk8nNq2Ca WrFccX5/11s1YTDKX6sznjavNzF6qSUbeWGXOEJnnM3wbcFavj3QGJsbjapXkkkMnW 1BqT405+zzd/+H5E//9HSyI8bXZ5YQyjIc+lxtnA= From: Siddhesh Poyarekar To: gcc-patches@gcc.gnu.org Subject: [PATCH 10/10] tree-object-size: Handle dynamic offsets Date: Wed, 10 Nov 2021 00:31:36 +0530 Message-Id: <20211109190137.1107736-11-siddhesh@gotplt.org> X-Mailer: git-send-email 2.31.1 In-Reply-To: <20211109190137.1107736-1-siddhesh@gotplt.org> References: <20211109190137.1107736-1-siddhesh@gotplt.org> MIME-Version: 1.0 X-Spam-Status: No, score=-3038.0 required=5.0 tests=BAYES_00, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, GIT_PATCH_0, RCVD_IN_BARRACUDACENTRAL, RCVD_IN_MSPIKE_H2, RCVD_IN_SBL, 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" Compute whole sizes for objects to allow offsets to be negative for dynamic object sizes. This way, the returned object size would be precise even for negative offsets as long as the offset is within bounds of the object. gcc/ChangeLog: * tree-object-size.c (addr_object_size, expr_object_size, plus_stmt_object_size, cond_expr_object_size, phi_dynamic_object_size, parm_object_size): Add new wholesize argument and handle whole sizes. (object_whole_sizes): New vector array. (object_sizes_grow, object_sizes_release, object_sizes_get, object_sizes_set, object_sizes_initialize): Add new wholesize argument to manage object_whole_sizes arrays. (size_for_offset): Get offset from wholesize if available. (estimate_size): Handle COMPOUND_EXPR. (gimplify_size_expressions): Also remove the whole size SSA. (bundle_whole_size): New function. (ssa_object_size): Remove function. (collect_object_sizes_for): Return a tree and accept new wholesize argument. (init_object_sizes): Allocate object_whole_sizes. (fini_object_sizes): Free object_whole_sizes. gcc/testsuite/ChangeLog: * gcc.dg/builtin-dynamic-object-size-0.c: Add new tests. Signed-off-by: Siddhesh Poyarekar --- .../gcc.dg/builtin-dynamic-object-size-0.c | 87 ++++ gcc/tree-object-size.c | 423 ++++++++++++------ 2 files changed, 383 insertions(+), 127 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 a1db63b2d45..3b38b915593 100644 --- a/gcc/testsuite/gcc.dg/builtin-dynamic-object-size-0.c +++ b/gcc/testsuite/gcc.dg/builtin-dynamic-object-size-0.c @@ -273,6 +273,25 @@ test_substring (size_t sz, size_t off) return __builtin_dynamic_object_size (&str[off], 0); } +size_t +__attribute__ ((noinline)) +test_substring_ptrplus (size_t sz, size_t off) +{ + int str[sz]; + + return __builtin_dynamic_object_size (str + off, 0); +} + +size_t +__attribute__ ((noinline)) +test_substring_ptrplus2 (size_t sz, size_t off, size_t off2) +{ + int str[sz]; + int *ptr = &str[off]; + + return __builtin_dynamic_object_size (ptr + off2, 0); +} + size_t __attribute__ ((access (__read_write__, 1, 2))) test_parmsz_simple (void *obj, size_t sz) @@ -280,6 +299,40 @@ test_parmsz_simple (void *obj, size_t sz) return __builtin_dynamic_object_size (obj, 0); } +size_t +__attribute__ ((noinline)) +__attribute__ ((access (__read_write__, 1, 2))) +test_parmsz (void *obj, size_t sz, size_t off) +{ + return __builtin_dynamic_object_size (obj + off, 0); +} + +size_t +__attribute__ ((noinline)) +__attribute__ ((access (__read_write__, 1, 2))) +test_parmsz_scale (int *obj, size_t sz, size_t off) +{ + return __builtin_dynamic_object_size (obj + off, 0); +} + +size_t +__attribute__ ((noinline)) +__attribute__ ((access (__read_write__, 1, 2))) +test_loop (int *obj, size_t sz, size_t start, size_t end, int incr) +{ + int *ptr = obj + start; + + for (int i = start; i != end; i = i + incr) + { + ptr = ptr + incr; + if (__builtin_dynamic_object_size (ptr, 0) == 0) + return 0; + } + + return __builtin_dynamic_object_size (ptr, 0); +} + + unsigned nfails = 0; #define FAIL() ({ \ @@ -357,6 +410,14 @@ main (int argc, char **argv) size_t objsz = 0; if (test_dynarray_struct_subobj2 (42, 4, &objsz) != objsz - 4 - 12) FAIL (); + if (test_substring_ptrplus (128, 4) != (128 - 4) * sizeof (int)) + FAIL (); + if (test_substring_ptrplus (128, 142) != 0) + FAIL (); + if (test_substring_ptrplus2 (128, 4, 4) != (128 - 8) * sizeof (int)) + FAIL (); + if (test_substring_ptrplus2 (128, 4, -3) != (128 - 1) * sizeof (int)) + FAIL (); if (test_dynarray_cond (0) != 16) FAIL (); if (test_dynarray_cond (1) != 8) @@ -368,6 +429,32 @@ main (int argc, char **argv) if (test_parmsz_simple (argv[0], __builtin_strlen (argv[0]) + 1) != __builtin_strlen (argv[0]) + 1) FAIL (); + if (test_parmsz (argv[0], __builtin_strlen (argv[0]) + 1, -1) != 0) + FAIL (); + if (test_parmsz (argv[0], __builtin_strlen (argv[0]) + 1, 0) + != __builtin_strlen (argv[0]) + 1) + FAIL (); + if (test_parmsz (argv[0], __builtin_strlen (argv[0]) + 1, + __builtin_strlen (argv[0])) != 1) + FAIL (); + if (test_parmsz (argv[0], __builtin_strlen (argv[0]) + 1, + __builtin_strlen (argv[0]) + 2) != 0) + FAIL (); + int in[42]; + if (test_parmsz_scale (in, 42, 2) != 40 * sizeof (int)) + FAIL (); + if (test_loop (in, 42, 0, 32, 1) != 10 * sizeof (int)) + FAIL (); + if (test_loop (in, 42, 32, -1, -1) != 0) + FAIL (); + if (test_loop (in, 42, 32, 10, -1) != 32 * sizeof (int)) + FAIL (); + if (test_loop (in, 42, 42, 0, -1) != 42 * sizeof (int)) + FAIL (); + if (test_loop (in, 42, 44, 0, -1) != 0) + FAIL (); + if (test_loop (in, 42, 20, 52, 1) != 0) + FAIL (); if (nfails > 0) __builtin_abort (); diff --git a/gcc/tree-object-size.c b/gcc/tree-object-size.c index 865fc3feea5..d82937de6ba 100644 --- a/gcc/tree-object-size.c +++ b/gcc/tree-object-size.c @@ -57,14 +57,14 @@ enum static tree compute_object_offset (const_tree, const_tree); static bool addr_object_size (struct object_size_info *, - const_tree, int, tree *); + const_tree, int, tree *, tree *t = NULL); static tree alloc_object_size (const gcall *, int); static tree pass_through_call (const gcall *); -static void collect_object_sizes_for (struct object_size_info *, tree); -static tree expr_object_size (struct object_size_info *, tree); -static tree ssa_object_size (struct object_size_info *, tree, tree); -static tree plus_stmt_object_size (struct object_size_info *, gimple *); -static tree cond_expr_object_size (struct object_size_info *, gimple *); +static tree collect_object_sizes_for (struct object_size_info *, tree, + tree *t = NULL); +static tree expr_object_size (struct object_size_info *, tree, tree *); +static tree plus_stmt_object_size (struct object_size_info *, tree, tree *); +static tree cond_expr_object_size (struct object_size_info *, tree, tree *); static void init_offset_limit (void); /* object_sizes[0] is upper bound for number of bytes till the end of @@ -90,6 +90,9 @@ static void init_offset_limit (void); - Its value in object_sizes is an expression that evaluates to the size. */ static vec object_sizes[OST_END]; +/* Whole size expressions are only needed for dynamic object sizes. */ +static vec object_whole_sizes[OST_DYNAMIC]; + /* Bitmaps what object sizes have been computed already. */ static bitmap computed[OST_END]; @@ -149,21 +152,35 @@ size_unknown (int object_size_type) return size_int (unknown (object_size_type)); } -/* Grow object_sizes[OBJECT_SIZE_TYPE] to num_ssa_names. */ +/* Grow object_sizes[OBJECT_SIZE_TYPE] and if WHOLE is true, + object_whole_sizes[OBJECT_SIZE_TYPE] to num_ssa_names. */ static inline void -object_sizes_grow (int object_size_type) +object_sizes_grow (int object_size_type, bool whole = false) { if (num_ssa_names > object_sizes[object_size_type].length ()) object_sizes[object_size_type].safe_grow (num_ssa_names, true); + if (whole) + { + gcc_assert (object_size_type & OST_DYNAMIC); + object_size_type &= ~OST_DYNAMIC; + if (num_ssa_names > object_whole_sizes[object_size_type].length ()) + object_whole_sizes[object_size_type].safe_grow (num_ssa_names, true); + } } /* Release object_sizes[OBJECT_SIZE_TYPE]. */ static inline void -object_sizes_release (int object_size_type) +object_sizes_release (int object_size_type, bool whole = false) { object_sizes[object_size_type].release (); + if (whole) + { + gcc_assert (object_size_type & OST_DYNAMIC); + object_size_type &= ~OST_DYNAMIC; + object_whole_sizes[object_size_type].release (); + } } /* Return true if object_sizes[OBJECT_SIZE_TYPE][VARNO] is unknown. */ @@ -178,8 +195,16 @@ object_sizes_unknown_p (int object_size_type, unsigned varno) /* Return size for VARNO corresponding to OSI. */ static inline tree -object_sizes_get (struct object_size_info *osi, unsigned varno) +object_sizes_get (struct object_size_info *osi, unsigned varno, + bool whole = false) { + if (whole) + { + int object_size_type = osi->object_size_type; + gcc_assert (object_size_type & OST_DYNAMIC); + object_size_type &= ~OST_DYNAMIC; + return object_whole_sizes[object_size_type][varno]; + } return object_sizes[osi->object_size_type][varno]; } @@ -187,22 +212,38 @@ object_sizes_get (struct object_size_info *osi, unsigned varno) static inline void object_sizes_initialize (struct object_size_info *osi, unsigned varno, - tree val = NULL_TREE) + tree val, bool whole = false) { int object_size_type = osi->object_size_type; - if (!val) - val = size_initval (object_size_type); object_sizes[object_size_type][varno] = val; + if (whole) + { + object_size_type = osi->object_size_type; + gcc_assert (object_size_type & OST_DYNAMIC); + object_size_type &= ~OST_DYNAMIC; + object_whole_sizes[object_size_type][varno] = val; + } } /* Set size for VARNO corresponding to OSI to VAL if it is the new minimum or maximum. */ static inline void -object_sizes_set (struct object_size_info *osi, unsigned varno, tree val) +object_sizes_set (struct object_size_info *osi, unsigned varno, tree val, + bool whole = false) { int object_size_type = osi->object_size_type; + + if (whole) + { + int object_size_type = osi->object_size_type; + gcc_assert (object_size_type & OST_DYNAMIC); + object_size_type &= ~OST_DYNAMIC; + object_whole_sizes[object_size_type][varno] = val; + return; + } + tree curval = object_sizes[object_size_type][varno]; /* Object size is set at most twice, once to put in an SSA name to resolve @@ -239,11 +280,21 @@ init_offset_limit (void) offset_limit /= 2; } -/* Bytes at end of the object with SZ from offset OFFSET. */ +/* Bytes at end of the object with SZ from offset OFFSET. If WHOLESIZE is + present, use it to allow negative OFFSET to the extent that it does not + underflow WHOLESIZE. */ static tree -size_for_offset (tree sz, tree offset) +size_for_offset (tree sz, tree offset, tree wholesize = NULL_TREE) { + if (wholesize) + { + offset = size_binop (PLUS_EXPR, size_binop (MAX_EXPR, wholesize, sz), + offset); + offset = size_binop (MINUS_EXPR, offset, sz); + sz = wholesize; + } + return size_binop (MINUS_EXPR, size_binop (MAX_EXPR, sz, offset), offset); } @@ -360,7 +411,7 @@ decl_init_size (tree decl, bool min) static bool addr_object_size (struct object_size_info *osi, const_tree ptr, - int object_size_type, tree *psize) + int object_size_type, tree *psize, tree *wholesize) { tree pt_var, pt_var_size = NULL_TREE, var_size, bytes; @@ -369,6 +420,8 @@ addr_object_size (struct object_size_info *osi, const_tree ptr, /* Set to unknown and overwrite just before returning if the size could be determined. */ *psize = size_unknown (object_size_type); + if (wholesize) + *wholesize = size_unknown (object_size_type); pt_var = TREE_OPERAND (ptr, 0); while (handled_component_p (pt_var)) @@ -391,21 +444,13 @@ addr_object_size (struct object_size_info *osi, const_tree ptr, else { tree var = TREE_OPERAND (pt_var, 0); - collect_object_sizes_for (osi, var); - if (bitmap_bit_p (computed[object_size_type], - SSA_NAME_VERSION (var))) - sz = object_sizes_get (osi, SSA_NAME_VERSION (var)); - else + sz = collect_object_sizes_for (osi, var); + if (!bitmap_bit_p (computed[object_size_type], + SSA_NAME_VERSION (var))) sz = size_unknown (object_size_type); } if (!size_unknown_p (sz, object_size_type)) - { - tree offset = TREE_OPERAND (pt_var, 1); - if (TREE_CODE (offset) != INTEGER_CST) - sz = size_unknown (object_size_type); - else - sz = size_for_offset (sz, offset); - } + sz = size_for_offset (sz, TREE_OPERAND (pt_var, 1)); if (!size_unknown_p (sz, object_size_type) && (TREE_CODE (sz) != INTEGER_CST @@ -570,6 +615,8 @@ addr_object_size (struct object_size_info *osi, const_tree ptr, if (size_known_p (bytes, object_size_type)) { + if ((object_size_type & OST_DYNAMIC) && wholesize) + *wholesize = object_size_type & OST_SUBOBJECT ? bytes : pt_var_size; *psize = bytes; return true; } @@ -766,6 +813,8 @@ estimate_size (object_size_info *osi, tree size, bitmap *visitlog = NULL) } return size_binop (code, ret, off); } + case COMPOUND_EXPR: + return estimate_size (osi, TREE_OPERAND (size, 1), visitlog); case INTEGER_CST: default: return size; @@ -943,6 +992,13 @@ gimplify_size_expressions (object_size_info *osi) if (stmt) { gimple_stmt_iterator gsi = gsi_for_stmt (stmt); + remove_phi_node (&gsi, false); + + /* Also remove the whole size SSA. */ + stmt = SSA_NAME_DEF_STMT (object_sizes_get (osi, varno, + true)); + gcc_checking_assert (stmt); + gsi = gsi_for_stmt (stmt); remove_phi_node (&gsi, true); } bitmap_set_bit (tempsize_free, i); @@ -1043,7 +1099,7 @@ compute_builtin_object_size (tree ptr, int object_size_type, bitmap_iterator bi; unsigned int i; - object_sizes_grow (object_size_type); + object_sizes_grow (object_size_type, object_size_type & OST_DYNAMIC); if (dump_file) { fprintf (dump_file, "Computing %s %s%sobject size for ", @@ -1142,10 +1198,52 @@ make_or_get_tempsize (struct object_size_info *osi, unsigned varno) return ssa; } +static tree +bundle_whole_size (struct object_size_info *osi, tree var, tree res, + tree *wholesize) +{ + int object_size_type = osi->object_size_type; + + if (!(object_size_type & OST_DYNAMIC) + || size_unknown_p (res, object_size_type)) + return res; + + tree cur = NULL_TREE; + + /* Get the temp SSA name if we created one for a dependency loop. */ + if (TREE_CODE (var) == SSA_NAME) + cur = object_sizes_get (osi, SSA_NAME_VERSION (var), true); + + /* If we need to gimplify WHOLERES, fold it into a compound expression + along with RES so that their statements are emitted together. */ + if (cur && TREE_CODE (cur) == SSA_NAME) + { + unsigned wno = SSA_NAME_VERSION (cur); + if (bitmap_bit_p (osi->reexamine, wno)) + bitmap_clear_bit (osi->reexamine, wno); + else + cur = NULL_TREE; + } + else if (!is_gimple_variable (*wholesize) + && TREE_CODE (*wholesize) != INTEGER_CST) + cur = make_ssa_name (sizetype); + else + cur = NULL_TREE; + + if (cur) + { + res = size_binop (COMPOUND_EXPR, + size_binop (MODIFY_EXPR, cur, *wholesize), + res); + *wholesize = cur; + } + return res; +} + /* Compute object_sizes for PTR, defined to VALUE, which is not an SSA_NAME. */ static tree -expr_object_size (struct object_size_info *osi, tree value) +expr_object_size (struct object_size_info *osi, tree value, tree *wholesize) { int object_size_type = osi->object_size_type; tree bytes; @@ -1153,14 +1251,17 @@ expr_object_size (struct object_size_info *osi, tree value) if (TREE_CODE (value) == WITH_SIZE_EXPR) value = TREE_OPERAND (value, 0); - /* Pointer variables should have been handled by ssa_object_size. */ + /* Pointer variables should have been handled by + collect_object_sizes_for. */ gcc_assert (TREE_CODE (value) != SSA_NAME || !POINTER_TYPE_P (TREE_TYPE (value))); if (TREE_CODE (value) == ADDR_EXPR - && addr_object_size (osi, value, object_size_type, &bytes)) - return bytes; + && addr_object_size (osi, value, object_size_type, &bytes, wholesize)) + return bundle_whole_size (osi, value, bytes, wholesize); + if (wholesize) + *wholesize = size_unknown (object_size_type); return size_unknown (object_size_type); } @@ -1168,16 +1269,20 @@ expr_object_size (struct object_size_info *osi, tree value) /* Compute object_sizes for PTR, defined to the result of a call. */ static tree -call_object_size (struct object_size_info *osi, gcall *call) +call_object_size (struct object_size_info *osi, tree var, tree *wholesize) { int object_size_type = osi->object_size_type; + gcall *call = as_a (SSA_NAME_DEF_STMT (var)); gcc_assert (is_gimple_call (call)); tree bytes = alloc_object_size (call, object_size_type); + if (wholesize) + *wholesize = bytes; + if (size_known_p (bytes, object_size_type)) - return bytes; + return bundle_whole_size (osi, var, bytes, wholesize); return size_unknown (object_size_type); } @@ -1186,44 +1291,25 @@ call_object_size (struct object_size_info *osi, gcall *call) /* Compute object_sizes for PTR, defined to an unknown value. */ static tree -unknown_object_size (struct object_size_info *osi) +unknown_object_size (struct object_size_info *osi, tree *wholesize) { int object_size_type = osi->object_size_type; + if (wholesize) + *wholesize = size_unknown (object_size_type); return size_unknown (object_size_type); } -/* Return object size of ORIG + OFFSET. */ - -static tree -ssa_object_size (struct object_size_info *osi, tree orig, tree offset) -{ - int object_size_type = osi->object_size_type; - tree orig_bytes; - - if (compare_tree_int (offset, offset_limit) >= 0) - return size_unknown (object_size_type); - - collect_object_sizes_for (osi, orig); - - orig_bytes = object_sizes_get (osi, SSA_NAME_VERSION (orig)); - if (!size_unknown_p (orig_bytes, object_size_type) - && !integer_zerop (offset)) - orig_bytes = size_for_offset (orig_bytes, offset); - - return orig_bytes; -} - - /* Compute object_sizes for VAR, defined to the result of an assignment with operator POINTER_PLUS_EXPR. */ static tree -plus_stmt_object_size (struct object_size_info *osi, gimple *stmt) +plus_stmt_object_size (struct object_size_info *osi, tree var, tree *wholesize) { int object_size_type = osi->object_size_type; tree bytes; tree op0, op1; + gimple *stmt = SSA_NAME_DEF_STMT (var); if (gimple_assign_rhs_code (stmt) == POINTER_PLUS_EXPR) { @@ -1240,29 +1326,24 @@ plus_stmt_object_size (struct object_size_info *osi, gimple *stmt) else gcc_unreachable (); - /* Handle PTR + OFFSET here. */ - if (TREE_CODE (op1) == INTEGER_CST - && (TREE_CODE (op0) == SSA_NAME - || TREE_CODE (op0) == ADDR_EXPR)) - { - if (TREE_CODE (op0) == SSA_NAME) - bytes = ssa_object_size (osi, op0, op1); - else - { - /* op0 will be ADDR_EXPR here. */ - addr_object_size (osi, op0, object_size_type, &bytes); - if (size_unknown_p (bytes, object_size_type)) - ; - else if (compare_tree_int (op1, offset_limit) > 0) - bytes = size_unknown (object_size_type); - else if (!integer_zerop (op1)) - bytes = size_for_offset (bytes, op1); - } - } + if (!(object_size_type & OST_DYNAMIC) + && (TREE_CODE (op1) != INTEGER_CST + || compare_tree_int (op1, offset_limit) > 0)) + return size_unknown (object_size_type); + + if (TREE_CODE (op0) == SSA_NAME) + bytes = collect_object_sizes_for (osi, op0, wholesize); + else if (TREE_CODE (op0) == ADDR_EXPR) + addr_object_size (osi, op0, object_size_type, &bytes, wholesize); else bytes = size_unknown (object_size_type); - return bytes; + if (!size_unknown_p (bytes, object_size_type)) + bytes = size_for_offset (bytes, op1, wholesize ? *wholesize : NULL_TREE); + else if (wholesize) + *wholesize = size_unknown (object_size_type); + + return bundle_whole_size (osi, var, bytes, wholesize); } @@ -1270,34 +1351,48 @@ plus_stmt_object_size (struct object_size_info *osi, gimple *stmt) a COND_EXPR. */ static tree -cond_expr_object_size (struct object_size_info *osi, gimple *stmt) +cond_expr_object_size (struct object_size_info *osi, tree var, tree *wholesize) { tree then_, else_; int object_size_type = osi->object_size_type; - tree thenbytes, elsebytes; + tree thenbytes, elsebytes, thenwhole, elsewhole; + gimple *stmt = SSA_NAME_DEF_STMT (var); gcc_assert (gimple_assign_rhs_code (stmt) == COND_EXPR); + if (!(object_size_type & OST_DYNAMIC)) + wholesize = NULL; + then_ = gimple_assign_rhs2 (stmt); else_ = gimple_assign_rhs3 (stmt); if (TREE_CODE (then_) == SSA_NAME) - thenbytes = ssa_object_size (osi, then_, size_int (0)); + thenbytes = collect_object_sizes_for (osi, then_, wholesize); else - thenbytes = expr_object_size (osi, then_); + thenbytes = expr_object_size (osi, then_, wholesize); + + thenwhole = wholesize ? *wholesize : NULL_TREE; if (TREE_CODE (else_) == SSA_NAME) - elsebytes = ssa_object_size (osi, else_, size_int (0)); + elsebytes = collect_object_sizes_for (osi, else_, wholesize); else - elsebytes = expr_object_size (osi, else_); + elsebytes = expr_object_size (osi, else_, wholesize); + + elsewhole = wholesize ? *wholesize : NULL_TREE; if (size_unknown_p (thenbytes, object_size_type) || size_unknown_p (elsebytes, object_size_type)) return size_unknown (object_size_type); if (object_size_type & OST_DYNAMIC) - return fold_build3 (COND_EXPR, sizetype, gimple_assign_rhs1 (stmt), - thenbytes, elsebytes); + { + gcc_checking_assert (elsewhole && thenwhole); + *wholesize = fold_build3 (COND_EXPR, sizetype, gimple_assign_rhs1 (stmt), + thenwhole, elsewhole); + tree res = fold_build3 (COND_EXPR, sizetype, gimple_assign_rhs1 (stmt), + thenbytes, elsebytes); + return bundle_whole_size (osi, var, res, wholesize); + } return size_binop (OST_TREE_CODE (object_size_type), thenbytes, elsebytes); } @@ -1316,9 +1411,9 @@ phi_object_size (struct object_size_info *osi, gimple *stmt) tree phires; if (TREE_CODE (rhs) == SSA_NAME) - phires = ssa_object_size (osi, rhs, size_int (0)); + phires = collect_object_sizes_for (osi, rhs); else - phires = expr_object_size (osi, rhs); + phires = expr_object_size (osi, rhs, NULL); res = size_binop (OST_TREE_CODE (object_size_type), res, phires); @@ -1329,42 +1424,69 @@ phi_object_size (struct object_size_info *osi, gimple *stmt) } static tree -phi_dynamic_object_size (struct object_size_info *osi, tree var) +phi_dynamic_object_size (struct object_size_info *osi, tree var, + tree *wholesize) { int object_size_type = osi->object_size_type; unsigned int varno = SSA_NAME_VERSION (var); gimple *stmt = SSA_NAME_DEF_STMT (var); unsigned i, num_args = gimple_phi_num_args (stmt); - tree res; + tree res, wholeres; - vec sizes; + vec sizes, wholesizes; sizes.create (0); + wholesizes.create (0); sizes.safe_grow (num_args); + wholesizes.safe_grow (num_args); /* Bail out if the size of any of the PHI arguments cannot be determined. */ for (i = 0; i < num_args; i++) { tree rhs = gimple_phi_arg_def (stmt, i); - tree sz; + tree sz, cur_whole; if (TREE_CODE (rhs) != SSA_NAME) - sz = expr_object_size (osi, rhs); + sz = expr_object_size (osi, rhs, &cur_whole); else - sz = ssa_object_size (osi, rhs, size_int (0)); + sz = collect_object_sizes_for (osi, rhs, &cur_whole); - if (size_unknown_p (sz, object_size_type)) + if (size_unknown_p (sz, object_size_type) + || size_unknown_p (cur_whole, object_size_type)) break; + if (!is_gimple_variable (cur_whole) + && TREE_CODE (cur_whole) != INTEGER_CST) + { + tree tmp = make_ssa_name (sizetype); + tmp = size_binop (MODIFY_EXPR, tmp, cur_whole); + sz = size_binop (COMPOUND_EXPR, tmp, sz); + cur_whole = tmp; + } sizes[i] = sz; + wholesizes[i] = cur_whole; } if (i == num_args) { res = make_or_get_tempsize (osi, varno); + wholeres = object_sizes_get (osi, varno, true); + if (TREE_CODE (wholeres) != SSA_NAME) + { + gcc_checking_assert (TREE_CODE (wholeres) == INTEGER_CST); + gcc_checking_assert (compare_tree_int (wholeres, + initval (object_size_type)) + == 0); + wholeres = make_ssa_name (sizetype); + } + else + /* We don't reexamine whole sizes on their own. */ + bitmap_clear_bit (osi->reexamine, SSA_NAME_VERSION (wholeres)); + bitmap_set_bit (osi->phiresults, SSA_NAME_VERSION (res)); object_sizes_initialize (osi, SSA_NAME_VERSION (res), res); + gphi *wholephi = create_phi_node (wholeres, gimple_bb (stmt)); gphi *phi = create_phi_node (res, gimple_bb (stmt)); gphi *obj_phi = as_a (stmt); @@ -1377,6 +1499,11 @@ phi_dynamic_object_size (struct object_size_info *osi, tree var) sizes[i] = ssa; } + /* We're guaranteed to get gimple variables for whole sizes through + expr_object_size and collect_object_sizes_for. */ + add_phi_arg (wholephi, wholesizes[i], + gimple_phi_arg_edge (obj_phi, i), + gimple_phi_arg_location (obj_phi, i)); add_phi_arg (phi, sizes[i], gimple_phi_arg_edge (obj_phi, i), gimple_phi_arg_location (obj_phi, i)); @@ -1387,20 +1514,26 @@ phi_dynamic_object_size (struct object_size_info *osi, tree var) print_generic_expr (dump_file, var, dump_flags); fprintf (dump_file, ": PHI Node with result: "); print_gimple_stmt (dump_file, phi, dump_flags); + fprintf (dump_file, " and wholephi: "); + print_gimple_stmt (dump_file, wholephi, dump_flags); } + *wholesize = wholeres; } else - res = size_unknown (object_size_type); + { + res = size_unknown (object_size_type); + *wholesize = size_unknown (object_size_type); + } sizes.release (); - + wholesizes.release (); return res; } /* Find size of an object passed as a parameter to the function. */ static tree -parm_object_size (struct object_size_info *osi, tree var) +parm_object_size (struct object_size_info *osi, tree var, tree *wholesize) { int object_size_type = osi->object_size_type; tree parm = SSA_NAME_VAR (var); @@ -1414,7 +1547,7 @@ parm_object_size (struct object_size_info *osi, tree var) } if (!(object_size_type & OST_DYNAMIC) || !POINTER_TYPE_P (TREE_TYPE (parm))) - return expr_object_size (osi, parm); + return expr_object_size (osi, parm, wholesize); /* Look for access attribute. */ rdwr_map rdwr_idx; @@ -1422,6 +1555,7 @@ parm_object_size (struct object_size_info *osi, tree var) tree fndecl = cfun->decl; const attr_access *access = get_parm_access (rdwr_idx, parm, fndecl); tree typesize = TYPE_SIZE_UNIT (TREE_TYPE (TREE_TYPE (parm))); + tree sz = NULL_TREE; if (access && access->sizarg != UINT_MAX) { @@ -1436,17 +1570,21 @@ parm_object_size (struct object_size_info *osi, tree var) if (arg != NULL_TREE && INTEGRAL_TYPE_P (TREE_TYPE (arg))) { - tree sz = get_or_create_ssa_default_def (cfun, arg); + sz = get_or_create_ssa_default_def (cfun, arg); if (sz != NULL_TREE) { sz = fold_convert (sizetype, sz); if (typesize) sz = size_binop (MULT_EXPR, sz, typesize); - return sz; } } } - return size_unknown (object_size_type); + if (sz == NULL_TREE) + sz = size_unknown (object_size_type); + + if (wholesize) + *wholesize = sz; + return bundle_whole_size (osi, var, sz, wholesize); } /* Compute object sizes for VAR. @@ -1469,23 +1607,32 @@ parm_object_size (struct object_size_info *osi, tree var) Otherwise, object size is the maximum of object sizes of variables that it might be set to. */ -static void -collect_object_sizes_for (struct object_size_info *osi, tree var) +static tree +collect_object_sizes_for (struct object_size_info *osi, tree var, + tree *wholesize) { int object_size_type = osi->object_size_type; unsigned int varno = SSA_NAME_VERSION (var); + tree res, wholeres = NULL_TREE; gimple *stmt; - tree res; + + if ((object_size_type & OST_DYNAMIC) && !wholesize) + wholesize = &wholeres; if (bitmap_bit_p (computed[object_size_type], varno)) - return; + { + if (wholesize) + *wholesize = object_sizes_get (osi, varno, true); + return object_sizes_get (osi, varno); + } /* We want to evaluate the self-referencing object only once. */ if (bitmap_set_bit (osi->visited, varno)) { /* Initialize to 0 for maximum size and M1U for minimum size so that it gets immediately overridden. */ - object_sizes_initialize (osi, varno); + object_sizes_initialize (osi, varno, size_initval (object_size_type), + object_size_type & OST_DYNAMIC); } else { @@ -1497,6 +1644,19 @@ collect_object_sizes_for (struct object_size_info *osi, tree var) fprintf (dump_file, "\n"); } res = make_or_get_tempsize (osi, varno); + if (wholesize) + { + tree tmp = object_sizes_get (osi, varno, true); + if (TREE_CODE (tmp) == INTEGER_CST) + *wholesize = make_tempsize (osi, varno); + else + { + gcc_assert (TREE_CODE (res) == SSA_NAME + && bitmap_bit_p (osi->reexamine, + SSA_NAME_VERSION (tmp))); + *wholesize = tmp; + } + } goto out; } @@ -1517,58 +1677,57 @@ collect_object_sizes_for (struct object_size_info *osi, tree var) if (gimple_assign_rhs_code (stmt) == POINTER_PLUS_EXPR || (gimple_assign_rhs_code (stmt) == ADDR_EXPR && TREE_CODE (TREE_OPERAND (rhs, 0)) == MEM_REF)) - res = plus_stmt_object_size (osi, stmt); + res = plus_stmt_object_size (osi, var, wholesize); else if (gimple_assign_rhs_code (stmt) == COND_EXPR) - res = cond_expr_object_size (osi, stmt); + res = cond_expr_object_size (osi, var, wholesize); else if (gimple_assign_single_p (stmt) || gimple_assign_unary_nop_p (stmt)) { if (TREE_CODE (rhs) == SSA_NAME && POINTER_TYPE_P (TREE_TYPE (rhs))) - res = ssa_object_size (osi, rhs, size_int (0)); + res = collect_object_sizes_for (osi, rhs, wholesize); else - res = expr_object_size (osi, rhs); + res = expr_object_size (osi, rhs, wholesize); } else - res = unknown_object_size (osi); + res = unknown_object_size (osi, wholesize); break; } case GIMPLE_CALL: { - gcall *call_stmt = as_a (stmt); - tree arg = pass_through_call (call_stmt); + tree arg = pass_through_call (as_a (stmt)); if (arg) { if (TREE_CODE (arg) == SSA_NAME && POINTER_TYPE_P (TREE_TYPE (arg))) - res = ssa_object_size (osi, arg, size_int (0)); + res = collect_object_sizes_for (osi, arg, wholesize); else - res = expr_object_size (osi, arg); + res = expr_object_size (osi, arg, wholesize); } else - res = call_object_size (osi, call_stmt); + res = call_object_size (osi, var, wholesize); break; } case GIMPLE_ASM: /* Pointers defined by __asm__ statements can point anywhere. */ - res = size_unknown (object_size_type); + res = unknown_object_size (osi, wholesize); break; case GIMPLE_NOP: if (SSA_NAME_VAR (var) && TREE_CODE (SSA_NAME_VAR (var)) == PARM_DECL) - res = parm_object_size (osi, var); + res = parm_object_size (osi, var, wholesize); else /* Uninitialized SSA names point nowhere. */ - res = size_unknown (object_size_type); + res = unknown_object_size (osi, wholesize); break; case GIMPLE_PHI: { if (object_size_type & OST_DYNAMIC) - res = phi_dynamic_object_size (osi, var); + res = phi_dynamic_object_size (osi, var, wholesize); else res = phi_object_size (osi, stmt); break; @@ -1578,16 +1737,26 @@ collect_object_sizes_for (struct object_size_info *osi, tree var) gcc_unreachable (); } - if ((object_size_type & OST_DYNAMIC) - && TREE_CODE (res) != INTEGER_CST && !is_gimple_variable (res)) + res = bundle_whole_size (osi, var, res, wholesize); + + if (wholesize) + gcc_checking_assert (TREE_CODE (*wholesize) == INTEGER_CST + || is_gimple_variable (*wholesize)); + + if ((object_size_type & OST_DYNAMIC) && TREE_CODE (res) != INTEGER_CST + && !is_gimple_variable (res)) { tree ssa = make_or_get_tempsize (osi, varno); object_sizes_initialize (osi, SSA_NAME_VERSION (ssa), res); res = ssa; } + bitmap_set_bit (computed[object_size_type], varno); out: object_sizes_set (osi, varno, res); + if (object_size_type & OST_DYNAMIC) + object_sizes_set (osi, varno, *wholesize, true); + return res; } @@ -1603,7 +1772,7 @@ init_object_sizes (void) for (object_size_type = 0; object_size_type < OST_END; object_size_type++) { - object_sizes_grow (object_size_type); + object_sizes_grow (object_size_type, object_size_type >= OST_DYNAMIC); computed[object_size_type] = BITMAP_ALLOC (NULL); } @@ -1620,7 +1789,7 @@ fini_object_sizes (void) for (object_size_type = 0; object_size_type < OST_END; object_size_type++) { - object_sizes_release (object_size_type); + object_sizes_release (object_size_type, object_size_type >= OST_DYNAMIC); BITMAP_FREE (computed[object_size_type]); } }