Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 9 additions & 11 deletions clang/test/OpenMP/bug54082.c
Original file line number Diff line number Diff line change
Expand Up @@ -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]]
Expand Down
29 changes: 29 additions & 0 deletions clang/test/OpenMP/callback_capture_lifetime.cpp
Original file line number Diff line number Diff line change
@@ -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]]
//
40 changes: 40 additions & 0 deletions flang/test/Integration/OpenMP/callback-capture-lifetime.f90
Original file line number Diff line number Diff line change
@@ -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
21 changes: 19 additions & 2 deletions llvm/lib/Transforms/IPO/OpenMPOpt.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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())
Expand Down
67 changes: 67 additions & 0 deletions llvm/test/Transforms/OpenMP/callback-capture-licm.ll
Original file line number Diff line number Diff line change
@@ -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}
34 changes: 34 additions & 0 deletions llvm/test/Transforms/OpenMP/callback-noalias.ll
Original file line number Diff line number Diff line change
@@ -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}
10 changes: 5 additions & 5 deletions llvm/test/Transforms/OpenMP/parallel_deletion.ll
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down Expand Up @@ -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:
Expand Down Expand Up @@ -527,15 +527,15 @@ 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
; CHECK-NEXT: call void @llvm.lifetime.start.p0(ptr noundef nonnull align 4 [[A1]]) #[[ATTR20:[0-9]+]]
; 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:%.*]]
Expand All @@ -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
Expand Down
Loading
Loading