Skip to content

Commit

Permalink
Merge pull request #643 from basnijholt/apple-silicon
Browse files Browse the repository at this point in the history
Make qsimcirq Apple Silicon (M1, M2, ARM64) compatible and improve build scripts
  • Loading branch information
95-martin-orion authored Nov 29, 2023
2 parents b73b5bb + 34ca2a5 commit de65341
Show file tree
Hide file tree
Showing 14 changed files with 157 additions and 97 deletions.
8 changes: 6 additions & 2 deletions .github/workflows/release_wheels.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,14 @@ jobs:
fail-fast: false
matrix:
include:
- os: macos-12
- os: macos-12 # x86_64
name: mac
cibw:
build: "cp37* cp38* cp39* cp310* cp311*"
- os: macos-13-large # Apple Silicon
name: mac_arm64
cibw:
build: "cp37* cp38* cp39* cp310* cp311*"
- os: ubuntu-20.04
name: manylinux2014
cibw:
Expand All @@ -32,7 +36,7 @@ jobs:
CIBW_SKIP: "*musllinux*"
CIBW_ARCHS: "${{ matrix.cibw.arch || 'auto' }}"
CIBW_MANYLINUX_X86_64_IMAGE: "${{ matrix.cibw.manylinux_image }}"
CIBW_BEFORE_BUILD_MACOS: "brew install libomp llvm"
CIBW_BEFORE_BUILD_MACOS: "brew install libomp llvm && brew link --overwrite [email protected] && brew link --force libomp"
CIBW_REPAIR_WHEEL_COMMAND_MACOS: "delocate-listdeps {wheel} && delocate-wheel --verbose --require-archs {delocate_archs} -w {dest_dir} {wheel}"
# to install latest delocate package
CIBW_DEPENDENCY_VERSIONS: "latest"
Expand Down
8 changes: 6 additions & 2 deletions .github/workflows/testing_wheels.yml
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,14 @@ jobs:
fail-fast: false
matrix:
include:
- os: macos-12
- os: macos-12 # x86_64
name: mac
cibw:
build: "cp37* cp38* cp39* cp310* cp311*"
- os: macos-13-large # Apple Silicon
name: mac_arm64
cibw:
build: "cp37* cp38* cp39* cp310* cp311*"
- os: ubuntu-20.04
name: manylinux2014
cibw:
Expand All @@ -37,7 +41,7 @@ jobs:
CIBW_SKIP: "*musllinux*"
CIBW_ARCHS: "${{ matrix.cibw.arch || 'auto' }}"
CIBW_MANYLINUX_X86_64_IMAGE: "${{ matrix.cibw.manylinux_image }}"
CIBW_BEFORE_BUILD_MACOS: "brew install libomp llvm"
CIBW_BEFORE_BUILD_MACOS: "brew install libomp llvm && brew link --overwrite [email protected] && brew link --force libomp"
CIBW_REPAIR_WHEEL_COMMAND_MACOS: "delocate-listdeps {wheel} && delocate-wheel --verbose --require-archs {delocate_archs} -w {dest_dir} {wheel}"
# to install latest delocate package
CIBW_DEPENDENCY_VERSIONS: "latest"
Expand Down
57 changes: 42 additions & 15 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,24 +1,51 @@
set(CMAKE_CXX_STANDARD 11)
cmake_minimum_required(VERSION 3.11)

execute_process(COMMAND which nvcc OUTPUT_VARIABLE has_nvcc)
if(has_nvcc STREQUAL "")
execute_process(COMMAND which hipcc OUTPUT_VARIABLE has_hipcc)
if(has_hipcc STREQUAL "")
project(qsim)
else()
project(qsim LANGUAGES CXX HIP)
ADD_SUBDIRECTORY(pybind_interface/hip)
# Set APPLE_ARM to TRUE if running on Apple Silicon
if(APPLE)
execute_process(COMMAND uname -m OUTPUT_VARIABLE OSX_ARCH OUTPUT_STRIP_TRAILING_WHITESPACE)
if (OSX_ARCH STREQUAL "arm64")
set(APPLE_ARM TRUE)
else() # x86_64
set(APPLE_ARM FALSE)
endif()
else()
project(qsim LANGUAGES CXX CUDA)
ADD_SUBDIRECTORY(pybind_interface/cuda)
if(DEFINED ENV{CUQUANTUM_ROOT})
ADD_SUBDIRECTORY(pybind_interface/custatevec)
set(APPLE_ARM FALSE)
endif(APPLE)

# Set the project name and language
if(APPLE)
project(qsim LANGUAGES CXX)
else()
execute_process(COMMAND which nvcc OUTPUT_VARIABLE has_nvcc OUTPUT_STRIP_TRAILING_WHITESPACE)
if(has_nvcc)
project(qsim LANGUAGES CXX CUDA)
else()
execute_process(COMMAND which hipcc OUTPUT_VARIABLE has_hipcc OUTPUT_STRIP_TRAILING_WHITESPACE)
if(has_hipcc)
project(qsim LANGUAGES CXX HIP)
else()
project(qsim LANGUAGES CXX)
endif()
endif()
endif()

ADD_SUBDIRECTORY(pybind_interface/sse)
ADD_SUBDIRECTORY(pybind_interface/avx512)
ADD_SUBDIRECTORY(pybind_interface/avx2)
find_package(OpenMP REQUIRED)

# Add subdirectories based on the architecture or available compilers
ADD_SUBDIRECTORY(pybind_interface/basic)
ADD_SUBDIRECTORY(pybind_interface/decide)
if(NOT APPLE_ARM)
if(has_nvcc)
ADD_SUBDIRECTORY(pybind_interface/cuda)
if(DEFINED ENV{CUQUANTUM_ROOT})
ADD_SUBDIRECTORY(pybind_interface/custatevec)
endif()
elseif(has_hipcc)
ADD_SUBDIRECTORY(pybind_interface/hip)
endif()

ADD_SUBDIRECTORY(pybind_interface/sse)
ADD_SUBDIRECTORY(pybind_interface/avx512)
ADD_SUBDIRECTORY(pybind_interface/avx2)
endif()
15 changes: 15 additions & 0 deletions pybind_interface/GetPybind11.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,21 @@ FetchContent_Declare(
)
FetchContent_GetProperties(pybind11)
find_package(pybind11 "${MIN_PYBIND_VERSION}" CONFIG)

if (pybind11_FOUND)
message(STATUS "Found pybind11 v${pybind11_VERSION}: ${pybind11_INCLUDE_DIRS}")
# The pybind11_add_module doesn't correctly set the CXX_INCLUDES properly if a system pybind11 is found.
# Using `include_directories(${pybind11_INCLUDE_DIRS})` doesn't result in anything in
# CXX_INCLUDES. e.g., `pybind_interface/basic/CMakeFiles/qsim_basic.dir/flags.make` would only
# have `CXX_INCLUDES = -isystem $PREFIX/include/python3.11` and would miss `$PREFIX/include`.
# This problem would result in `fatal error: pybind11/complex.h: No such file or directory`
# This is a hack to get around that by passing `-I/path/to/include` to CXX_FLAGS
# Iterate over each include directory and add it as a compile option
foreach(INCLUDE_DIR ${pybind11_INCLUDE_DIRS})
add_compile_options("-I${INCLUDE_DIR}")
endforeach()
endif()

if((NOT pybind11_FOUND) AND (NOT pybind11_POPULATED)) # check first on system path, then attempt git fetch
FetchContent_Populate(pybind11)
add_subdirectory(${pybind11_SOURCE_DIR} ${pybind11_BINARY_DIR})
Expand Down
4 changes: 3 additions & 1 deletion pybind_interface/avx2/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ project(qsim)
IF (WIN32)
set(CMAKE_CXX_FLAGS "/arch:AVX2 /O2 /openmp")
ELSE()
set(CMAKE_CXX_FLAGS "-mavx2 -mfma -O3 -fopenmp")
set(CMAKE_CXX_FLAGS "-mavx2 -mfma -O3")
ENDIF()

if(APPLE)
Expand All @@ -14,3 +14,5 @@ if(APPLE)
endif()
INCLUDE(../GetPybind11.cmake)
pybind11_add_module(qsim_avx2 pybind_main_avx2.cpp)

target_link_libraries(qsim_avx2 PUBLIC OpenMP::OpenMP_CXX)
4 changes: 3 additions & 1 deletion pybind_interface/avx512/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ project(qsim)
IF (WIN32)
set(CMAKE_CXX_FLAGS "/arch:AVX512 /O2 /openmp")
ELSE()
set(CMAKE_CXX_FLAGS "-mavx512f -mbmi2 -O3 -fopenmp")
set(CMAKE_CXX_FLAGS "-mavx512f -mbmi2 -O3")
ENDIF()

if(APPLE)
Expand All @@ -16,3 +16,5 @@ endif()

INCLUDE(../GetPybind11.cmake)
pybind11_add_module(qsim_avx512 pybind_main_avx512.cpp)

target_link_libraries(qsim_avx512 PUBLIC OpenMP::OpenMP_CXX)
10 changes: 6 additions & 4 deletions pybind_interface/basic/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
cmake_minimum_required(VERSION 3.11)
project(qsim)

IF (WIN32)
if(WIN32)
set(CMAKE_CXX_FLAGS "/O2 /openmp")
ELSE()
set(CMAKE_CXX_FLAGS "-O3 -fopenmp")
ENDIF()
else()
set(CMAKE_CXX_FLAGS "-O3")
endif()


if(APPLE)
Expand All @@ -16,3 +16,5 @@ endif()

INCLUDE(../GetPybind11.cmake)
pybind11_add_module(qsim_basic pybind_main_basic.cpp)

target_link_libraries(qsim_basic PUBLIC OpenMP::OpenMP_CXX)
10 changes: 6 additions & 4 deletions pybind_interface/cuda/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
cmake_minimum_required(VERSION 3.11)
project(qsim LANGUAGES CXX CUDA)

IF (WIN32)
if(WIN32)
set(CMAKE_CXX_FLAGS "/O2 /openmp")
ELSE()
set(CMAKE_CXX_FLAGS "-O3 -fopenmp")
ENDIF()
else()
set(CMAKE_CXX_FLAGS "-O3")
endif()


if(APPLE)
Expand All @@ -26,3 +26,5 @@ set_target_properties(qsim_cuda PROPERTIES
SUFFIX "${PYTHON_MODULE_EXTENSION}"
)
set_source_files_properties(pybind_main_cuda.cpp PROPERTIES LANGUAGE CUDA)

target_link_libraries(qsim_cuda PUBLIC OpenMP::OpenMP_CXX)
10 changes: 6 additions & 4 deletions pybind_interface/custatevec/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,11 @@
cmake_minimum_required(VERSION 3.11)
project(qsim LANGUAGES CXX CUDA)

IF (WIN32)
if(WIN32)
set(CMAKE_CXX_FLAGS "/O2 /openmp")
ELSE()
set(CMAKE_CXX_FLAGS "-O3 -fopenmp")
ENDIF()
else()
set(CMAKE_CXX_FLAGS "-O3")
endif()

if(APPLE)
set(CMAKE_CXX_STANDARD 14)
Expand All @@ -44,3 +44,5 @@ set_target_properties(qsim_custatevec PROPERTIES
SUFFIX "${PYTHON_MODULE_EXTENSION}"
)
set_source_files_properties(pybind_main_custatevec.cpp PROPERTIES LANGUAGE CUDA)

target_link_libraries(qsim_custatevec PUBLIC OpenMP::OpenMP_CXX)
80 changes: 31 additions & 49 deletions pybind_interface/decide/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,66 +1,48 @@
cmake_minimum_required(VERSION 3.11)

execute_process(COMMAND which nvcc OUTPUT_VARIABLE has_nvcc)
if(has_nvcc STREQUAL "")
execute_process(COMMAND which hipcc OUTPUT_VARIABLE has_hipcc)
if(has_hipcc STREQUAL "")
project(qsim)
else()
project(qsim LANGUAGES CXX HIP)
endif()
if(WIN32)
set(CMAKE_CXX_FLAGS "/O2 /openmp")
else()
project(qsim LANGUAGES CXX CUDA)
set(CMAKE_CXX_FLAGS "-O3")
endif()

IF (WIN32)
set(CMAKE_CXX_FLAGS "/O2 /openmp")
ELSE()
set(CMAKE_CXX_FLAGS "-O3 -fopenmp")
ENDIF()

if(APPLE)
if(APPLE AND NOT APPLE_ARM)
set(CMAKE_CXX_STANDARD 14)
include_directories("/usr/local/include" "/usr/local/opt/llvm/include")
link_directories("/usr/local/lib" "/usr/local/opt/llvm/lib")
endif()

INCLUDE(../GetPybind11.cmake)

if(has_nvcc STREQUAL "")
if(has_hipcc STREQUAL "")
pybind11_add_module(qsim_decide decide.cpp)
else()
include(../GetPybind11.cmake)

# Configure based on the detected platform
if(has_nvcc)
find_package(CUDA REQUIRED)
cuda_add_library(qsim_decide MODULE decide.cpp)
if(DEFINED ENV{CUQUANTUM_ROOT})
target_compile_options(qsim_decide PRIVATE
$<$<COMPILE_LANGUAGE:CUDA>:-D__CUSTATEVEC__>
)
endif()
find_package(Python3 3.7 REQUIRED COMPONENTS Interpreter Development)
include_directories(${PYTHON_INCLUDE_DIRS} ${pybind11_SOURCE_DIR}/include)
set_target_properties(qsim_decide PROPERTIES
PREFIX "${PYTHON_MODULE_PREFIX}"
SUFFIX "${PYTHON_MODULE_EXTENSION}"
)
set_source_files_properties(decide.cpp PROPERTIES LANGUAGE CUDA)
elseif(has_hipcc)
list(APPEND CMAKE_MODULE_PATH "/opt/rocm/lib/cmake/hip")
find_package(HIP REQUIRED)
find_package(PythonLibs 3.7 REQUIRED)

include_directories(${PYTHON_INCLUDE_DIRS} ${pybind11_SOURCE_DIR}/include)

hip_add_library(qsim_decide MODULE decide.cpp)

set_source_files_properties(decide.cpp PROPERTIES LANGUAGE HIP)
find_package(Python3 3.7 REQUIRED COMPONENTS Interpreter Development)
include_directories(${PYTHON_INCLUDE_DIRS} ${pybind11_SOURCE_DIR}/include)
set_target_properties(qsim_decide PROPERTIES
PREFIX "${PYTHON_MODULE_PREFIX}"
SUFFIX "${PYTHON_MODULE_EXTENSION}"
PREFIX "${PYTHON_MODULE_PREFIX}"
SUFFIX "${PYTHON_MODULE_EXTENSION}"
)
set_source_files_properties(decide.cpp PROPERTIES LANGUAGE HIP)
endif()
else()
find_package(PythonLibs 3.7 REQUIRED)
find_package(CUDA REQUIRED)

include_directories(${PYTHON_INCLUDE_DIRS} ${pybind11_SOURCE_DIR}/include)

cuda_add_library(qsim_decide MODULE decide.cpp)

if(DEFINED ENV{CUQUANTUM_ROOT})
target_compile_options(qsim_decide PRIVATE
$<$<COMPILE_LANGUAGE:CUDA>:-D__CUSTATEVEC__>
)
endif()

set_target_properties(qsim_decide PROPERTIES
PREFIX "${PYTHON_MODULE_PREFIX}"
SUFFIX "${PYTHON_MODULE_EXTENSION}"
)
set_source_files_properties(decide.cpp PROPERTIES LANGUAGE CUDA)
pybind11_add_module(qsim_decide decide.cpp)
endif()

target_link_libraries(qsim_decide PUBLIC OpenMP::OpenMP_CXX)
13 changes: 7 additions & 6 deletions pybind_interface/decide/decide.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,8 @@ namespace py = pybind11;
#include <intrin.h>
#define cpuid(info, x) __cpuidex(info, x, 0)

#else
// GCC Intrinsics
#elif defined(__x86_64__) || defined(__i386__)
// GCC Intrinsics for x86/x86_64
#include <cpuid.h>
void cpuid(int info[4], int infoType){
__cpuid_count(infoType, 0, info[0], info[1], info[2], info[3]);
Expand All @@ -34,10 +34,11 @@ enum Instructions { AVX512F = 0, AVX2 = 1, SSE4_1 = 2, BASIC = 3};

int detect_instructions() {
Instructions instr = BASIC;
int info[4];

#if !defined(__aarch64__) || !defined(__APPLE__)
// Existing x86/x86_64 specific instruction set detection logic
int info[4];
cpuid(info, 0);

int nIds = info[0];
if (nIds >= 1) {
cpuid(info, 1);
Expand All @@ -47,14 +48,14 @@ int detect_instructions() {
}
if (nIds >= 7) {
cpuid(info, 7);
if ((info[1] & (1 << 5))!= 0) {
if ((info[1] & (1 << 5)) != 0) {
instr = AVX2;
}
if ((info[1] & (1 << 16)) != 0) {
instr = AVX512F;
}

}
#endif

return static_cast<int>(instr);
}
Expand Down
10 changes: 6 additions & 4 deletions pybind_interface/hip/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
cmake_minimum_required(VERSION 3.18)
project(qsim LANGUAGES CXX HIP)

IF (WIN32)
if(WIN32)
set(CMAKE_CXX_FLAGS "/O2 /openmp")
ELSE()
set(CMAKE_CXX_FLAGS "-O3 -fopenmp")
ENDIF()
else()
set(CMAKE_CXX_FLAGS "-O3")
endif()

INCLUDE(../GetPybind11.cmake)
find_package(PythonLibs 3.7 REQUIRED)
Expand All @@ -22,3 +22,5 @@ set_target_properties(qsim_hip PROPERTIES
SUFFIX "${PYTHON_MODULE_EXTENSION}"
)
set_source_files_properties(pybind_main_hip.cpp PROPERTIES LANGUAGE HIP)

target_link_libraries(qsim_hip PUBLIC OpenMP::OpenMP_CXX)
Loading

0 comments on commit de65341

Please sign in to comment.