[llvm-bugs] [Bug 31774] New: LLVM generates poor code for MSVC std::string::~string due to memalign-like code in std::allocator<T>::deallocate
via llvm-bugs
llvm-bugs at lists.llvm.org
Thu Jan 26 10:49:01 PST 2017
https://llvm.org/bugs/show_bug.cgi?id=31774
Bug ID: 31774
Summary: LLVM generates poor code for MSVC std::string::~string
due to memalign-like code in
std::allocator<T>::deallocate
Product: libraries
Version: trunk
Hardware: PC
OS: Windows NT
Status: NEW
Severity: normal
Priority: P
Component: Transformation Utilities
Assignee: unassignedbugs at nondot.org
Reporter: rnk at google.com
CC: llvm-bugs at lists.llvm.org
Classification: Unclassified
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:
https://github.com/icestudent/vc-19-changes/blob/master/xmemory0#L97
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.
--
You are receiving this mail because:
You are on the CC list for the bug.
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/llvm-bugs/attachments/20170126/6abd3017/attachment-0001.html>
More information about the llvm-bugs
mailing list