gcc(最新版本:4.8、4.9)是否有类似于__assume()
icc 支持的内置的“假设”子句?例如,__assume( n % 8 == 0 );
5352 次
2 回答
23
从 gcc 4.8.2 开始,gcc 中没有 __assume() 等价物。我不知道为什么——它会非常有用。马夫索建议:
#define __assume(cond) do { if (!(cond)) __builtin_unreachable(); } while (0)
这是一个古老的技巧,至少早在 2010 年就已经知道,而且可能更久。编译器通常会优化 'cond' 的评估,因为任何 cond 为 false 的评估无论如何都将是未定义的。但是,如果它包含对不透明(非内联)函数的调用,它似乎并没有优化掉“cond”。编译器必须假设不透明调用可能有副作用(例如,更改全局)并且不能优化调用,尽管它可以优化结果上的任何计算和分支。因此,宏观方法充其量只是部分解决方案。
于 2014-10-04T17:43:26.817 回答
3
在您的示例中,您想通知编译器N
是 8 的倍数。您只需插入该行即可
N = N & 0xFFFFFFF8;
在您的代码中(如果N
是 32 位整数)。这不会改变N
,因为N
它是 8 的倍数,但由于 GCC 4.9,编译器似乎N
在这一行之后理解它是 8 的倍数。
下一个示例显示了这一点,其中添加了两个浮点向量:
int add_a(float * restrict a, float * restrict b, int N)
{
a = (float*)__builtin_assume_aligned(a, 32);
b = (float*)__builtin_assume_aligned(b, 32);
N = N & 0xFFFFFFF8;
for (int i = 0; i < N; i++){
a[i] = a[i] + b[i];
}
return 0;
}
int add_b(float * restrict a, float * restrict b, int N)
{
a = (float*)__builtin_assume_aligned(a, 32);
b = (float*)__builtin_assume_aligned(b, 32);
for (int i = 0; i < N; i++){
a[i] = a[i] + b[i];
}
return 0;
}
使用gcc -m64 -std=c99 -O3
gcc 4.9 版,add_a
编译为矢量化代码
add_a:
and edx, -8
jle .L6
sub edx, 4
xor ecx, ecx
shr edx, 2
lea eax, [rdx+1]
xor edx, edx
.L3:
movaps xmm0, XMMWORD PTR [rdi+rdx]
add ecx, 1
addps xmm0, XMMWORD PTR [rsi+rdx]
movaps XMMWORD PTR [rdi+rdx], xmm0
add rdx, 16
cmp ecx, eax
jb .L3
.L6:
xor eax, eax
ret
使用 function add_b
,需要超过 20 条额外指令来处理
N
不是 8 的倍数的情况:
add_b:
test edx, edx
jle .L17
lea ecx, [rdx-4]
lea r8d, [rdx-1]
shr ecx, 2
add ecx, 1
cmp r8d, 2
lea eax, [0+rcx*4]
jbe .L16
xor r8d, r8d
xor r9d, r9d
.L11:
movaps xmm0, XMMWORD PTR [rdi+r8]
add r9d, 1
addps xmm0, XMMWORD PTR [rsi+r8]
movaps XMMWORD PTR [rdi+r8], xmm0
add r8, 16
cmp ecx, r9d
ja .L11
cmp eax, edx
je .L17
.L10:
movsx r8, eax
lea rcx, [rdi+r8*4]
movss xmm0, DWORD PTR [rcx]
addss xmm0, DWORD PTR [rsi+r8*4]
movss DWORD PTR [rcx], xmm0
lea ecx, [rax+1]
cmp edx, ecx
jle .L17
movsx rcx, ecx
add eax, 2
lea r8, [rdi+rcx*4]
cmp edx, eax
movss xmm0, DWORD PTR [r8]
addss xmm0, DWORD PTR [rsi+rcx*4]
movss DWORD PTR [r8], xmm0
jle .L17
cdqe
lea rdx, [rdi+rax*4]
movss xmm0, DWORD PTR [rdx]
addss xmm0, DWORD PTR [rsi+rax*4]
movss DWORD PTR [rdx], xmm0
.L17:
xor eax, eax
ret
.L16:
xor eax, eax
jmp .L10
请参阅Godbolt 链接。
于 2018-03-20T10:50:24.010 回答