首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >GCC似乎错过了简单的优化

GCC似乎错过了简单的优化
EN

Stack Overflow用户
提问于 2018-09-13 19:38:18
回答 1查看 491关注 0票数 6

我试图引入一个具有三元操作符语义的泛型函数:E1 ? E2 : E3。我看到编译器能够消除E2E3之一的计算,这取决于三元操作符的E1条件。然而,GCC在ternary函数调用的情况下(即使E2/E3没有副作用)也忽略了这一优化。

在下面的清单中,函数ternary被写成类似于三元操作符的行为。然而,GCC可能会对函数f发出很大的调用,这对于某些输入值(对三元操作符来说是这样做的)来说似乎是可以消除的,因为f是用纯属性声明的--请看安理会生成的汇编代码的龙芯链接。

这是在GCC (优化空间)中可以改进的东西,还是C++标准明确禁止这种优化?

代码语言:javascript
复制
// Very heavy function
int f() __attribute__ ((pure));

inline int ternary(bool cond, int n1, int n2) {
    return cond ? n1 : n2;
}

int foo1(int i) {
    return i == 0 ? f() : 0;
}

int foo2(int i) {
    return ternary(i == 0, f(), 0);
}

使用-O3 -std=c++11的组装清单

代码语言:javascript
复制
foo1(int):
  test edi, edi
  jne .L2
  jmp f()
.L2:
  xor eax, eax
  ret
foo2(int):
  push rbx
  mov ebx, edi
  call f()
  test ebx, ebx
  mov edx, 0
  pop rbx
  cmovne eax, edx
  ret

https://godbolt.org/z/HfpNzo

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2018-09-13 20:09:26

我看到编译器能够根据三值操作符的E2或E3条件(只要E2/E3没有副作用)来消除E1或E1的计算。

编译器并没有消除它;它只是从一开始就没有将其优化为cmov C++抽象机器不计算三元操作符的未使用侧。

代码语言:javascript
复制
int a, b;
void foo(int sel) {
    sel ? a++ : b++;
}

像这样编译(哥德波特 )

代码语言:javascript
复制
foo(int):
    test    edi, edi
    je      .L2                # if(sel==0) goto
    add     DWORD PTR a[rip], 1   # ++a
    ret
.L2:
    add     DWORD PTR b[rip], 1   # ++b
    ret

如果任何输入都没有任何副作用,则三元操作符只能对asm cmov进行优化.否则它们就不完全等同了。

在抽象机器(即gcc的优化器的输入)中,您的foo2 foo1 总是调用 f()**,,而您的**foo1没有调用。并不奇怪foo1是这样编译的。

要用这种方式编译f()**.**,必须优化对的调用--它总是被调用来为ternary()创建一个arg。

这里有一个遗漏的优化,您应该报告GCC的bugzilla (使用missed-optimization关键字作为标记)。bug.cgi?product=gcc

int f() __attribute__ ((pure)); 的调用应该能够优化。可以读取全局,但不能有任何副作用。 (https://gcc.gnu.org/onlinedocs/gcc/Common-Function-Attributes.html)

正如@melpomene在评论中发现的那样,int f() __attribute__ ((const));确实为您提供了您想要的优化。一个__attribute__((const))函数甚至不能读取全局,只能读取它的args。(因此,如果没有args,则必须始终返回常量。)

HVD指出gcc没有任何f()的成本信息。即使它可以优化对((pure)) f()的调用,也可以优化对((const)) f的调用,可能是因为它不知道它比一个条件分支更昂贵吗?可能用配置文件引导的优化编译会说服gcc去做些什么?

但考虑到它在((const)) f中对foo2的调用是有条件的,gcc可能不知道它能优化对((pure))函数的调用吗?也许它只能对它们进行CSE (如果没有编写全局代码),但不能完全从基本块中优化?或者,当前的优化器可能只是没有利用。就像我说的,看上去是个漏掉的小虫子。

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

https://stackoverflow.com/questions/52320679

复制
相关文章

相似问题

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