diff --git a/CMakeLists.txt b/CMakeLists.txt index 37a553dd64..b1f05b0940 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -228,6 +228,9 @@ ELSEIF(CMAKE_SYSTEM_NAME STREQUAL "Windows" AND CMAKE_GENERATOR_PLATFORM STREQUA ELSEIF(CMAKE_SYSTEM_PROCESSOR STREQUAL "aarch64" OR CMAKE_SYSTEM_PROCESSOR STREQUAL "ARM64") MESSAGE(STATUS "Building for AArch64") SET(EMBREE_ARM ON) +ELSEIF(CMAKE_SYSTEM_PROCESSOR MATCHES "^(powerpc|ppc)64") + MESSAGE(STATUS "Building for PowerPC64") + SET(EMBREE_PPC64 ON) ENDIF() SET(EMBREE_TASKING_SYSTEM "TBB" CACHE STRING "Selects tasking system") @@ -369,6 +372,8 @@ ENDIF() IF (EMBREE_ARM) SET_PROPERTY(CACHE EMBREE_MAX_ISA PROPERTY STRINGS NONE NEON NEON2X) +ELSEIF (EMBREE_PPC64) + SET_PROPERTY(CACHE EMBREE_MAX_ISA PROPERTY STRINGS NONE SSE2 SSE4.2 DEFAULT) ELSE() SET_PROPERTY(CACHE EMBREE_MAX_ISA PROPERTY STRINGS NONE SSE2 SSE4.2 AVX AVX2 AVX512 APX DEFAULT) ENDIF() @@ -388,6 +393,13 @@ IF (EMBREE_MAX_ISA STREQUAL "NONE") TRY_COMPILE(COMPILER_SUPPORTS_AVX2 "${CMAKE_BINARY_DIR}" "${PROJECT_SOURCE_DIR}/common/cmake/check_isa.cpp" COMPILE_DEFINITIONS ${FLAGS_AVX2}) TRY_COMPILE(COMPILER_SUPPORTS_AVX512 "${CMAKE_BINARY_DIR}" "${PROJECT_SOURCE_DIR}/common/cmake/check_isa.cpp" COMPILE_DEFINITIONS ${FLAGS_AVX512}) TRY_COMPILE(COMPILER_SUPPORTS_APX "${CMAKE_BINARY_DIR}" "${PROJECT_SOURCE_DIR}/common/cmake/check_isa.cpp" COMPILE_DEFINITIONS ${FLAGS_APX}) + IF (EMBREE_PPC64) + # the probes pass trivially without any x86 flags + SET(COMPILER_SUPPORTS_AVX OFF) + SET(COMPILER_SUPPORTS_AVX2 OFF) + SET(COMPILER_SUPPORTS_AVX512 OFF) + SET(COMPILER_SUPPORTS_APX OFF) + ENDIF () OPTION(EMBREE_ISA_SSE2 "Enables SSE2 ISA." ON) OPTION(EMBREE_ISA_SSE42 "Enables SSE4.2 ISA." ON) @@ -502,6 +514,10 @@ IF(CMAKE_CXX_COMPILER_WRAPPER STREQUAL "CrayPrgEnv") SET(EMBREE_ISA_SSE42 OFF) ENDIF() +IF (EMBREE_PPC64 AND (EMBREE_ISA_AVX OR EMBREE_ISA_AVX2 OR EMBREE_ISA_AVX512 OR EMBREE_ISA_APX)) + MESSAGE(FATAL_ERROR "PowerPC64 only supports the SSE2 and SSE4.2 ISAs (the x86 intrinsic wrappers do not cover AVX).") +ENDIF() + IF (APPLE AND EMBREE_STATIC_LIB) # count number of set ISAs @@ -563,6 +579,10 @@ IF (EMBREE_ARM) ENDIF() ENDIF() +IF (EMBREE_PPC64) + LIST(APPEND ISPC_TARGETS "vsx-i32x4") +ENDIF() + IF (EMBREE_ISA_NEON) SET(EMBREE_ISA_SSE2 ON) ENDIF() @@ -576,7 +596,7 @@ ENDIF() IF (EMBREE_ISA_SSE2) ADD_DEFINITIONS(-DEMBREE_TARGET_SSE2) - IF (NOT EMBREE_ARM) + IF (NOT EMBREE_ARM AND NOT EMBREE_PPC64) LIST(APPEND ISPC_TARGETS "sse2") ENDIF() IF(NOT FLAGS_LOWEST) @@ -587,7 +607,7 @@ ENDIF() IF (EMBREE_ISA_SSE42) ADD_DEFINITIONS(-DEMBREE_TARGET_SSE42) - IF (NOT EMBREE_ARM) + IF (NOT EMBREE_ARM AND NOT EMBREE_PPC64) LIST(APPEND ISPC_TARGETS "sse4") ENDIF() IF(NOT FLAGS_LOWEST) diff --git a/common/cmake/clang.cmake b/common/cmake/clang.cmake index ecb5f399db..1ba7ec1faf 100644 --- a/common/cmake/clang.cmake +++ b/common/cmake/clang.cmake @@ -21,6 +21,14 @@ IF (EMBREE_ARM) SET(FLAGS_AVX "-D__AVX__ -D__SSE4_2__ -D__SSE4_1__ -D__BMI__ -D__BMI2__ -D__LZCNT__") SET(FLAGS_AVX2 "-D__AVX2__ -D__AVX__ -D__SSE4_2__ -D__SSE4_1__ -D__BMI__ -D__BMI2__ -D__LZCNT__") ENDIF () +ELSEIF (EMBREE_PPC64) + # the x86 intrinsic wrappers need POWER8, honor a newer -mcpu from the user + STRING(REGEX MATCH "-mcpu=[^ ]+" FLAGS_PPC64_CPU "${CMAKE_CXX_FLAGS}") + IF (NOT FLAGS_PPC64_CPU) + SET(FLAGS_PPC64_CPU "-mcpu=power8") + ENDIF () + SET(FLAGS_SSE2 "-D__SSE__ -D__SSE2__ ${FLAGS_PPC64_CPU}") + SET(FLAGS_SSE42 "-D__SSE4_2__ -D__SSE4_1__ ${FLAGS_PPC64_CPU}") ELSE () # for `thread` keyword _SET_IF_EMPTY(FLAGS_SSE2 "-msse -msse2 -mno-sse4.2") diff --git a/common/cmake/gnu.cmake b/common/cmake/gnu.cmake index 25598f0664..9e24c7a62f 100644 --- a/common/cmake/gnu.cmake +++ b/common/cmake/gnu.cmake @@ -12,6 +12,19 @@ IF (EMBREE_ARM) SET(FLAGS_SSE42 "-D__SSE4_2__ -D__SSE4_1__") SET(FLAGS_AVX "-D__AVX__ -D__SSE4_2__ -D__SSE4_1__ -D__BMI__ -D__BMI2__ -D__LZCNT__") SET(FLAGS_AVX2 "-D__AVX2__ -D__AVX__ -D__SSE4_2__ -D__SSE4_1__ -D__BMI__ -D__BMI2__ -D__LZCNT__") +ELSEIF (EMBREE_PPC64) + # GCC ships the x86 intrinsic wrappers for PowerPC since GCC 8, but + # immintrin.h (which intrinsics.h includes) only since GCC 12 + IF (CMAKE_CXX_COMPILER_VERSION VERSION_LESS "12.0") + MESSAGE(FATAL_ERROR "GCC ${CMAKE_CXX_COMPILER_VERSION} lacks the PowerPC x86 intrinsic wrappers, GCC 12 or newer is required.") + ENDIF () + # the x86 intrinsic wrappers need POWER8, honor a newer -mcpu from the user + STRING(REGEX MATCH "-mcpu=[^ ]+" FLAGS_PPC64_CPU "${CMAKE_CXX_FLAGS}") + IF (NOT FLAGS_PPC64_CPU) + SET(FLAGS_PPC64_CPU "-mcpu=power8") + ENDIF () + SET(FLAGS_SSE2 "-D__SSE__ -D__SSE2__ ${FLAGS_PPC64_CPU}") + SET(FLAGS_SSE42 "-D__SSE4_2__ -D__SSE4_1__ ${FLAGS_PPC64_CPU}") ELSE () _SET_IF_EMPTY(FLAGS_SSE2 "-msse2") _SET_IF_EMPTY(FLAGS_SSE42 "-msse4.2") diff --git a/common/cmake/ispc.cmake b/common/cmake/ispc.cmake index 7a4abaeb85..957dd66de9 100644 --- a/common/cmake/ispc.cmake +++ b/common/cmake/ispc.cmake @@ -75,6 +75,8 @@ MACRO (ISPC_COMPILE) IF (CMAKE_SIZEOF_VOID_P EQUAL 8) IF (${CMAKE_SYSTEM_PROCESSOR} MATCHES "arm64|aarch64") SET(ISPC_ARCHITECTURE "aarch64") + ELSEIF (${CMAKE_SYSTEM_PROCESSOR} MATCHES "^(powerpc|ppc)64le") + SET(ISPC_ARCHITECTURE "ppc64le") ELSE() SET(ISPC_ARCHITECTURE "x86-64") ENDIF() diff --git a/common/sys/intrinsics.h b/common/sys/intrinsics.h index fb6610605d..e6e6583d3c 100644 --- a/common/sys/intrinsics.h +++ b/common/sys/intrinsics.h @@ -13,6 +13,36 @@ #include "../simd/arm/emulation.h" #else #include +#if defined(__powerpc64__) +__forceinline unsigned int _mm_getcsr() { return 0; } +__forceinline void _mm_setcsr(unsigned int) {} +__forceinline int _mm_popcnt_u32(unsigned int v) { return __builtin_popcount(v); } +__forceinline long long _mm_popcnt_u64(unsigned long long v) { return __builtin_popcountll(v); } +__forceinline __m128i _mm_stream_load_si128(__m128i* p) { return _mm_load_si128(p); } +__forceinline __m128 _mm_dp_ps(__m128 a, __m128 b, const int imm) { + const __m128i hi = _mm_set_epi32((imm & 0x80) ? -1 : 0, (imm & 0x40) ? -1 : 0, (imm & 0x20) ? -1 : 0, (imm & 0x10) ? -1 : 0); + const __m128i lo = _mm_set_epi32((imm & 0x08) ? -1 : 0, (imm & 0x04) ? -1 : 0, (imm & 0x02) ? -1 : 0, (imm & 0x01) ? -1 : 0); + __m128 p = _mm_and_ps(_mm_mul_ps(a, b), _mm_castsi128_ps(hi)); + p = _mm_hadd_ps(p, p); + p = _mm_hadd_ps(p, p); + return _mm_and_ps(p, _mm_castsi128_ps(lo)); +} +__forceinline __m128 _mm_insert_ps(__m128 a, __m128 b, const int imm) { + float ta[4], tb[4]; + _mm_storeu_ps(ta, a); + _mm_storeu_ps(tb, b); + ta[(imm >> 4) & 3] = tb[(imm >> 6) & 3]; + for (int i = 0; i < 4; i++) if (imm & (1 << i)) ta[i] = 0.0f; + return _mm_loadu_ps(ta); +} +#define _MM_MASK_DENORM 0x0100 +#define _MM_MASK_DIV_ZERO 0x0200 +#define _MM_MASK_MASK 0x1f80 +#define _MM_FLUSH_ZERO_MASK 0x8000 +#define _MM_FLUSH_ZERO_ON 0x8000 +#define _MM_SET_EXCEPTION_MASK(x) _mm_setcsr((_mm_getcsr() & ~_MM_MASK_MASK) | (x)) +#define _MM_SET_FLUSH_ZERO_MODE(x) _mm_setcsr((_mm_getcsr() & ~_MM_FLUSH_ZERO_MASK) | (x)) +#endif #if defined(__EMSCRIPTEN__) #include "../simd/wasm/emulation.h" #endif diff --git a/common/sys/platform.h b/common/sys/platform.h index 73bb412aa8..ea8d10633b 100644 --- a/common/sys/platform.h +++ b/common/sys/platform.h @@ -57,12 +57,18 @@ #define __X86_ASM__ #endif +#if defined(__powerpc64__) +#define NO_WARN_X86_INTRINSICS +#define __SSE__ 1 +#define __SSE2__ 1 +#endif + /* detect 64 bit platform */ #if defined(__aarch64__) || defined(_M_ARM64) #define EMBREE_ARM64 #endif -#if defined(__X86_64__) || defined(EMBREE_ARM64) +#if defined(__X86_64__) || defined(EMBREE_ARM64) || defined(__powerpc64__) #define __64BIT__ #endif diff --git a/common/sys/sysinfo.cpp b/common/sys/sysinfo.cpp index 81e6cd23d8..843d9f1e1a 100644 --- a/common/sys/sysinfo.cpp +++ b/common/sys/sysinfo.cpp @@ -429,6 +429,13 @@ namespace embree #endif return cpu_features; +#elif defined(__powerpc64__) + + int cpu_features = CPU_FEATURE_SSE|CPU_FEATURE_SSE2|CPU_FEATURE_SSE3|CPU_FEATURE_SSSE3; + cpu_features |= CPU_FEATURE_SSE41|CPU_FEATURE_SSE42|CPU_FEATURE_POPCNT; + cpu_features |= CPU_FEATURE_XMM_ENABLED; + return cpu_features; + #elif defined(__ARM_NEON) || defined(EMBREE_ARM64) || defined(__EMSCRIPTEN__) int cpu_features = CPU_FEATURE_NEON|CPU_FEATURE_SSE|CPU_FEATURE_SSE2;