Я интегрирую доступный код PoissonRecon Вот в мой собственный код манипулирования сеткой, но я не смог скомпилировать интегрированный код в 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)<<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 << d
возвращает 32 в отладчике), но на самом деле перешагнуть через операцию вызывает ошибку «недопустимая инструкция».
Так как программа работает правильно в режиме отладки, я попытался удалить все оптимизации в режиме выпуска, но я все еще получаю ту же ошибку. Единственный обходной путь, который я нашел, — это заменить все операции сдвига битов pow()
вместо этого, и пока это работает, кажется, bit
смешной.
Оказывается, файл .sln, который поставляется с кодом восстановления, был установлен с помощью AVX2, который не был поддержан на моем компьютере.
собирается Configuration Properties >> C/C++ >> Code Generation
и установка «Включить расширенный набор инструкций» в AVX решила проблему.
Код сборки теперь показывает «SHL» вместо «SHLX», поэтому «недопустимая инструкция» заключалась в том, что фактическая команда SHLX была недоступна, а не проблема с параметрами, входящими в SHLX.
Других решений пока нет …