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