使用 gcc 编译时禁用所有明显的消除(不更改我的源代码!)

disable all obvious elimination when compiling with gcc (without changing my source code!)

我想在用 gcc 编译时保留所有死代码(或任何明显可以优化的代码),但即使使用 -O0,一些死代码仍然被优化。如何在不更改源代码 的情况下保留所有代码?示例代码如下,用g++ -S -O0 main.cc编译时,if-statement会在汇编代码中进行优化(不会有cmpljmp代码)。

int main() {
  constexpr int a = 123; // or const int a = 0; I do not want to remove `const` or `constexpr` qualifier.
  if (a) // or just if (123)
    return 1;
  return 0;
}

这里有一个相关问题:Disable "if(0)" elimination in gcc。但是那里的答案需要您更改源代码(删除 const/constexpr 限定符),我不想这样做。

难道我没有更改我的源代码,只是使用了一些编译器标志来实现这个?

在这种情况下,GCC 无法保留条件,因为它在编译的早期阶段就被删除了。

首先是GCC的编译步骤:

  1. 代码解析(语法和语义)生成 GENERIC 表示 (HL-IR) 中的 AST
  2. 高级 GIMPLE 生成 (ML-IR)
  3. 低级 GIMPLE 生成 (ML-IR)
  4. 树 SSA 优化 (ML-IR)
  5. RTL 生成 (LL-IR)
  6. 代码优化
  7. 程序集生成

在生成(理论上未优化的)高级 GIMPLE 表示后,条件已被删除。因此,在任何优化步骤之前。可以使用 GCC 标志 -fdump-tree-all 来检查这一点,并查看第一个生成的 GIMPLE 代码。这是结果:

;; Function int main() (null)
;; enabled by -tree-original
{
  const int a = 123;

  <<cleanup_point   const int a = 123;>>;
  return <retval> = 1;
  return <retval> = 0;
}
return <retval> = 0;

可以注意到,constexprconst 的结果代码相同。实际上,constexpr 在 HL GIMPLE 代码中被视为一个简单的 const 变量。

很难知道何时在步骤 1 中完全删除了条件,因为 GENERIC 是 GCC 的依赖于实现的内部表示。不是很flexible/customizable。 AFAIK,甚至还不可能生成 AST/GENERIC 表示。您可以使用一些 GCC 插件自行提取它,但这是一项非常棘手的任务。