[clang][OpenMP] Add codegen for scope directive by ddpagan · Pull Request #109197 · llvm/llvm-project (original) (raw)
@llvm/pr-subscribers-flang-openmp
@llvm/pr-subscribers-clang
@llvm/pr-subscribers-clang-codegen
Author: David Pagan (ddpagan)
Changes
Added codegen for scope directive, enabled allocate and firstprivate clauses, and added scope directive LIT test.
Testing
- LIT tests (including new scope test).
- OpenMP scope example test from 5.2 OpenMP API examples document.
- Three executable scope tests from OpenMP_VV/sollve_vv suite.
Patch is 160.18 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/109197.diff
6 Files Affected:
- (modified) clang/lib/CodeGen/CGStmt.cpp (+1-1)
- (modified) clang/lib/CodeGen/CGStmtOpenMP.cpp (+26)
- (modified) clang/lib/CodeGen/CodeGenFunction.h (+1)
- (removed) clang/test/OpenMP/error_unsupport_feature.c (-8)
- (added) clang/test/OpenMP/scope_codegen.cpp (+2267)
- (modified) llvm/include/llvm/Frontend/OpenMP/OMP.td (+2)
diff --git a/clang/lib/CodeGen/CGStmt.cpp b/clang/lib/CodeGen/CGStmt.cpp index b138c87a853495..27cf3de531d8a4 100644 --- a/clang/lib/CodeGen/CGStmt.cpp +++ b/clang/lib/CodeGen/CGStmt.cpp @@ -420,7 +420,7 @@ void CodeGenFunction::EmitStmt(const Stmt *S, ArrayRef<const Attr *> Attrs) { CGM.ErrorUnsupported(S, "OpenMP dispatch directive"); break; case Stmt::OMPScopeDirectiveClass: - CGM.ErrorUnsupported(S, "scope with FE outlining"); + EmitOMPScopeDirective(cast(*S)); break; case Stmt::OMPMaskedDirectiveClass: EmitOMPMaskedDirective(cast(*S)); diff --git a/clang/lib/CodeGen/CGStmtOpenMP.cpp b/clang/lib/CodeGen/CGStmtOpenMP.cpp index 8afe2abf2cc494..b11df8334766a8 100644 --- a/clang/lib/CodeGen/CGStmtOpenMP.cpp +++ b/clang/lib/CodeGen/CGStmtOpenMP.cpp @@ -4223,6 +4223,32 @@ void CodeGenFunction::EmitSections(const OMPExecutableDirective &S) { } } +void CodeGenFunction::EmitOMPScopeDirective(const OMPScopeDirective &S) { + { + // Emit code for 'scope' region + auto &&CodeGen = [&S](CodeGenFunction &CGF, PrePostActionTy &Action) { + Action.Enter(CGF); + OMPPrivateScope PrivateScope(CGF); + (void)CGF.EmitOMPFirstprivateClause(S, PrivateScope); + CGF.EmitOMPPrivateClause(S, PrivateScope); + CGF.EmitOMPReductionClauseInit(S, PrivateScope); + (void)PrivateScope.Privatize(); + CGF.EmitStmt(S.getInnermostCapturedStmt()->getCapturedStmt()); + CGF.EmitOMPReductionClauseFinal(S, /ReductionKind=/OMPD_parallel); + }; + auto LPCRegion = + CGOpenMPRuntime::LastprivateConditionalRAII::disable(*this, S); + OMPLexicalScope Scope(*this, S, OMPD_unknown); + CGM.getOpenMPRuntime().emitInlinedDirective(*this, OMPD_scope, CodeGen); + } + // Emit an implicit barrier at the end. + if (!S.getSingleClause()) { + CGM.getOpenMPRuntime().emitBarrierCall(*this, S.getBeginLoc(), OMPD_scope); + } + // Check for outer lastprivate conditional update. + checkForLastprivateConditionalUpdate(*this, S); +} + void CodeGenFunction::EmitOMPSectionsDirective(const OMPSectionsDirective &S) { if (CGM.getLangOpts().OpenMPIRBuilder) { llvm::OpenMPIRBuilder &OMPBuilder = CGM.getOpenMPRuntime().getOMPBuilder(); diff --git a/clang/lib/CodeGen/CodeGenFunction.h b/clang/lib/CodeGen/CodeGenFunction.h index 6802dc7f0c1598..2df17e83bae2ee 100644 --- a/clang/lib/CodeGen/CodeGenFunction.h +++ b/clang/lib/CodeGen/CodeGenFunction.h @@ -3823,6 +3823,7 @@ class CodeGenFunction : public CodeGenTypeCache { void EmitOMPInterchangeDirective(const OMPInterchangeDirective &S); void EmitOMPForDirective(const OMPForDirective &S); void EmitOMPForSimdDirective(const OMPForSimdDirective &S); + void EmitOMPScopeDirective(const OMPScopeDirective &S); void EmitOMPSectionsDirective(const OMPSectionsDirective &S); void EmitOMPSectionDirective(const OMPSectionDirective &S); void EmitOMPSingleDirective(const OMPSingleDirective &S); diff --git a/clang/test/OpenMP/error_unsupport_feature.c b/clang/test/OpenMP/error_unsupport_feature.c deleted file mode 100644 index eb381b3bea1e1a..00000000000000 --- a/clang/test/OpenMP/error_unsupport_feature.c +++ /dev/null @@ -1,8 +0,0 @@ -// RUN: %clang_cc1 -emit-llvm-only -verify -fopenmp %s
-int main () {
- int r = 0; -#pragma omp scope reduction(+:r) // expected-error {{cannot compile this scope with FE outlining yet}}
- r++;
- return r; -} diff --git a/clang/test/OpenMP/scope_codegen.cpp b/clang/test/OpenMP/scope_codegen.cpp new file mode 100644 index 00000000000000..ef69b8302fa2de --- /dev/null +++ b/clang/test/OpenMP/scope_codegen.cpp @@ -0,0 +1,2267 @@ +// NOTE: Assertions have been autogenerated by utils/update_cc_test_checks.py UTC_ARGS: --function-signature --include-generated-funcs --replace-value-regex "_omp_offloading[0-9a-z]+_[0-9a-z]+" "reduction_size[.].+[.]" "pl_cond[.].+[.|,]" --prefix-filecheck-ir-name _ +// RUN: %clang_cc1 -verify -Wno-vla -fopenmp -fopenmp-version=52 -fnoopenmp-use-tls -x c++ -std=c++11 -triple x86_64-unknown-unknown -emit-llvm %s -fexceptions -fcxx-exceptions -o - | FileCheck %s --check-prefix=CHECK1
- +// RUN: %clang_cc1 -fopenmp -fopenmp-version=52 -fnoopenmp-use-tls -x c++ -std=c++11 -triple x86_64-unknown-unknown -fexceptions -fcxx-exceptions -emit-pch -o %t %s +// RUN: %clang_cc1 -fopenmp -fopenmp-version=52 -fnoopenmp-use-tls -x c++ -triple x86_64-unknown-unknown -fexceptions -fcxx-exceptions -std=c++11 -include-pch %t -verify -Wno-vla %s -emit-llvm -o - | FileCheck %s --check-prefix=CHECK1
- +// RUN: %clang_cc1 -fopenmp -fopenmp-version=52 -fnoopenmp-use-tls -x c++ -std=c++11 -triple x86_64-unknown-unknown -fexceptions -fcxx-exceptions -emit-pch -o %t %s +// RUN: %clang_cc1 -fopenmp -fopenmp-version=52 -fnoopenmp-use-tls -x c++ -triple x86_64-unknown-unknown -fexceptions -fcxx-exceptions -std=c++11 -include-pch %t -verify -Wno-vla %s -emit-llvm -o - | FileCheck %s --check-prefix=CHECK4
- +// RUN: %clang_cc1 -verify -Wno-vla -triple x86_64-apple-darwin10 -std=c++11 -fopenmp -fopenmp-version=52 -fnoopenmp-use-tls -fexceptions -fcxx-exceptions -debug-info-kind=line-tables-only -x c++ -emit-llvm %s -o - | FileCheck %s --check-prefix=CHECK5 +// RUN: %clang_cc1 -verify -Wno-vla -fopenmp -fopenmp-version=52 -fnoopenmp-use-tls -x c++ -std=c++11 -DARRAY -triple x86_64-apple-darwin10 -emit-llvm %s -o - | FileCheck %s --check-prefix=CHECK6
- +// RUN: %clang_cc1 -verify -Wno-vla -fopenmp-simd -fopenmp-version=52 -fnoopenmp-use-tls -x c++ -std=c++11 -triple x86_64-unknown-unknown -emit-llvm %s -fexceptions -fcxx-exceptions -o - | FileCheck %s --implicit-check-not="{{__kmpc|__tgt}}" +// RUN: %clang_cc1 -fopenmp-simd -fopenmp-version=52 -fnoopenmp-use-tls -x c++ -std=c++11 -triple x86_64-unknown-unknown -fexceptions -fcxx-exceptions -emit-pch -o %t %s +// RUN: %clang_cc1 -fopenmp-simd -fopenmp-version=52 -fnoopenmp-use-tls -x c++ -triple x86_64-unknown-unknown -fexceptions -fcxx-exceptions -std=c++11 -include-pch %t -verify %s -emit-llvm -o - | FileCheck %s --implicit-check-not="{{__kmpc|__tgt}}" +// RUN: %clang_cc1 -verify -Wno-vla -triple x86_64-apple-darwin10 -std=c++11 -fopenmp-simd -fopenmp-version=52 -fnoopenmp-use-tls -fexceptions -fcxx-exceptions -debug-info-kind=line-tables-only -x c++ -emit-llvm %s -o - | FileCheck %s --implicit-check-not="{{__kmpc|__tgt}}" +// RUN: %clang_cc1 -verify -Wno-vla -fopenmp-simd -fopenmp-version=52 -fnoopenmp-use-tls -x c++ -std=c++11 -DARRAY -triple x86_64-apple-darwin10 -emit-llvm %s -o - | FileCheck %s --implicit-check-not="{{__kmpc|__tgt}}" +// expected-no-diagnostics
- +typedef void **omp_allocator_handle_t; +extern const omp_allocator_handle_t omp_null_allocator; +extern const omp_allocator_handle_t omp_default_mem_alloc; +extern const omp_allocator_handle_t omp_large_cap_mem_alloc; +extern const omp_allocator_handle_t omp_const_mem_alloc; +extern const omp_allocator_handle_t omp_high_bw_mem_alloc; +extern const omp_allocator_handle_t omp_low_lat_mem_alloc; +extern const omp_allocator_handle_t omp_cgroup_mem_alloc; +extern const omp_allocator_handle_t omp_pteam_mem_alloc; +extern const omp_allocator_handle_t omp_thread_mem_alloc;
- +#ifndef ARRAY
+#ifndef HEADER +#define HEADER + +class TestClass { +public:
- int a;
- TestClass() : a(0) {}
- TestClass(const TestClass &C) : a(C.a) {}
- TestClass &operator=(const TestClass &) { return *this;}
- ~TestClass(){}; +};
- +TestClass tc; +TestClass tc2[2];
- +void foo() { extern void mayThrow(); mayThrow(); }
- +struct SS {
- int e;
- int a;
- int b : 4;
- int &c;
- SS(int &d) : a(0), b(0), c(d) { +#pragma omp scope private(a, this->b, (this)->c) allocate(omp_default_mem_alloc:b) nowait
- & {
++this->a, --b, (this)->c /= 1;
+#pragma omp parallel num_threads(b) +#pragma omp scope firstprivate(a, this->b, (this)->c) reduction(+:e)
++(this)->a, e+=1, this->c /= 1;
- }();
- } +};
- +template +struct SST {
- T a;
- SST() : a(T()) { +#pragma omp target teams +#pragma omp parallel firstprivate(a) +#pragma omp scope private(this->a)
- & {
[&]() {
int c;
++this->a;
+#pragma omp parallel firstprivate(a) +#pragma omp scope private((this)->a) allocate(omp_cgroup_mem_alloc:a)
++(this)->a;
}();
- }();
- } +};
- +int main() {
- char a;
- char a2[2];
- TestClass &c = tc;
- SST sst;
- SS ss(c.a);
- +#pragma omp scope nowait
- a = 2; +#pragma omp scope
- a = 2; +#pragma omp scope firstprivate(a,c, tc) private(a2, tc2)
- foo();
- return a; +}
- +void parallel_single() { +#pragma omp parallel
+#pragma omp scope
- foo(); +} +#endif +#else +struct St {
- int a, b;
- St() : a(0), b(0) {}
- St &operator=(const St &) { return *this; };
- ~St() {} +};
- +void array_func(int n, int a[n], St s[2]) {
- int b,c; +#pragma omp scope nowait firstprivate(b) allocate(omp_high_bw_mem_alloc:c) private(a,s) reduction(*:c)
- ; +}
- +int main() {
- int n;
- int a[10];
- St s[2];
- array_func(n, a, s);
- return 0; +} +#endif +// CHECK1-LABEL: define {{[^@]+}}@__cxx_global_var_init +// CHECK1-SAME: () #[[ATTR0:[0-9]+]] { +// CHECK1-NEXT: entry: +// CHECK1-NEXT: call void @_ZN9TestClassC1Ev(ptr noundef nonnull align 4 dereferenceable(4) @tc) +// CHECK1-NEXT: [[TMP0:%.]] = call i32 @__cxa_atexit(ptr @_ZN9TestClassD1Ev, ptr @tc, ptr @__dso_handle) #[[ATTR3:[0-9]+]] +// CHECK1-NEXT: ret void +// +// +// CHECK1-LABEL: define {{[^@]+}}@_ZN9TestClassC1Ev +// CHECK1-SAME: (ptr noundef nonnull align 4 dereferenceable(4) [[THIS:%.]]) unnamed_addr #[[ATTR1:[0-9]+]] comdat align 2 { +// CHECK1-NEXT: entry: +// CHECK1-NEXT: [[THIS_ADDR:%.]] = alloca ptr, align 8 +// CHECK1-NEXT: store ptr [[THIS]], ptr [[THIS_ADDR]], align 8 +// CHECK1-NEXT: [[THIS1:%.]] = load ptr, ptr [[THIS_ADDR]], align 8 +// CHECK1-NEXT: call void @_ZN9TestClassC2Ev(ptr noundef nonnull align 4 dereferenceable(4) [[THIS1]]) +// CHECK1-NEXT: ret void +// +// +// CHECK1-LABEL: define {{[^@]+}}@_ZN9TestClassD1Ev +// CHECK1-SAME: (ptr noundef nonnull align 4 dereferenceable(4) [[THIS:%.]]) unnamed_addr #[[ATTR2:[0-9]+]] comdat align 2 { +// CHECK1-NEXT: entry: +// CHECK1-NEXT: [[THIS_ADDR:%.]] = alloca ptr, align 8 +// CHECK1-NEXT: store ptr [[THIS]], ptr [[THIS_ADDR]], align 8 +// CHECK1-NEXT: [[THIS1:%.]] = load ptr, ptr [[THIS_ADDR]], align 8 +// CHECK1-NEXT: call void @_ZN9TestClassD2Ev(ptr noundef nonnull align 4 dereferenceable(4) [[THIS1]]) #[[ATTR3]] +// CHECK1-NEXT: ret void +// +// +// CHECK1-LABEL: define {{[^@]+}}@_ZN9TestClassC2Ev +// CHECK1-SAME: (ptr noundef nonnull align 4 dereferenceable(4) [[THIS:%.]]) unnamed_addr #[[ATTR2]] comdat align 2 { +// CHECK1-NEXT: entry: +// CHECK1-NEXT: [[THIS_ADDR:%.]] = alloca ptr, align 8 +// CHECK1-NEXT: store ptr [[THIS]], ptr [[THIS_ADDR]], align 8 +// CHECK1-NEXT: [[THIS1:%.]] = load ptr, ptr [[THIS_ADDR]], align 8 +// CHECK1-NEXT: [[A:%.]] = getelementptr inbounds nuw [[CLASS_TESTCLASS:%.]], ptr [[THIS1]], i32 0, i32 0 +// CHECK1-NEXT: store i32 0, ptr [[A]], align 4 +// CHECK1-NEXT: ret void +// +// +// CHECK1-LABEL: define {{[^@]+}}@_ZN9TestClassD2Ev +// CHECK1-SAME: (ptr noundef nonnull align 4 dereferenceable(4) [[THIS:%.]]) unnamed_addr #[[ATTR2]] comdat align 2 { +// CHECK1-NEXT: entry: +// CHECK1-NEXT: [[THIS_ADDR:%.]] = alloca ptr, align 8 +// CHECK1-NEXT: store ptr [[THIS]], ptr [[THIS_ADDR]], align 8 +// CHECK1-NEXT: [[THIS1:%.]] = load ptr, ptr [[THIS_ADDR]], align 8 +// CHECK1-NEXT: ret void +// +// +// CHECK1-LABEL: define {{[^@]+}}@__cxx_global_var_init.1 +// CHECK1-SAME: () #[[ATTR0]] personality ptr @__gxx_personality_v0 { +// CHECK1-NEXT: entry: +// CHECK1-NEXT: [[EXN_SLOT:%.]] = alloca ptr, align 8 +// CHECK1-NEXT: [[EHSELECTOR_SLOT:%.]] = alloca i32, align 4 +// CHECK1-NEXT: br label [[ARRAYCTOR_LOOP:%.]] +// CHECK1: arrayctor.loop: +// CHECK1-NEXT: [[ARRAYCTOR_CUR:%.]] = phi ptr [ @tc2, [[ENTRY:%.]] ], [ [[ARRAYCTOR_NEXT:%.]], [[INVOKE_CONT:%.]] ] +// CHECK1-NEXT: invoke void @_ZN9TestClassC1Ev(ptr noundef nonnull align 4 dereferenceable(4) [[ARRAYCTOR_CUR]]) +// CHECK1-NEXT: to label [[INVOKE_CONT]] unwind label [[LPAD:%.]] +// CHECK1: invoke.cont: +// CHECK1-NEXT: [[ARRAYCTOR_NEXT]] = getelementptr inbounds [[CLASS_TESTCLASS:%.]], ptr [[ARRAYCTOR_CUR]], i64 1 +// CHECK1-NEXT: [[ARRAYCTOR_DONE:%.]] = icmp eq ptr [[ARRAYCTOR_NEXT]], getelementptr inbounds ([[CLASS_TESTCLASS]], ptr @tc2, i64 2) +// CHECK1-NEXT: br i1 [[ARRAYCTOR_DONE]], label [[ARRAYCTOR_CONT:%.]], label [[ARRAYCTOR_LOOP]] +// CHECK1: arrayctor.cont: +// CHECK1-NEXT: [[TMP0:%.]] = call i32 @__cxa_atexit(ptr @__cxx_global_array_dtor, ptr null, ptr @__dso_handle) #[[ATTR3]] +// CHECK1-NEXT: ret void +// CHECK1: lpad: +// CHECK1-NEXT: [[TMP1:%.]] = landingpad { ptr, i32 } +// CHECK1-NEXT: cleanup +// CHECK1-NEXT: [[TMP2:%.]] = extractvalue { ptr, i32 } [[TMP1]], 0 +// CHECK1-NEXT: store ptr [[TMP2]], ptr [[EXN_SLOT]], align 8 +// CHECK1-NEXT: [[TMP3:%.]] = extractvalue { ptr, i32 } [[TMP1]], 1 +// CHECK1-NEXT: store i32 [[TMP3]], ptr [[EHSELECTOR_SLOT]], align 4 +// CHECK1-NEXT: [[ARRAYDESTROY_ISEMPTY:%.]] = icmp eq ptr @tc2, [[ARRAYCTOR_CUR]] +// CHECK1-NEXT: br i1 [[ARRAYDESTROY_ISEMPTY]], label [[ARRAYDESTROY_DONE1:%.]], label [[ARRAYDESTROY_BODY:%.]] +// CHECK1: arraydestroy.body: +// CHECK1-NEXT: [[ARRAYDESTROY_ELEMENTPAST:%.]] = phi ptr [ [[ARRAYCTOR_CUR]], [[LPAD]] ], [ [[ARRAYDESTROY_ELEMENT:%.]], [[ARRAYDESTROY_BODY]] ] +// CHECK1-NEXT: [[ARRAYDESTROY_ELEMENT]] = getelementptr inbounds [[CLASS_TESTCLASS]], ptr [[ARRAYDESTROY_ELEMENTPAST]], i64 -1 +// CHECK1-NEXT: call void @_ZN9TestClassD1Ev(ptr noundef nonnull align 4 dereferenceable(4) [[ARRAYDESTROY_ELEMENT]]) #[[ATTR3]] +// CHECK1-NEXT: [[ARRAYDESTROY_DONE:%.]] = icmp eq ptr [[ARRAYDESTROY_ELEMENT]], @tc2 +// CHECK1-NEXT: br i1 [[ARRAYDESTROY_DONE]], label [[ARRAYDESTROY_DONE1]], label [[ARRAYDESTROY_BODY]] +// CHECK1: arraydestroy.done1: +// CHECK1-NEXT: br label [[EH_RESUME:%.]] +// CHECK1: eh.resume: +// CHECK1-NEXT: [[EXN:%.]] = load ptr, ptr [[EXN_SLOT]], align 8 +// CHECK1-NEXT: [[SEL:%.]] = load i32, ptr [[EHSELECTOR_SLOT]], align 4 +// CHECK1-NEXT: [[LPAD_VAL:%.]] = insertvalue { ptr, i32 } poison, ptr [[EXN]], 0 +// CHECK1-NEXT: [[LPAD_VAL2:%.]] = insertvalue { ptr, i32 } [[LPAD_VAL]], i32 [[SEL]], 1 +// CHECK1-NEXT: resume { ptr, i32 } [[LPAD_VAL2]] +// +// +// CHECK1-LABEL: define {{[^@]+}}@__cxx_global_array_dtor +// CHECK1-SAME: (ptr noundef [[TMP0:%.]]) #[[ATTR0]] { +// CHECK1-NEXT: entry: +// CHECK1-NEXT: [[DOTADDR:%.]] = alloca ptr, align 8 +// CHECK1-NEXT: store ptr [[TMP0]], ptr [[DOTADDR]], align 8 +// CHECK1-NEXT: br label [[ARRAYDESTROY_BODY:%.]] +// CHECK1: arraydestroy.body: +// CHECK1-NEXT: [[ARRAYDESTROY_ELEMENTPAST:%.]] = phi ptr [ getelementptr inbounds ([[CLASS_TESTCLASS:%.]], ptr @tc2, i64 2), [[ENTRY:%.]] ], [ [[ARRAYDESTROY_ELEMENT:%.]], [[ARRAYDESTROY_BODY]] ] +// CHECK1-NEXT: [[ARRAYDESTROY_ELEMENT]] = getelementptr inbounds [[CLASS_TESTCLASS]], ptr [[ARRAYDESTROY_ELEMENTPAST]], i64 -1 +// CHECK1-NEXT: call void @_ZN9TestClassD1Ev(ptr noundef nonnull align 4 dereferenceable(4) [[ARRAYDESTROY_ELEMENT]]) #[[ATTR3]] +// CHECK1-NEXT: [[ARRAYDESTROY_DONE:%.]] = icmp eq ptr [[ARRAYDESTROY_ELEMENT]], @tc2 +// CHECK1-NEXT: br i1 [[ARRAYDESTROY_DONE]], label [[ARRAYDESTROY_DONE1:%.]], label [[ARRAYDESTROY_BODY]] +// CHECK1: arraydestroy.done1: +// CHECK1-NEXT: ret void +// +// +// CHECK1-LABEL: define {{[^@]+}}@_Z3foov +// CHECK1-SAME: () #[[ATTR1]] { +// CHECK1-NEXT: entry: +// CHECK1-NEXT: call void @_Z8mayThrowv() +// CHECK1-NEXT: ret void +// +// +// CHECK1-LABEL: define {{[^@]+}}@main +// CHECK1-SAME: () #[[ATTR5:[0-9]+]] personality ptr @__gxx_personality_v0 { +// CHECK1-NEXT: entry: +// CHECK1-NEXT: [[RETVAL:%.]] = alloca i32, align 4 +// CHECK1-NEXT: [[A:%.]] = alloca i8, align 1 +// CHECK1-NEXT: [[A2:%.]] = alloca [2 x i8], align 1 +// CHECK1-NEXT: [[C:%.]] = alloca ptr, align 8 +// CHECK1-NEXT: [[SST:%.]] = alloca [[STRUCT_SST:%.]], align 8 +// CHECK1-NEXT: [[SS:%.]] = alloca [[STRUCT_SS:%.]], align 8 +// CHECK1-NEXT: [[A1:%.]] = alloca i8, align 1 +// CHECK1-NEXT: [[C2:%.]] = alloca [[CLASS_TESTCLASS:%.]], align 4 +// CHECK1-NEXT: [[TMP:%.]] = alloca ptr, align 8 +// CHECK1-NEXT: [[TC:%.]] = alloca [[CLASS_TESTCLASS]], align 4 +// CHECK1-NEXT: [[A24:%.]] = alloca [2 x i8], align 1 +// CHECK1-NEXT: [[TC2:%.]] = alloca [2 x %class.TestClass], align 4 +// CHECK1-NEXT: [[TMP0:%.]] = call i32 @__kmpc_global_thread_num(ptr @[[GLOB2:[0-9]+]]) +// CHECK1-NEXT: store i32 0, ptr [[RETVAL]], align 4 +// CHECK1-NEXT: store ptr @tc, ptr [[C]], align 8 +// CHECK1-NEXT: call void @_ZN3SSTIdEC1Ev(ptr noundef nonnull align 8 dereferenceable(8) [[SST]]) +// CHECK1-NEXT: call void @_ZN2SSC1ERi(ptr noundef nonnull align 8 dereferenceable(24) [[SS]], ptr noundef nonnull align 4 dereferenceable(4) @tc) +// CHECK1-NEXT: store i8 2, ptr [[A]], align 1 +// CHECK1-NEXT: store i8 2, ptr [[A]], align 1 +// CHECK1-NEXT: call void @__kmpc_barrier(ptr @[[GLOB1:[0-9]+]], i32 [[TMP0]]) +// CHECK1-NEXT: [[TMP1:%.]] = load i8, ptr [[A]], align 1 +// CHECK1-NEXT: store i8 [[TMP1]], ptr [[A1]], align 1 +// CHECK1-NEXT: invoke void @ZN9TestClassC1ERKS(ptr noundef nonnull align 4 dereferenceable(4) [[C2]], ptr noundef nonnull align 4 dereferenceable(4) @tc) +// CHECK1-NEXT: to label [[INVOKE_CONT:%.]] unwind label [[TERMINATE_LPAD:%.]] +// CHECK1: invoke.cont: +// CHECK1-NEXT: store ptr [[C2]], ptr [[TMP]], align 8 +// CHECK1-NEXT: invoke void @ZN9TestClassC1ERKS(ptr noundef nonnull align 4 dereferenceable(4) [[TC]], ptr noundef nonnull align 4 dereferenceable(4) @tc) +// CHECK1-NEXT: to label [[INVOKE_CONT3:%.]] unwind label [[TERMINATE_LPAD]] +// CHECK1: invoke.cont3: +// CHECK1-NEXT: [[ARRAY_BEGIN:%.]] = getelementptr inbounds [2 x %class.TestClass], ptr [[TC2]], i32 0, i32 0 +// CHECK1-NEXT: [[ARRAYCTOR_END:%.]] = getelementptr inbounds [[CLASS_TESTCLASS]], ptr [[ARRAY_BEGIN]], i64 2 +// CHECK1-NEXT: br label [[ARRAYCTOR_LOOP:%.]] +// CHECK1: arrayctor.loop: +// CHECK1-NEXT: [[ARRAYCTOR_CUR:%.]] = phi ptr [ [[ARRAY_BEGIN]], [[INVOKE_CONT3]] ], [ [[ARRAYCTOR_NEXT:%.]], [[INVOKE_CONT5:%.]] ] +// CHECK1-NEXT: invoke void @_ZN9TestClassC1Ev(ptr noundef nonnull align 4 dereferenceable(4) [[ARRAYCTOR_CUR]]) +// CHECK1-NEXT: to label [[INVOKE_CONT5]] unwind label [[TERMINATE_LPAD]] +// CHECK1: invoke.cont5: +// CHECK1-NEXT: [[ARRAYCTOR_NEXT]] = getelementptr inbounds [[CLASS_TESTCLASS]], ptr [[ARRAYCTOR_CUR]], i64 1 +// CHECK1-NEXT: [[ARRAYCTOR_DONE:%.]] = icmp eq ptr [[ARRAYCTOR_NEXT]], [[ARRAYCTOR_END]] +// CHECK1-NEXT: br i1 [[ARRAYCTOR_DONE]], label [[ARRAYCTOR_CONT:%.]], label [[ARRAYCTOR_LOOP]] +// CHECK1: arrayctor.cont: +// CHECK1-NEXT: invoke void @_Z3foov() +// CHECK1-NEXT: to label [[INVOKE_CONT6:%.]] unwind label [[TERMINATE_LPAD]] +// CHECK1: invoke.cont6: +// CHECK1-NEXT: [[ARRAY_BEGIN7:%.]] = getelementptr inbounds [2 x %class.TestClass], ptr [[TC2]], i32 0, i32 0 +// CHECK1-NEXT: [[TMP2:%.]] = getelementptr inbounds [[CLASS_TESTCLASS]], ptr [[ARRAY_BEGIN7]], i64 2 +// CHECK1-NEXT: br label [[ARRAYDESTROY_BODY:%.]] +// CHECK1: arraydestroy.body: +// CHECK1-NEXT: [[ARRAYDESTROY_ELEMENTPAST:%.]] = phi ptr [ [[TMP2]], [[INVOKE_CONT6]] ], [ [[ARRAYDESTROY_ELEMENT:%.]], [[ARRAYDESTROY_BODY]] ] +// CHECK1-NEXT: [[ARRAYDESTROY_ELEMENT]] = getelementptr inbounds [[CLASS_TESTCLASS]], ptr [[ARRAYDESTROY_ELEMENTPAST]], i64 -1 +// CHECK1-NEXT: call void @_ZN9TestClassD1Ev(ptr noundef nonnull align 4 dereferenceable(4) [[ARRAYDESTROY_ELEMENT]]) #[[ATTR3]] +// CHECK1-NEXT: [[ARRAYDESTROY_DONE:%.]] = icmp eq ptr [[ARRAYDESTROY_ELEMENT]], [[ARRAY_BEGIN7]] +// CHECK1-NEXT: br i1 [[ARRAYDESTROY_DONE]], label [[ARRAYDESTROY_DONE8:%.]], label [[ARRAYDESTROY_BODY]] +// CHECK1: arraydestroy.done8: +// CHECK1-NEXT: call void @_ZN9TestClassD1Ev(ptr noundef nonnull align 4 dereferenceable(4) [[TC]]) #[[ATTR3]] +/... [truncated]