C 64位整数比零更快的方法

C 64位整数比零更快的方法,c,compare,compiler-optimization,C,Compare,Compiler Optimization,然而,寻找更快的方法来检查x==0。。。有一些方法可以优化和以确保编译器进行一些优化? 插图仅将与零的比较抽象化,因为Stackoverflow要求一段代码是有效的问题 #include <stdint.h> _Bool is_zero(int64_t checkMe) { /* ensure that compiler will do some optimization */ return checkMe==0x00000000LL; } #包括 _布尔为零(int

然而,寻找更快的方法来检查x==0。。。有一些方法可以优化和以确保编译器进行一些优化?


插图仅将与零的比较抽象化,因为Stackoverflow要求一段代码是有效的问题

#include <stdint.h>

_Bool is_zero(int64_t checkMe)
{   /* ensure that compiler will do some optimization */
   return checkMe==0x00000000LL;
}
#包括
_布尔为零(int64检查我)
{/*确保编译器将进行一些优化*/
返回checkMe==0x00000000LL;
}

代码中没有太多需要优化的内容

  • 您可以使用实现定义的pragma或属性来确保函数是内联的

  • 返回值不应为固定长度-仅为处理器本机大小整数值

  • 对于gcc

    inline int __attribute__((always_inline)) is_zero(int64_t checkMe)
    {   /* ensure that compiler will do some optimization */
       return checkMe == 0;
    }
    
    为什么
    int
    而不是int64\t

    让我们考虑8位微控制器:

    inline int __attribute__((always_inline)) is_zero(int64_t checkMe)
    {   /* ensure that compiler will do some optimization */
       return checkMe == 0;
    }
    
    inline int64_t __attribute__((always_inline)) is_zero1(int64_t checkMe)
    {   /* ensure that compiler will do some optimization */
       return checkMe == 0;
    }
    
    /* or even better */
    inline uint8_t __attribute__((always_inline)) is_zero2(int64_t checkMe)
    {   /* ensure that compiler will do some optimization */
       return checkMe == 0;
    }
    
    结果是:

    is_zero:
            ldi r30,lo8(1)
            ldi r31,hi8(1)
            or r18,r19
            or r18,r20
            or r18,r21
            or r18,r22
            or r18,r23
            or r18,r24
            or r18,r25
            breq .L2
            ldi r30,lo8(0)
            ldi r31,hi8(0)
    .L2:
            mov r24,r30
            mov r25,r31
            ret
    is_zero1:
            ldi r30,lo8(1)
            or r18,r19
            or r18,r20
            or r18,r21
            or r18,r22
            or r18,r23
            or r18,r24
            or r18,r25
            breq .L4
            ldi r30,lo8(0)
    .L4:
            mov r18,r30
            ldi r19,lo8(0)
            ldi r20,lo8(0)
            ldi r21,lo8(0)
            ldi r22,lo8(0)
            ldi r23,lo8(0)
            ldi r24,lo8(0)
            ldi r25,lo8(0)
            ret
    is_zero2:
            ldi r30,lo8(1)
            or r18,r19
            or r18,r20
            or r18,r21
            or r18,r22
            or r18,r23
            or r18,r24
            or r18,r25
            breq .L6
            ldi r30,lo8(0)
    .L6:
            mov r24,r30
            ret
    

    您希望如何进一步优化它?您希望在最终装配中有哪些说明

    在的第一页上,有一个将零值分配给寄存器的几种方法的示例。其中一些更长或更有效,但它们都做同样的事情。例子:
    
    异或eax,eax
    lea rbx[0]
    环路$
    mov-rdx,0
    和esi,0
    电子数据交换
    推0
    流行限制性商业惯例
    

    与价值进行比较并不像分配价值那个样富有。为了进行比较,您基本上有
    test
    cmp
    或检查
    ZF
    标志

    我认为最有效的方法是在
    sete
    指令之后使用
    test
    指令来获取
    ZF
    的值,如tkausl评论中的链接所示

    一般来说,如果希望编译器进行优化,则需要将适当的标志传递给它

    有关GCC优化,请参阅


    或者对于MSVC优化

    来说,当检查零时,看起来不会有太多错误:Hi@tkausl,好的基准(!)。好吧,即使没有优化,这也是一个很好的答案(!!),为了“证明”这是一个优化,只需添加
    int64\u t is\u nonzero(int64\u t checkMe){return checkMe==3;}
    显示cont-example。首先,如果你需要关心这样一个微优化,你的算法是糟糕的。其次,请自己检查:@谢谢@P_uuj_uuu,获得了很好的答案以及更多信息。在这个链接中,指令表显示
    TEST r,r
    CMP r,r/i
    具有相同的延迟,所以它们是等价的-这要感谢编译器将英特尔或AMD处理器的
    cmp
    替换为
    test
    时并没有真正的性能提升。。。这是一个有效的回答。这个问题是关于“任何处理器”的一般性问题(谢谢你的函数建议将被内联),只需要一个演示。。。也许我没有提供更好的上下文化,这里是:C代码与生成的机器代码几乎没有关系,除了行为。您是否在启用优化的情况下检查机器代码?生成的代码有什么问题?您认为优化的潜力在哪里?为什么您认为编译器不会识别模式并生成最好的代码?哪个目标体系结构?哪个工具链?为什么要使用函数呢?您是否启用LTO?您好@P_uuuj_uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu?将是答案的核心:指令
    测试rdi,rdi
    更快(?我想)tham
    cmp rdi,3
    ,因此它是一个自动优化。他们,你关于如何用pragmas确保它的讨论,等等。关于我在返回数据类型中使用
    int64\t
    ,对不起(!),我编辑了这个问题。是,可以是
    int
    \u Bool
    。。。不管怎样,这只是一个“背景说明”。这就是VXY问题。使用的说明取决于优化选项。这个例子太琐碎了,不值得深入考虑。看看我们可以在哪里证明优化的存在。。。也许说“优化”的主要信息是关于
    test
    cmp
    性能的,正如您强调的那样。。。编译器似乎采用
    testeax,eax
    作为
    cmp-eax,0
    的优化版本。。。它可能是一些性能稍好的指令,所以另一个问题是:有性能增益吗?is3编译为
    48 83 ff 03 cmp rdi,3 0f 94 c0 sete al
    ,而ISU zero编译为
    48 85 ff test rdi,rdi 0f 94 c0 sete al
    ,短一个字节。这将产生更小的二进制文件,并可能使它们运行得更快,尽管这并不能保证。从我做的实证测试来看,它们的性能几乎相同,并且没有规则规定哪一个跑得更快,尽管平均跑得时间更短。你应该相信你的编译器能生成好的程序集,而不是试图找到一种强迫它这样做的方法。谢谢@Mickey695。似乎我们可以说没有“优化方法”(使用
    test
    时没有性能增益或边际),我们只需要采取“最小的谨慎”来避免产生糟糕的代码。下面是产生这个问题的确切背景:甚至不清楚OP使用的是x86/64。询问这样简单的C代码与生成的机器代码完全无关。优化首先应该留给编译器。直到现在,OP还没有回答很多相关的问题,其中关于为什么是最不重要的问题。