diff options
author | Richard Biener <rguenther@suse.de> | 2016-05-11 10:24:11 +0000 |
---|---|---|
committer | Richard Biener <rguenth@gcc.gnu.org> | 2016-05-11 10:24:11 +0000 |
commit | ebc1b29edb3428dd18e76cba8626625bfb184f1d (patch) | |
tree | c56af27e777a33142ec5005ae7600ac16297fad4 /gcc/testsuite | |
parent | 98ccd1d7ab1d9a0c99cce0d1c05ddcda3659dd26 (diff) | |
download | gcc-ebc1b29edb3428dd18e76cba8626625bfb184f1d.zip gcc-ebc1b29edb3428dd18e76cba8626625bfb184f1d.tar.gz gcc-ebc1b29edb3428dd18e76cba8626625bfb184f1d.tar.bz2 |
re PR middle-end/71002 (-fstrict-aliasing breaks Boost's short string optimization implementation)
2016-05-11 Richard Biener <rguenther@suse.de>
PR middle-end/71002
* alias.c (reference_alias_ptr_type): Preserve alias-set zero
if the langhook insists on it.
* fold-const.c (make_bit_field_ref): Add arg for the original
reference and preserve its alias-set.
(decode_field_reference): Take exp by reference and adjust it
to the original memory reference.
(optimize_bit_field_compare): Adjust callers.
(fold_truth_andor_1): Likewise.
* gimplify.c (gimplify_expr): Adjust in-SSA form test.
* g++.dg/torture/pr71002.C: New testcase.
From-SVN: r236117
Diffstat (limited to 'gcc/testsuite')
-rw-r--r-- | gcc/testsuite/ChangeLog | 5 | ||||
-rw-r--r-- | gcc/testsuite/g++.dg/torture/pr71002.C | 160 |
2 files changed, 165 insertions, 0 deletions
diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index de582b8..12fd1d0 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,8 @@ +2016-05-11 Richard Biener <rguenther@suse.de> + + PR middle-end/71002 + * g++.dg/torture/pr71002.C: New testcase. + 2016-05-11 Ilya Enkovich <ilya.enkovich@intel.com> PR middle-end/70807 diff --git a/gcc/testsuite/g++.dg/torture/pr71002.C b/gcc/testsuite/g++.dg/torture/pr71002.C new file mode 100644 index 0000000..8a72680 --- /dev/null +++ b/gcc/testsuite/g++.dg/torture/pr71002.C @@ -0,0 +1,160 @@ +// { dg-do run } + +using size_t = __SIZE_TYPE__; + +inline void* operator new(size_t, void* p) noexcept +{ return p; } + +inline void operator delete(void*, void*) +{ } + +struct long_t +{ + size_t is_short : 1; + size_t length : (__SIZEOF_SIZE_T__ * __CHAR_BIT__ - 1); + size_t capacity; + char* pointer; +}; + +union long_raw_t { + unsigned char data[sizeof(long_t)]; + struct __attribute__((aligned(alignof(long_t)))) { } align; +}; + +struct short_header +{ + unsigned char is_short : 1; + unsigned char length : (__CHAR_BIT__ - 1); +}; + +struct short_t +{ + short_header h; + char data[23]; +}; + +union repr_t +{ + long_raw_t r; + short_t s; + + const short_t& short_repr() const + { return s; } + + const long_t& long_repr() const + { return *static_cast<const long_t*>(static_cast<const void*>(&r)); } + + short_t& short_repr() + { return s; } + + long_t& long_repr() + { return *static_cast<long_t*>(static_cast<void*>(&r)); } +}; + +class string +{ +public: + string() + { + short_t& s = m_repr.short_repr(); + s.h.is_short = 1; + s.h.length = 0; + s.data[0] = '\0'; + } + + string(const char* str) + { + size_t length = __builtin_strlen(str); + if (length + 1 > 23) { + long_t& l = m_repr.long_repr(); + l.is_short = 0; + l.length = length; + l.capacity = length + 1; + l.pointer = new char[l.capacity]; + __builtin_memcpy(l.pointer, str, length + 1); + } else { + short_t& s = m_repr.short_repr(); + s.h.is_short = 1; + s.h.length = length; + __builtin_memcpy(s.data, str, length + 1); + } + } + + string(string&& other) + : string{} + { + swap_data(other); + } + + ~string() + { + if (!is_short()) { + delete[] m_repr.long_repr().pointer; + } + } + + size_t length() const + { return is_short() ? short_length() : long_length(); } + +private: + bool is_short() const + { return m_repr.s.h.is_short != 0; } + + size_t short_length() const + { return m_repr.short_repr().h.length; } + + size_t long_length() const + { return m_repr.long_repr().length; } + + void swap_data(string& other) + { + if (is_short()) { + if (other.is_short()) { + repr_t tmp(m_repr); + m_repr = other.m_repr; + other.m_repr = tmp; + } else { + short_t short_backup(m_repr.short_repr()); + m_repr.short_repr().~short_t(); + ::new(&m_repr.long_repr()) long_t(other.m_repr.long_repr()); + other.m_repr.long_repr().~long_t(); + ::new(&other.m_repr.short_repr()) short_t(short_backup); + } + } else { + if (other.is_short()) { + short_t short_backup(other.m_repr.short_repr()); + other.m_repr.short_repr().~short_t(); + ::new(&other.m_repr.long_repr()) long_t(m_repr.long_repr()); + m_repr.long_repr().~long_t(); + ::new(&m_repr.short_repr()) short_t(short_backup); + } else { + long_t tmp(m_repr.long_repr()); + m_repr.long_repr() = other.m_repr.long_repr(); + other.m_repr.long_repr() = tmp; + } + } + } + + repr_t m_repr; +}; + +struct foo +{ + __attribute__((noinline)) + foo(string str) + : m_str{static_cast<string&&>(str)}, + m_len{m_str.length()} + { } + + string m_str; + size_t m_len; +}; + +int main() +{ + foo f{"the quick brown fox jumps over the lazy dog"}; + if (f.m_len == 0) { + __builtin_abort(); + } + return 0; +} |