C++中公共子表达式消除的局限性
Limitations of Common Subexpression Elimination in C++
我在看一个演讲,"算法的效率,性能数据结构"对以下评论感到惊讶:
#include <string>
#include <unordered_map>
#include <memory>
struct Foo {
int x;
};
Foo* getFoo(std::string key,
std::unordered_map<std::string,
std::unique_ptr<Foo>> &cache) {
if (cache[key])
return cache[key].get();
cache[key] = std::unique_ptr<Foo>(new Foo());
return cache[key].get();
}
Foo* getFooBetter(std::string key,
std::unordered_map<std::string,
std::unique_ptr<Foo>> &cache) {
std::unique_ptr<Foo> &entry = cache[key];
if (entry)
return entry.get();
entry = std::unique_ptr<Foo>(new Foo());
return entry.get();
}
CCD_ 1较好。我一直相信我可以依靠关于在我希望只评估多次出现的x+y
一旦不出所料,生成的LLVM IR确实与节目主持人即使使用了-O9,我们在中也只剩下3个对cache[key]
的调用CCD_ 4版本。
我已经将两者的长LLVM IR与c++符号分开,以免在视觉上冒犯。
另一个StackOverflow问题揭示了这里的部分答案是operator[]
假设能够修改其希望的任何全局状态,以及因此我们不能取消呼叫。关于引入CCD_ 6注释介绍了它在CSE中的应用。
如果我们只打4个电话,我会在这里结束时感到满意。然而,如果我对IR的解读是正确的,那么看起来我们已经优化了getFoo()
变成好像我们写的:
Foo* getFoo(std::string key,
std::unordered_map<std::string,
std::unique_ptr<Foo>> &cache) {
if (cache[key])
return cache[key].get();
std::unique_ptr<Foo> &entry = cache[key];
entry = std::unique_ptr<Foo>(new Foo());
return entry.get();
}
有人能解释一下clang对代码的看法吗它能够合并最后两个cache[key]
,但不是全部他们(我的本地clang是3.4。(
我们在这里面临的案例是跨过程优化。
这个调用cache[key]
原来是getFooBetter()
0函数。因此,诸如内联之类的优化可能会根据[]函数的内联成本而起作用。Chandler提到了同样的问题,给定的哈希函数计算成本很高,内联被阻止,一个人最终会多次计算哈希函数!
在发生内联的情况下,首先计算-O3处的IR,cache[key]
,并且给定cache
,key
根本没有突变,这样的调用将优化为相同的SSA值。
在cache[key].get()
的情况下,我们通常会在cache[key]返回对象并使用get()
中的getelementpointer获取字段值时写入IR。打开优化后,这个IR变成了我们之前计算的"cache[key]"的SSA值,元素从唯一指针的结构访问。
回到getFooBetter()
,在最坏的情况下,如果编译器无法跨过程进行优化,cache[key]
的出现次数越多,计算量就会越多,即使在O3时,这个调用也会原样出现!
在无序映射查找中会发生很多事情。有散列计算,搜索一个bin,如果它不在bin中,则添加到bin中,如果表现在太大,则可能增长表。这与比较代码中有两个"x+y"实例不同。您应该更惊讶的是,它居然发现其中两个调用可以合并。(我是。(
一般来说,我不会指望编译器发现两个函数调用可以共享,当性能很重要时,我会自己在源代码中消除常见的子表达式。在constexpr完全实现之前,我甚至不会想到它会发现sin(x(是一样的。
- (C++)分析树以计算返回错误值的简单算术表达式
- 在VS2010-VS2015下编译时,如何使用decltype作为较大类型表达式的LHS
- 提升精神:解析布尔表达式并简化为规范范式
- 不能在初始值设定项列表中将非常量表达式从类型 'int' 缩小到'unsigned long long'
- 使用正则表达式regex_search在字符串中查找字符串
- 如何确认我的constexpr表达式实际上已经在编译时执行
- 概念中的cv限定符需要表达式参数列表
- 为什么constexpr的性能比正常表达式差
- 对于结构,表达式必须是可修改的ivalue
- 当一个值是非常量但用常量表达式初始化时使用constexpr
- 将fold表达式与std::一起用于两个元组
- 断言中的Fold表达式在某些计算机上编译,但在其他计算机上不编译
- 标记 '","' 之前的预期主表达式
- gcc和clang在表达式是否为常量求值的问题上存在分歧
- 如何计算具有指定类型的表达式的相对精度和绝对精度
- 带有用户定义类的c++折叠表达式
- 即使使用调试编译标志,表达式也是"optimized out"
- holeMenuProgram.cpp:38:1 错误:'}'令牌之前的预期主表达式
- 在 C++ 中使用正则表达式错误时出现问题 括号表达式中的范围无效
- C++中公共子表达式消除的局限性