Просмотр исходного кода

PowerPC Little Endian 64-bit support (#1377)

Co-authored-by: Jorrit Rouwe <[email protected]>
Link4Electronics 7 месяцев назад
Родитель
Сommit
9b3e9e6041

+ 30 - 0
.github/workflows/determinism_check.yml

@@ -9,6 +9,7 @@ env:
   UBUNTU_GCC_VERSION: g++-12
   UBUNTU_GCC_AARCH64_VERSION: aarch64-linux-gnu-g++-12
   UBUNTU_GCC_RISCV_VERSION: riscv64-linux-gnu-g++-12
+  UBUNTU_GCC_POWERPC_VERSION: powerpc64le-linux-gnu-g++-12
 
 on:
   push:
@@ -264,6 +265,35 @@ jobs:
       working-directory: ${{github.workspace}}/Build/Linux_Distribution
       run: qemu-riscv64 -L /usr/riscv64-linux-gnu/ ./PerformanceTest -q=LinearCast -t=max -s=Pyramid -validate_hash=${PYRAMID_HASH}
 
+  powerpcle_gcc:
+    runs-on: ubuntu-latest
+    name: PowerPC Little Endian GCC Determinism Check
+    steps:
+    - name: Checkout Code
+      uses: actions/checkout@v4
+    - name: Update index
+      run: sudo apt-get update
+    - name: Install Cross Compiler
+      run: sudo apt-get install g++-12-powerpc64le-linux-gnu gcc-12-multilib g++-12-multilib qemu-user -y
+    - name: Configure CMake
+      working-directory: ${{github.workspace}}/Build
+      run: ./cmake_linux_clang_gcc.sh Distribution ${{env.UBUNTU_GCC_POWERPC_VERSION}} -DCROSS_COMPILE_ARM=ON -DCROSS_PLATFORM_DETERMINISTIC=ON -DCROSS_COMPILE_ARM_TARGET="" -DTARGET_VIEWER=OFF -DTARGET_SAMPLES=OFF -DTARGET_HELLO_WORLD=OFF -DTARGET_UNIT_TESTS=ON -DTARGET_PERFORMANCE_TEST=ON
+    - name: Build
+      run: cmake --build ${{github.workspace}}/Build/Linux_Distribution -j $(nproc)
+    - name: Unit Tests
+      working-directory: ${{github.workspace}}/Build/Linux_Distribution
+      run: qemu-ppc64le -L /usr/powerpc64le-linux-gnu/ ./UnitTests
+    - name: Test ConvexVsMesh
+      working-directory: ${{github.workspace}}/Build/Linux_Distribution
+      run: qemu-ppc64le -L /usr/powerpc64le-linux-gnu/ ./PerformanceTest -q=LinearCast -t=max -s=ConvexVsMesh -validate_hash=${CONVEX_VS_MESH_HASH}
+# This is really slow so disabled for the moment
+#    - name: Test Ragdoll
+#      working-directory: ${{github.workspace}}/Build/Linux_Distribution
+#      run: qemu-ppc64le -L /usr/powerpc64le-linux-gnu/ ./PerformanceTest -q=LinearCast -t=max -s=Ragdoll -validate_hash=${RAGDOLL_HASH}
+#    - name: Test Pyramid
+#      working-directory: ${{github.workspace}}/Build/Linux_Distribution
+#      run: qemu-ppc64le -L /usr/powerpc64le-linux-gnu/ ./PerformanceTest -q=LinearCast -t=max -s=Pyramid -validate_hash=${PYRAMID_HASH}
+
   emscripten:
     runs-on: ubuntu-latest
     name: Emscripten Determinism Check

+ 1 - 0
Docs/Architecture.md

@@ -633,6 +633,7 @@ It is quite difficult to verify cross platform determinism, so this feature is l
 * Linux gcc x86 64-bit with AVX2
 * Linux gcc ARM 64-bit with NEON
 * Linux gcc RISC-V 64-bit
+* Linux gcc PowerPC (Little Endian) 64-bit
 * WASM emscripten running in nodejs
 
 The most important things to look out for in your own application:

+ 1 - 1
Docs/ReleaseNotes.md

@@ -14,7 +14,7 @@ For breaking API changes see [this document](https://github.com/jrouwe/JoltPhysi
 * Added `PhysicsSystem::SetSimShapeFilter`. This allows filtering out collisions between sub shapes within a body and can for example be used to have a single body that contains a low detail simulation shape an a high detail collision query shape.
 * Added an example of a body that's both a sensor and a rigid body in `ContactListenerTest`.
 * Added binary serialization to `SkeletalAnimation`.
-* Added support for RISC-V CPUs.
+* Added support for RISC-V and PowerPC (Little Endian) CPUs.
 
 ### Bug fixes
 

+ 7 - 0
Jolt/ConfigurationString.h

@@ -16,6 +16,13 @@ inline const char *GetConfigurationString()
 		"ARM "
 #elif defined(JPH_CPU_RISCV)
 		"RISC-V "
+#elif defined(JPH_CPU_PPC)
+		"PowerPC "
+	#ifdef JPH_CPU_BIG_ENDIAN
+		"(Big Endian) "
+	#else
+		"(Little Endian) "
+	#endif
 #elif defined(JPH_CPU_E2K)
 		"E2K "
 #elif defined(JPH_CPU_WASM)

+ 20 - 1
Jolt/Core/Core.h

@@ -203,6 +203,19 @@
 		#define JPH_USE_SSE4_1
 		#define JPH_USE_SSE4_2
 	#endif
+#elif defined(__powerpc__) || defined(__powerpc64__)
+	// PowerPC CPU architecture
+	#define JPH_CPU_PPC
+	#if defined(__powerpc64__)
+		#define JPH_CPU_ADDRESS_BITS 64
+	#else
+		#define JPH_CPU_ADDRESS_BITS 32
+	#endif
+	#ifdef _BIG_ENDIAN
+		#define JPH_CPU_BIG_ENDIAN
+	#endif
+	#define JPH_VECTOR_ALIGNMENT 16
+	#define JPH_DVECTOR_ALIGNMENT 8
 #elif defined(__e2k__)
 	// E2K CPU architecture (MCST Elbrus 2000)
 	#define JPH_CPU_E2K
@@ -224,6 +237,11 @@
 #else
 	#define JPH_IF_RISCV(x)
 #endif
+#ifdef JPH_CPU_PPC
+	#define JPH_IF_PPC(x) x
+#else
+	#define JPH_IF_PPC(x)
+#endif
 
 // If this define is set, Jolt is compiled as a shared library
 #ifdef JPH_SHARED_LIBRARY
@@ -340,6 +358,7 @@
 	JPH_GCC_SUPPRESS_WARNING("-Wunused-parameter")												\
 	JPH_GCC_SUPPRESS_WARNING("-Wmaybe-uninitialized")											\
 	JPH_IF_RISCV(JPH_GCC_SUPPRESS_WARNING("-Wuninitialized"))									\
+	JPH_IF_PPC(JPH_GCC_SUPPRESS_WARNING("-Wuninitialized"))										\
 																								\
 	JPH_MSVC_SUPPRESS_WARNING(4619) /* #pragma warning: there is no warning number 'XXXX' */	\
 	JPH_MSVC_SUPPRESS_WARNING(4514) /* 'X' : unreferenced inline function has been removed */	\
@@ -378,7 +397,7 @@
 #elif defined(JPH_PLATFORM_LINUX) || defined(JPH_PLATFORM_ANDROID) || defined(JPH_PLATFORM_MACOS) || defined(JPH_PLATFORM_IOS) || defined(JPH_PLATFORM_FREEBSD)
 	#if defined(JPH_CPU_X86)
 		#define JPH_BREAKPOINT	__asm volatile ("int $0x3")
-	#elif defined(JPH_CPU_ARM) || defined(JPH_CPU_RISCV) || defined(JPH_CPU_E2K)
+	#elif defined(JPH_CPU_ARM) || defined(JPH_CPU_RISCV) || defined(JPH_CPU_E2K) || defined(JPH_CPU_PPC)
 		#define JPH_BREAKPOINT	__builtin_trap()
 	#else
 		#error Unknown CPU architecture

+ 4 - 0
Jolt/Core/FPControlWord.h

@@ -130,6 +130,10 @@ private:
 
 // RISC-V only implements manually checking if exceptions occurred by reading the fcsr register. It doesn't generate exceptions.
 
+#elif defined(JPH_CPU_PPC)
+
+// Not implemented right now
+
 #else
 
 #error Unsupported CPU architecture

+ 4 - 0
Jolt/Core/FPException.h

@@ -60,6 +60,10 @@ class FPExceptionDisableDivByZero : public FPControlWord<0, FP_DZE> { };
 
 #error "RISC-V only implements manually checking if exceptions occurred by reading the fcsr register. It doesn't generate exceptions. JPH_FLOATING_POINT_EXCEPTIONS_ENABLED must be disabled."
 
+#elif defined(JPH_CPU_PPC)
+
+#error PowerPC floating point exception handling to be implemented. JPH_FLOATING_POINT_EXCEPTIONS_ENABLED must be disabled.
+
 #else
 
 #error Unsupported CPU architecture

+ 1 - 1
Jolt/Core/FPFlushDenormals.h

@@ -8,7 +8,7 @@
 
 JPH_NAMESPACE_BEGIN
 
-#if defined(JPH_CPU_WASM) || defined(JPH_CPU_RISCV)
+#if defined(JPH_CPU_WASM) || defined(JPH_CPU_RISCV) || defined(JPH_CPU_PPC)
 
 // Not supported
 class FPFlushDenormals { };

+ 1 - 1
Jolt/Core/TickCounter.h

@@ -35,7 +35,7 @@ JPH_INLINE uint64 GetProcessorTickCount()
 	uint64 val;
 	asm volatile("mrs %0, cntvct_el0" : "=r" (val));
 	return val;
-#elif defined(JPH_CPU_ARM) || defined(JPH_CPU_RISCV) || defined(JPH_CPU_WASM)
+#elif defined(JPH_CPU_ARM) || defined(JPH_CPU_RISCV) || defined(JPH_CPU_WASM) || defined(JPH_CPU_PPC)
 	return 0; // Not supported
 #else
 	#error Undefined

+ 2 - 2
Jolt/Math/Math.h

@@ -120,7 +120,7 @@ inline uint CountTrailingZeros(uint32 inValue)
 			return 32;
 		return __builtin_ctz(inValue);
 	#endif
-#elif defined(JPH_CPU_E2K) || defined(JPH_CPU_RISCV)
+#elif defined(JPH_CPU_E2K) || defined(JPH_CPU_RISCV) || defined(JPH_CPU_PPC)
 	return inValue ? __builtin_ctz(inValue) : 32;
 #else
 	#error Undefined
@@ -150,7 +150,7 @@ inline uint CountLeadingZeros(uint32 inValue)
 	#else
 		return __builtin_clz(inValue);
 	#endif
-#elif defined(JPH_CPU_E2K) || defined(JPH_CPU_RISCV)
+#elif defined(JPH_CPU_E2K) || defined(JPH_CPU_RISCV) || defined(JPH_CPU_PPC)
 	return inValue ? __builtin_clz(inValue) : 32;
 #else
 	#error Undefined

+ 1 - 1
README.md

@@ -90,7 +90,7 @@ Why create yet another physics engine? Firstly, it has been a personal learning
 ## Supported platforms
 
 * Windows (Desktop or UWP) x86/x64/ARM32/ARM64
-* Linux (tested on Ubuntu) x86/x64/ARM32/ARM64/RISC-V64
+* Linux (tested on Ubuntu) x86/x64/ARM32/ARM64/RISC-V64/PowerPC64LE
 * FreeBSD
 * Android x86/x64/ARM32/ARM64
 * Platform Blue (a popular game console) x64

+ 1 - 1
UnitTests/Core/FPFlushDenormalsTest.cpp

@@ -6,7 +6,7 @@
 #include <Jolt/Core/FPFlushDenormals.h>
 #include <atomic>
 
-#if !defined(JPH_CPU_WASM) && !defined(JPH_CPU_RISCV)
+#if !defined(JPH_CPU_WASM) && !defined(JPH_CPU_RISCV) && !defined(JPH_CPU_PPC)
 
 // Implemented as a global atomic so the compiler can't optimize it to a constant
 extern atomic<float> TestFltMin;

+ 6 - 6
UnitTests/Math/UVec4Tests.cpp

@@ -507,17 +507,17 @@ TEST_SUITE("UVec4Tests")
 
 	TEST_CASE("TestUVec4ExtractUInt16")
 	{
-		uint16 ints[] = { 1, 2, 3, 4, 5, 6, 7, 8 };
-		UVec4 vector = UVec4::sLoadInt4((const uint32 *)ints);
+		uint32 data[] = { 0x0b020a01, 0x0d040c03, 0x0b060a05, 0x0d080c07 };
+		UVec4 vector = UVec4::sLoadInt4(data);
 
-		CHECK(vector.Expand4Uint16Lo() == UVec4(1, 2, 3, 4));
-		CHECK(vector.Expand4Uint16Hi() == UVec4(5, 6, 7, 8));
+		CHECK(vector.Expand4Uint16Lo() == UVec4(0x0a01, 0x0b02, 0x0c03, 0x0d04));
+		CHECK(vector.Expand4Uint16Hi() == UVec4(0x0a05, 0x0b06, 0x0c07, 0x0d08));
 	}
 
 	TEST_CASE("TestUVec4ExtractBytes")
 	{
-		uint8 bytes[] = { 0x11, 0x12, 0x13, 0x14, 0x21, 0x22, 0x23, 0x24, 0x31, 0x32, 0x33, 0x34, 0x41, 0x42, 0x43, 0x44 };
-		UVec4 vector = UVec4::sLoadInt4((const uint32 *)bytes);
+		uint32 data[] = { 0x14131211, 0x24232221, 0x34333231, 0x44434241 };
+		UVec4 vector = UVec4::sLoadInt4(data);
 
 		CHECK(vector.Expand4Byte0()  == UVec4(0x11, 0x12, 0x13, 0x14));
 		CHECK(vector.Expand4Byte4()  == UVec4(0x21, 0x22, 0x23, 0x24));