3

是否有任何示例(例如在https://godbolt.org/上)当使用指针迭代而不是数组索引表示的算法时,CLang 会生成更糟糕的代码?例如,它可以在一种情况下矢量化/展开,但在另一种情况下不能?

在简单的例子中显然没关系。这是一个指针迭代样式:

while (len-- > 0) {
  *dst++ = *src++;
}

这是索引样式的逻辑相同的代码:

while (idx != len) {
  dst[idx] = src[idx];
  idx++;
}

在这里忽略任何 UB 和/或关闭一个错误。

编辑:关于索引是糖的论点是无关紧要的,因为去糖不会改变算法风格。所以以下基于指针的代码仍然是索引样式:

while (idx != len) {
  *(dst + idx) = *(src + idx);
  idx++;
}

请注意,基于索引的循环只有 1 个变化变量,而基于指针的循环有 2 个,编译器必须推断它们总是一起变化。

您应该在https://en.wikipedia.org/wiki/Induction_variablehttps://en.wikipedia.org/wiki/Strength_reduction的上下文中查看此内容。指针样式本质上是强度降低的索引样式,因为添加被增量替换。这种减少在一段时间内对性能有益,但不再有效。

所以我的问题归结为是否存在编译器无法执行或逆转这种强度降低的情况。

另一种可能的情况是索引不是归纳变量。因此,相应的指针代码包括“任意跳转”,并且由于过去迭代的“历史”,它在某种程度上更难以转换循环。

4

1 回答 1

3

只要不operator []涉及重载,下标表达式就被定义为与指针算术相同,然后取消引用结果[expr.sub]/1。因此,只要两个版本确实是等效的,编译器通常应该能够同样优化这两个版本(我可能会考虑编译器未能优化一个但不是另一个性能错误)。话虽如此,请注意有很多细微之处,例如无符号算术的环绕行为,它可以使迭代索引不完全等同于迭代指针......

于 2019-12-30T20:10:18.187 回答