Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
145 changes: 128 additions & 17 deletions cmake/compiler_flags/CXXFlags.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,7 @@
# - ``CMAKE_CXX_FLAGS_<CONFIG>`` are build-type specific compiler flags.
# The defaults are compiler-dependent: have a look at the ``GNU.CXX.cmake``,
# ``Clang.CXX.cmake``, and ``Intel.CXX.cmake`` files.
# - ``ARCH_FLAG`` is the architecture-dependent optimization flag, *e.g.*
# vectorization. Default is empty.
# - ``monoprop_CXX_FLAGS`` are monoprop-specific flags to be used for all builds.
# - ``monoprop_CXX_FLAGS`` are monorop-specific flags to be used for all builds.
# The defaults are compiler-dependent: have a look at the ``GNU.CXX.cmake``,
# ``Clang.CXX.cmake``, and ``Intel.CXX.cmake`` files.
# - ``EXTRA_CXXFLAGS`` useful if you need to append certain flags to the full
Expand All @@ -26,7 +24,7 @@
#
# Variables used::
#
# monoprop_ENABLE_ARCH_FLAGS
# monoprop_ENABLE_MULTIVERSIONING
# EXTRA_CXXFLAGS
#
# Variables modified::
Expand All @@ -37,11 +35,7 @@
#
# CXXFLAGS

option(
monoprop_ENABLE_ARCH_FLAGS
"Enable architecture-specific compiler flags"
ON
)
option_with_print(monoprop_ENABLE_MULTIVERSIONING "Enable function multiversioning" ON)

# code needs C++23 at least
set(CMAKE_CXX_STANDARD 23)
Expand All @@ -61,19 +55,136 @@ set(CMAKE_POSITION_INDEPENDENT_CODE TRUE)
set(CMAKE_CXX_VISIBILITY_PRESET "hidden")
set(CMAKE_VISIBILITY_INLINES_HIDDEN TRUE)

set(ARCH_FLAG "")
if(monoprop_ENABLE_ARCH_FLAGS AND NOT CMAKE_BUILD_TYPE STREQUAL "Debug")
if(CMAKE_CXX_COMPILER_ID MATCHES GNU)
set(ARCH_FLAG "-march=native")
# Query the machine-dependent flags for a given -march value and store the
# cleaned, space-separated string in the variable named by OUTPUT_VARIABLE. A
# MARCH of "default" queries the default target (no -march flag).
#
# Usage:
# _monoprop_query_machine_flags(MARCH <arch> OUTPUT_VARIABLE <var>)
function(_monoprop_query_machine_flags)
set(
_one_value_args
MARCH
OUTPUT_VARIABLE
)
cmake_parse_arguments(PARSE_ARGV 0 _arg "" "${_one_value_args}" "")

if(NOT _arg_OUTPUT_VARIABLE)
message(
FATAL_ERROR
"_monoprop_query_machine_flags: OUTPUT_VARIABLE is required"
)
endif()
if(NOT _arg_MARCH)
message(FATAL_ERROR "_monoprop_query_machine_flags: MARCH is required")
endif()

if(_arg_MARCH STREQUAL "default")
set(_march_args "")
else()
set(_march_args "-march=${_arg_MARCH}")
endif()
if(CMAKE_CXX_COMPILER_ID MATCHES Clang)
set(ARCH_FLAG "-march=native")
execute_process(
COMMAND
${CMAKE_CXX_COMPILER} ${_march_args} -Q --help=target
COMMAND
${Python_EXECUTABLE} ${_machine_flags_cleaner}
OUTPUT_VARIABLE _flags
OUTPUT_STRIP_TRAILING_WHITESPACE
RESULT_VARIABLE _result
)
if(NOT _result EQUAL 0)
message(
FATAL_ERROR
"Failed to query machine-dependent flags for '${_arg_MARCH}' (exit code ${_result})"
)
endif()
if(CMAKE_CXX_COMPILER_ID MATCHES Intel)
set(ARCH_FLAG "-xHost")
set(${_arg_OUTPUT_VARIABLE} "${_flags}" PARENT_SCOPE)
endfunction()

# Report the machine-dependent flags GCC uses for each target variant by
# querying `gcc -march=<arch> -Q --help=target` and cleaning the output with
# tools/gcc-target-help-clean.py.
find_package(Python COMPONENTS Interpreter REQUIRED QUIET)
set(
_machine_flags_cleaner
"${PROJECT_SOURCE_DIR}/tools/gcc-target-help-clean.py"
)

set(monoprop_MACHINE_FLAGS_DEFAULT "")
_monoprop_query_machine_flags(MARCH default OUTPUT_VARIABLE monoprop_MACHINE_FLAGS_DEFAULT)

set(monoprop_TARGET_CLONES "")
set(monoprop_VARIANTS "")
set(monoprop_MACHINE_FLAGS_VARIANTS "")
# function multiversioning is only enabled in release builds on x86_64 architectures
if(
monoprop_ENABLE_MULTIVERSIONING
AND
NOT
CMAKE_BUILD_TYPE
STREQUAL
"Debug"
AND
CMAKE_HOST_SYSTEM_PROCESSOR
MATCHES
"x86_64"
)
if(NOT CMAKE_CXX_COMPILER_ID MATCHES GNU)
message(
FATAL_ERROR
"Multiversioning is only supported with GNU compilers. Please disable monoprop_ENABLE_MULTIVERSIONING or use a GNU compiler."
)
else()
list(
APPEND _targets
"x86-64-v2"
"x86-64-v3"
"x86-64-v4"
"icelake-server"
"sapphirerapids"
"graniterapids"
"znver3"
"znver4"
"znver5"
)

set(_targets_arch "")
foreach(_target IN LISTS _targets)
list(APPEND _targets_arch "\"arch=${_target}\"")
endforeach()
list(JOIN _targets_arch ", " TARGETS)

message(STATUS "Function multiversioning targets: \"default\", ${TARGETS}")
set(
monoprop_TARGET_CLONES
"[[using gnu: flatten, target_clones(\"default\", ${TARGETS})]]"
)
set(_variants "")
foreach(_target IN LISTS _targets)
string(APPEND _variants "monoprop_FMV_VARIANT(\"${_target}\")\n")
endforeach()
set(monoprop_VARIANTS "${_variants}")

set(_machine_flags_variants "")
foreach(_target IN LISTS _targets)
_monoprop_query_machine_flags(MARCH "${_target}" OUTPUT_VARIABLE _target_machine_flags)
string(
APPEND _machine_flags_variants
"monoprop_FMV_MACHINE_FLAGS(\"${_target}\", \"${_target_machine_flags}\")\n"
)
endforeach()
set(monoprop_MACHINE_FLAGS_VARIANTS "${_machine_flags_variants}")
endif()
endif()

# generate a header file with a macro containing (or not) the function multiversioning attribute
configure_file(
${PROJECT_SOURCE_DIR}/include/monoprop/FunctionMultiversioning.h.in
${PROJECT_BINARY_DIR}/include/monoprop/FunctionMultiversioning.h
@ONLY
)

set(monoprop_CXX_FLAGS "")
include(${CMAKE_CURRENT_LIST_DIR}/GNU.CXX.cmake)
include(${CMAKE_CURRENT_LIST_DIR}/Intel.CXX.cmake)
Expand Down
75 changes: 75 additions & 0 deletions include/monoprop/FunctionMultiversioning.h.in
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
// Copyright 2026 Algorithmiq
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#pragma once

#include <string_view>

/**
* @brief Attribute used to enable function multiversioning target clones.
*
* This macro is configured at build time and expands to the compiler-specific
* attribute declaration.
*/
// clang-format off
#define monoprop_TARGET_CLONES @monoprop_TARGET_CLONES@
// clang-format on

/**
* @brief Declares a compile-time function that reports the active FMV variant.
*
* Expands to a `consteval` function named `variant()` with a GNU
* `target("arch=...")` attribute bound to the provided architecture string.
*
* @param archstr Architecture suffix used in `arch=<archstr>`.
*/
#define monoprop_FMV_VARIANT(archstr) \
[[using gnu: target("arch=" archstr)]] consteval auto variant() noexcept -> std::string_view { \
return "arch=" archstr; \
}

/**
* @brief Declares a compile-time function that reports the machine-dependent
* flags GCC applies for the given FMV variant.
*
* Expands to a `consteval` function named `machine_flags()` with a GNU
* `target("arch=...")` attribute bound to the provided architecture string. The
* returned value is the cleaned, space-separated list of machine flags GCC uses
* for that architecture, as reported by `gcc -march=<archstr> -Q --help=target`.
*
* @param archstr Architecture suffix used in `arch=<archstr>`.
* @param flagsstr Machine-dependent flags reported for the architecture.
*/
#define monoprop_FMV_MACHINE_FLAGS(archstr, flagsstr) \
[[using gnu: target("arch=" archstr)]] consteval auto machine_flags() noexcept -> std::string_view { \
return flagsstr; \
}

namespace monoprop {
[[using gnu: target("default")]] consteval auto variant() noexcept -> std::string_view {
return "default";
}

// clang-format off
@monoprop_VARIANTS@
// clang-format on

[[using gnu: target("default")]] consteval auto machine_flags() noexcept -> std::string_view {
return "@monoprop_MACHINE_FLAGS_DEFAULT@";
}

// clang-format off
@monoprop_MACHINE_FLAGS_VARIANTS@
// clang-format on
} // namespace monoprop
4 changes: 3 additions & 1 deletion include/monoprop/Info.h.in
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@
#include <string>
#include <string_view>

#include "monoprop/FunctionMultiversioning.h"

namespace monoprop {
static constexpr auto build_type() noexcept -> std::string_view {
return "@CMAKE_BUILD_TYPE@";
Expand All @@ -27,7 +29,7 @@ static auto compiler_flags() noexcept -> std::map<std::string, std::string> {
return {
{"from-environment", "@CMAKE_CXX_FLAGS@"},
{"build-type-flags", "@_cmake_build_type_specific_flags@"},
{"vectorization", "@ARCH_FLAG@"},
{"machine-flags", std::string(machine_flags())},
{"project-defaults", "@CMAKE_CXX23_STANDARD_COMPILE_OPTION@ @monoprop_CXX_FLAGS@"},
{"user-appended", "@EXTRA_CXXFLAGS@"},
};
Expand Down
2 changes: 2 additions & 0 deletions src/monoprop/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
MAX_NUM_MODES,
__build_type__,
__compiler_flags__,
__variant__,
antihermitian_generator_correction,
has_mpi,
is_antihermitian,
Expand Down Expand Up @@ -57,6 +58,7 @@
"PauliPropagator",
"__build_type__",
"__compiler_flags__",
"__variant__",
"__version__",
"antihermitian_generator_correction",
"expand_monomials",
Expand Down
8 changes: 5 additions & 3 deletions src/monoprop/bindings/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -104,9 +104,11 @@ configure_file(
)

nanobind_add_module(_core
STABLE_ABI # Perform a stable ABI build
NB_STATIC # Compile the core nanobind library as a static library
NOMINSIZE # Don’t perform optimizations to minimize binary size
STABLE_ABI # perform a stable ABI build
NB_SUPPRESS_WARNINGS # suppress warnings from nanobind and Python headers
NB_STATIC # compile the core nanobind library as a static library
NOMINSIZE # don’t perform optimizations to minimize binary size
LTO # perform link-time optimization
${CMAKE_CURRENT_BINARY_DIR}/bindings.cpp
${_bind_cpps} # List of generated binders
)
Expand Down
15 changes: 9 additions & 6 deletions src/monoprop/bindings/bindings.cpp.in
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
#endif

#include "generated/bind.h"
#include "monoprop/FunctionMultiversioning.h"
#include "monoprop/Info.h"
#include "monoprop/MPFunctions.h"
#include "monoprop/detail/mpi/MPICompat.h"
Expand Down Expand Up @@ -47,10 +48,10 @@ auto get_mpi_comm(nb::object obj) -> MPI_Comm {

auto cutoff_type_str_2_enum(const std::string &cutoff_type) -> CutoffType {
if (cutoff_type == "length") {
return monoprop::CutoffType::Length;
return CutoffType::Length;
}
else if (cutoff_type == "support") {
return monoprop::CutoffType::Support;
return CutoffType::Support;
}
else {
throw std::invalid_argument(
Expand All @@ -61,9 +62,9 @@ auto cutoff_type_str_2_enum(const std::string &cutoff_type) -> CutoffType {

auto cutoff_type_enum_2_str(CutoffType cutoff_type) -> std::string {
switch (cutoff_type) {
case monoprop::CutoffType::Length:
case CutoffType::Length:
return "length";
case monoprop::CutoffType::Support:
case CutoffType::Support:
return "support";
default:
throw std::invalid_argument("Unknown CutoffType enum value");
Expand Down Expand Up @@ -112,18 +113,20 @@ NB_MODULE(_core, m) {
// clang-format on
m.attr("__build_type__") = std::string(build_type());
m.attr("__compiler_flags__") = compiler_flags();
m.attr("__variant__") = std::string(variant());

#ifdef monoprop_ENABLE_MPI
m.attr("has_mpi") = true;
#else
m.attr("has_mpi") = false;
#endif

m.def("is_antihermitian",
&monoprop::is_antihermitian,
&is_antihermitian,
"indices"_a,
"Check if a Majorana operator (represented by indices) is antihermitian.");
m.def("antihermitian_generator_correction",
&monoprop::antihermitian_generator_correction,
&antihermitian_generator_correction,
"indices"_a,
"Get the generator correction for a Majorana operator (represented by indices).");
// clang-format off
Expand Down
Loading
Loading