<html>
<head>
<base href="https://llvm.org/bugs/" />
</head>
<body><table border="1" cellspacing="0" cellpadding="8">
<tr>
<th>Bug ID</th>
<td><a class="bz_bug_link
bz_status_NEW "
title="NEW --- - LLVM generates poor code for MSVC std::string::~string due to memalign-like code in std::allocator<T>::deallocate"
href="https://llvm.org/bugs/show_bug.cgi?id=31774">31774</a>
</td>
</tr>
<tr>
<th>Summary</th>
<td>LLVM generates poor code for MSVC std::string::~string due to memalign-like code in std::allocator<T>::deallocate
</td>
</tr>
<tr>
<th>Product</th>
<td>libraries
</td>
</tr>
<tr>
<th>Version</th>
<td>trunk
</td>
</tr>
<tr>
<th>Hardware</th>
<td>PC
</td>
</tr>
<tr>
<th>OS</th>
<td>Windows NT
</td>
</tr>
<tr>
<th>Status</th>
<td>NEW
</td>
</tr>
<tr>
<th>Severity</th>
<td>normal
</td>
</tr>
<tr>
<th>Priority</th>
<td>P
</td>
</tr>
<tr>
<th>Component</th>
<td>Transformation Utilities
</td>
</tr>
<tr>
<th>Assignee</th>
<td>unassignedbugs@nondot.org
</td>
</tr>
<tr>
<th>Reporter</th>
<td>rnk@google.com
</td>
</tr>
<tr>
<th>CC</th>
<td>llvm-bugs@lists.llvm.org
</td>
</tr>
<tr>
<th>Classification</th>
<td>Unclassified
</td>
</tr></table>
<p>
<div>
<pre>There are many temporary std::strings in Chrome, and they are destroyed
frequently. LLVM inlines std::string and the things it calls, like
std::allocator<char>::deallocate. That calls std::_Deallocate in <xmemory0>,
which has this memalign-like code in it:
<a href="https://github.com/icestudent/vc-19-changes/blob/master/xmemory0#L97">https://github.com/icestudent/vc-19-changes/blob/master/xmemory0#L97</a>
This is what it looks like after pre-processing and reformatting:
inline void _Deallocate(void* _Ptr, size_t _Count, size_t _Sz) {
const size_t _User_size = _Count * _Sz;
if (4096 <= _User_size) {
const uintptr_t _Ptr_user = reinterpret_cast<uintptr_t>(_Ptr);
{
if (!((_Ptr_user & (32 - 1)) == 0)) {
::_invalid_parameter_noinfo_noreturn();
}
};
const uintptr_t _Ptr_ptr = _Ptr_user - sizeof(void*);
const uintptr_t _Ptr_container = *reinterpret_cast<uintptr_t*>(_Ptr_ptr);
{
if (!(_Ptr_container < _Ptr_user)) {
::_invalid_parameter_noinfo_noreturn();
}
if (!(sizeof(void*) <= _Ptr_user - _Ptr_container)) {
::_invalid_parameter_noinfo_noreturn();
}
if (!(_Ptr_user - _Ptr_container <= (sizeof(void*) + 32 - 1))) {
::_invalid_parameter_noinfo_noreturn();
}
};
_Ptr = reinterpret_cast<void*>(_Ptr_container);
}
::operator delete(_Ptr);
}
This causes two problems:
1. excessive code size because most strings are < 4096 bytes
2. blocks new / delete pair removal by obscuring the _Ptr argument to delete
The code size issue would be addressed by commoning the calls to
::_invalid_parameter_noinfo_noreturn(), which surprisingly we don't do.
One way to look at it is that we should canonicalize f and g to the same code:
void __attribute__((noreturn)) abort();
void f(unsigned x, unsigned y) {
if (x >= y)
abort();
int i = y - x;
if (i < 7)
abort();
if (i > 40)
abort();
}
void g(unsigned x, unsigned y) {
if (!(x < y) || (y - x) < 7 || (y - x) > 40)
abort();
}
Fixing 1 seems like a nice general improvement. I know in the past tail merging
was considered to be non-canonical, but tail merging the abort calls here
unlocks a lot of instcombine goodness, so it might be worth revisiting that.
To fix 2, we should probably recognize std::_Deallocate and std::_Allocate
pairs as allocation functions like new and delete, and avoid inlining them in
the first place.</pre>
</div>
</p>
<hr>
<span>You are receiving this mail because:</span>
<ul>
<li>You are on the CC list for the bug.</li>
</ul>
</body>
</html>