C++ 这是gcc优化器中的错误吗?
当我用gcc6-O3-std=c++14编译下面的代码时,我得到了一个很好的空C++ 这是gcc优化器中的错误吗?,c++,c++14,C++,C++14,当我用gcc6-O3-std=c++14编译下面的代码时,我得到了一个很好的空main: Dump of assembler code for function main(): 0x00000000004003e0 <+0>: xor %eax,%eax 0x00000000004003e2 <+2>: retq 函数main()的汇编程序代码转储: 0x00000000004003e0:xor%eax,%eax 0x00000000
main
:
Dump of assembler code for function main():
0x00000000004003e0 <+0>: xor %eax,%eax
0x00000000004003e2 <+2>: retq
函数main()的汇编程序代码转储:
0x00000000004003e0:xor%eax,%eax
0x00000000004003e2:retq
但取消注释主“中断”优化中的最后一行:
Dump of assembler code for function main():
0x00000000004005f0 <+0>: sub $0x78,%rsp
0x00000000004005f4 <+4>: lea 0x40(%rsp),%rdi
0x00000000004005f9 <+9>: movq $0x400838,0x10(%rsp)
0x0000000000400602 <+18>: movb $0x0,0x18(%rsp)
0x0000000000400607 <+23>: mov %fs:0x28,%rax
0x0000000000400610 <+32>: mov %rax,0x68(%rsp)
0x0000000000400615 <+37>: xor %eax,%eax
0x0000000000400617 <+39>: movl $0x0,(%rsp)
0x000000000040061e <+46>: movq $0x400838,0x30(%rsp)
0x0000000000400627 <+55>: movb $0x0,0x38(%rsp)
0x000000000040062c <+60>: movl $0x0,0x20(%rsp)
0x0000000000400634 <+68>: movq $0x400838,0x50(%rsp)
0x000000000040063d <+77>: movb $0x0,0x58(%rsp)
0x0000000000400642 <+82>: movl $0x0,0x40(%rsp)
0x000000000040064a <+90>: callq 0x400790 <ErasedObject::~ErasedObject()>
0x000000000040064f <+95>: lea 0x20(%rsp),%rdi
0x0000000000400654 <+100>: callq 0x400790 <ErasedObject::~ErasedObject()>
0x0000000000400659 <+105>: mov %rsp,%rdi
0x000000000040065c <+108>: callq 0x400790 <ErasedObject::~ErasedObject()>
0x0000000000400661 <+113>: mov 0x68(%rsp),%rdx
0x0000000000400666 <+118>: xor %fs:0x28,%rdx
0x000000000040066f <+127>: jne 0x400678 <main()+136>
0x0000000000400671 <+129>: xor %eax,%eax
0x0000000000400673 <+131>: add $0x78,%rsp
0x0000000000400677 <+135>: retq
0x0000000000400678 <+136>: callq 0x4005c0 <__stack_chk_fail@plt>
函数main()的汇编程序代码转储:
0x00000000004005f0:子$0x78,%rsp
0x00000000004005f4:lea 0x40(%rsp),%rdi
0x00000000004005f9:movq$0x400838,0x10(%rsp)
0x00000000000400602:movb$0x0,0x18(%rsp)
0x00000000000400607:mov%fs:0x28,%rax
0x000000000040610:mov%rax,0x68(%rsp)
0x00000000000400615:xor%eax,%eax
0x00000000000400617:movl$0x0,(%rsp)
0x0000000000040061E:movq$0x400838,0x30(%rsp)
0x00000000000400627:movb$0x0,0x38(%rsp)
0x000000000040062c:movl$0x0,0x20(%rsp)
0x00000000000400634:movq$0x400838,0x50(%rsp)
0x0000000000040063D:movb$0x0,0x58(%rsp)
0x00000000000400642:movl$0x0,0x40(%rsp)
0x000000000040064a:callq 0x400790
0x0000000000040064F:lea 0x20(%rsp),%rdi
0x00000000000400654:callq 0x400790
0x0000000000400659:mov%rsp,%rdi
0x00000000004065C:callq 0x400790
0x00000000000400661:mov 0x68(%rsp),%rdx
0x00000000000400666:xor%fs:0x28,%rdx
0x000000000040066f:jne 0x400678
0x00000000000400671:xor%eax,%eax
0x00000000000400673:添加$0x78,%rsp
0x0000000000400677:retq
0x00000000000400678:callq 0x4005c0
代码
#包括
#包括
名称空间
{
结构擦除类型表
{
使用析构函数_t=void(*)(void*obj);
析构函数;
};
模板
无效数据或(无效*obj)
{
返回静态_cast(obj)->~T();
}
模板
静态常量橡皮擦类型表橡皮擦类型表={
&dtor
};
}
结构擦除对象
{
std::aligned_storage::type storage;
常量擦除类型vtable&vtbl;
布尔标志=假;
模板
橡皮擦对象(T&obj)
:vtbl(已擦除类型vtable)
{
static_assert(sizeof(T)我使用-fdump ipa inline运行了g++
,以获取有关函数内联或不内联原因的更多信息
对于使用main()函数和创建的三个对象的testcase,我得到:
(...)
150 Deciding on inlining of small functions. Starting with size 35.
151 Enqueueing calls in void {anonymous}::dtor(void*) [with T = myType]/40.
152 Enqueueing calls in int main()/35.
153 not inlinable: int main()/35 -> ErasedObject::~ErasedObject()/33, call is unlikely and code size would grow
154 not inlinable: int main()/35 -> ErasedObject::~ErasedObject()/33, call is unlikely and code size would grow
155 not inlinable: int main()/35 -> ErasedObject::~ErasedObject()/33, call is unlikely and code size would grow
(...)
此错误代码在gcc/gcc/ipa inline.c中设置:
else if (!e->maybe_hot_p ()
&& (growth >= MAX_INLINE_INSNS_SINGLE
|| growth_likely_positive (callee, growth)))
{
e->inline_failed = CIF_UNLIKELY_CALL;
want_inline = false;
}
然后我发现,使g++内联这些函数的最小更改是添加一个声明:
int main() __attribute__((hot));
我无法在代码中找到为什么intmain()
不被认为是热门的,但这可能应该留给另一个问题
更有趣的是我上面粘贴的条件的第二部分,其目的是在代码增长时不内联,并且您生成了一个在完全内联后代码收缩的示例
我认为这值得一提,但我不确定你是否可以称之为bug——内联影响的估计是一种启发式方法,因此它在大多数情况下都能正常工作,而不是在所有情况下。在我看来像个bug。在GCC(Ubuntu 5.3.1-14ubuntu2)5.3.1 20160413GCC不内联main()<代码> >积极地尝试调用它>代码> MEOW。MaIEJCECORCA可能因为<代码>主< /代码>不应该是热的,并且指令缓存受到内联和展开的影响。我认为我知道一点C++……我看不出代码的一半:(我认为运行A来获得最小值是一个有趣的实验。l无法内联的示例。我猜main()
不被认为是热门的,因为显式调用或通过指针调用它是未定义的行为(C++11 3.6.1/3:“函数main不能在程序中使用”)。所以gcc“知道”这一点main()
只能被调用一次。@MichaelBurr关于未定义的行为,你是完全正确的,但由于我在GCC源代码中找不到使main()
变冷的原因,我仍然“不知道:)我在中没有看到特殊情况,可能是热/冷启发本身。
int main() __attribute__((hot));