首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >分支掩蔽在CryENGINE 3中是如何工作的?

分支掩蔽在CryENGINE 3中是如何工作的?
EN

Stack Overflow用户
提问于 2012-12-15 17:06:53
回答 1查看 494关注 0票数 11

CryENGINE SDK标题的这一部分引起了我的注意:

brchmask.h

代码语言:javascript
复制
#ifndef __BRANCHLESS_MASK__
#define __BRANCHLESS_MASK__

///////////////////////////////////////////
// helper functions for branch elimination
//
// msb/lsb - most/less significant byte
//
// mask - 0xFFFFFFFF
// nz   - not zero
// zr   - is zero

ILINE const uint32 nz2msb(const uint32 x)
{
    return -(int32)x | x;
}

ILINE const uint32 msb2mask(const uint32 x)
{
    return (int32)(x) >> 31;
}

ILINE const uint32 nz2one(const uint32 x)
{
    return nz2msb(x) >> 31; // int((bool)x);
}

ILINE const uint32 nz2mask(const uint32 x)
{
    return (int32)msb2mask(nz2msb(x)); // -(int32)(bool)x;
}


ILINE const uint32 iselmask(const uint32 mask, uint32 x, const uint32 y)// select integer with mask (0xFFFFFFFF or 0x0 only!!!)
{
    return (x & mask) | (y & ~mask);
}


ILINE const uint32 mask_nz_nz(const uint32 x, const uint32 y)// mask if( x != 0 && y != 0)
{
    return msb2mask(nz2msb(x) & nz2msb(y));
}

ILINE const uint32 mask_nz_zr(const uint32 x, const uint32 y)// mask if( x != 0 && y == 0)
{
    return msb2mask(nz2msb(x) & ~nz2msb(y));
}


ILINE const uint32 mask_zr_zr(const uint32 x, const uint32 y)// mask if( x == 0 && y == 0)
{
    return ~nz2mask(x | y);
}

#endif//__BRANCHLESS_MASK__

有人能简短地解释一下这些函数究竟是如何被用来减少分支的吗?我想ILINE是预定义的力,内嵌或类似的东西。我搜索了谷歌,但我只找到了上传到不同网站的CryENGINE头的副本,但没有讨论过这个特定的页面。

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2012-12-15 17:37:34

这些函数返回可以在其他计算中得到结果的位掩码,以便在不附加条件的情况下执行操作,从而无需引入分支。

例如:

  • 如果参数为nz2mask,则返回0,否则返回0xffffffff
  • 如果参数的顶部位是msb2mask,则返回0,如果是1,则返回0xffffffff

因此,如果您有类似的代码(参考x86指令):

代码语言:javascript
复制
if(a != 0) x += y;
    //  test        ebx,ebx  
    //  je          skip  
    //  add         dword ptr [x],eax  
    // skip:

您可以将其替换为:

代码语言:javascript
复制
x += y & (nz2mask(a));
    //  mov     ecx,ebx  
    //  neg     ecx  
    //  or      ecx,ebx  
    //  sar     ecx,1Fh  
    //  and     ecx,eax  
    //  add     ecx,dword ptr [x]  

它产生更多的指令(至少在x86上),但它避免分支。

然后还有一些额外的函数,比如iselmask(),它允许根据所提供的掩码选择输入,所以您可以替换:

代码语言:javascript
复制
x = (a != 0) ? r1 : r2;

使用

代码语言:javascript
复制
x = iselmask(nz2mask(a), r1, r2);

同样,这些函数应该内联并编译到相对高效的汇编程序中,用一些额外的数学来换取不分支。

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

https://stackoverflow.com/questions/13894302

复制
相关文章

相似问题

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