From patchwork Sat Dec 18 12:35:08 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Siddhesh Poyarekar X-Patchwork-Id: 1570485 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: bilbo.ozlabs.org; dkim=pass (1024-bit key; unprotected) header.d=gotplt.org header.i=@gotplt.org header.a=rsa-sha1 header.s=gotplt.org header.b=xaKLRBv+; dkim-atps=neutral Authentication-Results: ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=gcc.gnu.org (client-ip=8.43.85.97; helo=sourceware.org; envelope-from=gcc-patches-bounces+incoming=patchwork.ozlabs.org@gcc.gnu.org; receiver=) Received: from sourceware.org (ip-8-43-85-97.sourceware.org [8.43.85.97]) (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) by bilbo.ozlabs.org (Postfix) with ESMTPS id 4JGQMV14rmz9sVq for ; Sat, 18 Dec 2021 23:36:38 +1100 (AEDT) Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id ED773385843D for ; Sat, 18 Dec 2021 12:36:35 +0000 (GMT) X-Original-To: gcc-patches@gcc.gnu.org Delivered-To: gcc-patches@gcc.gnu.org Received: from coral.oak.relay.mailchannels.net (coral.oak.relay.mailchannels.net [23.83.215.39]) by sourceware.org (Postfix) with ESMTPS id C10DC385842D for ; Sat, 18 Dec 2021 12:35:27 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.1 sourceware.org C10DC385842D 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 76C7B8213B1; Sat, 18 Dec 2021 12:35:26 +0000 (UTC) Received: from pdx1-sub0-mail-a305.dreamhost.com (unknown [127.0.0.6]) (Authenticated sender: dreamhost) by relay.mailchannels.net (Postfix) with ESMTPA id BBA48820DDF; Sat, 18 Dec 2021 12:35:25 +0000 (UTC) X-Sender-Id: dreamhost|x-authsender|siddhesh@gotplt.org Received: from pdx1-sub0-mail-a305.dreamhost.com (pop.dreamhost.com [64.90.62.162]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384) by 100.120.81.136 (trex/6.4.3); Sat, 18 Dec 2021 12:35:26 +0000 X-MC-Relay: Bad X-MailChannels-SenderId: dreamhost|x-authsender|siddhesh@gotplt.org X-MailChannels-Auth-Id: dreamhost X-Eight-Lyrical: 488799f359fad40c_1639830926044_1340365374 X-MC-Loop-Signature: 1639830926044:2350479468 X-MC-Ingress-Time: 1639830926043 Received: from rhbox.redhat.com (unknown [1.6.40.51]) (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-a305.dreamhost.com (Postfix) with ESMTPSA id 4JGQL35JzVz2Q; Sat, 18 Dec 2021 04:35:23 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha1; c=relaxed/relaxed; d=gotplt.org; s=gotplt.org; t=1639830925; bh=JsfuuIWnGKqhTVZTuStoq34m+I0=; h=From:To:Cc:Subject:Date:Content-Transfer-Encoding; b=xaKLRBv+x0xpaIo2u1IOcS/PVmR0u6Lm3wR3fLch4fRgfYUDx4PMXRoXan+N1sxXo uKPL/5V/TM6L1/AuMHQXnUlLt13iLj3d6AyygLpH98NUoNmaDb3+HWbd9Yd+wAcu7r Xb7itynEHgGWHpUIhECVQ7owJ5y79qeAkg92AAng= From: Siddhesh Poyarekar To: gcc-patches@gcc.gnu.org Subject: [PATCH v5 1/4] tree-object-size: Support dynamic sizes in conditions Date: Sat, 18 Dec 2021 18:05:08 +0530 Message-Id: <20211218123511.139456-2-siddhesh@gotplt.org> X-Mailer: git-send-email 2.31.1 In-Reply-To: <20211218123511.139456-1-siddhesh@gotplt.org> References: <20211109190137.1107736-1-siddhesh@gotplt.org> <20211218123511.139456-1-siddhesh@gotplt.org> MIME-Version: 1.0 X-Spam-Status: No, score=-3038.1 required=5.0 tests=BAYES_00, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, GIT_PATCH_0, RCVD_IN_DNSWL_NONE, 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+incoming=patchwork.ozlabs.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: * builtins.c (fold_builtin_object_size): Adjust for dynamic size expressions. * tree-object-size.c: Include gimplify-me.h. (struct object_size_info): New member UNKNOWNS. (size_initval_p, size_usable_p, object_sizes_get_raw): New functions. (object_sizes_get): Return suitable gimple variable for object size. (bundle_sizes): New function. (object_sizes_set): Use it and handle dynamic object size expressions. (object_sizes_set_temp): New function. (size_for_offset): Adjust for dynamic size expressions. (emit_phi_nodes, propagate_unknowns, gimplify_size_expressions): New functions. (compute_builtin_object_size): Call gimplify_size_expressions for OST_DYNAMIC. (dynamic_object_size): New function. (cond_expr_object_size): Use it. (phi_dynamic_object_size): New function. (collect_object_sizes_for): Call it for OST_DYNAMIC. Adjust to accommodate dynamic object sizes. gcc/testsuite/ChangeLog: * gcc.dg/builtin-dynamic-object-size-0.c: New tests. * gcc.dg/builtin-dynamic-object-size-10.c: Add comment. * gcc.dg/builtin-dynamic-object-size-5-main.c: New file. * gcc.dg/builtin-dynamic-object-size-5.c: Use it and change test to dg-do run. * gcc.dg/builtin-object-size-5.c [!N]: Define N. (test1, test2, test3, test4) [__builtin_object_size]: Expect exact result for __builtin_dynamic_object_size. * gcc.dg/builtin-object-size-1.c [__builtin_object_size]: Expect exact size expressions for __builtin_dynamic_object_size. * gcc.dg/builtin-object-size-2.c [__builtin_object_size]: Likewise. * gcc.dg/builtin-object-size-3.c [__builtin_object_size]: Likewise. * gcc.dg/builtin-object-size-4.c [__builtin_object_size]: Likewise. * gcc.dg/builtin-object-size-5.c [__builtin_object_size]: Likewise. Signed-off-by: Siddhesh Poyarekar --- Changes since v4: - Propagate sameness of size and wholesize through PHI nodes whenever possible. Check and avoid emitting wholesize if it is the same as size. - Bail out and punt to __builtin_object_size if PHI node has any complex edges. Use insert_seq_on_edge to emit size PHI node edge values. - Free allocations in tests. gcc/builtins.c | 6 +- .../gcc.dg/builtin-dynamic-object-size-0.c | 77 +++ .../gcc.dg/builtin-dynamic-object-size-10.c | 2 + .../builtin-dynamic-object-size-5-main.c | 32 ++ .../gcc.dg/builtin-dynamic-object-size-5.c | 7 +- gcc/testsuite/gcc.dg/builtin-object-size-1.c | 119 +++- gcc/testsuite/gcc.dg/builtin-object-size-2.c | 92 ++++ gcc/testsuite/gcc.dg/builtin-object-size-3.c | 121 +++++ gcc/testsuite/gcc.dg/builtin-object-size-4.c | 78 +++ gcc/testsuite/gcc.dg/builtin-object-size-5.c | 22 +- gcc/tree-object-size.c | 509 +++++++++++++++++- 11 files changed, 1030 insertions(+), 35 deletions(-) create mode 100644 gcc/testsuite/gcc.dg/builtin-dynamic-object-size-0.c create mode 100644 gcc/testsuite/gcc.dg/builtin-dynamic-object-size-5-main.c diff --git a/gcc/builtins.c b/gcc/builtins.c index 00f6c5552bf..01c24f42540 100644 --- a/gcc/builtins.c +++ b/gcc/builtins.c @@ -10285,7 +10285,8 @@ fold_builtin_object_size (tree ptr, tree ost, enum built_in_function fcode) if (TREE_CODE (ptr) == ADDR_EXPR) { compute_builtin_object_size (ptr, object_size_type, &bytes); - if (int_fits_type_p (bytes, size_type_node)) + if ((object_size_type & OST_DYNAMIC) + || int_fits_type_p (bytes, size_type_node)) return fold_convert (size_type_node, bytes); } else if (TREE_CODE (ptr) == SSA_NAME) @@ -10294,7 +10295,8 @@ fold_builtin_object_size (tree ptr, tree ost, enum built_in_function fcode) later. Maybe subsequent passes will help determining it. */ if (compute_builtin_object_size (ptr, object_size_type, &bytes) - && int_fits_type_p (bytes, size_type_node)) + && ((object_size_type & OST_DYNAMIC) + || int_fits_type_p (bytes, size_type_node))) return fold_convert (size_type_node, bytes); } 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..81588cb28a6 --- /dev/null +++ b/gcc/testsuite/gcc.dg/builtin-dynamic-object-size-0.c @@ -0,0 +1,77 @@ +/* { 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 *ch; + + if (cond) + ch = __builtin_malloc (32); + else + ch = __builtin_malloc (64); + + size_t ret = __builtin_dynamic_object_size (ch, 0); + + __builtin_free (ch); + return ret; +} + +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); + size_t ret = __builtin_dynamic_object_size (cond ? ch : (void *) &bin, 0); + + __builtin_free (ch); + return ret; +} + +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-10.c b/gcc/testsuite/gcc.dg/builtin-dynamic-object-size-10.c index bc880a589ae..3a2d9821a44 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,7 @@ #define __builtin_object_size __builtin_dynamic_object_size #include "builtin-object-size-10.c" +/* early_objsz should resolve __builtin_dynamic_object_size like + __builtin_object_size. */ /* { 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-5-main.c b/gcc/testsuite/gcc.dg/builtin-dynamic-object-size-5-main.c new file mode 100644 index 00000000000..49f459b8cf2 --- /dev/null +++ b/gcc/testsuite/gcc.dg/builtin-dynamic-object-size-5-main.c @@ -0,0 +1,32 @@ +#ifdef N +typedef __SIZE_TYPE__ size_t; + +char buf[N]; + +void test1 (size_t); +void test2 (size_t); +void test3 (size_t); +void test4 (size_t); +void test5 (size_t); +void test6 (size_t); +void test7 (size_t); + +int +main (void) +{ + test1 (42); + test2 (42); + test3 (42); + test4 (42); + test5 (42); + test6 (42); + test7 (42); + return 0; +} +#else +int +main (void) +{ + return 0; +} +#endif 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..80b77dd5249 100644 --- a/gcc/testsuite/gcc.dg/builtin-dynamic-object-size-5.c +++ b/gcc/testsuite/gcc.dg/builtin-dynamic-object-size-5.c @@ -1,7 +1,6 @@ -/* { dg-do compile { target i?86-*-linux* i?86-*-gnu* x86_64-*-linux* } } */ -/* { dg-options "-O2" } */ +/* { dg-do run { target i?86-*-linux* i?86-*-gnu* x86_64-*-linux* } } */ +/* { dg-options "-O2 -DN=0x4000000" } */ +/* { dg-additional-sources "builtin-dynamic-object-size-5-main.c" } */ #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-object-size-1.c b/gcc/testsuite/gcc.dg/builtin-object-size-1.c index 0154f4e9695..265c87ed6fb 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 __builtin_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 __builtin_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 __builtin_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 __builtin_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 __builtin_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 __builtin_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 __builtin_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); } @@ -380,8 +474,13 @@ test6 (size_t x) for (i = 0; i < x; ++i) p = p + 4; +#ifdef __builtin_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); } @@ -436,21 +535,37 @@ test9 (unsigned cond) else p = &buf2[4]; +#ifdef __builtin_object_size + if (__builtin_object_size (&p[-4], 0) != (cond ? 6 : 10)) + abort (); +#else if (__builtin_object_size (&p[-4], 0) != 10) abort (); +#endif for (unsigned i = cond; i > 0; i--) p--; +#ifdef __builtin_object_size + if (__builtin_object_size (p, 0) != ((cond ? 2 : 6) + cond)) + abort (); +#else if (__builtin_object_size (p, 0) != 10) abort (); +#endif p = &y.c[8]; for (unsigned i = cond; i > 0; i--) p--; +#ifdef __builtin_object_size + if (__builtin_object_size (p, 0) + != sizeof (y) - __builtin_offsetof (struct A, c) - 8 + cond) + abort (); +#else if (__builtin_object_size (p, 0) != sizeof (y)) abort (); +#endif } int diff --git a/gcc/testsuite/gcc.dg/builtin-object-size-2.c b/gcc/testsuite/gcc.dg/builtin-object-size-2.c index 5cf29291aff..5051fea47c3 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 __builtin_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 __builtin_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 __builtin_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 __builtin_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 __builtin_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 __builtin_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 @@ -339,8 +411,13 @@ test5 (size_t x) for (i = 0; i < x; ++i) p = p + 4; +#ifdef __builtin_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); } @@ -394,21 +471,36 @@ test8 (unsigned cond) else p = &buf2[4]; +#ifdef __builtin_object_size + if (__builtin_object_size (&p[-4], 1) != (cond ? 6 : 10)) + abort (); +#else if (__builtin_object_size (&p[-4], 1) != 10) abort (); +#endif for (unsigned i = cond; i > 0; i--) p--; +#ifdef __builtin_object_size + if (__builtin_object_size (p, 1) != ((cond ? 2 : 6) + cond)) + abort (); +#else if (__builtin_object_size (p, 1) != 10) abort (); +#endif p = &y.c[8]; for (unsigned i = cond; i > 0; i--) p--; +#ifdef __builtin_object_size + if (__builtin_object_size (p, 1) != sizeof (y.c) - 8 + cond) + abort (); +#else if (__builtin_object_size (p, 1) != sizeof (y.c)) abort (); +#endif } int diff --git a/gcc/testsuite/gcc.dg/builtin-object-size-3.c b/gcc/testsuite/gcc.dg/builtin-object-size-3.c index 3a692c4e3d2..1d92627266b 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 __builtin_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 __builtin_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 __builtin_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 __builtin_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 __builtin_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 __builtin_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 __builtin_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 __builtin_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 __builtin_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 __builtin_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); } @@ -386,7 +487,11 @@ test6 (size_t x) for (i = 0; i < x; ++i) p = p + 4; +#ifdef __builtin_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); } @@ -442,22 +547,38 @@ test9 (unsigned cond) else p = &buf2[4]; +#ifdef __builtin_object_size + if (__builtin_object_size (&p[-4], 2) != (cond ? 6 : 10)) + abort (); +#else if (__builtin_object_size (&p[-4], 2) != 6) abort (); +#endif for (unsigned i = cond; i > 0; i--) p--; +#ifdef __builtin_object_size + if (__builtin_object_size (p, 2) != ((cond ? 2 : 6) + cond)) + abort (); +#else if (__builtin_object_size (p, 2) != 2) abort (); +#endif p = &y.c[8]; for (unsigned i = cond; i > 0; i--) p--; +#ifdef __builtin_object_size + if (__builtin_object_size (p, 2) + != sizeof (y) - __builtin_offsetof (struct A, c) - 8 + cond) + abort (); +#else if (__builtin_object_size (p, 2) != sizeof (y) - __builtin_offsetof (struct A, c) - 8) abort (); +#endif } int diff --git a/gcc/testsuite/gcc.dg/builtin-object-size-4.c b/gcc/testsuite/gcc.dg/builtin-object-size-4.c index 87381620cc9..9da3537a5f7 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 __builtin_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 __builtin_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 __builtin_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 __builtin_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 __builtin_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 __builtin_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 __builtin_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 __builtin_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 __builtin_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 __builtin_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 @@ -352,7 +411,11 @@ test5 (size_t x) for (i = 0; i < x; ++i) p = p + 4; +#ifdef __builtin_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); } @@ -407,21 +470,36 @@ test8 (unsigned cond) else p = &buf2[4]; +#ifdef __builtin_object_size + if (__builtin_object_size (&p[-4], 3) != (cond ? 6 : 10)) + abort (); +#else if (__builtin_object_size (&p[-4], 3) != 6) abort (); +#endif for (unsigned i = cond; i > 0; i--) p--; +#ifdef __builtin_object_size + if (__builtin_object_size (p, 3) != ((cond ? 2 : 6) + cond)) + abort (); +#else if (__builtin_object_size (p, 3) != 2) abort (); +#endif p = &y.c[8]; for (unsigned i = cond; i > 0; i--) p--; +#ifdef __builtin_object_size + if (__builtin_object_size (p, 3) != sizeof (y.c) - 8 + cond) + abort (); +#else if (__builtin_object_size (p, 3) != sizeof (y.c) - 8) abort (); +#endif } int diff --git a/gcc/testsuite/gcc.dg/builtin-object-size-5.c b/gcc/testsuite/gcc.dg/builtin-object-size-5.c index 8e63d9c7a5e..cb8f753b039 100644 --- a/gcc/testsuite/gcc.dg/builtin-object-size-5.c +++ b/gcc/testsuite/gcc.dg/builtin-object-size-5.c @@ -1,9 +1,13 @@ /* { dg-do compile { target i?86-*-linux* i?86-*-gnu* x86_64-*-linux* } } */ /* { dg-options "-O2" } */ +#ifndef N +# define N 0x40000000 +#endif + typedef __SIZE_TYPE__ size_t; extern void abort (void); -extern char buf[0x40000000]; +extern char buf[N]; void test1 (size_t x) @@ -13,7 +17,11 @@ test1 (size_t x) for (i = 0; i < x; ++i) p = p + 4; +#ifdef __builtin_object_size + if (__builtin_object_size (p, 0) != sizeof (buf) - 8 - 4 * x) +#else if (__builtin_object_size (p, 0) != sizeof (buf) - 8) +#endif abort (); } @@ -25,7 +33,11 @@ test2 (size_t x) for (i = 0; i < x; ++i) p = p + 4; +#ifdef __builtin_object_size + if (__builtin_object_size (p, 1) != sizeof (buf) - 8 - 4 * x) +#else if (__builtin_object_size (p, 1) != sizeof (buf) - 8) +#endif abort (); } @@ -37,7 +49,11 @@ test3 (size_t x) for (i = 0; i < x; ++i) p = p + 4; +#ifdef __builtin_object_size + if (__builtin_object_size (p, 2) != sizeof (buf) - 8 - 4 * x) +#else if (__builtin_object_size (p, 2) != 0) +#endif abort (); } @@ -49,7 +65,11 @@ test4 (size_t x) for (i = 0; i < x; ++i) p = p + 4; +#ifdef __builtin_object_size + if (__builtin_object_size (p, 3) != sizeof (buf) - 8 - 4 * x) +#else if (__builtin_object_size (p, 3) != 0) +#endif abort (); } diff --git a/gcc/tree-object-size.c b/gcc/tree-object-size.c index ee9ea1bfbfd..95cb44d9c7e 100644 --- a/gcc/tree-object-size.c +++ b/gcc/tree-object-size.c @@ -35,13 +35,14 @@ 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; unsigned char pass; bool changed; - bitmap visited, reexamine; + bitmap visited, reexamine, unknowns; unsigned int *depths; unsigned int *stack, *tos; }; @@ -74,7 +75,11 @@ static void check_for_plus_in_loops_1 (struct object_size_info *, tree, object_sizes[1] is upper bound for the object size and number of bytes till the end of the subobject (innermost array or field with address taken). object_sizes[2] is lower bound for the object size and number of bytes till - the end of the object and object_sizes[3] lower bound for subobject. */ + the end of the object and object_sizes[3] lower bound for subobject. + + For static object sizes, the object size and the bytes till the end of the + object are both INTEGER_CST. In the dynamic case, they are finally either a + gimple variable or an INTEGER_CST. */ static vec object_sizes[OST_END]; /* Bitmaps what object sizes have been computed already. */ @@ -83,6 +88,15 @@ static bitmap computed[OST_END]; /* Maximum value of offset we consider to be addition. */ static unsigned HOST_WIDE_INT offset_limit; +/* Return true if VAL is represents an initial size for OBJECT_SIZE_TYPE. */ + +static inline bool +size_initval_p (tree val, int object_size_type) +{ + return ((object_size_type & OST_MINIMUM) + ? integer_all_onesp (val) : integer_zerop (val)); +} + /* Return true if VAL is represents an unknown size for OBJECT_SIZE_TYPE. */ static inline bool @@ -92,6 +106,15 @@ size_unknown_p (tree val, int object_size_type) ? integer_zerop (val) : integer_all_onesp (val)); } +/* Return true if VAL is usable as an object size in the object_sizes + vectors. */ + +static inline bool +size_usable_p (tree val) +{ + return TREE_CODE (val) == SSA_NAME || TREE_CODE (val) == INTEGER_CST; +} + /* Return a tree with initial value for OBJECT_SIZE_TYPE. */ static inline tree @@ -136,17 +159,43 @@ object_sizes_unknown_p (int object_size_type, unsigned varno) object_size_type); } -/* Return size for VARNO corresponding to OSI. If WHOLE is true, return the - whole object size. */ +/* Return the raw size expression for VARNO corresponding to OSI. This returns + the TREE_VEC as is and should only be used during gimplification. */ + +static inline object_size +object_sizes_get_raw (struct object_size_info *osi, unsigned varno) +{ + gcc_assert (osi->pass != 0); + return object_sizes[osi->object_size_type][varno]; +} + +/* Return a size tree for VARNO corresponding to OSI. If WHOLE is true, return + the whole object size. Use this for building size expressions based on size + of VARNO. */ static inline tree object_sizes_get (struct object_size_info *osi, unsigned varno, bool whole = false) { + tree ret; + int object_size_type = osi->object_size_type; + if (whole) - return object_sizes[osi->object_size_type][varno].wholesize; + ret = object_sizes[object_size_type][varno].wholesize; else - return object_sizes[osi->object_size_type][varno].size; + ret = object_sizes[object_size_type][varno].size; + + if (object_size_type & OST_DYNAMIC) + { + if (TREE_CODE (ret) == MODIFY_EXPR) + return TREE_OPERAND (ret, 0); + else if (TREE_CODE (ret) == TREE_VEC) + return TREE_VEC_ELT (ret, TREE_VEC_LENGTH (ret) - 1); + else + gcc_checking_assert (size_usable_p (ret)); + } + + return ret; } /* Set size for VARNO corresponding to OSI to VAL. */ @@ -161,28 +210,116 @@ object_sizes_initialize (struct object_size_info *osi, unsigned varno, object_sizes[object_size_type][varno].wholesize = wholeval; } +/* Return a MODIFY_EXPR for cases where SSA and EXPR have the same type. The + TREE_VEC is returned only in case of PHI nodes. */ + +static tree +bundle_sizes (tree name, tree expr) +{ + gcc_checking_assert (TREE_TYPE (name) == sizetype); + + if (TREE_CODE (expr) == TREE_VEC) + { + TREE_VEC_ELT (expr, TREE_VEC_LENGTH (expr) - 1) = name; + return expr; + } + + gcc_checking_assert (types_compatible_p (TREE_TYPE (expr), sizetype)); + return build2 (MODIFY_EXPR, sizetype, name, expr); +} + /* Set size for VARNO corresponding to OSI to VAL if it is the new minimum or - maximum. */ + maximum. For static sizes, each element of TREE_VEC is always INTEGER_CST + throughout the computation. For dynamic sizes, each element may either be a + gimple variable, a MODIFY_EXPR or a TREE_VEC. The MODIFY_EXPR is for + expressions that need to be gimplified. TREE_VECs are special, they're + emitted only for GIMPLE_PHI and the PHI result variable is the last element + of the vector. */ -static inline bool +static bool object_sizes_set (struct object_size_info *osi, unsigned varno, tree val, tree wholeval) { int object_size_type = osi->object_size_type; object_size osize = object_sizes[object_size_type][varno]; + bool changed = true; tree oldval = osize.size; tree old_wholeval = osize.wholesize; - enum tree_code code = object_size_type & OST_MINIMUM ? MIN_EXPR : MAX_EXPR; + if (object_size_type & OST_DYNAMIC) + { + if (bitmap_bit_p (osi->reexamine, varno)) + { + if (size_unknown_p (val, object_size_type)) + { + oldval = object_sizes_get (osi, varno); + old_wholeval = object_sizes_get (osi, varno, true); + bitmap_set_bit (osi->unknowns, SSA_NAME_VERSION (oldval)); + bitmap_set_bit (osi->unknowns, SSA_NAME_VERSION (old_wholeval)); + bitmap_clear_bit (osi->reexamine, varno); + } + else + { + val = bundle_sizes (oldval, val); + wholeval = bundle_sizes (old_wholeval, wholeval); + } + } + else + { + gcc_checking_assert (size_initval_p (oldval, object_size_type)); + gcc_checking_assert (size_initval_p (old_wholeval, + object_size_type)); + /* For dynamic object sizes, all object sizes that are not gimple + variables will need to be gimplified. */ + if (wholeval != val && !size_usable_p (wholeval)) + { + bitmap_set_bit (osi->reexamine, varno); + wholeval = bundle_sizes (make_ssa_name (sizetype), wholeval); + } + if (!size_usable_p (val)) + { + bitmap_set_bit (osi->reexamine, varno); + tree newval = bundle_sizes (make_ssa_name (sizetype), val); + if (val == wholeval) + wholeval = newval; + val = newval; + } + /* If the new value is a temporary variable, mark it for + reexamination. */ + else if (TREE_CODE (val) == SSA_NAME && !SSA_NAME_DEF_STMT (val)) + bitmap_set_bit (osi->reexamine, varno); + } + } + else + { + enum tree_code code = (object_size_type & OST_MINIMUM + ? MIN_EXPR : MAX_EXPR); - val = size_binop (code, val, oldval); - wholeval = size_binop (code, wholeval, old_wholeval); + val = size_binop (code, val, oldval); + wholeval = size_binop (code, wholeval, old_wholeval); + changed = (tree_int_cst_compare (val, oldval) != 0 + || tree_int_cst_compare (old_wholeval, wholeval) != 0); + } object_sizes[object_size_type][varno].size = val; object_sizes[object_size_type][varno].wholesize = wholeval; - return (tree_int_cst_compare (oldval, val) != 0 - || tree_int_cst_compare (old_wholeval, wholeval) != 0); + + return changed; +} + +/* Set temporary SSA names for object size and whole size to resolve dependency + loops in dynamic size computation. */ + +static inline void +object_sizes_set_temp (struct object_size_info *osi, unsigned varno) +{ + tree val = object_sizes_get (osi, varno); + + if (size_initval_p (val, osi->object_size_type)) + object_sizes_set (osi, varno, + make_ssa_name (sizetype), + make_ssa_name (sizetype)); } /* Initialize OFFSET_LIMIT variable. */ @@ -204,14 +341,15 @@ static tree size_for_offset (tree sz, tree offset, tree wholesize = NULL_TREE) { gcc_checking_assert (TREE_CODE (offset) == INTEGER_CST); - gcc_checking_assert (TREE_CODE (sz) == INTEGER_CST); gcc_checking_assert (types_compatible_p (TREE_TYPE (sz), sizetype)); /* For negative offsets, if we have a distinct WHOLESIZE, use it to get a net offset from the whole object. */ - if (wholesize && tree_int_cst_compare (sz, wholesize)) + if (wholesize && wholesize != sz + && (TREE_CODE (sz) != INTEGER_CST + || TREE_CODE (wholesize) != INTEGER_CST + || tree_int_cst_compare (sz, wholesize))) { - gcc_checking_assert (TREE_CODE (wholesize) == INTEGER_CST); gcc_checking_assert (types_compatible_p (TREE_TYPE (wholesize), sizetype)); @@ -228,13 +366,16 @@ size_for_offset (tree sz, tree offset, tree wholesize = NULL_TREE) if (!types_compatible_p (TREE_TYPE (offset), sizetype)) fold_convert (sizetype, offset); - if (integer_zerop (offset)) - return sz; + if (TREE_CODE (offset) == INTEGER_CST) + { + if (integer_zerop (offset)) + return sz; - /* Negative or too large offset even after adjustment, cannot be within - bounds of an object. */ - if (compare_tree_int (offset, offset_limit) > 0) - return size_zero_node; + /* Negative or too large offset even after adjustment, cannot be within + bounds of an object. */ + if (compare_tree_int (offset, offset_limit) > 0) + return size_zero_node; + } return size_binop (MINUS_EXPR, size_binop (MAX_EXPR, sz, offset), offset); } @@ -671,6 +812,201 @@ pass_through_call (const gcall *call) return NULL_TREE; } +/* Emit PHI nodes for size expressions fo. */ + +static void +emit_phi_nodes (gimple *stmt, tree size, tree wholesize) +{ + tree phires; + gphi *wholephi = NULL; + + if (wholesize != size) + { + phires = TREE_VEC_ELT (wholesize, TREE_VEC_LENGTH (wholesize) - 1); + wholephi = create_phi_node (phires, gimple_bb (stmt)); + } + + phires = TREE_VEC_ELT (size, TREE_VEC_LENGTH (size) - 1); + gphi *phi = create_phi_node (phires, gimple_bb (stmt)); + gphi *obj_phi = as_a (stmt); + + gcc_checking_assert (TREE_CODE (wholesize) == TREE_VEC); + gcc_checking_assert (TREE_CODE (size) == TREE_VEC); + + for (unsigned i = 0; i < gimple_phi_num_args (stmt); i++) + { + gimple_seq seq = NULL; + tree wsz = TREE_VEC_ELT (wholesize, i); + tree sz = TREE_VEC_ELT (size, i); + + /* If we built an expression, we will need to build statements + and insert them on the edge right away. */ + if (TREE_CODE (wsz) != SSA_NAME) + wsz = force_gimple_operand (wsz, &seq, true, NULL); + if (TREE_CODE (sz) != SSA_NAME) + { + gimple_seq s; + sz = force_gimple_operand (sz, &s, true, NULL); + gimple_seq_add_seq (&seq, s); + } + + if (seq) + gsi_insert_seq_on_edge (gimple_phi_arg_edge (obj_phi, i), seq); + + if (wholephi) + add_phi_arg (wholephi, wsz, + gimple_phi_arg_edge (obj_phi, i), + gimple_phi_arg_location (obj_phi, i)); + + add_phi_arg (phi, sz, + gimple_phi_arg_edge (obj_phi, i), + gimple_phi_arg_location (obj_phi, i)); + } +} + +/* Descend through EXPR and return size_unknown if it uses any SSA variable + object_size_set or object_size_set_temp generated, which turned out to be + size_unknown, as noted in UNKNOWNS. */ + +static tree +propagate_unknowns (object_size_info *osi, tree expr) +{ + int object_size_type = osi->object_size_type; + + switch (TREE_CODE (expr)) + { + case SSA_NAME: + if (bitmap_bit_p (osi->unknowns, SSA_NAME_VERSION (expr))) + return size_unknown (object_size_type); + return expr; + + case MIN_EXPR: + case MAX_EXPR: + { + tree res = propagate_unknowns (osi, TREE_OPERAND (expr, 0)); + if (size_unknown_p (res, object_size_type)) + return res; + + res = propagate_unknowns (osi, TREE_OPERAND (expr, 1)); + if (size_unknown_p (res, object_size_type)) + return res; + + return expr; + } + case MODIFY_EXPR: + { + tree res = propagate_unknowns (osi, TREE_OPERAND (expr, 1)); + if (size_unknown_p (res, object_size_type)) + return res; + return expr; + } + case TREE_VEC: + for (int i = 0; i < TREE_VEC_LENGTH (expr); i++) + { + tree res = propagate_unknowns (osi, TREE_VEC_ELT (expr, i)); + if (size_unknown_p (res, object_size_type)) + return res; + } + return expr; + case PLUS_EXPR: + case MINUS_EXPR: + { + tree res = propagate_unknowns (osi, TREE_OPERAND (expr, 0)); + if (size_unknown_p (res, object_size_type)) + return res; + + return expr; + } + default: + return expr; + } +} + +/* Walk through size expressions that need reexamination and generate + statements for them. */ + +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 reexamine = BITMAP_ALLOC (NULL); + bitmap_copy (reexamine, osi->reexamine); + do + { + changed = false; + EXECUTE_IF_SET_IN_BITMAP (reexamine, 0, i, bi) + { + object_size cur = object_sizes_get_raw (osi, i); + + if (size_unknown_p (propagate_unknowns (osi, cur.size), + object_size_type) + || size_unknown_p (propagate_unknowns (osi, cur.wholesize), + object_size_type)) + { + object_sizes_set (osi, i, + size_unknown (object_size_type), + size_unknown (object_size_type)); + changed = true; + } + } + bitmap_copy (reexamine, osi->reexamine); + } + while (changed); + + /* Release all unknowns. */ + EXECUTE_IF_SET_IN_BITMAP (osi->unknowns, 0, i, bi) + release_ssa_name (ssa_name (i)); + + /* Expand all size expressions to put their definitions close to the objects + for whom size is being computed. */ + EXECUTE_IF_SET_IN_BITMAP (osi->reexamine, 0, i, bi) + { + gimple_seq seq = NULL; + object_size osize = object_sizes_get_raw (osi, i); + + gimple *stmt = SSA_NAME_DEF_STMT (ssa_name (i)); + enum gimple_code code = gimple_code (stmt); + + /* PHI nodes need special attention. */ + if (code == GIMPLE_PHI) + emit_phi_nodes (stmt, osize.size, osize.wholesize); + else + { + tree size_expr = NULL_TREE; + + /* Bundle wholesize in with the size to gimplify if needed. */ + if (osize.wholesize != osize.size + && !size_usable_p (osize.wholesize)) + size_expr = size_binop (COMPOUND_EXPR, + osize.wholesize, + osize.size); + else if (!size_usable_p (osize.size)) + size_expr = osize.size; + + if (size_expr) + { + gimple_stmt_iterator gsi; + if (code == GIMPLE_NOP) + gsi = gsi_start_bb (single_succ (ENTRY_BLOCK_PTR_FOR_FN (cfun))); + else + gsi = gsi_for_stmt (stmt); + + force_gimple_operand (size_expr, &seq, true, NULL); + gsi_insert_seq_before (&gsi, seq, GSI_CONTINUE_LINKING); + } + } + + /* We're done, so replace the MODIFY_EXPRs with the SSA names. */ + object_sizes_initialize (osi, i, + object_sizes_get (osi, i), + object_sizes_get (osi, i, true)); + } +} /* Compute __builtin_object_size value for PTR and set *PSIZE to the resulting value. If the declared object is known and PDECL @@ -749,9 +1085,15 @@ 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; + + if (object_size_type & OST_DYNAMIC) + osi.unknowns = BITMAP_ALLOC (NULL); + else + { + 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 @@ -761,6 +1103,14 @@ compute_builtin_object_size (tree ptr, int object_size_type, osi.changed = false; collect_object_sizes_for (&osi, ptr); + if (object_size_type & OST_DYNAMIC) + { + osi.pass = 1; + gimplify_size_expressions (&osi); + BITMAP_FREE (osi.unknowns); + bitmap_clear (osi.reexamine); + } + /* Second pass: keep recomputing object sizes of variables that need reexamination, until no object sizes are increased or all object sizes are computed. */ @@ -1007,6 +1357,25 @@ plus_stmt_object_size (struct object_size_info *osi, tree var, gimple *stmt) return reexamine; } +static void +dynamic_object_size (struct object_size_info *osi, tree var, + tree *size, tree *wholesize) +{ + int object_size_type = osi->object_size_type; + + if (TREE_CODE (var) == SSA_NAME) + { + unsigned varno = SSA_NAME_VERSION (var); + + collect_object_sizes_for (osi, var); + *size = object_sizes_get (osi, varno); + *wholesize = object_sizes_get (osi, varno, true); + } + else if (TREE_CODE (var) == ADDR_EXPR) + addr_object_size (osi, var, object_size_type, size, wholesize); + else + *size = *wholesize = size_unknown (object_size_type); +} /* Compute object_sizes for VAR, defined at STMT, which is a COND_EXPR. Return true if the object size might need reexamination @@ -1028,6 +1397,33 @@ cond_expr_object_size (struct object_size_info *osi, tree var, gimple *stmt) then_ = gimple_assign_rhs2 (stmt); else_ = gimple_assign_rhs3 (stmt); + if (object_size_type & OST_DYNAMIC) + { + tree then_size, then_wholesize, else_size, else_wholesize; + + dynamic_object_size (osi, then_, &then_size, &then_wholesize); + if (!size_unknown_p (then_size, object_size_type)) + dynamic_object_size (osi, else_, &else_size, &else_wholesize); + + tree cond_size, cond_wholesize; + if (size_unknown_p (then_size, object_size_type) + || size_unknown_p (else_size, object_size_type)) + cond_size = cond_wholesize = size_unknown (object_size_type); + else + { + cond_size = fold_build3 (COND_EXPR, sizetype, + gimple_assign_rhs1 (stmt), + then_size, else_size); + cond_wholesize = fold_build3 (COND_EXPR, sizetype, + gimple_assign_rhs1 (stmt), + then_wholesize, else_wholesize); + } + + object_sizes_set (osi, varno, cond_size, cond_wholesize); + + return false; + } + if (TREE_CODE (then_) == SSA_NAME) reexamine |= merge_object_sizes (osi, var, then_); else @@ -1044,6 +1440,57 @@ cond_expr_object_size (struct object_size_info *osi, tree var, gimple *stmt) return reexamine; } +/* Compute an object size expression for VAR, which is the result of a PHI + node. */ + +static void +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); + bool wholesize_needed = false; + + /* The extra space is for the PHI result at the end, which object_sizes_set + sets for us. */ + tree sizes = make_tree_vec (num_args + 1); + tree wholesizes = make_tree_vec (num_args + 1); + + /* Bail out if the size of any of the PHI arguments cannot be + determined. */ + for (i = 0; i < num_args; i++) + { + edge e = gimple_phi_arg_edge (as_a (stmt), i); + if (e->flags & EDGE_COMPLEX) + break; + + tree rhs = gimple_phi_arg_def (stmt, i); + tree size, wholesize; + + dynamic_object_size (osi, rhs, &size, &wholesize); + + if (size_unknown_p (size, object_size_type)) + break; + + if (size != wholesize) + wholesize_needed = true; + + TREE_VEC_ELT (sizes, i) = size; + TREE_VEC_ELT (wholesizes, i) = wholesize; + } + + if (i < num_args) + sizes = wholesizes = size_unknown (object_size_type); + + /* Point to the same TREE_VEC so that we can avoid emitting two PHI + nodes. */ + if (!wholesize_needed) + wholesizes = sizes; + + object_sizes_set (osi, varno, sizes, wholesizes); +} + /* 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 @@ -1089,6 +1536,9 @@ collect_object_sizes_for (struct object_size_info *osi, tree var) { /* Found a dependency loop. Mark the variable for later re-examination. */ + if (object_size_type & OST_DYNAMIC) + object_sizes_set_temp (osi, varno); + bitmap_set_bit (osi->reexamine, varno); if (dump_file && (dump_flags & TDF_DETAILS)) { @@ -1170,6 +1620,12 @@ collect_object_sizes_for (struct object_size_info *osi, tree var) { unsigned i; + if (object_size_type & OST_DYNAMIC) + { + phi_dynamic_object_size (osi, var); + break; + } + for (i = 0; i < gimple_phi_num_args (stmt); i++) { tree rhs = gimple_phi_arg (stmt, i)->def; @@ -1192,7 +1648,8 @@ collect_object_sizes_for (struct object_size_info *osi, tree var) if (! reexamine || object_sizes_unknown_p (object_size_type, varno)) { bitmap_set_bit (computed[object_size_type], varno); - bitmap_clear_bit (osi->reexamine, varno); + if (!(object_size_type & OST_DYNAMIC)) + bitmap_clear_bit (osi->reexamine, varno); } else { From patchwork Sat Dec 18 12:35:09 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Siddhesh Poyarekar X-Patchwork-Id: 1570484 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: bilbo.ozlabs.org; dkim=pass (1024-bit key; unprotected) header.d=gotplt.org header.i=@gotplt.org header.a=rsa-sha1 header.s=gotplt.org header.b=iWaWkGat; dkim-atps=neutral Authentication-Results: ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=gcc.gnu.org (client-ip=8.43.85.97; helo=sourceware.org; envelope-from=gcc-patches-bounces+incoming=patchwork.ozlabs.org@gcc.gnu.org; receiver=) Received: from sourceware.org (server2.sourceware.org [8.43.85.97]) (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) by bilbo.ozlabs.org (Postfix) with ESMTPS id 4JGQLv6FLfz9sVq for ; Sat, 18 Dec 2021 23:36:07 +1100 (AEDT) Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id C09EC3858432 for ; Sat, 18 Dec 2021 12:36:05 +0000 (GMT) X-Original-To: gcc-patches@gcc.gnu.org Delivered-To: gcc-patches@gcc.gnu.org Received: from quail.birch.relay.mailchannels.net (quail.birch.relay.mailchannels.net [23.83.209.151]) by sourceware.org (Postfix) with ESMTPS id B1293385803A for ; Sat, 18 Dec 2021 12:35:29 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.1 sourceware.org B1293385803A 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 5110E6C07A5; Sat, 18 Dec 2021 12:35:28 +0000 (UTC) Received: from pdx1-sub0-mail-a305.dreamhost.com (unknown [127.0.0.6]) (Authenticated sender: dreamhost) by relay.mailchannels.net (Postfix) with ESMTPA id A57C46C071A; Sat, 18 Dec 2021 12:35:27 +0000 (UTC) X-Sender-Id: dreamhost|x-authsender|siddhesh@gotplt.org Received: from pdx1-sub0-mail-a305.dreamhost.com (pop.dreamhost.com [64.90.62.162]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384) by 100.118.248.87 (trex/6.4.3); Sat, 18 Dec 2021 12:35:28 +0000 X-MC-Relay: Neutral X-MailChannels-SenderId: dreamhost|x-authsender|siddhesh@gotplt.org X-MailChannels-Auth-Id: dreamhost X-Average-Oafish: 061ac5a14b1647dd_1639830927931_2140372071 X-MC-Loop-Signature: 1639830927931:3877870807 X-MC-Ingress-Time: 1639830927931 Received: from rhbox.redhat.com (unknown [1.6.40.51]) (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-a305.dreamhost.com (Postfix) with ESMTPSA id 4JGQL62Hhmz26; Sat, 18 Dec 2021 04:35:25 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha1; c=relaxed/relaxed; d=gotplt.org; s=gotplt.org; t=1639830927; bh=P7peP8jscjVqGyL8jTqzSzZLGnA=; h=From:To:Cc:Subject:Date:Content-Transfer-Encoding; b=iWaWkGatax6DEe7YqmqCxFkWMH9PawTpP9v5uVXjhe6SF5TJNamWR7zVYRlx+UYWK zkfSBhQsFzxBQKLLwGern5DFtxQnfhAyj4eBZbkGeW8h+otYSBN8tdxWbnXQkTWb+9 lcqDTBdnPBa0QHFG94qTjrw0dtDAm9NL7Eqs4l/0= From: Siddhesh Poyarekar To: gcc-patches@gcc.gnu.org Subject: [PATCH v5 2/4] tree-object-size: Handle function parameters Date: Sat, 18 Dec 2021 18:05:09 +0530 Message-Id: <20211218123511.139456-3-siddhesh@gotplt.org> X-Mailer: git-send-email 2.31.1 In-Reply-To: <20211218123511.139456-1-siddhesh@gotplt.org> References: <20211109190137.1107736-1-siddhesh@gotplt.org> <20211218123511.139456-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_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+incoming=patchwork.ozlabs.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 | 11 ++++ gcc/tree-object-size.c | 50 ++++++++++++++++++- 2 files changed, 60 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 81588cb28a6..7616ffa4cf0 100644 --- a/gcc/testsuite/gcc.dg/builtin-dynamic-object-size-0.c +++ b/gcc/testsuite/gcc.dg/builtin-dynamic-object-size-0.c @@ -51,6 +51,14 @@ test_deploop (size_t sz, size_t cond) return __builtin_dynamic_object_size (bin, 0); } +size_t +__attribute__ ((access (__read_write__, 1, 2))) +__attribute__ ((noinline)) +test_parmsz_simple (void *obj, size_t sz) +{ + return __builtin_dynamic_object_size (obj, 0); +} + unsigned nfails = 0; #define FAIL() ({ \ @@ -69,6 +77,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 95cb44d9c7e..bf33ac93b93 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" @@ -1440,6 +1441,53 @@ cond_expr_object_size (struct object_size_info *osi, tree var, gimple *stmt) return reexamine; } +/* Find size of an object passed as a parameter to the function. */ + +static void +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 (!(object_size_type & OST_DYNAMIC) || !POINTER_TYPE_P (TREE_TYPE (parm))) + expr_object_size (osi, var, 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))); + tree sz = NULL_TREE; + + 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))) + { + 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); + } + } + } + if (!sz) + sz = size_unknown (object_size_type); + + object_sizes_set (osi, SSA_NAME_VERSION (var), sz, sz); +} + /* Compute an object size expression for VAR, which is the result of a PHI node. */ @@ -1610,7 +1658,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) - expr_object_size (osi, var, SSA_NAME_VAR (var)); + parm_object_size (osi, var); else /* Uninitialized SSA names point nowhere. */ unknown_object_size (osi, var); From patchwork Sat Dec 18 12:35:10 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Siddhesh Poyarekar X-Patchwork-Id: 1570486 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: bilbo.ozlabs.org; dkim=pass (1024-bit key; unprotected) header.d=gotplt.org header.i=@gotplt.org header.a=rsa-sha1 header.s=gotplt.org header.b=bpJDnE0U; dkim-atps=neutral Authentication-Results: ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=gcc.gnu.org (client-ip=8.43.85.97; helo=sourceware.org; envelope-from=gcc-patches-bounces+incoming=patchwork.ozlabs.org@gcc.gnu.org; receiver=) Received: from sourceware.org (ip-8-43-85-97.sourceware.org [8.43.85.97]) (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) by bilbo.ozlabs.org (Postfix) with ESMTPS id 4JGQNH0ZH9z9sVq for ; Sat, 18 Dec 2021 23:37:19 +1100 (AEDT) Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id E2EBC3858033 for ; Sat, 18 Dec 2021 12:37:16 +0000 (GMT) X-Original-To: gcc-patches@gcc.gnu.org Delivered-To: gcc-patches@gcc.gnu.org Received: from olivedrab.birch.relay.mailchannels.net (olivedrab.birch.relay.mailchannels.net [23.83.209.135]) by sourceware.org (Postfix) with ESMTPS id F2EAB385800D for ; Sat, 18 Dec 2021 12:35:30 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.1 sourceware.org F2EAB385800D 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 F34B66C07AA; Sat, 18 Dec 2021 12:35:29 +0000 (UTC) Received: from pdx1-sub0-mail-a305.dreamhost.com (unknown [127.0.0.6]) (Authenticated sender: dreamhost) by relay.mailchannels.net (Postfix) with ESMTPA id 894936C07A6; Sat, 18 Dec 2021 12:35:29 +0000 (UTC) X-Sender-Id: dreamhost|x-authsender|siddhesh@gotplt.org Received: from pdx1-sub0-mail-a305.dreamhost.com (pop.dreamhost.com [64.90.62.162]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384) by 100.124.6.96 (trex/6.4.3); Sat, 18 Dec 2021 12:35:29 +0000 X-MC-Relay: Neutral X-MailChannels-SenderId: dreamhost|x-authsender|siddhesh@gotplt.org X-MailChannels-Auth-Id: dreamhost X-Towering-Soft: 232eb1055c4f551f_1639830929811_3721036417 X-MC-Loop-Signature: 1639830929811:1480934908 X-MC-Ingress-Time: 1639830929811 Received: from rhbox.redhat.com (unknown [1.6.40.51]) (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-a305.dreamhost.com (Postfix) with ESMTPSA id 4JGQL80vllz2Q; Sat, 18 Dec 2021 04:35:27 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha1; c=relaxed/relaxed; d=gotplt.org; s=gotplt.org; t=1639830929; bh=NZKLZWfPoGADQp72n1eCq1FFGNc=; h=From:To:Cc:Subject:Date:Content-Transfer-Encoding; b=bpJDnE0UqUl7m6PTbYkG+Qz2f2lrqpd4LOx2PlaeUgGxKWM0643OUDjikx4SZMx2m ATtIpoOOChc2x4ePL5yjMEQVn5s8waTFlbYxYT3fQ2eM/0l8Cxd7QTU1U5uWscazoi dj673pMQoG2Hd+aHyIgo4UZih2aoY/Ez2a2W0ZXA= From: Siddhesh Poyarekar To: gcc-patches@gcc.gnu.org Subject: [PATCH v5 3/4] tree-object-size: Handle GIMPLE_CALL Date: Sat, 18 Dec 2021 18:05:10 +0530 Message-Id: <20211218123511.139456-4-siddhesh@gotplt.org> X-Mailer: git-send-email 2.31.1 In-Reply-To: <20211218123511.139456-1-siddhesh@gotplt.org> References: <20211109190137.1107736-1-siddhesh@gotplt.org> <20211218123511.139456-1-siddhesh@gotplt.org> MIME-Version: 1.0 X-Spam-Status: No, score=-3038.2 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_H3, RCVD_IN_MSPIKE_WL, 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+incoming=patchwork.ozlabs.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) [__builtin_object_size]: Alter expected result for dynamic object size. * gcc.dg/builtin-object-size-2.c (test1) [__builtin_object_size]: Likewise. * gcc.dg/builtin-object-size-3.c (test1) [__builtin_object_size]: Likewise. * gcc.dg/builtin-object-size-4.c (test1) [__builtin_object_size]: Likewise. Signed-off-by: Siddhesh Poyarekar --- Changes since v4: - Free allocations in tests. .../gcc.dg/builtin-dynamic-object-size-0.c | 251 +++++++++++++++++- 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 | 22 +- 6 files changed, 307 insertions(+), 8 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 7616ffa4cf0..d67cf4a3c07 100644 --- a/gcc/testsuite/gcc.dg/builtin-dynamic-object-size-0.c +++ b/gcc/testsuite/gcc.dg/builtin-dynamic-object-size-0.c @@ -4,6 +4,73 @@ 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 *ch = unknown_allocator (cnt, sz); + size_t ret = __builtin_dynamic_object_size (ch, 0); + __builtin_free (ch); + return ret; +} + +/* Malloc-like allocator. */ + +size_t +__attribute__ ((noinline)) +test_malloc (size_t sz) +{ + void *ch = alloc_func (sz); + size_t ret = __builtin_dynamic_object_size (ch, 0); + __builtin_free (ch); + return ret; +} + +size_t +__attribute__ ((noinline)) +test_builtin_malloc (size_t sz) +{ + void *ch = __builtin_malloc (sz); + size_t ret = __builtin_dynamic_object_size (ch, 0); + __builtin_free (ch); + return ret; +} + +size_t +__attribute__ ((noinline)) +test_builtin_malloc_cond (int cond) +{ + void *ch = __builtin_malloc (cond ? 32 : 64); + size_t ret = __builtin_dynamic_object_size (ch, 0); + __builtin_free (ch); + return ret; +} + size_t __attribute__ ((noinline)) test_builtin_malloc_condphi (int cond) @@ -21,6 +88,95 @@ test_builtin_malloc_condphi (int cond) return ret; } +size_t +__attribute__ ((noinline)) +test_builtin_malloc_condphi2 (int cond, size_t in) +{ + void *ch; + + if (cond) + ch = __builtin_malloc (in); + else + ch = __builtin_malloc (64); + + size_t ret = __builtin_dynamic_object_size (ch, 0); + + __builtin_free (ch); + return ret; +} + +size_t +__attribute__ ((noinline)) +test_builtin_malloc_condphi3 (int cond, size_t in, size_t in2) +{ + void *ch; + + if (cond) + ch = __builtin_malloc (in); + else + ch = __builtin_malloc (in2); + + size_t ret = __builtin_dynamic_object_size (ch, 0); + + __builtin_free (ch); + return ret; +} + +size_t +__attribute__ ((noinline)) +test_builtin_malloc_condphi4 (size_t sz, int cond) +{ + char *a = __builtin_malloc (sz); + char b[sz / 2]; + + size_t ret = __builtin_dynamic_object_size (cond ? b : (void *) &a, 0); + __builtin_free (a); + return ret; +} + +size_t +__attribute__ ((noinline)) +test_builtin_malloc_condphi5 (size_t sz, int cond, char *c) +{ + char *a = __builtin_malloc (sz); + + size_t ret = __builtin_dynamic_object_size (cond ? c : (void *) &a, 0); + __builtin_free (a); + return ret; +} + +/* Calloc-like allocator. */ + +size_t +__attribute__ ((noinline)) +test_calloc (size_t cnt, size_t sz) +{ + void *ch = calloc_func (cnt, sz); + size_t ret = __builtin_dynamic_object_size (ch, 0); + __builtin_free (ch); + return ret; +} + +size_t +__attribute__ ((noinline)) +test_builtin_calloc (size_t cnt, size_t sz) +{ + void *ch = __builtin_calloc (cnt, sz); + size_t ret = __builtin_dynamic_object_size (ch, 0); + __builtin_free (ch); + return ret; +} + +size_t +__attribute__ ((noinline)) +test_builtin_calloc_cond (int cond1, int cond2) +{ + void *ch = __builtin_calloc (cond1 ? 32 : 64, cond2 ? 1024 : 16); + size_t ret = __builtin_dynamic_object_size (ch, 0); + __builtin_free (ch); + return ret; +} + size_t __attribute__ ((noinline)) test_builtin_calloc_condphi (size_t cnt, size_t sz, int cond) @@ -38,6 +194,49 @@ test_builtin_calloc_condphi (size_t cnt, size_t sz, int cond) return ret; } +/* 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); + + size_t ret = __builtin_dynamic_object_size (dest, 0); + __builtin_free (bin); + return ret; +} + +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) @@ -46,7 +245,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); } @@ -69,12 +268,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 265c87ed6fb..06d442796cb 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 __builtin_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 5051fea47c3..2364f2d6afd 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 __builtin_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 __builtin_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 1d92627266b..753ee4a1a4f 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 __builtin_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 9da3537a5f7..c383385e060 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 __builtin_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 __builtin_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 bf33ac93b93..e17ef294d0c 100644 --- a/gcc/tree-object-size.c +++ b/gcc/tree-object-size.c @@ -751,7 +751,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); @@ -771,12 +772,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; @@ -787,7 +789,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); } @@ -1242,6 +1247,9 @@ call_object_size (struct object_size_info *osi, tree ptr, gcall *call) gcc_assert (osi->pass == 0); tree bytes = alloc_object_size (call, object_size_type); + if (!(object_size_type & OST_DYNAMIC) && TREE_CODE (bytes) != INTEGER_CST) + bytes = size_unknown (object_size_type); + object_sizes_set (osi, varno, bytes, bytes); } From patchwork Sat Dec 18 12:35:11 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Siddhesh Poyarekar X-Patchwork-Id: 1570487 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: bilbo.ozlabs.org; dkim=pass (1024-bit key; unprotected) header.d=gotplt.org header.i=@gotplt.org header.a=rsa-sha1 header.s=gotplt.org header.b=MspWYdoO; dkim-atps=neutral Authentication-Results: ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=gcc.gnu.org (client-ip=2620:52:3:1:0:246e:9693:128c; helo=sourceware.org; envelope-from=gcc-patches-bounces+incoming=patchwork.ozlabs.org@gcc.gnu.org; receiver=) Received: from sourceware.org (server2.sourceware.org [IPv6:2620:52:3:1:0:246e:9693:128c]) (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) by bilbo.ozlabs.org (Postfix) with ESMTPS id 4JGQNm6Gdpz9sVq for ; Sat, 18 Dec 2021 23:37:44 +1100 (AEDT) Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id 621243858428 for ; Sat, 18 Dec 2021 12:37:42 +0000 (GMT) X-Original-To: gcc-patches@gcc.gnu.org Delivered-To: gcc-patches@gcc.gnu.org Received: from bird.elm.relay.mailchannels.net (bird.elm.relay.mailchannels.net [23.83.212.17]) by sourceware.org (Postfix) with ESMTPS id 2FB48385802B for ; Sat, 18 Dec 2021 12:35:33 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.1 sourceware.org 2FB48385802B 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 DDBE386239D; Sat, 18 Dec 2021 12:35:31 +0000 (UTC) Received: from pdx1-sub0-mail-a305.dreamhost.com (unknown [127.0.0.6]) (Authenticated sender: dreamhost) by relay.mailchannels.net (Postfix) with ESMTPA id 6CABF86239F; Sat, 18 Dec 2021 12:35:31 +0000 (UTC) X-Sender-Id: dreamhost|x-authsender|siddhesh@gotplt.org Received: from pdx1-sub0-mail-a305.dreamhost.com (pop.dreamhost.com [64.90.62.162]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384) by 100.105.57.85 (trex/6.4.3); Sat, 18 Dec 2021 12:35:31 +0000 X-MC-Relay: Neutral X-MailChannels-SenderId: dreamhost|x-authsender|siddhesh@gotplt.org X-MailChannels-Auth-Id: dreamhost X-Reign-Madly: 7f6c92d40e463008_1639830931621_2287709876 X-MC-Loop-Signature: 1639830931621:1698196021 X-MC-Ingress-Time: 1639830931621 Received: from rhbox.redhat.com (unknown [1.6.40.51]) (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-a305.dreamhost.com (Postfix) with ESMTPSA id 4JGQLB0lq3z26; Sat, 18 Dec 2021 04:35:29 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha1; c=relaxed/relaxed; d=gotplt.org; s=gotplt.org; t=1639830931; bh=QoF3pGYt0A9ykjRX5JbTYpkX7pQ=; h=From:To:Cc:Subject:Date:Content-Transfer-Encoding; b=MspWYdoOeMehFGIWUfl1ILW/g1AVj5v/U5S2pj8t6ve3oXX1ktAaiMz//7oVWSlkR Rr9+BavywpVUxaXp65zPZxFyJ/qU2BkS5XNbfrk58guekBM0pg9arS5Bt/ml6/1l5K enWRkqjzJtWwAKER5LflDpWArNRb/YwOEi9EtVYw= From: Siddhesh Poyarekar To: gcc-patches@gcc.gnu.org Subject: [PATCH v5 4/4] tree-object-size: Dynamic sizes for ADDR_EXPR Date: Sat, 18 Dec 2021 18:05:11 +0530 Message-Id: <20211218123511.139456-5-siddhesh@gotplt.org> X-Mailer: git-send-email 2.31.1 In-Reply-To: <20211218123511.139456-1-siddhesh@gotplt.org> References: <20211109190137.1107736-1-siddhesh@gotplt.org> <20211218123511.139456-1-siddhesh@gotplt.org> MIME-Version: 1.0 X-Spam-Status: No, score=-3038.2 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+incoming=patchwork.ozlabs.org@gcc.gnu.org Sender: "Gcc-patches" Allow returning dynamic expressions from ADDR_EXPR for __builtin_dynamic_object_size and also allow offsets to be dynamic. gcc/ChangeLog: * tree-object-size.c (size_valid_p): New function. (size_for_offset): Remove OFFSET constness assertion. (addr_object_size): Build dynamic expressions for object sizes and use size_valid_p to decide if it is valid for the given OBJECT_SIZE_TYPE. (compute_builtin_object_size): Allow dynamic offsets when computing size at O0. (call_object_size): Call size_valid_p. (plus_stmt_object_size): Allow non-constant offset and use size_valid_p to decide if it is valid for the given OBJECT_SIZE_TYPE. gcc/testsuite/ChangeLog: * gcc.dg/builtin-dynamic-object-size-0.c: Add new tests. * gcc.dg/builtin-object-size-1.c (test1) [__builtin_object_size]: Adjust expected output for dynamic object sizes. * gcc.dg/builtin-object-size-2.c (test1) [__builtin_object_size]: Likewise. * gcc.dg/builtin-object-size-3.c (test1) [__builtin_object_size]: Likewise. * gcc.dg/builtin-object-size-4.c (test1) [__builtin_object_size]: Likewise. Signed-off-by: Siddhesh Poyarekar --- .../gcc.dg/builtin-dynamic-object-size-0.c | 158 ++++++++++++++++++ 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 | 91 +++++----- 6 files changed, 300 insertions(+), 64 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 d67cf4a3c07..ba710f47f1c 100644 --- a/gcc/testsuite/gcc.dg/builtin-dynamic-object-size-0.c +++ b/gcc/testsuite/gcc.dg/builtin-dynamic-object-size-0.c @@ -250,6 +250,79 @@ 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__ ((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))) __attribute__ ((noinline)) @@ -258,6 +331,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() ({ \ @@ -318,6 +425,31 @@ 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_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) @@ -329,6 +461,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/testsuite/gcc.dg/builtin-object-size-1.c b/gcc/testsuite/gcc.dg/builtin-object-size-1.c index 06d442796cb..161f426ec0b 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 __builtin_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 __builtin_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 __builtin_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 __builtin_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 __builtin_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 2364f2d6afd..2729538da17 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 __builtin_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 __builtin_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 __builtin_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 __builtin_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 __builtin_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 __builtin_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 753ee4a1a4f..db31171a8bd 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 __builtin_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 __builtin_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 __builtin_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 c383385e060..f644890dd14 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 __builtin_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 e17ef294d0c..bdc5c0a001b 100644 --- a/gcc/tree-object-size.c +++ b/gcc/tree-object-size.c @@ -107,6 +107,14 @@ size_unknown_p (tree val, int object_size_type) ? integer_zerop (val) : integer_all_onesp (val)); } +/* Return true if VAL is represents a valid size for OBJECT_SIZE_TYPE. */ + +static inline bool +size_valid_p (tree val, int object_size_type) +{ + return ((object_size_type & OST_DYNAMIC) || TREE_CODE (val) == INTEGER_CST); +} + /* Return true if VAL is usable as an object size in the object_sizes vectors. */ @@ -341,7 +349,6 @@ init_offset_limit (void) static tree size_for_offset (tree sz, tree offset, tree wholesize = NULL_TREE) { - gcc_checking_assert (TREE_CODE (offset) == INTEGER_CST); gcc_checking_assert (types_compatible_p (TREE_TYPE (sz), sizetype)); /* For negative offsets, if we have a distinct WHOLESIZE, use it to get a net @@ -540,18 +547,11 @@ addr_object_size (struct object_size_info *osi, const_tree ptr, sz = wholesize = 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 - || TREE_CODE (sz) != INTEGER_CST) - sz = wholesize = size_unknown (object_size_type); - else - sz = size_for_offset (sz, offset, wholesize); - } + sz = size_for_offset (sz, TREE_OPERAND (pt_var, 1), wholesize); 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; pt_var_wholesize = wholesize; @@ -571,8 +571,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; } @@ -596,7 +597,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; @@ -610,17 +611,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; @@ -687,20 +682,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 @@ -709,11 +704,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); } } @@ -729,14 +720,18 @@ addr_object_size (struct object_size_info *osi, const_tree ptr, wholebytes = pt_var_wholesize; } - if (TREE_CODE (bytes) != INTEGER_CST - || TREE_CODE (wholebytes) != INTEGER_CST) - return false; + if (!size_unknown_p (bytes, object_size_type) + && size_valid_p (bytes, object_size_type) + && !size_unknown_p (bytes, object_size_type) + && size_valid_p (wholebytes, object_size_type)) + { + *psize = bytes; + if (pwholesize) + *pwholesize = wholebytes; + return true; + } - *psize = bytes; - if (pwholesize) - *pwholesize = wholebytes; - return true; + return false; } @@ -1058,11 +1053,11 @@ compute_builtin_object_size (tree ptr, int object_size_type, tree offset = gimple_assign_rhs2 (def); ptr = gimple_assign_rhs1 (def); - if (tree_fits_shwi_p (offset) + if (((object_size_type & OST_DYNAMIC) + || tree_fits_shwi_p (offset)) && compute_builtin_object_size (ptr, object_size_type, psize)) { - /* Return zero when the offset is out of bounds. */ *psize = size_for_offset (*psize, offset); return true; } @@ -1247,7 +1242,7 @@ call_object_size (struct object_size_info *osi, tree ptr, gcall *call) gcc_assert (osi->pass == 0); tree bytes = alloc_object_size (call, object_size_type); - if (!(object_size_type & OST_DYNAMIC) && TREE_CODE (bytes) != INTEGER_CST) + if (!size_valid_p (bytes, object_size_type)) bytes = size_unknown (object_size_type); object_sizes_set (osi, varno, bytes, bytes); @@ -1328,7 +1323,7 @@ plus_stmt_object_size (struct object_size_info *osi, tree var, gimple *stmt) return false; /* Handle PTR + OFFSET here. */ - if (TREE_CODE (op1) == INTEGER_CST + if (((object_size_type & OST_DYNAMIC) || TREE_CODE (op1) == INTEGER_CST) && (TREE_CODE (op0) == SSA_NAME || TREE_CODE (op0) == ADDR_EXPR)) { @@ -1361,6 +1356,10 @@ plus_stmt_object_size (struct object_size_info *osi, tree var, gimple *stmt) else bytes = wholesize = size_unknown (object_size_type); + if (!size_valid_p (bytes, object_size_type) + || !size_valid_p (wholesize, object_size_type)) + bytes = wholesize = size_unknown (object_size_type); + if (object_sizes_set (osi, varno, bytes, wholesize)) osi->changed = true; return reexamine;