optimization - c 优化32位值构造

  显示原文与译文双语对照的内容

因此,我有以下代码:


uint32_t val;


if (swap) {


 val = ((uint32_t)a & 0x0000ffff) | ((uint32_t)b < <16);


} else {


 val = ((uint32_t)b & 0x0000ffff) | ((uint32_t)a < <16);


}



是否有一种优化它的方法,并且以某种方式嵌入在语句中去检查swap?

时间:


val = swap? ((uint32_t)a & 0x0000ffff) | ((uint32_t)b < <16) : ((uint32_t)b & 0x0000ffff) | ((uint32_t)a < <16);



这将实现你所要求的"嵌入" 但是,我不推荐这样做,因为它使可读性更差,并且运行时优化。

GCCClang对64位处理器的策略略有不同, GCC生成分支代码,而且Clang将同时运行两个分支,然后使用条件移动, GCC和Clang将生成"zero-extend short to int"指令,而不是 and

使用?:并没有改变生成的代码,

Clang版本似乎更有效,

总而言之,如果不需要swap,那么两者都会生成相同的代码 ,

我们没有太多的时间来优化

这里有两个版本


typedef union


{


 uint16_t u16[2];


 uint32_t u32;


}D32_t;



uint32_t foo(uint32_t a, uint32_t b, int swap)


{


 D32_t da = {.u32 = a}, db = {.u32 = b}, val;



 if(swap)


 {


 val.u16[0] = da.u16[1];


 val.u16[1] = db.u16[0];


 }


 else


 {


 val.u16[0] = db.u16[1];


 val.u16[1] = da.u16[0];


 }



 return val.u32;


}



uint32_t foo2(uint32_t a, uint32_t b, int swap)


{


 uint32_t val;


 if (swap) 


 {


 val = ((uint32_t)a & 0x0000ffff) | ((uint32_t)b < <16);


 } 


 else 


 {


 val = ((uint32_t)b & 0x0000ffff) | ((uint32_t)a < <16);


 }



 return val;


}



生成的代码几乎是相同的,

clang:


foo: # @foo


 mov eax, edi


 test edx, edx


 mov ecx, esi


 cmove ecx, edi


 cmove eax, esi


 shrd eax, ecx, 16


 ret


foo2: # @foo2


 movzx ecx, si


 movzx eax, di


 shl edi, 16


 or edi, ecx


 shl esi, 16


 or eax, esi


 test edx, edx


 cmove eax, edi


 ret



GCC:


foo:


 test edx, edx


 je . L2


 shr edi, 16


 mov eax, esi


 mov edx, edi


 sal eax, 16


 mov ax, dx


 ret


.L2:


 shr esi, 16


 mov eax, edi


 mov edx, esi


 sal eax, 16


 mov ax, dx


 ret


foo2:


 test edx, edx


 je . L6


 movzx eax, di


 sal esi, 16


 or eax, esi


 ret


.L6:


 movzx eax, si


 sal edi, 16


 or eax, edi


 ret



https://godbolt.org/z/F4zOnf

如果目标是避免分支,那么你可以编写:


val = ((!!swap) * (uint32_t)a + (!swap) * (uint32_t)b) & 0x0000ffff)


 | (((!!swap) * (uint32_t)b + (!swap) * (uint32_t)a) < <16);



如果x为1,则使用计算为0,每当swap为false时,为1,则为当x为0时,x也计算为1,尽管!!xx本身可能不是 1 按结果相乘可选择 ab

但是,请注意,你现在有多个逻辑和算术操作,而不是一个比较和分支, 这并不清楚是否能在实践中提高性能。

...