diff options
author | Alexey Bataev <a.bataev@hotmail.com> | 2016-05-05 08:46:22 +0000 |
---|---|---|
committer | Alexey Bataev <a.bataev@hotmail.com> | 2016-05-05 08:46:22 +0000 |
commit | f93095a0035e58b33db1cb6e96fd517cd982727c (patch) | |
tree | 6d843960c9985b6c4ccb2ab451edde6de499130d /clang/lib/CodeGen | |
parent | c14e8ced85ecaa4d6c65d91107d583c6b60fb25b (diff) | |
download | bcm5719-llvm-f93095a0035e58b33db1cb6e96fd517cd982727c.tar.gz bcm5719-llvm-f93095a0035e58b33db1cb6e96fd517cd982727c.zip |
[OPENMP 4.5] Codegen for 'lastprivate' clauses in 'taskloop' directives.
OpenMP 4.5 adds taskloop/taskloop simd directives. These directives
allow to use lastprivate clause. Patch adds codegen for this clause.
llvm-svn: 268618
Diffstat (limited to 'clang/lib/CodeGen')
-rw-r--r-- | clang/lib/CodeGen/CGOpenMPRuntime.cpp | 286 | ||||
-rw-r--r-- | clang/lib/CodeGen/CGOpenMPRuntime.h | 3 | ||||
-rw-r--r-- | clang/lib/CodeGen/CGStmtOpenMP.cpp | 68 |
3 files changed, 273 insertions, 84 deletions
diff --git a/clang/lib/CodeGen/CGOpenMPRuntime.cpp b/clang/lib/CodeGen/CGOpenMPRuntime.cpp index b280d53dd39..edb9ddad794 100644 --- a/clang/lib/CodeGen/CGOpenMPRuntime.cpp +++ b/clang/lib/CodeGen/CGOpenMPRuntime.cpp @@ -3292,6 +3292,7 @@ static llvm::Value * emitTaskPrivateMappingFunction(CodeGenModule &CGM, SourceLocation Loc, ArrayRef<const Expr *> PrivateVars, ArrayRef<const Expr *> FirstprivateVars, + ArrayRef<const Expr *> LastprivateVars, QualType PrivatesQTy, ArrayRef<PrivateDataTy> Privates) { auto &C = CGM.getContext(); @@ -3322,6 +3323,16 @@ emitTaskPrivateMappingFunction(CodeGenModule &CGM, SourceLocation Loc, PrivateVarsPos[VD] = Counter; ++Counter; } + for (auto *E: LastprivateVars) { + Args.push_back(ImplicitParamDecl::Create( + C, /*DC=*/nullptr, Loc, + /*Id=*/nullptr, C.getPointerType(C.getPointerType(E->getType())) + .withConst() + .withRestrict())); + auto *VD = cast<VarDecl>(cast<DeclRefExpr>(E)->getDecl()); + PrivateVarsPos[VD] = Counter; + ++Counter; + } auto &TaskPrivatesMapFnInfo = CGM.getTypes().arrangeBuiltinFunctionDeclaration(C.VoidTy, Args); auto *TaskPrivatesMapTy = @@ -3361,6 +3372,179 @@ static int array_pod_sort_comparator(const PrivateDataTy *P1, return P1->first < P2->first ? 1 : (P2->first < P1->first ? -1 : 0); } +/// Emit initialization for private variables in task-based directives. +/// \return true if cleanups are required, false otherwise. +static bool emitPrivatesInit(CodeGenFunction &CGF, + const OMPExecutableDirective &D, + Address KmpTaskSharedsPtr, LValue TDBase, + const RecordDecl *KmpTaskTWithPrivatesQTyRD, + QualType SharedsTy, QualType SharedsPtrTy, + const OMPTaskDataTy &Data, + ArrayRef<PrivateDataTy> Privates, bool ForDup) { + auto &C = CGF.getContext(); + bool NeedsCleanup = false; + auto FI = std::next(KmpTaskTWithPrivatesQTyRD->field_begin()); + LValue PrivatesBase = CGF.EmitLValueForField(TDBase, *FI); + LValue SrcBase; + if (!Data.FirstprivateVars.empty()) { + SrcBase = CGF.MakeAddrLValue( + CGF.Builder.CreatePointerBitCastOrAddrSpaceCast( + KmpTaskSharedsPtr, CGF.ConvertTypeForMem(SharedsPtrTy)), + SharedsTy); + } + CodeGenFunction::CGCapturedStmtInfo CapturesInfo( + cast<CapturedStmt>(*D.getAssociatedStmt())); + FI = cast<RecordDecl>(FI->getType()->getAsTagDecl())->field_begin(); + for (auto &&Pair : Privates) { + auto *VD = Pair.second.PrivateCopy; + auto *Init = VD->getAnyInitializer(); + LValue PrivateLValue = CGF.EmitLValueForField(PrivatesBase, *FI); + if (Init && (!ForDup || (isa<CXXConstructExpr>(Init) && + !CGF.isTrivialInitializer(Init)))) { + if (auto *Elem = Pair.second.PrivateElemInit) { + auto *OriginalVD = Pair.second.Original; + auto *SharedField = CapturesInfo.lookup(OriginalVD); + auto SharedRefLValue = CGF.EmitLValueForField(SrcBase, SharedField); + SharedRefLValue = CGF.MakeAddrLValue( + Address(SharedRefLValue.getPointer(), C.getDeclAlign(OriginalVD)), + SharedRefLValue.getType(), AlignmentSource::Decl); + QualType Type = OriginalVD->getType(); + if (Type->isArrayType()) { + // Initialize firstprivate array. + if (!isa<CXXConstructExpr>(Init) || CGF.isTrivialInitializer(Init)) { + // Perform simple memcpy. + CGF.EmitAggregateAssign(PrivateLValue.getAddress(), + SharedRefLValue.getAddress(), Type); + } else { + // Initialize firstprivate array using element-by-element + // intialization. + CGF.EmitOMPAggregateAssign( + PrivateLValue.getAddress(), SharedRefLValue.getAddress(), Type, + [&CGF, Elem, Init, &CapturesInfo](Address DestElement, + Address SrcElement) { + // Clean up any temporaries needed by the initialization. + CodeGenFunction::OMPPrivateScope InitScope(CGF); + InitScope.addPrivate( + Elem, [SrcElement]() -> Address { return SrcElement; }); + (void)InitScope.Privatize(); + // Emit initialization for single element. + CodeGenFunction::CGCapturedStmtRAII CapInfoRAII( + CGF, &CapturesInfo); + CGF.EmitAnyExprToMem(Init, DestElement, + Init->getType().getQualifiers(), + /*IsInitializer=*/false); + }); + } + } else { + CodeGenFunction::OMPPrivateScope InitScope(CGF); + InitScope.addPrivate(Elem, [SharedRefLValue]() -> Address { + return SharedRefLValue.getAddress(); + }); + (void)InitScope.Privatize(); + CodeGenFunction::CGCapturedStmtRAII CapInfoRAII(CGF, &CapturesInfo); + CGF.EmitExprAsInit(Init, VD, PrivateLValue, + /*capturedByInit=*/false); + } + } else + CGF.EmitExprAsInit(Init, VD, PrivateLValue, /*capturedByInit=*/false); + } + NeedsCleanup = NeedsCleanup || FI->getType().isDestructedType(); + ++FI; + } + return NeedsCleanup; +} + +/// Check if duplication function is required for taskloops. +static bool checkInitIsRequired(CodeGenFunction &CGF, + ArrayRef<PrivateDataTy> Privates) { + bool InitRequired = false; + for (auto &&Pair : Privates) { + auto *VD = Pair.second.PrivateCopy; + auto *Init = VD->getAnyInitializer(); + InitRequired = InitRequired || (Init && isa<CXXConstructExpr>(Init) && + !CGF.isTrivialInitializer(Init)); + } + return InitRequired; +} + + +/// Emit task_dup function (for initialization of +/// private/firstprivate/lastprivate vars and last_iter flag) +/// \code +/// void __task_dup_entry(kmp_task_t *task_dst, const kmp_task_t *task_src, int +/// lastpriv) { +/// // setup lastprivate flag +/// task_dst->last = lastpriv; +/// // could be constructor calls here... +/// } +/// \endcode +static llvm::Value * +emitTaskDupFunction(CodeGenModule &CGM, SourceLocation Loc, + const OMPExecutableDirective &D, + QualType KmpTaskTWithPrivatesPtrQTy, + const RecordDecl *KmpTaskTWithPrivatesQTyRD, + const RecordDecl *KmpTaskTQTyRD, QualType SharedsTy, + QualType SharedsPtrTy, const OMPTaskDataTy &Data, + ArrayRef<PrivateDataTy> Privates, bool WithLastIter) { + auto &C = CGM.getContext(); + FunctionArgList Args; + ImplicitParamDecl DstArg(C, /*DC=*/nullptr, Loc, + /*Id=*/nullptr, KmpTaskTWithPrivatesPtrQTy); + ImplicitParamDecl SrcArg(C, /*DC=*/nullptr, Loc, + /*Id=*/nullptr, KmpTaskTWithPrivatesPtrQTy); + ImplicitParamDecl LastprivArg(C, /*DC=*/nullptr, Loc, + /*Id=*/nullptr, C.IntTy); + Args.push_back(&DstArg); + Args.push_back(&SrcArg); + Args.push_back(&LastprivArg); + auto &TaskDupFnInfo = + CGM.getTypes().arrangeBuiltinFunctionDeclaration(C.VoidTy, Args); + auto *TaskDupTy = CGM.getTypes().GetFunctionType(TaskDupFnInfo); + auto *TaskDup = + llvm::Function::Create(TaskDupTy, llvm::GlobalValue::InternalLinkage, + ".omp_task_dup.", &CGM.getModule()); + CGM.SetInternalFunctionAttributes(/*D=*/nullptr, TaskDup, TaskDupFnInfo); + CodeGenFunction CGF(CGM); + CGF.disableDebugInfo(); + CGF.StartFunction(GlobalDecl(), C.VoidTy, TaskDup, TaskDupFnInfo, Args); + + LValue TDBase = CGF.EmitLoadOfPointerLValue( + CGF.GetAddrOfLocalVar(&DstArg), + KmpTaskTWithPrivatesPtrQTy->castAs<PointerType>()); + // task_dst->liter = lastpriv; + if (WithLastIter) { + auto LIFI = std::next(KmpTaskTQTyRD->field_begin(), KmpTaskTLastIter); + LValue Base = CGF.EmitLValueForField( + TDBase, *KmpTaskTWithPrivatesQTyRD->field_begin()); + LValue LILVal = CGF.EmitLValueForField(Base, *LIFI); + llvm::Value *Lastpriv = CGF.EmitLoadOfScalar( + CGF.GetAddrOfLocalVar(&LastprivArg), /*Volatile=*/false, C.IntTy, Loc); + CGF.EmitStoreOfScalar(Lastpriv, LILVal); + } + + // Emit initial values for private copies (if any). + assert(!Privates.empty()); + Address KmpTaskSharedsPtr = Address::invalid(); + if (!Data.FirstprivateVars.empty()) { + LValue TDBase = CGF.EmitLoadOfPointerLValue( + CGF.GetAddrOfLocalVar(&SrcArg), + KmpTaskTWithPrivatesPtrQTy->castAs<PointerType>()); + LValue Base = CGF.EmitLValueForField( + TDBase, *KmpTaskTWithPrivatesQTyRD->field_begin()); + KmpTaskSharedsPtr = Address( + CGF.EmitLoadOfScalar(CGF.EmitLValueForField( + Base, *std::next(KmpTaskTQTyRD->field_begin(), + KmpTaskTShareds)), + Loc), + CGF.getNaturalTypeAlignment(SharedsTy)); + } + (void)emitPrivatesInit(CGF, D, KmpTaskSharedsPtr, TDBase, + KmpTaskTWithPrivatesQTyRD, SharedsTy, SharedsPtrTy, + Data, Privates, /*ForDup=*/true); + CGF.FinishFunction(); + return TaskDup; +} + CGOpenMPRuntime::TaskResultTy CGOpenMPRuntime::emitTaskInit(CodeGenFunction &CGF, SourceLocation Loc, const OMPExecutableDirective &D, @@ -3390,6 +3574,15 @@ CGOpenMPRuntime::emitTaskInit(CodeGenFunction &CGF, SourceLocation Loc, ++I; ++IElemInitRef; } + I = Data.LastprivateCopies.begin(); + for (auto *E : Data.LastprivateVars) { + auto *VD = cast<VarDecl>(cast<DeclRefExpr>(E)->getDecl()); + Privates.push_back(std::make_pair( + C.getDeclAlign(VD), + PrivateHelpersTy(VD, cast<VarDecl>(cast<DeclRefExpr>(*I)->getDecl()), + /*PrivateElemInit=*/nullptr))); + ++I; + } llvm::array_pod_sort(Privates.begin(), Privates.end(), array_pod_sort_comparator); auto KmpInt32Ty = C.getIntTypeForBitwidth(/*DestWidth=*/32, /*Signed=*/1); @@ -3420,9 +3613,9 @@ CGOpenMPRuntime::emitTaskInit(CodeGenFunction &CGF, SourceLocation Loc, ->getType(); if (!Privates.empty()) { auto FI = std::next(KmpTaskTWithPrivatesQTyRD->field_begin()); - TaskPrivatesMap = emitTaskPrivateMappingFunction(CGM, Loc, Data.PrivateVars, - Data.FirstprivateVars, - FI->getType(), Privates); + TaskPrivatesMap = emitTaskPrivateMappingFunction( + CGM, Loc, Data.PrivateVars, Data.FirstprivateVars, Data.LastprivateVars, + FI->getType(), Privates); TaskPrivatesMap = CGF.Builder.CreatePointerBitCastOrAddrSpaceCast( TaskPrivatesMap, TaskPrivatesMapTy); } else { @@ -3480,78 +3673,19 @@ CGOpenMPRuntime::emitTaskInit(CodeGenFunction &CGF, SourceLocation Loc, CGF.EmitAggregateCopy(KmpTaskSharedsPtr, Shareds, SharedsTy); } // Emit initial values for private copies (if any). + TaskResultTy Result; bool NeedsCleanup = false; if (!Privates.empty()) { - auto FI = std::next(KmpTaskTWithPrivatesQTyRD->field_begin()); - auto PrivatesBase = CGF.EmitLValueForField(Base, *FI); - FI = cast<RecordDecl>(FI->getType()->getAsTagDecl())->field_begin(); - LValue SharedsBase; - if (!Data.FirstprivateVars.empty()) { - SharedsBase = CGF.MakeAddrLValue( - CGF.Builder.CreatePointerBitCastOrAddrSpaceCast( - KmpTaskSharedsPtr, CGF.ConvertTypeForMem(SharedsPtrTy)), - SharedsTy); - } - CodeGenFunction::CGCapturedStmtInfo CapturesInfo( - cast<CapturedStmt>(*D.getAssociatedStmt())); - for (auto &&Pair : Privates) { - auto *VD = Pair.second.PrivateCopy; - auto *Init = VD->getAnyInitializer(); - LValue PrivateLValue = CGF.EmitLValueForField(PrivatesBase, *FI); - if (Init) { - if (auto *Elem = Pair.second.PrivateElemInit) { - auto *OriginalVD = Pair.second.Original; - auto *SharedField = CapturesInfo.lookup(OriginalVD); - auto SharedRefLValue = - CGF.EmitLValueForField(SharedsBase, SharedField); - SharedRefLValue = CGF.MakeAddrLValue( - Address(SharedRefLValue.getPointer(), C.getDeclAlign(OriginalVD)), - SharedRefLValue.getType(), AlignmentSource::Decl); - QualType Type = OriginalVD->getType(); - if (Type->isArrayType()) { - // Initialize firstprivate array. - if (!isa<CXXConstructExpr>(Init) || - CGF.isTrivialInitializer(Init)) { - // Perform simple memcpy. - CGF.EmitAggregateAssign(PrivateLValue.getAddress(), - SharedRefLValue.getAddress(), Type); - } else { - // Initialize firstprivate array using element-by-element - // intialization. - CGF.EmitOMPAggregateAssign( - PrivateLValue.getAddress(), SharedRefLValue.getAddress(), - Type, [&CGF, Elem, Init, &CapturesInfo]( - Address DestElement, Address SrcElement) { - // Clean up any temporaries needed by the initialization. - CodeGenFunction::OMPPrivateScope InitScope(CGF); - InitScope.addPrivate(Elem, [SrcElement]() -> Address { - return SrcElement; - }); - (void)InitScope.Privatize(); - // Emit initialization for single element. - CodeGenFunction::CGCapturedStmtRAII CapInfoRAII( - CGF, &CapturesInfo); - CGF.EmitAnyExprToMem(Init, DestElement, - Init->getType().getQualifiers(), - /*IsInitializer=*/false); - }); - } - } else { - CodeGenFunction::OMPPrivateScope InitScope(CGF); - InitScope.addPrivate(Elem, [SharedRefLValue]() -> Address { - return SharedRefLValue.getAddress(); - }); - (void)InitScope.Privatize(); - CodeGenFunction::CGCapturedStmtRAII CapInfoRAII(CGF, &CapturesInfo); - CGF.EmitExprAsInit(Init, VD, PrivateLValue, - /*capturedByInit=*/false); - } - } else { - CGF.EmitExprAsInit(Init, VD, PrivateLValue, /*capturedByInit=*/false); - } - } - NeedsCleanup = NeedsCleanup || FI->getType().isDestructedType(); - ++FI; + NeedsCleanup = emitPrivatesInit(CGF, D, KmpTaskSharedsPtr, Base, + KmpTaskTWithPrivatesQTyRD, SharedsTy, + SharedsPtrTy, Data, Privates, + /*ForDup=*/false); + if (isOpenMPTaskLoopDirective(D.getDirectiveKind()) && + (!Data.LastprivateVars.empty() || checkInitIsRequired(CGF, Privates))) { + Result.TaskDupFn = emitTaskDupFunction( + CGM, Loc, D, KmpTaskTWithPrivatesPtrQTy, KmpTaskTWithPrivatesQTyRD, + KmpTaskTQTyRD, SharedsTy, SharedsPtrTy, Data, Privates, + /*WithLastIter=*/!Data.LastprivateVars.empty()); } } // Provide pointer to function with destructors for privates. @@ -3566,7 +3700,6 @@ CGOpenMPRuntime::emitTaskInit(CodeGenFunction &CGF, SourceLocation Loc, CGF.EmitStoreOfScalar(CGF.Builder.CreatePointerBitCastOrAddrSpaceCast( DestructorFn, KmpRoutineEntryPtrTy), Destructor); - TaskResultTy Result; Result.NewTask = NewTask; Result.TaskEntry = TaskEntry; Result.NewTaskNewTaskTTy = NewTaskNewTaskTTy; @@ -3823,7 +3956,10 @@ void CGOpenMPRuntime::emitTaskLoopCall(CodeGenFunction &CGF, SourceLocation Loc, ? CGF.Builder.CreateIntCast(Data.Schedule.getPointer(), CGF.Int64Ty, /*isSigned=*/false) : llvm::ConstantInt::get(CGF.Int64Ty, /*V=*/0), - llvm::ConstantPointerNull::get(CGF.VoidPtrTy)}; + Result.TaskDupFn + ? CGF.Builder.CreatePointerBitCastOrAddrSpaceCast(Result.TaskDupFn, + CGF.VoidPtrTy) + : llvm::ConstantPointerNull::get(CGF.VoidPtrTy)}; CGF.EmitRuntimeCall(createRuntimeFunction(OMPRTL__kmpc_taskloop), TaskArgs); } diff --git a/clang/lib/CodeGen/CGOpenMPRuntime.h b/clang/lib/CodeGen/CGOpenMPRuntime.h index 25d6909dc8e..881bd6a9c3d 100644 --- a/clang/lib/CodeGen/CGOpenMPRuntime.h +++ b/clang/lib/CodeGen/CGOpenMPRuntime.h @@ -93,6 +93,8 @@ struct OMPTaskDataTy final { SmallVector<const Expr *, 4> FirstprivateVars; SmallVector<const Expr *, 4> FirstprivateCopies; SmallVector<const Expr *, 4> FirstprivateInits; + SmallVector<const Expr *, 4> LastprivateVars; + SmallVector<const Expr *, 4> LastprivateCopies; SmallVector<std::pair<OpenMPDependClauseKind, const Expr *>, 4> Dependences; llvm::PointerIntPair<llvm::Value *, 1, bool> Final; llvm::PointerIntPair<llvm::Value *, 1, bool> Schedule; @@ -453,6 +455,7 @@ private: llvm::Value *NewTaskNewTaskTTy = nullptr; LValue TDBase; RecordDecl *KmpTaskTQTyRD = nullptr; + llvm::Value *TaskDupFn = nullptr; }; /// Emit task region for the task directive. The task region is emitted in /// several steps: diff --git a/clang/lib/CodeGen/CGStmtOpenMP.cpp b/clang/lib/CodeGen/CGStmtOpenMP.cpp index 878cf3ff2d1..3c117316ee6 100644 --- a/clang/lib/CodeGen/CGStmtOpenMP.cpp +++ b/clang/lib/CodeGen/CGStmtOpenMP.cpp @@ -740,12 +740,16 @@ bool CodeGenFunction::EmitOMPLastprivateClauseInit( llvm::DenseSet<const VarDecl *> AlreadyEmittedVars; for (const auto *C : D.getClausesOfKind<OMPLastprivateClause>()) { HasAtLeastOneLastprivate = true; + if (isOpenMPTaskLoopDirective(D.getDirectiveKind())) + break; auto IRef = C->varlist_begin(); auto IDestRef = C->destination_exprs().begin(); for (auto *IInit : C->private_copies()) { // Keep the address of the original variable for future update at the end // of the loop. auto *OrigVD = cast<VarDecl>(cast<DeclRefExpr>(*IRef)->getDecl()); + // Taskloops do not require additional initialization, it is done in + // runtime support library. if (AlreadyEmittedVars.insert(OrigVD->getCanonicalDecl()).second) { auto *DestVD = cast<VarDecl>(cast<DeclRefExpr>(*IDestRef)->getDecl()); PrivateScope.addPrivate(DestVD, [this, OrigVD, IRef]() -> Address { @@ -761,12 +765,11 @@ bool CodeGenFunction::EmitOMPLastprivateClauseInit( // for 'firstprivate' clause. if (IInit && !SIMDLCVs.count(OrigVD->getCanonicalDecl())) { auto *VD = cast<VarDecl>(cast<DeclRefExpr>(IInit)->getDecl()); - bool IsRegistered = - PrivateScope.addPrivate(OrigVD, [&]() -> Address { - // Emit private VarDecl with copy init. - EmitDecl(*VD); - return GetAddrOfLocalVar(VD); - }); + bool IsRegistered = PrivateScope.addPrivate(OrigVD, [&]() -> Address { + // Emit private VarDecl with copy init. + EmitDecl(*VD); + return GetAddrOfLocalVar(VD); + }); assert(IsRegistered && "lastprivate var already registered as private"); (void)IsRegistered; @@ -2363,15 +2366,34 @@ void CodeGenFunction::EmitOMPTaskBasedDirective(const OMPExecutableDirective &S, ++IElemInitRef; } } + // Get list of lastprivate variables (for taskloops). + llvm::DenseMap<const VarDecl *, const DeclRefExpr *> LastprivateDstsOrigs; + for (const auto *C : S.getClausesOfKind<OMPLastprivateClause>()) { + auto IRef = C->varlist_begin(); + auto ID = C->destination_exprs().begin(); + for (auto *IInit : C->private_copies()) { + auto *OrigVD = cast<VarDecl>(cast<DeclRefExpr>(*IRef)->getDecl()); + if (EmittedAsPrivate.insert(OrigVD->getCanonicalDecl()).second) { + Data.LastprivateVars.push_back(*IRef); + Data.LastprivateCopies.push_back(IInit); + } + LastprivateDstsOrigs.insert( + {cast<VarDecl>(cast<DeclRefExpr>(*ID)->getDecl()), + cast<DeclRefExpr>(*IRef)}); + ++IRef; + ++ID; + } + } // Build list of dependences. for (const auto *C : S.getClausesOfKind<OMPDependClause>()) for (auto *IRef : C->varlists()) Data.Dependences.push_back(std::make_pair(C->getDependencyKind(), IRef)); - auto &&CodeGen = [PartId, &S, &Data, CS, &BodyGen](CodeGenFunction &CGF, - PrePostActionTy &Action) { + auto &&CodeGen = [PartId, &S, &Data, CS, &BodyGen, &LastprivateDstsOrigs]( + CodeGenFunction &CGF, PrePostActionTy &Action) { // Set proper addresses for generated private copies. OMPPrivateScope Scope(CGF); - if (!Data.PrivateVars.empty() || !Data.FirstprivateVars.empty()) { + if (!Data.PrivateVars.empty() || !Data.FirstprivateVars.empty() || + !Data.LastprivateVars.empty()) { auto *CopyFn = CGF.Builder.CreateLoad( CGF.GetAddrOfLocalVar(CS->getCapturedDecl()->getParam(3))); auto *PrivatesPtr = CGF.Builder.CreateLoad( @@ -2395,7 +2417,26 @@ void CodeGenFunction::EmitOMPTaskBasedDirective(const OMPExecutableDirective &S, PrivatePtrs.push_back(std::make_pair(VD, PrivatePtr)); CallArgs.push_back(PrivatePtr.getPointer()); } + for (auto *E : Data.LastprivateVars) { + auto *VD = cast<VarDecl>(cast<DeclRefExpr>(E)->getDecl()); + Address PrivatePtr = + CGF.CreateMemTemp(CGF.getContext().getPointerType(E->getType()), + ".lastpriv.ptr.addr"); + PrivatePtrs.push_back(std::make_pair(VD, PrivatePtr)); + CallArgs.push_back(PrivatePtr.getPointer()); + } CGF.EmitRuntimeCall(CopyFn, CallArgs); + for (auto &&Pair : LastprivateDstsOrigs) { + auto *OrigVD = cast<VarDecl>(Pair.second->getDecl()); + DeclRefExpr DRE( + const_cast<VarDecl *>(OrigVD), + /*RefersToEnclosingVariableOrCapture=*/CGF.CapturedStmtInfo->lookup( + OrigVD) != nullptr, + Pair.second->getType(), VK_LValue, Pair.second->getExprLoc()); + Scope.addPrivate(Pair.first, [&CGF, &DRE]() { + return CGF.EmitLValue(&DRE).getAddress(); + }); + } for (auto &&Pair : PrivatePtrs) { Address Replacement(CGF.Builder.CreateLoad(Pair.second), CGF.getContext().getDeclAlign(Pair.first)); @@ -3402,6 +3443,7 @@ void CodeGenFunction::EmitOMPTaskLoopBasedDirective(const OMPLoopDirective &S) { mapParam(CGF, cast<DeclRefExpr>(S.getIsLastIterVariable()), *LIP, LoopScope); CGF.EmitOMPPrivateLoopCounters(S, LoopScope); + bool HasLastprivateClause = CGF.EmitOMPLastprivateClauseInit(S, LoopScope); (void)LoopScope.Privatize(); // Emit the loop iteration variable. const Expr *IVExpr = S.getIterationVariable(); @@ -3430,6 +3472,14 @@ void CodeGenFunction::EmitOMPTaskLoopBasedDirective(const OMPLoopDirective &S) { CGF.EmitBranch(ContBlock); CGF.EmitBlock(ContBlock, true); } + // Emit final copy of the lastprivate variables if IsLastIter != 0. + if (HasLastprivateClause) { + CGF.EmitOMPLastprivateClauseFinal( + S, isOpenMPSimdDirective(S.getDirectiveKind()), + CGF.Builder.CreateIsNotNull(CGF.EmitLoadOfScalar( + CGF.GetAddrOfLocalVar(*LIP), /*Volatile=*/false, + (*LIP)->getType(), S.getLocStart()))); + } }; auto &&TaskGen = [&S, SharedsTy, CapturedStruct, IfCond](CodeGenFunction &CGF, llvm::Value *OutlinedFn, |