g ++优化:O2标志修复了破坏的代码,其中O3再次破坏它

时间:2017-11-01 16:03:23

标签: c++ g++ compiler-optimization

此代码,用于匹配NFA中的字符串,我认为需要20,000内存,当字符串大小为-O2时,可预测会中断,然后使用-O3编译代码,然后再次中断为-std=c++14。编译是在启用"ab"的情况下完成的。在我看来,问题是堆栈溢出。

输入字符串10,000重复'c'次,最后加-O2。下面的图片包含我尝试匹配的NFA。

具体来说,我的问题是 -

1)这背后的-O3优化是什么(我相信这是令人印象深刻的)修复?

2)struct State { map<char,vector<State*> > transitions; bool accepting = false; }; bool match(State* state,string inp){ if(inp=="") return state->accepting; for(auto s:state->transitions[inp[0]]) if(match(s,inp.substr(1))) return true; for(auto s:state->transitions['|']) //e-transitions if(match(s,inp)) return true; return false; } 优化会再次破坏它?

{{1}}

在gcc文档中,它说O3具有O2的所有优化,还有更多优化。我无法得到&#34;其中一些额外内容或它们与此问题的相关性。我想强调的是,对于我在类似问题中看到的内容,我并没有找到解决此问题的具体方法。

Th tested NFA

1 个答案:

答案 0 :(得分:2)

正如您已经想到的那样:问题在于递归的堆栈使用。同样,TLO既不会对a[href*="value"] - the attribute value *contains* the specified value a[href$="value"] - the attribute value *ends with* the specified value a[href^="value"] - the attribute value *starts with* the specified value a[href="value"] - the attribute value *matches exactly* the specified value 也不会对-O2执行(理论上,只有最后一次重复调用才有可能在你的情况下无效)。

但是,根据优化级别,您的功能需要不同的堆栈空间。无法保证-O3版本更快,并且需要更少的空间。

当我们查看assembly时,我们可以看到以下内容:

  1. -O3通过-O3保留88个字节,堆栈上的占用空间更大,因为除了通常的函数序言之外,寄存器subq $88, %rsp也被压入堆栈。

  2. 除了在堆栈上推送的寄存器之外,
  3. r12-r15仅保留56个字节。

  4. 如果没有优化,堆栈上的占用空间是最大的:所有内容都需要在两行原始代码之间存储/加载到堆栈中,以便获得可预测的调试行为,以便我们可以在调试器中更改值

  5. 这可以解释你的观察结果:没有优化,堆栈很快就会满了。 -O2优化可以缓解它(但是没有修复它),因此可以处理20000的递归深度 - 它可能会因30000而崩溃。-O2优化具有更大的堆栈占用空间并且已经失败较小的投入。

    现在很明显正确解决了这个问题:应该使用深度优先搜索的迭代版本或广度优先搜索。

    代码中的另一个问题 - 使用-O3会导致不必要的内存复制/使用。只需将迭代器传递给字符串中的第一个字符,然后递增它以进行递归调用。