Home > front end >  Setting maximum static alignment in Eigen from CMake
Setting maximum static alignment in Eigen from CMake

Time:11-14

I'm working in a general CMake script that provides a grateful fallback strategy regarding activation of vectorization capabilities while compiling a project with Eigen.

Using Eigen 3.4 with C 17 standard and compiled with an updated compiler (ex. gcc > 7), there is no code requirements for the developer to comply regarding static objects alignment. No more EIGEN_MAKE_ALIGNED_OPERATOR_NEW macro and explicit alignment in STL containers (and we cheered hard in our lab for this!).

But we have a diverse landscape of projects with diverse compilation setups. We would like to write our code without worrying about alignment while a CMake script detects the architecture compilation capabilities and deactivates Eigen's unsafe vectorization features for the architecture (even when this means breaking abi-compatibility).

Is there a way to retrieve the architecture max alignment size at CMake level, to properly set the EIGEN_MAX_STATIC_ALIGN_BYTES directive??

Maybe a bash script that retrieves the max_align_t? https://en.cppreference.com/w/cpp/types/max_align_t

CodePudding user response:

You can use the source code from https://en.cppreference.com/w/cpp/types/max_align_t with try_run. Note that cross compilation requires additional considerations; refer to the documentation of try_run for more on this.

cmake_tests/alignment_check.cpp:

This is the source from https://en.cppreference.com/w/cpp/types/max_align_t

#include <iostream>
#include <cstddef>
int main()
{
    std::cout << alignof(std::max_align_t) << '\n';
}

CMakeLists.txt

...

try_run(MY_MAXALIGN_RUN_RESULT MY_MAXALIGN_COMPILE_SUCCESS
        ${CMAKE_CURRENT_BINARY_DIR} "${CMAKE_CURRENT_SOURCE_DIR}/cmake_tests/alignment_check.cpp"
        COMPILE_OUTPUT_VARIABLE MY_MAXALIGN_COMPILE_OUTPUT
        RUN_OUTPUT_VARIABLE MY_MAXALIGN_RUN_OUTPUT)

if (NOT MY_MAXALIGN_COMPILE_SUCCESS)
    message(FATAL_ERROR "Error during compilation of ${CMAKE_CURRENT_SOURCE_DIR}/cmake_tests/alignment_check.cpp :\n\n${MY_MAXALIGN_COMPILE_OUTPUT}")
endif()

if (MY_MAXALIGN_RUN_RESULT)
    message(FATAL_ERROR "Error running logic in ${CMAKE_CURRENT_SOURCE_DIR}/cmake_tests/alignment_check.cpp :\n\n${MY_MAXALIGN_RUN_OUTPUT}")
endif()

string(STRIP ${MY_MAXALIGN_RUN_OUTPUT} MY_MAXALIGN)

message(STATUS "MY_MAXALIGN = \"${MY_MAXALIGN}\"")

...

The content of the MY_MAXALIGN cmake variable can be used to e.g. specify a compile definition.

CMake output

...
MY_MAXALIGN = "8"
...

CodePudding user response:

While fabian idea is great it has one huge drawback - you have to run the executable. Not always can you run the executable. The goal is to get the value of alignof(std::max_align_t) without running anything, only with compilation. And we can do it.

As always, learn from the best. From CMake modules inspect files: CMakeCompilerABI.h CMakeCCompilerABI.c CMakeDetermineCompilerABI.cmake. Note how CMakeCompilerABI.h embeds the information into executable, without actually printing it. Take the same approuch. Your source file would look like the following:

// determineAlingofMax.cpp
#include <cstddef>
#define VAL  alignof(std::max_align_t)
const char info_alingof_max_align_t[] = {
    'I', 'N', 'F', 'O', ':', 'a', 'l', 'i', 'n', 'g', 'o', 'f', 'm', 'a', 'x'
    '[', '0'   ((VAL / 10) % 10), '0'   (VAL % 10), ']', '\0',
};
int main(int argc, char *argv[]) {
   return  info_alingof_max_align_t[argc];
}

Note how we calculated the alignof and converted it to a string at compile time.

Now we have to compile it to an object file - we do not need to run any executable. So we take a look at CMakeDetermineCompilerABI.cmake and write similar:

set(BIN "${CMAKE_BINARY_DIR}/determineAlingofMax.bin"
try_compile(ALIGNMAX_COMPILED
  ${CMAKE_BINARY_DIR}
  SOURCES /path/to/the/determineAlingofMax.cpp
  CMAKE_FLAGS ${CMAKE_FLAGS}
              # Ignore unused flags
              "--no-warn-unused-cli"
  COMPILE_DEFINITIONS ${COMPILE_DEFINITIONS}
  COPY_FILE "${BIN}"
  COPY_FILE_ERROR copy_error
  OUTPUT_VARIABLE OUTPUT
)
if (ALIGNMAX_COMPILED AND not copy_error)
   file(STRINGS "${BIN}" data REGEX "INFO:alingofmax\\[[^]]*\\]")
   if (data MATCHES "INFO:alingofmax\\[0*([^]]*)\\]")
       set(ALINGOFMAX "${CMAKE_MATCH_1}" CACHE INTERNAL "")
   endif()
endif()
if (NOT ALINGOFMAX) 
   message(FATAL_ERROR some error here)
endif()
# and finally, maybe option()
set(EIGEN_MAX_STATIC_ALIGN_BYTES ${ALINGOFMAX})

Note how the binary is not executed - only compiled. The string INFO:alignofmax has to be only unique enough, so it does not come anywhere in the executable - I prefer to use UUIDs lately.

  • Related