__builtin_expect
该指令是gcc引入的,就是允许代码编写者把最有可能执行的分支告诉编译器,标准写法是__bultin_expect(exp, n),意思是exp==n的概率很大,这样编译器可以对代码进行优化,减少指令跳转带来的性能下降,对应通常有两个宏定义:
#define likely(x) __builtin_expect(!!(x), 1) // x为真的可能性更大
#define unlikely(x) __builtin_expect(!!(x), 0) // x为假的可能性更大
需要注意一点,!!(x)似乎是没有意义的,但其实是有意义的,首先__buildin_expect(x, a)意味着很可能x==a,然而x==2时,x也是true,但x!=1,所以!!(x)可以保证x==true时,!!(x)==1。
__builtin_unreachable
__builtin_unreachable函数是用来通知编译器这一行在CPU运行时永远不会到达,这样可以提前防止编译中的很多麻烦。我们来看一个例子:
# define ATHCONTAINERS_ASSUME(x) do { if (!(x)) __builtin_unreachable(); } while(0)
inline
void*
AuxVectorData::Cache::getDataArray (SG::auxid_t auxid,
AuxVectorData& parent)
{
// This function is important for performance.
// Be careful when changing it.
void* ptr = cachePtr (auxid);
if (ATHCONTAINERS_UNLIKELY (ptr == 0)) {
// We don't have the variable cached.
// Call the out-of-line routine to get it cached.
ptr = parent.getDataOol (auxid, false);
// These inform the compiler of what the previous call did.
// They tell the optimizer that it can now assume that this cache
// entry is valid.
ATHCONTAINERS_ASSUME (ptr != 0);
ATHCONTAINERS_ASSUME (cachePtr (auxid) != 0);
ATHCONTAINERS_ASSUME (cachePtr (auxid) == ptr);
}
return ptr;
}
宏定义ATHCONTAINERS_ASSUME告诉编译器参数x不能为false。这使编译器不必生成任何代码来适应x为假的可能。例如,当编译器看到ATHCONTAINERS_ASSUME (ptr != 0)时,它可以假设ptr不为空,并且任何与该假设相矛盾的代码都可以被优化掉,因为它将是未定义的行为。由于getDataArray()是内联的,编译器可以在每个调用点知道返回的指针永远不会为空。
__builtin_prefetch
用于预取数据到CPU的缓存中,以便提高程序的执行效率:
__builtin_prefetch (const void *addr, int rw, int locality)
addr
是一个指向要预取数据的地址的指针,rw
是一个表示读写属性的整数,locality
是一个表示预取数据的局部性的整数。__builtin_prefetch
的返回值是void
类型,它只是告诉CPU预取数据到缓存中,而不会等待数据被加载到缓存中。