llvm-project/llvm/test/Transforms/OpenMP/parallel_deletion.ll
Nikita Popov c23b4fbdbb
[IR] Remove size argument from lifetime intrinsics (#150248)
Now that #149310 has restricted lifetime intrinsics to only work on
allocas, we can also drop the explicit size argument. Instead, the size
is implied by the alloca.

This removes the ability to only mark a prefix of an alloca alive/dead.
We never used that capability, so we should remove the need to handle
that possibility everywhere (though many key places, including stack
coloring, did not actually respect this).
2025-08-08 11:09:34 +02:00

720 lines
41 KiB
LLVM

; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --function-signature
; RUN: opt -S -passes='attributor,cgscc(openmp-opt-cgscc)' < %s | FileCheck %s
;
target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128"
%struct.ident_t = type { i32, i32, i32, i32, ptr }
@.str = private unnamed_addr constant [23 x i8] c";unknown;unknown;0;0;;\00", align 1
@0 = private unnamed_addr global %struct.ident_t { i32 0, i32 2, i32 0, i32 0, ptr @.str }, align 8
@1 = private unnamed_addr global %struct.ident_t { i32 0, i32 322, i32 0, i32 0, ptr @.str }, align 8
@.gomp_critical_user_.reduction.var = common global [8 x i32] zeroinitializer
@2 = private unnamed_addr global %struct.ident_t { i32 0, i32 18, i32 0, i32 0, ptr @.str }, align 8
; void delete_parallel_0(void) {
; #pragma omp parallel
; { unknown_willreturn(); }
; #pragma omp parallel
; { readonly_willreturn(); }
; #pragma omp parallel
; { readnone_willreturn(); }
; #pragma omp parallel
; {}
; }
;
; We delete all but the first of the parallel regions in this test.
define void @delete_parallel_0() {
; CHECK-LABEL: define {{[^@]+}}@delete_parallel_0() {
; CHECK-NEXT: entry:
; CHECK-NEXT: call void (ptr, i32, ptr, ...) @__kmpc_fork_call(ptr noundef nonnull align 8 dereferenceable(24) @[[GLOB0:[0-9]+]], i32 noundef 0, ptr noundef nonnull @.omp_outlined.willreturn)
; CHECK-NEXT: ret void
;
; CHECK1-LABEL: define {{[^@]+}}@delete_parallel_0() {
; CHECK1-NEXT: entry:
; CHECK1-NEXT: call void (ptr, i32, ptr, ...) @__kmpc_fork_call(ptr noundef nonnull align 8 dereferenceable(24) @[[GLOB0:[0-9]+]], i32 noundef 0, ptr noundef @.omp_outlined.willreturn)
; CHECK1-NEXT: ret void
; CHECK2-LABEL: define {{[^@]+}}@delete_parallel_0() {
; CHECK2-NEXT: entry:
; CHECK2-NEXT: call void (ptr, i32, ptr, ...) @__kmpc_fork_call(ptr noundef nonnull align 8 dereferenceable(24) @[[GLOB0:[0-9]+]], i32 noundef 0, ptr noundef @.omp_outlined.willreturn)
; CHECK2-NEXT: ret void
entry:
call void (ptr, i32, ptr, ...) @__kmpc_fork_call(ptr nonnull @0, i32 0, ptr @.omp_outlined.willreturn)
call void (ptr, i32, ptr, ...) @__kmpc_fork_call(ptr nonnull @0, i32 0, ptr @.omp_outlined.willreturn.0)
call void (ptr, i32, ptr, ...) @__kmpc_fork_call(ptr nonnull @0, i32 0, ptr @.omp_outlined.willreturn.1)
call void (ptr, i32, ptr, ...) @__kmpc_fork_call(ptr nonnull @0, i32 0, ptr @.omp_outlined.willreturn.2)
ret void
}
define internal void @.omp_outlined.willreturn(ptr noalias %.global_tid., ptr noalias %.bound_tid.) {
; CHECK-LABEL: define {{[^@]+}}@.omp_outlined.willreturn
; CHECK-SAME: (ptr noalias nofree readnone captures(none) [[DOTGLOBAL_TID_:%.*]], ptr noalias nofree readnone captures(none) [[DOTBOUND_TID_:%.*]]) #[[ATTR0:[0-9]+]] {
; CHECK-NEXT: entry:
; CHECK-NEXT: call void @unknown() #[[ATTR15:[0-9]+]]
; CHECK-NEXT: ret void
;
; CHECK1-LABEL: define {{[^@]+}}@.omp_outlined.willreturn
; CHECK1-SAME: (ptr noalias nocapture nofree readnone [[DOTGLOBAL_TID_:%.*]], ptr noalias nocapture nofree readnone [[DOTBOUND_TID_:%.*]]) #[[ATTR0:[0-9]+]] {
; CHECK1-NEXT: entry:
; CHECK1-NEXT: call void @unknown() #[[ATTR0]]
; CHECK1-NEXT: ret void
; CHECK2-LABEL: define {{[^@]+}}@.omp_outlined.willreturn
; CHECK2-SAME: (ptr noalias nocapture nofree readnone [[DOTGLOBAL_TID_:%.*]], ptr noalias nocapture nofree readnone [[DOTBOUND_TID_:%.*]]) #[[ATTR0:[0-9]+]] {
; CHECK2-NEXT: entry:
; CHECK2-NEXT: call void @unknown() #[[ATTR0]]
; CHECK2-NEXT: ret void
entry:
call void @unknown() willreturn
ret void
}
define internal void @.omp_outlined.willreturn.0(ptr noalias %.global_tid., ptr noalias %.bound_tid.) willreturn {
; CHECK-LABEL: define {{[^@]+}}@.omp_outlined.willreturn.0
; CHECK-SAME: (ptr noalias nofree readnone captures(none) [[DOTGLOBAL_TID_:%.*]], ptr noalias nofree readnone captures(none) [[DOTBOUND_TID_:%.*]]) #[[ATTR1:[0-9]+]] {
; CHECK-NEXT: entry:
; CHECK-NEXT: call void @readonly() #[[ATTR4:[0-9]+]]
; CHECK-NEXT: ret void
;
; CHECK1-LABEL: define {{[^@]+}}@.omp_outlined.willreturn.0
; CHECK1-SAME: (ptr noalias nocapture nofree readnone [[DOTGLOBAL_TID_:%.*]], ptr noalias nocapture nofree readnone [[DOTBOUND_TID_:%.*]]) #[[ATTR1:[0-9]+]] {
; CHECK1-NEXT: entry:
; CHECK1-NEXT: call void @readonly() #[[ATTR4:[0-9]+]]
; CHECK1-NEXT: ret void
; CHECK2-LABEL: define {{[^@]+}}@.omp_outlined.willreturn.0
; CHECK2-SAME: (ptr noalias nocapture nofree readnone [[DOTGLOBAL_TID_:%.*]], ptr noalias nocapture nofree readnone [[DOTBOUND_TID_:%.*]]) #[[ATTR1:[0-9]+]] {
; CHECK2-NEXT: entry:
; CHECK2-NEXT: call void @readonly() #[[ATTR4:[0-9]+]]
; CHECK2-NEXT: ret void
entry:
call void @readonly()
ret void
}
define internal void @.omp_outlined.willreturn.1(ptr noalias %.global_tid., ptr noalias %.bound_tid.) {
; CHECK-LABEL: define {{[^@]+}}@.omp_outlined.willreturn.1
; CHECK-SAME: (ptr noalias nofree readnone captures(none) [[DOTGLOBAL_TID_:%.*]], ptr noalias nofree readnone captures(none) [[DOTBOUND_TID_:%.*]]) #[[ATTR2:[0-9]+]] {
; CHECK-NEXT: entry:
; CHECK-NEXT: call void @readnone() #[[ATTR16:[0-9]+]]
; CHECK-NEXT: ret void
;
; CHECK1-LABEL: define {{[^@]+}}@.omp_outlined.willreturn.1
; CHECK1-SAME: (ptr noalias nocapture nofree readnone [[DOTGLOBAL_TID_:%.*]], ptr noalias nocapture nofree readnone [[DOTBOUND_TID_:%.*]]) #[[ATTR2:[0-9]+]] {
; CHECK1-NEXT: entry:
; CHECK1-NEXT: call void @readnone() #[[ATTR0]]
; CHECK1-NEXT: ret void
; CHECK2-LABEL: define {{[^@]+}}@.omp_outlined.willreturn.1
; CHECK2-SAME: (ptr noalias nocapture nofree readnone [[DOTGLOBAL_TID_:%.*]], ptr noalias nocapture nofree readnone [[DOTBOUND_TID_:%.*]]) #[[ATTR2:[0-9]+]] {
; CHECK2-NEXT: entry:
; CHECK2-NEXT: call void @readnone() #[[ATTR0]]
; CHECK2-NEXT: ret void
entry:
call void @readnone() willreturn
ret void
}
define internal void @.omp_outlined.willreturn.2(ptr noalias %.global_tid., ptr noalias %.bound_tid.) {
; CHECK-LABEL: define {{[^@]+}}@.omp_outlined.willreturn.2
; CHECK-SAME: (ptr noalias nofree readnone captures(none) [[DOTGLOBAL_TID_:%.*]], ptr noalias nofree readnone captures(none) [[DOTBOUND_TID_:%.*]]) #[[ATTR3:[0-9]+]] {
; CHECK-NEXT: entry:
; CHECK-NEXT: ret void
;
; CHECK1-LABEL: define {{[^@]+}}@.omp_outlined.willreturn.2
; CHECK1-SAME: (ptr noalias nocapture nofree readnone [[DOTGLOBAL_TID_:%.*]], ptr noalias nocapture nofree readnone [[DOTBOUND_TID_:%.*]]) #[[ATTR3:[0-9]+]] {
; CHECK1-NEXT: entry:
; CHECK1-NEXT: ret void
; CHECK2-LABEL: define {{[^@]+}}@.omp_outlined.willreturn.2
; CHECK2-SAME: (ptr noalias nocapture nofree readnone [[DOTGLOBAL_TID_:%.*]], ptr noalias nocapture nofree readnone [[DOTBOUND_TID_:%.*]]) #[[ATTR3:[0-9]+]] {
; CHECK2-NEXT: entry:
; CHECK2-NEXT: ret void
entry:
ret void
}
; void delete_parallel_1(void) {
; #pragma omp parallel
; { unknown(); }
; #pragma omp parallel
; { readonly(); }
; #pragma omp parallel
; { readnone(); }
; #pragma omp parallel
; {}
; }
;
; We delete only the last parallel regions in this test because the others might not return.
define void @delete_parallel_1() {
; CHECK-LABEL: define {{[^@]+}}@delete_parallel_1() {
; CHECK-NEXT: entry:
; CHECK-NEXT: call void (ptr, i32, ptr, ...) @__kmpc_fork_call(ptr noundef nonnull align 8 dereferenceable(24) @[[GLOB0]], i32 noundef 0, ptr noundef nonnull @.omp_outlined.)
; CHECK-NEXT: call void (ptr, i32, ptr, ...) @__kmpc_fork_call(ptr noundef nonnull align 8 dereferenceable(24) @[[GLOB0]], i32 noundef 0, ptr noundef nonnull @.omp_outlined..0)
; CHECK-NEXT: call void (ptr, i32, ptr, ...) @__kmpc_fork_call(ptr noundef nonnull align 8 dereferenceable(24) @[[GLOB0]], i32 noundef 0, ptr noundef nonnull @.omp_outlined..1)
; CHECK-NEXT: ret void
;
; CHECK1-LABEL: define {{[^@]+}}@delete_parallel_1() {
; CHECK1-NEXT: entry:
; CHECK1-NEXT: call void (ptr, i32, ptr, ...) @__kmpc_fork_call(ptr noundef nonnull align 8 dereferenceable(24) @[[GLOB0]], i32 noundef 0, ptr noundef @.omp_outlined.)
; CHECK1-NEXT: call void (ptr, i32, ptr, ...) @__kmpc_fork_call(ptr noundef nonnull align 8 dereferenceable(24) @[[GLOB0]], i32 noundef 0, ptr noundef @.omp_outlined..0)
; CHECK1-NEXT: call void (ptr, i32, ptr, ...) @__kmpc_fork_call(ptr noundef nonnull align 8 dereferenceable(24) @[[GLOB0]], i32 noundef 0, ptr noundef @.omp_outlined..1)
; CHECK1-NEXT: ret void
; CHECK2-LABEL: define {{[^@]+}}@delete_parallel_1() {
; CHECK2-NEXT: entry:
; CHECK2-NEXT: call void (ptr, i32, ptr, ...) @__kmpc_fork_call(ptr noundef nonnull align 8 dereferenceable(24) @[[GLOB0]], i32 noundef 0, ptr noundef @.omp_outlined.)
; CHECK2-NEXT: call void (ptr, i32, ptr, ...) @__kmpc_fork_call(ptr noundef nonnull align 8 dereferenceable(24) @[[GLOB0]], i32 noundef 0, ptr noundef @.omp_outlined..0)
; CHECK2-NEXT: call void (ptr, i32, ptr, ...) @__kmpc_fork_call(ptr noundef nonnull align 8 dereferenceable(24) @[[GLOB0]], i32 noundef 0, ptr noundef @.omp_outlined..1)
; CHECK2-NEXT: ret void
entry:
call void (ptr, i32, ptr, ...) @__kmpc_fork_call(ptr nonnull @0, i32 0, ptr @.omp_outlined.)
call void (ptr, i32, ptr, ...) @__kmpc_fork_call(ptr nonnull @0, i32 0, ptr @.omp_outlined..0)
call void (ptr, i32, ptr, ...) @__kmpc_fork_call(ptr nonnull @0, i32 0, ptr @.omp_outlined..1)
call void (ptr, i32, ptr, ...) @__kmpc_fork_call(ptr nonnull @0, i32 0, ptr @.omp_outlined..2)
ret void
}
define internal void @.omp_outlined.(ptr noalias %.global_tid., ptr noalias %.bound_tid.) {
; CHECK-LABEL: define {{[^@]+}}@.omp_outlined.
; CHECK-SAME: (ptr noalias nofree readnone captures(none) [[DOTGLOBAL_TID_:%.*]], ptr noalias nofree readnone captures(none) [[DOTBOUND_TID_:%.*]]) {
; CHECK-NEXT: entry:
; CHECK-NEXT: call void @unknown()
; CHECK-NEXT: ret void
;
; CHECK1-LABEL: define {{[^@]+}}@.omp_outlined.
; CHECK1-SAME: (ptr noalias nocapture nofree readnone [[DOTGLOBAL_TID_:%.*]], ptr noalias nocapture nofree readnone [[DOTBOUND_TID_:%.*]]) {
; CHECK1-NEXT: entry:
; CHECK1-NEXT: call void @unknown()
; CHECK1-NEXT: ret void
; CHECK2-LABEL: define {{[^@]+}}@.omp_outlined.
; CHECK2-SAME: (ptr noalias nocapture nofree readnone [[DOTGLOBAL_TID_:%.*]], ptr noalias nocapture nofree readnone [[DOTBOUND_TID_:%.*]]) {
; CHECK2-NEXT: entry:
; CHECK2-NEXT: call void @unknown()
; CHECK2-NEXT: ret void
entry:
call void @unknown()
ret void
}
define internal void @.omp_outlined..0(ptr noalias %.global_tid., ptr noalias %.bound_tid.) {
; CHECK-LABEL: define {{[^@]+}}@.omp_outlined..0
; CHECK-SAME: (ptr noalias nofree readnone captures(none) [[DOTGLOBAL_TID_:%.*]], ptr noalias nofree readnone captures(none) [[DOTBOUND_TID_:%.*]]) #[[ATTR4]] {
; CHECK-NEXT: entry:
; CHECK-NEXT: call void @readonly() #[[ATTR4]]
; CHECK-NEXT: ret void
;
; CHECK1-LABEL: define {{[^@]+}}@.omp_outlined..0
; CHECK1-SAME: (ptr noalias nocapture nofree readnone [[DOTGLOBAL_TID_:%.*]], ptr noalias nocapture nofree readnone [[DOTBOUND_TID_:%.*]]) #[[ATTR4]] {
; CHECK1-NEXT: entry:
; CHECK1-NEXT: call void @readonly() #[[ATTR4]]
; CHECK1-NEXT: ret void
; CHECK2-LABEL: define {{[^@]+}}@.omp_outlined..0
; CHECK2-SAME: (ptr noalias nocapture nofree readnone [[DOTGLOBAL_TID_:%.*]], ptr noalias nocapture nofree readnone [[DOTBOUND_TID_:%.*]]) #[[ATTR4]] {
; CHECK2-NEXT: entry:
; CHECK2-NEXT: call void @readonly() #[[ATTR4]]
; CHECK2-NEXT: ret void
entry:
call void @readonly()
ret void
}
define internal void @.omp_outlined..1(ptr noalias %.global_tid., ptr noalias %.bound_tid.) {
; CHECK-LABEL: define {{[^@]+}}@.omp_outlined..1
; CHECK-SAME: (ptr noalias nofree readnone captures(none) [[DOTGLOBAL_TID_:%.*]], ptr noalias nofree readnone captures(none) [[DOTBOUND_TID_:%.*]]) #[[ATTR5:[0-9]+]] {
; CHECK-NEXT: entry:
; CHECK-NEXT: call void @readnone() #[[ATTR17:[0-9]+]]
; CHECK-NEXT: ret void
;
; CHECK1-LABEL: define {{[^@]+}}@.omp_outlined..1
; CHECK1-SAME: (ptr noalias nocapture nofree readnone [[DOTGLOBAL_TID_:%.*]], ptr noalias nocapture nofree readnone [[DOTBOUND_TID_:%.*]]) #[[ATTR5:[0-9]+]] {
; CHECK1-NEXT: entry:
; CHECK1-NEXT: call void @readnone()
; CHECK1-NEXT: ret void
; CHECK2-LABEL: define {{[^@]+}}@.omp_outlined..1
; CHECK2-SAME: (ptr noalias nocapture nofree readnone [[DOTGLOBAL_TID_:%.*]], ptr noalias nocapture nofree readnone [[DOTBOUND_TID_:%.*]]) #[[ATTR5:[0-9]+]] {
; CHECK2-NEXT: entry:
; CHECK2-NEXT: call void @readnone()
; CHECK2-NEXT: ret void
entry:
call void @readnone()
ret void
}
define internal void @.omp_outlined..2(ptr noalias %.global_tid., ptr noalias %.bound_tid.) {
; CHECK-LABEL: define {{[^@]+}}@.omp_outlined..2
; CHECK-SAME: (ptr noalias nofree readnone captures(none) [[DOTGLOBAL_TID_:%.*]], ptr noalias nofree readnone captures(none) [[DOTBOUND_TID_:%.*]]) #[[ATTR3]] {
; CHECK-NEXT: entry:
; CHECK-NEXT: ret void
;
; CHECK1-LABEL: define {{[^@]+}}@.omp_outlined..2
; CHECK1-SAME: (ptr noalias nocapture nofree readnone [[DOTGLOBAL_TID_:%.*]], ptr noalias nocapture nofree readnone [[DOTBOUND_TID_:%.*]]) #[[ATTR3]] {
; CHECK1-NEXT: entry:
; CHECK1-NEXT: ret void
; CHECK2-LABEL: define {{[^@]+}}@.omp_outlined..2
; CHECK2-SAME: (ptr noalias nocapture nofree readnone [[DOTGLOBAL_TID_:%.*]], ptr noalias nocapture nofree readnone [[DOTBOUND_TID_:%.*]]) #[[ATTR3]] {
; CHECK2-NEXT: entry:
; CHECK2-NEXT: ret void
entry:
ret void
}
; void delete_parallel_2(void) {
; int a = 0;
; #pragma omp parallel
; {
; if (omp_get_thread_num() == 0)
; ++a;
; }
; #pragma omp parallel
; {
; #pragma omp master
; ++a;
; }
; #pragma omp parallel
; {
; #pragma omp single
; ++a;
; }
; #pragma omp parallel reduction(+: a)
; {
; ++a;
; }
; }
;
; FIXME: We do not realize that `a` is dead and all accesses to it can be removed
; making the parallel regions readonly and deletable.
define void @delete_parallel_2() {
; CHECK-LABEL: define {{[^@]+}}@delete_parallel_2() {
; CHECK-NEXT: entry:
; CHECK-NEXT: [[A:%.*]] = alloca i32, align 4
; CHECK-NEXT: call void @llvm.lifetime.start.p0(ptr noundef nonnull align 4 dereferenceable(4) [[A]]) #[[ATTR18:[0-9]+]]
; CHECK-NEXT: store i32 0, ptr [[A]], align 4
; CHECK-NEXT: call void (ptr, i32, ptr, ...) @__kmpc_fork_call(ptr noundef nonnull align 8 dereferenceable(24) @[[GLOB0]], i32 noundef 1, ptr noundef nonnull @.omp_outlined..3, ptr nofree noundef nonnull align 4 captures(none) dereferenceable(4) [[A]])
; CHECK-NEXT: call void (ptr, i32, ptr, ...) @__kmpc_fork_call(ptr noundef nonnull align 8 dereferenceable(24) @[[GLOB0]], i32 noundef 1, ptr noundef nonnull @.omp_outlined..4, ptr nofree noundef nonnull align 4 captures(none) dereferenceable(4) [[A]])
; CHECK-NEXT: call void (ptr, i32, ptr, ...) @__kmpc_fork_call(ptr noundef nonnull align 8 dereferenceable(24) @[[GLOB0]], i32 noundef 1, ptr noundef nonnull @.omp_outlined..5, ptr nofree noundef nonnull align 4 captures(none) dereferenceable(4) [[A]])
; CHECK-NEXT: call void (ptr, i32, ptr, ...) @__kmpc_fork_call(ptr noundef nonnull align 8 dereferenceable(24) @[[GLOB0]], i32 noundef 1, ptr noundef nonnull @.omp_outlined..6, ptr noundef nonnull align 4 captures(none) dereferenceable(4) [[A]])
; CHECK-NEXT: call void @llvm.lifetime.end.p0(ptr noundef nonnull [[A]])
; CHECK-NEXT: ret void
;
; CHECK1-LABEL: define {{[^@]+}}@delete_parallel_2() {
; CHECK1-NEXT: entry:
; CHECK1-NEXT: [[A:%.*]] = alloca i32, align 4
; CHECK1-NEXT: call void @llvm.lifetime.start.p0(ptr noundef nonnull align 4 dereferenceable(4) [[A]]) #[[ATTR0]]
; CHECK1-NEXT: store i32 0, ptr [[A]], align 4
; CHECK1-NEXT: call void (ptr, i32, ptr, ...) @__kmpc_fork_call(ptr noundef nonnull align 8 dereferenceable(24) @[[GLOB0]], i32 noundef 1, ptr noundef @.omp_outlined..3, ptr nocapture nofree noundef nonnull align 4 dereferenceable(4) [[A]])
; CHECK1-NEXT: call void (ptr, i32, ptr, ...) @__kmpc_fork_call(ptr noundef nonnull align 8 dereferenceable(24) @[[GLOB0]], i32 noundef 1, ptr noundef @.omp_outlined..4, ptr nocapture nofree noundef nonnull align 4 dereferenceable(4) [[A]])
; CHECK1-NEXT: call void (ptr, i32, ptr, ...) @__kmpc_fork_call(ptr noundef nonnull align 8 dereferenceable(24) @[[GLOB0]], i32 noundef 1, ptr noundef @.omp_outlined..5, ptr nocapture nofree noundef nonnull align 4 dereferenceable(4) [[A]])
; CHECK1-NEXT: call void (ptr, i32, ptr, ...) @__kmpc_fork_call(ptr noundef nonnull align 8 dereferenceable(24) @[[GLOB0]], i32 noundef 1, ptr noundef @.omp_outlined..6, ptr nocapture noundef nonnull align 4 dereferenceable(4) [[A]])
; CHECK1-NEXT: call void @llvm.lifetime.end.p0(ptr noundef nonnull [[A]])
; CHECK1-NEXT: ret void
; CHECK2-LABEL: define {{[^@]+}}@delete_parallel_2() {
; CHECK2-NEXT: entry:
; CHECK2-NEXT: [[A:%.*]] = alloca i32, align 4
; CHECK2-NEXT: call void @llvm.lifetime.start.p0(ptr noundef nonnull align 4 dereferenceable(4) [[A]]) #[[ATTR0]]
; CHECK2-NEXT: store i32 0, ptr [[A]], align 4
; CHECK2-NEXT: call void (ptr, i32, ptr, ...) @__kmpc_fork_call(ptr noundef nonnull align 8 dereferenceable(24) @[[GLOB0]], i32 noundef 1, ptr noundef @.omp_outlined..3, ptr nocapture nofree noundef nonnull align 4 dereferenceable(4) [[A]])
; CHECK2-NEXT: call void (ptr, i32, ptr, ...) @__kmpc_fork_call(ptr noundef nonnull align 8 dereferenceable(24) @[[GLOB0]], i32 noundef 1, ptr noundef @.omp_outlined..4, ptr nocapture nofree noundef nonnull align 4 dereferenceable(4) [[A]])
; CHECK2-NEXT: call void (ptr, i32, ptr, ...) @__kmpc_fork_call(ptr noundef nonnull align 8 dereferenceable(24) @[[GLOB0]], i32 noundef 1, ptr noundef @.omp_outlined..5, ptr nocapture nofree noundef nonnull align 4 dereferenceable(4) [[A]])
; CHECK2-NEXT: call void (ptr, i32, ptr, ...) @__kmpc_fork_call(ptr noundef nonnull align 8 dereferenceable(24) @[[GLOB0]], i32 noundef 1, ptr noundef @.omp_outlined..6, ptr nocapture noundef nonnull align 4 dereferenceable(4) [[A]])
; CHECK2-NEXT: call void @llvm.lifetime.end.p0(ptr noundef nonnull [[A]])
; CHECK2-NEXT: ret void
entry:
%a = alloca i32, align 4
call void @llvm.lifetime.start.p0(ptr nonnull %a)
store i32 0, ptr %a, align 4
call void (ptr, i32, ptr, ...) @__kmpc_fork_call(ptr nonnull @0, i32 1, ptr @.omp_outlined..3, ptr nonnull %a)
call void (ptr, i32, ptr, ...) @__kmpc_fork_call(ptr nonnull @0, i32 1, ptr @.omp_outlined..4, ptr nonnull %a)
call void (ptr, i32, ptr, ...) @__kmpc_fork_call(ptr nonnull @0, i32 1, ptr @.omp_outlined..5, ptr nonnull %a)
call void (ptr, i32, ptr, ...) @__kmpc_fork_call(ptr nonnull @0, i32 1, ptr @.omp_outlined..6, ptr nonnull %a)
call void @llvm.lifetime.end.p0(ptr nonnull %a)
ret void
}
define internal void @.omp_outlined..3(ptr noalias %.global_tid., ptr noalias %.bound_tid., ptr dereferenceable(4) %a) {
; CHECK-LABEL: define {{[^@]+}}@.omp_outlined..3
; CHECK-SAME: (ptr noalias nofree readnone captures(none) [[DOTGLOBAL_TID_:%.*]], ptr noalias nofree readnone captures(none) [[DOTBOUND_TID_:%.*]], ptr nofree noundef nonnull align 4 captures(none) dereferenceable(4) [[A:%.*]]) #[[ATTR6:[0-9]+]] {
; CHECK-NEXT: entry:
; CHECK-NEXT: [[CALL:%.*]] = call i32 @omp_get_thread_num() #[[ATTR19:[0-9]+]]
; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[CALL]], 0
; CHECK-NEXT: br i1 [[CMP]], label [[IF_THEN:%.*]], label [[IF_END:%.*]]
; CHECK: if.then:
; CHECK-NEXT: [[TMP:%.*]] = load i32, ptr [[A]], align 4
; CHECK-NEXT: [[INC:%.*]] = add nsw i32 [[TMP]], 1
; CHECK-NEXT: store i32 [[INC]], ptr [[A]], align 4
; CHECK-NEXT: br label [[IF_END]]
; CHECK: if.end:
; CHECK-NEXT: ret void
;
; CHECK1-LABEL: define {{[^@]+}}@.omp_outlined..3
; CHECK1-SAME: (ptr noalias nocapture nofree readnone [[DOTGLOBAL_TID_:%.*]], ptr noalias nocapture nofree readnone [[DOTBOUND_TID_:%.*]], ptr nocapture nofree noundef nonnull align 4 dereferenceable(4) [[A:%.*]]) #[[ATTR6:[0-9]+]] {
; CHECK1-NEXT: entry:
; CHECK1-NEXT: [[CALL:%.*]] = call i32 @omp_get_thread_num() #[[ATTR14:[0-9]+]]
; CHECK1-NEXT: [[CMP:%.*]] = icmp eq i32 [[CALL]], 0
; CHECK1-NEXT: br i1 [[CMP]], label [[IF_THEN:%.*]], label [[IF_END:%.*]]
; CHECK1: if.then:
; CHECK1-NEXT: [[TMP:%.*]] = load i32, ptr [[A]], align 4
; CHECK1-NEXT: [[INC:%.*]] = add nsw i32 [[TMP]], 1
; CHECK1-NEXT: store i32 [[INC]], ptr [[A]], align 4
; CHECK1-NEXT: br label [[IF_END]]
; CHECK1: if.end:
; CHECK1-NEXT: ret void
; CHECK2-LABEL: define {{[^@]+}}@.omp_outlined..3
; CHECK2-SAME: (ptr noalias nocapture nofree readnone [[DOTGLOBAL_TID_:%.*]], ptr noalias nocapture nofree readnone [[DOTBOUND_TID_:%.*]], ptr nocapture nofree noundef nonnull align 4 dereferenceable(4) [[A:%.*]]) #[[ATTR6:[0-9]+]] {
; CHECK2-NEXT: entry:
; CHECK2-NEXT: [[CALL:%.*]] = call i32 @omp_get_thread_num() #[[ATTR14:[0-9]+]]
; CHECK2-NEXT: [[CMP:%.*]] = icmp eq i32 [[CALL]], 0
; CHECK2-NEXT: br i1 [[CMP]], label [[IF_THEN:%.*]], label [[IF_END:%.*]]
; CHECK2: if.then:
; CHECK2-NEXT: [[TMP:%.*]] = load i32, ptr [[A]], align 4
; CHECK2-NEXT: [[INC:%.*]] = add nsw i32 [[TMP]], 1
; CHECK2-NEXT: store i32 [[INC]], ptr [[A]], align 4
; CHECK2-NEXT: br label [[IF_END]]
; CHECK2: if.end:
; CHECK2-NEXT: ret void
entry:
%call = call i32 @omp_get_thread_num()
%cmp = icmp eq i32 %call, 0
br i1 %cmp, label %if.then, label %if.end
if.then: ; preds = %entry
%tmp = load i32, ptr %a, align 4
%inc = add nsw i32 %tmp, 1
store i32 %inc, ptr %a, align 4
br label %if.end
if.end: ; preds = %if.then, %entry
ret void
}
define internal void @.omp_outlined..4(ptr noalias %.global_tid., ptr noalias %.bound_tid., ptr dereferenceable(4) %a) {
; CHECK-LABEL: define {{[^@]+}}@.omp_outlined..4
; 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
; CHECK-NEXT: [[TMP1:%.*]] = call i32 @__kmpc_master(ptr noundef nonnull @[[GLOB0]], i32 [[TMP]])
; 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:
; CHECK-NEXT: [[TMP3:%.*]] = load i32, ptr [[A]], align 4
; CHECK-NEXT: [[INC:%.*]] = add nsw i32 [[TMP3]], 1
; CHECK-NEXT: store i32 [[INC]], ptr [[A]], align 4
; CHECK-NEXT: call void @__kmpc_end_master(ptr noundef nonnull @[[GLOB0]], i32 [[TMP]])
; CHECK-NEXT: br label [[OMP_IF_END]]
; CHECK: omp_if.end:
; CHECK-NEXT: ret void
;
; CHECK1-LABEL: define {{[^@]+}}@.omp_outlined..4
; CHECK1-SAME: (ptr noalias nocapture nofree noundef nonnull readonly align 4 dereferenceable(4) [[DOTGLOBAL_TID_:%.*]], ptr noalias nocapture nofree readnone [[DOTBOUND_TID_:%.*]], ptr nocapture nofree noundef nonnull align 4 dereferenceable(4) [[A:%.*]]) {
; CHECK1-NEXT: entry:
; CHECK1-NEXT: [[TMP:%.*]] = load i32, ptr [[DOTGLOBAL_TID_]], align 4
; CHECK1-NEXT: [[TMP1:%.*]] = call i32 @__kmpc_master(ptr noundef nonnull @[[GLOB0]], i32 [[TMP]])
; CHECK1-NEXT: [[TMP2:%.*]] = icmp eq i32 [[TMP1]], 0
; CHECK1-NEXT: br i1 [[TMP2]], label [[OMP_IF_END:%.*]], label [[OMP_IF_THEN:%.*]]
; CHECK1: omp_if.then:
; CHECK1-NEXT: [[TMP3:%.*]] = load i32, ptr [[A]], align 4
; CHECK1-NEXT: [[INC:%.*]] = add nsw i32 [[TMP3]], 1
; CHECK1-NEXT: store i32 [[INC]], ptr [[A]], align 4
; CHECK1-NEXT: call void @__kmpc_end_master(ptr noundef nonnull @[[GLOB0]], i32 [[TMP]])
; CHECK1-NEXT: br label [[OMP_IF_END]]
; CHECK1: omp_if.end:
; CHECK1-NEXT: ret void
; CHECK2-LABEL: define {{[^@]+}}@.omp_outlined..4
; CHECK2-SAME: (ptr noalias nocapture nofree noundef nonnull readonly align 4 dereferenceable(4) [[DOTGLOBAL_TID_:%.*]], ptr noalias nocapture nofree readnone [[DOTBOUND_TID_:%.*]], ptr nocapture nofree noundef nonnull align 4 dereferenceable(4) [[A:%.*]]) {
; CHECK2-NEXT: entry:
; CHECK2-NEXT: [[TMP:%.*]] = load i32, ptr [[DOTGLOBAL_TID_]], align 4
; CHECK2-NEXT: [[TMP1:%.*]] = call i32 @__kmpc_master(ptr noundef nonnull @[[GLOB0]], i32 [[TMP]])
; CHECK2-NEXT: [[TMP2:%.*]] = icmp eq i32 [[TMP1]], 0
; CHECK2-NEXT: br i1 [[TMP2]], label [[OMP_IF_END:%.*]], label [[OMP_IF_THEN:%.*]]
; CHECK2: omp_if.then:
; CHECK2-NEXT: [[TMP3:%.*]] = load i32, ptr [[A]], align 4
; CHECK2-NEXT: [[INC:%.*]] = add nsw i32 [[TMP3]], 1
; CHECK2-NEXT: store i32 [[INC]], ptr [[A]], align 4
; CHECK2-NEXT: call void @__kmpc_end_master(ptr noundef nonnull @[[GLOB0]], i32 [[TMP]])
; CHECK2-NEXT: br label [[OMP_IF_END]]
; CHECK2: omp_if.end:
; CHECK2-NEXT: ret void
entry:
%tmp = load i32, ptr %.global_tid., align 4
%tmp1 = call i32 @__kmpc_master(ptr nonnull @0, i32 %tmp)
%tmp2 = icmp eq i32 %tmp1, 0
br i1 %tmp2, label %omp_if.end, label %omp_if.then
omp_if.then: ; preds = %entry
%tmp3 = load i32, ptr %a, align 4
%inc = add nsw i32 %tmp3, 1
store i32 %inc, ptr %a, align 4
call void @__kmpc_end_master(ptr nonnull @0, i32 %tmp)
br label %omp_if.end
omp_if.end: ; preds = %entry, %omp_if.then
ret void
}
declare void @llvm.lifetime.start.p0(ptr nocapture)
declare i32 @omp_get_thread_num() inaccessiblememonly nofree nosync nounwind readonly
declare i32 @__kmpc_master(ptr, i32)
declare void @__kmpc_end_master(ptr, i32)
define internal void @.omp_outlined..5(ptr noalias %.global_tid., ptr noalias %.bound_tid., ptr dereferenceable(4) %a) {
; CHECK-LABEL: define {{[^@]+}}@.omp_outlined..5
; CHECK-SAME: (ptr noalias nofree readonly captures(none) [[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: [[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
; CHECK-NEXT: [[TMP1:%.*]] = call i32 @__kmpc_single(ptr noundef nonnull @[[GLOB0]], i32 [[TMP]])
; 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:
; CHECK-NEXT: [[TMP3:%.*]] = load i32, ptr [[A]], align 4
; CHECK-NEXT: [[INC:%.*]] = add nsw i32 [[TMP3]], 1
; CHECK-NEXT: store i32 [[INC]], ptr [[A]], align 4
; CHECK-NEXT: call void @__kmpc_end_single(ptr noundef nonnull @[[GLOB0]], i32 [[TMP]])
; CHECK-NEXT: br label [[OMP_IF_END]]
; CHECK: omp_if.end:
; CHECK-NEXT: call void @__kmpc_barrier(ptr noundef nonnull @[[GLOB1:[0-9]+]], i32 [[OMP_GLOBAL_THREAD_NUM]])
; CHECK-NEXT: ret void
;
; CHECK1-LABEL: define {{[^@]+}}@.omp_outlined..5
; CHECK1-SAME: (ptr noalias nocapture nofree readonly [[DOTGLOBAL_TID_:%.*]], ptr noalias nocapture nofree readnone [[DOTBOUND_TID_:%.*]], ptr nocapture nofree noundef nonnull align 4 dereferenceable(4) [[A:%.*]]) {
; CHECK1-NEXT: entry:
; CHECK1-NEXT: [[OMP_GLOBAL_THREAD_NUM:%.*]] = call i32 @__kmpc_global_thread_num(ptr noundef nonnull @[[GLOB0]]) #[[ATTR14]]
; CHECK1-NEXT: [[TMP:%.*]] = load i32, ptr [[DOTGLOBAL_TID_]], align 4
; CHECK1-NEXT: [[TMP1:%.*]] = call i32 @__kmpc_single(ptr noundef nonnull @[[GLOB0]], i32 [[TMP]])
; CHECK1-NEXT: [[TMP2:%.*]] = icmp eq i32 [[TMP1]], 0
; CHECK1-NEXT: br i1 [[TMP2]], label [[OMP_IF_END:%.*]], label [[OMP_IF_THEN:%.*]]
; CHECK1: omp_if.then:
; CHECK1-NEXT: [[TMP3:%.*]] = load i32, ptr [[A]], align 4
; CHECK1-NEXT: [[INC:%.*]] = add nsw i32 [[TMP3]], 1
; CHECK1-NEXT: store i32 [[INC]], ptr [[A]], align 4
; CHECK1-NEXT: call void @__kmpc_end_single(ptr noundef nonnull @[[GLOB0]], i32 [[TMP]])
; CHECK1-NEXT: br label [[OMP_IF_END]]
; CHECK1: omp_if.end:
; CHECK1-NEXT: call void @__kmpc_barrier(ptr noundef nonnull @[[GLOB1:[0-9]+]], i32 [[OMP_GLOBAL_THREAD_NUM]])
; CHECK1-NEXT: ret void
; CHECK2-LABEL: define {{[^@]+}}@.omp_outlined..5
; CHECK2-SAME: (ptr noalias nocapture nofree readonly [[DOTGLOBAL_TID_:%.*]], ptr noalias nocapture nofree readnone [[DOTBOUND_TID_:%.*]], ptr nocapture nofree noundef nonnull align 4 dereferenceable(4) [[A:%.*]]) {
; CHECK2-NEXT: entry:
; CHECK2-NEXT: [[OMP_GLOBAL_THREAD_NUM:%.*]] = call i32 @__kmpc_global_thread_num(ptr noundef nonnull @[[GLOB0]]) #[[ATTR14]]
; CHECK2-NEXT: [[TMP:%.*]] = load i32, ptr [[DOTGLOBAL_TID_]], align 4
; CHECK2-NEXT: [[TMP1:%.*]] = call i32 @__kmpc_single(ptr noundef nonnull @[[GLOB0]], i32 [[TMP]])
; CHECK2-NEXT: [[TMP2:%.*]] = icmp eq i32 [[TMP1]], 0
; CHECK2-NEXT: br i1 [[TMP2]], label [[OMP_IF_END:%.*]], label [[OMP_IF_THEN:%.*]]
; CHECK2: omp_if.then:
; CHECK2-NEXT: [[TMP3:%.*]] = load i32, ptr [[A]], align 4
; CHECK2-NEXT: [[INC:%.*]] = add nsw i32 [[TMP3]], 1
; CHECK2-NEXT: store i32 [[INC]], ptr [[A]], align 4
; CHECK2-NEXT: call void @__kmpc_end_single(ptr noundef nonnull @[[GLOB0]], i32 [[TMP]])
; CHECK2-NEXT: br label [[OMP_IF_END]]
; CHECK2: omp_if.end:
; CHECK2-NEXT: call void @__kmpc_barrier(ptr noundef nonnull @[[GLOB1:[0-9]+]], i32 [[OMP_GLOBAL_THREAD_NUM]])
; CHECK2-NEXT: ret void
entry:
%omp_global_thread_num = call i32 @__kmpc_global_thread_num(ptr nonnull @0)
%tmp = load i32, ptr %.global_tid., align 4
%tmp1 = call i32 @__kmpc_single(ptr nonnull @0, i32 %tmp)
%tmp2 = icmp eq i32 %tmp1, 0
br i1 %tmp2, label %omp_if.end, label %omp_if.then
omp_if.then: ; preds = %entry
%tmp3 = load i32, ptr %a, align 4
%inc = add nsw i32 %tmp3, 1
store i32 %inc, ptr %a, align 4
call void @__kmpc_end_single(ptr nonnull @0, i32 %tmp)
br label %omp_if.end
omp_if.end: ; preds = %entry, %omp_if.then
call void @__kmpc_barrier(ptr nonnull @1, i32 %omp_global_thread_num) #6
ret void
}
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 noundef nonnull align 4 captures(none) dereferenceable(4) [[A:%.*]]) {
; 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
; 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: switch i32 [[TMP4]], label [[DOTOMP_REDUCTION_DEFAULT:%.*]] [
; CHECK-NEXT: i32 1, label [[DOTOMP_REDUCTION_CASE1:%.*]]
; CHECK-NEXT: i32 2, label [[DOTOMP_REDUCTION_CASE2:%.*]]
; CHECK-NEXT: ]
; CHECK: .omp.reduction.case1:
; CHECK-NEXT: [[TMP5:%.*]] = load i32, ptr [[A]], align 4
; 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: br label [[DOTOMP_REDUCTION_DEFAULT]]
; CHECK: .omp.reduction.case2:
; CHECK-NEXT: [[TMP7:%.*]] = load i32, ptr [[A1]], align 4
; CHECK-NEXT: [[TMP8:%.*]] = atomicrmw add ptr [[A]], i32 [[TMP7]] monotonic, align 4
; CHECK-NEXT: br label [[DOTOMP_REDUCTION_DEFAULT]]
; CHECK: .omp.reduction.default:
; CHECK-NEXT: call void @llvm.lifetime.end.p0(ptr noundef nonnull [[A1]])
; CHECK-NEXT: ret void
;
; CHECK1-LABEL: define {{[^@]+}}@.omp_outlined..6
; CHECK1-SAME: (ptr noalias nocapture nofree noundef nonnull readonly align 4 dereferenceable(4) [[DOTGLOBAL_TID_:%.*]], ptr noalias nocapture nofree readnone [[DOTBOUND_TID_:%.*]], ptr nocapture noundef nonnull align 4 dereferenceable(4) [[A:%.*]]) {
; CHECK1-NEXT: entry:
; CHECK1-NEXT: [[A1:%.*]] = alloca i32, align 4
; CHECK1-NEXT: [[DOTOMP_REDUCTION_RED_LIST:%.*]] = alloca [1 x ptr], align 8
; CHECK1-NEXT: call void @llvm.lifetime.start.p0(ptr noundef nonnull align 4 [[A1]]) #[[ATTR0]]
; CHECK1-NEXT: store i32 1, ptr [[A1]], align 4
; CHECK1-NEXT: store ptr [[A1]], ptr [[DOTOMP_REDUCTION_RED_LIST]], align 8
; CHECK1-NEXT: [[TMP2:%.*]] = load i32, ptr [[DOTGLOBAL_TID_]], align 4
; CHECK1-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)
; CHECK1-NEXT: switch i32 [[TMP4]], label [[DOTOMP_REDUCTION_DEFAULT:%.*]] [
; CHECK1-NEXT: i32 1, label [[DOTOMP_REDUCTION_CASE1:%.*]]
; CHECK1-NEXT: i32 2, label [[DOTOMP_REDUCTION_CASE2:%.*]]
; CHECK1-NEXT: ]
; CHECK1: .omp.reduction.case1:
; CHECK1-NEXT: [[TMP5:%.*]] = load i32, ptr [[A]], align 4
; CHECK1-NEXT: [[TMP6:%.*]] = load i32, ptr [[A1]], align 4
; CHECK1-NEXT: [[ADD:%.*]] = add nsw i32 [[TMP5]], [[TMP6]]
; CHECK1-NEXT: store i32 [[ADD]], ptr [[A]], align 4
; CHECK1-NEXT: call void @__kmpc_end_reduce_nowait(ptr noundef nonnull @[[GLOB2]], i32 [[TMP2]], ptr noundef nonnull @.gomp_critical_user_.reduction.var)
; CHECK1-NEXT: br label [[DOTOMP_REDUCTION_DEFAULT]]
; CHECK1: .omp.reduction.case2:
; CHECK1-NEXT: [[TMP7:%.*]] = load i32, ptr [[A1]], align 4
; CHECK1-NEXT: [[TMP8:%.*]] = atomicrmw add ptr [[A]], i32 [[TMP7]] monotonic, align 4
; CHECK1-NEXT: br label [[DOTOMP_REDUCTION_DEFAULT]]
; CHECK1: .omp.reduction.default:
; CHECK1-NEXT: call void @llvm.lifetime.end.p0(ptr noundef nonnull [[A1]])
; CHECK1-NEXT: ret void
; CHECK2-LABEL: define {{[^@]+}}@.omp_outlined..6
; CHECK2-SAME: (ptr noalias nocapture nofree noundef nonnull readonly align 4 dereferenceable(4) [[DOTGLOBAL_TID_:%.*]], ptr noalias nocapture nofree readnone [[DOTBOUND_TID_:%.*]], ptr nocapture noundef nonnull align 4 dereferenceable(4) [[A:%.*]]) {
; CHECK2-NEXT: entry:
; CHECK2-NEXT: [[A1:%.*]] = alloca i32, align 4
; CHECK2-NEXT: [[DOTOMP_REDUCTION_RED_LIST:%.*]] = alloca [1 x ptr], align 8
; CHECK2-NEXT: call void @llvm.lifetime.start.p0(ptr noundef nonnull align 4 [[A1]]) #[[ATTR0]]
; CHECK2-NEXT: store i32 1, ptr [[A1]], align 4
; CHECK2-NEXT: store ptr [[A1]], ptr [[DOTOMP_REDUCTION_RED_LIST]], align 8
; CHECK2-NEXT: [[TMP2:%.*]] = load i32, ptr [[DOTGLOBAL_TID_]], align 4
; CHECK2-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)
; CHECK2-NEXT: switch i32 [[TMP4]], label [[DOTOMP_REDUCTION_DEFAULT:%.*]] [
; CHECK2-NEXT: i32 1, label [[DOTOMP_REDUCTION_CASE1:%.*]]
; CHECK2-NEXT: i32 2, label [[DOTOMP_REDUCTION_CASE2:%.*]]
; CHECK2-NEXT: ]
; CHECK2: .omp.reduction.case1:
; CHECK2-NEXT: [[TMP5:%.*]] = load i32, ptr [[A]], align 4
; CHECK2-NEXT: [[TMP6:%.*]] = load i32, ptr [[A1]], align 4
; CHECK2-NEXT: [[ADD:%.*]] = add nsw i32 [[TMP5]], [[TMP6]]
; CHECK2-NEXT: store i32 [[ADD]], ptr [[A]], align 4
; CHECK2-NEXT: call void @__kmpc_end_reduce_nowait(ptr noundef nonnull @[[GLOB2]], i32 [[TMP2]], ptr noundef nonnull @.gomp_critical_user_.reduction.var)
; CHECK2-NEXT: br label [[DOTOMP_REDUCTION_DEFAULT]]
; CHECK2: .omp.reduction.case2:
; CHECK2-NEXT: [[TMP7:%.*]] = load i32, ptr [[A1]], align 4
; CHECK2-NEXT: [[TMP8:%.*]] = atomicrmw add ptr [[A]], i32 [[TMP7]] monotonic, align 4
; CHECK2-NEXT: br label [[DOTOMP_REDUCTION_DEFAULT]]
; CHECK2: .omp.reduction.default:
; CHECK2-NEXT: call void @llvm.lifetime.end.p0(ptr noundef nonnull [[A1]])
; CHECK2-NEXT: ret void
entry:
%a1 = alloca i32, align 4
%.omp.reduction.red_list = alloca [1 x ptr], align 8
call void @llvm.lifetime.start.p0(ptr nonnull %a1)
store i32 1, ptr %a1, align 4
store ptr %a1, ptr %.omp.reduction.red_list, align 8
%tmp2 = load i32, ptr %.global_tid., align 4
%tmp4 = call i32 @__kmpc_reduce_nowait(ptr nonnull @2, i32 %tmp2, i32 1, i64 8, ptr nonnull %.omp.reduction.red_list, ptr nonnull @.omp.reduction.reduction_func, ptr nonnull @.gomp_critical_user_.reduction.var)
switch i32 %tmp4, label %.omp.reduction.default [
i32 1, label %.omp.reduction.case1
i32 2, label %.omp.reduction.case2
]
.omp.reduction.case1: ; preds = %entry
%tmp5 = load i32, ptr %a, align 4
%tmp6 = load i32, ptr %a1, align 4
%add = add nsw i32 %tmp5, %tmp6
store i32 %add, ptr %a, align 4
call void @__kmpc_end_reduce_nowait(ptr nonnull @2, i32 %tmp2, ptr nonnull @.gomp_critical_user_.reduction.var)
br label %.omp.reduction.default
.omp.reduction.case2: ; preds = %entry
%tmp7 = load i32, ptr %a1, align 4
%tmp8 = atomicrmw add ptr %a, i32 %tmp7 monotonic
br label %.omp.reduction.default
.omp.reduction.default: ; preds = %.omp.reduction.case2, %.omp.reduction.case1, %entry
call void @llvm.lifetime.end.p0(ptr nonnull %a1)
ret void
}
define internal void @.omp.reduction.reduction_func(ptr %arg, ptr %arg1) {
; CHECK-LABEL: define {{[^@]+}}@.omp.reduction.reduction_func
; CHECK-SAME: (ptr nofree noundef nonnull readonly align 8 captures(none) dereferenceable(8) [[ARG:%.*]], ptr nofree noundef nonnull readonly align 8 captures(none) dereferenceable(8) [[ARG1:%.*]]) #[[ATTR10:[0-9]+]] {
; CHECK-NEXT: entry:
; CHECK-NEXT: [[TMP2:%.*]] = load ptr, ptr [[ARG1]], align 8
; CHECK-NEXT: [[TMP4:%.*]] = load ptr, ptr [[ARG]], align 8
; CHECK-NEXT: [[TMP5:%.*]] = load i32, ptr [[TMP4]], align 4
; CHECK-NEXT: [[TMP6:%.*]] = load i32, ptr [[TMP2]], align 4
; CHECK-NEXT: [[ADD:%.*]] = add nsw i32 [[TMP5]], [[TMP6]]
; CHECK-NEXT: store i32 [[ADD]], ptr [[TMP4]], align 4
; CHECK-NEXT: ret void
;
; CHECK1-LABEL: define {{[^@]+}}@.omp.reduction.reduction_func
; CHECK1-SAME: (ptr nocapture nofree nonnull readonly align 8 dereferenceable(8) [[ARG:%.*]], ptr nocapture nofree nonnull readonly align 8 dereferenceable(8) [[ARG1:%.*]]) #[[ATTR10:[0-9]+]] {
; CHECK1-NEXT: entry:
; CHECK1-NEXT: [[TMP2:%.*]] = load ptr, ptr [[ARG1]], align 8
; CHECK1-NEXT: [[TMP4:%.*]] = load ptr, ptr [[ARG]], align 8
; CHECK1-NEXT: [[TMP5:%.*]] = load i32, ptr [[TMP4]], align 4
; CHECK1-NEXT: [[TMP6:%.*]] = load i32, ptr [[TMP2]], align 4
; CHECK1-NEXT: [[ADD:%.*]] = add nsw i32 [[TMP5]], [[TMP6]]
; CHECK1-NEXT: store i32 [[ADD]], ptr [[TMP4]], align 4
; CHECK1-NEXT: ret void
; CHECK2-LABEL: define {{[^@]+}}@.omp.reduction.reduction_func
; CHECK2-SAME: (ptr nocapture nofree nonnull readonly align 8 dereferenceable(8) [[ARG:%.*]], ptr nocapture nofree nonnull readonly align 8 dereferenceable(8) [[ARG1:%.*]]) #[[ATTR10:[0-9]+]] {
; CHECK2-NEXT: entry:
; CHECK2-NEXT: [[TMP2:%.*]] = load ptr, ptr [[ARG1]], align 8
; CHECK2-NEXT: [[TMP4:%.*]] = load ptr, ptr [[ARG]], align 8
; CHECK2-NEXT: [[TMP5:%.*]] = load i32, ptr [[TMP4]], align 4
; CHECK2-NEXT: [[TMP6:%.*]] = load i32, ptr [[TMP2]], align 4
; CHECK2-NEXT: [[ADD:%.*]] = add nsw i32 [[TMP5]], [[TMP6]]
; CHECK2-NEXT: store i32 [[ADD]], ptr [[TMP4]], align 4
; CHECK2-NEXT: ret void
entry:
%tmp2 = load ptr, ptr %arg1, align 8
%tmp4 = load ptr, ptr %arg, align 8
%tmp5 = load i32, ptr %tmp4, align 4
%tmp6 = load i32, ptr %tmp2, align 4
%add = add nsw i32 %tmp5, %tmp6
store i32 %add, ptr %tmp4, align 4
ret void
}
declare i32 @__kmpc_single(ptr, i32)
declare void @__kmpc_end_single(ptr, i32)
declare void @__kmpc_barrier(ptr, i32)
declare i32 @__kmpc_global_thread_num(ptr) nofree nosync nounwind readonly
declare i32 @__kmpc_reduce_nowait(ptr, i32, i32, i64, ptr, ptr, ptr)
declare void @__kmpc_end_reduce_nowait(ptr, i32, ptr)
declare void @llvm.lifetime.end.p0(ptr nocapture)
declare !callback !2 void @__kmpc_fork_call(ptr, i32, ptr, ...)
declare void @unknown()
declare void @readonly() readonly
declare void @readnone() readnone
!llvm.module.flags = !{!8}
!0 = !{i32 1, !"wchar_size", i32 4}
!1 = !{!"clang"}
!2 = !{!3}
!3 = !{i64 2, i64 -1, i64 -1, i1 true}
!4 = !{!5, !5, i64 0}
!5 = !{!"int", !6, i64 0}
!6 = !{!"omnipotent char", !7, i64 0}
!7 = !{!"Simple C/C++ TBAA"}
!8 = !{i32 7, !"openmp", i32 50}