Open EdSchouten opened 9 years ago
This behavior is still the same in post 17 trunk(975deb366470e4943a5b73d8f3031ed54dec6e8b) https://godbolt.org/z/zYEo4Y4WK
code
class Bunny {
public:
Bunny() {}
};
Bunny& GetBunny() {
static Bunny bunny;
return bunny;
}
class Cat {
public:
Cat() = default;
};
Cat& GetCat() {
static Cat cat;
return cat;
}
class Puppy {
};
Puppy& GetPuppy() {
static Puppy puppy;
return puppy;
}
assembly, notice the different between bunny, can and puppy
GetBunny(): # @GetBunny()
movzx eax, byte ptr [rip + guard variable for GetBunny()::bunny]
test al, al
je .LBB0_1
lea rax, [rip + GetBunny()::bunny]
ret
.LBB0_1:
push rax
lea rdi, [rip + guard variable for GetBunny()::bunny]
call __cxa_guard_acquire@PLT
test eax, eax
je .LBB0_3
lea rdi, [rip + guard variable for GetBunny()::bunny]
call __cxa_guard_release@PLT
.LBB0_3:
add rsp, 8
lea rax, [rip + GetBunny()::bunny]
ret
GetCat(): # @GetCat()
lea rax, [rip + GetCat()::cat]
ret
GetPuppy(): # @GetPuppy()
lea rax, [rip + GetPuppy()::puppy]
ret
I should be noted that
class Bunny {
public:
Bunny() {}
};
is not a trivially constructible class, despite author claiming that Bunny() {}
is a trivial constructor, because it's not. I wonder to which extent our hands are tied by language rules.
@llvm/issue-subscribers-c-1
Author: Ed Schouten (EdSchouten)
Extended Description
Consider the following piece of code:
When compiled, Clang is smart enough to just emit a static copy of a
Bunny
object and implementGetBunny()
as follows:Now consider the case where we add the following trivial constructor to Bunny:
Suddenly the
GetBunny()
function starts to look like this:This is of course not needed, as the constructor is trivial. There is no need to explicitly invoke it. In fact, if I make the constructor
constexpr
, Clang is smart enough to reduceGetBunny()
to the simple implementation shown above. Clang should be able to use some smartness even ifconstexpr
is not used.Can reproduce this with the following versions of Clang: