Нарушаю ли я строгие правила сглаживания?


Я хотел бы знать, нарушаю ли я строгие правила псевдонимирования с этим фрагментом. (Я думаю, что да, поскольку это разыменование каламбурного указателя, однако это делается в одном выражении и / Wall не плачет.)

inline double plop() const // member function
{
    __m128d x = _mm_load_pd(v);
    ... // some stuff
    return *(reinterpret_cast<double*>(&x)); // return the lower double in xmm reg referred to by x.
}

Если да, то каков обходной путь? Использование различных представлений одновременно становится жестким, как только вы хотите уважать спецификацию.

Спасибо за ваши ответы, я теряю хорошее настроение, пытаясь найти решение.

Ответы, которые не будут приняты и почему:

"use mm_store" -> оптимизатору не удается удалить его, если следующие инструкции требуют наличия регистра xmm, поэтому он генерирует нагрузку сразу после него. Магазин + загрузка за бесценок.

" use a union " - > нарушение правила сглаживания при использовании двух типов для одного и того же объекта. Если я правильно понял статью, написанную Тьяго Мацейрой.

4 12

4 ответа:

Существует только одна внутренняя функция, которая "извлекает" двойное значение нижнего порядка из регистра xmm:

double _mm_cvtsd_f64 (__m128d a)

Вы можете использовать его следующим образом:

return _mm_cvtsd_f64(x);
Существует некоторое противоречие между различными ссылками. MSDN говорит: This intrinsic does not map to any specific machine instruction. В то время как Intel intrinsic guide упоминает movsd инструкцию. В последнем случае эта дополнительная инструкция легко устраняется оптимизатором. По крайней мере, gcc 4.8.1 с флагом -O2 генерирует код без дополнительной инструкции.

Выделенный жирным шрифтом пункт должен, как мне кажется, разрешить ваш бросок здесь, поскольку мы можем рассматривать __m128d как совокупность четырех double союзов в полном регистре. Что касается строгого псевдонимирования, компилятор всегда был очень примирительным вокруг объединения, где в начале координат считалось допустимым только приведение к (char*).

§3.10: Если программа пытается получить доступ к сохраненному значению объекта через glvalue, отличное от одного из следующих типов поведения неопределенный (намерение этого список предназначен для указания тех обстоятельств, при которых объект может быть или не может иметь псевдоним):

  • динамический тип объекта,
  • CV-квалифицированная версия динамического типа объекта,
  • тип, аналогичный (как определено в 4.4) динамическому типу объекта,
  • тип, который является подписанным или беззнаковым типом, соответствующим динамическому типу объекта,
  • тип, который является подписанным или неподписанным типом, соответствующим CV-квалифицированной версии динамический тип объекта,
  • агрегатный или объединительный тип, включающий один из вышеупомянутых типов среди своих элементов или элементов нестатических данных (включая, рекурсивно, элемент или нестатический элемент данных субагрегата или сдержанный Союз),
  • тип, который является (возможно, CV-квалифицированным) базовым типом класса динамического типа объекта,
  • тип char или unsigned char.

Да, я думаю, что это нарушает строгое сглаживание. Однако на практике это, как правило, хорошо.
(Я в основном пишу это как ответ, потому что это трудно описать хорошо в комментарии)

Но вместо этого вы могли бы сделать что-то вроде этого:

inline double plop() const // member function
{
    __m128d x = _mm_load_pd(v);
    ... // some stuff

    union {
        unsigned long long i; // 64-bit int
        double             d; // 64-bit double
    };

    i = _mm_cvtsi128_si64(_mm_castpd_si128(x)); // _mm_castpd_si128 to interpret the register as an int vector, _mm_cvtsi128_si64 to extract the lowest 64-bits

    return d; // use the union to return the value as a double without breaking strict aliasing
}

А как насчет return x.m128d_f64[0];?