c++ - 我可以鼓励 g++ 内联一个返回符号的开关吗?

标签 c++ compiler-optimization

我有一堆如下代码:

int sign(MyEnum e)
{
  switch(e)
  {
    case A:
    case B:
      return 1;
    case C:
    case D:
      return -1;
    default:
      throw std::runtime_error("Invalid enum value");
  }
}

int f(int a, int b, int c, MyEnum e)
{
  const int sign = sign(e);

  const int x = a * b - sign * c;
  const int y = a + sign * c;

  return x / y;
}

这里的算法只是一个例子。实际代码更复杂,但要点是 sign 是 -1 或 1,具体取决于枚举值,我们做了一堆计算,其中各种东西乘以 sign。 (编辑:枚举值在编译时未知。)

我希望优化此代码,就好像我编写了如下内容一样:

  int f(int a, int b, int c, MyEnum e)
  {
    switch(e)
    {
      case A:
      case B:
        {
          const int x = a * b - c;
          const int y = a + c;

          return x / y;
        }
      case C:
      case D:
        {
          const int x = a * b + c;
          const int y = a - c;

          return x / y;
        }
      default:
        throw new std::runtime_error("Invalid enum value");
    }
  }

当然,我实际上并不想编写所有这样的代码,因为这是测试和维护的噩梦。

使用 Compiler Explorer,看起来 sign 中的异常可能是这里的问题;如果我有“默认”案例返回,比如说,-1,那么我就得到了我想要的。但我希望这里一些安全。

问题:

  1. 是否存在抛出异常阻止(或阻止编译器使用)此优化的根本原因?
  2. 看起来在 -O3 处编译此方法会生成该方法的两个克隆,其中一个执行我想要的操作,尽管我不知道实际会运行哪个。我可以为此提供提示吗?
  3. 我不知道我是否想在 -O3 编译所有。我可以只对特定代码块进行优化,还是鼓励编译器进行优化?
  4. 是否有一些花哨的模板元编程技巧或我可以用来编写看起来像第一个 block 但生成的代码看起来像第二个 block 的代码?
  5. 对于我正在尝试做的事情还有其他建议吗?

编辑:因为我(显然)不理解手头的所有问题,所以我可能没有给它起一个好标题。如果您知道自己在做什么,请随时进行编辑。

最佳答案

这里有一个替代方案:

template <int sign>
int f(int a, int b, int c)
{
  const int x = a * b - sign * c;
  const int y = a + sign * c;

  return x / y;
}


int f(int a, int b, int c, MyEnum e)
{
  const int sign = sign(e);
  if (sign == 1) return f<1>(a, b, c);
  else return f<-1>(a, b, c);
}

通过这种方式,您可以保持所需的安全性(以异常的形式),然后将结果信息转换为编译器可用于优化的编译时值。

作为Chris在评论中指出,如果 sign 仅用于切换 c 的符号,您可以完全摆脱模板,只需翻转 c 打电话时的手势:

int f(int a, int b, int c)
{
  const int x = a * b - c;
  const int y = a + c;

  return x / y;
}


int f(int a, int b, int c, MyEnum e)
{
  const int sign = sign(e);
  if (sign == 1) return f(a, b, c);
  else return f(a, b, -c);
}

关于c++ - 我可以鼓励 g++ 内联一个返回符号的开关吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57061181/

相关文章:

C++ 编译器优化

c++ - "sibling calls"是什么意思?

c++ - 如何知道 QPlainTextEdit 继承类中是否显示水平滚动条?

C++ 无法添加到模板内的 vector

c++ - gcc 静态分析器 (Weffc++) : exclude directories

c++ - 奇怪的内存泄漏

compiler-optimization - 编译器可以基于 assert(...) 表达式/契约(Contract)进行优化吗?

c - 通过 header 嵌入无法优化的字符串

c++ - 在 Windows 7 64 位中使用 32 位 shell 扩展

assembly - ASM 空间优化 : EAX vs EBX