我应该内联运算符==和!=,以防运算符!=()使用运算符==()的否定

用户名

我使用这个简单的示例来说明一个问题,在此问题中我试图优化堆栈使用率。假设我有一个这样的结构:

// Something.h
struct Something {
  int val;

  bool operator==(const Something& rhs);
  bool operator!=(const Something& rhs);
};

// Something.cpp
bool Something::operator==(const Something& rhs) {
  return val == rhs.val;
}

bool Something::operator!=(const Something& rhs) {
  return !(*this == rhs);
}

调用operator!=()会将两个堆栈帧压入堆栈(一个用于!=,另一个用于==)。我应该内联运算符!=(),以便==和!=都使用相同数量的堆栈吗?

彼得·科德斯

您应该使用链接时间优化(LTO),以便它们中的任何一个都可以完全内联到调用站点中,尤其是在这样的情况下。

但是,如果您不想使用LTO进行跨文件内联,那么可以的话,最好将operator != return !(*this == rhs);定义放入)中的类定义中,.h这样每个调用者都可以看到它,并且可以将其内联到刚刚包含的文件中的.h然后,调用者的asm将调用相同的operator==定义,但以相反的方式使用结果。例如test al,al/,jnz而不是jz在结果上进行分支。

如果您不使用LTO并且在编译时内联中不显示该定义,那么最好的做法是编译器在编译该内联时将其内联operator==operator!=独立定义中.cpp然后,您在机器代码中就有两个大小相似的函数,它们之间的区别只是一个布尔值求反。这些函数的用户(从其他文件)将调用另一个函数,因此它们都占用了I缓存/代码占用空间。


例子

https://godbolt.org/z/e88nGj

// Something.h
struct Something {
  int val;

  bool operator==(const Something& rhs);
  bool operator!=(const Something& rhs) { return !(*this == rhs); }
};
// simulated #include for one-file demo purposes

// Some other .cpp file, operator== definition not visible.
int foo(Something &a, Something &b)
{
    if (a != b) {
        return a.val;
    } else { 
        return b.val;
    }
}

用于x86-64(Godbolt)的GCC -O3编译如下:

foo(Something&, Something&):
        push    rbp
        mov     rbp, rsi
        push    rbx
        mov     rbx, rdi           # save the pointers in call-preserved regs
        sub     rsp, 8
        call    Something::operator==(Something const&)
        test    al, al                # set FLAGS from the bool retval
        cmovne  rbx, rbp              # select the right pointer
        mov     eax, DWORD PTR [rbx]  # and load from it

        add     rsp, 8                # epilogue
        pop     rbx
        pop     rbp
        ret

请注意,此代码调用Something::operator==在编译时无法内联(它可以在与LTO链接时进行内联)。它只是使用cmovne而不是cmove是否调用了一个单独的operator!=

operator!=联字面上零额外费用,并且或者函数的所有呼叫使用相同的独立定义,既可以节省代码的足迹。对性能有好处,尤其是当您具有同时使用两个运算符的代码以使其在缓存中保持最新状态时。

当然,operator==如果仅是class,则内联也可以节省大量资金int根本没有呼叫通常会好很多,因为不需要在某些内容周围保留寄存器。

(当然,在这种情况下,我的例子是太微不足道了:如果他们平等的,那么它仍然可以恢复a.val,因为它知道这是一样的b.val所以,如果你取消注释。operator==在Godbolt链接定义,foo编译为mov eax, DWORD PTR [rdi]/ ret,甚至从来没有接触b。)

本文收集自互联网,转载请注明来源。

如有侵权,请联系[email protected] 删除。

编辑于
0

我来说两句

0条评论
登录后参与评论

相关文章

来自分类Dev

我应该内联运算符==和!=,以防运算符!=()使用运算符==()的否定

来自分类Dev

否定&& JSON运算符

来自分类Dev

使用or和not运算符

来自分类Dev

如何否定Groovy Match运算符?

来自分类Dev

内联和运算符重载问题

来自分类Dev

重载++和+运算符

来自分类Dev

逻辑AND(&&)和OR(||)运算符

来自分类Dev

==和eq运算符

来自分类Dev

StringBuilder和'+'运算符

来自分类Dev

IfElse和OR运算符

来自分类Dev

逻辑AND(&&)和OR(||)运算符

来自分类Dev

C ++运算符“ <”和“>”

来自分类Dev

AnsiString 和 += 运算符

来自分类Dev

运算符 = 和 != 同时

来自分类Dev

使用CAML <Or>和<And>运算符

来自分类Dev

Excel Pivot使用“和”运算符

来自分类Dev

存储和使用算术运算符

来自分类Dev

混合使用 AND 运算符和 OR javascript

来自分类Dev

比较SIFT运算符和MOPS运算符

来自分类Dev

Java,运算符重载和String的“ +”运算符

来自分类Dev

组合问题:运算符'=='和运算符'-'

来自分类Dev

sqflite IN运算符和AND运算符

来自分类Dev

Haskell美元运算符和中缀运算符

来自分类Dev

位运算符比+和-运算符快吗

来自分类Dev

+ =运算符和新的运算符c#

来自分类Dev

逻辑运算符和增量运算符

来自分类Dev

实现|| =和&& =运算符:没有匹配运算符声明的运算符实现

来自分类Dev

C运算符的优势:增量运算符和逻辑运算符

来自分类Dev

使用>>运算符