首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >通过按位选择删除分支

通过按位选择删除分支
EN

Stack Overflow用户
提问于 2013-01-29 21:57:52
回答 2查看 1.5K关注 0票数 5

我被告知代码中的分支

代码语言:javascript
复制
int value = //some number;
if(value > some_other_value)
   value *= 23;
else
   value -= 5; 

可以通过按位掩码消除(以便对代码启用SIMD优化):

代码语言:javascript
复制
const int Mask = (some_other_value-value)>>31;
value =      ((value * 23)&Mask)|((value-5)&~Mask);

然而,我不明白这是如何工作的(即使我知道这里使用的是什么操作,以及结果在二进制中看起来是什么样子)。此外,这有多普遍适用?如果原来的代码是这样的呢?

代码语言:javascript
复制
if(value & 1 == 1)
   value *= 23;
else
   value -= 5;

删除分支的代码还会是一样的吗?否则,遮罩的用途是什么,我应该如何开始创建它?这是怎么回事?

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2013-01-29 22:07:41

这是可行的:

代码语言:javascript
复制
const int Mask = (some_other_value-value)>>31;
value =      ((value * 23)&Mask)|((value-5)&~Mask);

Mask成为some_other_value - value的符号位-类似于:

代码语言:javascript
复制
if (value > some_other_value) mask = -1; else mask = 0; 

你可以用你的第二个例子来实现同样的事情,使用:

代码语言:javascript
复制
mask = -(value & 1);

所以,-0 = 0,-1 =全1。

编辑:我也会记住,如果计算变得太复杂,你不会从分支版本中获得任何东西,特别是如果分支是合理可预测的。

票数 4
EN

Stack Overflow用户

发布于 2013-01-30 21:56:06

在最好的情况下,这是过早的优化,在最坏的情况下,这是反优化。

如果代码可以矢量化,它无论如何都会使用条件移动,因为SIMD不知道其他任何事情。

但是,即使对于标量代码,现代编译器通常也会生成条件移动,所以没有分支(除非编译器认为计算这两个等式的代价足够高,所以分支更有效)。

条件移动一直是RISC处理器(例如ARM)上的标准功能,甚至在x86上也支持了17年。在现代处理器上,条件移动将占用与正常移动完全相同的周期,或者最多额外占用2-3个周期。

这显然假设条件已经足够早地进行了评估(尽管如果不存在对值的依赖关系并不重要,因为无序执行会隐藏它),但这也适用于您所应用的任何一种隐蔽的优化技巧。你只是不能使用一个还不存在的结果。

如果可以的话,在第一眼看到时,总是写一些容易理解的代码,而不是一些模糊的代码

代码语言:javascript
复制
value = (((foo<<31)&bar, ++baz) -= (foo & 7121)) + PHASE_OF_MOON;

这种东西不仅不会更快,也可能更慢,而且会让审查你的代码的人感到困惑(包括你自己,从现在开始的6-10个月!),它是高度不可移植的,而且很可能在你意想不到的情况下产生不正确的结果。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/14584681

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档