【问题标题】:bit-shift illegal instruction in 64-bit release mode only仅在 64 位释放模式下移位非法指令
【发布时间】:2017-02-14 17:13:54
【问题描述】:

我正在将可用的 PoissonRecon 代码 here 集成到我自己的网格操作代码中,但由于 Poisson 中的每个位移指令中的“非法指令”错误,我无法在 x64 中编译集成代码代码的八叉树生成。

我使用的是 Visual Studio 2015,我的问题仅在 x64 中编译且仅在发布模式下才会出现(即,它适用于 x86 调试和发布以及 x64 调试)。

作为移位指令之一的示例,在 Octree.inl 的顶部定义了以下内容:

template< class NodeData > const int OctNode< NodeData >::DepthShift=5;
template< class NodeData > const int OctNode< NodeData >::OffsetShift = ( sizeof(long long)*8 - DepthShift ) / 3;
template< class NodeData > const int OctNode< NodeData >::DepthMask=(1<<DepthShift)-1; // This variable is correct
template< class NodeData > const int OctNode< NodeData >::OffsetMask=(1<<OffsetShift)-1; // This variable is also correct
template< class NodeData > const int OctNode< NodeData >::OffsetShift1=DepthShift;
template< class NodeData > const int OctNode< NodeData >::OffsetShift2=OffsetShift1+OffsetShift;
template< class NodeData > const int OctNode< NodeData >::OffsetShift3=OffsetShift2+OffsetShift;

这些变量用在以下函数中:

template< class NodeData >
inline unsigned long long OctNode< NodeData >::Index( int depth , const int offset[3] )
{
    unsigned long long idx=0;
    idx |= ( ( (unsigned long long)(depth    ) ) & DepthMask  );
    idx |= ( ( (unsigned long long)(offset[0]) ) & OffsetMask ) << OffsetShift1;
    idx |= ( ( (unsigned long long)(offset[1]) ) & OffsetMask ) << OffsetShift2;
    idx |= ( ( (unsigned long long)(offset[2]) ) & OffsetMask ) << OffsetShift3;
    return idx;
}

这个函数在行中断

idx |= ( ( (unsigned long long)(offset[0]) ) & OffsetMask ) << OffsetShift1;

我进一步分解发现问题在于位移本身,即(var)&lt;&lt;OffsetShift1;,但这会导致“非法指令”错误。

请注意,OffsetShift1 只是“5”,因此这相当于(var)&lt;&lt;5;,它确实可以按预期工作。

一种可能的解决方法是在顶部简单地 #define 所有这些变量(这确实解决了问题),但这并不能解决其他位移问题,例如:

void _startAndWidth( const TreeOctNode* node , Point3D< Real >& start , Real& width ) const
    {
        LocalDepth d ; LocalOffset off;
        _localDepthAndOffset( node , d , off );
        if (d >= 0) width = Real(1.0 / (1 << d));
        else width = Real( 1.0 * (1<<(-d)) );
        for( int dd=0 ; dd<DIMENSION ; dd++ ) start[dd] = Real( off[dd] ) * width;
    }

我已经尝试static_cast&lt;long long&gt; 一切,但这不是溢出问题。更奇怪的是,如果我在移位之前中断(在发布模式下)然后突出显示操作,调试器会告诉我正确的结果(例如,_startAndWidth 中的d = 5,所以1 &lt;&lt; d 在调试器),但实际上单步执行操作会导致“非法指令”错误。

由于程序在调试模式下正常工作,我尝试在发布模式下删除所有优化,但仍然遇到相同的错误。我发现的唯一解决方法是用pow() 替换所有位移操作,虽然这样可行,但bit 似乎很荒谬。

【问题讨论】:

  • 欢迎来到 Stack Overflow。请花时间阅读The Tour 并参考Help Center 中的材料,您可以在这里询问什么以及如何询问。
  • 可能是无声代码生成错误,从您描述的症状来看,这听起来很合理。我建议您继续升级到 MSVC14.1 和 Visual Studio 2017 RC 或 MSVC14 和 Visual Studio 2015。请注意,Visual Studio 2017 将很快发布,从 RC 升级不应该是一件麻烦事。很棒的新安装程序真的值得,它速度更快,并且包含更好的编译器。
  • 我刚刚检查并意识到我说错了。我使用的是 MSVC 2015,而不是 2010。我已经编辑了帖子。
  • 此时我将逐步完成程序集。
  • @A.Comer:TBH,我不明白你如何获得积分常数表达式的汇编。即使在调试模式下,编译器本身也应该对此进行全面评估。这是不可避免的,因为OctNode&lt; NodeData &gt;::DepthMask 必须可以用作例如char buf[OctNode&lt; NodeData &gt;::DepthMask] 即使在调试模式下也需要编译时常量。

标签: c++ bit-shift illegal-instruction


【解决方案1】:

事实证明,重构代码附带的 .sln 文件是用 AVX2 设置的,我的机器不支持它。

转到Configuration Properties &gt;&gt; C/C++ &gt;&gt; Code Generation 并将“启用增强指令集”设置为 AVX 解决了该问题。

汇编代码现在显示“SHL”而不是“SHLX”,因此“非法指令”是实际的 SHLX 命令不可用,而不是进入 SHLX 的参数有问题。

【讨论】:

  • 您通过回答您自己的问题为我节省了大量令人头疼的问题。欣赏你!
猜你喜欢
  • 2015-01-09
  • 1970-01-01
  • 2012-06-12
  • 2013-12-05
  • 2012-07-02
  • 1970-01-01
  • 2017-09-12
  • 2021-04-13
  • 2010-11-08
相关资源
最近更新 更多