diff options
author | Jakub Jelinek <jakub@redhat.com> | 2020-12-03 15:46:54 +0100 |
---|---|---|
committer | Jakub Jelinek <jakub@redhat.com> | 2020-12-03 15:46:54 +0100 |
commit | 896048cf43d5eb21ab7c16553bb9d13b0f890b81 (patch) | |
tree | 3d929f74e3ad0cd70a86d101744be4a961a57450 /gcc/gimple-fold.c | |
parent | 341035a54aa8954c66b0492f366b8c65fdb34299 (diff) | |
download | gcc-896048cf43d5eb21ab7c16553bb9d13b0f890b81.zip gcc-896048cf43d5eb21ab7c16553bb9d13b0f890b81.tar.gz gcc-896048cf43d5eb21ab7c16553bb9d13b0f890b81.tar.bz2 |
c++: Add __builtin_bit_cast to implement std::bit_cast [PR93121]
The following patch adds __builtin_bit_cast builtin, similarly to
clang or MSVC which implement std::bit_cast using such an builtin too.
It checks the various std::bit_cast requirements, when not constexpr
evaluated acts pretty much like VIEW_CONVERT_EXPR of the source argument
to the destination type and the hardest part is obviously the constexpr
evaluation.
I've left out PDP11 handling of those, couldn't figure out how exactly are
bitfields laid out there
2020-12-03 Jakub Jelinek <jakub@redhat.com>
PR libstdc++/93121
* fold-const.h (native_encode_initializer): Add mask argument
defaulted to nullptr.
(find_bitfield_repr_type): Declare.
(native_interpret_aggregate): Declare.
* fold-const.c (find_bitfield_repr_type): New function.
(native_encode_initializer): Add mask argument and support for
filling it. Handle also some bitfields without integral
DECL_BIT_FIELD_REPRESENTATIVE.
(native_interpret_aggregate): New function.
* gimple-fold.h (clear_type_padding_in_mask): Declare.
* gimple-fold.c (struct clear_padding_struct): Add clear_in_mask
member.
(clear_padding_flush): Handle buf->clear_in_mask.
(clear_padding_union): Copy clear_in_mask. Don't error if
buf->clear_in_mask is set.
(clear_padding_type): Don't error if buf->clear_in_mask is set.
(clear_type_padding_in_mask): New function.
(gimple_fold_builtin_clear_padding): Set buf.clear_in_mask to false.
* doc/extend.texi (__builtin_bit_cast): Document.
* c-common.h (enum rid): Add RID_BUILTIN_BIT_CAST.
* c-common.c (c_common_reswords): Add __builtin_bit_cast.
* cp-tree.h (cp_build_bit_cast): Declare.
* cp-tree.def (BIT_CAST_EXPR): New tree code.
* cp-objcp-common.c (names_builtin_p): Handle RID_BUILTIN_BIT_CAST.
(cp_common_init_ts): Handle BIT_CAST_EXPR.
* cxx-pretty-print.c (cxx_pretty_printer::postfix_expression):
Likewise.
* parser.c (cp_parser_postfix_expression): Handle
RID_BUILTIN_BIT_CAST.
* semantics.c (cp_build_bit_cast): New function.
* tree.c (cp_tree_equal): Handle BIT_CAST_EXPR.
(cp_walk_subtrees): Likewise.
* pt.c (tsubst_copy): Likewise.
* constexpr.c (check_bit_cast_type, cxx_eval_bit_cast): New functions.
(cxx_eval_constant_expression): Handle BIT_CAST_EXPR.
(potential_constant_expression_1): Likewise.
* cp-gimplify.c (cp_genericize_r): Likewise.
* g++.dg/cpp2a/bit-cast1.C: New test.
* g++.dg/cpp2a/bit-cast2.C: New test.
* g++.dg/cpp2a/bit-cast3.C: New test.
* g++.dg/cpp2a/bit-cast4.C: New test.
* g++.dg/cpp2a/bit-cast5.C: New test.
Diffstat (limited to 'gcc/gimple-fold.c')
-rw-r--r-- | gcc/gimple-fold.c | 74 |
1 files changed, 68 insertions, 6 deletions
diff --git a/gcc/gimple-fold.c b/gcc/gimple-fold.c index ab74494..3148c6b 100644 --- a/gcc/gimple-fold.c +++ b/gcc/gimple-fold.c @@ -3958,6 +3958,10 @@ 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; + /* 0 during __builtin_clear_padding folding, nonzero during + clear_type_padding_in_mask. In that case, instead of clearing the + non-padding bits in union_ptr array clear the padding bits in there. */ + bool clear_in_mask; tree base; tree alias_type; gimple_stmt_iterator *gsi; @@ -4000,6 +4004,39 @@ clear_padding_flush (clear_padding_struct *buf, bool full) size_t padding_bytes = buf->padding_bytes; if (buf->union_ptr) { + if (buf->clear_in_mask) + { + /* During clear_type_padding_in_mask, clear the padding + bits set in buf->buf in the buf->union_ptr mask. */ + for (size_t i = 0; i < end; i++) + { + if (buf->buf[i] == (unsigned char) ~0) + padding_bytes++; + else + { + memset (&buf->union_ptr[buf->off + i - padding_bytes], + 0, padding_bytes); + padding_bytes = 0; + buf->union_ptr[buf->off + i] &= ~buf->buf[i]; + } + } + if (full) + { + memset (&buf->union_ptr[buf->off + end - padding_bytes], + 0, padding_bytes); + 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; + } /* 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. */ @@ -4311,6 +4348,7 @@ clear_padding_union (clear_padding_struct *buf, tree type, HOST_WIDE_INT sz) clear_padding_flush (buf, false); union_buf = XALLOCA (clear_padding_struct); union_buf->loc = buf->loc; + union_buf->clear_in_mask = buf->clear_in_mask; union_buf->base = NULL_TREE; union_buf->alias_type = NULL_TREE; union_buf->gsi = NULL; @@ -4335,9 +4373,10 @@ clear_padding_union (clear_padding_struct *buf, tree type, HOST_WIDE_INT sz) continue; gcc_assert (TREE_CODE (TREE_TYPE (field)) == ARRAY_TYPE && !COMPLETE_TYPE_P (TREE_TYPE (field))); - error_at (buf->loc, "flexible array member %qD does not have " - "well defined padding bits for %qs", - field, "__builtin_clear_padding"); + if (!buf->clear_in_mask) + error_at (buf->loc, "flexible array member %qD does not have " + "well defined padding bits for %qs", + field, "__builtin_clear_padding"); continue; } HOST_WIDE_INT fldsz = tree_to_shwi (DECL_SIZE_UNIT (field)); @@ -4529,9 +4568,10 @@ clear_padding_type (clear_padding_struct *buf, tree type, HOST_WIDE_INT sz) continue; gcc_assert (TREE_CODE (ftype) == ARRAY_TYPE && !COMPLETE_TYPE_P (ftype)); - error_at (buf->loc, "flexible array member %qD does not have " - "well defined padding bits for %qs", - field, "__builtin_clear_padding"); + if (!buf->clear_in_mask) + error_at (buf->loc, "flexible array member %qD does not " + "have well defined padding bits for %qs", + field, "__builtin_clear_padding"); } else if (is_empty_type (TREE_TYPE (field))) continue; @@ -4645,6 +4685,27 @@ clear_padding_type (clear_padding_struct *buf, tree type, HOST_WIDE_INT sz) } } +/* Clear padding bits of TYPE in MASK. */ + +void +clear_type_padding_in_mask (tree type, unsigned char *mask) +{ + clear_padding_struct buf; + buf.loc = UNKNOWN_LOCATION; + buf.clear_in_mask = true; + buf.base = NULL_TREE; + buf.alias_type = NULL_TREE; + buf.gsi = NULL; + buf.align = 0; + buf.off = 0; + buf.padding_bytes = 0; + buf.sz = int_size_in_bytes (type); + buf.size = 0; + buf.union_ptr = mask; + clear_padding_type (&buf, type, buf.sz); + clear_padding_flush (&buf, true); +} + /* Fold __builtin_clear_padding builtin. */ static bool @@ -4664,6 +4725,7 @@ gimple_fold_builtin_clear_padding (gimple_stmt_iterator *gsi) gsi_prev (&gsiprev); buf.loc = loc; + buf.clear_in_mask = false; buf.base = ptr; buf.alias_type = NULL_TREE; buf.gsi = gsi; |