C++ &引用;“自定义固有”;是否可以使用x64函数代替内联程序集?

C++ &引用;“自定义固有”;是否可以使用x64函数代替内联程序集?,c++,assembly,64-bit,inline-assembly,intrinsics,C++,Assembly,64 Bit,Inline Assembly,Intrinsics,我目前正在尝试为我的一个库创建高度优化、可重用的函数。例如,我用以下方式编写函数“is power of 2”: template<class IntType> inline bool is_power_of_two( const IntType x ) { return (x != 0) && ((x & (x - 1)) == 0); } 我还从这里找到了实现:,它将在x64的汇编中编码如下: is_power_of_two_fast PRO

我目前正在尝试为我的一个库创建高度优化、可重用的函数。例如,我用以下方式编写函数“is power of 2”:

template<class IntType>  
inline bool is_power_of_two( const IntType x )
{
    return (x != 0) && ((x & (x - 1)) == 0);
}
我还从这里找到了实现:,它将在x64的汇编中编码如下:

is_power_of_two_fast PROC
    test rcx, rcx
    je  SHORT NotAPowerOfTwo
    lea rax, [rcx-1]
    and rax, rcx
    neg rax
    sbb rax, rax
    inc rax
    ret
NotAPowerOfTwo:
    xor rax, rax
    ret
is_power_of_two_fast ENDP

我测试了两个独立于C++的子程序在汇编模块(.ASM文件)中写入,第二个程序工作速度快了20%!p> 然而,函数调用的开销是相当大的:如果我将第二个程序集实现“is_power_of_two_fast”与模板函数的内联版本进行比较,尽管存在分支,后者的速度更快

不幸的是,x64的新约定指定不允许内联程序集。人们应该使用“内在函数”


现在的问题是:我能否将更快的版本“is_power_of_two_fast”实现为一个定制的内在函数或类似的东西,以便可以内联使用?或者,是否有可能以某种方式强制编译器生成函数的低分支版本?

唯一的方法是后退一步,开始看大图。要么停止实施微优化API,要么继续进行更大的API调用,所有调用都在MASM64、YASM、NASM等中进行了优化


如果您使用功能更强大的汇编程序,您可以将小函数转换为宏,因此基本上可以将基于C/C++头的内联汇编程序函数更改为汇编程序包含文件。

不,您无法实现任何自定义的内部函数,它们都内置在编译器中。它不仅是内置的指令,而且编译器还知道内在的语义,并根据不同的周围代码调整代码

删除x86-64的内联程序集的一个原因是,将程序集插入函数的中间会干扰优化器,并且通常会导致在汇编代码周围的代码没有得到很好的优化。那里很容易出现净损失

唯一用于内蕴的是用于“有趣”的特殊指令,编译器不能从C或C++结构生成,比如BSF或BSR。使用内联函数,如上面的模板,其他大多数功能都会工作得更好

如果您需要执行编译器不理解的特殊操作,唯一的实际选择是将整个函数作为单独的汇编模块编写。如果该函数的调用开销太大,那么优化一开始可能就没有那么大的价值


相信你的编译器(tm)

在这种简单的情况下,VC10 x64内部函数不会有很大帮助。 您拥有的动态分支是由于&&运算符,它是一个早出运算符。 在许多情况下(您的案例是一个完美的例子),最好通过计算所有分支的结果来避免分支,然后应用掩码来选择好的分支。带有屏蔽的cpp代码如下所示:

template<typename T_Type>
inline bool isPowerOfTwo(T_Type const& x)
{
    // static type checking for the example
    static_assert( std::is_integral<T_Type>::value && std::is_unsigned<T_Type>::value, "limited to unsigned types for the example" );
    typedef std::make_signed<T_Type>::type s_Type;

    // same as yours but with no branching
    return bool(  ((s_Type( s_Type(x != 0) << (s_Type(sizeof(T_Type)<<3u)-1) )) >> (s_Type(s_Type(sizeof(T_Type)<<3u)-1)))  & ((x & (x - 1)) == 0)  );
}
模板
内联bool isPowerOfTwo(T_类型const&x)
{
//示例的静态类型检查
静态断言(std::is_integral::value&&std::is_unsigned::value,“仅限于示例中的无符号类型”);
typedef std::make_signed::type s_type;
//和你的一样,但没有分支

返回bool(((s_-Type)(s_-Type(x!=0)即使是VC2005也能够使用sbb指令生成代码

对于C代码

bool __declspec(noinline) IsPowOf2(unsigned int a)
{
    return (a>=1)&((a&(a-1))<1);
}

GCC和ICC仍然允许内联汇编通过使用&而不是&&来避免分支。@drhirsch:谢谢,我记住了这一点。@Hans Passant:我已经尝试过了,但它会导致代码速度变慢(指令太多)不幸的是,您的建议与最初的C++函数没有什么不同。汇编输出的汇编显示,VC++ 2008在编译代码时使用“测试”指令,分支仍然存在。
bool __declspec(noinline) IsPowOf2(unsigned int a)
{
    return (a>=1)&((a&(a-1))<1);
}
00401000  lea         eax,[ecx-1] 
00401003  and         eax,ecx 
00401005  cmp         eax,1 
00401008  sbb         eax,eax 
0040100A  neg         eax  
0040100C  cmp         ecx,1 
0040100F  sbb         ecx,ecx 
00401011  add         ecx,1 
00401014  and         eax,ecx 
00401016  ret