为什么在使用 Clang 3.9 时返回复制的 Matrix3d 的元素会导致输出不正确?

Why does returning an element of a copied Matrix3d result in incorrect output when using Clang 3.9?

在 Clang 3.9 上使用 -O2 编译以下示例会导致在 main 中调用 returning 垃圾 (1.9038e+185):

代码

double reproFunction(const Eigen::Matrix3d& R_in)
{
  const Eigen::Matrix3d R = R_in;

  Eigen::Matrix3d Q = R.cwiseAbs();

  if(R(1,2) < 2) {
    Eigen::Vector3d n{0, 1, R(1, 2)};
    double s2 = R(1,2);
    s2 /= n.norm();
  }
  return R(1, 2);
}

int main() {
  Eigen::Matrix3d R;
  R = Eigen::Matrix3d::Zero(3,3); 

  // This fails - reproFunction(R) returns 0
  R(1, 2) = 0.7;
  double R12 = reproFunction(R);
  bool are_they_equal = (R12 == R(1,2));
  std::cout << "R12 == R(1,2): " << are_they_equal << std::endl;
  std::cout << "R12: " << R12 << std::endl;
  std::cout << "R(1, 2): " << R(1, 2) << std::endl;
}

输出

R12 == R(1,2): 0
R12: 1.9036e+185
R(1, 2): 0.7

reproFunction,通过 R_in 的赋值初始化 R 是 const)。它 returns R(1, 2)。在赋值和return之间,reproFunction在几个操作中使用了R,但是其中none应该可以改变R。删除任何这些操作都会导致 reproFunction return 得到正确的值。

以下任何一种情况都不会出现此行为:

现在的问题是:这种行为是由于我在上面的代码中遗漏的错误、Eigen 3.3.3 中的错误还是 Clang 3.9 中的错误造成的?

可以在 https://github.com/avalenzu/eigen-clang-weirdness.

找到独立的复制示例

我可以用 clang 3.9 重现这个,但不能用 clang 3.8。我将 Eigen 方面的问题一分为二 this commit from 2016-05-24 21:54:

Bug 256: enable vectorization with unaligned loads/stores. This concerns all architectures and all sizes. This new behavior can be disabled by defining EIGEN_UNALIGNED_VECTORIZE=0

该提交启用了对未对齐数据的矢量化操作。

我仍然认为,这是 clang 中的一个错误,但您可以通过使用

进行编译来解决它
-D EIGEN_UNALIGNED_VECTORIZE=0

此外,如果检测到 clang 3.9 作为编译器,Eigen 可以 'fixed' 通过自动禁用此功能。