3 ms·
Please note the intended use case was this: #define gc(x) ({ auto y=x; defer(free, y); y; }) int *buf = gc(malloc(sizeof(int))); if (coldpath) {
by jart 6y ago
Please note the intended use case was this:
#define gc(x) ({ auto y=x; defer(free, y); y; })
int *buf = gc(malloc(sizeof(int)));
if (coldpath) {
...
It's a bit of stretch to leak memory doing this:
int *buf = malloc(sizeof(int));
if (coldpath) {
defer(fake_free, buf);
...
Your point is otherwise valid. It appears a nonstandard nondefault LLVM extension can break the macro under circumstances that are difficult to imagine happening in practice. Here's why LLVM is wrong. It surgically removes a chunk of code from the middle of a function, turn it an external function, and then emits a synthetic call. It should jump to the cold block and jump back. The amount of code I'm seeing it generate just to handle the abi boundary it needlessly created is almost as large as the chunk that's being outlined.
Godbolt's website doesn't show this, but if you pass -S to clang-10 you'll notice other suboptimalities exist in the way this LLVM extension was implemented. For example, it doesn't emit .section directives to relocate the cold code, which is half the point of hot cold pgo style optimizations, since I recall Google building the thing to not have their web-scale static binaries paging hundreds of megs of cold code off disk.
LLVM is doing great work, but still has so much catching up to do compared to GCC on the code generation. GCC 9+ does cold optimizations by default, but only to relocate cold noreturn error handling paths into .text.unlikely. That's not an issue. I can't say for certain what it does if you generate and pass and optimization profile.