__builtin + __attribute__
一些gcc/clang内置的__builtin函数, 大部分clang也有
1. __builtin
1. __builtin_expect
允许将最有可能执行的分支告诉编译器
1
2
#define likely(x) __builtin_expect(!!(x), 1)
#define unlikely(x) __builtin_expect(!!(x), 0)
if else 句型编译后, 一个分支的汇编代码紧随前面的代码,而另一个分支的汇编代码需要使用JMP指令才能访问到.
很明显通过JMP访问需要更多的时间, 在复杂的程序中,有很多的if else句型,又或者是一个有if else句型的库函数,每秒钟被调用几万次,
通常程序员在分支预测方面做得很糟糕, 编译器又不能精准的预测每一个分支,这时JMP产生的时间浪费就会很大,
函数__builtin_expect()就是用来解决这个问题的.
具体的原理可以看下likely() and unlikely()
2. int __builtin_popcount (unsigned int x)
返回x中1位(bit)的数量, 但是在c++里,这玩意其实有个std::bitset<32>之类的,你可以用这个
而且我实测了一下,bench,我不知道为啥,bitset比builtin快, 他们生成的汇编是一样的
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#include <bitset>
static void GccBuiltInPopCount(benchmark::State& state) {
for (auto _ : state) {
__builtin_popcount(5);
}
}
BENCHMARK(GccBuiltInPopCount);
static void StdBitsetCount(benchmark::State& state) {
for (auto _ : state) {
std::bitset<8>(5).count();
}
}
BENCHMARK(StdBitsetCount);
3. void __builtin_prefetch (const void *addr, …)
此功能用于通过在访问数据之前将数据移入缓存来最大限度地减少缓存未命中延迟。您可以将对__builtin_prefetch
的调用插入到您知道内存中可能很快会访问的数据地址的代码中。如果目标支持它们,则会生成数据预取指令。如果在访问之前足够早地完成预取,则数据在访问时将位于缓存中。
addr 的值是要预取的内存地址。有两个可选参数: rw 和 locality 。 rw 的值是编译时常量 1 或 0;1 表示预取正在准备写入内存地址,默认值 0 表示预取正在准备读取。值 locality 必须是介于 0 和 3 之间的编译时常量整数。值为零意味着数据没有时间局部性,因此访问后不需要将其保留在缓存中。值为 3 意味着数据具有高度的时间局部性,并且应该保留在所有可能的级别的缓存中。值 1 和 2 分别表示低或中等程度的时间局部性。默认值为三个。
4. ctz/clz/parity
count zero, count leading zero, parity, 这几个就知道就行了
2. attribute
2.1 __attribute__((always_inline))
在C和C++编程中,attribute__关键字可以用来为函数、变量和类型指定特定的属性。要将函数设置为内联(inline),可以使用__attribute((always_inline))或标准的inline关键字。使用__attribute__((always_inline))可以强制编译器始终将函数内联,而不仅仅是建议。