[llvm-branch-commits] [clang] [flang] [llvm] [OpenMP][Attributor] Infer noalias for host callback captures (PR #218453)

Tomas Matheson via llvm-branch-commits llvm-branch-commits at lists.llvm.org
Wed Aug 26 02:57:03 PDT 2026


https://github.com/tommat01 updated https://github.com/llvm/llvm-project/pull/218453

>From fd29f5508d4b90cbfca0ffb2a9be50b8c04ae918 Mon Sep 17 00:00:00 2001
From: Tomas Matheson <tomas.matheson at arm.com>
Date: Mon, 24 Aug 2026 11:07:25 +0100
Subject: [PATCH] [OpenMP] Seed noalias for host callback captures

The generic Attributor can derive noalias and the related lifetime facts for callback-mapped capture arguments, but OpenMPOpt does not seed AANoAlias in its restricted host run. Consequently capture-container loads remain in loops under dereferenceable-at-point semantics.

Seed AANoAlias for pointer arguments mapped to broker operands by callback metadata. Existing call-site reasoning checks every callback and direct call site and rejects escaped or aliased slots. LICM can then hoist immutable capture-container loads without changing the callback ABI or adding an OpenMP-specific hoisting transform.

Add LLVM, Clang, and Flang coverage for pointer, scalar, and aggregate captures together with escaped, duplicated, unmapped, and unknown-use negatives.
---
 clang/test/OpenMP/bug54082.c                  | 20 +++---
 .../test/OpenMP/callback_capture_lifetime.cpp | 29 ++++++++
 .../OpenMP/callback-capture-lifetime.f90      | 40 +++++++++++
 llvm/lib/Transforms/IPO/OpenMPOpt.cpp         | 21 +++++-
 .../OpenMP/callback-capture-licm.ll           | 67 +++++++++++++++++++
 .../Transforms/OpenMP/callback-noalias.ll     | 34 ++++++++++
 .../Transforms/OpenMP/parallel_deletion.ll    | 10 +--
 .../OpenMP/parallel_region_merging.ll         | 12 ++--
 8 files changed, 209 insertions(+), 24 deletions(-)
 create mode 100644 clang/test/OpenMP/callback_capture_lifetime.cpp
 create mode 100644 flang/test/Integration/OpenMP/callback-capture-lifetime.f90
 create mode 100644 llvm/test/Transforms/OpenMP/callback-capture-licm.ll
 create mode 100644 llvm/test/Transforms/OpenMP/callback-noalias.ll

diff --git a/clang/test/OpenMP/bug54082.c b/clang/test/OpenMP/bug54082.c
index 6b8c93e9ffc96..b317a88d8aacb 100644
--- a/clang/test/OpenMP/bug54082.c
+++ b/clang/test/OpenMP/bug54082.c
@@ -69,43 +69,41 @@ void foo() {
 // CHECK-NEXT:    [[X_TRAITS:%.*]] = alloca [1 x [[STRUCT_OMP_ALLOCTRAIT_T:%.*]]], align 16
 // CHECK-NEXT:    [[X_ALLOC:%.*]] = alloca i64, align 8
 // CHECK-NEXT:    call void @llvm.lifetime.start.p0(ptr nonnull [[X_TRAITS]]) #[[ATTR4:[0-9]+]]
-// CHECK-NEXT:    call void @llvm.memcpy.p0.p0.i64(ptr noundef nonnull align 16 dereferenceable(16) [[X_TRAITS]], ptr noundef nonnull align 16 dereferenceable(16) @__const.foo.x_traits, i64 16, i1 false)
+// CHECK-NEXT:    call void @llvm.memcpy.p0.p0.i64(ptr noundef nonnull writeonly align 16 dereferenceable(16) [[X_TRAITS]], ptr noundef nonnull readonly align 16 dereferenceable(16) @__const.foo.x_traits, i64 16, i1 false)
 // CHECK-NEXT:    call void @llvm.lifetime.start.p0(ptr nonnull [[X_ALLOC]]) #[[ATTR4]]
 // CHECK-NEXT:    [[CALL:%.*]] = call i64 @omp_init_allocator(i64 noundef 0, i32 noundef 1, ptr noundef nonnull [[X_TRAITS]]) #[[ATTR4]]
 // CHECK-NEXT:    store i64 [[CALL]], ptr [[X_ALLOC]], align 8, !tbaa [[LONG_TBAA7:![0-9]+]]
-// CHECK-NEXT:    call void (ptr, i32, ptr, ...) @__kmpc_fork_call(ptr nonnull @[[GLOB2:[0-9]+]], i32 1, ptr nonnull @foo.omp_outlined, ptr nonnull [[X_ALLOC]])
+// CHECK-NEXT:    call void (ptr, i32, ptr, ...) @__kmpc_fork_call(ptr nonnull @[[GLOB2:[0-9]+]], i32 1, ptr nonnull @foo.omp_outlined, ptr noalias nonnull readonly captures(none) [[X_ALLOC]])
 // CHECK-NEXT:    call void @llvm.lifetime.end.p0(ptr nonnull [[X_ALLOC]]) #[[ATTR4]]
 // CHECK-NEXT:    call void @llvm.lifetime.end.p0(ptr nonnull [[X_TRAITS]]) #[[ATTR4]]
 // CHECK-NEXT:    ret void
 //
 //
 // CHECK-LABEL: define internal void @foo.omp_outlined(
-// CHECK-SAME: ptr noalias nofree noundef readonly captures(none) [[DOTGLOBAL_TID_:%.*]], ptr noalias nofree readnone captures(none) [[DOTBOUND_TID_:%.*]], ptr nofree noundef nonnull readonly align 8 captures(none) dereferenceable(8) [[X_ALLOC:%.*]]) #[[ATTR3:[0-9]+]] {
+// CHECK-SAME: ptr noalias nofree noundef readonly captures(none) [[DOTGLOBAL_TID_:%.*]], ptr noalias nofree readnone captures(none) [[DOTBOUND_TID_:%.*]], ptr noalias noundef nonnull readonly align 8 captures(none) dereferenceable(8) [[X_ALLOC:%.*]]) #[[ATTR3:[0-9]+]] {
 // CHECK-NEXT:  [[ENTRY:.*:]]
 // CHECK-NEXT:    [[DOTOMP_LB:%.*]] = alloca i32, align 4
 // CHECK-NEXT:    [[DOTOMP_UB:%.*]] = alloca i32, align 4
 // CHECK-NEXT:    [[DOTOMP_STRIDE:%.*]] = alloca i32, align 4
 // CHECK-NEXT:    [[DOTOMP_IS_LAST:%.*]] = alloca i32, align 4
-// CHECK-NEXT:    call void @llvm.lifetime.start.p0(ptr nonnull [[DOTOMP_LB]]) #[[ATTR4]]
+// CHECK-NEXT:    call void @llvm.lifetime.start.p0(ptr nonnull [[DOTOMP_LB]]) #[[ATTR6:[0-9]+]]
 // CHECK-NEXT:    store i32 0, ptr [[DOTOMP_LB]], align 4, !tbaa [[INT_TBAA9:![0-9]+]]
-// CHECK-NEXT:    call void @llvm.lifetime.start.p0(ptr nonnull [[DOTOMP_UB]]) #[[ATTR4]]
+// CHECK-NEXT:    call void @llvm.lifetime.start.p0(ptr nonnull [[DOTOMP_UB]]) #[[ATTR6]]
 // CHECK-NEXT:    store i32 1023, ptr [[DOTOMP_UB]], align 4, !tbaa [[INT_TBAA9]]
-// CHECK-NEXT:    call void @llvm.lifetime.start.p0(ptr nonnull [[DOTOMP_STRIDE]]) #[[ATTR4]]
+// CHECK-NEXT:    call void @llvm.lifetime.start.p0(ptr nonnull [[DOTOMP_STRIDE]]) #[[ATTR6]]
 // CHECK-NEXT:    store i32 1, ptr [[DOTOMP_STRIDE]], align 4, !tbaa [[INT_TBAA9]]
-// CHECK-NEXT:    call void @llvm.lifetime.start.p0(ptr nonnull [[DOTOMP_IS_LAST]]) #[[ATTR4]]
+// CHECK-NEXT:    call void @llvm.lifetime.start.p0(ptr nonnull [[DOTOMP_IS_LAST]]) #[[ATTR6]]
 // CHECK-NEXT:    store i32 0, ptr [[DOTOMP_IS_LAST]], align 4, !tbaa [[INT_TBAA9]]
 // CHECK-NEXT:    [[TMP0:%.*]] = load i32, ptr [[DOTGLOBAL_TID_]], align 4, !tbaa [[INT_TBAA9]]
 // CHECK-NEXT:    [[TMP1:%.*]] = load i64, ptr [[X_ALLOC]], align 8, !tbaa [[LONG_TBAA7]]
 // CHECK-NEXT:    [[CONV:%.*]] = inttoptr i64 [[TMP1]] to ptr
-// CHECK-NEXT:    [[DOTX__VOID_ADDR:%.*]] = tail call ptr @__kmpc_alloc(i32 [[TMP0]], i64 8, ptr [[CONV]])
+// CHECK-NEXT:    [[DOTX__VOID_ADDR:%.*]] = tail call ptr @__kmpc_alloc(i32 [[TMP0]], i64 8, ptr [[CONV]]) #[[ATTR4]]
 // CHECK-NEXT:    call void @__kmpc_for_static_init_4(ptr nonnull @[[GLOB1:[0-9]+]], i32 [[TMP0]], i32 34, ptr nonnull [[DOTOMP_IS_LAST]], ptr nonnull [[DOTOMP_LB]], ptr nonnull [[DOTOMP_UB]], ptr nonnull [[DOTOMP_STRIDE]], i32 1, i32 1)
 // CHECK-NEXT:    [[TMP2:%.*]] = load i32, ptr [[DOTOMP_UB]], align 4, !tbaa [[INT_TBAA9]]
 // CHECK-NEXT:    [[COND:%.*]] = call i32 @llvm.smin.i32(i32 [[TMP2]], i32 1023)
 // CHECK-NEXT:    store i32 [[COND]], ptr [[DOTOMP_UB]], align 4, !tbaa [[INT_TBAA9]]
 // CHECK-NEXT:    call void @__kmpc_for_static_fini(ptr nonnull @[[GLOB1]], i32 [[TMP0]])
-// CHECK-NEXT:    [[TMP3:%.*]] = load i64, ptr [[X_ALLOC]], align 8, !tbaa [[LONG_TBAA7]]
-// CHECK-NEXT:    [[CONV5:%.*]] = inttoptr i64 [[TMP3]] to ptr
-// CHECK-NEXT:    call void @__kmpc_free(i32 [[TMP0]], ptr [[DOTX__VOID_ADDR]], ptr [[CONV5]])
+// CHECK-NEXT:    call void @__kmpc_free(i32 [[TMP0]], ptr [[DOTX__VOID_ADDR]], ptr [[CONV]])
 // CHECK-NEXT:    call void @llvm.lifetime.end.p0(ptr nonnull [[DOTOMP_IS_LAST]]) #[[ATTR4]]
 // CHECK-NEXT:    call void @llvm.lifetime.end.p0(ptr nonnull [[DOTOMP_STRIDE]]) #[[ATTR4]]
 // CHECK-NEXT:    call void @llvm.lifetime.end.p0(ptr nonnull [[DOTOMP_UB]]) #[[ATTR4]]
diff --git a/clang/test/OpenMP/callback_capture_lifetime.cpp b/clang/test/OpenMP/callback_capture_lifetime.cpp
new file mode 100644
index 0000000000000..4e75c53197c93
--- /dev/null
+++ b/clang/test/OpenMP/callback_capture_lifetime.cpp
@@ -0,0 +1,29 @@
+// NOTE: Assertions have been autogenerated by utils/update_cc_test_checks.py UTC_ARGS: --functions ".*omp_outlined$" --filter "define internal void" --filter "load ptr, ptr" --filter "@opaque" --filter "getelementptr" --include-generated-funcs --version 6
+// Verify end-to-end that Clang's host OpenMP pipeline infers noalias for a
+// captured pointer container and hoists its load out of a loop containing an
+// unrelated call.
+// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -O2 -fopenmp -x c++ \
+// RUN:   -emit-llvm -o - %s | FileCheck %s
+
+extern bool enabled[64];
+extern "C" void opaque();
+extern "C" void use(double);
+
+void use_enabled(double *values) {
+#pragma omp parallel
+  for (int i = 0; i < 64; ++i) {
+    opaque();
+    if (enabled[i])
+      use(values[i]);
+  }
+}
+// CHECK-LABEL: define dso_local void @_Z11use_enabledPd(
+// CHECK-SAME: ptr noundef [[VALUES:%.*]]) local_unnamed_addr #[[ATTR0:[0-9]+]] {
+//
+// CHECK-LABEL: define internal void @_Z11use_enabledPd.omp_outlined(
+// CHECK-SAME: ptr noalias nofree readnone captures(none) [[DOTGLOBAL_TID_:%.*]], ptr noalias nofree readnone captures(none) [[DOTBOUND_TID_:%.*]], ptr noalias noundef nonnull readonly align 8 captures(none) dereferenceable(8) [[VALUES:%.*]]) #[[ATTR1:[0-9]+]] {
+// CHECK:    [[TMP0:%.*]] = load ptr, ptr [[VALUES]], align 8
+// CHECK:    tail call void @opaque() #[[ATTR3:[0-9]+]]
+// CHECK:    [[ARRAYIDX:%.*]] = getelementptr inbounds nuw i8, ptr @enabled, i64 [[INDVARS_IV:%.*]]
+// CHECK:    [[ARRAYIDX2:%.*]] = getelementptr inbounds nuw [8 x i8], ptr [[TMP0]], i64 [[INDVARS_IV]]
+//
diff --git a/flang/test/Integration/OpenMP/callback-capture-lifetime.f90 b/flang/test/Integration/OpenMP/callback-capture-lifetime.f90
new file mode 100644
index 0000000000000..b824ddcba00c1
--- /dev/null
+++ b/flang/test/Integration/OpenMP/callback-capture-lifetime.f90
@@ -0,0 +1,40 @@
+!===----------------------------------------------------------------------===!
+! This directory can be used to add Integration tests involving multiple
+! stages of the compiler (for eg. from Fortran to LLVM IR). It should not
+! contain executable tests. We should only add tests here sparingly and only
+! if there is no other way to test. Repeat this message in each test that is
+! added to this directory and sub-directories.
+!===----------------------------------------------------------------------===!
+
+! Verify that host OpenMPOpt infers noalias for Flang's aggregate capture
+! container, allowing both captured addresses to be loaded before an opaque
+! call.
+!
+! RUN: %flang_fc1 -O2 -fopenmp -emit-llvm %s -o - | FileCheck %s
+
+subroutine capture_lifetime(first, second)
+  integer(8), intent(in) :: first, second
+
+  interface
+    subroutine opaque()
+    end subroutine
+    subroutine use_value(value)
+      integer(8), value :: value
+    end subroutine
+  end interface
+
+  !$omp parallel shared(first, second)
+  call opaque()
+  call use_value(first)
+  call use_value(second)
+  !$omp end parallel
+end subroutine
+
+! CHECK-LABEL: define internal void @capture_lifetime_..omp_par(
+! CHECK-SAME: ptr noalias readonly captures(none) [[CAPTURES:%.*]])
+! CHECK: [[FIRST:%.*]] = load ptr, ptr [[CAPTURES]], align 8
+! CHECK-NEXT: [[SECOND_FIELD:%.*]] = getelementptr i8, ptr [[CAPTURES]], i64 8
+! CHECK-NEXT: [[SECOND:%.*]] = load ptr, ptr [[SECOND_FIELD]], align 8
+! CHECK-NEXT: tail call void @opaque_()
+! CHECK: load i64, ptr [[FIRST]], align 8
+! CHECK: load i64, ptr [[SECOND]], align 8
diff --git a/llvm/lib/Transforms/IPO/OpenMPOpt.cpp b/llvm/lib/Transforms/IPO/OpenMPOpt.cpp
index 22a5efb402504..0fff56cf17ced 100644
--- a/llvm/lib/Transforms/IPO/OpenMPOpt.cpp
+++ b/llvm/lib/Transforms/IPO/OpenMPOpt.cpp
@@ -5627,10 +5627,27 @@ void OpenMPOpt::registerAAs(bool IsModulePass) {
     }
   }
 
+  // Seed the generic noalias deduction for callback-mapped pointer arguments
+  // in host regions. It will inspect every callback and direct call site before
+  // manifesting the attribute.
+  if (!isOpenMPDevice(M)) {
+    for (Function *F : SCC) {
+      if (F->isDeclaration())
+        continue;
+      for (Use &U : F->uses()) {
+        AbstractCallSite ACS(&U);
+        if (!ACS || !ACS.isCallbackCall())
+          continue;
+        for (Argument &Arg : F->args())
+          if (Arg.getType()->isPointerTy() && ACS.getCallArgOperandNo(Arg) >= 0)
+            A.getOrCreateAAFor<AANoAlias>(IRPosition::argument(Arg));
+      }
+    }
+    return;
+  }
+
   // Create an ExecutionDomain AA for every function and a HeapToStack AA for
   // every function if there is a device kernel.
-  if (!isOpenMPDevice(M))
-    return;
 
   for (auto *F : SCC) {
     if (F->isDeclaration())
diff --git a/llvm/test/Transforms/OpenMP/callback-capture-licm.ll b/llvm/test/Transforms/OpenMP/callback-capture-licm.ll
new file mode 100644
index 0000000000000..086ec1972393c
--- /dev/null
+++ b/llvm/test/Transforms/OpenMP/callback-capture-licm.ll
@@ -0,0 +1,67 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --function outlined --version 6
+; Verify that noalias inferred for host callback capture storage lets LICM
+; hoist its load out of a loop containing an unknown call.
+;
+; RUN: opt -passes='openmp-opt,function(loop-mssa(licm))' -S < %s | FileCheck %s
+
+target triple = "aarch64-unknown-linux-gnu"
+
+define void @run(ptr %value) {
+  %capture = alloca ptr, align 8
+  store ptr %value, ptr %capture, align 8
+  call void (ptr, i32, ptr, ...) @__kmpc_fork_call(ptr null, i32 1, ptr @outlined, ptr %capture)
+  ret void
+}
+
+define internal void @outlined(ptr %global_tid, ptr %bound_tid, ptr align 8 dereferenceable(8) %capture) {
+; CHECK-LABEL: define internal void @outlined(
+; CHECK-SAME: ptr [[GLOBAL_TID:%.*]], ptr [[BOUND_TID:%.*]], ptr noalias readonly align 8 captures(none) dereferenceable(8) [[CAPTURE:%.*]]) {
+; CHECK-NEXT:  [[ENTRY:.*]]:
+; CHECK-NEXT:    [[VALUE:%.*]] = load ptr, ptr [[CAPTURE]], align 8
+; CHECK-NEXT:    br label %[[LOOP:.*]]
+; CHECK:       [[LOOP]]:
+; CHECK-NEXT:    [[INDEX:%.*]] = phi i64 [ 0, %[[ENTRY]] ], [ [[NEXT:%.*]], %[[LATCH:.*]] ]
+; CHECK-NEXT:    call void @opaque()
+; CHECK-NEXT:    [[ENABLED:%.*]] = icmp eq i64 [[INDEX]], 7
+; CHECK-NEXT:    br i1 [[ENABLED]], label %[[IF_THEN:.*]], label %[[LATCH]]
+; CHECK:       [[IF_THEN]]:
+; CHECK-NEXT:    call void @use(ptr [[VALUE]])
+; CHECK-NEXT:    br label %[[LATCH]]
+; CHECK:       [[LATCH]]:
+; CHECK-NEXT:    [[NEXT]] = add nuw nsw i64 [[INDEX]], 1
+; CHECK-NEXT:    [[DONE:%.*]] = icmp eq i64 [[NEXT]], 64
+; CHECK-NEXT:    br i1 [[DONE]], label %[[EXIT:.*]], label %[[LOOP]]
+; CHECK:       [[EXIT]]:
+; CHECK-NEXT:    ret void
+;
+entry:
+  br label %loop
+
+loop:
+  %index = phi i64 [ 0, %entry ], [ %next, %latch ]
+  call void @opaque()
+  %enabled = icmp eq i64 %index, 7
+  br i1 %enabled, label %if.then, label %latch
+
+if.then:
+  %value = load ptr, ptr %capture, align 8
+  call void @use(ptr %value)
+  br label %latch
+
+latch:
+  %next = add nuw nsw i64 %index, 1
+  %done = icmp eq i64 %next, 64
+  br i1 %done, label %exit, label %loop
+
+exit:
+  ret void
+}
+
+declare !callback !0 void @__kmpc_fork_call(ptr, i32, ptr, ...)
+declare void @opaque()
+declare void @use(ptr) memory(none)
+
+!0 = !{!1}
+!1 = !{i64 2, i64 -1, i64 -1, i1 true}
+!llvm.module.flags = !{!2}
+!2 = !{i32 7, !"openmp", i32 51}
diff --git a/llvm/test/Transforms/OpenMP/callback-noalias.ll b/llvm/test/Transforms/OpenMP/callback-noalias.ll
new file mode 100644
index 0000000000000..aee80f31a7235
--- /dev/null
+++ b/llvm/test/Transforms/OpenMP/callback-noalias.ll
@@ -0,0 +1,34 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --function outlined --version 6
+; Verify that host OpenMPOpt seeds noalias reasoning for a callback argument
+; mapped to capture storage by callback metadata.
+;
+; RUN: opt -passes=openmp-opt -S < %s | FileCheck %s
+
+target triple = "aarch64-unknown-linux-gnu"
+
+define void @run(i64 %value) {
+  %capture = alloca i64, align 8
+  store i64 %value, ptr %capture, align 8
+  call void (ptr, i32, ptr, ...) @__kmpc_fork_call(ptr null, i32 1, ptr @outlined, ptr %capture)
+  ret void
+}
+
+define internal void @outlined(ptr %global_tid, ptr %bound_tid, ptr align 8 dereferenceable(8) %capture) {
+; CHECK-LABEL: define internal void @outlined(
+; CHECK-SAME: ptr [[GLOBAL_TID:%.*]], ptr [[BOUND_TID:%.*]], ptr noalias readonly align 8 captures(none) dereferenceable(8) [[CAPTURE:%.*]]) #[[ATTR1:[0-9]+]] {
+; CHECK-NEXT:    [[VALUE:%.*]] = load i64, ptr [[CAPTURE]], align 8
+; CHECK-NEXT:    call void @use(i64 [[VALUE]]) #[[ATTR3:[0-9]+]]
+; CHECK-NEXT:    ret void
+;
+  %value = load i64, ptr %capture, align 8
+  call void @use(i64 %value)
+  ret void
+}
+
+declare !callback !0 void @__kmpc_fork_call(ptr, i32, ptr, ...)
+declare void @use(i64) memory(none)
+
+!0 = !{!1}
+!1 = !{i64 2, i64 -1, i64 -1, i1 true}
+!llvm.module.flags = !{!2}
+!2 = !{i32 7, !"openmp", i32 51}
diff --git a/llvm/test/Transforms/OpenMP/parallel_deletion.ll b/llvm/test/Transforms/OpenMP/parallel_deletion.ll
index c362cebeda9b0..7003f81756ac9 100644
--- a/llvm/test/Transforms/OpenMP/parallel_deletion.ll
+++ b/llvm/test/Transforms/OpenMP/parallel_deletion.ll
@@ -386,7 +386,7 @@ define internal void @.omp_outlined..4(ptr noalias %.global_tid., ptr noalias %.
 ; CHECK-SAME: (ptr noalias nofree noundef nonnull readonly align 4 captures(none) dereferenceable(4) [[DOTGLOBAL_TID_:%.*]], ptr noalias nofree readnone captures(none) [[DOTBOUND_TID_:%.*]], ptr nofree noundef nonnull align 4 captures(none) dereferenceable(4) [[A:%.*]]) {
 ; CHECK-NEXT:  entry:
 ; CHECK-NEXT:    [[TMP:%.*]] = load i32, ptr [[DOTGLOBAL_TID_]], align 4, !invariant.load [[META1:![0-9]+]]
-; CHECK-NEXT:    [[TMP1:%.*]] = call i32 @__kmpc_master(ptr noundef nonnull @[[GLOB0]], i32 [[TMP]])
+; CHECK-NEXT:    [[TMP1:%.*]] = call i32 @__kmpc_master(ptr noundef nonnull @[[GLOB0]], i32 [[TMP]]) #[[ATTR9:[0-9]+]]
 ; CHECK-NEXT:    [[TMP2:%.*]] = icmp eq i32 [[TMP1]], 0
 ; CHECK-NEXT:    br i1 [[TMP2]], label [[OMP_IF_END:%.*]], label [[OMP_IF_THEN:%.*]]
 ; CHECK:       omp_if.then:
@@ -459,7 +459,7 @@ define internal void @.omp_outlined..5(ptr noalias %.global_tid., ptr noalias %.
 ; CHECK-NEXT:  entry:
 ; CHECK-NEXT:    [[OMP_GLOBAL_THREAD_NUM:%.*]] = call i32 @__kmpc_global_thread_num(ptr noundef nonnull @[[GLOB0]]) #[[ATTR19]]
 ; CHECK-NEXT:    [[TMP:%.*]] = load i32, ptr [[DOTGLOBAL_TID_]], align 4, !invariant.load [[META1]]
-; CHECK-NEXT:    [[TMP1:%.*]] = call i32 @__kmpc_single(ptr noundef nonnull @[[GLOB0]], i32 [[TMP]])
+; CHECK-NEXT:    [[TMP1:%.*]] = call i32 @__kmpc_single(ptr noundef nonnull @[[GLOB0]], i32 [[TMP]]) #[[ATTR9]]
 ; CHECK-NEXT:    [[TMP2:%.*]] = icmp eq i32 [[TMP1]], 0
 ; CHECK-NEXT:    br i1 [[TMP2]], label [[OMP_IF_END:%.*]], label [[OMP_IF_THEN:%.*]]
 ; CHECK:       omp_if.then:
@@ -527,7 +527,7 @@ omp_if.end:                                       ; preds = %entry, %omp_if.then
 
 define internal void @.omp_outlined..6(ptr noalias %.global_tid., ptr noalias %.bound_tid., ptr dereferenceable(4) %a) {
 ; CHECK-LABEL: define {{[^@]+}}@.omp_outlined..6
-; CHECK-SAME: (ptr noalias nofree noundef nonnull readonly align 4 captures(none) dereferenceable(4) [[DOTGLOBAL_TID_:%.*]], ptr noalias nofree readnone captures(none) [[DOTBOUND_TID_:%.*]], ptr nofree noundef nonnull align 4 captures(none) dereferenceable(4) [[A:%.*]]) {
+; CHECK-SAME: (ptr noalias nofree noundef nonnull readonly align 4 captures(none) dereferenceable(4) [[DOTGLOBAL_TID_:%.*]], ptr noalias nofree readnone captures(none) [[DOTBOUND_TID_:%.*]], ptr nofree noundef nonnull align 4 captures(none) dereferenceable(4) [[A:%.*]]) #[[ATTR9]] {
 ; CHECK-NEXT:  entry:
 ; CHECK-NEXT:    [[A1:%.*]] = alloca i32, align 4
 ; CHECK-NEXT:    [[DOTOMP_REDUCTION_RED_LIST:%.*]] = alloca [1 x ptr], align 8
@@ -535,7 +535,7 @@ define internal void @.omp_outlined..6(ptr noalias %.global_tid., ptr noalias %.
 ; CHECK-NEXT:    store i32 1, ptr [[A1]], align 4
 ; CHECK-NEXT:    store ptr [[A1]], ptr [[DOTOMP_REDUCTION_RED_LIST]], align 8
 ; CHECK-NEXT:    [[TMP2:%.*]] = load i32, ptr [[DOTGLOBAL_TID_]], align 4, !invariant.load [[META1]]
-; CHECK-NEXT:    [[TMP4:%.*]] = call i32 @__kmpc_reduce_nowait(ptr noundef nonnull @[[GLOB2:[0-9]+]], i32 [[TMP2]], i32 noundef 1, i64 noundef 8, ptr noundef nonnull align 8 [[DOTOMP_REDUCTION_RED_LIST]], ptr noundef nonnull @.omp.reduction.reduction_func, ptr noundef nonnull @.gomp_critical_user_.reduction.var)
+; CHECK-NEXT:    [[TMP4:%.*]] = call i32 @__kmpc_reduce_nowait(ptr noundef nonnull @[[GLOB2:[0-9]+]], i32 [[TMP2]], i32 noundef 1, i64 noundef 8, ptr noundef nonnull align 8 [[DOTOMP_REDUCTION_RED_LIST]], ptr noundef nonnull @.omp.reduction.reduction_func, ptr noundef nonnull @.gomp_critical_user_.reduction.var) #[[ATTR9]]
 ; CHECK-NEXT:    switch i32 [[TMP4]], label [[DOTOMP_REDUCTION_DEFAULT:%.*]] [
 ; CHECK-NEXT:      i32 1, label [[DOTOMP_REDUCTION_CASE1:%.*]]
 ; CHECK-NEXT:      i32 2, label [[DOTOMP_REDUCTION_CASE2:%.*]]
@@ -545,7 +545,7 @@ define internal void @.omp_outlined..6(ptr noalias %.global_tid., ptr noalias %.
 ; CHECK-NEXT:    [[TMP6:%.*]] = load i32, ptr [[A1]], align 4
 ; CHECK-NEXT:    [[ADD:%.*]] = add nsw i32 [[TMP5]], [[TMP6]]
 ; CHECK-NEXT:    store i32 [[ADD]], ptr [[A]], align 4
-; CHECK-NEXT:    call void @__kmpc_end_reduce_nowait(ptr noundef nonnull @[[GLOB2]], i32 [[TMP2]], ptr noundef nonnull @.gomp_critical_user_.reduction.var)
+; CHECK-NEXT:    call void @__kmpc_end_reduce_nowait(ptr noundef nonnull @[[GLOB2]], i32 [[TMP2]], ptr noundef nonnull @.gomp_critical_user_.reduction.var) #[[ATTR9]]
 ; CHECK-NEXT:    br label [[DOTOMP_REDUCTION_DEFAULT]]
 ; CHECK:       .omp.reduction.case2:
 ; CHECK-NEXT:    [[TMP7:%.*]] = load i32, ptr [[A1]], align 4
diff --git a/llvm/test/Transforms/OpenMP/parallel_region_merging.ll b/llvm/test/Transforms/OpenMP/parallel_region_merging.ll
index 6d3e5935d2e11..312a4ec8be74b 100644
--- a/llvm/test/Transforms/OpenMP/parallel_region_merging.ll
+++ b/llvm/test/Transforms/OpenMP/parallel_region_merging.ll
@@ -5252,12 +5252,12 @@ entry:
 ; CHECK2:       omp.par.pre_finalize:
 ; CHECK2-NEXT:    br label [[DOTFINI:%.*]]
 ; CHECK2:       .fini:
-; CHECK2-NEXT:    call void @llvm.lifetime.end.p0(ptr noundef nonnull [[B]])
+; CHECK2-NEXT:    call void @llvm.lifetime.end.p0(ptr noundef nonnull captures(none) [[B]])
 ; CHECK2-NEXT:    br label [[OMP_PAR_EXIT_EXITSTUB:%.*]]
 ; CHECK2:       omp_region.body:
 ; CHECK2-NEXT:    br label [[SEQ_PAR_MERGED:%.*]]
 ; CHECK2:       seq.par.merged:
-; CHECK2-NEXT:    call void @llvm.lifetime.start.p0(ptr noundef nonnull align 4 dereferenceable(4) [[B]])
+; CHECK2-NEXT:    call void @llvm.lifetime.start.p0(ptr noundef nonnull align 4 captures(none) dereferenceable(4) [[B]])
 ; CHECK2-NEXT:    [[ADD:%.*]] = add nsw i32 [[TMP2]], 1
 ; CHECK2-NEXT:    store i32 [[ADD]], ptr [[B]], align 4
 ; CHECK2-NEXT:    br label [[OMP_PAR_MERGED_SPLIT:%.*]]
@@ -5352,7 +5352,7 @@ entry:
 ; CHECK2-NEXT:    br i1 [[TOBOOL_NOT]], label [[IF_END:%.*]], label [[IF_THEN:%.*]]
 ; CHECK2:       if.then:
 ; CHECK2-NEXT:    [[TMP1:%.*]] = load i32, ptr [[DOTGLOBAL_TID_]], align 4, !invariant.load [[META7:![0-9]+]]
-; CHECK2-NEXT:    [[TMP2:%.*]] = call i32 @__kmpc_cancel(ptr noundef nonnull @[[GLOB1]], i32 [[TMP1]], i32 noundef 1)
+; CHECK2-NEXT:    [[TMP2:%.*]] = call i32 @__kmpc_cancel(ptr noundef nonnull @[[GLOB1]], i32 [[TMP1]], i32 noundef 1) #[[ATTR0]]
 ; CHECK2-NEXT:    ret void
 ; CHECK2:       if.end:
 ; CHECK2-NEXT:    ret void
@@ -5366,7 +5366,7 @@ entry:
 ; CHECK2-NEXT:    br i1 [[TOBOOL_NOT]], label [[IF_END:%.*]], label [[IF_THEN:%.*]]
 ; CHECK2:       if.then:
 ; CHECK2-NEXT:    [[TMP1:%.*]] = load i32, ptr [[DOTGLOBAL_TID_]], align 4, !invariant.load [[META7]]
-; CHECK2-NEXT:    [[TMP2:%.*]] = call i32 @__kmpc_cancel(ptr noundef nonnull @[[GLOB1]], i32 [[TMP1]], i32 noundef 1)
+; CHECK2-NEXT:    [[TMP2:%.*]] = call i32 @__kmpc_cancel(ptr noundef nonnull @[[GLOB1]], i32 [[TMP1]], i32 noundef 1) #[[ATTR0]]
 ; CHECK2-NEXT:    ret void
 ; CHECK2:       if.end:
 ; CHECK2-NEXT:    ret void
@@ -5464,7 +5464,7 @@ entry:
 ; CHECK2-NEXT:    br i1 [[TOBOOL_NOT]], label [[IF_END:%.*]], label [[IF_THEN:%.*]]
 ; CHECK2:       if.then:
 ; CHECK2-NEXT:    [[TMP1:%.*]] = load i32, ptr [[DOTGLOBAL_TID_]], align 4, !invariant.load [[META7]]
-; CHECK2-NEXT:    [[TMP2:%.*]] = call i32 @__kmpc_cancel(ptr noundef nonnull @[[GLOB1]], i32 [[TMP1]], i32 noundef 1)
+; CHECK2-NEXT:    [[TMP2:%.*]] = call i32 @__kmpc_cancel(ptr noundef nonnull @[[GLOB1]], i32 [[TMP1]], i32 noundef 1) #[[ATTR0]]
 ; CHECK2-NEXT:    ret void
 ; CHECK2:       if.end:
 ; CHECK2-NEXT:    ret void
@@ -5478,7 +5478,7 @@ entry:
 ; CHECK2-NEXT:    br i1 [[TOBOOL_NOT]], label [[IF_END:%.*]], label [[IF_THEN:%.*]]
 ; CHECK2:       if.then:
 ; CHECK2-NEXT:    [[TMP1:%.*]] = load i32, ptr [[DOTGLOBAL_TID_]], align 4, !invariant.load [[META7]]
-; CHECK2-NEXT:    [[TMP2:%.*]] = call i32 @__kmpc_cancel(ptr noundef nonnull @[[GLOB1]], i32 [[TMP1]], i32 noundef 1)
+; CHECK2-NEXT:    [[TMP2:%.*]] = call i32 @__kmpc_cancel(ptr noundef nonnull @[[GLOB1]], i32 [[TMP1]], i32 noundef 1) #[[ATTR0]]
 ; CHECK2-NEXT:    ret void
 ; CHECK2:       if.end:
 ; CHECK2-NEXT:    ret void



More information about the llvm-branch-commits mailing list