From patchwork Tue Nov 9 19:01:32 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Siddhesh Poyarekar X-Patchwork-Id: 47328 Return-Path: X-Original-To: patchwork@sourceware.org Delivered-To: patchwork@sourceware.org Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id D89E83858404 for ; Tue, 9 Nov 2021 19:06:07 +0000 (GMT) X-Original-To: gcc-patches@gcc.gnu.org Delivered-To: gcc-patches@gcc.gnu.org Received: from giant.ash.relay.mailchannels.net (giant.ash.relay.mailchannels.net [23.83.222.68]) by sourceware.org (Postfix) with ESMTPS id B9F423857C60 for ; Tue, 9 Nov 2021 19:02:12 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.1 sourceware.org B9F423857C60 Authentication-Results: sourceware.org; dmarc=none (p=none dis=none) header.from=gotplt.org Authentication-Results: sourceware.org; spf=pass smtp.mailfrom=gotplt.org X-Sender-Id: dreamhost|x-authsender|siddhesh@gotplt.org Received: from relay.mailchannels.net (localhost [127.0.0.1]) by relay.mailchannels.net (Postfix) with ESMTP id 2FEF3342DC0; Tue, 9 Nov 2021 19:02:09 +0000 (UTC) Received: from pdx1-sub0-mail-a306.dreamhost.com (100-96-17-28.trex.outbound.svc.cluster.local [100.96.17.28]) (Authenticated sender: dreamhost) by relay.mailchannels.net (Postfix) with ESMTPA id CB198342CC0; Tue, 9 Nov 2021 19:02:03 +0000 (UTC) X-Sender-Id: dreamhost|x-authsender|siddhesh@gotplt.org Received: from pdx1-sub0-mail-a306.dreamhost.com (pop.dreamhost.com [64.90.62.162]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384) by 100.96.17.28 (trex/6.4.3); Tue, 09 Nov 2021 19:02:09 +0000 X-MC-Relay: Neutral X-MailChannels-SenderId: dreamhost|x-authsender|siddhesh@gotplt.org X-MailChannels-Auth-Id: dreamhost X-Absorbed-Left: 5b148cd43c218174_1636484529002_4268973158 X-MC-Loop-Signature: 1636484529002:238601578 X-MC-Ingress-Time: 1636484529002 Received: from rhbox.redhat.com (unknown [1.186.121.127]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256) (No client certificate requested) (Authenticated sender: siddhesh@gotplt.org) by pdx1-sub0-mail-a306.dreamhost.com (Postfix) with ESMTPSA id 4Hpcm9729Hz1WX; Tue, 9 Nov 2021 11:02:01 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha1; c=relaxed/relaxed; d=gotplt.org; s=gotplt.org; t=1636484523; bh=EP15VczHotRyxjt/NeE9RSZx4BE=; h=From:To:Cc:Subject:Date:Content-Transfer-Encoding; b=MXigowzCpzx645S3xBlQqjiMbMJPBhkr2w6tH+1tdZy2QYaQFf5AemV1fQJFVZoWf PcmpAuQPmnb/+GCfxiBNbt3Jq7JvkbVQQHvoIJTD8ZAz2R9oqjZLsXOCGjtmiTW7VK H+qRh0QNcG6JNwAXs0fmZc+gdWc661ubtGjJ/BEc= From: Siddhesh Poyarekar To: gcc-patches@gcc.gnu.org Subject: [PATCH 06/10] tree-object-size: Support dynamic sizes in conditions Date: Wed, 10 Nov 2021 00:31:32 +0530 Message-Id: <20211109190137.1107736-7-siddhesh@gotplt.org> X-Mailer: git-send-email 2.31.1 In-Reply-To: <20211109190137.1107736-1-siddhesh@gotplt.org> References: <20211109190137.1107736-1-siddhesh@gotplt.org> MIME-Version: 1.0 X-Spam-Status: No, score=-3038.0 required=5.0 tests=BAYES_00, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, GIT_PATCH_0, RCVD_IN_BARRACUDACENTRAL, RCVD_IN_DNSWL_NONE, RCVD_IN_MSPIKE_H2, RCVD_IN_SBL, SPF_HELO_NONE, SPF_PASS, TXREP autolearn=ham autolearn_force=no version=3.4.4 X-Spam-Checker-Version: SpamAssassin 3.4.4 (2020-01-24) on server2.sourceware.org X-BeenThere: gcc-patches@gcc.gnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Gcc-patches mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: jakub@redhat.com Errors-To: gcc-patches-bounces+patchwork=sourceware.org@gcc.gnu.org Sender: "Gcc-patches" Handle GIMPLE_PHI and conditionals specially for dynamic objects, returning PHI/conditional expressions instead of just a MIN/MAX estimate. This makes the returned object size variable for loops and conditionals, so tests need to be adjusted to look for precise size in some cases. builtin-dynamic-object-size-5.c had to be modified to only look for success in maximum object size case and skip over the minimum object size tests because the result is no longer a compile time constant. I also added some simple tests to exercise conditionals with dynamic object sizes. gcc/ChangeLog: * tree-object-size.c: Include gimplify-me.h. (struct object_size_info): New member phiresults. (estimate_size): New argument visitlog. Handle newly inserted PHI nodes. (get_insertion_point, gimplify_size_expressions): New functions. (compute_builtin_object_size): Call gimplify_size_expressions. (make_or_get_tempsize): New function. (cond_expr_object_size): Return COND_EXPR for dynamic sizes. (phi_object_size, phi_dynamic_object_size): New functions. (collect_object_sizes_for): Call them. (object_sizes_execute): Don't insert min/max for dynamic sizes. gcc/testsuite/ChangeLog: * gcc.dg/builtin-dynamic-object-size-0.c: New file. * gcc.dg/builtin-dynamic-object-size-10.c: Adjust expected output. * gcc.dg/builtin-dynamic-object-size-1.c (DYNAMIC_OBJECT_SIZE): New macro. * gcc.dg/builtin-dynamic-object-size-2.c (DYNAMIC_OBJECT_SIZE): Likewise. * gcc.dg/builtin-dynamic-object-size-3.c (DYNAMIC_OBJECT_SIZE): Likewise. * gcc.dg/builtin-dynamic-object-size-4.c (DYNAMIC_OBJECT_SIZE): Likewise. * gcc.dg/builtin-dynamic-object-size-5.c (DYNAMIC_OBJECT_SIZE): Likewise. * gcc.dg/builtin-object-size-1.c [DYNAMIC_OBJECT_SIZE]: Alter expected results for dynamic object size. * gcc.dg/builtin-object-size-2.c [DYNAMIC_OBJECT_SIZE]: Likewise. * gcc.dg/builtin-object-size-3.c [DYNAMIC_OBJECT_SIZE]: Likewise. * gcc.dg/builtin-object-size-4.c [DYNAMIC_OBJECT_SIZE]: Likewise. * gcc.dg/builtin-object-size-5.c [DYNAMIC_OBJECT_SIZE]: Likewise. Signed-off-by: Siddhesh Poyarekar --- .../gcc.dg/builtin-dynamic-object-size-0.c | 72 ++++ .../gcc.dg/builtin-dynamic-object-size-1.c | 1 + .../gcc.dg/builtin-dynamic-object-size-10.c | 4 +- .../gcc.dg/builtin-dynamic-object-size-2.c | 1 + .../gcc.dg/builtin-dynamic-object-size-3.c | 1 + .../gcc.dg/builtin-dynamic-object-size-4.c | 1 + .../gcc.dg/builtin-dynamic-object-size-5.c | 1 + gcc/testsuite/gcc.dg/builtin-object-size-1.c | 109 +++++- gcc/testsuite/gcc.dg/builtin-object-size-2.c | 77 +++++ gcc/testsuite/gcc.dg/builtin-object-size-3.c | 105 ++++++ gcc/testsuite/gcc.dg/builtin-object-size-4.c | 68 ++++ gcc/testsuite/gcc.dg/builtin-object-size-5.c | 12 + gcc/tree-object-size.c | 315 +++++++++++++++--- 13 files changed, 725 insertions(+), 42 deletions(-) create mode 100644 gcc/testsuite/gcc.dg/builtin-dynamic-object-size-0.c diff --git a/gcc/testsuite/gcc.dg/builtin-dynamic-object-size-0.c b/gcc/testsuite/gcc.dg/builtin-dynamic-object-size-0.c new file mode 100644 index 00000000000..ddedf6a49bd --- /dev/null +++ b/gcc/testsuite/gcc.dg/builtin-dynamic-object-size-0.c @@ -0,0 +1,72 @@ +/* { dg-do run } */ +/* { dg-options "-O2" } */ + +typedef __SIZE_TYPE__ size_t; +#define abort __builtin_abort + +size_t +__attribute__ ((noinline)) +test_builtin_malloc_condphi (int cond) +{ + void *ret; + + if (cond) + ret = __builtin_malloc (32); + else + ret = __builtin_malloc (64); + + return __builtin_dynamic_object_size (ret, 0); +} + +size_t +__attribute__ ((noinline)) +test_builtin_calloc_condphi (size_t cnt, size_t sz, int cond) +{ + struct + { + int a; + char b; + } bin[cnt]; + + char *ch = __builtin_calloc (cnt, sz); + + return __builtin_dynamic_object_size (cond ? ch : (void *) &bin, 0); +} + +size_t +__attribute__ ((noinline)) +test_deploop (size_t sz, size_t cond) +{ + char *bin = __builtin_alloca (32); + + for (size_t i = 0; i < sz; i++) + if (i == cond) + bin = __builtin_alloca (64); + + return __builtin_dynamic_object_size (bin, 0); +} + +unsigned nfails = 0; + +#define FAIL() ({ \ + __builtin_printf ("Failure at line: %d\n", __LINE__); \ + nfails++; \ +}) + +int +main (int argc, char **argv) +{ + if (test_builtin_malloc_condphi (1) != 32) + FAIL (); + if (test_builtin_malloc_condphi (0) != 64) + FAIL (); + if (test_builtin_calloc_condphi (128, 1, 0) == 128) + FAIL (); + if (test_deploop (128, 129) != 32) + FAIL (); + + if (nfails > 0) + __builtin_abort (); + + return 0; +} diff --git a/gcc/testsuite/gcc.dg/builtin-dynamic-object-size-1.c b/gcc/testsuite/gcc.dg/builtin-dynamic-object-size-1.c index 7cc8b1c9488..2c7d2128913 100644 --- a/gcc/testsuite/gcc.dg/builtin-dynamic-object-size-1.c +++ b/gcc/testsuite/gcc.dg/builtin-dynamic-object-size-1.c @@ -2,5 +2,6 @@ /* { dg-options "-O2" } */ /* { dg-require-effective-target alloca } */ +#define DYNAMIC_OBJECT_SIZE #define __builtin_object_size __builtin_dynamic_object_size #include "builtin-object-size-1.c" diff --git a/gcc/testsuite/gcc.dg/builtin-dynamic-object-size-10.c b/gcc/testsuite/gcc.dg/builtin-dynamic-object-size-10.c index bc880a589ae..e234467d6d0 100644 --- a/gcc/testsuite/gcc.dg/builtin-dynamic-object-size-10.c +++ b/gcc/testsuite/gcc.dg/builtin-dynamic-object-size-10.c @@ -5,5 +5,5 @@ #define __builtin_object_size __builtin_dynamic_object_size #include "builtin-object-size-10.c" -/* { dg-final { scan-tree-dump "maximum object size 21" "early_objsz" } } */ -/* { dg-final { scan-tree-dump "maximum subobject size 16" "early_objsz" } } */ +/* { dg-final { scan-tree-dump "maximum dynamic object size 21" "early_objsz" } } */ +/* { dg-final { scan-tree-dump "maximum dynamic subobject size 16" "early_objsz" } } */ diff --git a/gcc/testsuite/gcc.dg/builtin-dynamic-object-size-2.c b/gcc/testsuite/gcc.dg/builtin-dynamic-object-size-2.c index 267dbf48ca7..2f07534c11b 100644 --- a/gcc/testsuite/gcc.dg/builtin-dynamic-object-size-2.c +++ b/gcc/testsuite/gcc.dg/builtin-dynamic-object-size-2.c @@ -2,5 +2,6 @@ /* { dg-options "-O2" } */ /* { dg-require-effective-target alloca } */ +#define DYNAMIC_OBJECT_SIZE #define __builtin_object_size __builtin_dynamic_object_size #include "builtin-object-size-2.c" diff --git a/gcc/testsuite/gcc.dg/builtin-dynamic-object-size-3.c b/gcc/testsuite/gcc.dg/builtin-dynamic-object-size-3.c index fb9dc56da7e..29b5b358845 100644 --- a/gcc/testsuite/gcc.dg/builtin-dynamic-object-size-3.c +++ b/gcc/testsuite/gcc.dg/builtin-dynamic-object-size-3.c @@ -2,5 +2,6 @@ /* { dg-options "-O2" } */ /* { dg-require-effective-target alloca } */ +#define DYNAMIC_OBJECT_SIZE #define __builtin_object_size __builtin_dynamic_object_size #include "builtin-object-size-3.c" diff --git a/gcc/testsuite/gcc.dg/builtin-dynamic-object-size-4.c b/gcc/testsuite/gcc.dg/builtin-dynamic-object-size-4.c index 870548b4206..5ff1f16c978 100644 --- a/gcc/testsuite/gcc.dg/builtin-dynamic-object-size-4.c +++ b/gcc/testsuite/gcc.dg/builtin-dynamic-object-size-4.c @@ -2,5 +2,6 @@ /* { dg-options "-O2" } */ /* { dg-require-effective-target alloca } */ +#define DYNAMIC_OBJECT_SIZE #define __builtin_object_size __builtin_dynamic_object_size #include "builtin-object-size-4.c" diff --git a/gcc/testsuite/gcc.dg/builtin-dynamic-object-size-5.c b/gcc/testsuite/gcc.dg/builtin-dynamic-object-size-5.c index 698b03c34be..2438a26d920 100644 --- a/gcc/testsuite/gcc.dg/builtin-dynamic-object-size-5.c +++ b/gcc/testsuite/gcc.dg/builtin-dynamic-object-size-5.c @@ -1,6 +1,7 @@ /* { dg-do compile { target i?86-*-linux* i?86-*-gnu* x86_64-*-linux* } } */ /* { dg-options "-O2" } */ +#define DYNAMIC_OBJECT_SIZE #define __builtin_object_size __builtin_dynamic_object_size #include "builtin-object-size-5.c" diff --git a/gcc/testsuite/gcc.dg/builtin-object-size-1.c b/gcc/testsuite/gcc.dg/builtin-object-size-1.c index b270e8d8827..76df4c96271 100644 --- a/gcc/testsuite/gcc.dg/builtin-object-size-1.c +++ b/gcc/testsuite/gcc.dg/builtin-object-size-1.c @@ -42,9 +42,17 @@ test1 (void *q, int x) abort (); if (__builtin_object_size (q, 0) != (size_t) -1) abort (); +#ifdef DYNAMIC_OBJECT_SIZE + if (__builtin_object_size (r, 0) + != (x < 0 + ? sizeof (a) - __builtin_offsetof (struct A, a) - 9 + : sizeof (a) - __builtin_offsetof (struct A, c) - 1)) + abort (); +#else if (__builtin_object_size (r, 0) != sizeof (a) - __builtin_offsetof (struct A, a) - 9) abort (); +#endif if (x < 6) r = &w[2].a[1]; else @@ -58,9 +66,17 @@ test1 (void *q, int x) if (__builtin_object_size (&y.b, 0) != sizeof (a) - __builtin_offsetof (struct A, b)) abort (); +#ifdef DYNAMIC_OBJECT_SIZE + if (__builtin_object_size (r, 0) + != (x < 6 + ? 2 * sizeof (w[0]) - __builtin_offsetof (struct A, a) - 1 + : sizeof (a) - __builtin_offsetof (struct A, a) - 6)) + abort (); +#else if (__builtin_object_size (r, 0) != 2 * sizeof (w[0]) - __builtin_offsetof (struct A, a) - 1) abort (); +#endif if (x < 20) r = malloc (30); else @@ -165,6 +181,7 @@ test2 (void) struct B { char buf1[10]; char buf2[10]; } a; char *r, buf3[20]; int i; + size_t res; if (sizeof (a) != 20) return; @@ -181,7 +198,24 @@ test2 (void) else if (i == l1 + 2) r = &a.buf1[9]; } - if (__builtin_object_size (r, 0) != 20) +#ifdef DYNAMIC_OBJECT_SIZE + res = sizeof (buf3); + + for (i = 0; i < 4; ++i) + { + if (i == l1 - 1) + res = sizeof (a) - __builtin_offsetof (struct B, buf1) - 1; + else if (i == l1) + res = sizeof (a) - __builtin_offsetof (struct B, buf2) - 7; + else if (i == l1 + 1) + res = sizeof (buf3) - 5; + else if (i == l1 + 2) + res = sizeof (a) - __builtin_offsetof (struct B, buf1) - 9; + } +#else + res = 20; +#endif + if (__builtin_object_size (r, 0) != res) abort (); r = &buf3[20]; for (i = 0; i < 4; ++i) @@ -195,13 +229,45 @@ test2 (void) else if (i == l1 + 2) r = &a.buf1[9]; } - if (__builtin_object_size (r, 0) != 15) +#ifdef DYNAMIC_OBJECT_SIZE + res = sizeof (buf3) - 20; + + for (i = 0; i < 4; ++i) + { + if (i == l1 - 1) + res = sizeof (a) - __builtin_offsetof (struct B, buf1) - 7; + else if (i == l1) + res = sizeof (a) - __builtin_offsetof (struct B, buf2) - 7; + else if (i == l1 + 1) + res = sizeof (buf3) - 5; + else if (i == l1 + 2) + res = sizeof (a) - __builtin_offsetof (struct B, buf1) - 9; + } + if (__builtin_object_size (r, 0) != res) + abort (); +#else + res = 15; +#endif + if (__builtin_object_size (r, 0) != res) abort (); r += 8; +#ifdef DYNAMIC_OBJECT_SIZE + res -= 8; + if (__builtin_object_size (r, 0) != res) + abort (); + if (res >= 6) + { + if (__builtin_object_size (r + 6, 0) != res - 6) + abort (); + } + else if (__builtin_object_size (r + 6, 0) != 0) + abort (); +#else if (__builtin_object_size (r, 0) != 7) abort (); if (__builtin_object_size (r + 6, 0) != 1) abort (); +#endif r = &buf3[18]; for (i = 0; i < 4; ++i) { @@ -214,8 +280,31 @@ test2 (void) else if (i == l1 + 2) r = &a.buf1[4]; } +#ifdef DYNAMIC_OBJECT_SIZE + res = sizeof (buf3) - 18; + + for (i = 0; i < 4; ++i) + { + if (i == l1 - 1) + res = sizeof (a) - __builtin_offsetof (struct B, buf1) - 9; + else if (i == l1) + res = sizeof (a) - __builtin_offsetof (struct B, buf2) - 9; + else if (i == l1 + 1) + res = sizeof (buf3) - 5; + else if (i == l1 + 2) + res = sizeof (a) - __builtin_offsetof (struct B, buf1) - 4; + } + if (res >= 12) + { + if (__builtin_object_size (r + 12, 0) != res - 12) + abort (); + } + else if (__builtin_object_size (r + 12, 0) != 0) + abort (); +#else if (__builtin_object_size (r + 12, 0) != 4) abort (); +#endif } void @@ -358,6 +447,10 @@ test5 (size_t x) for (i = 0; i < x; ++i) p = p + 4; +#ifdef DYNAMIC_OBJECT_SIZE + if (__builtin_object_size (p, 0) != sizeof (buf) - 8 - 4 * x) + abort (); +#else /* My understanding of ISO C99 6.5.6 is that a conforming program will not end up with p equal to &buf[0] through &buf[7], i.e. calling this function with say @@ -367,6 +460,7 @@ test5 (size_t x) it would be 64 (or conservative (size_t) -1 == unknown). */ if (__builtin_object_size (p, 0) != sizeof (buf) - 8) abort (); +#endif memset (p, ' ', sizeof (buf) - 8 - 4 * 4); } @@ -381,8 +475,13 @@ test6 (size_t x) for (i = 0; i < x; ++i) p = p + 4; +#ifdef DYNAMIC_OBJECT_SIZE + if (__builtin_object_size (p, 0) != sizeof (t) - 8 - 4 * x) + abort (); +#else if (__builtin_object_size (p, 0) != sizeof (t) - 8) abort (); +#endif memset (p, ' ', sizeof (t) - 8 - 4 * 4); p = &t.buf[8]; for (i = 0; i < x; i++) @@ -390,8 +489,14 @@ test6 (size_t x) r = __builtin_memcpy (r, t.buf, i); p = r + 1; } +#ifdef DYNAMIC_OBJECT_SIZE + if (__builtin_object_size (p, 0) + != ((x > 0) ? sizeof (t.buf2) - 1 : sizeof (t) - 8)) + abort (); +#else if (__builtin_object_size (p, 0) != sizeof (t) - 8) abort (); +#endif for (i = 0; i < x; i++) { r = __builtin_mempcpy (r, t.buf, i); diff --git a/gcc/testsuite/gcc.dg/builtin-object-size-2.c b/gcc/testsuite/gcc.dg/builtin-object-size-2.c index ea11a17b6d8..c395d2e95b3 100644 --- a/gcc/testsuite/gcc.dg/builtin-object-size-2.c +++ b/gcc/testsuite/gcc.dg/builtin-object-size-2.c @@ -43,8 +43,15 @@ test1 (void *q, int x) abort (); if (__builtin_object_size (q, 1) != (size_t) -1) abort (); +#ifdef DYNAMIC_OBJECT_SIZE + if (x < 0 + ? __builtin_object_size (r, 1) != sizeof (a.a) - 9 + : __builtin_object_size (r, 1) != sizeof (a.c) - 1) + abort (); +#else if (__builtin_object_size (r, 1) != sizeof (a.c) - 1) abort (); +#endif if (x < 6) r = &w[2].a[1]; else @@ -55,8 +62,15 @@ test1 (void *q, int x) abort (); if (__builtin_object_size (&y.b, 1) != sizeof (a.b)) abort (); +#ifdef DYNAMIC_OBJECT_SIZE + if (x < 6 + ? __builtin_object_size (r, 1) != sizeof (a.a) - 1 + : __builtin_object_size (r, 1) != sizeof (a.a) - 6) + abort (); +#else if (__builtin_object_size (r, 1) != sizeof (a.a) - 1) abort (); +#endif if (x < 20) r = malloc (30); else @@ -185,6 +199,9 @@ test2 (void) struct B { char buf1[10]; char buf2[10]; } a; char *r, buf3[20]; int i; +#ifdef DYNAMIC_OBJECT_SIZE + size_t dyn_res; +#endif if (sizeof (a) != 20) return; @@ -201,8 +218,26 @@ test2 (void) else if (i == l1 + 2) r = &a.buf1[9]; } +#ifdef DYNAMIC_OBJECT_SIZE + dyn_res = sizeof (buf3); + + for (i = 0; i < 4; ++i) + { + if (i == l1 - 1) + dyn_res = sizeof (a.buf1) - 1; + else if (i == l1) + dyn_res = sizeof (a.buf2) - 7; + else if (i == l1 + 1) + dyn_res = sizeof (buf3) - 5; + else if (i == l1 + 2) + dyn_res = sizeof (a.buf1) - 9; + } + if (__builtin_object_size (r, 1) != dyn_res) + abort (); +#else if (__builtin_object_size (r, 1) != sizeof (buf3)) abort (); +#endif r = &buf3[20]; for (i = 0; i < 4; ++i) { @@ -215,13 +250,50 @@ test2 (void) else if (i == l1 + 2) r = &a.buf1[9]; } +#ifdef DYNAMIC_OBJECT_SIZE + dyn_res = sizeof (buf3) - 20; + + for (i = 0; i < 4; ++i) + { + if (i == l1 - 1) + dyn_res = sizeof (a.buf1) - 7; + else if (i == l1) + dyn_res = sizeof (a.buf2) - 7; + else if (i == l1 + 1) + dyn_res = sizeof (buf3) - 5; + else if (i == l1 + 2) + dyn_res = sizeof (a.buf1) - 9; + } + if (__builtin_object_size (r, 1) != dyn_res) + abort (); +#else if (__builtin_object_size (r, 1) != sizeof (buf3) - 5) abort (); +#endif r += 8; +#ifdef DYNAMIC_OBJECT_SIZE + if (dyn_res >= 8) + { + dyn_res -= 8; + if (__builtin_object_size (r, 1) != dyn_res) + abort (); + + if (dyn_res >= 6) + { + if (__builtin_object_size (r + 6, 1) != dyn_res - 6) + abort (); + } + else if (__builtin_object_size (r + 6, 1) != 0) + abort (); + } + else if (__builtin_object_size (r, 1) != 0) + abort (); +#else if (__builtin_object_size (r, 1) != sizeof (buf3) - 13) abort (); if (__builtin_object_size (r + 6, 1) != sizeof (buf3) - 19) abort (); +#endif } void @@ -340,8 +412,13 @@ test5 (size_t x) for (i = 0; i < x; ++i) p = p + 4; +#ifdef DYNAMIC_OBJECT_SIZE + if (__builtin_object_size (p, 1) != sizeof (t.buf) - 8 - 4 * x) + abort (); +#else if (__builtin_object_size (p, 1) != sizeof (t.buf) - 8) abort (); +#endif memset (p, ' ', sizeof (t.buf) - 8 - 4 * 4); p = &t.buf[8]; for (i = 0; i < x; i++) diff --git a/gcc/testsuite/gcc.dg/builtin-object-size-3.c b/gcc/testsuite/gcc.dg/builtin-object-size-3.c index 2d68925077e..ccdc6ef8cc8 100644 --- a/gcc/testsuite/gcc.dg/builtin-object-size-3.c +++ b/gcc/testsuite/gcc.dg/builtin-object-size-3.c @@ -71,23 +71,45 @@ test1 (void *q, int x) r = malloc (30); else r = calloc (2, 14); +#ifdef DYNAMIC_OBJECT_SIZE + if (__builtin_object_size (r, 2) != (x < 20 ? 30 : 2 * 14)) + abort (); +#else if (__builtin_object_size (r, 2) != 2 * 14) abort (); +#endif if (x < 30) r = malloc (sizeof (a)); else r = &a.a[3]; +#ifdef DYNAMIC_OBJECT_SIZE + size_t objsz = (x < 30 ? sizeof (a) + : sizeof (a) - __builtin_offsetof (struct A, a) - 3); + if (__builtin_object_size (r, 2) != objsz) + abort (); +#else if (__builtin_object_size (r, 2) != sizeof (a) - __builtin_offsetof (struct A, a) - 3) abort (); +#endif r = memcpy (r, "a", 2); +#ifdef DYNAMIC_OBJECT_SIZE + if (__builtin_object_size (r, 2) != objsz) + abort (); +#else if (__builtin_object_size (r, 2) != sizeof (a) - __builtin_offsetof (struct A, a) - 3) abort (); +#endif r = memcpy (r + 2, "b", 2) + 2; +#ifdef DYNAMIC_OBJECT_SIZE + if (__builtin_object_size (r, 2) != objsz - 4) + abort (); +#else if (__builtin_object_size (r, 2) != sizeof (a) - __builtin_offsetof (struct A, a) - 3 - 4) abort (); +#endif r = &a.a[4]; r = memset (r, 'a', 2); if (__builtin_object_size (r, 2) @@ -164,6 +186,9 @@ test2 (void) struct B { char buf1[10]; char buf2[10]; } a; char *r, buf3[20]; int i; +#ifdef DYNAMIC_OBJECT_SIZE + size_t dyn_res; +#endif if (sizeof (a) != 20) return; @@ -180,8 +205,26 @@ test2 (void) else if (i == l1 + 2) r = &a.buf1[9]; } +#ifdef DYNAMIC_OBJECT_SIZE + dyn_res = sizeof (buf3); + + for (i = 0; i < 4; ++i) + { + if (i == l1 - 1) + dyn_res = sizeof (a) - __builtin_offsetof (struct B, buf1) - 1; + else if (i == l1) + dyn_res = sizeof (a) - __builtin_offsetof (struct B, buf2) - 7; + else if (i == l1 + 1) + dyn_res = sizeof (buf3) - 5; + else if (i == l1 + 2) + dyn_res = sizeof (a) - __builtin_offsetof (struct B, buf1) - 9; + } + if (__builtin_object_size (r, 2) != dyn_res) + abort (); +#else if (__builtin_object_size (r, 2) != 3) abort (); +#endif r = &buf3[20]; for (i = 0; i < 4; ++i) { @@ -208,13 +251,44 @@ test2 (void) else if (i == l1 + 2) r = &a.buf1[4]; } +#ifdef DYNAMIC_OBJECT_SIZE + dyn_res = sizeof (buf3) - 2; + + for (i = 0; i < 4; ++i) + { + if (i == l1 - 1) + dyn_res = sizeof (a) - __builtin_offsetof (struct B, buf1) - 1; + else if (i == l1) + dyn_res = sizeof (a) - __builtin_offsetof (struct B, buf1) - 2; + else if (i == l1 + 1) + dyn_res = sizeof (buf3) - 5; + else if (i == l1 + 2) + dyn_res = sizeof (a) - __builtin_offsetof (struct B, buf1) - 4; + } + if (__builtin_object_size (r, 2) != dyn_res) + abort (); +#else if (__builtin_object_size (r, 2) != 15) abort (); +#endif r += 8; +#ifdef DYNAMIC_OBJECT_SIZE + dyn_res -= 8; + if (__builtin_object_size (r, 2) != dyn_res) + abort (); + if (dyn_res >= 6) + { + if (__builtin_object_size (r + 6, 2) != dyn_res - 6) + abort (); + } + else if (__builtin_object_size (r + 6, 2) != 0) + abort (); +#else if (__builtin_object_size (r, 2) != 7) abort (); if (__builtin_object_size (r + 6, 2) != 1) abort (); +#endif r = &buf3[18]; for (i = 0; i < 4; ++i) { @@ -227,8 +301,31 @@ test2 (void) else if (i == l1 + 2) r = &a.buf1[4]; } +#ifdef DYNAMIC_OBJECT_SIZE + dyn_res = sizeof (buf3) - 18; + + for (i = 0; i < 4; ++i) + { + if (i == l1 - 1) + dyn_res = sizeof (a) - __builtin_offsetof (struct B, buf1) - 9; + else if (i == l1) + dyn_res = sizeof (a) - __builtin_offsetof (struct B, buf2) - 9; + else if (i == l1 + 1) + dyn_res = sizeof (buf3) - 5; + else if (i == l1 + 2) + dyn_res = sizeof (a) - __builtin_offsetof (struct B, buf1) - 4; + } + if (dyn_res >= 12) + { + if (__builtin_object_size (r + 12, 2) != dyn_res - 12) + abort (); + } + else if (__builtin_object_size (r + 12, 2) != 0) + abort (); +#else if (__builtin_object_size (r + 12, 2) != 0) abort (); +#endif } void @@ -371,7 +468,11 @@ test5 (size_t x) for (i = 0; i < x; ++i) p = p + 4; +#ifdef DYNAMIC_OBJECT_SIZE + if (__builtin_object_size (p, 2) != sizeof (buf) - 8 - 4 * x) +#else if (__builtin_object_size (p, 2) != 0) +#endif abort (); memset (p, ' ', sizeof (buf) - 8 - 4 * 4); } @@ -387,7 +488,11 @@ test6 (size_t x) for (i = 0; i < x; ++i) p = p + 4; +#ifdef DYNAMIC_OBJECT_SIZE + if (__builtin_object_size (p, 2) != sizeof (t) - 8 - 4 * x) +#else if (__builtin_object_size (p, 2) != 0) +#endif abort (); memset (p, ' ', sizeof (t) - 8 - 4 * 4); p = &t.buf[8]; diff --git a/gcc/testsuite/gcc.dg/builtin-object-size-4.c b/gcc/testsuite/gcc.dg/builtin-object-size-4.c index dd7f6d7336d..002512d38ab 100644 --- a/gcc/testsuite/gcc.dg/builtin-object-size-4.c +++ b/gcc/testsuite/gcc.dg/builtin-object-size-4.c @@ -43,7 +43,12 @@ test1 (void *q, int x) abort (); if (__builtin_object_size (q, 3) != 0) abort (); +#ifdef DYNAMIC_OBJECT_SIZE + if (__builtin_object_size (r, 3) + != (x < 0 ? sizeof (a.a) - 9 : sizeof (a.c) - 1)) +#else if (__builtin_object_size (r, 3) != sizeof (a.a) - 9) +#endif abort (); if (x < 6) r = &w[2].a[1]; @@ -55,31 +60,57 @@ test1 (void *q, int x) abort (); if (__builtin_object_size (&y.b, 3) != sizeof (a.b)) abort (); +#ifdef DYNAMIC_OBJECT_SIZE + if (__builtin_object_size (r, 3) + != (x < 6 ? sizeof (w[2].a) - 1 : sizeof (a.a) - 6)) +#else if (__builtin_object_size (r, 3) != sizeof (a.a) - 6) +#endif abort (); if (x < 20) r = malloc (30); else r = calloc (2, 16); +#ifdef DYNAMIC_OBJECT_SIZE + if (__builtin_object_size (r, 3) != (x < 20 ? 30 : 2 * 16)) +#else if (__builtin_object_size (r, 3) != 30) +#endif abort (); if (x < 20) r = malloc (30); else r = calloc (2, 14); +#ifdef DYNAMIC_OBJECT_SIZE + if (__builtin_object_size (r, 3) != (x < 20 ? 30 : 2 * 14)) +#else if (__builtin_object_size (r, 3) != 2 * 14) +#endif abort (); if (x < 30) r = malloc (sizeof (a)); else r = &a.a[3]; +#ifdef DYNAMIC_OBJECT_SIZE + size_t objsz = x < 30 ? sizeof (a) : sizeof (a.a) - 3; + if (__builtin_object_size (r, 3) != objsz) +#else if (__builtin_object_size (r, 3) != sizeof (a.a) - 3) +#endif abort (); r = memcpy (r, "a", 2); +#ifdef DYNAMIC_OBJECT_SIZE + if (__builtin_object_size (r, 3) != objsz) +#else if (__builtin_object_size (r, 3) != sizeof (a.a) - 3) +#endif abort (); r = memcpy (r + 2, "b", 2) + 2; +#ifdef DYNAMIC_OBJECT_SIZE + if (__builtin_object_size (r, 3) != objsz - 4) +#else if (__builtin_object_size (r, 3) != sizeof (a.a) - 3 - 4) +#endif abort (); r = &a.a[4]; r = memset (r, 'a', 2); @@ -184,6 +215,9 @@ test2 (void) struct B { char buf1[10]; char buf2[10]; } a; char *r, buf3[20]; int i; +#ifdef DYNAMIC_OBJECT_SIZE + size_t dyn_res = 0; +#endif if (sizeof (a) != 20) return; @@ -228,13 +262,38 @@ test2 (void) else if (i == l1 + 2) r = &a.buf1[2]; } +#ifdef DYNAMIC_OBJECT_SIZE + dyn_res = sizeof (buf3) - 1; + + for (i = 0; i < 4; ++i) + { + if (i == l1 - 1) + dyn_res = sizeof (a.buf1) - 6; + else if (i == l1) + dyn_res = sizeof (a.buf2) - 4; + else if (i == l1 + 1) + dyn_res = sizeof (buf3) - 5; + else if (i == l1 + 2) + dyn_res = sizeof (a.buf1) - 2; + } + if (__builtin_object_size (r, 3) != dyn_res) + abort (); +#else if (__builtin_object_size (r, 3) != sizeof (a.buf1) - 6) abort (); +#endif r += 2; +#ifdef DYNAMIC_OBJECT_SIZE + if (__builtin_object_size (r, 3) != dyn_res - 2) + abort (); + if (__builtin_object_size (r + 1, 3) != dyn_res - 3) + abort (); +#else if (__builtin_object_size (r, 3) != sizeof (a.buf1) - 6 - 2) abort (); if (__builtin_object_size (r + 1, 3) != sizeof (a.buf1) - 6 - 3) abort (); +#endif } void @@ -353,7 +412,11 @@ test5 (size_t x) for (i = 0; i < x; ++i) p = p + 4; +#ifdef DYNAMIC_OBJECT_SIZE + if (__builtin_object_size (p, 3) != sizeof (t.buf) - 8 - 4 * x) +#else if (__builtin_object_size (p, 3) != 0) +#endif abort (); memset (p, ' ', sizeof (t.buf) - 8 - 4 * 4); p = &t.buf[8]; @@ -362,7 +425,12 @@ test5 (size_t x) r = __builtin_memcpy (r, t.buf, i); p = r + 1; } +#ifdef DYNAMIC_OBJECT_SIZE + if (__builtin_object_size (p, 3) + != (x > 0 ? sizeof (t.buf2) - 1 : sizeof (t.buf) - 8)) +#else if (__builtin_object_size (p, 3) != sizeof (t.buf) - 8) +#endif abort (); for (i = 0; i < x; i++) { diff --git a/gcc/testsuite/gcc.dg/builtin-object-size-5.c b/gcc/testsuite/gcc.dg/builtin-object-size-5.c index 7c274cdfd42..dd19747c97a 100644 --- a/gcc/testsuite/gcc.dg/builtin-object-size-5.c +++ b/gcc/testsuite/gcc.dg/builtin-object-size-5.c @@ -1,5 +1,7 @@ /* { dg-do compile { target i?86-*-linux* i?86-*-gnu* x86_64-*-linux* } } */ /* { dg-options "-O2" } */ +/* For dynamic object sizes we 'succeed' if the returned size is known for + maximum object size. */ typedef __SIZE_TYPE__ size_t; extern void abort (void); @@ -13,7 +15,11 @@ test1 (size_t x) for (i = 0; i < x; ++i) p = p + 4; +#ifdef DYNAMIC_OBJECT_SIZE + if (__builtin_object_size (p, 0) == -1) +#else if (__builtin_object_size (p, 0) != sizeof (buf) - 8) +#endif abort (); } @@ -25,10 +31,15 @@ test2 (size_t x) for (i = 0; i < x; ++i) p = p + 4; +#ifdef DYNAMIC_OBJECT_SIZE + if (__builtin_object_size (p, 1) == -1) +#else if (__builtin_object_size (p, 1) != sizeof (buf) - 8) +#endif abort (); } +#ifndef DYNAMIC_OBJECT_SIZE void test3 (size_t x) { @@ -52,5 +63,6 @@ test4 (size_t x) if (__builtin_object_size (p, 3) != 0) abort (); } +#endif /* { dg-final { scan-assembler-not "abort" } } */ diff --git a/gcc/tree-object-size.c b/gcc/tree-object-size.c index 983df24719e..33598ddc91c 100644 --- a/gcc/tree-object-size.c +++ b/gcc/tree-object-size.c @@ -35,11 +35,12 @@ along with GCC; see the file COPYING3. If not see #include "stringpool.h" #include "attribs.h" #include "builtins.h" +#include "gimplify-me.h" struct object_size_info { int object_size_type; - bitmap visited, reexamine; + bitmap visited, reexamine, phiresults; vec tempsize_objs; }; @@ -681,7 +682,7 @@ reducing_size (tree orig, tree expr, bool found_minus) simplified expression. */ static tree -estimate_size (object_size_info *osi, tree size) +estimate_size (object_size_info *osi, tree size, bitmap *visitlog = NULL) { enum tree_code code = TREE_CODE (size); int object_size_type = osi->object_size_type; @@ -691,15 +692,38 @@ estimate_size (object_size_info *osi, tree size) case SSA_NAME: { unsigned num = SSA_NAME_VERSION (size); - if (!bitmap_bit_p (osi->reexamine, num)) + if (!bitmap_bit_p (osi->reexamine, num) + || (visitlog && !bitmap_set_bit (*visitlog, num))) return size; + gimple *stmt = SSA_NAME_DEF_STMT (size); + if (stmt) + { + /* Only the PHI results are added to gimple. */ + gcc_checking_assert (gimple_code (stmt) == GIMPLE_PHI); + gcc_checking_assert (osi->object_size_type & OST_DYNAMIC); + unsigned i, num_args = gimple_phi_num_args (stmt); + + gcc_checking_assert (num_args > 0); + for (i = 0; i < num_args; i++) + { + tree rhs = gimple_phi_arg_def (stmt, i); + + if (TREE_CODE (rhs) == SSA_NAME + && bitmap_bit_p (osi->reexamine, SSA_NAME_VERSION (rhs))) + rhs = estimate_size (osi, rhs, visitlog); + + if (size_unknown_p (rhs, object_size_type)) + return size_unknown (object_size_type); + } + return size; + } return object_sizes_get (osi, osi->tempsize_objs[num]); } case MIN_EXPR: case MAX_EXPR: { - tree op0 = estimate_size (osi, TREE_OPERAND (size, 0)); - tree op1 = estimate_size (osi, TREE_OPERAND (size, 1)); + tree op0 = estimate_size (osi, TREE_OPERAND (size, 0), visitlog); + tree op1 = estimate_size (osi, TREE_OPERAND (size, 1), visitlog); if (size_unknown_p (op0, object_size_type) || size_unknown_p (op1, object_size_type)) return size_unknown (object_size_type); @@ -708,7 +732,7 @@ estimate_size (object_size_info *osi, tree size) case MINUS_EXPR: case PLUS_EXPR: { - tree ret = estimate_size (osi, TREE_OPERAND (size, 0)); + tree ret = estimate_size (osi, TREE_OPERAND (size, 0), visitlog); if (size_unknown_p (ret, object_size_type)) return size_unknown (object_size_type); @@ -821,6 +845,7 @@ resolve_dependency_loops (struct object_size_info *osi) if (TREE_CODE (szexpr) == INTEGER_CST) continue; tree sz = estimate_size (osi, szexpr); + gcc_checking_assert (TREE_CODE (sz) == INTEGER_CST); object_sizes_initialize (osi, i, sz); } @@ -829,6 +854,109 @@ resolve_dependency_loops (struct object_size_info *osi) release_ssa_name (ssa_name (i)); } +static void +get_insertion_point (struct object_size_info *osi, unsigned ssano, + gimple_stmt_iterator *gsi) +{ + unsigned varno = osi->tempsize_objs[ssano]; + gimple *stmt = SSA_NAME_DEF_STMT (ssa_name (varno)); + + switch (gimple_code (stmt)) + { + case GIMPLE_NOP: + *gsi = gsi_start_bb (single_succ (ENTRY_BLOCK_PTR_FOR_FN (cfun))); + break; + case GIMPLE_PHI: + { + gimple *size_stmt = SSA_NAME_DEF_STMT (object_sizes_get (osi, + varno)); + + for (unsigned i = 0; i < gimple_phi_num_args (stmt); i++) + { + tree rhs = gimple_phi_arg_def (size_stmt, i); + if (TREE_CODE (rhs) == SSA_NAME + && SSA_NAME_VERSION (rhs) == ssano) + { + edge e = gimple_phi_arg_edge (as_a (stmt), i); + *gsi = gsi_last_bb (e->src); + break; + } + } + break; + } + default: + *gsi = gsi_for_stmt (stmt); + } +} + +static void +gimplify_size_expressions (object_size_info *osi) +{ + int object_size_type = osi->object_size_type; + bitmap_iterator bi; + unsigned int i; + bool changed; + + /* Step 1: Propagate unknowns into expressions. */ + bitmap tempsize_free = BITMAP_ALLOC (NULL); + do + { + changed = false; + EXECUTE_IF_SET_IN_BITMAP (osi->reexamine, 0, i, bi) + { + unsigned varno = osi->tempsize_objs[i]; + + tree cur = object_sizes_get (osi, varno); + + if (size_unknown_p (cur, object_size_type)) + { + bitmap_set_bit (tempsize_free, i); + continue; + } + + tree szexpr = object_sizes_get (osi, i); + bitmap visitlog = BITMAP_ALLOC (NULL); + tree sz = estimate_size (osi, szexpr, &visitlog); + + if (size_unknown_p (sz, object_size_type)) + { + gimple *stmt = SSA_NAME_DEF_STMT (cur); + if (stmt) + { + gimple_stmt_iterator gsi = gsi_for_stmt (stmt); + remove_phi_node (&gsi, true); + } + bitmap_set_bit (tempsize_free, i); + object_sizes_initialize (osi, varno, sz); + changed = true; + } + } + bitmap_and_compl_into (osi->reexamine, tempsize_free); + } + while (changed); + + /* Expand all size expressions to put their definitions close to the objects + for whom size is being computed. */ + bitmap_and_compl_into (osi->reexamine, osi->phiresults); + EXECUTE_IF_SET_IN_BITMAP (osi->reexamine, 0, i, bi) + { + gimple_stmt_iterator gsi; + gimple_seq seq = NULL; + tree size_expr = object_sizes_get (osi, i); + + size_expr = size_binop (MODIFY_EXPR, ssa_name (i), size_expr); + force_gimple_operand (size_expr, &seq, true, NULL); + + get_insertion_point (osi, i, &gsi); + gsi_insert_seq_before (&gsi, seq, GSI_CONTINUE_LINKING); + } + + EXECUTE_IF_SET_IN_BITMAP (tempsize_free, 0, i, bi) + release_ssa_name (ssa_name (i)); + + BITMAP_FREE (tempsize_free); +} + /* Compute __builtin_object_size value for PTR and set *PSIZE to the resulting value. If the declared object is known and PDECL is nonnull, sets *PDECL to the object's DECL. OBJECT_SIZE_TYPE @@ -909,11 +1037,17 @@ compute_builtin_object_size (tree ptr, int object_size_type, osi.visited = BITMAP_ALLOC (NULL); osi.reexamine = BITMAP_ALLOC (NULL); + osi.phiresults = BITMAP_ALLOC (NULL); osi.tempsize_objs.create (0); collect_object_sizes_for (&osi, ptr); if (!bitmap_empty_p (osi.reexamine)) - resolve_dependency_loops (&osi); + { + if (dynamic) + gimplify_size_expressions (&osi); + else + resolve_dependency_loops (&osi); + } /* Debugging dumps. */ if (dump_file) @@ -936,6 +1070,7 @@ compute_builtin_object_size (tree ptr, int object_size_type, } osi.tempsize_objs.release (); + BITMAP_FREE (osi.phiresults); BITMAP_FREE (osi.reexamine); BITMAP_FREE (osi.visited); } @@ -970,6 +1105,24 @@ make_tempsize (struct object_size_info *osi, unsigned varno) return ssa; } +/* Get the temp size variable if it exists for the object with VARNO as ssa + name version and if it doesn't exist, create one. */ + +static tree +make_or_get_tempsize (struct object_size_info *osi, unsigned varno) +{ + tree ssa = object_sizes_get (osi, varno); + if (TREE_CODE (ssa) != SSA_NAME) + ssa = make_tempsize (osi, varno); + else if (dump_file) + { + fprintf (dump_file, " temp name already assigned: "); + print_generic_expr (dump_file, ssa, dump_flags); + fprintf (dump_file, "\n"); + } + return ssa; +} + /* Compute object_sizes for PTR, defined to VALUE, which is not an SSA_NAME. */ static tree @@ -1114,9 +1267,112 @@ cond_expr_object_size (struct object_size_info *osi, gimple *stmt) else elsebytes = expr_object_size (osi, else_); + if (size_unknown_p (thenbytes, object_size_type) + || size_unknown_p (elsebytes, object_size_type)) + return size_unknown (object_size_type); + + if (object_size_type & OST_DYNAMIC) + return fold_build3 (COND_EXPR, sizetype, gimple_assign_rhs1 (stmt), + thenbytes, elsebytes); + return size_binop (OST_TREE_CODE (object_size_type), thenbytes, elsebytes); } +static tree +phi_object_size (struct object_size_info *osi, gimple *stmt) +{ + int object_size_type = osi->object_size_type; + unsigned i; + + tree res = size_initval (object_size_type); + + for (i = 0; i < gimple_phi_num_args (stmt); i++) + { + tree rhs = gimple_phi_arg (stmt, i)->def; + tree phires; + + if (TREE_CODE (rhs) == SSA_NAME) + phires = ssa_object_size (osi, rhs, size_int (0)); + else + phires = expr_object_size (osi, rhs); + + res = size_binop (OST_TREE_CODE (object_size_type), res, phires); + + if (size_unknown_p (phires, object_size_type)) + break; + } + return res; +} + +static tree +phi_dynamic_object_size (struct object_size_info *osi, tree var) +{ + int object_size_type = osi->object_size_type; + unsigned int varno = SSA_NAME_VERSION (var); + gimple *stmt = SSA_NAME_DEF_STMT (var); + unsigned i, num_args = gimple_phi_num_args (stmt); + tree res; + + vec sizes; + sizes.create (0); + sizes.safe_grow (num_args); + + /* Bail out if the size of any of the PHI arguments cannot be + determined. */ + for (i = 0; i < num_args; i++) + { + tree rhs = gimple_phi_arg_def (stmt, i); + tree sz; + + if (TREE_CODE (rhs) != SSA_NAME) + sz = expr_object_size (osi, rhs); + else + sz = ssa_object_size (osi, rhs, size_int (0)); + + if (size_unknown_p (sz, object_size_type)) + break; + + sizes[i] = sz; + } + + if (i == num_args) + { + res = make_or_get_tempsize (osi, varno); + bitmap_set_bit (osi->phiresults, SSA_NAME_VERSION (res)); + object_sizes_initialize (osi, SSA_NAME_VERSION (res), res); + + gphi *phi = create_phi_node (res, gimple_bb (stmt)); + gphi *obj_phi = as_a (stmt); + + for (unsigned i = 0; i < gimple_phi_num_args (stmt); i++) + { + if (!is_gimple_variable (sizes[i])) + { + tree ssa = make_tempsize (osi, varno); + object_sizes_initialize (osi, SSA_NAME_VERSION (ssa), sizes[i]); + sizes[i] = ssa; + } + + add_phi_arg (phi, sizes[i], + gimple_phi_arg_edge (obj_phi, i), + gimple_phi_arg_location (obj_phi, i)); + } + + if (dump_file) + { + print_generic_expr (dump_file, var, dump_flags); + fprintf (dump_file, ": PHI Node with result: "); + print_gimple_stmt (dump_file, phi, dump_flags); + } + } + else + res = size_unknown (object_size_type); + + sizes.release (); + + return res; +} + /* Compute object sizes for VAR. For ADDR_EXPR an object size is the number of remaining bytes to the end of the object (where what is considered an object depends on @@ -1164,14 +1420,7 @@ collect_object_sizes_for (struct object_size_info *osi, tree var) print_generic_expr (dump_file, var, dump_flags); fprintf (dump_file, "\n"); } - res = object_sizes_get (osi, varno); - if (TREE_CODE (res) != SSA_NAME) - res = make_tempsize (osi, varno); - else if (dump_file) - { - fprintf (dump_file, " temp name already assigned: "); - print_generic_expr (dump_file, res, dump_flags); - } + res = make_or_get_tempsize (osi, varno); goto out; } @@ -1242,34 +1491,24 @@ collect_object_sizes_for (struct object_size_info *osi, tree var) case GIMPLE_PHI: { - unsigned i; - - res = size_initval (object_size_type); - - for (i = 0; i < gimple_phi_num_args (stmt); i++) - { - tree rhs = gimple_phi_arg (stmt, i)->def; - tree phires; - - if (object_sizes_unknown_p (object_size_type, varno)) - break; - - if (TREE_CODE (rhs) == SSA_NAME) - phires = ssa_object_size (osi, rhs, size_int (0)); - else - phires = expr_object_size (osi, rhs); - - res = size_binop (OST_TREE_CODE (object_size_type), res, phires); - - if (size_unknown_p (phires, object_size_type)) - break; - } + if (object_size_type & OST_DYNAMIC) + res = phi_dynamic_object_size (osi, var); + else + res = phi_object_size (osi, stmt); break; } default: gcc_unreachable (); } + + if ((object_size_type & OST_DYNAMIC) + && TREE_CODE (res) != INTEGER_CST && !is_gimple_variable (res)) + { + tree ssa = make_or_get_tempsize (osi, varno); + object_sizes_initialize (osi, SSA_NAME_VERSION (ssa), res); + res = ssa; + } bitmap_set_bit (computed[object_size_type], varno); out: object_sizes_set (osi, varno, res); @@ -1419,7 +1658,7 @@ object_sizes_execute (function *fun, bool early) and rather than folding the builtin to the constant if any, create a MIN_EXPR or MAX_EXPR of the __builtin_object_size call result and the computed constant. */ - if (early) + if (early && !dynamic) { early_object_sizes_execute_one (&i, call); continue;