Skip to content

Type punning in block_ldlt_internal::find_maxloc is undefined behaviour #154

@mjacobse

Description

@mjacobse

A union is introduced in

// Define a union that lets us abuse T to store ints and still use
// avx blend.
union intT {
int i;
T d;
};
which is used repeatedly to store int to .i and "read it as double" from .d, for example:
intT imax;
imax.i = std::numeric_limits<int>::max();
SimdVecT bestr(imax.d);

This is commonly done for type punning and I believe this was allowed in C and happens to work on most platforms even in C++. But it is undefined behaviour in C++ (https://www.youtube.com/watch?v=_qzMpk-22cc&t=570s). In general, the modern way to do this in C++20 is std::bit_cast. Probably wanting to support earlier standards, one could write their own version with that possible implementation using std::memcpy.

In this specific case, it seems strange to me that any type punning is done at all though. If we have AVX, couldn't we just load the int values into the AVX register using _mm256_set1_epi32, do the operations and then extract them with _mm256_extract_epi32? Otherwise without AVX, SimdVec just turns into a plain double, which makes its use for the row and column indices in block_ldlt_internal::find_maxloc very akward. For no real reason the int values are basically type-punned to unnecessarily larger double type as which swaps are done, only to then be punned back into int.

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions