使用Clang 3.9时,为什么返回复制的Matrix3d元素导致输出错误?

时间:2017-08-02 19:05:25

标签: clang eigen eigen3

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

代码

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的分配初始化R_in,即const )。它返回R(1, 2)。在分配和返回之间,reproFunction在多个操作中使用R,但它们都不能更改R。删除任何这些操作会导致reproFunction返回正确的值。

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

  • 该程序使用Clang 3.5,Clang 4.0或g ++ - 5.4进行编译。
  • 优化级别为-O1或更低
  • 使用Eigen 3.2.10代替Eigen 3.3.3

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

可在https://github.com/avalenzu/eigen-clang-weirdness找到一个独立的复制示例。

1 个答案:

答案 0 :(得分:4)

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

  

错误256:使用未对齐的加载/存储启用矢量化。这涉及所有架构和所有规模。可以通过定义EIGEN_UNALIGNED_VECTORIZE = 0

来禁用此新行为

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

我仍然认为,这是clang中的一个错误,但您可以通过编译来解决它

-D EIGEN_UNALIGNED_VECTORIZE=0

此外,如果将clang 3.9检测为编译器,则可以通过自动禁用此功能来“固定”Eigen。