[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:32:04 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, >id, &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)(>id, &tid);
- break;
- case 1:
- (*(microtask_t1)pkfn)(>id, &tid, p_argv[0]);
- break;
- case 2:
- (*(microtask_t2)pkfn)(>id, &tid, p_argv[0], p_argv[1]);
- break;
- case 3:
- (*(microtask_t3)pkfn)(>id, &tid, p_argv[0], p_argv[1], p_argv[2]);
- break;
- case 4:
- (*(microtask_t4)pkfn)(>id, &tid, p_argv[0], p_argv[1], p_argv[2],
- p_argv[3]);
- break;
- case 5:
- (*(microtask_t5)pkfn)(>id, &tid, p_argv[0], p_argv[1], p_argv[2],
- p_argv[3], p_argv[4]);
- break;
- case 6:
- (*(microtask_t6)pkfn)(>id, &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)(>id, &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)(>id, &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)(>id, &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)(>id, &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)(>id, &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)(>id, &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)(>id, &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)(>id, &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)(>id, &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, >id, &tid, p_argv, \
- make_microtask_index_sequence<N>::type{}); \
+ invokeMicrotask(pkfn, >id, &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