仅 64 位释放模式下的移位非法指令
bit-shift illegal instruction in 64-bit release mode only
我正在将可用的 PoissonRecon 代码 here 集成到我自己的网格操作代码中,但我无法在 x64 中编译集成代码,因为每一位都存在 "illegal instruction" 错误-泊松码八叉树生成中的移位指令。
我使用的是 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)<<OffsetShift1;
但这会导致 "illegal instruction" 错误。
请注意,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
returns 32 在调试器中)但实际上单步执行操作会导致 "illegal instruction" 错误。
由于程序在调试模式下运行正常,我尝试在发布模式下删除所有优化,但我仍然遇到同样的错误。我发现的唯一解决方法是用 pow()
替换所有移位操作,虽然可行,但似乎 bit
荒谬。
事实证明,重建代码附带的.sln文件是用AVX2设置的,我的机器不支持。
转到 Configuration Properties >> C/C++ >> Code Generation
并将 "Enable Enhanced Instruction Set" 设置为 AVX 解决了这个问题。
汇编代码现在显示 "SHL" 而不是 "SHLX," 所以 "illegal instruction" 是实际的 SHLX 命令不可用,不是进入 SHLX 的参数的问题。
我正在将可用的 PoissonRecon 代码 here 集成到我自己的网格操作代码中,但我无法在 x64 中编译集成代码,因为每一位都存在 "illegal instruction" 错误-泊松码八叉树生成中的移位指令。
我使用的是 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)<<OffsetShift1;
但这会导致 "illegal instruction" 错误。
请注意,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
returns 32 在调试器中)但实际上单步执行操作会导致 "illegal instruction" 错误。
由于程序在调试模式下运行正常,我尝试在发布模式下删除所有优化,但我仍然遇到同样的错误。我发现的唯一解决方法是用 pow()
替换所有移位操作,虽然可行,但似乎 bit
荒谬。
事实证明,重建代码附带的.sln文件是用AVX2设置的,我的机器不支持。
转到 Configuration Properties >> C/C++ >> Code Generation
并将 "Enable Enhanced Instruction Set" 设置为 AVX 解决了这个问题。
汇编代码现在显示 "SHL" 而不是 "SHLX," 所以 "illegal instruction" 是实际的 SHLX 命令不可用,不是进入 SHLX 的参数的问题。