On Fri, 20 Nov 2020, Jakub Jelinek wrote:

> On Fri, Nov 20, 2020 at 09:19:31AM +0000, Richard Biener wrote:
> > > --- gcc/builtins.c.jj     2020-11-19 12:34:10.749514278 +0100
> > > +++ gcc/builtins.c        2020-11-19 16:23:55.261250903 +0100
> > > @@ -11189,6 +11189,13 @@ fold_builtin_1 (location_t loc, tree exp
> > >   return build_empty_stmt (loc);
> > >        break;
> > >  
> > > +    case BUILT_IN_CLEAR_PADDING:
> > > +      /* Remember the original type of the argument in an internal
> > > +  dummy second argument, as in GIMPLE pointer conversions are
> > > +  useless.  */
> > > +      return build_call_expr_loc (loc, fndecl, 2, arg0,
> > > +                           build_zero_cst (TREE_TYPE (arg0)));
> > > +
> > 
> > I'd rather make this change during gimplify_call_expr, I'm not
> > even sure at which point we'd hit the above (and if at all).
> 
> As discussed on IRC, it was called from the FE folding or could be even from
> gimplify_call_expr which also folds builtins and it wasn't recursing
> because after it got second argument fold_builtin_1 wouldn't be called on it
> anymore (but fold_builtin_2).
> Anyway, I've implemented it now in gimplify_call_expr instead.
> 
> > You're using alias-set zero for all stores but since we're
> > effectively inspecting the layout of a type we could specify
> > that __builtin_clear_padding expects an object of said type
> > at the very location active as dynamic type.  So IMHO
> > less conservative but still sound would be to use
> > build_pointer_type (aggregate-type) in place of ptr_type_node.
> > 
> > I'm not sure it will make a difference but it might be useful
> > to parametrize 'ptr_type_node' in the IL generation?
> 
> Ok, added alias_type to the data structure which is passed around,
> and initialized it to pointer to the toplevel type (except for VLAs,
> in that case just to pointer to the VLA element type).
> 
> Here is the updated patch.

LGTM.

Thanks,
Richard.

> 
> 2020-11-20  Jakub Jelinek  <ja...@redhat.com>
> 
>       PR libstdc++/88101
> gcc/
>       * builtins.def (BUILT_IN_CLEAR_PADDING): New built-in function.
>       * gimplify.c (gimplify_call_expr): Rewrite single argument
>       BUILT_IN_CLEAR_PADDING into two-argument variant.
>       * gimple-fold.c (clear_padding_unit, clear_padding_buf_size): New
>       const variables.
>       (struct clear_padding_struct): New type.
>       (clear_padding_flush, clear_padding_add_padding,
>       clear_padding_emit_loop, clear_padding_type,
>       clear_padding_union, clear_padding_real_needs_padding_p,
>       clear_padding_type_may_have_padding_p,
>       gimple_fold_builtin_clear_padding): New functions.
>       (gimple_fold_builtin): Handle BUILT_IN_CLEAR_PADDING.
>       * doc/extend.texi (__builtin_clear_padding): Document.
> gcc/c-family/
>       * c-common.c (check_builtin_function_arguments): Handle
>       BUILT_IN_CLEAR_PADDING.
> gcc/testsuite/
>       * c-c++-common/builtin-clear-padding-1.c: New test.
>       * c-c++-common/torture/builtin-clear-padding-1.c: New test.
>       * c-c++-common/torture/builtin-clear-padding-2.c: New test.
>       * c-c++-common/torture/builtin-clear-padding-3.c: New test.
>       * c-c++-common/torture/builtin-clear-padding-4.c: New test.
>       * c-c++-common/torture/builtin-clear-padding-5.c: New test.
>       * g++.dg/torture/builtin-clear-padding-1.C: New test.
>       * g++.dg/torture/builtin-clear-padding-2.C: New test.
>       * gcc.dg/builtin-clear-padding-1.c: New test.
> 
> --- gcc/builtins.def.jj       2020-11-19 20:00:47.116518082 +0100
> +++ gcc/builtins.def  2020-11-20 10:51:44.715684363 +0100
> @@ -839,6 +839,7 @@ DEF_EXT_LIB_BUILTIN    (BUILT_IN_CLEAR_C
>  /* [trans-mem]: Adjust BUILT_IN_TM_CALLOC if BUILT_IN_CALLOC is changed.  */
>  DEF_LIB_BUILTIN        (BUILT_IN_CALLOC, "calloc", BT_FN_PTR_SIZE_SIZE, 
> ATTR_MALLOC_WARN_UNUSED_RESULT_SIZE_1_2_NOTHROW_LEAF_LIST)
>  DEF_GCC_BUILTIN        (BUILT_IN_CLASSIFY_TYPE, "classify_type", 
> BT_FN_INT_VAR, ATTR_LEAF_LIST)
> +DEF_GCC_BUILTIN        (BUILT_IN_CLEAR_PADDING, "clear_padding", 
> BT_FN_VOID_VAR, ATTR_NOTHROW_NONNULL_TYPEGENERIC_LEAF)
>  DEF_GCC_BUILTIN        (BUILT_IN_CLZ, "clz", BT_FN_INT_UINT, 
> ATTR_CONST_NOTHROW_LEAF_LIST)
>  DEF_GCC_BUILTIN        (BUILT_IN_CLZIMAX, "clzimax", BT_FN_INT_UINTMAX, 
> ATTR_CONST_NOTHROW_LEAF_LIST)
>  DEF_GCC_BUILTIN        (BUILT_IN_CLZL, "clzl", BT_FN_INT_ULONG, 
> ATTR_CONST_NOTHROW_LEAF_LIST)
> --- gcc/gimplify.c.jj 2020-11-20 08:43:52.262473979 +0100
> +++ gcc/gimplify.c    2020-11-20 10:58:37.035125705 +0100
> @@ -3384,6 +3384,20 @@ gimplify_call_expr (tree *expr_p, gimple
>       cfun->calls_eh_return = true;
>       break;
>  
> +      case BUILT_IN_CLEAR_PADDING:
> +     if (call_expr_nargs (*expr_p) == 1)
> +       {
> +         /* Remember the original type of the argument in an internal
> +            dummy second argument, as in GIMPLE pointer conversions are
> +            useless.  */
> +         p = CALL_EXPR_ARG (*expr_p, 0);
> +         *expr_p
> +           = build_call_expr_loc (EXPR_LOCATION (*expr_p), fndecl, 2, p,
> +                                  build_zero_cst (TREE_TYPE (p)));
> +         return GS_OK;
> +       }
> +     break;
> +
>        default:
>          ;
>        }
> --- gcc/gimple-fold.c.jj      2020-11-19 20:00:47.191517285 +0100
> +++ gcc/gimple-fold.c 2020-11-20 11:07:15.246395988 +0100
> @@ -3948,6 +3948,698 @@ gimple_fold_builtin_realloc (gimple_stmt
>    return false;
>  }
>  
> +/* Number of bytes into which any type but aggregate or vector types
> +   should fit.  */
> +static constexpr size_t clear_padding_unit
> +  = MAX_BITSIZE_MODE_ANY_MODE / BITS_PER_UNIT;
> +/* Buffer size on which __builtin_clear_padding folding code works.  */
> +static const size_t clear_padding_buf_size = 32 * clear_padding_unit;
> +
> +/* Data passed through __builtin_clear_padding folding.  */
> +struct clear_padding_struct {
> +  location_t loc;
> +  tree base;
> +  tree alias_type;
> +  gimple_stmt_iterator *gsi;
> +  /* Alignment of buf->base + 0.  */
> +  unsigned align;
> +  /* Offset from buf->base.  Should be always a multiple of UNITS_PER_WORD.  
> */
> +  HOST_WIDE_INT off;
> +  /* Number of padding bytes before buf->off that don't have padding clear
> +     code emitted yet.  */
> +  HOST_WIDE_INT padding_bytes;
> +  /* The size of the whole object.  Never emit code to touch
> +     buf->base + buf->sz or following bytes.  */
> +  HOST_WIDE_INT sz;
> +  /* Number of bytes recorded in buf->buf.  */
> +  size_t size;
> +  /* When inside union, instead of emitting code we and bits inside of
> +     the union_ptr array.  */
> +  unsigned char *union_ptr;
> +  /* Set bits mean padding bits that need to be cleared by the builtin.  */
> +  unsigned char buf[clear_padding_buf_size + clear_padding_unit];
> +};
> +
> +/* Emit code to clear padding requested in BUF->buf - set bits
> +   in there stand for padding that should be cleared.  FULL is true
> +   if everything from the buffer should be flushed, otherwise
> +   it can leave up to 2 * clear_padding_unit bytes for further
> +   processing.  */
> +
> +static void
> +clear_padding_flush (clear_padding_struct *buf, bool full)
> +{
> +  gcc_assert ((clear_padding_unit % UNITS_PER_WORD) == 0);
> +  if (!full && buf->size < 2 * clear_padding_unit)
> +    return;
> +  gcc_assert ((buf->off % UNITS_PER_WORD) == 0);
> +  size_t end = buf->size;
> +  if (!full)
> +    end = ((end - clear_padding_unit - 1) / clear_padding_unit
> +        * clear_padding_unit);
> +  size_t padding_bytes = buf->padding_bytes;
> +  if (buf->union_ptr)
> +    {
> +      /* Inside of a union, instead of emitting any code, instead
> +      clear all bits in the union_ptr buffer that are clear
> +      in buf.  Whole padding bytes don't clear anything.  */
> +      for (size_t i = 0; i < end; i++)
> +     {
> +       if (buf->buf[i] == (unsigned char) ~0)
> +         padding_bytes++;
> +       else
> +         {
> +           padding_bytes = 0;
> +           buf->union_ptr[buf->off + i] &= buf->buf[i];
> +         }
> +     }
> +      if (full)
> +     {
> +       buf->off = 0;
> +       buf->size = 0;
> +       buf->padding_bytes = 0;
> +     }
> +      else
> +     {
> +       memmove (buf->buf, buf->buf + end, buf->size - end);
> +       buf->off += end;
> +       buf->size -= end;
> +       buf->padding_bytes = padding_bytes;
> +     }
> +      return;
> +    }
> +  size_t wordsize = UNITS_PER_WORD;
> +  for (size_t i = 0; i < end; i += wordsize)
> +    {
> +      size_t nonzero_first = wordsize;
> +      size_t nonzero_last = 0;
> +      bool all_ones = true;
> +      if ((unsigned HOST_WIDE_INT) (buf->off + i + wordsize)
> +       > (unsigned HOST_WIDE_INT) buf->sz)
> +     {
> +       gcc_assert (wordsize > 1);
> +       wordsize /= 2;
> +       i -= wordsize;
> +       continue;
> +     }
> +      for (size_t j = i; j < i + wordsize && j < end; j++)
> +     {
> +       if (buf->buf[j])
> +         {
> +           if (nonzero_first == wordsize)
> +             {
> +               nonzero_first = j - i;
> +               nonzero_last = j - i;
> +             }
> +           if (nonzero_last != j - i)
> +             all_ones = false;
> +           nonzero_last = j + 1 - i;
> +         }
> +       if (buf->buf[j] != 0 && buf->buf[j] != (unsigned char) ~0)
> +         all_ones = false;
> +     }
> +      if (padding_bytes)
> +     {
> +       if (nonzero_first == 0
> +           && nonzero_last == wordsize
> +           && all_ones)
> +         {
> +           /* All bits are padding and we had some padding
> +              before too.  Just extend it.  */
> +           padding_bytes += wordsize;
> +           continue;
> +         }
> +       size_t padding_end = i;
> +       if (all_ones && nonzero_first == 0)
> +         {
> +           padding_bytes += nonzero_last;
> +           padding_end += nonzero_last;
> +           nonzero_first = wordsize;
> +           nonzero_last = 0;
> +         }
> +       tree atype = build_array_type_nelts (char_type_node, padding_bytes);
> +       tree dst = build2_loc (buf->loc, MEM_REF, atype, buf->base,
> +                              build_int_cst (buf->alias_type,
> +                                             buf->off + padding_end
> +                                             - padding_bytes));
> +       tree src = build_constructor (atype, NULL);
> +       gimple *g = gimple_build_assign (dst, src);
> +       gimple_set_location (g, buf->loc);
> +       gsi_insert_before (buf->gsi, g, GSI_SAME_STMT);
> +       padding_bytes = 0;
> +       buf->padding_bytes = 0;
> +     }
> +      if (nonzero_first == wordsize)
> +     /* All bits in a word are 0, there are no padding bits.  */
> +     continue;
> +      if (all_ones && nonzero_last == wordsize)
> +     {
> +       /* All bits between nonzero_first and end of word are padding
> +          bits, start counting padding_bytes.  */
> +       padding_bytes = nonzero_last - nonzero_first;
> +       continue;
> +     }
> +      for (size_t eltsz = 1; eltsz <= wordsize; eltsz <<= 1)
> +     {
> +       if (nonzero_last - nonzero_first <= eltsz
> +           && ((nonzero_first & ~(eltsz - 1))
> +               == ((nonzero_last - 1) & ~(eltsz - 1))))
> +         {
> +           tree type;
> +           if (eltsz == 1)
> +             type = char_type_node;
> +           else
> +             type = lang_hooks.types.type_for_size (eltsz * BITS_PER_UNIT,
> +                                                    0);
> +           size_t start = nonzero_first & ~(eltsz - 1);
> +           HOST_WIDE_INT off = buf->off + i + start;
> +           tree atype = type;
> +           if (eltsz > 1 && buf->align < TYPE_ALIGN (type))
> +             atype = build_aligned_type (type, buf->align);
> +           tree dst = build2_loc (buf->loc, MEM_REF, atype, buf->base,
> +                                  build_int_cst (buf->alias_type, off));
> +           tree src;
> +           gimple *g;
> +           if (all_ones
> +               && nonzero_first == start
> +               && nonzero_last == start + eltsz)
> +             src = build_zero_cst (type);
> +           else
> +             {
> +               src = make_ssa_name (type);
> +               g = gimple_build_assign (src, unshare_expr (dst));
> +               gimple_set_location (g, buf->loc);
> +               gsi_insert_before (buf->gsi, g, GSI_SAME_STMT);
> +               tree mask = native_interpret_expr (type,
> +                                                  buf->buf + i + start,
> +                                                  eltsz);
> +               gcc_assert (mask && TREE_CODE (mask) == INTEGER_CST);
> +               mask = fold_build1 (BIT_NOT_EXPR, type, mask);
> +               tree src_masked = make_ssa_name (type);
> +               g = gimple_build_assign (src_masked, BIT_AND_EXPR,
> +                                        src, mask);
> +               gimple_set_location (g, buf->loc);
> +               gsi_insert_before (buf->gsi, g, GSI_SAME_STMT);
> +               src = src_masked;
> +             }
> +           g = gimple_build_assign (dst, src);
> +           gimple_set_location (g, buf->loc);
> +           gsi_insert_before (buf->gsi, g, GSI_SAME_STMT);
> +           break;
> +         }
> +     }
> +    }
> +  if (full)
> +    {
> +      if (padding_bytes)
> +     {
> +       tree atype = build_array_type_nelts (char_type_node, padding_bytes);
> +       tree dst = build2_loc (buf->loc, MEM_REF, atype, buf->base,
> +                              build_int_cst (buf->alias_type,
> +                                             buf->off + end
> +                                             - padding_bytes));
> +       tree src = build_constructor (atype, NULL);
> +       gimple *g = gimple_build_assign (dst, src);
> +       gimple_set_location (g, buf->loc);
> +       gsi_insert_before (buf->gsi, g, GSI_SAME_STMT);
> +     }
> +      size_t end_rem = end % UNITS_PER_WORD;
> +      buf->off += end - end_rem;
> +      buf->size = end_rem;
> +      memset (buf->buf, 0, buf->size);
> +      buf->padding_bytes = 0;
> +    }
> +  else
> +    {
> +      memmove (buf->buf, buf->buf + end, buf->size - end);
> +      buf->off += end;
> +      buf->size -= end;
> +      buf->padding_bytes = padding_bytes;
> +    }
> +}
> +
> +/* Append PADDING_BYTES padding bytes.  */
> +
> +static void
> +clear_padding_add_padding (clear_padding_struct *buf,
> +                        HOST_WIDE_INT padding_bytes)
> +{
> +  if (padding_bytes == 0)
> +    return;
> +  if ((unsigned HOST_WIDE_INT) padding_bytes + buf->size
> +      > (unsigned HOST_WIDE_INT) clear_padding_buf_size)
> +    clear_padding_flush (buf, false);
> +  if ((unsigned HOST_WIDE_INT) padding_bytes + buf->size
> +      > (unsigned HOST_WIDE_INT) clear_padding_buf_size)
> +    {
> +      memset (buf->buf + buf->size, ~0, clear_padding_buf_size - buf->size);
> +      padding_bytes -= clear_padding_buf_size - buf->size;
> +      buf->size = clear_padding_buf_size;
> +      clear_padding_flush (buf, false);
> +      gcc_assert (buf->padding_bytes);
> +      /* At this point buf->buf[0] through buf->buf[buf->size - 1]
> +      is guaranteed to be all ones.  */
> +      padding_bytes += buf->size;
> +      buf->size = padding_bytes % UNITS_PER_WORD;
> +      memset (buf->buf, ~0, buf->size);
> +      buf->off += padding_bytes - buf->size;
> +      buf->padding_bytes += padding_bytes - buf->size;
> +    }
> +  else
> +    {
> +      memset (buf->buf + buf->size, ~0, padding_bytes);
> +      buf->size += padding_bytes;
> +    }
> +}
> +
> +static void clear_padding_type (clear_padding_struct *, tree, HOST_WIDE_INT);
> +
> +/* Clear padding bits of union type TYPE.  */
> +
> +static void
> +clear_padding_union (clear_padding_struct *buf, tree type, HOST_WIDE_INT sz)
> +{
> +  clear_padding_struct *union_buf;
> +  HOST_WIDE_INT start_off = 0, next_off = 0;
> +  size_t start_size = 0;
> +  if (buf->union_ptr)
> +    {
> +      start_off = buf->off + buf->size;
> +      next_off = start_off + sz;
> +      start_size = start_off % UNITS_PER_WORD;
> +      start_off -= start_size;
> +      clear_padding_flush (buf, true);
> +      union_buf = buf;
> +    }
> +  else
> +    {
> +      if (sz + buf->size > clear_padding_buf_size)
> +     clear_padding_flush (buf, false);
> +      union_buf = XALLOCA (clear_padding_struct);
> +      union_buf->loc = buf->loc;
> +      union_buf->base = NULL_TREE;
> +      union_buf->alias_type = NULL_TREE;
> +      union_buf->gsi = NULL;
> +      union_buf->align = 0;
> +      union_buf->off = 0;
> +      union_buf->padding_bytes = 0;
> +      union_buf->sz = sz;
> +      union_buf->size = 0;
> +      if (sz + buf->size <= clear_padding_buf_size)
> +     union_buf->union_ptr = buf->buf + buf->size;
> +      else
> +     union_buf->union_ptr = XNEWVEC (unsigned char, sz);
> +      memset (union_buf->union_ptr, ~0, sz);
> +    }
> +
> +  for (tree field = TYPE_FIELDS (type); field; field = DECL_CHAIN (field))
> +    if (TREE_CODE (field) == FIELD_DECL)
> +      {
> +     HOST_WIDE_INT fldsz = tree_to_shwi (DECL_SIZE_UNIT (field));
> +     gcc_assert (union_buf->size == 0);
> +     union_buf->off = start_off;
> +     union_buf->size = start_size;
> +     memset (union_buf->buf, ~0, start_size);
> +     clear_padding_type (union_buf, TREE_TYPE (field), fldsz);
> +     clear_padding_add_padding (union_buf, sz - fldsz);
> +     clear_padding_flush (union_buf, true);
> +      }
> +
> +  if (buf == union_buf)
> +    {
> +      buf->off = next_off;
> +      buf->size = next_off % UNITS_PER_WORD;
> +      buf->off -= buf->size;
> +      memset (buf->buf, ~0, buf->size);
> +    }
> +  else if (sz + buf->size <= clear_padding_buf_size)
> +    buf->size += sz;
> +  else
> +    {
> +      unsigned char *union_ptr = union_buf->union_ptr;
> +      while (sz)
> +     {
> +       clear_padding_flush (buf, false);
> +       HOST_WIDE_INT this_sz
> +         = MIN ((unsigned HOST_WIDE_INT) sz,
> +                clear_padding_buf_size - buf->size);
> +       memcpy (buf->buf + buf->size, union_ptr, this_sz);
> +       buf->size += this_sz;
> +       union_ptr += this_sz;
> +       sz -= this_sz;
> +     }
> +      XDELETE (union_buf->union_ptr);
> +    }
> +}
> +
> +/* The only known floating point formats with padding bits are the
> +   IEEE extended ones.  */
> +
> +static bool
> +clear_padding_real_needs_padding_p (tree type)
> +{
> +  const struct real_format *fmt = REAL_MODE_FORMAT (TYPE_MODE (type));
> +  return (fmt->b == 2
> +       && fmt->signbit_ro == fmt->signbit_rw
> +       && (fmt->signbit_ro == 79 || fmt->signbit_ro == 95));
> +}
> +
> +/* Return true if TYPE might contain any padding bits.  */
> +
> +static bool
> +clear_padding_type_may_have_padding_p (tree type)
> +{
> +  switch (TREE_CODE (type))
> +    {
> +    case RECORD_TYPE:
> +    case UNION_TYPE:
> +      return true;
> +    case ARRAY_TYPE:
> +    case COMPLEX_TYPE:
> +    case VECTOR_TYPE:
> +      return clear_padding_type_may_have_padding_p (TREE_TYPE (type));
> +    case REAL_TYPE:
> +      return clear_padding_real_needs_padding_p (type);
> +    default:
> +      return false;
> +    }
> +}
> +
> +/* 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, buf->sz);
> +  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.  */
> +
> +static void
> +clear_padding_type (clear_padding_struct *buf, tree type, HOST_WIDE_INT sz)
> +{
> +  switch (TREE_CODE (type))
> +    {
> +    case RECORD_TYPE:
> +      HOST_WIDE_INT cur_pos;
> +      cur_pos = 0;
> +      for (tree field = TYPE_FIELDS (type); field; field = DECL_CHAIN 
> (field))
> +     if (TREE_CODE (field) == FIELD_DECL)
> +       {
> +         if (DECL_BIT_FIELD (field))
> +           {
> +             if (DECL_NAME (field) == NULL_TREE)
> +               continue;
> +             HOST_WIDE_INT fldsz = TYPE_PRECISION (TREE_TYPE (field));
> +             if (fldsz == 0)
> +               continue;
> +             HOST_WIDE_INT pos = int_byte_position (field);
> +             HOST_WIDE_INT bpos
> +               = tree_to_uhwi (DECL_FIELD_BIT_OFFSET (field));
> +             bpos %= BITS_PER_UNIT;
> +             HOST_WIDE_INT end
> +               = ROUND_UP (bpos + fldsz, BITS_PER_UNIT) / BITS_PER_UNIT;
> +             if (pos + end > cur_pos)
> +               {
> +                 clear_padding_add_padding (buf, pos + end - cur_pos);
> +                 cur_pos = pos + end;
> +               }
> +             gcc_assert (cur_pos > pos
> +                         && ((unsigned HOST_WIDE_INT) buf->size
> +                             >= (unsigned HOST_WIDE_INT) cur_pos - pos));
> +             unsigned char *p = buf->buf + buf->size - (cur_pos - pos);
> +             if (BYTES_BIG_ENDIAN != WORDS_BIG_ENDIAN)
> +               sorry_at (buf->loc, "PDP11 bit-field handling unsupported"
> +                                   " in %qs", "__builtin_clear_padding");
> +             else if (BYTES_BIG_ENDIAN)
> +               {
> +                 /* Big endian.  */
> +                 if (bpos + fldsz <= BITS_PER_UNIT)
> +                   *p &= ~(((1 << fldsz) - 1)
> +                           << (BITS_PER_UNIT - bpos - fldsz));
> +                 else
> +                   {
> +                     if (bpos)
> +                       {
> +                         *p &= ~(((1U << BITS_PER_UNIT) - 1) >> bpos);
> +                         p++;
> +                         fldsz -= BITS_PER_UNIT - bpos;
> +                       }
> +                     memset (p, 0, fldsz / BITS_PER_UNIT);
> +                     p += fldsz / BITS_PER_UNIT;
> +                     fldsz %= BITS_PER_UNIT;
> +                     if (fldsz)
> +                       *p &= ((1U << BITS_PER_UNIT) - 1) >> fldsz;
> +                   }
> +               }
> +             else
> +               {
> +                 /* Little endian.  */
> +                 if (bpos + fldsz <= BITS_PER_UNIT)
> +                   *p &= ~(((1 << fldsz) - 1) << bpos);
> +                 else
> +                   {
> +                     if (bpos)
> +                       {
> +                         *p &= ~(((1 << BITS_PER_UNIT) - 1) << bpos);
> +                         p++;
> +                         fldsz -= BITS_PER_UNIT - bpos;
> +                       }
> +                     memset (p, 0, fldsz / BITS_PER_UNIT);
> +                     p += fldsz / BITS_PER_UNIT;
> +                     fldsz %= BITS_PER_UNIT;
> +                     if (fldsz)
> +                       *p &= ~((1 << fldsz) - 1);
> +                   }
> +               }
> +           }
> +         else
> +           {
> +             HOST_WIDE_INT pos = int_byte_position (field);
> +             HOST_WIDE_INT fldsz = tree_to_shwi (DECL_SIZE_UNIT (field));
> +             gcc_assert (pos >= 0 && fldsz >= 0 && pos >= cur_pos);
> +             clear_padding_add_padding (buf, pos - cur_pos);
> +             cur_pos = pos;
> +             clear_padding_type (buf, TREE_TYPE (field), fldsz);
> +             cur_pos += fldsz;
> +           }
> +       }
> +      gcc_assert (sz >= cur_pos);
> +      clear_padding_add_padding (buf, sz - cur_pos);
> +      break;
> +    case ARRAY_TYPE:
> +      HOST_WIDE_INT nelts, fldsz;
> +      fldsz = int_size_in_bytes (TREE_TYPE (type));
> +      nelts = sz / fldsz;
> +      if (nelts > 1
> +       && sz > 8 * UNITS_PER_WORD
> +       && buf->union_ptr == NULL
> +       && clear_padding_type_may_have_padding_p (TREE_TYPE (type)))
> +     {
> +       /* 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 = fldsz;
> +       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), fldsz);
> +      break;
> +    case UNION_TYPE:
> +      clear_padding_union (buf, type, sz);
> +      break;
> +    case REAL_TYPE:
> +      gcc_assert ((size_t) sz <= clear_padding_unit);
> +      if ((unsigned HOST_WIDE_INT) sz + buf->size > clear_padding_buf_size)
> +     clear_padding_flush (buf, false);
> +      if (clear_padding_real_needs_padding_p (type))
> +     {
> +       /* Use native_interpret_expr + native_encode_expr to figure out
> +          which bits are padding.  */
> +       memset (buf->buf + buf->size, ~0, sz);
> +       tree cst = native_interpret_expr (type, buf->buf + buf->size, sz);
> +       gcc_assert (cst && TREE_CODE (cst) == REAL_CST);
> +       int len = native_encode_expr (cst, buf->buf + buf->size, sz);
> +       gcc_assert (len > 0 && (size_t) len == (size_t) sz);
> +       for (size_t i = 0; i < (size_t) sz; i++)
> +         buf->buf[buf->size + i] ^= ~0;
> +     }
> +      else
> +     memset (buf->buf + buf->size, 0, sz);
> +      buf->size += sz;
> +      break;
> +    case COMPLEX_TYPE:
> +      fldsz = int_size_in_bytes (TREE_TYPE (type));
> +      clear_padding_type (buf, TREE_TYPE (type), fldsz);
> +      clear_padding_type (buf, TREE_TYPE (type), fldsz);
> +      break;
> +    case VECTOR_TYPE:
> +      nelts = TYPE_VECTOR_SUBPARTS (type).to_constant ();
> +      fldsz = int_size_in_bytes (TREE_TYPE (type));
> +      for (HOST_WIDE_INT i = 0; i < nelts; i++)
> +     clear_padding_type (buf, TREE_TYPE (type), fldsz);
> +      break;
> +    case NULLPTR_TYPE:
> +      gcc_assert ((size_t) sz <= clear_padding_unit);
> +      if ((unsigned HOST_WIDE_INT) sz + buf->size > clear_padding_buf_size)
> +     clear_padding_flush (buf, false);
> +      memset (buf->buf + buf->size, ~0, sz);
> +      buf->size += sz;
> +      break;
> +    default:
> +      gcc_assert ((size_t) sz <= clear_padding_unit);
> +      if ((unsigned HOST_WIDE_INT) sz + buf->size > clear_padding_buf_size)
> +     clear_padding_flush (buf, false);
> +      memset (buf->buf + buf->size, 0, sz);
> +      buf->size += sz;
> +      break;
> +    }
> +}
> +
> +/* Fold __builtin_clear_padding builtin.  */
> +
> +static bool
> +gimple_fold_builtin_clear_padding (gimple_stmt_iterator *gsi)
> +{
> +  gimple *stmt = gsi_stmt (*gsi);
> +  gcc_assert (gimple_call_num_args (stmt) == 2);
> +  tree ptr = gimple_call_arg (stmt, 0);
> +  tree typearg = gimple_call_arg (stmt, 1);
> +  tree type = TREE_TYPE (TREE_TYPE (typearg));
> +  location_t loc = gimple_location (stmt);
> +  clear_padding_struct buf;
> +  gimple_stmt_iterator gsiprev = *gsi;
> +  /* This should be folded during the lower pass.  */
> +  gcc_assert (!gimple_in_ssa_p (cfun) && cfun->cfg == NULL);
> +  gcc_assert (COMPLETE_TYPE_P (type));
> +  gsi_prev (&gsiprev);
> +
> +  buf.loc = loc;
> +  buf.base = ptr;
> +  buf.alias_type = NULL_TREE;
> +  buf.gsi = gsi;
> +  buf.align = get_pointer_alignment (ptr);
> +  unsigned int talign = min_align_of_type (type) * BITS_PER_UNIT;
> +  buf.align = MAX (buf.align, talign);
> +  buf.off = 0;
> +  buf.padding_bytes = 0;
> +  buf.size = 0;
> +  buf.sz = int_size_in_bytes (type);
> +  buf.union_ptr = NULL;
> +  if (buf.sz < 0 && int_size_in_bytes (strip_array_types (type)) < 0)
> +    sorry_at (loc, "%s not supported for variable length aggregates",
> +           "__builtin_clear_padding");
> +  /* The implementation currently assumes 8-bit host and target
> +     chars which is the case for all currently supported targets
> +     and hosts and is required e.g. for native_{encode,interpret}* APIs.  */
> +  else if (CHAR_BIT != 8 || BITS_PER_UNIT != 8)
> +    sorry_at (loc, "%s not supported on this target",
> +           "__builtin_clear_padding");
> +  else if (!clear_padding_type_may_have_padding_p (type))
> +    ;
> +  else if (TREE_CODE (type) == ARRAY_TYPE && buf.sz < 0)
> +    {
> +      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);
> +       buf.alias_type = build_pointer_type (elttype);
> +       clear_padding_emit_loop (&buf, elttype, end);
> +     }
> +    }
> +  else
> +    {
> +      if (!is_gimple_mem_ref_addr (buf.base))
> +     {
> +       buf.base = make_ssa_name (TREE_TYPE (ptr));
> +       gimple *g = gimple_build_assign (buf.base, ptr);
> +       gimple_set_location (g, loc);
> +       gsi_insert_before (gsi, g, GSI_SAME_STMT);
> +     }
> +      buf.alias_type = build_pointer_type (type);
> +      clear_padding_type (&buf, type, buf.sz);
> +      clear_padding_flush (&buf, true);
> +    }
> +
> +  gimple_stmt_iterator gsiprev2 = *gsi;
> +  gsi_prev (&gsiprev2);
> +  if (gsi_stmt (gsiprev) == gsi_stmt (gsiprev2))
> +    gsi_replace (gsi, gimple_build_nop (), true);
> +  else
> +    {
> +      gsi_remove (gsi, true);
> +      *gsi = gsiprev2;
> +    }
> +  return true;
> +}
> +
>  /* Fold the non-target builtin at *GSI and return whether any simplification
>     was made.  */
>  
> @@ -4105,6 +4797,9 @@ gimple_fold_builtin (gimple_stmt_iterato
>      case BUILT_IN_REALLOC:
>        return gimple_fold_builtin_realloc (gsi);
>  
> +    case BUILT_IN_CLEAR_PADDING:
> +      return gimple_fold_builtin_clear_padding (gsi);
> +
>      default:;
>      }
>  
> --- gcc/doc/extend.texi.jj    2020-11-19 20:00:57.421408611 +0100
> +++ gcc/doc/extend.texi       2020-11-20 10:51:44.719684319 +0100
> @@ -13564,6 +13564,19 @@ initializers of variables usable in cons
>  refer to the latest revision of the C++ standard.
>  @end deftypefn
>  
> +@deftypefn {Built-in Function} void __builtin_clear_padding (@var{ptr})
> +The built-in function @code{__builtin_clear_padding} function clears
> +padding bits inside of the object representation of object pointed by
> +@var{ptr}, which has to be a pointer.  The value representation of the
> +object is not affected.  The type of the object is assumed to be the type
> +the pointer points to.  Inside of a union, the only cleared bits are
> +bits that are padding bits for all the union members.
> +
> +This built-in-function is useful if the padding bits of an object might
> +have intederminate values and the object representation needs to be
> +bitwise compared to some other object, for example for atomic operations.
> +@end deftypefn
> +
>  @deftypefn {Built-in Function} long __builtin_expect (long @var{exp}, long 
> @var{c})
>  @opindex fprofile-arcs
>  You may use @code{__builtin_expect} to provide the compiler with
> --- gcc/c-family/c-common.c.jj        2020-11-19 20:00:47.148517742 +0100
> +++ gcc/c-family/c-common.c   2020-11-20 10:51:44.720684308 +0100
> @@ -6178,6 +6178,39 @@ check_builtin_function_arguments (locati
>       }
>        return false;
>  
> +    case BUILT_IN_CLEAR_PADDING:
> +      if (builtin_function_validate_nargs (loc, fndecl, nargs, 1))
> +     {
> +       if (!POINTER_TYPE_P (TREE_TYPE (args[0])))
> +         {
> +           error_at (ARG_LOCATION (0), "argument %u in call to function "
> +                     "%qE does not have pointer type", 1, fndecl);
> +           return false;
> +         }
> +       else if (!COMPLETE_TYPE_P (TREE_TYPE (TREE_TYPE (args[0]))))
> +         {
> +           error_at (ARG_LOCATION (0), "argument %u in call to function "
> +                     "%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;
> +
>      default:
>        return true;
>      }
> --- gcc/testsuite/c-c++-common/builtin-clear-padding-1.c.jj   2020-11-20 
> 10:51:44.720684308 +0100
> +++ gcc/testsuite/c-c++-common/builtin-clear-padding-1.c      2020-11-20 
> 10:51:44.720684308 +0100
> @@ -0,0 +1,19 @@
> +/* PR libstdc++/88101 */
> +/* { dg-do compile } */
> +
> +struct S;
> +struct T { char a; long long b; };
> +
> +void
> +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" } */
> +  __builtin_clear_padding (&p);
> +  __builtin_clear_padding (&p, 1);   /* { dg-error "too many arguments to 
> function '__builtin_clear_padding'" } */
> +  __builtin_clear_padding (&p, &p);  /* { dg-error "too many arguments to 
> function '__builtin_clear_padding'" } */
> +  __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-1.c.jj   
> 2020-11-20 10:51:44.720684308 +0100
> +++ gcc/testsuite/c-c++-common/torture/builtin-clear-padding-1.c      
> 2020-11-20 10:51:44.720684308 +0100
> @@ -0,0 +1,47 @@
> +/* PR libstdc++/88101 */
> +
> +int i1, i2;
> +long double l1, l2;
> +struct S { char a; short b; char c; int d; char e; long long f; char g; long 
> double h; } s1, s2;
> +struct T { int a; struct S b[3]; int c; } t1, t2;
> +struct U { int a : 3; int : 2; int b : 15; int : 14; int c : 1; int : 0; int 
> : 3; int d : 2; int : 3; int e : 13; int : 3; signed char f; } u1, u2;
> +
> +__attribute__((noipa)) void
> +foo (int *i, long double *l, struct S *s, struct T *t, struct U *u)
> +{
> +  *i = 123;
> +  *l = -123.456L;
> +  s->a = 1; s->b = 2; s->c = 3; s->d = 4; s->e = 5; s->f = 6; s->g = 7; s->h 
> = 18.52L;
> +  t->a = 8; t->c = 9;
> +  t->b[0].a = 11; t->b[0].b = 12; t->b[0].c = 13; t->b[0].d = 14;
> +  t->b[0].e = 15; t->b[0].f = 16; t->b[0].g = 17; t->b[0].h = 18.26L;
> +  t->b[1].a = 21; t->b[1].b = 22; t->b[1].c = 23; t->b[1].d = 24;
> +  t->b[1].e = 25; t->b[1].f = 26; t->b[1].g = 27; t->b[1].h = 28.26L;
> +  t->b[2].a = 31; t->b[2].b = 32; t->b[2].c = 33; t->b[2].d = 34;
> +  t->b[2].e = 35; t->b[2].f = 36; t->b[2].g = 37; t->b[2].h = 38.26L;
> +  u->a = -1; u->b = -1; u->c = -1; u->d = -1; u->e = -1; u->f = -1;
> +}
> +
> +int
> +main ()
> +{
> +  __builtin_memset (&i2, -1, sizeof (i2));
> +  __builtin_memset (&l2, -1, sizeof (i2));
> +  __builtin_memset (&s2, -1, sizeof (s2));
> +  __builtin_memset (&t2, -1, sizeof (t2));
> +  __builtin_memset (&u2, -1, sizeof (u2));
> +  foo (&i1, &l1, &s1, &t1, &u1);
> +  foo (&i2, &l2, &s2, &t2, &u2);
> +  __builtin_clear_padding (&i2);
> +  __builtin_clear_padding (&l2);
> +  __builtin_clear_padding (&s2);
> +  __builtin_clear_padding (&t2);
> +  __builtin_clear_padding (&u2);
> +  if (__builtin_memcmp (&i1, &i2, sizeof (i1))
> +      || __builtin_memcmp (&l1, &l2, sizeof (l1))
> +      || __builtin_memcmp (&s1, &s2, sizeof (s1))
> +      || __builtin_memcmp (&t1, &t2, sizeof (t1))
> +      || __builtin_memcmp (&u1, &u2, sizeof (u1)))
> +    __builtin_abort ();
> +  return 0;
> +}
> --- gcc/testsuite/c-c++-common/torture/builtin-clear-padding-2.c.jj   
> 2020-11-20 10:51:44.720684308 +0100
> +++ gcc/testsuite/c-c++-common/torture/builtin-clear-padding-2.c      
> 2020-11-20 10:51:44.720684308 +0100
> @@ -0,0 +1,24 @@
> +/* PR libstdc++/88101 */
> +
> +typedef int T __attribute__((aligned (16384)));
> +struct S { char a; short b; long double c; T d; T e; long long f; };
> +
> +__attribute__((noipa)) void
> +foo (struct S *s)
> +{
> +  s->a = -1; s->b = -1; s->c = -18.52L; s->d = -1; s->e = -1; s->f = -1;
> +}
> +
> +int
> +main ()
> +{
> +  struct S s1, s2;
> +  __builtin_memset (&s1, 0, sizeof (s1));
> +  __builtin_memset (&s2, -1, sizeof (s2));
> +  foo (&s1);
> +  foo (&s2);
> +  __builtin_clear_padding (&s2);
> +  if (__builtin_memcmp (&s1, &s2, sizeof (s1)))
> +    __builtin_abort ();
> +  return 0;
> +}
> --- gcc/testsuite/c-c++-common/torture/builtin-clear-padding-3.c.jj   
> 2020-11-20 10:51:44.720684308 +0100
> +++ gcc/testsuite/c-c++-common/torture/builtin-clear-padding-3.c      
> 2020-11-20 10:51:44.720684308 +0100
> @@ -0,0 +1,65 @@
> +/* PR libstdc++/88101 */
> +
> +union V { char a; signed char b; unsigned char c; };
> +struct T { char a; int b; union V c; };
> +union U { int a; long double b; struct T c; };
> +struct S { char a; union U b; long long c; char d; } s1, s2;
> +
> +__attribute__((noipa)) void
> +foo (struct S *s, int x)
> +{
> +  s->a = -1; s->c = -1; s->d = -1;
> +  switch (x)
> +    {
> +    case 0:
> +      s->b.a = -1;
> +      break;
> +    case 1:
> +      s->b.b = -12345.25L;
> +      break;
> +    case 2:
> +      s->b.c.a = -1;
> +      s->b.c.b = -1;
> +      s->b.c.c.b = -1;
> +      break;
> +    }
> +}
> +
> +int
> +main ()
> +{
> +  __builtin_memset (&s1, 0, sizeof (s1));
> +  __builtin_memset (&s2, -1, sizeof (s2));
> +  foo (&s1, 0);
> +  foo (&s2, 0);
> +  __builtin_clear_padding (&s2);
> +  if (s2.b.a != (char) -1)
> +    __builtin_abort ();
> +  __builtin_clear_padding (&s2.b.a);
> +  __builtin_memset (&s2.b.a + 1, 0, sizeof (union U) - sizeof (s2.b.a));
> +  if (__builtin_memcmp (&s1, &s2, sizeof (s1)))
> +    __builtin_abort ();
> +  __builtin_memset (&s1, 0, sizeof (s1));
> +  __builtin_memset (&s2, -1, sizeof (s2));
> +  foo (&s1, 1);
> +  foo (&s2, 1);
> +  __builtin_clear_padding (&s2);
> +  if (s2.b.b != -12345.25L)
> +    __builtin_abort ();
> +  __builtin_clear_padding (&s2.b.b);
> +  __builtin_memset (&s2.b.b + 1, 0, sizeof (union U) - sizeof (s2.b.b));
> +  if (__builtin_memcmp (&s1, &s2, sizeof (s1)))
> +    __builtin_abort ();
> +  __builtin_memset (&s1, 0, sizeof (s1));
> +  __builtin_memset (&s2, -1, sizeof (s2));
> +  foo (&s1, 2);
> +  foo (&s2, 2);
> +  __builtin_clear_padding (&s2);
> +  if (s2.b.c.a != (char) -1 || s2.b.c.b != -1 || s2.b.c.c.b != -1)
> +    __builtin_abort ();
> +  __builtin_clear_padding (&s2.b.c);
> +  __builtin_memset (&s2.b.c + 1, 0, sizeof (union U) - sizeof (s2.b.c));
> +  if (__builtin_memcmp (&s1, &s2, sizeof (s1)))
> +    __builtin_abort ();
> +  return 0;
> +}
> --- gcc/testsuite/c-c++-common/torture/builtin-clear-padding-4.c.jj   
> 2020-11-20 10:51:44.720684308 +0100
> +++ gcc/testsuite/c-c++-common/torture/builtin-clear-padding-4.c      
> 2020-11-20 10:51:44.720684308 +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-20 10:51:44.720684308 +0100
> +++ gcc/testsuite/c-c++-common/torture/builtin-clear-padding-5.c      
> 2020-11-20 10:51:44.720684308 +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-1.c.jj 2020-11-20 
> 10:51:44.720684308 +0100
> +++ gcc/testsuite/gcc.dg/builtin-clear-padding-1.c    2020-11-20 
> 10:51:44.720684308 +0100
> @@ -0,0 +1,10 @@
> +/* PR libstdc++/88101 */
> +/* { dg-do compile } */
> +/* { dg-options "" } */
> +
> +void
> +foo (int n)
> +{
> +  struct S { char a; int b[n]; long long c; } s;
> +  __builtin_clear_padding (&s);              /* { dg-message "unimplemented: 
> __builtin_clear_padding not supported for variable length aggregates" } */
> +}
> --- gcc/testsuite/g++.dg/torture/builtin-clear-padding-1.C.jj 2020-11-20 
> 10:51:44.721684296 +0100
> +++ gcc/testsuite/g++.dg/torture/builtin-clear-padding-1.C    2020-11-20 
> 10:51:44.721684296 +0100
> @@ -0,0 +1,31 @@
> +/* PR libstdc++/88101 */
> +
> +struct S {} s1, s2;
> +struct T : public S { char a; short b; char c; } t1, t2;
> +struct U : public T { char d; long long e; char f; } u1, u2;
> +
> +__attribute__((noipa)) void
> +foo (T *t, U *u)
> +{
> +  int i;
> +  t->a = -1; t->b = -1; t->c = -1;
> +  u->a = -1; u->b = -1; u->c = -1; u->d = -1; u->e = -1; u->f = -1;
> +}
> +
> +int
> +main ()
> +{
> +  __builtin_memset (&s2, -1, sizeof (s2));
> +  __builtin_memset (&t2, -1, sizeof (t2));
> +  __builtin_memset (&u2, -1, sizeof (u2));
> +  foo (&t1, &u1);
> +  foo (&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/g++.dg/torture/builtin-clear-padding-2.C.jj 2020-11-20 
> 10:51:44.721684296 +0100
> +++ gcc/testsuite/g++.dg/torture/builtin-clear-padding-2.C    2020-11-20 
> 10:51:44.721684296 +0100
> @@ -0,0 +1,34 @@
> +/* PR libstdc++/88101 */
> +
> +#include <new>
> +
> +struct S { char a; short b; char c; long long d; char e; decltype (nullptr) 
> f; char g; };
> +alignas (S) unsigned char buf1[sizeof (S)];
> +alignas (S) unsigned char buf2[sizeof (S)];
> +
> +template <int N>
> +void
> +foo ()
> +{
> +  __builtin_clear_padding ((S *) buf2);
> +}
> +
> +void
> +bar (S *s)
> +{
> +  s->a = -1; s->b = -1; s->c = -1; s->d = -1; s->e = -1; s->g = -1;
> +}
> +
> +int
> +main ()
> +{
> +  S *s1 = new (buf1) S;
> +  S *s2 = new (buf2) S;
> +  __builtin_memset (s1, 0, sizeof (S));
> +  __builtin_memset (s2, ~0, sizeof (S));
> +  bar (s1);
> +  bar (s2);
> +  foo <0> ();
> +  if (__builtin_memcmp (s1, s2, sizeof (S)) != 0)
> +    __builtin_abort ();
> +}
> 
> 
>       Jakub
> 
> 
> 

-- 
Richard Biener <rguent...@suse.de>
SUSE Software Solutions Germany GmbH, Maxfeldstrasse 5, 90409 Nuernberg,
Germany; GF: Felix Imend

Reply via email to