Cuda type punning - memcpy против UB union

В не-Cuda C++-коде в настоящее время предлагается практика, заключающаяся в том, что вместо объединения UB следует использовать штампование типов через memcpy. Несмотря на то, что это может вызывать проблемы с производительностью в сборках Debug, и тот факт, что мне пришлось несколько раз обращаться к корню UB для повышения производительности в сборках Release.

Какова рекомендуемая практика в Cuda? И будет ли он всегда вызывать memcpy() в сборках Debug?

2 ответа

Мне было любопытно об этом, и я заглянул в проводник компилятора https://godbolt.org/z/Cv5ozC Похоже, что cuda полностью выполняет memcpy. Общих рекомендаций нет, но мы можем кое-что узнать из стандарта C++20 с помощью std::bit_cast. Я думаю, что реализация std::bit_cast и изменение кишок для переинтерпретации приведений - лучший путь вперед. Это все еще неопределенное поведение, но вы компилируете для одной архитектуры, поэтому оно, по крайней мере, будет постоянно неопределенным. И это добавляет много защиты от идиотов, которую допускает неопределенный маршрут поведения.

template <class To, class From, class Res = typename std::enable_if<
    (sizeof(To) == sizeof(From)) && 
    (alignof(To) == alignof(From)) &&
    std::is_trivially_copyable<From>::value &&
    std::is_trivially_copyable<To>::value,
    To>::type>
__device__ Res& bit_cast(From& src) noexcept {
    return *reinterpret_cast<To*>(&src);
}

По-прежнему нет хорошего способа привести float[4] к float4, потому что система типов не может представить, что указатель на начало массива удовлетворяет требованиям выравнивания float4.

Если вам нужна дополнительная информация, я разобрался с этим, посмотрев доклад на CPPCon2019: https://www.youtube.com/watch?v=_qzMpk-22cc

Если вы сначала загрузите src в регистры, затем memcpy опущено, поэтому я думаю, что подход memcpy по-прежнему является предпочтительным способом избежать UB.

      template <class To, class From>
__device__  To bit_cast(From& src) noexcept {
    To tgt;
    From staged = src;
    memcpy(&tgt, &staged, sizeof(To));
    return tgt;
}

Модифицированная версия примера @ esdanol, которая показывает тот же сгенерированный код: https://cuda.godbolt.org/z/4f9n1ndEW

Другие вопросы по тегам