public inbox for gcc-patches@gcc.gnu.org
 help / color / mirror / Atom feed
From: Jakub Jelinek <jakub@redhat.com>
To: Jason Merrill <jason@redhat.com>,
	Richard Biener <rguenther@suse.de>,
	Jonathan Wakely <jwakely@redhat.com>,
	gcc-patches@gcc.gnu.org
Subject: [PATCH] c++: __builtin_clear_padding builtin follow-up [PR88101]
Date: Mon, 16 Nov 2020 22:13:52 +0100	[thread overview]
Message-ID: <20201116211352.GS3788@tucnak> (raw)
In-Reply-To: <20201116115755.GA369547@tucnak>

On Sun, Nov 15, 2020 at 11:57:55PM -1200, Jakub Jelinek via Gcc-patches wrote:
> Tested on x86_64-linux, i686-linux and powerpc64-linux, ok for trunk?

Here is an incremental patch that resolves the remaining FIXMEs, in
particular implements VLAs (except for variable length structures)
and for larger fixed sized arrays or members with larger array types
uses runtime loops for the clearing (unless inside of a union).
Furthermore, I've added diagnostics about last argument being const whatever *
(similarly to e.g. __builtin_*_overflow) and also about _Atomic whatever *.

Bootstrapped/regtested on x86_64-linux, ok for trunk?

2020-11-16  Jakub Jelinek  <jakub@redhat.com>

	PR libstdc++/88101
gcc/
	* gimple-fold.c (clear_padding_emit_loop): New function.
	(clear_padding_type): Optimize larger ARRAY_TYPEs not inside of a
	union by clearing the padding inside of a runtime loop.
	(gimple_fold_builtin_clear_padding): Handle VLAs.
gcc/c-family/
	* c-common.c (check_builtin_function_arguments)
	<case BUILT_IN_CLEAR_PADDING>: Diagnose pointer to const or pointer
	to _Atomic arguments.
gcc/testsuite/
	* c-c++-common/builtin-clear-padding-1.c (struct T): New type.
	(foo): Add test for const struct T * argument.
	* c-c++-common/torture/builtin-clear-padding-4.c: New test.
	* c-c++-common/torture/builtin-clear-padding-5.c: New test.
	* gcc.dg/builtin-clear-padding-2.c: New test.

--- gcc/gimple-fold.c.jj	2020-11-16 12:20:29.551779949 +0100
+++ gcc/gimple-fold.c	2020-11-16 18:47:42.997770758 +0100
@@ -4323,6 +4323,39 @@ clear_padding_type_may_have_padding_p (t
     }
 }
 
+/* Emit a runtime loop:
+   for (; buf.base != end; buf.base += sz)
+     __builtin_clear_padding (buf.base);  */
+
+static void
+clear_padding_emit_loop (clear_padding_struct *buf, tree type, tree end)
+{
+  tree l1 = create_artificial_label (buf->loc);
+  tree l2 = create_artificial_label (buf->loc);
+  tree l3 = create_artificial_label (buf->loc);
+  gimple *g = gimple_build_goto (l2);
+  gimple_set_location (g, buf->loc);
+  gsi_insert_before (buf->gsi, g, GSI_SAME_STMT);
+  g = gimple_build_label (l1);
+  gimple_set_location (g, buf->loc);
+  gsi_insert_before (buf->gsi, g, GSI_SAME_STMT);
+  clear_padding_type (buf, type);
+  clear_padding_flush (buf, true);
+  g = gimple_build_assign (buf->base, POINTER_PLUS_EXPR, buf->base,
+			   size_int (buf->sz));
+  gimple_set_location (g, buf->loc);
+  gsi_insert_before (buf->gsi, g, GSI_SAME_STMT);
+  g = gimple_build_label (l2);
+  gimple_set_location (g, buf->loc);
+  gsi_insert_before (buf->gsi, g, GSI_SAME_STMT);
+  g = gimple_build_cond (NE_EXPR, buf->base, end, l1, l3);
+  gimple_set_location (g, buf->loc);
+  gsi_insert_before (buf->gsi, g, GSI_SAME_STMT);
+  g = gimple_build_label (l3);
+  gimple_set_location (g, buf->loc);
+  gsi_insert_before (buf->gsi, g, GSI_SAME_STMT);
+}
+
 /* Clear padding bits for TYPE.  Called recursively from
    gimple_fold_builtin_clear_padding.  */
 
@@ -4423,11 +4456,41 @@ clear_padding_type (clear_padding_struct
       HOST_WIDE_INT nelts;
       nelts = int_size_in_bytes (TREE_TYPE (type));
       nelts = sz / nelts;
-      if (nelts > 1 && sz > 8 * UNITS_PER_WORD && buf->union_ptr == NULL)
+      if (nelts > 1
+	  && sz > 8 * UNITS_PER_WORD
+	  && buf->union_ptr == NULL
+	  && clear_padding_type_may_have_padding_p (TREE_TYPE (type)))
 	{
-	  /* FIXME: If ARRAY_TYPE has nelts > 1 and sz over certain
-	     small threshold, instead call clear_padding_flush (&buf, true);
-	     and emit a runtime loop filling each array element separately.  */
+	  /* For sufficiently large array of more than one elements,
+	     emit a runtime loop to keep code size manageable.  */
+	  tree base = buf->base;
+	  unsigned int prev_align = buf->align;
+	  HOST_WIDE_INT off = buf->off + buf->size;
+	  HOST_WIDE_INT prev_sz = buf->sz;
+	  clear_padding_flush (buf, true);
+	  tree elttype = TREE_TYPE (type);
+	  buf->base = create_tmp_var (build_pointer_type (elttype));
+	  tree end = make_ssa_name (TREE_TYPE (buf->base));
+	  gimple *g = gimple_build_assign (buf->base, POINTER_PLUS_EXPR,
+					   base, size_int (off));
+	  gimple_set_location (g, buf->loc);
+	  gsi_insert_before (buf->gsi, g, GSI_SAME_STMT);
+	  g = gimple_build_assign (end, POINTER_PLUS_EXPR, buf->base,
+				   size_int (sz));
+	  gimple_set_location (g, buf->loc);
+	  gsi_insert_before (buf->gsi, g, GSI_SAME_STMT);
+	  buf->sz = sz / nelts;
+	  buf->align = TYPE_ALIGN (elttype);
+	  buf->off = 0;
+	  buf->size = 0;
+	  clear_padding_emit_loop (buf, elttype, end);
+	  buf->base = base;
+	  buf->sz = prev_sz;
+	  buf->align = prev_align;
+	  buf->size = off % UNITS_PER_WORD;
+	  buf->off = off - buf->size;
+	  memset (buf->buf, 0, buf->size);
+	  break;
 	}
       for (HOST_WIDE_INT i = 0; i < nelts; i++)
 	clear_padding_type (buf, TREE_TYPE (type));
@@ -4514,11 +4577,28 @@ gimple_fold_builtin_clear_padding (gimpl
     ;
   else if (TREE_CODE (type) == ARRAY_TYPE && buf.sz < 0)
     {
-      /* FIXME: Handle VLAs.  These can be handled by adding runtime
-	 loop (or multiple for multiple VLAs) calling clear_padding_type
-	 only on each non-VLA element.  */
-      sorry_at (loc, "%s does not support VLAs yet",
-		"__builtin_clear_padding");
+      tree sz = TYPE_SIZE_UNIT (type);
+      tree elttype = type;
+      /* Only supports C/C++ VLAs and flattens all the VLA levels.  */
+      while (TREE_CODE (elttype) == ARRAY_TYPE
+	     && int_size_in_bytes (elttype) < 0)
+	elttype = TREE_TYPE (elttype);
+      HOST_WIDE_INT eltsz = int_size_in_bytes (elttype);
+      gcc_assert (eltsz >= 0);
+      if (eltsz)
+	{
+	  buf.base = create_tmp_var (build_pointer_type (elttype));
+	  tree end = make_ssa_name (TREE_TYPE (buf.base));
+	  gimple *g = gimple_build_assign (buf.base, ptr);
+	  gimple_set_location (g, loc);
+	  gsi_insert_before (gsi, g, GSI_SAME_STMT);
+	  g = gimple_build_assign (end, POINTER_PLUS_EXPR, buf.base, sz);
+	  gimple_set_location (g, loc);
+	  gsi_insert_before (gsi, g, GSI_SAME_STMT);
+	  buf.sz = eltsz;
+	  buf.align = TYPE_ALIGN (elttype);
+	  clear_padding_emit_loop (&buf, elttype, end);
+	}
     }
   else
     {
--- gcc/c-family/c-common.c.jj	2020-11-15 18:29:12.441618995 +0100
+++ gcc/c-family/c-common.c	2020-11-16 19:33:56.458507220 +0100
@@ -6186,6 +6186,20 @@ check_builtin_function_arguments (locati
 			"%qE points to incomplete type", 1, fndecl);
 	      return false;
 	    }
+	  else if (TYPE_READONLY (TREE_TYPE (TREE_TYPE (args[0]))))
+	    {
+	      error_at (ARG_LOCATION (0), "argument %u in call to function %qE "
+			"has pointer to %qs type (%qT)", 1, fndecl, "const",
+			TREE_TYPE (args[0]));
+	      return false;
+	    }
+	  else if (TYPE_ATOMIC (TREE_TYPE (TREE_TYPE (args[0]))))
+	    {
+	      error_at (ARG_LOCATION (0), "argument %u in call to function %qE "
+			"has pointer to %qs type (%qT)", 1, fndecl,
+			"_Atomic", TREE_TYPE (args[0]));
+	      return false;
+	    }
 	  return true;
 	}
       return false;
--- gcc/testsuite/c-c++-common/builtin-clear-padding-1.c.jj	2020-11-16 12:39:37.000000000 +0100
+++ gcc/testsuite/c-c++-common/builtin-clear-padding-1.c	2020-11-16 19:35:08.628693878 +0100
@@ -2,9 +2,10 @@
 /* { dg-do compile } */
 
 struct S;
+struct T { char a; long long b; };
 
 void
-foo (struct S *p, void *q, char *r)
+foo (struct S *p, void *q, char *r, const struct T *s)
 {
   __builtin_clear_padding ();		/* { dg-error "too few arguments to function '__builtin_clear_padding'" } */
   __builtin_clear_padding (1);		/* { dg-error "argument 1 in call to function '__builtin_clear_padding' does not have pointer type" } */
@@ -14,4 +15,5 @@ foo (struct S *p, void *q, char *r)
   __builtin_clear_padding (p);		/* { dg-error "argument 1 in call to function '__builtin_clear_padding' points to incomplete type" } */
   __builtin_clear_padding (q);		/* { dg-error "argument 1 in call to function '__builtin_clear_padding' points to incomplete type" } */
   __builtin_clear_padding (r);
+  __builtin_clear_padding (s);		/* { dg-error "argument 1 in call to function '__builtin_clear_padding' has pointer to 'const' type" } */
 }
--- gcc/testsuite/c-c++-common/torture/builtin-clear-padding-4.c.jj	2020-11-16 17:40:47.111049570 +0100
+++ gcc/testsuite/c-c++-common/torture/builtin-clear-padding-4.c	2020-11-16 17:40:53.074982330 +0100
@@ -0,0 +1,59 @@
+/* PR libstdc++/88101 */
+
+struct S { char a; short b; char c; };
+
+__attribute__((noipa)) void
+foo (int m, int n, int o)
+{
+  long double a1[m];
+  long double a2[m];
+  struct S b1[m][n];
+  struct S b2[m][n];
+  struct S c1[m][n][o];
+  struct S c2[m][n][o];
+  int i, j, k;
+  __builtin_memset (&a1, 0, sizeof (a1));
+  __builtin_memset (&a2, ~0, sizeof (a2));
+  __builtin_memset (&b1, 0, sizeof (b1));
+  __builtin_memset (&b2, ~0, sizeof (b2));
+  __builtin_memset (&c1, 0, sizeof (c1));
+  __builtin_memset (&c2, ~0, sizeof (c2));
+  for (i = 0; i < m; i++)
+    {
+      a1[i] = 13.132L;
+      a2[i] = 13.132L;
+      for (j = 0; j < n; j++)
+	{
+	  b1[i][j].a = -1;
+	  b1[i][j].b = -1;
+	  b1[i][j].c = -1;
+	  b2[i][j].a = -1;
+	  b2[i][j].b = -1;
+	  b2[i][j].c = -1;
+	  for (k = 0; k < o; k++)
+	    {
+	      c1[i][j][k].a = -1;
+	      c1[i][j][k].b = -1;
+	      c1[i][j][k].c = -1;
+	      c2[i][j][k].a = -1;
+	      c2[i][j][k].b = -1;
+	      c2[i][j][k].c = -1;
+	    }
+	}
+    }
+  __builtin_clear_padding (&a2);
+  __builtin_clear_padding (&b2);
+  __builtin_clear_padding (&c2);
+  if (__builtin_memcmp (&a1, &a2, sizeof (a1))
+      || __builtin_memcmp (&b1, &b2, sizeof (b1))
+      || __builtin_memcmp (&c1, &c2, sizeof (c1)))
+    __builtin_abort ();
+}
+
+int
+main ()
+{
+  foo (5, 3, 4);
+  foo (17, 2, 1);
+  return 0;
+}
--- gcc/testsuite/c-c++-common/torture/builtin-clear-padding-5.c.jj	2020-11-16 18:51:02.463521254 +0100
+++ gcc/testsuite/c-c++-common/torture/builtin-clear-padding-5.c	2020-11-16 17:58:58.385746596 +0100
@@ -0,0 +1,49 @@
+/* PR libstdc++/88101 */
+
+struct S { char a; short b; char c; } s1[24], s2[24];
+struct T { char a; long long b; char c; struct S d[3]; long long e; char f; } t1, t2;
+struct U { char a; long long b; char c; struct S d[25]; long long e; char f; } u1, u2;
+
+__attribute__((noipa)) void
+foo (struct S *s, struct T *t, struct U *u)
+{
+  int i;
+  t->a = -1; t->b = -1; t->c = -1; t->e = -1; t->f = -1;
+  u->a = -1; u->b = -1; u->c = -1; u->e = -1; u->f = -1;
+  for (i = 0; i < 24; i++)
+    {
+      s[i].a = -1;
+      s[i].b = -1;
+      s[i].c = -1;
+    }
+  for (i = 0; i < 3; i++)
+    {
+      t->d[i].a = -1;
+      t->d[i].b = -1;
+      t->d[i].c = -1;
+    }
+  for (i = 0; i < 25; i++)
+    {
+      u->d[i].a = -1;
+      u->d[i].b = -1;
+      u->d[i].c = -1;
+    }
+}
+
+int
+main ()
+{
+  __builtin_memset (&s2, -1, sizeof (s2));
+  __builtin_memset (&t2, -1, sizeof (t2));
+  __builtin_memset (&u2, -1, sizeof (u2));
+  foo (&s1[0], &t1, &u1);
+  foo (&s2[0], &t2, &u2);
+  __builtin_clear_padding (&s2);
+  __builtin_clear_padding (&t2);
+  __builtin_clear_padding (&u2);
+  if (__builtin_memcmp (&s1, &s2, sizeof (s1))
+      || __builtin_memcmp (&t1, &t2, sizeof (t1))
+      || __builtin_memcmp (&u1, &u2, sizeof (u1)))
+    __builtin_abort ();
+  return 0;
+}
--- gcc/testsuite/gcc.dg/builtin-clear-padding-2.c.jj	2020-11-16 19:36:17.221920848 +0100
+++ gcc/testsuite/gcc.dg/builtin-clear-padding-2.c	2020-11-16 19:36:44.158617264 +0100
@@ -0,0 +1,11 @@
+/* PR libstdc++/88101 */
+/* { dg-do compile } */
+/* { dg-options "" } */
+
+struct T { char a; long long b; };
+
+void
+foo (_Atomic struct T *p)
+{
+  __builtin_clear_padding (p);		/* { dg-error "argument 1 in call to function '__builtin_clear_padding' has pointer to '_Atomic' type" } */
+}


	Jakub


  reply	other threads:[~2020-11-16 21:14 UTC|newest]

Thread overview: 4+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2020-11-16 11:57 [PATCH] c++: Add __builtin_clear_padding builtin - C++20 P0528R3 compiler side [PR88101] Jakub Jelinek
2020-11-16 21:13 ` Jakub Jelinek [this message]
2020-11-18  8:48   ` [PATCH] c++: __builtin_clear_padding builtin C++ tail padding fix [PR88101] Jakub Jelinek
     [not found] ` <1AD8DAAC-A7A1-4A19-8538-4092C1F8C327@comcast.net>
2020-11-20 16:26   ` PDP endian bitfields Jakub Jelinek

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20201116211352.GS3788@tucnak \
    --to=jakub@redhat.com \
    --cc=gcc-patches@gcc.gnu.org \
    --cc=jason@redhat.com \
    --cc=jwakely@redhat.com \
    --cc=rguenther@suse.de \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).