看过前面的问题1、2后,我想知道是否可以强制编译器对以下打印素数的代码执行常量折叠。
#include <iostream>
using namespace std;
inline bool is_prime(int n)
{
if(n<2)
return false;
for(int i=2;i*i<=n;i++)
if(n%i==0)
return false;
return true;
}
int main()
{
for(int i=0;i<20;i++)
if(is_prime(i))
cout<<i<<endl;
return 0;
}
我通过以下方式构建它:
g++ -O3 -S main.cpp -o main.asm
结果有几个:
2,3,5,7,11,13,17,19
我想强制编译器查看类似于
for(int x:{2,3,5,7,11,13,17,19})
cout<<x<<endl;
或者
cout<< 2 <<endl;
cout<< 3 <<endl;
cout<< 5 <<endl;
cout<< 7 <<endl;
cout<< 11 <<endl;
cout<< 13 <<endl;
cout<< 17 <<endl;
cout<< 19 <<endl;
但是阅读程序集表明没有发生任何事情。
我什至用过__builtin_expect
,但没有用。
有没有办法强制编译器优化器读取for循环并利用输出数据已知的优势?
我想在不使用模板元编程的情况下做到这一点。
PS。 我的真正目的只是测试编译器,而不是计算素数的有效方法。我只是想向我的朋友炫耀 C++ 编译器有多么强大。
如果分离is_prime
是关注的问题,我将所有内容都放在 main 中并且没有观察到差异:
#include <iostream>
using namespace std;
int main()
{
for(int n=2;n<20;n++)
{
bool is_prime=true;
for(int i=2;i*i<=n;i++)
if(n%i==0)
{
is_prime=false;
break;
}
if(is_prime)
cout<<n<<endl;
}
return 0;
}
甚至还有一个示例仍然不能为编译器提供任何借口:
#include <iostream>
#include <vector>
using namespace std;
int prime_after6000()
{
int n=6000;
do
{
bool is_prime=true;
for(int i=2;i*i<=n;i++)
if(n%i==0)
{
is_prime=false;
break;
}
if(is_prime)
return n;
n++;
}while(true);
}
int main()
{
cout<<prime_after6000()<<endl;
return 0;
}
部件:
...
main:
.LFB1907:
.cfi_startproc
subq $8, %rsp
.cfi_def_cfa_offset 16
movl $6000, %esi ;;;;;;;;;;;;;;;;;;;; bad
.L18:
testb $1, %sil
je .L15
movl $2, %ecx
jmp .L16
.p2align 4,,10
.p2align 3
.L17:
movl %esi, %eax
cltd
idivl %ecx
testl %edx, %edx
je .L15
.L16:
addl $1, %ecx
movl %ecx, %eax
imull %ecx, %eax
cmpl %esi, %eax
jle .L17
movl $_ZSt4cout, %edi
call _ZNSolsEi
movq %rax, %rdi
call _ZSt4endlIcSt11char_traitsIcEERSt13basic_ostreamIT_T0_ES6_
xorl %eax, %eax
addq $8, %rsp
.cfi_remember_state
.cfi_def_cfa_offset 8
ret
.p2align 4,,10
.p2align 3
.L15:
.cfi_restore_state
addl $1, %esi
jmp .L18
.cfi_endproc
.LFE1907:
.size main, .-main
.p2align 4,,15
.type _GLOBAL__sub_I__Z15prime_after6000v, @function
_GLOBAL__sub_I__Z15prime_after6000v:
...