【问题标题】:Do compilers optimize switches differently than long if-then-else chains?编译器优化开关的方式是否与长 if-then-else 链不同?
【发布时间】:2019-04-11 09:40:15
【问题描述】:

假设我有 N 个在编译时已知的不同整数值,从 V_1 到 V_N。考虑以下结构:

const int x = foo();
switch(x) {
case V_1: { /* commands for V_1 which don't change x */ } break;
case V_2: { /* commands for V_1 which don't change x */ } break;
/* ... */
case V_N: { /* commands for V_1 which don't change x */ } break;
}

对比

const int x = foo();
if      (x == V_1) { /* commands for V_1 which don't change x */ }
else if (x == V_2) { /* commands for V_2 which don't change x */ }
else ...
else if (x == V_N) { /* commands for V_N which don't change x */ }

现代 C++ 编译器是否以不同的方式处理这些?也就是说,他们是否对这些代码结构应用了不同的潜在优化?还是他们将它们“规范化”为相同的,然后决定优化(例如是否形成跳转表)?

注意事项:

  • 我所说的现代 C++ 编译器主要指的是最新版本的 GCC、clang 和 MSVC。 ICC 也可能是相关的。
  • 请回答关于最大优化级别(-O3 用于 clang 和 GCC)
  • ...但是,如果switches 和if-then-else-chains 的处理在某些优化级别相同而在其他优化级别不同,那也很有趣。
  • 我猜答案可能取决于 N 的值 - 如果可能,请给出阈值。

【问题讨论】:

  • 在 godbolt.org 上尝试通常是解决这类问题的良好第一步。
  • @FrançoisAndrieux:结果可能相同,但这可能是由于 N 选择不当,或者由于不同的优化导致相同的结果。

标签: c++ switch-statement g++ compiler-optimization clang++


【解决方案1】:

具有讽刺意味的是,这正是我几天前为最近的编译器所做的测试。碰巧的是,使用最新的编译器,clangswitchif 生成相同的程序集 - 对于少数情况(低于 5),它会生成一堆直接条件跳转,而对于 5 或​​更多情况,它会生成间接跳表。

另一方面,gcc 对它们的处理方式不同:它将switch 转换为间接表跳转,而一系列if 语句仍然是一系列有条件的直接跳转。

另外值得注意的是,如果switch case里面有“洞”(即没有被case标签覆盖的控制变量的可能值),它仍然可以转换成一系列有条件的直接跳转或间接表跳转,但我无法弄清楚确切的公式。

这是一些播放代码: https://gcc.godbolt.org/z/Lll1Kd

【讨论】:

  • 我更感兴趣的是编译器如何处理这个问题,而不是最终生成的代码是否相同,但我会阅读链接。
  • @einpoklum 我不确定您所说的“编译器如何接近它”是什么意思。结果代码不是最好的判断吗?
  • 同样的结果可能是偶然的,而不是根本的。无论如何,建议您将链接更改为this:减少boo()'ing,并且更容易比较生成的程序集。
  • 我刚刚就这个问题向 GCC 提交了一个错误:gcc.gnu.org/bugzilla/show_bug.cgi?id=87925
  • @einpoklum 有趣的是它会发生什么。我很乐意看到一系列与案例标签相同的处理方式。
猜你喜欢
  • 2020-05-23
  • 2015-04-15
  • 1970-01-01
  • 2016-04-18
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多