[Openmp-commits] [openmp] [OpenMP] Support up to 32 arguments in the generic microtask dispatcher (PR #211071)

via Openmp-commits openmp-commits at lists.llvm.org
Mon Aug 3 06:26:14 PDT 2026


https://github.com/arsnyder16 updated https://github.com/llvm/llvm-project/pull/211071

>From 7b76acc6c9fa6222b4360dd90ce465df1acaff2a Mon Sep 17 00:00:00 2001
From: Andrew Snyder <asnyder at minitab.com>
Date: Tue, 21 Jul 2026 13:39:00 -0400
Subject: [PATCH 1/3] [OpenMP] Support up to 32 arguments in the generic
 microtask dispatcher

---
 openmp/runtime/src/kmp_invoke_microtask.cpp   | 177 +++++++-----------
 .../test/misc_bugs/microtask-32-args.c        |  56 ++++++
 .../test/misc_bugs/wasm-microtask-33-args.c   |  60 ++++++
 3 files changed, 183 insertions(+), 110 deletions(-)
 create mode 100644 openmp/runtime/test/misc_bugs/microtask-32-args.c
 create mode 100644 openmp/runtime/test/misc_bugs/wasm-microtask-33-args.c

diff --git a/openmp/runtime/src/kmp_invoke_microtask.cpp b/openmp/runtime/src/kmp_invoke_microtask.cpp
index f14f27cc06ee3..474423b62188e 100644
--- a/openmp/runtime/src/kmp_invoke_microtask.cpp
+++ b/openmp/runtime/src/kmp_invoke_microtask.cpp
@@ -5,45 +5,33 @@
       KMP_ARCH_ARM || KMP_ARCH_VE || KMP_ARCH_S390X || KMP_ARCH_PPC_XCOFF ||   \
       KMP_ARCH_AARCH64_32)
 
-// Because WebAssembly will use `call_indirect` to invoke the microtask and
-// WebAssembly indirect calls check that the called signature is a precise
-// match, we need to cast each microtask function pointer back from `void *` to
-// its original type.
-typedef void (*microtask_t0)(int *, int *);
-typedef void (*microtask_t1)(int *, int *, void *);
-typedef void (*microtask_t2)(int *, int *, void *, void *);
-typedef void (*microtask_t3)(int *, int *, void *, void *, void *);
-typedef void (*microtask_t4)(int *, int *, void *, void *, void *, void *);
-typedef void (*microtask_t5)(int *, int *, void *, void *, void *, void *,
-                             void *);
-typedef void (*microtask_t6)(int *, int *, void *, void *, void *, void *,
-                             void *, void *);
-typedef void (*microtask_t7)(int *, int *, void *, void *, void *, void *,
-                             void *, void *, void *);
-typedef void (*microtask_t8)(int *, int *, void *, void *, void *, void *,
-                             void *, void *, void *, void *);
-typedef void (*microtask_t9)(int *, int *, void *, void *, void *, void *,
-                             void *, void *, void *, void *, void *);
-typedef void (*microtask_t10)(int *, int *, void *, void *, void *, void *,
-                              void *, void *, void *, void *, void *, void *);
-typedef void (*microtask_t11)(int *, int *, void *, void *, void *, void *,
-                              void *, void *, void *, void *, void *, void *,
-                              void *);
-typedef void (*microtask_t12)(int *, int *, void *, void *, void *, void *,
-                              void *, void *, void *, void *, void *, void *,
-                              void *, void *);
-typedef void (*microtask_t13)(int *, int *, void *, void *, void *, void *,
-                              void *, void *, void *, void *, void *, void *,
-                              void *, void *, void *);
-typedef void (*microtask_t14)(int *, int *, void *, void *, void *, void *,
-                              void *, void *, void *, void *, void *, void *,
-                              void *, void *, void *, void *);
-typedef void (*microtask_t15)(int *, int *, void *, void *, void *, void *,
-                              void *, void *, void *, void *, void *, void *,
-                              void *, void *, void *, void *, void *);
+template <size_t... Indices> struct microtask_index_sequence {};
 
-// we really only need the case with 1 argument, because CLANG always build
-// a struct of pointers to shared variables referenced in the outlined function
+template <size_t N, size_t... Indices>
+struct make_microtask_index_sequence
+    : make_microtask_index_sequence<N - 1, N - 1, Indices...> {};
+
+template <size_t... Indices>
+struct make_microtask_index_sequence<0, Indices...> {
+  using type = microtask_index_sequence<Indices...>;
+};
+
+template <size_t> using microtask_argument_t = void *;
+
+template <size_t... Indices>
+static void invokeMicrotask(microtask_t pkfn, int *gtid, int *tid,
+                            void *p_argv[],
+                            microtask_index_sequence<Indices...>) {
+  // WebAssembly's `call_indirect` requires the callee type to exactly match the
+  // call site. Cast the variadic microtask_t to the fixed-arity signature that
+  // matches argc before invoking it.
+  using typed_microtask_t =
+      void (*)(int *, int *, microtask_argument_t<Indices>...);
+  (*(typed_microtask_t)pkfn)(gtid, tid, p_argv[Indices]...);
+}
+
+// Keep a bounded set of exact signatures for targets that cannot dynamically
+// construct a variable-argument microtask call.
 int __kmp_invoke_microtask(microtask_t pkfn, int gtid, int tid, int argc,
                            void *p_argv[]
 #if OMPT_SUPPORT
@@ -55,85 +43,54 @@ int __kmp_invoke_microtask(microtask_t pkfn, int gtid, int tid, int argc,
   *exit_frame_ptr = OMPT_GET_FRAME_ADDRESS(0);
 #endif
 
+#define KMP_INVOKE_MICROTASK_CASE(N)                                           \
+  case N:                                                                      \
+    invokeMicrotask(pkfn, &gtid, &tid, p_argv,                                 \
+                    make_microtask_index_sequence<N>::type{});                 \
+    break
+
   switch (argc) {
+    KMP_INVOKE_MICROTASK_CASE(0);
+    KMP_INVOKE_MICROTASK_CASE(1);
+    KMP_INVOKE_MICROTASK_CASE(2);
+    KMP_INVOKE_MICROTASK_CASE(3);
+    KMP_INVOKE_MICROTASK_CASE(4);
+    KMP_INVOKE_MICROTASK_CASE(5);
+    KMP_INVOKE_MICROTASK_CASE(6);
+    KMP_INVOKE_MICROTASK_CASE(7);
+    KMP_INVOKE_MICROTASK_CASE(8);
+    KMP_INVOKE_MICROTASK_CASE(9);
+    KMP_INVOKE_MICROTASK_CASE(10);
+    KMP_INVOKE_MICROTASK_CASE(11);
+    KMP_INVOKE_MICROTASK_CASE(12);
+    KMP_INVOKE_MICROTASK_CASE(13);
+    KMP_INVOKE_MICROTASK_CASE(14);
+    KMP_INVOKE_MICROTASK_CASE(15);
+    KMP_INVOKE_MICROTASK_CASE(16);
+    KMP_INVOKE_MICROTASK_CASE(17);
+    KMP_INVOKE_MICROTASK_CASE(18);
+    KMP_INVOKE_MICROTASK_CASE(19);
+    KMP_INVOKE_MICROTASK_CASE(20);
+    KMP_INVOKE_MICROTASK_CASE(21);
+    KMP_INVOKE_MICROTASK_CASE(22);
+    KMP_INVOKE_MICROTASK_CASE(23);
+    KMP_INVOKE_MICROTASK_CASE(24);
+    KMP_INVOKE_MICROTASK_CASE(25);
+    KMP_INVOKE_MICROTASK_CASE(26);
+    KMP_INVOKE_MICROTASK_CASE(27);
+    KMP_INVOKE_MICROTASK_CASE(28);
+    KMP_INVOKE_MICROTASK_CASE(29);
+    KMP_INVOKE_MICROTASK_CASE(30);
+    KMP_INVOKE_MICROTASK_CASE(31);
+    KMP_INVOKE_MICROTASK_CASE(32);
   default:
     fprintf(stderr, "Too many args to microtask: %d!\n", argc);
     fflush(stderr);
     exit(-1);
-  case 0:
-    (*(microtask_t0)pkfn)(&gtid, &tid);
-    break;
-  case 1:
-    (*(microtask_t1)pkfn)(&gtid, &tid, p_argv[0]);
-    break;
-  case 2:
-    (*(microtask_t2)pkfn)(&gtid, &tid, p_argv[0], p_argv[1]);
-    break;
-  case 3:
-    (*(microtask_t3)pkfn)(&gtid, &tid, p_argv[0], p_argv[1], p_argv[2]);
-    break;
-  case 4:
-    (*(microtask_t4)pkfn)(&gtid, &tid, p_argv[0], p_argv[1], p_argv[2],
-                          p_argv[3]);
-    break;
-  case 5:
-    (*(microtask_t5)pkfn)(&gtid, &tid, p_argv[0], p_argv[1], p_argv[2],
-                          p_argv[3], p_argv[4]);
-    break;
-  case 6:
-    (*(microtask_t6)pkfn)(&gtid, &tid, p_argv[0], p_argv[1], p_argv[2],
-                          p_argv[3], p_argv[4], p_argv[5]);
-    break;
-  case 7:
-    (*(microtask_t7)pkfn)(&gtid, &tid, p_argv[0], p_argv[1], p_argv[2],
-                          p_argv[3], p_argv[4], p_argv[5], p_argv[6]);
-    break;
-  case 8:
-    (*(microtask_t8)pkfn)(&gtid, &tid, p_argv[0], p_argv[1], p_argv[2],
-                          p_argv[3], p_argv[4], p_argv[5], p_argv[6],
-                          p_argv[7]);
-    break;
-  case 9:
-    (*(microtask_t9)pkfn)(&gtid, &tid, p_argv[0], p_argv[1], p_argv[2],
-                          p_argv[3], p_argv[4], p_argv[5], p_argv[6], p_argv[7],
-                          p_argv[8]);
-    break;
-  case 10:
-    (*(microtask_t10)pkfn)(&gtid, &tid, p_argv[0], p_argv[1], p_argv[2],
-                           p_argv[3], p_argv[4], p_argv[5], p_argv[6],
-                           p_argv[7], p_argv[8], p_argv[9]);
-    break;
-  case 11:
-    (*(microtask_t11)pkfn)(&gtid, &tid, p_argv[0], p_argv[1], p_argv[2],
-                           p_argv[3], p_argv[4], p_argv[5], p_argv[6],
-                           p_argv[7], p_argv[8], p_argv[9], p_argv[10]);
-    break;
-  case 12:
-    (*(microtask_t12)pkfn)(&gtid, &tid, p_argv[0], p_argv[1], p_argv[2],
-                           p_argv[3], p_argv[4], p_argv[5], p_argv[6],
-                           p_argv[7], p_argv[8], p_argv[9], p_argv[10],
-                           p_argv[11]);
-    break;
-  case 13:
-    (*(microtask_t13)pkfn)(&gtid, &tid, p_argv[0], p_argv[1], p_argv[2],
-                           p_argv[3], p_argv[4], p_argv[5], p_argv[6],
-                           p_argv[7], p_argv[8], p_argv[9], p_argv[10],
-                           p_argv[11], p_argv[12]);
-    break;
-  case 14:
-    (*(microtask_t14)pkfn)(&gtid, &tid, p_argv[0], p_argv[1], p_argv[2],
-                           p_argv[3], p_argv[4], p_argv[5], p_argv[6],
-                           p_argv[7], p_argv[8], p_argv[9], p_argv[10],
-                           p_argv[11], p_argv[12], p_argv[13]);
-    break;
-  case 15:
-    (*(microtask_t15)pkfn)(&gtid, &tid, p_argv[0], p_argv[1], p_argv[2],
-                           p_argv[3], p_argv[4], p_argv[5], p_argv[6],
-                           p_argv[7], p_argv[8], p_argv[9], p_argv[10],
-                           p_argv[11], p_argv[12], p_argv[13], p_argv[14]);
-    break;
   }
 
+#undef KMP_INVOKE_MICROTASK_CASE
+
   return 1;
 }
 
diff --git a/openmp/runtime/test/misc_bugs/microtask-32-args.c b/openmp/runtime/test/misc_bugs/microtask-32-args.c
new file mode 100644
index 0000000000000..848ab7c368481
--- /dev/null
+++ b/openmp/runtime/test/misc_bugs/microtask-32-args.c
@@ -0,0 +1,56 @@
+// RUN: %libomp-compile-and-run
+
+// Exercise the upper bound supported by the generic microtask dispatcher.
+
+int main(void) {
+  volatile int value0 = 0;
+  volatile int value1 = 1;
+  volatile int value2 = 2;
+  volatile int value3 = 3;
+  volatile int value4 = 4;
+  volatile int value5 = 5;
+  volatile int value6 = 6;
+  volatile int value7 = 7;
+  volatile int value8 = 8;
+  volatile int value9 = 9;
+  volatile int value10 = 10;
+  volatile int value11 = 11;
+  volatile int value12 = 12;
+  volatile int value13 = 13;
+  volatile int value14 = 14;
+  volatile int value15 = 15;
+  volatile int value16 = 16;
+  volatile int value17 = 17;
+  volatile int value18 = 18;
+  volatile int value19 = 19;
+  volatile int value20 = 20;
+  volatile int value21 = 21;
+  volatile int value22 = 22;
+  volatile int value23 = 23;
+  volatile int value24 = 24;
+  volatile int value25 = 25;
+  volatile int value26 = 26;
+  volatile int value27 = 27;
+  volatile int value28 = 28;
+  volatile int value29 = 29;
+  volatile int value30 = 30;
+  volatile int value31 = 31;
+
+#pragma omp parallel num_threads(2)                                            \
+    shared(value0, value1, value2, value3, value4, value5, value6, value7,     \
+               value8, value9, value10, value11, value12, value13, value14,    \
+               value15, value16, value17, value18, value19, value20, value21,  \
+               value22, value23, value24, value25, value26, value27, value28,  \
+               value29, value30, value31)
+  {
+    int sum = value0 + value1 + value2 + value3 + value4 + value5 + value6 +
+              value7 + value8 + value9 + value10 + value11 + value12 + value13 +
+              value14 + value15 + value16 + value17 + value18 + value19 +
+              value20 + value21 + value22 + value23 + value24 + value25 +
+              value26 + value27 + value28 + value29 + value30 + value31;
+    if (sum != 496)
+      __builtin_trap();
+  }
+
+  return 0;
+}
diff --git a/openmp/runtime/test/misc_bugs/wasm-microtask-33-args.c b/openmp/runtime/test/misc_bugs/wasm-microtask-33-args.c
new file mode 100644
index 0000000000000..bb88fcb239777
--- /dev/null
+++ b/openmp/runtime/test/misc_bugs/wasm-microtask-33-args.c
@@ -0,0 +1,60 @@
+// REQUIRES: wasm32-target-arch
+// RUN: %libomp-compile
+// RUN: %not %libomp-run 2>&1 | FileCheck %s
+
+// CHECK: Too many args to microtask: 33!
+
+int main(void) {
+  volatile int value0 = 0;
+  volatile int value1 = 1;
+  volatile int value2 = 2;
+  volatile int value3 = 3;
+  volatile int value4 = 4;
+  volatile int value5 = 5;
+  volatile int value6 = 6;
+  volatile int value7 = 7;
+  volatile int value8 = 8;
+  volatile int value9 = 9;
+  volatile int value10 = 10;
+  volatile int value11 = 11;
+  volatile int value12 = 12;
+  volatile int value13 = 13;
+  volatile int value14 = 14;
+  volatile int value15 = 15;
+  volatile int value16 = 16;
+  volatile int value17 = 17;
+  volatile int value18 = 18;
+  volatile int value19 = 19;
+  volatile int value20 = 20;
+  volatile int value21 = 21;
+  volatile int value22 = 22;
+  volatile int value23 = 23;
+  volatile int value24 = 24;
+  volatile int value25 = 25;
+  volatile int value26 = 26;
+  volatile int value27 = 27;
+  volatile int value28 = 28;
+  volatile int value29 = 29;
+  volatile int value30 = 30;
+  volatile int value31 = 31;
+  volatile int value32 = 32;
+
+#pragma omp parallel num_threads(2)                                            \
+    shared(value0, value1, value2, value3, value4, value5, value6, value7,     \
+               value8, value9, value10, value11, value12, value13, value14,    \
+               value15, value16, value17, value18, value19, value20, value21,  \
+               value22, value23, value24, value25, value26, value27, value28,  \
+               value29, value30, value31, value32)
+  {
+    int sum = value0 + value1 + value2 + value3 + value4 + value5 + value6 +
+              value7 + value8 + value9 + value10 + value11 + value12 + value13 +
+              value14 + value15 + value16 + value17 + value18 + value19 +
+              value20 + value21 + value22 + value23 + value24 + value25 +
+              value26 + value27 + value28 + value29 + value30 + value31 +
+              value32;
+    if (sum != 528)
+      __builtin_trap();
+  }
+
+  return 0;
+}

>From 0d4675ceb222fac240640591567daf089a9f6f87 Mon Sep 17 00:00:00 2001
From: Andrew Snyder <asnyder at minitab.com>
Date: Tue, 21 Jul 2026 14:00:54 -0400
Subject: [PATCH 2/3] use make_index_sequence

---
 openmp/runtime/src/kmp_invoke_microtask.cpp | 19 ++++---------------
 1 file changed, 4 insertions(+), 15 deletions(-)

diff --git a/openmp/runtime/src/kmp_invoke_microtask.cpp b/openmp/runtime/src/kmp_invoke_microtask.cpp
index 474423b62188e..ec13eb8af7e97 100644
--- a/openmp/runtime/src/kmp_invoke_microtask.cpp
+++ b/openmp/runtime/src/kmp_invoke_microtask.cpp
@@ -1,27 +1,17 @@
 #include "kmp.h"
 
+#include <utility>
+
 #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_AARCH64_32)
 
-template <size_t... Indices> struct microtask_index_sequence {};
-
-template <size_t N, size_t... Indices>
-struct make_microtask_index_sequence
-    : make_microtask_index_sequence<N - 1, N - 1, Indices...> {};
-
-template <size_t... Indices>
-struct make_microtask_index_sequence<0, Indices...> {
-  using type = microtask_index_sequence<Indices...>;
-};
-
 template <size_t> using microtask_argument_t = void *;
 
 template <size_t... Indices>
 static void invokeMicrotask(microtask_t pkfn, int *gtid, int *tid,
-                            void *p_argv[],
-                            microtask_index_sequence<Indices...>) {
+                            void *p_argv[], std::index_sequence<Indices...>) {
   // WebAssembly's `call_indirect` requires the callee type to exactly match the
   // call site. Cast the variadic microtask_t to the fixed-arity signature that
   // matches argc before invoking it.
@@ -45,8 +35,7 @@ int __kmp_invoke_microtask(microtask_t pkfn, int gtid, int tid, int argc,
 
 #define KMP_INVOKE_MICROTASK_CASE(N)                                           \
   case N:                                                                      \
-    invokeMicrotask(pkfn, &gtid, &tid, p_argv,                                 \
-                    make_microtask_index_sequence<N>::type{});                 \
+    invokeMicrotask(pkfn, &gtid, &tid, p_argv, std::make_index_sequence<N>{}); \
     break
 
   switch (argc) {

>From 33ed4a3e001d2b52a24d678870ce6722f17b6a61 Mon Sep 17 00:00:00 2001
From: Andrew Snyder <asnyder at minitab.com>
Date: Tue, 21 Jul 2026 14:12:13 -0400
Subject: [PATCH 3/3] should work on arm64ec now

---
 openmp/runtime/test/misc_bugs/many-microtask-args.c | 5 -----
 1 file changed, 5 deletions(-)

diff --git a/openmp/runtime/test/misc_bugs/many-microtask-args.c b/openmp/runtime/test/misc_bugs/many-microtask-args.c
index 48ef2a0222d17..b91cfe542079f 100644
--- a/openmp/runtime/test/misc_bugs/many-microtask-args.c
+++ b/openmp/runtime/test/misc_bugs/many-microtask-args.c
@@ -1,10 +1,6 @@
 // RUN: %libomp-compile-and-run
 #include <stdio.h>
 
-// This test fails on Arm64EC as __kmp_invoke_microtask doesn't support more
-// than 16 arguments on that target.
-// XFAIL: arm64ec
-
 int main()
 {
 
@@ -40,4 +36,3 @@ int main()
 
   return 0;
 }
-



More information about the Openmp-commits mailing list