Dan*_*ury 11 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;
}
Run Code Online (Sandbox Code Playgroud)
这里的算术只是一个例子。实际的代码更复杂,但要点是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");
}
}
Run Code Online (Sandbox Code Playgroud)
当然,我实际上并不想编写所有这样的代码,因为这是测试和维护的噩梦。
使用Compiler Explorer,看起来sign这里可能是一个例外。如果我有“默认”情况下的返回值,例如-1,那么我得到了我想要的。但是我想要一些安全。
问题:
-O3将其克隆为两个方法,其中一个克隆完成了我想要的操作,尽管我不知道哪个实际上可以运行。我可以为此提供提示吗?-O3。我可以仅针对特定的代码块启用优化,还是鼓励编译器进行优化?编辑:由于我(显然)不了解手头的所有问题,所以我可能没有给这个标题好。如果您知道自己在做什么,请随时进行编辑。
这是另一种选择:
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);
}
Run Code Online (Sandbox Code Playgroud)
这样,您可以保持所需的安全性(以异常的形式),但是随后将结果信息转换为编译时值,编译器可以使用该值进行优化。
正如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);
}
Run Code Online (Sandbox Code Playgroud)
由于在这种情况下,int sign(MyEnum)其他翻译单元不使用该函数,因此可以将其标记为static。
在这种情况下,static意味着该函数是翻译单元的本地函数,并且不会链接到该翻译单元之外。(该关键字static在 C++ 中具有不同的含义,具体取决于所使用的上下文。)
这允许优化器执行更多优化,并可能完全消除该函数(假设启用了优化)。
| 归档时间: |
|
| 查看次数: |
174 次 |
| 最近记录: |