[Openmp-commits] [openmp] [OpenMP] Fix various alignment issues (PR #142376)

Rainer Orth via Openmp-commits openmp-commits at lists.llvm.org
Mon Jun 2 05:31:43 PDT 2025


https://github.com/rorth created https://github.com/llvm/llvm-project/pull/142376

When running the `openmp` testsuite on 32-bit SPARC, several tests `FAIL` apparently randomly, but always with the same kind of error:
```
# error: command failed with exit status: -11
```
The tests die with `SIGBUS`, as can be seen in `truss` output:
```
26461/1:            Incurred fault #5, FLTACCESS  %pc = 0x00010EAC
26461/1:              siginfo: SIGBUS BUS_ADRALN addr=0x0013D12C
26461/1:            Received signal #10, SIGBUS [default]
26461/1:              siginfo: SIGBUS BUS_ADRALN addr=0x0013D12C
```
i.e. the code is trying an unaligned access which cannot work on SPARC, a strict-alignment target which enforces natural alignment on access.  This explains the apparent randomness of the failures: if the memory happens to be aligned appropriately, the tests work, but fail if not.

A `Debug` build reveals much more:

- `__kmp_alloc` currently aligns to `sizeof(void *)`, which isn't enough on strict-alignment targets when the data are accessed as types requiring larger alignment.  Therefore, this patch increases `alignment` to `SizeQuant`.

- 32-bit Solaris/sparc `libc` guarantees 8-byte alignment from `malloc`, so this patch adjusts `SizeQuant` to match.

- There's a `SIGBUS` in
  ```
  __kmpc_fork_teams (loc=0x112f8, argc=0, 
      microtask=0x16cc8 <__omp_offloading_ffbc020a_4b1abe_main_l9_debug__.omp_outlined>)
      at openmp/runtime/src/kmp_csupport.cpp:573
  573	  *(kmp_int64 *)(&this_thr->th.th_teams_size) = 0L;
  ```
  Casting to a pointer to a type requiring 64-bit alignment when that isn't guaranteed is wrong.  Instead, this patch uses `memset` instead.

- There's another `SIGBUS` in
  ```
  0xfef8cb9c in __kmp_taskloop_recur (loc=0x10cb8, gtid=0, task=0x23cd00, 
      lb=0x23cd18, ub=0x23cd20, st=1, ub_glob=499, num_tasks=100, grainsize=5, 
      extras=0, last_chunk=0, tc=500, num_t_min=20, 
      codeptr_ra=0xfef8dbc8 <__kmpc_taskloop(ident_t*, int, kmp_task_t*, int, kmp_uint64*, kmp_uint64*, kmp_int64, int, int, kmp_uint64, void*)+240>, 
      task_dup=0x0)
      at openmp/runtime/src/kmp_tasking.cpp:5147
  5147	  p->st = st;
  ```
  `p->st` doesn't currently guarantee the 8-byte alignment required by `kmp_int64 st`.  `p` is set in
  ```
   __taskloop_params_t *p = (__taskloop_params_t *)new_task->shareds;
  ```
  but `shareds_offset` is currently aligned to `sizeof(void *)` only.  Increasing it to `sizeof(kmp_uint64)` to match its use fixes the `SIGBUS`.

With these fixes I get clean `openmp` test results on 32-bit SPARC (both Solaris and Linux), with one unrelated exception.

Tested on `sparc-sun-solaris2.11`, `sparcv9-sun-solaris2.11`, `sparc-unknown-linux-gnu`, `sparc64-unknown-linux-gnu`, `i386-pc-solaris2.11`, `amd64-pc-solaris2.11`, `i686-pc-linux-gnu`, and `x86_64-pc-linux-gnu`.

>From 6cff8b2367f1bddbf04ed2e8bbbca548ad5c1514 Mon Sep 17 00:00:00 2001
From: Rainer Orth <ro at gcc.gnu.org>
Date: Mon, 2 Jun 2025 14:22:39 +0200
Subject: [PATCH] [OpenMP] Fix various alignment issues

When running the `openmp` testsuite on 32-bit SPARC, several tests `FAIL`
apparently randomly, but always with the same kind of error:
```
# error: command failed with exit status: -11
```
The tests die with `SIGBUS`, as can be seen in `truss` output:
```
26461/1:            Incurred fault #5, FLTACCESS  %pc = 0x00010EAC
26461/1:              siginfo: SIGBUS BUS_ADRALN addr=0x0013D12C
26461/1:            Received signal #10, SIGBUS [default]
26461/1:              siginfo: SIGBUS BUS_ADRALN addr=0x0013D12C
```
i.e. the code is trying an unaligned access which cannot work on SPARC, a
strict-alignment target which enforces natural alignment on access.  This
explains the apparent randomness of the failures: if the memory happens to
be aligned appropriately, the tests work, but fail if not.

A `Debug` build reveals much more:

- `__kmp_alloc` currently aligns to `sizeof(void *)`, which isn't enough on
  strict-alignment targets when the data are accessed as types requiring
  larger alignment.  Therefore, this patch increases `alignment` to
  `SizeQuant`.

- 32-bit Solaris/sparc `libc` guarantees 8-byte alignment from `malloc`, so
  this patch adjusts `SizeQuant` to match.

- There's a `SIGBUS` in
  ```
  __kmpc_fork_teams (loc=0x112f8, argc=0,
      microtask=0x16cc8 <__omp_offloading_ffbc020a_4b1abe_main_l9_debug__.omp_outlined>)
      at openmp/runtime/src/kmp_csupport.cpp:573
  573	  *(kmp_int64 *)(&this_thr->th.th_teams_size) = 0L;
  ```
  Casting to a pointer to a type requiring 64-bit alignment when that isn't
  guaranteed is wrong.  Instead, this patch uses `memset` instead.

- There's another `SIGBUS` in
  ```
  0xfef8cb9c in __kmp_taskloop_recur (loc=0x10cb8, gtid=0, task=0x23cd00,
      lb=0x23cd18, ub=0x23cd20, st=1, ub_glob=499, num_tasks=100, grainsize=5,
      extras=0, last_chunk=0, tc=500, num_t_min=20,
      codeptr_ra=0xfef8dbc8 <__kmpc_taskloop(ident_t*, int, kmp_task_t*, int, kmp_uint64*, kmp_uint64*, kmp_int64, int, int, kmp_uint64, void*)+240>,
      task_dup=0x0)
      at openmp/runtime/src/kmp_tasking.cpp:5147
  5147	  p->st = st;
  ```
  `p->st` doesn't currently guarantee the 8-byte alignment required by
  `kmp_int64 st`.  `p` is set in
  ```
  __taskloop_params_t *p = (__taskloop_params_t *)new_task->shareds;
  ```
  but `shareds_offset` is currently `sizeof(void *)` only.  Increasing it
  to `sizeof(kmp_uint64)` to match its use fixes the `SIGBUS`.

With these fixes I get clean `openmp` test results on 32-bit SPARC (both
Solaris and Linux), with one unrelated exception.

Tested on `sparc-sun-solaris2.11`, `sparcv9-sun-solaris2.11`,
`sparc-unknown-linux-gnu`, `sparc64-unknown-linux-gnu`,
`i386-pc-solaris2.11`, `amd64-pc-solaris2.11`, `i686-pc-linux-gnu`, and
`x86_64-pc-linux-gnu`.
---
 openmp/runtime/src/kmp_alloc.cpp    | 4 ++--
 openmp/runtime/src/kmp_csupport.cpp | 2 +-
 openmp/runtime/src/kmp_tasking.cpp  | 2 +-
 3 files changed, 4 insertions(+), 4 deletions(-)

diff --git a/openmp/runtime/src/kmp_alloc.cpp b/openmp/runtime/src/kmp_alloc.cpp
index 801cd06c95502..a978feb2b8973 100644
--- a/openmp/runtime/src/kmp_alloc.cpp
+++ b/openmp/runtime/src/kmp_alloc.cpp
@@ -73,7 +73,7 @@ static void bectl(kmp_info_t *th, bget_compact_t compact,
 /* On IA-32 architecture with  Linux* OS, malloc() does not
    ensure 16 byte alignment */
 
-#if KMP_ARCH_X86 || !KMP_HAVE_QUAD
+#if KMP_ARCH_X86 || KMP_ARCH_SPARC || !KMP_HAVE_QUAD
 
 #define SizeQuant 8
 #define AlignType double
@@ -1861,7 +1861,7 @@ typedef struct kmp_mem_desc { // Memory block descriptor
   void *ptr_align; // Pointer to aligned memory, returned
   kmp_allocator_t *allocator; // allocator
 } kmp_mem_desc_t;
-static int alignment = sizeof(void *); // align to pointer size by default
+static int alignment = SizeQuant;
 
 // external interfaces are wrappers over internal implementation
 void *__kmpc_alloc(int gtid, size_t size, omp_allocator_handle_t allocator) {
diff --git a/openmp/runtime/src/kmp_csupport.cpp b/openmp/runtime/src/kmp_csupport.cpp
index fdbf9ff45e354..3ca32ba583fe2 100644
--- a/openmp/runtime/src/kmp_csupport.cpp
+++ b/openmp/runtime/src/kmp_csupport.cpp
@@ -570,7 +570,7 @@ void __kmpc_fork_teams(ident_t *loc, kmp_int32 argc, kmpc_micro microtask,
 
   this_thr->th.th_teams_microtask = NULL;
   this_thr->th.th_teams_level = 0;
-  *(kmp_int64 *)(&this_thr->th.th_teams_size) = 0L;
+  memset(&this_thr->th.th_teams_size, 0, sizeof(kmp_teams_size_t));
   va_end(ap);
 #if KMP_STATS_ENABLED
   if (previous_state == stats_state_e::SERIAL_REGION) {
diff --git a/openmp/runtime/src/kmp_tasking.cpp b/openmp/runtime/src/kmp_tasking.cpp
index 3d85a29423540..d7bc4922d54f7 100644
--- a/openmp/runtime/src/kmp_tasking.cpp
+++ b/openmp/runtime/src/kmp_tasking.cpp
@@ -1528,7 +1528,7 @@ kmp_task_t *__kmp_task_alloc(ident_t *loc_ref, kmp_int32 gtid,
   // Calculate shared structure offset including padding after kmp_task_t struct
   // to align pointers in shared struct
   shareds_offset = sizeof(kmp_taskdata_t) + sizeof_kmp_task_t;
-  shareds_offset = __kmp_round_up_to_val(shareds_offset, sizeof(void *));
+  shareds_offset = __kmp_round_up_to_val(shareds_offset, sizeof(kmp_uint64));
 
   // Allocate a kmp_taskdata_t block and a kmp_task_t block.
   KA_TRACE(30, ("__kmp_task_alloc: T#%d First malloc size: %ld\n", gtid,



More information about the Openmp-commits mailing list