首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >为什么边界检查没有被消除?

为什么边界检查没有被消除?
EN

Stack Overflow用户
提问于 2014-02-11 21:17:12
回答 3查看 1.3K关注 0票数 20

我写了一个简单的benchmark,以便了解在通过按位and计算数组时是否可以消除边界检查。这基本上就是几乎所有哈希表所做的事情:它们计算

代码语言:javascript
运行
复制
h & (table.length - 1)

作为table的索引,其中hhashCode或派生值。results显示边界检查不会被消除。

我的基准测试的想法非常简单:计算两个值ij,这两个值都保证是有效的数组索引。

  • i是循环计数器。当它被用作数组索引时,边界检查将eliminated.
  • j计算为x & (table.length - 1),其中x是在每次迭代中更改的某个值。当它用作数组索引时,不会消除边界检查。

相关部分如下:

代码语言:javascript
运行
复制
for (int i=0; i<=table.length-1; ++i) {
    x += result;
    final int j = x & (table.length-1);
    result ^= i + table[j];
}

另一个实验使用

代码语言:javascript
运行
复制
    result ^= table[i] + j;

而不是。时间上的差异可能是15% (在我尝试过的不同变种中都是如此)。我的问题:

除了绑定检查elimination?

  • Is,还有其他可能的原因吗?我看不出为什么j

没有绑定检查消除的复杂原因

答案摘要

MarkoTopolnik的回答表明,这一切都要复杂得多,消除边界检查并不能保证成功,特别是在他的计算机上,“正常”代码比“屏蔽”代码慢。我猜这是因为它允许一些额外的优化,这在这种情况下实际上是有害的(考虑到当前CPU的复杂性,编译器甚至很难确定)。

列文托夫的回答清楚地表明,数组边界检查是在“掩蔽”中完成的,它的消除使代码的速度与“正常”一样快。

Donal for指出,掩码不适用于长度为零的表,因为x & (0-1)等于x。因此,编译器能做的最好的事情就是用零长度的检查来代替边界检查。但这仍然是值得的,因为零长度检查可以很容易地移出循环。

建议的优化

由于当且仅当a.length == 0a[x & (a.length - 1)]抛出的等价性,编译器可以执行以下操作:

  • 对于每个数组访问,请检查索引是否已通过位and。
  • 计算。如果是,请检查其中一个操作数是否计算为长度减一。
  • 如果是,请将边界检查替换为零长度检查。
  • 让现有优化来处理它。

这样的优化应该是非常简单和廉价的,因为它只查看SSA图中的父节点。与许多复杂的优化不同,它永远不会是有害的,因为它只用稍微简单的检查替换了一次检查;所以没有问题,即使它不能移出循环。

我会把这个贴到hotspot-dev邮件列表上。

新闻

John Rose提交了一份RFE,而且已经有了一个“快速和肮脏”的patch

EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/21702939

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档