From 23e8dcbd81759478c5856aedf000867f30c1753b Mon Sep 17 00:00:00 2001 From: Alexey Bataev Date: Fri, 22 Apr 2016 03:56:56 +0000 Subject: [PATCH] [OPENMP] Fix for LCV in simd directives in explicit clauses. If loop control variable for simd-based directives is explicitly marked as linear/lastprivate in clauses, codegen for such construct would crash. Patch fixes this problem. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@267101 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/CodeGen/CGStmtOpenMP.cpp | 209 +++++++++++------- lib/CodeGen/CodeGenFunction.h | 14 +- lib/Sema/SemaOpenMP.cpp | 95 +++++--- test/OpenMP/for_lastprivate_codegen.cpp | 3 - test/OpenMP/for_simd_codegen.cpp | 7 +- .../OpenMP/loops_explicit_clauses_codegen.cpp | 162 ++++++++++++++ test/OpenMP/simd_codegen.cpp | 8 +- 7 files changed, 375 insertions(+), 123 deletions(-) create mode 100644 test/OpenMP/loops_explicit_clauses_codegen.cpp diff --git a/lib/CodeGen/CGStmtOpenMP.cpp b/lib/CodeGen/CGStmtOpenMP.cpp index 3dfef3b0ed..1b4a5ffd52 100644 --- a/lib/CodeGen/CGStmtOpenMP.cpp +++ b/lib/CodeGen/CGStmtOpenMP.cpp @@ -700,6 +700,14 @@ bool CodeGenFunction::EmitOMPLastprivateClauseInit( if (!HaveInsertPoint()) return false; bool HasAtLeastOneLastprivate = false; + llvm::DenseSet SIMDLCVs; + if (isOpenMPSimdDirective(D.getDirectiveKind())) { + auto *LoopDirective = cast(&D); + for (auto *C : LoopDirective->counters()) { + SIMDLCVs.insert( + cast(cast(C)->getDecl())->getCanonicalDecl()); + } + } llvm::DenseSet AlreadyEmittedVars; for (const auto *C : D.getClausesOfKind()) { HasAtLeastOneLastprivate = true; @@ -722,7 +730,7 @@ bool CodeGenFunction::EmitOMPLastprivateClauseInit( // Check if the variable is also a firstprivate: in this case IInit is // not generated. Initialization of this variable will happen in codegen // for 'firstprivate' clause. - if (IInit) { + if (IInit && !SIMDLCVs.count(OrigVD->getCanonicalDecl())) { auto *VD = cast(cast(IInit)->getDecl()); bool IsRegistered = PrivateScope.addPrivate(OrigVD, [&]() -> Address { @@ -743,7 +751,8 @@ bool CodeGenFunction::EmitOMPLastprivateClauseInit( } void CodeGenFunction::EmitOMPLastprivateClauseFinal( - const OMPExecutableDirective &D, llvm::Value *IsLastIterCond) { + const OMPExecutableDirective &D, bool NoFinals, + llvm::Value *IsLastIterCond) { if (!HaveInsertPoint()) return; // Emit following code: @@ -760,16 +769,20 @@ void CodeGenFunction::EmitOMPLastprivateClauseFinal( Builder.CreateCondBr(IsLastIterCond, ThenBB, DoneBB); EmitBlock(ThenBB); } - llvm::DenseMap LoopCountersAndUpdates; + llvm::DenseSet AlreadyEmittedVars; + llvm::DenseMap LoopCountersAndUpdates; if (auto *LoopDirective = dyn_cast(&D)) { auto IC = LoopDirective->counters().begin(); for (auto F : LoopDirective->finals()) { - auto *D = cast(*IC)->getDecl()->getCanonicalDecl(); - LoopCountersAndUpdates[D] = F; + auto *D = + cast(cast(*IC)->getDecl())->getCanonicalDecl(); + if (NoFinals) + AlreadyEmittedVars.insert(D); + else + LoopCountersAndUpdates[D] = F; ++IC; } } - llvm::DenseSet AlreadyEmittedVars; for (const auto *C : D.getClausesOfKind()) { auto IRef = C->varlist_begin(); auto ISrcRef = C->source_exprs().begin(); @@ -782,8 +795,8 @@ void CodeGenFunction::EmitOMPLastprivateClauseFinal( // If lastprivate variable is a loop control variable for loop-based // directive, update its value before copyin back to original // variable. - if (auto *UpExpr = LoopCountersAndUpdates.lookup(CanonicalVD)) - EmitIgnoredExpr(UpExpr); + if (auto *FinalExpr = LoopCountersAndUpdates.lookup(CanonicalVD)) + EmitIgnoredExpr(FinalExpr); auto *SrcVD = cast(cast(*ISrcRef)->getDecl()); auto *DestVD = cast(cast(*IDestRef)->getDecl()); // Get the address of the original variable. @@ -1181,9 +1194,8 @@ void CodeGenFunction::EmitOMPLoopBody(const OMPLoopDirective &D, } // Update the linear variables. for (const auto *C : D.getClausesOfKind()) { - for (auto U : C->updates()) { + for (auto *U : C->updates()) EmitIgnoredExpr(U); - } } // On a continue in the body, jump to the end. @@ -1248,7 +1260,7 @@ void CodeGenFunction::EmitOMPLinearClauseInit(const OMPLoopDirective &D) { return; // Emit inits for the linear variables. for (const auto *C : D.getClausesOfKind()) { - for (auto Init : C->inits()) { + for (auto *Init : C->inits()) { auto *VD = cast(cast(Init)->getDecl()); if (auto *Ref = dyn_cast(VD->getInit()->IgnoreImpCasts())) { AutoVarEmission Emission = EmitAutoVarAlloca(*VD); @@ -1275,43 +1287,42 @@ void CodeGenFunction::EmitOMPLinearClauseInit(const OMPLoopDirective &D) { } } -static void emitLinearClauseFinal( - CodeGenFunction &CGF, const OMPLoopDirective &D, +void CodeGenFunction::EmitOMPLinearClauseFinal( + const OMPLoopDirective &D, const llvm::function_ref &CondGen) { - if (!CGF.HaveInsertPoint()) + if (!HaveInsertPoint()) return; llvm::BasicBlock *DoneBB = nullptr; // Emit the final values of the linear variables. for (const auto *C : D.getClausesOfKind()) { auto IC = C->varlist_begin(); - for (auto F : C->finals()) { + for (auto *F : C->finals()) { if (!DoneBB) { - if (auto *Cond = CondGen(CGF)) { + if (auto *Cond = CondGen(*this)) { // If the first post-update expression is found, emit conditional // block if it was requested. - auto *ThenBB = CGF.createBasicBlock(".omp.linear.pu"); - DoneBB = CGF.createBasicBlock(".omp.linear.pu.done"); - CGF.Builder.CreateCondBr(Cond, ThenBB, DoneBB); - CGF.EmitBlock(ThenBB); + auto *ThenBB = createBasicBlock(".omp.linear.pu"); + DoneBB = createBasicBlock(".omp.linear.pu.done"); + Builder.CreateCondBr(Cond, ThenBB, DoneBB); + EmitBlock(ThenBB); } } auto *OrigVD = cast(cast(*IC)->getDecl()); DeclRefExpr DRE(const_cast(OrigVD), - CGF.CapturedStmtInfo->lookup(OrigVD) != nullptr, + CapturedStmtInfo->lookup(OrigVD) != nullptr, (*IC)->getType(), VK_LValue, (*IC)->getExprLoc()); - Address OrigAddr = CGF.EmitLValue(&DRE).getAddress(); - CodeGenFunction::OMPPrivateScope VarScope(CGF); - VarScope.addPrivate(OrigVD, - [OrigAddr]() -> Address { return OrigAddr; }); + Address OrigAddr = EmitLValue(&DRE).getAddress(); + CodeGenFunction::OMPPrivateScope VarScope(*this); + VarScope.addPrivate(OrigVD, [OrigAddr]() -> Address { return OrigAddr; }); (void)VarScope.Privatize(); - CGF.EmitIgnoredExpr(F); + EmitIgnoredExpr(F); ++IC; } if (auto *PostUpdate = C->getPostUpdateExpr()) - CGF.EmitIgnoredExpr(PostUpdate); + EmitIgnoredExpr(PostUpdate); } if (DoneBB) - CGF.EmitBlock(DoneBB, /*IsFinished=*/true); + EmitBlock(DoneBB, /*IsFinished=*/true); } static void emitAlignedClause(CodeGenFunction &CGF, @@ -1347,25 +1358,34 @@ static void emitAlignedClause(CodeGenFunction &CGF, } } -static void emitPrivateLoopCounters(CodeGenFunction &CGF, - CodeGenFunction::OMPPrivateScope &LoopScope, - ArrayRef Counters, - ArrayRef PrivateCounters) { - if (!CGF.HaveInsertPoint()) +void CodeGenFunction::EmitOMPPrivateLoopCounters( + const OMPLoopDirective &S, CodeGenFunction::OMPPrivateScope &LoopScope) { + if (!HaveInsertPoint()) return; - auto I = PrivateCounters.begin(); - for (auto *E : Counters) { + auto I = S.private_counters().begin(); + for (auto *E : S.counters()) { auto *VD = cast(cast(E)->getDecl()); auto *PrivateVD = cast(cast(*I)->getDecl()); - Address Addr = Address::invalid(); - (void)LoopScope.addPrivate(PrivateVD, [&]() -> Address { + (void)LoopScope.addPrivate(VD, [&]() -> Address { // Emit var without initialization. - auto VarEmission = CGF.EmitAutoVarAlloca(*PrivateVD); - CGF.EmitAutoVarCleanups(VarEmission); - Addr = VarEmission.getAllocatedAddress(); - return Addr; + if (!LocalDeclMap.count(PrivateVD)) { + auto VarEmission = EmitAutoVarAlloca(*PrivateVD); + EmitAutoVarCleanups(VarEmission); + } + DeclRefExpr DRE(const_cast(PrivateVD), + /*RefersToEnclosingVariableOrCapture=*/false, + (*I)->getType(), VK_LValue, (*I)->getExprLoc()); + return EmitLValue(&DRE).getAddress(); }); - (void)LoopScope.addPrivate(VD, [&]() -> Address { return Addr; }); + if (LocalDeclMap.count(VD) || CapturedStmtInfo->lookup(VD) || + VD->hasGlobalStorage()) { + (void)LoopScope.addPrivate(PrivateVD, [&]() -> Address { + DeclRefExpr DRE(const_cast(VD), + LocalDeclMap.count(VD) || CapturedStmtInfo->lookup(VD), + E->getType(), VK_LValue, E->getExprLoc()); + return EmitLValue(&DRE).getAddress(); + }); + } ++I; } } @@ -1377,8 +1397,7 @@ static void emitPreCond(CodeGenFunction &CGF, const OMPLoopDirective &S, return; { CodeGenFunction::OMPPrivateScope PreCondScope(CGF); - emitPrivateLoopCounters(CGF, PreCondScope, S.counters(), - S.private_counters()); + CGF.EmitOMPPrivateLoopCounters(S, PreCondScope); (void)PreCondScope.Privatize(); // Get initial values of real counters. for (auto I : S.inits()) { @@ -1389,25 +1408,35 @@ static void emitPreCond(CodeGenFunction &CGF, const OMPLoopDirective &S, CGF.EmitBranchOnBoolExpr(Cond, TrueBlock, FalseBlock, TrueCount); } -static void -emitPrivateLinearVars(CodeGenFunction &CGF, const OMPExecutableDirective &D, - CodeGenFunction::OMPPrivateScope &PrivateScope) { - if (!CGF.HaveInsertPoint()) +void CodeGenFunction::EmitOMPLinearClause( + const OMPLoopDirective &D, CodeGenFunction::OMPPrivateScope &PrivateScope) { + if (!HaveInsertPoint()) return; + llvm::DenseSet SIMDLCVs; + if (isOpenMPSimdDirective(D.getDirectiveKind())) { + auto *LoopDirective = cast(&D); + for (auto *C : LoopDirective->counters()) { + SIMDLCVs.insert( + cast(cast(C)->getDecl())->getCanonicalDecl()); + } + } for (const auto *C : D.getClausesOfKind()) { auto CurPrivate = C->privates().begin(); for (auto *E : C->varlists()) { auto *VD = cast(cast(E)->getDecl()); auto *PrivateVD = cast(cast(*CurPrivate)->getDecl()); - bool IsRegistered = PrivateScope.addPrivate(VD, [&]() -> Address { - // Emit private VarDecl with copy init. - CGF.EmitVarDecl(*PrivateVD); - return CGF.GetAddrOfLocalVar(PrivateVD); - }); - assert(IsRegistered && "linear var already registered as private"); - // Silence the warning about unused variable. - (void)IsRegistered; + if (!SIMDLCVs.count(VD->getCanonicalDecl())) { + bool IsRegistered = PrivateScope.addPrivate(VD, [&]() -> Address { + // Emit private VarDecl with copy init. + EmitVarDecl(*PrivateVD); + return GetAddrOfLocalVar(PrivateVD); + }); + assert(IsRegistered && "linear var already registered as private"); + // Silence the warning about unused variable. + (void)IsRegistered; + } else + EmitVarDecl(*PrivateVD); ++CurPrivate; } } @@ -1455,9 +1484,13 @@ void CodeGenFunction::EmitOMPSimdFinal( return; llvm::BasicBlock *DoneBB = nullptr; auto IC = D.counters().begin(); + auto IPC = D.private_counters().begin(); for (auto F : D.finals()) { auto *OrigVD = cast(cast((*IC))->getDecl()); - if (LocalDeclMap.count(OrigVD) || CapturedStmtInfo->lookup(OrigVD)) { + auto *PrivateVD = cast(cast((*IPC))->getDecl()); + auto *CED = dyn_cast(OrigVD); + if (LocalDeclMap.count(OrigVD) || CapturedStmtInfo->lookup(OrigVD) || + OrigVD->hasGlobalStorage() || CED) { if (!DoneBB) { if (auto *Cond = CondGen(*this)) { // If the first post-update expression is found, emit conditional @@ -1468,10 +1501,15 @@ void CodeGenFunction::EmitOMPSimdFinal( EmitBlock(ThenBB); } } - DeclRefExpr DRE(const_cast(OrigVD), - CapturedStmtInfo->lookup(OrigVD) != nullptr, - (*IC)->getType(), VK_LValue, (*IC)->getExprLoc()); - Address OrigAddr = EmitLValue(&DRE).getAddress(); + Address OrigAddr = Address::invalid(); + if (CED) + OrigAddr = EmitLValue(CED->getInit()->IgnoreImpCasts()).getAddress(); + else { + DeclRefExpr DRE(const_cast(PrivateVD), + /*RefersToEnclosingVariableOrCapture=*/false, + (*IPC)->getType(), VK_LValue, (*IPC)->getExprLoc()); + OrigAddr = EmitLValue(&DRE).getAddress(); + } OMPPrivateScope VarScope(*this); VarScope.addPrivate(OrigVD, [OrigAddr]() -> Address { return OrigAddr; }); @@ -1479,6 +1517,7 @@ void CodeGenFunction::EmitOMPSimdFinal( EmitIgnoredExpr(F); } ++IC; + ++IPC; } if (DoneBB) EmitBlock(DoneBB, /*IsFinished=*/true); @@ -1531,12 +1570,12 @@ void CodeGenFunction::EmitOMPSimdDirective(const OMPSimdDirective &S) { CGF.EmitOMPLinearClauseInit(S); { OMPPrivateScope LoopScope(CGF); - emitPrivateLoopCounters(CGF, LoopScope, S.counters(), - S.private_counters()); - emitPrivateLinearVars(CGF, S, LoopScope); + CGF.EmitOMPPrivateLoopCounters(S, LoopScope); + CGF.EmitOMPLinearClause(S, LoopScope); CGF.EmitOMPPrivateClause(S, LoopScope); CGF.EmitOMPReductionClauseInit(S, LoopScope); - bool HasLastprivateClause = CGF.EmitOMPLastprivateClauseInit(S, LoopScope); + bool HasLastprivateClause = + CGF.EmitOMPLastprivateClauseInit(S, LoopScope); (void)LoopScope.Privatize(); CGF.EmitOMPInnerLoop(S, LoopScope.requiresCleanups(), S.getCond(), S.getInc(), @@ -1545,17 +1584,17 @@ void CodeGenFunction::EmitOMPSimdDirective(const OMPSimdDirective &S) { CGF.EmitStopPoint(&S); }, [](CodeGenFunction &) {}); + CGF.EmitOMPSimdFinal( + S, [](CodeGenFunction &) -> llvm::Value * { return nullptr; }); // Emit final copy of the lastprivate variables at the end of loops. if (HasLastprivateClause) - CGF.EmitOMPLastprivateClauseFinal(S); + CGF.EmitOMPLastprivateClauseFinal(S, /*NoFinals=*/true); CGF.EmitOMPReductionClauseFinal(S); emitPostUpdateForReductionClause( CGF, S, [](CodeGenFunction &) -> llvm::Value * { return nullptr; }); } - CGF.EmitOMPSimdFinal( + CGF.EmitOMPLinearClauseFinal( S, [](CodeGenFunction &) -> llvm::Value * { return nullptr; }); - emitLinearClauseFinal( - CGF, S, [](CodeGenFunction &) -> llvm::Value * { return nullptr; }); // Emit: if (PreCond) - end. if (ContBlock) { CGF.EmitBranch(ContBlock); @@ -1819,6 +1858,7 @@ bool CodeGenFunction::EmitOMPWorksharingLoop(const OMPLoopDirective &S) { incrementProfileCounter(&S); } + llvm::DenseSet EmittedFinals; emitAlignedClause(*this, S); EmitOMPLinearClauseInit(S); // Emit helper vars inits. @@ -1845,9 +1885,8 @@ bool CodeGenFunction::EmitOMPWorksharingLoop(const OMPLoopDirective &S) { EmitOMPPrivateClause(S, LoopScope); HasLastprivateClause = EmitOMPLastprivateClauseInit(S, LoopScope); EmitOMPReductionClauseInit(S, LoopScope); - emitPrivateLoopCounters(*this, LoopScope, S.counters(), - S.private_counters()); - emitPrivateLinearVars(*this, S, LoopScope); + EmitOMPPrivateLoopCounters(S, LoopScope); + EmitOMPLinearClause(S, LoopScope); (void)LoopScope.Privatize(); // Detect the loop schedule kind and chunk. @@ -1916,6 +1955,13 @@ bool CodeGenFunction::EmitOMPWorksharingLoop(const OMPLoopDirective &S) { LB.getAddress(), UB.getAddress(), ST.getAddress(), IL.getAddress(), Chunk); } + if (isOpenMPSimdDirective(S.getDirectiveKind())) { + EmitOMPSimdFinal(S, + [&](CodeGenFunction &CGF) -> llvm::Value * { + return CGF.Builder.CreateIsNotNull( + CGF.EmitLoadOfScalar(IL, S.getLocStart())); + }); + } EmitOMPReductionClauseFinal(S); // Emit post-update of the reduction variables if IsLastIter != 0. emitPostUpdateForReductionClause( @@ -1926,15 +1972,10 @@ bool CodeGenFunction::EmitOMPWorksharingLoop(const OMPLoopDirective &S) { // Emit final copy of the lastprivate variables if IsLastIter != 0. if (HasLastprivateClause) EmitOMPLastprivateClauseFinal( - S, Builder.CreateIsNotNull(EmitLoadOfScalar(IL, S.getLocStart()))); - } - if (isOpenMPSimdDirective(S.getDirectiveKind())) { - EmitOMPSimdFinal(S, [&](CodeGenFunction &CGF) -> llvm::Value * { - return CGF.Builder.CreateIsNotNull( - CGF.EmitLoadOfScalar(IL, S.getLocStart())); - }); + S, isOpenMPSimdDirective(S.getDirectiveKind()), + Builder.CreateIsNotNull(EmitLoadOfScalar(IL, S.getLocStart()))); } - emitLinearClauseFinal(*this, S, [&](CodeGenFunction &CGF) -> llvm::Value * { + EmitOMPLinearClauseFinal(S, [&](CodeGenFunction &CGF) -> llvm::Value * { return CGF.Builder.CreateIsNotNull( CGF.EmitLoadOfScalar(IL, S.getLocStart())); }); @@ -2101,8 +2142,9 @@ void CodeGenFunction::EmitSections(const OMPExecutableDirective &S) { // Emit final copy of the lastprivate variables if IsLastIter != 0. if (HasLastprivates) CGF.EmitOMPLastprivateClauseFinal( - S, CGF.Builder.CreateIsNotNull( - CGF.EmitLoadOfScalar(IL, S.getLocStart()))); + S, /*NoFinals=*/false, + CGF.Builder.CreateIsNotNull( + CGF.EmitLoadOfScalar(IL, S.getLocStart()))); }; bool HasCancel = false; @@ -2449,8 +2491,7 @@ void CodeGenFunction::EmitOMPDistributeLoop(const OMPDistributeDirective &S) { EmitOMPHelperVar(*this, cast(S.getIsLastIterVariable())); OMPPrivateScope LoopScope(*this); - emitPrivateLoopCounters(*this, LoopScope, S.counters(), - S.private_counters()); + EmitOMPPrivateLoopCounters(S, LoopScope); (void)LoopScope.Privatize(); // Detect the distribute schedule kind and chunk. diff --git a/lib/CodeGen/CodeGenFunction.h b/lib/CodeGen/CodeGenFunction.h index 28754c306b..17b7fcaa25 100644 --- a/lib/CodeGen/CodeGenFunction.h +++ b/lib/CodeGen/CodeGenFunction.h @@ -2309,7 +2309,17 @@ public: /// it is the last iteration of the loop code in associated directive, or to /// 'i1 false' otherwise. If this item is nullptr, no final check is required. void EmitOMPLastprivateClauseFinal(const OMPExecutableDirective &D, + bool NoFinals, llvm::Value *IsLastIterCond = nullptr); + /// Emit initial code for linear clauses. + void EmitOMPLinearClause(const OMPLoopDirective &D, + CodeGenFunction::OMPPrivateScope &PrivateScope); + /// Emit final code for linear clauses. + /// \param CondGen Optional conditional code for final part of codegen for + /// linear clause. + void EmitOMPLinearClauseFinal( + const OMPLoopDirective &D, + const llvm::function_ref &CondGen); /// \brief Emit initial code for reduction variables. Creates reduction copies /// and initializes them with the values according to OpenMP standard. /// @@ -2390,9 +2400,11 @@ public: const llvm::function_ref &PostIncGen); JumpDest getOMPCancelDestination(OpenMPDirectiveKind Kind); + /// Emit initial code for loop counters of loop-based directives. + void EmitOMPPrivateLoopCounters(const OMPLoopDirective &S, + OMPPrivateScope &LoopScope); private: - /// Helpers for the OpenMP loop directives. void EmitOMPLoopBody(const OMPLoopDirective &D, JumpDest LoopExit); void EmitOMPSimdInit(const OMPLoopDirective &D, bool IsMonotonic = false); diff --git a/lib/Sema/SemaOpenMP.cpp b/lib/Sema/SemaOpenMP.cpp index 01474518a5..97647c3f99 100644 --- a/lib/Sema/SemaOpenMP.cpp +++ b/lib/Sema/SemaOpenMP.cpp @@ -1033,9 +1033,9 @@ void Sema::EndOpenMPDSABlock(Stmt *CurDirective) { PopExpressionEvaluationContext(); } -static bool -FinishOpenMPLinearClause(OMPLinearClause &Clause, DeclRefExpr *IV, - Expr *NumIterations, Sema &SemaRef, Scope *S); +static bool FinishOpenMPLinearClause(OMPLinearClause &Clause, DeclRefExpr *IV, + Expr *NumIterations, Sema &SemaRef, + Scope *S, DSAStackTy *Stack); namespace { @@ -3523,8 +3523,8 @@ public: Expr *BuildPreCond(Scope *S, Expr *Cond, llvm::MapVector &Captures) const; /// \brief Build reference expression to the counter be used for codegen. - DeclRefExpr * - BuildCounterVar(llvm::MapVector &Captures) const; + DeclRefExpr *BuildCounterVar(llvm::MapVector &Captures, + DSAStackTy &DSA) const; /// \brief Build reference expression to the private counter be used for /// codegen. Expr *BuildPrivateCounterVar() const; @@ -4063,13 +4063,17 @@ Expr *OpenMPIterationSpaceChecker::BuildPreCond( /// \brief Build reference expression to the counter be used for codegen. DeclRefExpr *OpenMPIterationSpaceChecker::BuildCounterVar( - llvm::MapVector &Captures) const { + llvm::MapVector &Captures, DSAStackTy &DSA) const { auto *VD = dyn_cast(LCDecl); if (!VD) { VD = SemaRef.IsOpenMPCapturedDecl(LCDecl); auto *Ref = buildDeclRefExpr( SemaRef, VD, VD->getType().getNonReferenceType(), DefaultLoc); - Captures.insert(std::make_pair(LCRef, Ref)); + DSAStackTy::DSAVarData Data = DSA.getTopDSA(LCDecl, /*FromParent=*/false); + // If the loop control decl is explicitly marked as private, do not mark it + // as captured again. + if (!isOpenMPPrivate(Data.CKind) || !Data.RefExpr) + Captures.insert(std::make_pair(LCRef, Ref)); return Ref; } return buildDeclRefExpr(SemaRef, VD, VD->getType().getNonReferenceType(), @@ -4283,7 +4287,7 @@ static bool CheckOpenMPIterationSpace( (isOpenMPWorksharingDirective(DKind) || isOpenMPTaskLoopDirective(DKind) || isOpenMPDistributeDirective(DKind)), Captures); - ResultIterSpace.CounterVar = ISC.BuildCounterVar(Captures); + ResultIterSpace.CounterVar = ISC.BuildCounterVar(Captures, DSA); ResultIterSpace.PrivateCounterVar = ISC.BuildPrivateCounterVar(); ResultIterSpace.CounterInit = ISC.BuildCounterInit(); ResultIterSpace.CounterStep = ISC.BuildCounterStep(); @@ -4787,10 +4791,10 @@ CheckOpenMPLoop(OpenMPDirectiveKind DKind, Expr *CollapseLoopCountExpr, } // Build update: IS.CounterVar(Private) = IS.Start + Iter * IS.Step - auto *CounterVar = buildDeclRefExpr( - SemaRef, cast(cast(IS.CounterVar)->getDecl()), - IS.CounterVar->getType(), IS.CounterVar->getExprLoc(), - /*RefersToCapture=*/true); + auto *VD = cast(cast(IS.CounterVar)->getDecl()); + auto *CounterVar = buildDeclRefExpr(SemaRef, VD, IS.CounterVar->getType(), + IS.CounterVar->getExprLoc(), + /*RefersToCapture=*/true); ExprResult Init = BuildCounterInit(SemaRef, CurScope, UpdLoc, CounterVar, IS.CounterInit, Captures); if (!Init.isUsable()) { @@ -4933,7 +4937,8 @@ StmtResult Sema::ActOnOpenMPSimdDirective( for (auto C : Clauses) { if (auto LC = dyn_cast(C)) if (FinishOpenMPLinearClause(*LC, cast(B.IterationVarRef), - B.NumIterations, *this, CurScope)) + B.NumIterations, *this, CurScope, + DSAStack)) return StmtError(); } } @@ -4986,7 +4991,8 @@ StmtResult Sema::ActOnOpenMPForDirective( for (auto C : Clauses) { if (auto LC = dyn_cast(C)) if (FinishOpenMPLinearClause(*LC, cast(B.IterationVarRef), - B.NumIterations, *this, CurScope)) + B.NumIterations, *this, CurScope, + DSAStack)) return StmtError(); } } @@ -5022,7 +5028,8 @@ StmtResult Sema::ActOnOpenMPForSimdDirective( for (auto C : Clauses) { if (auto LC = dyn_cast(C)) if (FinishOpenMPLinearClause(*LC, cast(B.IterationVarRef), - B.NumIterations, *this, CurScope)) + B.NumIterations, *this, CurScope, + DSAStack)) return StmtError(); } } @@ -5238,7 +5245,8 @@ StmtResult Sema::ActOnOpenMPParallelForDirective( for (auto C : Clauses) { if (auto LC = dyn_cast(C)) if (FinishOpenMPLinearClause(*LC, cast(B.IterationVarRef), - B.NumIterations, *this, CurScope)) + B.NumIterations, *this, CurScope, + DSAStack)) return StmtError(); } } @@ -5279,7 +5287,8 @@ StmtResult Sema::ActOnOpenMPParallelForSimdDirective( for (auto C : Clauses) { if (auto LC = dyn_cast(C)) if (FinishOpenMPLinearClause(*LC, cast(B.IterationVarRef), - B.NumIterations, *this, CurScope)) + B.NumIterations, *this, CurScope, + DSAStack)) return StmtError(); } } @@ -6251,7 +6260,8 @@ StmtResult Sema::ActOnOpenMPTargetParallelForDirective( for (auto C : Clauses) { if (auto LC = dyn_cast(C)) if (FinishOpenMPLinearClause(*LC, cast(B.IterationVarRef), - B.NumIterations, *this, CurScope)) + B.NumIterations, *this, CurScope, + DSAStack)) return StmtError(); } } @@ -6474,7 +6484,8 @@ StmtResult Sema::ActOnOpenMPTaskLoopSimdDirective( for (auto C : Clauses) { if (auto LC = dyn_cast(C)) if (FinishOpenMPLinearClause(*LC, cast(B.IterationVarRef), - B.NumIterations, *this, CurScope)) + B.NumIterations, *this, CurScope, + DSAStack)) return StmtError(); } } @@ -8964,9 +8975,9 @@ OMPClause *Sema::ActOnOpenMPLinearClause( buildPostUpdate(*this, ExprPostUpdates)); } -static bool -FinishOpenMPLinearClause(OMPLinearClause &Clause, DeclRefExpr *IV, - Expr *NumIterations, Sema &SemaRef, Scope *S) { +static bool FinishOpenMPLinearClause(OMPLinearClause &Clause, DeclRefExpr *IV, + Expr *NumIterations, Sema &SemaRef, + Scope *S, DSAStackTy *Stack) { // Walk the vars and build update/final expressions for the CodeGen. SmallVector Updates; SmallVector Finals; @@ -8984,10 +8995,27 @@ FinishOpenMPLinearClause(OMPLinearClause &Clause, DeclRefExpr *IV, auto CurPrivate = Clause.privates().begin(); auto LinKind = Clause.getModifier(); for (auto &RefExpr : Clause.varlists()) { + SourceLocation ELoc; + SourceRange ERange; + Expr *SimpleRefExpr = RefExpr; + auto Res = getPrivateItem(SemaRef, SimpleRefExpr, ELoc, ERange, + /*AllowArraySection=*/false); + ValueDecl *D = Res.first; + if (Res.second || !D) { + Updates.push_back(nullptr); + Finals.push_back(nullptr); + HasErrors = true; + continue; + } + if (auto *CED = dyn_cast(D)) { + D = cast(CED->getInit()->IgnoreParenImpCasts()) + ->getMemberDecl(); + } + auto &&Info = Stack->isLoopControlVariable(D); Expr *InitExpr = *CurInit; // Build privatized reference to the current linear var. - auto DE = cast(RefExpr); + auto DE = cast(SimpleRefExpr); Expr *CapturedRef; if (LinKind == OMPC_LINEAR_uval) CapturedRef = cast(DE->getDecl())->getInit(); @@ -8998,18 +9026,27 @@ FinishOpenMPLinearClause(OMPLinearClause &Clause, DeclRefExpr *IV, /*RefersToCapture=*/true); // Build update: Var = InitExpr + IV * Step - ExprResult Update = - BuildCounterUpdate(SemaRef, S, RefExpr->getExprLoc(), *CurPrivate, - InitExpr, IV, Step, /* Subtract */ false); + ExprResult Update; + if (!Info.first) { + Update = + BuildCounterUpdate(SemaRef, S, RefExpr->getExprLoc(), *CurPrivate, + InitExpr, IV, Step, /* Subtract */ false); + } else + Update = *CurPrivate; Update = SemaRef.ActOnFinishFullExpr(Update.get(), DE->getLocStart(), /*DiscardedValue=*/true); // Build final: Var = InitExpr + NumIterations * Step - ExprResult Final = - BuildCounterUpdate(SemaRef, S, RefExpr->getExprLoc(), CapturedRef, - InitExpr, NumIterations, Step, /* Subtract */ false); + ExprResult Final; + if (!Info.first) { + Final = BuildCounterUpdate(SemaRef, S, RefExpr->getExprLoc(), CapturedRef, + InitExpr, NumIterations, Step, + /* Subtract */ false); + } else + Final = *CurPrivate; Final = SemaRef.ActOnFinishFullExpr(Final.get(), DE->getLocStart(), /*DiscardedValue=*/true); + if (!Update.isUsable() || !Final.isUsable()) { Updates.push_back(nullptr); Finals.push_back(nullptr); diff --git a/test/OpenMP/for_lastprivate_codegen.cpp b/test/OpenMP/for_lastprivate_codegen.cpp index f9a2bccdca..2b1d6c3cf9 100644 --- a/test/OpenMP/for_lastprivate_codegen.cpp +++ b/test/OpenMP/for_lastprivate_codegen.cpp @@ -188,7 +188,6 @@ int main() { // LAMBDA: store i8 // LAMBDA: getelementptr inbounds [[SS_TY]], [[SS_TY]]* %{{.+}}, i32 0, i32 2 // LAMBDA: call void (%{{.+}}*, i{{[0-9]+}}, void (i{{[0-9]+}}*, i{{[0-9]+}}*, ...)*, ...) @__kmpc_fork_call(%{{.+}}* @{{.+}}, i{{[0-9]+}} 1, void (i{{[0-9]+}}*, i{{[0-9]+}}*, ...)* bitcast (void (i{{[0-9]+}}*, i{{[0-9]+}}*, [[SS_TY]]*)* [[SS_MICROTASK:@.+]] to void - // LAMBDA: getelementptr inbounds [[SS_TY]], [[SS_TY]]* %{{.+}}, i32 0, i32 0 // LAMBDA: call void @__kmpc_for_static_init_4( // LAMBDA-NOT: getelementptr inbounds [[SS_TY]], [[SS_TY]]* %{{.+}}, i32 0, i32 0 // LAMBDA: call void {{.+}} [[SS_LAMBDA:@[^ ]+]] @@ -371,7 +370,6 @@ int main() { // BLOCKS: store i8 // BLOCKS: getelementptr inbounds [[SS_TY]], [[SS_TY]]* %{{.+}}, i32 0, i32 2 // BLOCKS: call void (%{{.+}}*, i{{[0-9]+}}, void (i{{[0-9]+}}*, i{{[0-9]+}}*, ...)*, ...) @__kmpc_fork_call(%{{.+}}* @{{.+}}, i{{[0-9]+}} 1, void (i{{[0-9]+}}*, i{{[0-9]+}}*, ...)* bitcast (void (i{{[0-9]+}}*, i{{[0-9]+}}*, [[SS_TY]]*)* [[SS_MICROTASK:@.+]] to void -// BLOCKS: getelementptr inbounds [[SS_TY]], [[SS_TY]]* %{{.+}}, i32 0, i32 0 // BLOCKS: call void @__kmpc_for_static_init_4( // BLOCKS-NOT: getelementptr inbounds [[SS_TY]], [[SS_TY]]* %{{.+}}, i32 0, i32 0 // BLOCKS: call void @@ -650,7 +648,6 @@ int main() { // CHECK: store i8 // CHECK: getelementptr inbounds [[SS_TY]], [[SS_TY]]* %{{.+}}, i32 0, i32 2 // CHECK: call void (%{{.+}}*, i{{[0-9]+}}, void (i{{[0-9]+}}*, i{{[0-9]+}}*, ...)*, ...) @__kmpc_fork_call(%{{.+}}* @{{.+}}, i{{[0-9]+}} 1, void (i{{[0-9]+}}*, i{{[0-9]+}}*, ...)* bitcast (void (i{{[0-9]+}}*, i{{[0-9]+}}*, [[SS_TY]]*)* [[SS_MICROTASK:@.+]] to void -// CHECK: getelementptr inbounds [[SS_TY]], [[SS_TY]]* %{{.+}}, i32 0, i32 0 // CHECK: call void @__kmpc_for_static_init_4( // CHECK-NOT: getelementptr inbounds [[SS_TY]], [[SS_TY]]* %{{.+}}, i32 0, i32 0 // CHECK: getelementptr inbounds [[SS_TY]], [[SS_TY]]* %{{.+}}, i32 0, i32 1 diff --git a/test/OpenMP/for_simd_codegen.cpp b/test/OpenMP/for_simd_codegen.cpp index 7c012f0279..1c7291cd8f 100644 --- a/test/OpenMP/for_simd_codegen.cpp +++ b/test/OpenMP/for_simd_codegen.cpp @@ -582,9 +582,10 @@ void collapsed(float *a, float *b, float *c, float *d) { // i,j,l are updated; k is not updated. // CHECK: call void @__kmpc_for_static_fini(%ident_t* {{.+}}, i32 %{{.+}}) // CHECK: br i1 -// CHECK: store i32 3, i32* [[I:%[^,]+]] -// CHECK-NEXT: store i32 5, i32* [[I:%[^,]+]] -// CHECK-NEXT: store i16 9, i16* [[I:%[^,]+]] +// CHECK: store i32 3, i32* +// CHECK-NEXT: store i32 5, +// CHECK-NEXT: store i32 7, +// CHECK-NEXT: store i16 9, i16* // CHECK: call void @__kmpc_barrier(%ident_t* {{.+}}, i32 %{{.+}}) // CHECK: ret void } diff --git a/test/OpenMP/loops_explicit_clauses_codegen.cpp b/test/OpenMP/loops_explicit_clauses_codegen.cpp new file mode 100644 index 0000000000..dc21fd11af --- /dev/null +++ b/test/OpenMP/loops_explicit_clauses_codegen.cpp @@ -0,0 +1,162 @@ +// RUN: %clang_cc1 -verify -fopenmp -x c++ -triple x86_64-unknown-unknown -emit-llvm %s -o - | FileCheck %s +// RUN: %clang_cc1 -fopenmp -x c++ -std=c++11 -triple x86_64-unknown-unknown -emit-pch -o %t %s +// RUN: %clang_cc1 -fopenmp -x c++ -triple x86_64-unknown-unknown -std=c++11 -include-pch %t -verify %s -emit-llvm -o - | FileCheck %s +// expected-no-diagnostics + + +#ifndef HEADER +#define HEADER + +#define N 10 +int foo(); +int bar(); +int k; +// CHECK-LABEL: @main +int main(int argc, char **argv) { + foo(); +// CHECK: @{{.+}}foo +// CHECK: call void @__kmpc_for_static_init_4( +// CHECK-NOT: @k +// CHECK: call void @__kmpc_for_static_fini( +// CHECK-NOT: @k +#pragma omp for private(k) + for (k = 0; k < argc; k++) + ; + foo(); +// CHECK: @{{.+}}foo +// CHECK: call void @__kmpc_for_static_init_8( +// CHECK-NOT: @k +// CHECK: call void @__kmpc_for_static_fini( +// CHECK: store i32 %{{.+}}, i32* @k +#pragma omp for lastprivate(k) collapse(2) + for (int i = 0; i < 2; ++i) + for (k = 0; k < argc; k++) + ; + foo(); +// CHECK: @{{.+}}foo +// CHECK-NOT: @k{{.+}}!llvm.mem.parallel_loop_access +// CHECK: i32 @{{.+}}bar{{.+}}!llvm.mem.parallel_loop_access +// CHECK-NOT: @k{{.+}}!llvm.mem.parallel_loop_access +// CHECK: sdiv i32 +// CHECK: store i32 %{{.+}}, i32* @k, +#pragma omp simd linear(k : 2) + for (k = 0; k < argc; k++) + bar(); +// CHECK: @{{.+}}foo +// CHECK-NOT: @k{{.+}}!llvm.mem.parallel_loop_access +// CHECK: i32 @{{.+}}bar{{.+}}!llvm.mem.parallel_loop_access +// CHECK-NOT: @k{{.+}}!llvm.mem.parallel_loop_access +// CHECK: sdiv i32 +// CHECK: store i32 %{{.+}}, i32* @k, + foo(); +#pragma omp simd lastprivate(k) collapse(2) + for (int i = 0; i < 2; ++i) + for (k = 0; k < argc; k++) + bar() ; + foo(); +// CHECK: @{{.+}}foo +// CHECK-NOT: @k{{.+}}!llvm.mem.parallel_loop_access +// CHECK: i32 @{{.+}}bar{{.+}}!llvm.mem.parallel_loop_access +// CHECK-NOT: @k{{.+}}!llvm.mem.parallel_loop_access +// CHECK: sdiv i32 +// CHECK: store i32 %{{.+}}, i32* @k, +#pragma omp simd + for (k = 0; k < argc; k++) + bar(); + foo(); +// CHECK: @{{.+}}foo +// CHECK-NOT: @k{{.+}}!llvm.mem.parallel_loop_access +// CHECK: i32 @{{.+}}bar{{.+}}!llvm.mem.parallel_loop_access +// CHECK-NOT: @k{{.+}}!llvm.mem.parallel_loop_access +// CHECK: sdiv i32 +// CHECK: store i32 %{{.+}}, i32* @k, +#pragma omp simd collapse(2) + for (int i = 0; i < 2; ++i) + for (k = 0; k < argc; k++) + bar(); +// CHECK: @{{.+}}foo + foo(); + return 0; +} + +struct S { + int k; + S(int argc) { + foo(); +// CHECK: @{{.+}}foo +// CHECK: call void @__kmpc_for_static_init_4( +// CHECK-NOT: getelementptr inbounds %struct.S, %struct.S* %{{.+}}, i32 0, i32 0 +// CHECK: call void @__kmpc_for_static_fini( +// CHECK-NOT: getelementptr inbounds %struct.S, %struct.S* %{{.+}}, i32 0, i32 0 +#pragma omp for private(k) + for (k = 0; k < argc; k++) + ; + foo(); +// CHECK: @{{.+}}foo +// CHECK: call void @__kmpc_for_static_init_8( +// CHECK-NOT: getelementptr inbounds %struct.S, %struct.S* %{{.+}}, i32 0, i32 0 +// CHECK: call void @__kmpc_for_static_fini( +#pragma omp for lastprivate(k) collapse(2) + for (int i = 0; i < 2; ++i) + for (k = 0; k < argc; k++) + ; + foo(); +// CHECK: @{{.+}}foo +// CHECK: getelementptr inbounds %struct.S, %struct.S* %{{.+}}, i32 0, i32 0 +// CHECK: br i1 +// CHECK-NOT: getelementptr inbounds %struct.S, %struct.S* %{{.+}}, i32 0, i32 0 +// CHECK: i32 @{{.+}}bar{{.+}}!llvm.mem.parallel_loop_access +// CHECK-NOT: getelementptr inbounds %struct.S, %struct.S* %{{.+}}, i32 0, i32 0 +// CHECK: add nsw i32 %{{.+}}, 1 +// CHECK: br label {{.+}}, !llvm.loop +// CHECK: getelementptr inbounds %struct.S, %struct.S* %{{.+}}, i32 0, i32 0 +#pragma omp simd linear(k : 2) + for (k = 0; k < argc; k++) + bar(); + foo(); +// CHECK: @{{.+}}foo +// CHECK: getelementptr inbounds %struct.S, %struct.S* %{{.+}}, i32 0, i32 0 +// CHECK: br i1 +// CHECK-NOT: getelementptr inbounds %struct.S, %struct.S* %{{.+}}, i32 0, i32 0 +// CHECK: i32 @{{.+}}bar{{.+}}!llvm.mem.parallel_loop_access +// CHECK-NOT: getelementptr inbounds %struct.S, %struct.S* %{{.+}}, i32 0, i32 0 +// CHECK: add nsw i64 %{{.+}}, 1 +// CHECK: br label {{.+}}, !llvm.loop +// CHECK: getelementptr inbounds %struct.S, %struct.S* %{{.+}}, i32 0, i32 0 +#pragma omp simd lastprivate(k) collapse(2) + for (int i = 0; i < 2; ++i) + for (k = 0; k < argc; k++) + bar(); + foo(); +// CHECK: @{{.+}}foo +// CHECK-NOT: getelementptr inbounds %struct.S, %struct.S* %{{.+}}, i32 0, i32 0 +// CHECK: br i1 +// CHECK-NOT: getelementptr inbounds %struct.S, %struct.S* %{{.+}}, i32 0, i32 0 +// CHECK: i32 @{{.+}}bar{{.+}}!llvm.mem.parallel_loop_access +// CHECK-NOT: getelementptr inbounds %struct.S, %struct.S* %{{.+}}, i32 0, i32 0 +// CHECK: add nsw i32 %{{.+}}, 1 +// CHECK: br label {{.+}}, !llvm.loop +// CHECK: getelementptr inbounds %struct.S, %struct.S* %{{.+}}, i32 0, i32 0 +#pragma omp simd + for (k = 0; k < argc; k++) + bar(); + foo(); +// CHECK: @{{.+}}foo +// CHECK-NOT: getelementptr inbounds %struct.S, %struct.S* %{{.+}}, i32 0, i32 0 +// CHECK: br i1 +// CHECK-NOT: getelementptr inbounds %struct.S, %struct.S* %{{.+}}, i32 0, i32 0 +// CHECK: i32 @{{.+}}bar{{.+}}!llvm.mem.parallel_loop_access +// CHECK-NOT: getelementptr inbounds %struct.S, %struct.S* %{{.+}}, i32 0, i32 0 +// CHECK: add nsw i64 %{{.+}}, 1 +// CHECK: br label {{.+}}, !llvm.loop +// CHECK: getelementptr inbounds %struct.S, %struct.S* %{{.+}}, i32 0, i32 0 +#pragma omp simd collapse(2) + for (int i = 0; i < 2; ++i) + for (k = 0; k < argc; k++) + bar(); +// CHECK: @{{.+}}foo + foo(); + } +} s(N); + +#endif // HEADER diff --git a/test/OpenMP/simd_codegen.cpp b/test/OpenMP/simd_codegen.cpp index a43d999600..852699d813 100644 --- a/test/OpenMP/simd_codegen.cpp +++ b/test/OpenMP/simd_codegen.cpp @@ -209,6 +209,7 @@ void simple(float *a, float *b, float *c, float *d) { // CHECK-NEXT: store i64 [[ADD7_2]], i64* [[OMP_IV7]]{{.*}}!llvm.mem.parallel_loop_access ![[SIMPLE_LOOP7_ID]] } // CHECK: [[SIMPLE_LOOP7_END]] +// CHECK-NEXT: store i64 11, i64* // CHECK-NEXT: [[A_PRIV_VAL:%.+]] = load i32, i32* [[A_PRIV]], // CHECK-NEXT: store i32 [[A_PRIV_VAL]], i32* [[A]], int R; @@ -418,9 +419,10 @@ void collapsed(float *a, float *b, float *c, float *d) { // CHECK: [[COLL1_END]] } // i,j,l are updated; k is not updated. -// CHECK: store i32 3, i32* [[I:%[^,]+]] -// CHECK-NEXT: store i32 5, i32* [[I:%[^,]+]] -// CHECK-NEXT: store i16 9, i16* [[I:%[^,]+]] +// CHECK: store i32 3, i32* +// CHECK-NEXT: store i32 5, i32* +// CHECK-NEXT: store i32 7, i32* +// CHECK-NEXT: store i16 9, i16* // CHECK: ret void } -- 2.40.0