From patchwork Thu Oct 7 22:14: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: 45978 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 C03713857831 for ; Thu, 7 Oct 2021 22:18:57 +0000 (GMT) X-Original-To: gcc-patches@gcc.gnu.org Delivered-To: gcc-patches@gcc.gnu.org Received: from hedgehog.birch.relay.mailchannels.net (hedgehog.birch.relay.mailchannels.net [23.83.209.81]) by sourceware.org (Postfix) with ESMTPS id 87B8F385780B for ; Thu, 7 Oct 2021 22:15:20 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.1 sourceware.org 87B8F385780B 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 CFA1F342028; Thu, 7 Oct 2021 22:15:17 +0000 (UTC) Received: from pdx1-sub0-mail-a17.g.dreamhost.com (100-96-16-65.trex.outbound.svc.cluster.local [100.96.16.65]) (Authenticated sender: dreamhost) by relay.mailchannels.net (Postfix) with ESMTPA id 6762E34138A; Thu, 7 Oct 2021 22:15:17 +0000 (UTC) X-Sender-Id: dreamhost|x-authsender|siddhesh@gotplt.org Received: from pdx1-sub0-mail-a17.g.dreamhost.com (pop.dreamhost.com [64.90.62.162]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384) by 100.96.16.65 (trex/6.4.3); Thu, 07 Oct 2021 22:15:17 +0000 X-MC-Relay: Neutral X-MailChannels-SenderId: dreamhost|x-authsender|siddhesh@gotplt.org X-MailChannels-Auth-Id: dreamhost X-Shade-Hysterical: 68b71d6a07efe313_1633644917704_2481779754 X-MC-Loop-Signature: 1633644917703:813508260 X-MC-Ingress-Time: 1633644917703 Received: from pdx1-sub0-mail-a17.g.dreamhost.com (localhost [127.0.0.1]) by pdx1-sub0-mail-a17.g.dreamhost.com (Postfix) with ESMTP id 271AE83495; Thu, 7 Oct 2021 15:15:17 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha1; c=relaxed; d=gotplt.org; h=from:to:cc :subject:date:message-id:in-reply-to:references:mime-version :content-transfer-encoding; s=gotplt.org; bh=pffZTZsIOey9B7rUZnH lWsQ4++4=; b=sW3gLPS8qzfLOkjrJ1IF5c36vxBlRuZjx0JfgbOjl/ieoqiTBR6 5IsagfCzR++TbhQ5a5guK8ahB/nc/FHIzsDhCIB1UTlXvNEoXzFmsqeKV2pNqtsQ 6FJJuWNwogscnuq03S7Vimg8leJp+ZVpenT955MT0xg+Bs0IX80OXQuQ= Received: from rhbox.redhat.com (unknown [1.186.223.58]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) (Authenticated sender: siddhesh@gotplt.org) by pdx1-sub0-mail-a17.g.dreamhost.com (Postfix) with ESMTPSA id DEC007F2D7; Thu, 7 Oct 2021 15:15:13 -0700 (PDT) X-DH-BACKEND: pdx1-sub0-mail-a17 From: Siddhesh Poyarekar To: gcc-patches@gcc.gnu.org Subject: [PATCH 7/8] tree-dynamic-object-size: Get subobject sizes Date: Fri, 8 Oct 2021 03:44:31 +0530 Message-Id: <20211007221432.1029249-8-siddhesh@gotplt.org> X-Mailer: git-send-email 2.31.1 In-Reply-To: <20211007221432.1029249-1-siddhesh@gotplt.org> References: <20211007221432.1029249-1-siddhesh@gotplt.org> MIME-Version: 1.0 X-Spam-Status: No, score=-3039.0 required=5.0 tests=BAYES_00, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, GIT_PATCH_0, RCVD_IN_DNSWL_NONE, RCVD_IN_MSPIKE_H2, SPF_HELO_NONE, SPF_PASS, TXREP autolearn=ham autolearn_force=no version=3.4.4 X-Spam-Checker-Version: SpamAssassin 3.4.4 (2020-01-24) on server2.sourceware.org X-BeenThere: gcc-patches@gcc.gnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Gcc-patches mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: jakub@redhat.com Errors-To: gcc-patches-bounces+patchwork=sourceware.org@gcc.gnu.org Sender: "Gcc-patches" Adapt subobject computation logic from tree-object-size to make it work with variable sizes. gcc/ChangeLog: * tree-dynamic-object-size.c (build_cond_branch): New function. (compute_object_offset): Use it. (get_closest_subobject): New function. (addr_dyn_object_size): Call it. Support subobject size computation. gcc/testsuite/ChangeLog: * gcc.dg/builtin-dynamic-object-size-0.c (test_dynarray_struct_subobj): New test. (main): Call it. Signed-off-by: Siddhesh Poyarekar --- .../gcc.dg/builtin-dynamic-object-size-0.c | 34 ++++ gcc/tree-dynamic-object-size.c | 172 ++++++++++++++++-- 2 files changed, 194 insertions(+), 12 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 c72fa0508db..94f8e071e2c 100644 --- a/gcc/testsuite/gcc.dg/builtin-dynamic-object-size-0.c +++ b/gcc/testsuite/gcc.dg/builtin-dynamic-object-size-0.c @@ -237,6 +237,33 @@ test_dynarray_struct (size_t sz, size_t off) 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) @@ -334,6 +361,13 @@ main (int argc, char **argv) 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_substring_ptrplus (128, 4) != (128 - 4) * sizeof (int)) FAIL (); if (test_substring_ptrplus (128, 142) != 0) diff --git a/gcc/tree-dynamic-object-size.c b/gcc/tree-dynamic-object-size.c index 8d7283623dc..ebc2fad7a87 100644 --- a/gcc/tree-dynamic-object-size.c +++ b/gcc/tree-dynamic-object-size.c @@ -102,12 +102,21 @@ static bitmap computed[4]; bool compute_builtin_dyn_object_size (tree, int, tree *, struct function *fun = NULL); +static tree +build_cond_branch (tree t, tree low_bound, tree unit_size) +{ + tree br = fold_build2 (MINUS_EXPR, TREE_TYPE (t), t, low_bound); + br = fold_convert (sizetype, br); + br = fold_build2 (MULT_EXPR, sizetype, unit_size, br); + + return br; +} + /* Compute offset of EXPR within VAR. Return error_mark_node if unknown. */ static tree compute_object_offset (const_tree expr, const_tree var) { - enum tree_code code = PLUS_EXPR; tree base, off, t; if (expr == var) @@ -150,12 +159,16 @@ compute_object_offset (const_tree expr, const_tree var) low_bound = array_ref_low_bound (CONST_CAST_TREE (expr)); unit_size = array_ref_element_size (CONST_CAST_TREE (expr)); if (! integer_zerop (low_bound)) - t = fold_build2 (MINUS_EXPR, TREE_TYPE (t), t, low_bound); - if (TREE_CODE (t) == INTEGER_CST && tree_int_cst_sgn (t) < 0) { - code = MINUS_EXPR; - t = fold_build1 (NEGATE_EXPR, TREE_TYPE (t), t); + tree cond = fold_build2 (GE_EXPR, TREE_TYPE (t), t, low_bound); + tree then_br = build_cond_branch (t, low_bound, unit_size); + tree else_br = build_cond_branch (low_bound, t, unit_size); + + then_br = fold_build2 (PLUS_EXPR, sizetype, base, then_br); + else_br = fold_build2 (MINUS_EXPR, sizetype, base, else_br); + return fold_build3 (COND_EXPR, sizetype, cond, then_br, else_br); } + t = fold_convert (sizetype, t); off = fold_build2 (MULT_EXPR, sizetype, unit_size, t); break; @@ -168,7 +181,7 @@ compute_object_offset (const_tree expr, const_tree var) return error_mark_node; } - return fold_build2 (code, sizetype, base, off); + return fold_build2 (PLUS_EXPR, sizetype, base, off); } /* Given an object size SZ and offset OFF into it, compute the usable object @@ -328,6 +341,105 @@ whole_var_size (struct object_size_info *osi, tree pt_var, return true; } +/* Get the most immediate subobject encapsulating the pointer PTR, given the + whole_var object WHOLE_VAR. */ + +static tree +get_closest_subobject (const_tree ptr, tree whole_var) +{ + tree var = TREE_OPERAND (ptr, 0); + + while (var != whole_var + && TREE_CODE (var) != BIT_FIELD_REF + && TREE_CODE (var) != COMPONENT_REF + && TREE_CODE (var) != ARRAY_REF + && TREE_CODE (var) != ARRAY_RANGE_REF + && TREE_CODE (var) != REALPART_EXPR + && TREE_CODE (var) != IMAGPART_EXPR) + var = TREE_OPERAND (var, 0); + + if (var != whole_var && TREE_CODE (var) == ARRAY_REF) + var = TREE_OPERAND (var, 0); + + if (! TYPE_SIZE_UNIT (TREE_TYPE (var))) + var = whole_var; + else if (var != whole_var && TREE_CODE (whole_var) == MEM_REF) + { + tree v = var; + while (v && v != whole_var) + switch (TREE_CODE (v)) + { + case ARRAY_REF: + 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)) + { + v = NULL_TREE; + break; + } + } + v = TREE_OPERAND (v, 0); + break; + case REALPART_EXPR: + case IMAGPART_EXPR: + v = NULL_TREE; + break; + case COMPONENT_REF: + if (TREE_CODE (TREE_TYPE (v)) != ARRAY_TYPE) + { + v = NULL_TREE; + break; + } + while (v != whole_var && TREE_CODE (v) == COMPONENT_REF) + if (TREE_CODE (TREE_TYPE (TREE_OPERAND (v, 0))) + != UNION_TYPE + && TREE_CODE (TREE_TYPE (TREE_OPERAND (v, 0))) + != QUAL_UNION_TYPE) + break; + else + v = TREE_OPERAND (v, 0); + if (TREE_CODE (v) == COMPONENT_REF + && TREE_CODE (TREE_TYPE (TREE_OPERAND (v, 0))) + == RECORD_TYPE) + { + tree fld_chain = DECL_CHAIN (TREE_OPERAND (v, 1)); + for (; fld_chain; fld_chain = DECL_CHAIN (fld_chain)) + if (TREE_CODE (fld_chain) == FIELD_DECL) + break; + + if (fld_chain) + { + v = NULL_TREE; + break; + } + v = TREE_OPERAND (v, 0); + } + while (v != whole_var && TREE_CODE (v) == COMPONENT_REF) + if (TREE_CODE (TREE_TYPE (TREE_OPERAND (v, 0))) + != UNION_TYPE + && TREE_CODE (TREE_TYPE (TREE_OPERAND (v, 0))) + != QUAL_UNION_TYPE) + break; + else + v = TREE_OPERAND (v, 0); + if (v != whole_var) + v = NULL_TREE; + else + v = whole_var; + break; + default: + v = whole_var; + break; + } + if (v == whole_var) + var = whole_var; + } + + return var; +} + /* Compute an object size estimate for PTR, which is a ADDR_EXPR. OBJECT_SIZE_TYPE is the second argument from __builtin_dynamic_object_size. If unknown, return false, setting PSIZE to NULL_TREE. */ @@ -337,7 +449,8 @@ addr_dyn_object_size (struct object_size_info *osi, const_tree ptr, int object_size_type, tree *psize, tree *wholesizep = NULL) { - tree pt_var, pt_var_size = NULL_TREE, bytes; + struct function *fun = osi ? osi->fun : cfun; + tree pt_var, pt_var_size = NULL_TREE, var_size, bytes; gcc_assert (TREE_CODE (ptr) == ADDR_EXPR); @@ -353,22 +466,57 @@ addr_dyn_object_size (struct object_size_info *osi, const_tree ptr, if (!whole_var_size (osi, pt_var, object_size_type, &pt_var_size)) return false; - if (!pt_var_size) - return false; + var_size = pt_var_size; /* PTR points to a subobject of whole variable PT_VAR. */ if (pt_var != TREE_OPERAND (ptr, 0)) { - bytes = compute_object_offset (TREE_OPERAND (ptr, 0), pt_var); + tree var; + + if (object_size_type & 1) + var = get_closest_subobject (ptr, pt_var); + else + var = pt_var; + + if (var != pt_var) + { + var_size = TYPE_SIZE_UNIT (TREE_TYPE (var)); + if (!TREE_CONSTANT (var_size)) + var_size = get_or_create_ssa_default_def (fun, var_size); + if (!var_size) + return false; + } + else if (!pt_var_size) + return false; + + bytes = compute_object_offset (TREE_OPERAND (ptr, 0), var); if (bytes != error_mark_node) - bytes = size_for_offset (pt_var_size, bytes, pt_var_size); + { + tree cap_size = pt_var_size; + + /* For subobject sizes where the whole object is a structure, + restrict size to the size of the struct less the offset of the + subobject in the struct. */ + if (var != pt_var && pt_var_size && TREE_CODE (pt_var) == MEM_REF) + { + tree off = compute_object_offset (TREE_OPERAND (ptr, 0), pt_var); + if (off == error_mark_node) + off = size_zero_node; + else + off = fold_build2 (MIN_EXPR, sizetype, pt_var_size, off); + cap_size = fold_build2 (MINUS_EXPR, sizetype, pt_var_size, off); + } + bytes = size_for_offset (var_size, bytes, cap_size); + } } + else if (!pt_var_size) + return false; else bytes = pt_var_size; *psize = bytes == error_mark_node ? NULL_TREE : bytes; if (wholesizep) - *wholesizep = pt_var_size; + *wholesizep = var_size; return true; }