Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/150.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ clang vs gcc-优化,包括新操作符_C++_Gcc_C++11_Clang_Compiler Optimization - Fatal编程技术网

C++ clang vs gcc-优化,包括新操作符

C++ clang vs gcc-优化,包括新操作符,c++,gcc,c++11,clang,compiler-optimization,C++,Gcc,C++11,Clang,Compiler Optimization,我有一个简单的例子进行测试,我注意到当涉及到操作符new时,gcc优化(-O3)似乎不如铿锵优化。我想知道可能存在什么问题,是否有可能迫使gcc以某种方式生成更优化的代码 template<typename T> T* create() { return new T(); } int main() { auto result = 0; for (auto i = 0; i < 1000000; ++i) { result += (create&

我有一个简单的例子进行测试,我注意到当涉及到操作符new时,gcc优化(-O3)似乎不如铿锵优化。我想知道可能存在什么问题,是否有可能迫使gcc以某种方式生成更优化的代码

template<typename T>
T* create() { return new T(); }

int main() {
    auto result = 0;
    for (auto i = 0; i < 1000000; ++i) {
        result += (create<int>() != nullptr);
    }

    return result;
}


#clang3.6++ -O3 -s --std=c++11 test.cpp
#size a.out
   text    data     bss     dec     hex filename
   1324     616       8    1948     79c a.out
#time ./a.out 
real 0m0.002s
user 0m0.001s
sys  0m0.000s

#gcc4.9 -O3 -s --std=c++11 test.cpp
#size a.out
   text    data     bss     dec     hex filename
   1484     624       8    2116     844 a.out
#time ./a.out
real 0m0.045s
user 0m0.035s
sys  0m0.009s
模板
T*create(){返回新的T();}
int main(){
自动结果=0;
用于(自动i=0;i<1000000;++i){
结果+=(创建()!=nullptr);
}
返回结果;
}
#clang3.6++-O3-s--std=c++11 test.cpp
#尺码a
文本数据bss dec十六进制文件名
1324 616 8 1948 79c a.out
#时间到了
实0.002s
用户0m0.001s
系统0m0.000s
#gcc4.9-O3-s--std=c++11 test.cpp
#尺码a
文本数据bss dec十六进制文件名
148462482116844 a.out
#时间到了
实际0.045s
用户0.035s
系统0m0.009s
上面的例子只是我一开始测试的代码的一个简单版本, 但它仍然说明了gcc/clang之间的区别。 我也检查了汇编代码,在大小上没有很大的差别,但在性能上肯定有差别。另一方面,可能clang正在做一些不允许的事情?

如果我们将此代码插入,我们可以看到
clang
将代码优化为:

main:                                   # @main
movl    $1000000, %eax          # imm = 0xF4240
ret
gcc
不执行此优化。那么问题是这是一个有效的优化吗?这是否遵循《程序执行》(强调我的)一节中所述的《程序执行》中的《如同规则》

本国际标准中的语义描述定义了 参数化非确定性抽象机器。这个国际 标准对一致性的结构没有要求 实现。特别是,它们不需要复制或模仿 抽象机器的结构。相反,一致性实现 需要模拟(仅)抽象的可观察行为 机器如下所述。5

其中注释
5
表示:

这一规定有时被称为“仿佛”规则,因为 实施可自由忽略本协议的任何要求 只要符合国际标准,结果就如同要求 根据可观察到的情况,已被遵守 程序的行为。例如,实际的实现需要 如果表达式可以推断其值为 未使用,且无影响患者可观察行为的副作用 节目制作完成了


因为
new
可能引发异常,该异常将具有可观察的行为,因为它将改变程序的返回值

R.MartinhoFernandes认为,何时抛出异常是实现细节,因此
clang
可以决定此场景不会导致异常,因此省略
new
调用不会违反
规则。对我来说,这似乎是一个合理的论点

但正如T.C.所指出的:

替换全局运算符new可以在不同的转换单元中定义

Casey提供了一个示例,显示即使当
clang
看到有替代品时,它仍然会执行此优化,即使有丢失的副作用。因此,这似乎是过于激进的优化


注意,.

看来,clang是在根据C++14中包含的更改规则优化内存分配。N3664允许通过合并分配或完全取消分配来减少对分配/解除分配函数的调用次数。

其基本原理是,没有关于机器可能拥有多少内存的规则,该语言也没有提供任何方法来检查分配或释放的内存量(请注意POSIX确实定义了mallinfo)。在这里,我们在一个具有无限内存的抽象机器上模拟您的程序,在这个机器上分配连续成功。或者至少,无限内存用于此循环中的分配,但不用于整个程序。无论如何,我知道有两个很好的反对意见

首先,考虑它是否是Maloc而不是算子new。C99规范状态:

malloc函数为大小由size指定且值不确定的对象分配空间。malloc函数返回空指针或指向所分配空间的指针

编译malloc()“总是成功”似乎符合该规范。但如果您调用它的次数超过了我们实际可以为其创建指针的次数,并且只有在失败时才退出循环,该怎么办?一种可能的解决方法是注意,在抽象机器定义中没有规则规定64位指针只能容纳264个可能值,只是没有提供任何方法构建超出此范围的值。看来实现可能会随意创建这样的东西。我个人觉得这个答案不令人满意

考虑到我们还优化了一些东西,比如
“T*t1=newt;T*t2=(T*)rand();”
通过假设
t1
可能不是别名
t2
。不管rand是否选择了正确的地址,或者你是否遍历了整个地址空间,一旦我们证明t1的地址没有反馈到t2,我们应该能够得出结论,它们引用不同的对象。虽然我希望这是标准工作的方式ked,这就是编译器的工作原理,我不知道有哪种标准支持这一立场。这可能会成为未来论文的主题

其次,运算符new不是malloc,它是一个可替换的函数。正如Casey在回复中所建议的,我们打算遵循中的规则(尽管我认为clang对待新表达式的方式与显式调用运算符new的方式没有什么不同)