我正在使用一种int类型来存储一个值.根据程序的语义,值总是在很小的范围内变化(0 - 36),并且仅使用int(不是a char)因为CPU效率.
似乎可以在如此小的整数范围内执行许多特殊的算术优化.可以将对这些整数的许多函数调用优化为一小组"神奇"操作,并且甚至可以将某些函数优化为表查找.
那么,是否有可能告诉编译器这int总是在那么小的范围内,并且编译器是否可以进行这些优化?
GCC支持__builtin_clz(int x)内置,它计算参数中前导零(连续最重要的零)的数量.
除了其他东西0之外,这对于有效地实现lg(unsigned int x)函数非常有用,该函数采用基数2的对数x,舍入为1:
/** return the base-2 log of x, where x > 0 */
unsigned lg(unsigned x) {
return 31U - (unsigned)__builtin_clz(x);
}
Run Code Online (Sandbox Code Playgroud)
这部作品在简单的方式-尤其是考虑的情况下x == 1,并clz(x) == 31-再x == 2^0这样lg(x) == 0和31 - 31 == 0我们得到正确的结果.更高的x工作价值.
假设内置程序有效实现,这比备用纯C解决方案更好.
现在,它发生了,计数前导零操作基本上是bsrx86中指令的双重.返回参数中最重要的1位2的索引.因此,如果有10个前导零,则第一个1位位于参数的第21位.一般来说,我们有31 - clz(x) == bsr(x),并在这样bsr …
除了其他方面,x86-64 SysV ABI指定了如何在寄存器中传递函数参数(第一个参数in rdi,then rsi等等),以及如何传回整数返回值(in rax和then rdx表示非常大的值).
然而,我找不到的是当传递小于64位的类型时,参数或返回值寄存器的高位应该是什么.
例如,对于以下功能:
void foo(unsigned x, unsigned y);
Run Code Online (Sandbox Code Playgroud)
... x将被传入rdi和y在rsi,但他们只是32位.不要的高32位rdi和rsi必须为零?直观地说,我会假设是,但是所有gcc,clang和icc 生成的代码mov在开始时都有特定的指令将高位清零,所以看起来编译器假定不然.
类似地,编译器似乎假设rax如果返回值小于64 位,则返回值的高位可能具有垃圾位.例如,以下代码中的循环:
unsigned gives32();
unsigned short gives16();
long sum32_64() {
long total = 0;
for (int i=1000; i--; ) {
total += gives32();
}
return total;
}
long sum16_64() {
long total = 0;
for (int i=1000; i--; ) {
total += …Run Code Online (Sandbox Code Playgroud) 从SIMD寄存器加载和存储生成目的寄存器的最佳方法是什么?到目前为止,我一直在使用堆栈作为临时.例如,
mov [rsp + 0x00], r8
mov [rsp + 0x08], r9
mov [rsp + 0x10], r10
mov [rsp + 0x18], r11
vmovdqa ymm0, [rsp] ; stack is properly aligned first.
Run Code Online (Sandbox Code Playgroud)
我认为没有任何指令可以直接(或另一个方向)执行此操作,因为它意味着具有五个操作数的指令.但是,上面的代码对我来说似乎很愚蠢.有没有更好的方法呢?我只能想到一个替代方案,使用pinsrd相关说明.但它似乎没有任何好转.
动机是,有时候在AVX2中做一些事情会更快,而其他用于通用的注册事项.例如,在一小段代码中,有四个64位无符号整数,我将需要四个xor,两个mulx来自BMI2.这将是更快的做xor用vpxor,但是,mulx没有一个AVX2等同.由于包装和拆包过程,任何vpxor对比4 的增益xor都会丢失.