I am integrating the PoissonRecon code available here into my own mesh manipulation code, but I've been unable to compile the integrated code in x64 because of an "illegal instruction" error in every bit-shift instruction in the Poisson code's octree generation.
I'm using Visual Studio 2015 and my issue occurs only when compiled in x64 and only when in release mode (i.e., it works in x86 debug and release as well as x64 debug).
As an example of one of the bitshift instructions, the following is defined at the top of 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;
And these variables are used in the following function:
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;
}
This function breaks at the line
idx |= ( ( (unsigned long long)(offset[0]) ) & OffsetMask ) << OffsetShift1;
which I've split down further and found that the issue is the bit-shift itself, i.e. (var)<<OffsetShift1;
but this causes an "illegal instruction" error.
Note that OffsetShift1 is simply "5", so this is equivalent to (var)<<5;
which does work as expected.
A possible workaround is to simply #define
all of these variables at the top (which does fix the issue), but this does not solve other bit-shift issues such as the following:
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;
}
I've tried to static_cast<long long>
everything, but it's not an overflow issue. Even stranger, if I break before a bit-shift (while in release mode) and then highlight the operation, the debugger tells me the correct result (for example, d = 5
in _startAndWidth
, so 1 << d
returns 32 in the debugger) but actually stepping over the operation causes an "illegal instruction" error.
Since the program works correctly in debug mode, I've tried removing all optimizations in release mode, but I still get the same error. The only workaround I've found is to replace all bit-shift operations with pow()
instead, and while that works, it seems a bit
ridiculous.
As it turns out, the .sln file that came with the reconstruction code was set with AVX2, which was unsupported on my machine.
going to Configuration Properties >> C/C++ >> Code Generation
and setting "Enable Enhanced Instruction Set" to AVX solved the issue.
The assembly code now shows "SHL" instead of "SHLX," so the "illegal instruction" was the actual SHLX command not being available, not an issue with the parameters going into SHLX.