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

bit-shift illegal instruction in 64-bit release mode only

本文关键字:位非 非法 指令 64位 释放 模式 仅在      更新时间:2023-10-16

我正在将此处可用的PoissonCon代码集成到我自己的网格操作代码中,但我无法在x64中编译集成代码,因为Poisson代码的八叉树生成中的每个位偏移指令中都存在"非法指令"错误。

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

作为其中一个位移位指令的示例,在Octre.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>所有内容,但这不是溢出问题。更奇怪的是,如果我在位移位之前中断(在释放模式下),然后突出显示该操作,则调试器告诉我正确的结果(例如,_startAndWidth中的d = 5,因此1 << d在调试器中返回32),但实际上跨接该操作会导致"非法指令"错误。

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

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

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

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