仅64位释放模式下的位移非法指令

时间:2017-02-14 17:13:55

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

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

我正在使用Visual Studio 2015,只有在x64中编译时才会出现问题,并且仅在处于发布模式时(即,它在x86调试和发布以及x64调试中工作)。

作为其中一个bitshift指令的示例,以下内容在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)<<OffsetShift1;,但这会导致“非法指令”错误。

请注意,OffsetShift1只是“5”,所以这相当于(var)<<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<long long>一切,但这不是溢出问题。更奇怪的是,如果我在位移前(在释放模式下)中断然后突出显示操作,调试器会告诉我正确的结果(例如,d = 5中的_startAndWidth,所以{{1在调试器中返回32)但实际上单步执行操作会导致“非法指令”错误。

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

1 个答案:

答案 0 :(得分:1)

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

转到Configuration Properties >> C/C++ >> Code Generation并为AVX设置“启用增强指令集”解决了这个问题。

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