[PATCH 06/10] tree-object-size: Support dynamic sizes in conditions

Siddhesh Poyarekar siddhesh@gotplt.org
Tue Nov 9 19:01:32 GMT 2021


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 <siddhesh@gotplt.org>
---
 .../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<unsigned> 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 <gphi *> (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<tree> 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 <gphi *> (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;
-- 
2.31.1



More information about the Gcc-patches mailing list