[Openmp-commits] [openmp] [OpenMP] Add __kmp_invoke_microtask for 32-bit PowerPC (PR #227541)
Matt Turner via Openmp-commits
openmp-commits at lists.llvm.org
Tue Sep 29 19:51:31 PDT 2026
https://github.com/mattst88 created https://github.com/llvm/llvm-project/pull/227541
Depends on https://github.com/llvm/llvm-project/pull/227539; only the last commit is new.
32-bit PowerPC ELF targets use the generic C++ `__kmp_invoke_microtask`, which exits when a parallel region has more than 15 arguments, so misc_bugs/many-microtask-args.c fails. Add an assembly version for the SysV ABI, based on the ppc64 one.
AIX also defines `KMP_ARCH_PPC` and already has its own version in z_AIX_asm.S.
Tested with check-openmp under qemu-ppc.
>From 339f71565cec3d7f40f0fdd9354e73be85a109be Mon Sep 17 00:00:00 2001
From: Matt Turner <mattst88 at gmail.com>
Date: Tue, 29 Sep 2026 20:24:41 -0400
Subject: [PATCH 1/2] [OpenMP] Build libomp on 32-bit PowerPC Linux
kmp_affinity.h has no sched_{set,get}affinity syscall numbers for 32-bit
PowerPC and stops at its #error. They are the same as on ppc64 (222 and
223), so share that case.
32-bit PowerPC has no 64-bit atomic instructions, so linking libomp.so
also fails on undefined __atomic_*_8 references. Link libatomic, as for
MIPS, but only if it exists: other 32-bit PowerPC targets such as
OpenBSD (52a02b6d1e0c) may not have it. AIX already links
libcompiler_rt for these.
Assisted-by: Claude Code
---
openmp/runtime/CMakeLists.txt | 10 ++++++++++
openmp/runtime/src/kmp_affinity.h | 2 +-
2 files changed, 11 insertions(+), 1 deletion(-)
diff --git a/openmp/runtime/CMakeLists.txt b/openmp/runtime/CMakeLists.txt
index 0256bfaf4a892..2a461388585f0 100644
--- a/openmp/runtime/CMakeLists.txt
+++ b/openmp/runtime/CMakeLists.txt
@@ -153,6 +153,16 @@ if("${LIBOMP_ARCH}" STREQUAL "mips" OR "${LIBOMP_ARCH}" STREQUAL "mips64")
set(LIBOMP_LIBFLAGS "${LIBOMP_LIBFLAGS} -latomic")
endif()
+if("${LIBOMP_ARCH}" STREQUAL "ppc" AND NOT "${CMAKE_SYSTEM_NAME}" MATCHES "AIX")
+ # PPC (32-bit) has no 64-bit atomic instructions, so __atomic_load_8, etc.
+ # come from libatomic where the toolchain provides one.
+ include(CheckLibraryExists)
+ check_library_exists(atomic __atomic_load_8 "" LIBOMP_HAVE_LIBATOMIC_8)
+ if(LIBOMP_HAVE_LIBATOMIC_8)
+ set(LIBOMP_LIBFLAGS "${LIBOMP_LIBFLAGS} -latomic")
+ endif()
+endif()
+
# Should the libomp library and generated headers be copied into the original source exports/ directory
# Turning this to FALSE aids parallel builds to not interfere with each other.
# Currently, the testsuite module expects the just built OpenMP library to be located inside the exports/
diff --git a/openmp/runtime/src/kmp_affinity.h b/openmp/runtime/src/kmp_affinity.h
index fa69585f7e2d5..6d814578ca4f2 100644
--- a/openmp/runtime/src/kmp_affinity.h
+++ b/openmp/runtime/src/kmp_affinity.h
@@ -234,7 +234,7 @@ class KMPHwlocAffinity : public KMPAffinity {
#elif __NR_sched_getaffinity != 204
#error Wrong code for getaffinity system call.
#endif /* __NR_sched_getaffinity */
-#elif KMP_ARCH_PPC64
+#elif KMP_ARCH_PPC64 || KMP_ARCH_PPC
#ifndef __NR_sched_setaffinity
#define __NR_sched_setaffinity 222
#elif __NR_sched_setaffinity != 222
>From ce2759f694e8cbb90454b7540a0ed276388a8fdd Mon Sep 17 00:00:00 2001
From: Matt Turner <mattst88 at gmail.com>
Date: Tue, 29 Sep 2026 20:24:41 -0400
Subject: [PATCH 2/2] [OpenMP] Add __kmp_invoke_microtask for 32-bit PowerPC
32-bit PowerPC ELF targets use the generic C++ __kmp_invoke_microtask,
which exits when a parallel region has more than 15 arguments, so
misc_bugs/many-microtask-args.c fails. Add an assembly version for the
SysV ABI, based on the ppc64 one.
AIX also defines KMP_ARCH_PPC and already has its own version in
z_AIX_asm.S.
Assisted-by: Claude Code
---
openmp/runtime/src/kmp_invoke_microtask.cpp | 2 +-
openmp/runtime/src/z_Linux_asm.S | 110 ++++++++++++++++++++
2 files changed, 111 insertions(+), 1 deletion(-)
diff --git a/openmp/runtime/src/kmp_invoke_microtask.cpp b/openmp/runtime/src/kmp_invoke_microtask.cpp
index e3cae9938bcd3..40ea3b3f15578 100644
--- a/openmp/runtime/src/kmp_invoke_microtask.cpp
+++ b/openmp/runtime/src/kmp_invoke_microtask.cpp
@@ -4,7 +4,7 @@
#if !(KMP_ARCH_X86 || KMP_ARCH_X86_64 || KMP_MIC || KMP_ARCH_AARCH64 || \
KMP_ARCH_PPC64 || KMP_ARCH_RISCV64 || KMP_ARCH_LOONGARCH64 || \
- KMP_ARCH_ARM || KMP_ARCH_VE || KMP_ARCH_S390X || KMP_ARCH_PPC_XCOFF || \
+ KMP_ARCH_ARM || KMP_ARCH_VE || KMP_ARCH_S390X || KMP_ARCH_PPC || \
KMP_ARCH_AARCH64_32)
template <size_t> using microtask_argument_t = void *;
diff --git a/openmp/runtime/src/z_Linux_asm.S b/openmp/runtime/src/z_Linux_asm.S
index 68b755a089412..27a7c97558d9f 100644
--- a/openmp/runtime/src/z_Linux_asm.S
+++ b/openmp/runtime/src/z_Linux_asm.S
@@ -1801,6 +1801,116 @@ __kmp_invoke_microtask:
#endif /* KMP_ARCH_PPC64 */
+#if KMP_ARCH_PPC
+//------------------------------------------------------------------------
+// Same interface and argument registers as the PPC64 version above.
+//
+ .text
+ .globl __kmp_invoke_microtask
+ .p2align 2
+ .type __kmp_invoke_microtask, at function
+__kmp_invoke_microtask:
+.Lfunc_begin0:
+// -- Begin __kmp_invoke_microtask
+// The 32-bit SysV ABI has no red zone, so nothing may be stored below r1
+// until the frame is established. The frame is the 8-byte header, 4*argc
+// bytes of parameter area for the microtask (only argc - 6 are used), and
+// 16 bytes for r31, r30 (OMP-T), gtid and tid.
+ .cfi_startproc
+ mflr 0
+ stw 0, 4(1)
+ .cfi_offset lr, 4
+ mr 12, 1
+ .cfi_def_cfa_register r12
+// Compute the size necessary for the local stack frame, keeping it aligned
+// to 16 bytes.
+ slwi 11, 6, 2
+ addi 11, 11, 24 + 15
+ rlwinm 11, 11, 0, 0, 27
+ neg 11, 11
+// Establish the local stack frame.
+ stwux 1, 1, 11
+ stw 31, -4(12)
+// As on PPC64, r31 holds the incoming r1 rather than the new one, because
+// the frame size is computed dynamically.
+ mr 31, 12
+ .cfi_def_cfa_register r31
+ .cfi_offset r31, -4
+# if OMPT_SUPPORT
+ stw 30, -8(31)
+ .cfi_offset r30, -8
+ stw 1, 0(8)
+ mr 30, 8
+# endif
+// Store gtid and tid to the stack because they're passed by reference to the microtask.
+ stw 4, -12(31)
+ stw 5, -16(31)
+ mr 12, 3
+ mr 11, 6
+ mr 4, 7
+ cmpwi 0, 11, 1
+ blt 0, .Lcall
+ lwz 5, 0(4)
+ cmpwi 0, 11, 2
+ blt 0, .Lcall
+ lwz 6, 4(4)
+ cmpwi 0, 11, 3
+ blt 0, .Lcall
+ lwz 7, 8(4)
+ cmpwi 0, 11, 4
+ blt 0, .Lcall
+ lwz 8, 12(4)
+ cmpwi 0, 11, 5
+ blt 0, .Lcall
+ lwz 9, 16(4)
+ cmpwi 0, 11, 6
+ blt 0, .Lcall
+ lwz 10, 20(4)
+ cmpwi 0, 11, 7
+ blt 0, .Lcall
+// There are more than 6 microtask parameters, so we need to store the
+// remainder to the stack.
+ addi 11, 11, -6
+ mtctr 11
+// These are set to 4 bytes before the first desired load and store addresses
+// (we're using pre-increment loads and stores in the loop below). The
+// parameter area for the microtask begins 8 bytes above r1.
+ addi 4, 4, 20
+ addi 3, 1, 4
+.Lnext:
+ lwzu 0, 4(4)
+ stwu 0, 4(3)
+ bdnz .Lnext
+.Lcall:
+ mtctr 12
+ addi 3, 31, -12
+ addi 4, 31, -16
+// The microtask is called through a variadic type, so tell it that no
+// floating-point arguments are passed in registers.
+ crxor 6, 6, 6
+ bctrl
+# if OMPT_SUPPORT
+ li 3, 0
+ stw 3, 0(30)
+ lwz 30, -8(31)
+# endif
+ li 3, 1
+ lwz 0, 4(31)
+ mtlr 0
+// Reload r31 before popping the frame; nothing below r1 survives once it is
+// gone.
+ mr 11, 31
+ lwz 31, -4(11)
+ mr 1, 11
+ blr
+.Lfunc_end0:
+ .size __kmp_invoke_microtask, .Lfunc_end0-.Lfunc_begin0
+ .cfi_endproc
+
+// -- End __kmp_invoke_microtask
+
+#endif /* KMP_ARCH_PPC */
+
#if KMP_ARCH_RISCV64
//------------------------------------------------------------------------
More information about the Openmp-commits
mailing list