if (RV.isScalar())
EmitNullabilityCheck(LV, RV.getScalarVal(), E->getExprLoc());
EmitStoreThroughLValue(RV, LV);
+ if (getLangOpts().OpenMP)
+ CGM.getOpenMPRuntime().checkAndEmitLastprivateConditional(*this,
+ E->getLHS());
return LV;
}
//
//===----------------------------------------------------------------------===//
+#include "CGOpenMPRuntime.h"
#include "CodeGenFunction.h"
#include "CodeGenModule.h"
#include "clang/AST/StmtVisitor.h"
LValue CodeGenFunction::EmitComplexAssignmentLValue(const BinaryOperator *E) {
assert(E->getOpcode() == BO_Assign);
ComplexPairTy Val; // ignored
- return ComplexExprEmitter(*this).EmitBinAssignLValue(E, Val);
+ LValue LVal = ComplexExprEmitter(*this).EmitBinAssignLValue(E, Val);
+ if (getLangOpts().OpenMP)
+ CGM.getOpenMPRuntime().checkAndEmitLastprivateConditional(*this,
+ E->getLHS());
+ return LVal;
}
typedef ComplexPairTy (ComplexExprEmitter::*CompoundFunc)(
#include "CGCleanup.h"
#include "CGDebugInfo.h"
#include "CGObjCRuntime.h"
+#include "CGOpenMPRuntime.h"
#include "CodeGenFunction.h"
#include "CodeGenModule.h"
#include "ConstantEmitter.h"
else
CGF.EmitStoreThroughLValue(RValue::get(Result), LHSLV);
+ if (CGF.getLangOpts().OpenMP)
+ CGF.CGM.getOpenMPRuntime().checkAndEmitLastprivateConditional(CGF,
+ E->getLHS());
return LHSLV;
}
#include "clang/AST/Decl.h"
#include "clang/AST/OpenMPClause.h"
#include "clang/AST/StmtOpenMP.h"
+#include "clang/AST/StmtVisitor.h"
#include "clang/Basic/BitmaskEnum.h"
#include "clang/CodeGen/ConstantInitBuilder.h"
#include "llvm/ADT/ArrayRef.h"
[VD](const NontemporalDeclsSet &Set) { return Set.count(VD) > 0; });
}
+CGOpenMPRuntime::LastprivateConditionalRAII::LastprivateConditionalRAII(
+ CodeGenFunction &CGF, const OMPExecutableDirective &S, LValue IVLVal)
+ : CGM(CGF.CGM),
+ NeedToPush(llvm::any_of(S.getClausesOfKind<OMPLastprivateClause>(),
+ [](const OMPLastprivateClause *C) {
+ return C->getKind() ==
+ OMPC_LASTPRIVATE_conditional;
+ })) {
+ assert(CGM.getLangOpts().OpenMP && "Not in OpenMP mode.");
+ if (!NeedToPush)
+ return;
+ LastprivateConditionalData &Data =
+ CGM.getOpenMPRuntime().LastprivateConditionalStack.emplace_back();
+ for (const auto *C : S.getClausesOfKind<OMPLastprivateClause>()) {
+ if (C->getKind() != OMPC_LASTPRIVATE_conditional)
+ continue;
+
+ for (const Expr *Ref : C->varlists()) {
+ Data.DeclToUniqeName.try_emplace(
+ cast<DeclRefExpr>(Ref->IgnoreParenImpCasts())->getDecl(),
+ generateUniqueName(CGM, "pl_cond", Ref));
+ }
+ }
+ Data.IVLVal = IVLVal;
+ // In simd only mode or for simd directives no need to generate threadprivate
+ // references for the loop iteration counter, we can use the original one
+ // since outlining cannot happen in simd regions.
+ if (CGF.getLangOpts().OpenMPSimd ||
+ isOpenMPSimdDirective(S.getDirectiveKind())) {
+ Data.UseOriginalIV = true;
+ return;
+ }
+ llvm::SmallString<16> Buffer;
+ llvm::raw_svector_ostream OS(Buffer);
+ PresumedLoc PLoc =
+ CGM.getContext().getSourceManager().getPresumedLoc(S.getBeginLoc());
+ assert(PLoc.isValid() && "Source location is expected to be always valid.");
+
+ llvm::sys::fs::UniqueID ID;
+ if (auto EC = llvm::sys::fs::getUniqueID(PLoc.getFilename(), ID))
+ CGM.getDiags().Report(diag::err_cannot_open_file)
+ << PLoc.getFilename() << EC.message();
+ OS << "$pl_cond_" << ID.getDevice() << "_" << ID.getFile() << "_"
+ << PLoc.getLine() << "_" << PLoc.getColumn() << "$iv";
+ Data.IVName = OS.str();
+
+ // Global loop counter. Required to handle inner parallel-for regions.
+ // global_iv = &iv;
+ QualType PtrIVTy = CGM.getContext().getPointerType(IVLVal.getType());
+ Address GlobIVAddr = CGM.getOpenMPRuntime().getAddrOfArtificialThreadPrivate(
+ CGF, PtrIVTy, Data.IVName);
+ LValue GlobIVLVal = CGF.MakeAddrLValue(GlobIVAddr, PtrIVTy);
+ CGF.EmitStoreOfScalar(IVLVal.getPointer(CGF), GlobIVLVal);
+}
+
+CGOpenMPRuntime::LastprivateConditionalRAII::~LastprivateConditionalRAII() {
+ if (!NeedToPush)
+ return;
+ CGM.getOpenMPRuntime().LastprivateConditionalStack.pop_back();
+}
+
+namespace {
+/// Checks if the lastprivate conditional variable is referenced in LHS.
+class LastprivateConditionalRefChecker final
+ : public ConstStmtVisitor<LastprivateConditionalRefChecker, bool> {
+ CodeGenFunction &CGF;
+ ArrayRef<CGOpenMPRuntime::LastprivateConditionalData> LPM;
+ const Expr *FoundE = nullptr;
+ const Decl *FoundD = nullptr;
+ StringRef UniqueDeclName;
+ LValue IVLVal;
+ StringRef IVName;
+ SourceLocation Loc;
+ bool UseOriginalIV = false;
+
+public:
+ bool VisitDeclRefExpr(const DeclRefExpr *E) {
+ for (const CGOpenMPRuntime::LastprivateConditionalData &D :
+ llvm::reverse(LPM)) {
+ auto It = D.DeclToUniqeName.find(E->getDecl());
+ if (It == D.DeclToUniqeName.end())
+ continue;
+ FoundE = E;
+ FoundD = E->getDecl()->getCanonicalDecl();
+ UniqueDeclName = It->getSecond();
+ IVLVal = D.IVLVal;
+ IVName = D.IVName;
+ UseOriginalIV = D.UseOriginalIV;
+ break;
+ }
+ return FoundE == E;
+ }
+ bool VisitMemberExpr(const MemberExpr *E) {
+ if (!CGF.IsWrappedCXXThis(E->getBase()))
+ return false;
+ for (const CGOpenMPRuntime::LastprivateConditionalData &D :
+ llvm::reverse(LPM)) {
+ auto It = D.DeclToUniqeName.find(E->getMemberDecl());
+ if (It == D.DeclToUniqeName.end())
+ continue;
+ FoundE = E;
+ FoundD = E->getMemberDecl()->getCanonicalDecl();
+ UniqueDeclName = It->getSecond();
+ IVLVal = D.IVLVal;
+ IVName = D.IVName;
+ UseOriginalIV = D.UseOriginalIV;
+ break;
+ }
+ return FoundE == E;
+ }
+ bool VisitStmt(const Stmt *S) {
+ for (const Stmt *Child : S->children()) {
+ if (!Child)
+ continue;
+ if (const auto *E = dyn_cast<Expr>(Child))
+ if (!E->isGLValue())
+ continue;
+ if (Visit(Child))
+ return true;
+ }
+ return false;
+ }
+ explicit LastprivateConditionalRefChecker(
+ CodeGenFunction &CGF,
+ ArrayRef<CGOpenMPRuntime::LastprivateConditionalData> LPM)
+ : CGF(CGF), LPM(LPM) {}
+ std::tuple<const Expr *, const Decl *, StringRef, LValue, StringRef, bool>
+ getFoundData() const {
+ return std::make_tuple(FoundE, FoundD, UniqueDeclName, IVLVal, IVName,
+ UseOriginalIV);
+ }
+};
+} // namespace
+
+void CGOpenMPRuntime::checkAndEmitLastprivateConditional(CodeGenFunction &CGF,
+ const Expr *LHS) {
+ if (CGF.getLangOpts().OpenMP < 50)
+ return;
+ LastprivateConditionalRefChecker Checker(CGF, LastprivateConditionalStack);
+ if (!Checker.Visit(LHS))
+ return;
+ const Expr *FoundE;
+ const Decl *FoundD;
+ StringRef UniqueDeclName;
+ LValue IVLVal;
+ StringRef IVName;
+ bool UseOriginalIV;
+ std::tie(FoundE, FoundD, UniqueDeclName, IVLVal, IVName, UseOriginalIV) =
+ Checker.getFoundData();
+
+ // Last updated loop counter for the lastprivate conditional var.
+ // int<xx> last_iv = 0;
+ llvm::Type *LLIVTy = CGF.ConvertTypeForMem(IVLVal.getType());
+ llvm::Constant *LastIV =
+ getOrCreateInternalVariable(LLIVTy, UniqueDeclName + "$iv");
+ cast<llvm::GlobalVariable>(LastIV)->setAlignment(
+ IVLVal.getAlignment().getAsAlign());
+ LValue LastIVLVal = CGF.MakeNaturalAlignAddrLValue(LastIV, IVLVal.getType());
+
+ // Private address of the lastprivate conditional in the current context.
+ // priv_a
+ LValue LVal = CGF.EmitLValue(FoundE);
+ // Last value of the lastprivate conditional.
+ // decltype(priv_a) last_a;
+ llvm::Constant *Last = getOrCreateInternalVariable(
+ LVal.getAddress(CGF).getElementType(), UniqueDeclName);
+ cast<llvm::GlobalVariable>(Last)->setAlignment(
+ LVal.getAlignment().getAsAlign());
+ LValue LastLVal =
+ CGF.MakeAddrLValue(Last, LVal.getType(), LVal.getAlignment());
+
+ // Global loop counter. Required to handle inner parallel-for regions.
+ // global_iv
+ if (!UseOriginalIV) {
+ QualType PtrIVTy = CGM.getContext().getPointerType(IVLVal.getType());
+ Address IVAddr = getAddrOfArtificialThreadPrivate(CGF, PtrIVTy, IVName);
+ IVLVal =
+ CGF.EmitLoadOfPointerLValue(IVAddr, PtrIVTy->castAs<PointerType>());
+ }
+ llvm::Value *IVVal = CGF.EmitLoadOfScalar(IVLVal, FoundE->getExprLoc());
+
+ // #pragma omp critical(a)
+ // if (last_iv <= iv) {
+ // last_iv = iv;
+ // last_a = priv_a;
+ // }
+ auto &&CodeGen = [&LastIVLVal, &IVLVal, IVVal, &LVal, &LastLVal,
+ FoundE](CodeGenFunction &CGF, PrePostActionTy &Action) {
+ Action.Enter(CGF);
+ llvm::Value *LastIVVal =
+ CGF.EmitLoadOfScalar(LastIVLVal, FoundE->getExprLoc());
+ // (last_iv <= global_iv) ? Check if the variable is updated and store new
+ // value in global var.
+ llvm::Value *CmpRes;
+ if (IVLVal.getType()->isSignedIntegerType()) {
+ CmpRes = CGF.Builder.CreateICmpSLE(LastIVVal, IVVal);
+ } else {
+ assert(IVLVal.getType()->isUnsignedIntegerType() &&
+ "Loop iteration variable must be integer.");
+ CmpRes = CGF.Builder.CreateICmpULE(LastIVVal, IVVal);
+ }
+ llvm::BasicBlock *ThenBB = CGF.createBasicBlock("lp_cond_then");
+ llvm::BasicBlock *ExitBB = CGF.createBasicBlock("lp_cond_exit");
+ CGF.Builder.CreateCondBr(CmpRes, ThenBB, ExitBB);
+ // {
+ CGF.EmitBlock(ThenBB);
+
+ // last_iv = global_iv;
+ CGF.EmitStoreOfScalar(IVVal, LastIVLVal);
+
+ // last_a = priv_a;
+ switch (CGF.getEvaluationKind(LVal.getType())) {
+ case TEK_Scalar: {
+ llvm::Value *PrivVal = CGF.EmitLoadOfScalar(LVal, FoundE->getExprLoc());
+ CGF.EmitStoreOfScalar(PrivVal, LastLVal);
+ break;
+ }
+ case TEK_Complex: {
+ CodeGenFunction::ComplexPairTy PrivVal =
+ CGF.EmitLoadOfComplex(LVal, FoundE->getExprLoc());
+ CGF.EmitStoreOfComplex(PrivVal, LastLVal, /*isInit=*/false);
+ break;
+ }
+ case TEK_Aggregate:
+ llvm_unreachable(
+ "Aggregates are not supported in lastprivate conditional.");
+ }
+ // }
+ CGF.EmitBranch(ExitBB);
+ // There is no need to emit line number for unconditional branch.
+ (void)ApplyDebugLocation::CreateEmpty(CGF);
+ CGF.EmitBlock(ExitBB, /*IsFinished=*/true);
+ };
+
+ if (CGM.getLangOpts().OpenMPSimd) {
+ // Do not emit as a critical region as no parallel region could be emitted.
+ RegionCodeGenTy ThenRCG(CodeGen);
+ ThenRCG(CGF);
+ } else {
+ emitCriticalRegion(CGF, UniqueDeclName, CodeGen, FoundE->getExprLoc());
+ }
+}
+
+void CGOpenMPRuntime::emitLastprivateConditionalFinalUpdate(
+ CodeGenFunction &CGF, LValue PrivLVal, const VarDecl *VD,
+ SourceLocation Loc) {
+ if (CGF.getLangOpts().OpenMP < 50)
+ return;
+ auto It = LastprivateConditionalStack.back().DeclToUniqeName.find(VD);
+ assert(It != LastprivateConditionalStack.back().DeclToUniqeName.end() &&
+ "Unknown lastprivate conditional variable.");
+ StringRef UniqueName = It->getSecond();
+ llvm::GlobalVariable *GV = CGM.getModule().getNamedGlobal(UniqueName);
+ // The variable was not updated in the region - exit.
+ if (!GV)
+ return;
+ LValue LPLVal = CGF.MakeAddrLValue(
+ GV, PrivLVal.getType().getNonReferenceType(), PrivLVal.getAlignment());
+ llvm::Value *Res = CGF.EmitLoadOfScalar(LPLVal, Loc);
+ CGF.EmitStoreOfScalar(Res, PrivLVal);
+}
+
llvm::Function *CGOpenMPSIMDRuntime::emitParallelOutlinedFunction(
const OMPExecutableDirective &D, const VarDecl *ThreadIDVar,
OpenMPDirectiveKind InnermostKind, const RegionCodeGenTy &CodeGen) {
~NontemporalDeclsRAII();
};
+ /// Maps the expression for the lastprivate variable to the global copy used
+ /// to store new value because original variables are not mapped in inner
+ /// parallel regions. Only private copies are captured but we need also to
+ /// store private copy in shared address.
+ /// Also, stores the expression for the private loop counter and it
+ /// threaprivate name.
+ struct LastprivateConditionalData {
+ llvm::SmallDenseMap<CanonicalDeclPtr<const Decl>, SmallString<16>>
+ DeclToUniqeName;
+ LValue IVLVal;
+ SmallString<16> IVName;
+ /// True if original lvalue for loop counter can be used in codegen (simd
+ /// region or simd only mode) and no need to create threadprivate
+ /// references.
+ bool UseOriginalIV = false;
+ };
+ /// Manages list of lastprivate conditional decls for the specified directive.
+ class LastprivateConditionalRAII {
+ CodeGenModule &CGM;
+ const bool NeedToPush;
+
+ public:
+ LastprivateConditionalRAII(CodeGenFunction &CGF,
+ const OMPExecutableDirective &S, LValue IVLVal);
+ ~LastprivateConditionalRAII();
+ };
+
protected:
CodeGenModule &CGM;
StringRef FirstSeparator, Separator;
/// The set is the union of all current stack elements.
llvm::SmallVector<NontemporalDeclsSet, 4> NontemporalDeclsStack;
+ /// Stack for list of addresses of declarations in current context marked as
+ /// lastprivate conditional. The set is the union of all current stack
+ /// elements.
+ llvm::SmallVector<LastprivateConditionalData, 4> LastprivateConditionalStack;
+
/// Flag for keeping track of weather a requires unified_shared_memory
/// directive is present.
bool HasRequiresUnifiedSharedMemory = false;
/// Checks if the \p VD variable is marked as nontemporal declaration in
/// current context.
bool isNontemporalDecl(const ValueDecl *VD) const;
+
+ /// Checks if the provided \p LVal is lastprivate conditional and emits the
+ /// code to update the value of the original variable.
+ /// \code
+ /// lastprivate(conditional: a)
+ /// ...
+ /// <type> a;
+ /// lp_a = ...;
+ /// #pragma omp critical(a)
+ /// if (last_iv_a <= iv) {
+ /// last_iv_a = iv;
+ /// global_a = lp_a;
+ /// }
+ /// \endcode
+ virtual void checkAndEmitLastprivateConditional(CodeGenFunction &CGF,
+ const Expr *LHS);
+
+ /// Gets the address of the global copy used for lastprivate conditional
+ /// update, if any.
+ /// \param PrivLVal LValue for the private copy.
+ /// \param VD Original lastprivate declaration.
+ virtual void emitLastprivateConditionalFinalUpdate(CodeGenFunction &CGF,
+ LValue PrivLVal,
+ const VarDecl *VD,
+ SourceLocation Loc);
};
/// Class supports emissionof SIMD-only code.
llvm::BasicBlock *ThenBB = nullptr;
llvm::BasicBlock *DoneBB = nullptr;
if (IsLastIterCond) {
+ // Emit implicit barrier if at least one lastprivate conditional is found
+ // and this is not a simd mode.
+ if (!getLangOpts().OpenMPSimd &&
+ llvm::any_of(D.getClausesOfKind<OMPLastprivateClause>(),
+ [](const OMPLastprivateClause *C) {
+ return C->getKind() == OMPC_LASTPRIVATE_conditional;
+ })) {
+ CGM.getOpenMPRuntime().emitBarrierCall(*this, D.getBeginLoc(),
+ OMPD_unknown,
+ /*EmitChecks=*/false,
+ /*ForceSimpleCall=*/true);
+ }
ThenBB = createBasicBlock(".omp.lastprivate.then");
DoneBB = createBasicBlock(".omp.lastprivate.done");
Builder.CreateCondBr(IsLastIterCond, ThenBB, DoneBB);
cast<VarDecl>(cast<DeclRefExpr>(*ISrcRef)->getDecl());
const auto *DestVD =
cast<VarDecl>(cast<DeclRefExpr>(*IDestRef)->getDecl());
- // Get the address of the original variable.
- Address OriginalAddr = GetAddrOfLocalVar(DestVD);
// Get the address of the private variable.
Address PrivateAddr = GetAddrOfLocalVar(PrivateVD);
if (const auto *RefTy = PrivateVD->getType()->getAs<ReferenceType>())
PrivateAddr =
Address(Builder.CreateLoad(PrivateAddr),
getNaturalTypeAlignment(RefTy->getPointeeType()));
+ // Store the last value to the private copy in the last iteration.
+ if (C->getKind() == OMPC_LASTPRIVATE_conditional)
+ CGM.getOpenMPRuntime().emitLastprivateConditionalFinalUpdate(
+ *this, MakeAddrLValue(PrivateAddr, (*IRef)->getType()), PrivateVD,
+ (*IRef)->getExprLoc());
+ // Get the address of the original variable.
+ Address OriginalAddr = GetAddrOfLocalVar(DestVD);
EmitOMPCopy(Type, OriginalAddr, PrivateAddr, DestVD, SrcVD, AssignOp);
}
++IRef;
CGF.EmitOMPLinearClause(S, LoopScope);
CGF.EmitOMPPrivateClause(S, LoopScope);
CGF.EmitOMPReductionClauseInit(S, LoopScope);
+ CGOpenMPRuntime::LastprivateConditionalRAII LPCRegion(
+ CGF, S, CGF.EmitLValue(S.getIterationVariable()));
bool HasLastprivateClause = CGF.EmitOMPLastprivateClauseInit(S, LoopScope);
(void)LoopScope.Privatize();
if (isOpenMPTargetExecutionDirective(S.getDirectiveKind()))
/*ForceSimpleCall=*/true);
}
EmitOMPPrivateClause(S, LoopScope);
+ CGOpenMPRuntime::LastprivateConditionalRAII LPCRegion(
+ *this, S, EmitLValue(S.getIterationVariable()));
HasLastprivateClause = EmitOMPLastprivateClauseInit(S, LoopScope);
EmitOMPReductionClauseInit(S, LoopScope);
EmitOMPPrivateLoopCounters(S, LoopScope);
/*ForceSimpleCall=*/true);
}
CGF.EmitOMPPrivateClause(S, LoopScope);
+ CGOpenMPRuntime::LastprivateConditionalRAII LPCRegion(CGF, S, IV);
HasLastprivates = CGF.EmitOMPLastprivateClauseInit(S, LoopScope);
CGF.EmitOMPReductionClauseInit(S, LoopScope);
(void)LoopScope.Privatize();
// RUN: %clang_cc1 -fopenmp -x c++ -triple x86_64-apple-darwin10 -std=c++11 -include-pch %t -verify %s -emit-llvm -o - | FileCheck %s
// RUN: %clang_cc1 -verify -fopenmp -x c++ -std=c++11 -DLAMBDA -triple x86_64-apple-darwin10 -emit-llvm %s -o - | FileCheck -check-prefix=LAMBDA %s
// RUN: %clang_cc1 -verify -fopenmp -x c++ -fblocks -DBLOCKS -triple x86_64-apple-darwin10 -emit-llvm %s -o - | FileCheck -check-prefix=BLOCKS %s
+// RUN: %clang_cc1 -verify -fopenmp -fopenmp-version=50 -DOMP5 -x c++ -triple x86_64-apple-darwin10 -emit-llvm %s -o - | FileCheck %s -check-prefix=CHECK -check-prefix=OMP50
+// RUN: %clang_cc1 -fopenmp -fopenmp-version=50 -DOMP5 -x c++ -std=c++11 -triple x86_64-apple-darwin10 -emit-pch -o %t %s
+// RUN: %clang_cc1 -fopenmp -fopenmp-version=50 -DOMP5 -x c++ -triple x86_64-apple-darwin10 -std=c++11 -include-pch %t -verify %s -emit-llvm -o - | FileCheck %s -check-prefix=CHECK -check-prefix=OMP50
+// RUN: %clang_cc1 -verify -fopenmp -fopenmp-version=50 -DOMP5 -x c++ -std=c++11 -DLAMBDA -triple x86_64-apple-darwin10 -emit-llvm %s -o - | FileCheck -check-prefix=LAMBDA %s
+// RUN: %clang_cc1 -verify -fopenmp -fopenmp-version=50 -DOMP5 -x c++ -fblocks -DBLOCKS -triple x86_64-apple-darwin10 -emit-llvm %s -o - | FileCheck -check-prefix=BLOCKS %s
// RUN: %clang_cc1 -verify -fopenmp-simd -x c++ -triple x86_64-apple-darwin10 -emit-llvm %s -o - | FileCheck --check-prefix SIMD-ONLY0 %s
// RUN: %clang_cc1 -fopenmp-simd -x c++ -std=c++11 -triple x86_64-apple-darwin10 -emit-pch -o %t %s
// RUN: %clang_cc1 -fopenmp-simd -x c++ -triple x86_64-apple-darwin10 -std=c++11 -include-pch %t -verify %s -emit-llvm -o - | FileCheck --check-prefix SIMD-ONLY0 %s
// RUN: %clang_cc1 -verify -fopenmp-simd -x c++ -std=c++11 -DLAMBDA -triple x86_64-apple-darwin10 -emit-llvm %s -o - | FileCheck --check-prefix SIMD-ONLY0 %s
// RUN: %clang_cc1 -verify -fopenmp-simd -x c++ -fblocks -DBLOCKS -triple x86_64-apple-darwin10 -emit-llvm %s -o - | FileCheck --check-prefix SIMD-ONLY0 %s
+// RUN: %clang_cc1 -verify -fopenmp-simd -fopenmp-version=50 -DOMP5 -x c++ -triple x86_64-apple-darwin10 -emit-llvm %s -o - | FileCheck --check-prefix SIMD-ONLY0 %s
+// RUN: %clang_cc1 -fopenmp-simd -fopenmp-version=50 -DOMP5 -x c++ -std=c++11 -triple x86_64-apple-darwin10 -emit-pch -o %t %s
+// RUN: %clang_cc1 -fopenmp-simd -fopenmp-version=50 -DOMP5 -x c++ -triple x86_64-apple-darwin10 -std=c++11 -include-pch %t -verify %s -emit-llvm -o - | FileCheck --check-prefix SIMD-ONLY0 %s
+// RUN: %clang_cc1 -verify -fopenmp-simd -fopenmp-version=50 -DOMP5 -x c++ -std=c++11 -DLAMBDA -triple x86_64-apple-darwin10 -emit-llvm %s -o - | FileCheck --check-prefix SIMD-ONLY0 %s
+// RUN: %clang_cc1 -verify -fopenmp-simd -fopenmp-version=50 -DOMP5 -x c++ -fblocks -DBLOCKS -triple x86_64-apple-darwin10 -emit-llvm %s -o - | FileCheck --check-prefix SIMD-ONLY0 %s
// SIMD-ONLY0-NOT: {{__kmpc|__tgt}}
// expected-no-diagnostics
#ifndef HEADER
#define HEADER
+#ifdef OMP5
+#define CONDITIONAL conditional :
+#else
+#define CONDITIONAL
+#endif //OMP5
+
enum omp_allocator_handle_t {
omp_null_allocator = 0,
omp_default_mem_alloc = 1,
// CHECK-DAG: [[X:@.+]] = global double 0.0
// CHECK-DAG: [[F:@.+]] = global float 0.0
// CHECK-DAG: [[CNT:@.+]] = global i8 0
+// OMP50-DAG: [[IV_REF:@.+]] = {{.*}}common global i32* null
+// OMP50-DAG: [[LAST_IV_F:@.+]] = {{.*}}common global i32 0
+// OMP50-DAG: [[LAST_F:@.+]] = {{.*}}common global float 0.000000e+00,
+
template <typename T>
T tmain() {
S<T> test;
A::x++;
}
#pragma omp parallel
-#pragma omp for allocate(omp_const_mem_alloc :cnt) lastprivate(cnt)
+#pragma omp for allocate(omp_const_mem_alloc :cnt) lastprivate(cnt) lastprivate(CONDITIONAL f)
for (cnt = 0; cnt < 2; ++cnt) {
A::x++;
+ f = 0;
}
return tmain<int>();
#endif
// CHECK: [[GTID_REF:%.+]] = load i{{[0-9]+}}*, i{{[0-9]+}}** [[GTID_ADDR_REF]]
// CHECK: [[GTID:%.+]] = load i{{[0-9]+}}, i{{[0-9]+}}* [[GTID_REF]]
+// OMP50: [[LOCAL_IV_REF:%.+]] = call i8* @__kmpc_threadprivate_cached(%struct.ident_t* @{{.+}}, i32 [[GTID]], i8* bitcast (i32** [[IV_REF]] to i8*), i64 8, i8*** @{{.+}})
+// OMP50: [[BC:%.+]] = bitcast i8* [[LOCAL_IV_REF]] to i32**
+// OMP50: store i32* %{{.+}}, i32** [[BC]],
// CHECK: [[CNT_PRIV:%.+]] = call i8* @__kmpc_alloc(i32 [[GTID]], i64 1, i8* inttoptr (i64 3 to i8*))
// CHECK: call {{.+}} @__kmpc_for_static_init_4(%{{.+}}* @{{.+}}, i32 [[GTID]], i32 34, i32* [[IS_LAST_ADDR:%.+]], i32* [[OMP_LB:%[^,]+]], i32* [[OMP_UB:%[^,]+]], i32* [[OMP_ST:%[^,]+]], i32 1, i32 1)
// UB = min(UB, GlobalUB)
// CHECK-NEXT: [[LB:%.+]] = load i32, i32* [[OMP_LB]]
// CHECK-NEXT: store i32 [[LB]], i32* [[OMP_IV:[^,]+]]
// <Skip loop body>
+// CHECK: store float 0.000000e+00, float* [[F_PRIV:%.+]],
+// OMP50: [[LOCAL_IV_REF:%.+]] = call i8* @__kmpc_threadprivate_cached(%struct.ident_t* @{{.+}}, i32 [[GTID]], i8* bitcast (i32** [[IV_REF]] to i8*), i64 8, i8*** @{{.+}})
+// OMP50: [[BC:%.+]] = bitcast i8* [[LOCAL_IV_REF]] to i32**
+// OMP50: [[IV_ADDR:%.+]] = load i32*, i32** [[BC]],
+// OMP50: [[IV:%.+]] = load i32, i32* [[IV_ADDR]],
+// OMP50: call void @__kmpc_critical(%struct.ident_t* @{{.+}}, i32 [[GTID]], [8 x i32]* [[F_REGION:@.+]])
+// OMP50: [[LAST_IV:%.+]] = load i32, i32* [[LAST_IV_F]],
+// OMP50: [[CMP:%.+]] = icmp sle i32 [[LAST_IV]], [[IV]]
+// OMP50: br i1 [[CMP]], label %[[LP_THEN:.+]], label %[[LP_DONE:[^,]+]]
+
+// OMP50: [[LP_THEN]]:
+// OMP50: store i32 [[IV]], i32* [[LAST_IV_F]],
+// OMP50: [[F_VAL:%.+]] = load float, float* [[F_PRIV]],
+// OMP50: store float [[F_VAL]], float* [[LAST_F]],
+// OMP50: br label %[[LP_DONE]]
+
+// OMP50: [[LP_DONE]]:
+// OMP50: call void @__kmpc_end_critical(%struct.ident_t* @{{.+}}, i32 [[GTID]], [8 x i32]* [[F_REGION]])
// CHECK: call void @__kmpc_for_static_fini(%{{.+}}* @{{.+}}, i32 [[GTID]])
// Check for final copying of private values back to original vars.
// CHECK: [[IS_LAST_VAL:%.+]] = load i32, i32* [[IS_LAST_ADDR]],
// CHECK: [[IS_LAST_ITER:%.+]] = icmp ne i32 [[IS_LAST_VAL]], 0
+// OMP50-NEXT: call void @__kmpc_barrier(%{{.+}}* [[IMPLICIT_BARRIER_LOC]], i{{[0-9]+}} [[GTID]])
// CHECK: br i1 [[IS_LAST_ITER:%.+]], label %[[LAST_THEN:.+]], label %[[LAST_DONE:.+]]
// CHECK: [[LAST_THEN]]
// original cnt=private_cnt;
// CHECK: [[CNT_VAL:%.+]] = load i8, i8* [[CNT_PRIV]],
// CHECK: store i8 [[CNT_VAL]], i8* [[CNT]],
+// OMP50: [[F_VAL:%.+]] = load float, float* [[LAST_F]],
+// OMP50: store float [[F_VAL]], float* [[F_PRIV]],
+// CHECK: [[F_VAL:%.+]] = load float, float* [[F_PRIV]],
+// CHECK: store float [[F_VAL]], float* [[F]],
// CHECK-NEXT: br label %[[LAST_DONE]]
// CHECK: [[LAST_DONE]]
-// RUN: %clang_cc1 -verify -fopenmp -x c++ -triple x86_64-unknown-unknown -emit-llvm %s -fexceptions -fcxx-exceptions -o - | FileCheck %s
-// RUN: %clang_cc1 -fopenmp -x c++ -std=c++11 -triple x86_64-unknown-unknown -fexceptions -fcxx-exceptions -emit-pch -o %t %s
-// RUN: %clang_cc1 -fopenmp -x c++ -triple x86_64-unknown-unknown -fexceptions -fcxx-exceptions -debug-info-kind=limited -std=c++11 -include-pch %t -verify %s -emit-llvm -o - | FileCheck %s
-// RUN: %clang_cc1 -verify -triple x86_64-apple-darwin10 -fopenmp -fexceptions -fcxx-exceptions -debug-info-kind=line-tables-only -x c++ -emit-llvm %s -o - | FileCheck %s --check-prefix=TERM_DEBUG
-// RUN: %clang_cc1 -verify -fopenmp -x c++ -triple x86_64-unknown-unknown -emit-llvm %s -fexceptions -fcxx-exceptions -o - -fopenmp-version=50 -DOMP5 | FileCheck %s --check-prefix=CHECK --check-prefix=OMP50
+// RUN: %clang_cc1 -verify -fopenmp -x c++ -triple x86_64-unknown-unknown -emit-llvm %s -fexceptions -fcxx-exceptions -o - -fopenmp-version=45 | FileCheck %s
+// RUN: %clang_cc1 -fopenmp -x c++ -std=c++11 -triple x86_64-unknown-unknown -fexceptions -fcxx-exceptions -emit-pch -o %t %s -fopenmp-version=45
+// RUN: %clang_cc1 -fopenmp -x c++ -triple x86_64-unknown-unknown -fexceptions -fcxx-exceptions -debug-info-kind=limited -std=c++11 -include-pch %t -verify %s -emit-llvm -o - -fopenmp-version=45 | FileCheck %s
+// RUN: %clang_cc1 -verify -triple x86_64-apple-darwin10 -fopenmp -fexceptions -fcxx-exceptions -debug-info-kind=line-tables-only -x c++ -emit-llvm %s -o - -fopenmp-version=45 | FileCheck %s --check-prefix=TERM_DEBUG
+// RUN: %clang_cc1 -verify -fopenmp -x c++ -triple x86_64-unknown-unknown -emit-llvm %s -fexceptions -fcxx-exceptions -o - -fopenmp-version=50 -DOMP5 | FileCheck %s --check-prefix=CHECK --check-prefix=OMP50 --check-prefix=OMP50RT
// RUN: %clang_cc1 -fopenmp -x c++ -std=c++11 -triple x86_64-unknown-unknown -fexceptions -fcxx-exceptions -emit-pch -o %t %s -fopenmp-version=50 -DOMP5
-// RUN: %clang_cc1 -fopenmp -x c++ -triple x86_64-unknown-unknown -fexceptions -fcxx-exceptions -debug-info-kind=limited -std=c++11 -include-pch %t -verify %s -emit-llvm -o - -fopenmp-version=50 -DOMP5 | FileCheck %s --check-prefix=CHECK --check-prefix=OMP50
+// RUN: %clang_cc1 -fopenmp -x c++ -triple x86_64-unknown-unknown -fexceptions -fcxx-exceptions -debug-info-kind=limited -std=c++11 -include-pch %t -verify %s -emit-llvm -o - -fopenmp-version=50 -DOMP5 | FileCheck %s --check-prefix=CHECK --check-prefix=OMP50 --check-prefix=OMP50RT
-// RUN: %clang_cc1 -verify -fopenmp-simd -x c++ -triple x86_64-unknown-unknown -emit-llvm %s -fexceptions -fcxx-exceptions -o - | FileCheck %s
-// RUN: %clang_cc1 -fopenmp-simd -x c++ -std=c++11 -triple x86_64-unknown-unknown -fexceptions -fcxx-exceptions -emit-pch -o %t %s
-// RUN: %clang_cc1 -fopenmp-simd -x c++ -triple x86_64-unknown-unknown -fexceptions -fcxx-exceptions -debug-info-kind=limited -std=c++11 -include-pch %t -verify %s -emit-llvm -o - | FileCheck %s
-// RUN: %clang_cc1 -verify -triple x86_64-apple-darwin10 -fopenmp-simd -fexceptions -fcxx-exceptions -debug-info-kind=line-tables-only -x c++ -emit-llvm %s -o - | FileCheck --check-prefix=TERM_DEBUG %s
+// RUN: %clang_cc1 -verify -fopenmp-simd -x c++ -triple x86_64-unknown-unknown -emit-llvm %s -fexceptions -fcxx-exceptions -o - -fopenmp-version=45 | FileCheck %s
+// RUN: %clang_cc1 -fopenmp-simd -x c++ -std=c++11 -triple x86_64-unknown-unknown -fexceptions -fcxx-exceptions -emit-pch -o %t %s -fopenmp-version=45
+// RUN: %clang_cc1 -fopenmp-simd -x c++ -triple x86_64-unknown-unknown -fexceptions -fcxx-exceptions -debug-info-kind=limited -std=c++11 -include-pch %t -verify %s -emit-llvm -o - -fopenmp-version=45 | FileCheck %s
+// RUN: %clang_cc1 -verify -triple x86_64-apple-darwin10 -fopenmp-simd -fexceptions -fcxx-exceptions -debug-info-kind=line-tables-only -x c++ -emit-llvm %s -o - -fopenmp-version=45 | FileCheck --check-prefix=TERM_DEBUG %s
// RUN: %clang_cc1 -verify -fopenmp-simd -x c++ -triple x86_64-unknown-unknown -emit-llvm %s -fexceptions -fcxx-exceptions -o - -fopenmp-version=50 -DOMP5 | FileCheck %s --check-prefix=CHECK --check-prefix=OMP50
// RUN: %clang_cc1 -fopenmp-simd -x c++ -std=c++11 -triple x86_64-unknown-unknown -fexceptions -fcxx-exceptions -emit-pch -o %t %s -fopenmp-version=50 -DOMP5
// RUN: %clang_cc1 -fopenmp-simd -x c++ -triple x86_64-unknown-unknown -fexceptions -fcxx-exceptions -debug-info-kind=limited -std=c++11 -include-pch %t -verify %s -emit-llvm -o - -fopenmp-version=50 -DOMP5 | FileCheck %s --check-prefix=CHECK --check-prefix=OMP50
#ifndef HEADER
#define HEADER
+#ifdef OMP5
+#define CONDITIONAL conditional :
+#else
+#define CONDITIONAL
+#endif //OMP5
// CHECK: [[SS_TY:%.+]] = type { i32 }
+// OMP50-DAG: [[LAST_IV:@.+]] = {{.*}}common global i64 0
+// OMP50-DAG: [[LAST_A:@.+]] = {{.*}}common global i32 0
long long get_val() { return 0; }
double *g_ptr;
int A;
// CHECK: store i32 -1, i32* [[A:%.+]],
A = -1;
- #pragma omp simd lastprivate(A)
+ #pragma omp simd lastprivate(CONDITIONAL A)
// CHECK: store i64 0, i64* [[OMP_IV7:%[^,]+]]
// CHECK: br label %[[SIMD_LOOP7_COND:[^,]+]]
// CHECK: [[SIMD_LOOP7_COND]]:
// CHECK-NEXT: [[LC_IT_2:%.+]] = add nsw i64 -10, [[LC_IT_1]]
// CHECK-NEXT: store i64 [[LC_IT_2]], i64* [[LC:%[^,]+]],{{.+}}!llvm.access.group
// CHECK-NEXT: [[LC_VAL:%.+]] = load i64, i64* [[LC]]{{.+}}!llvm.access.group
-// CHECK-NEXT: [[CONV:%.+]] = trunc i64 [[LC_VAL]] to i32
-// CHECK-NEXT: store i32 [[CONV]], i32* [[A_PRIV:%[^,]+]],{{.+}}!llvm.access.group
- A = i;
+// CHECK-NEXT: [[A_VAL:%.+]] = load i32, i32* [[A_PRIV:%[^,]+]],{{.+}}!llvm.access.group
+// CHECK-NEXT: [[CAST:%.+]] = sext i32 [[A_VAL]] to i64
+// CHECK-NEXT: [[ADD:%.+]] = add nsw i64 [[CAST]], [[LC_VAL]]
+// CHECK-NEXT: [[CONV:%.+]] = trunc i64 [[ADD]] to i32
+// CHECK-NEXT: store i32 [[CONV]], i32* [[A_PRIV]],{{.+}}!llvm.access.group
+// OMP50-NEXT: [[IV:%.+]] = load i64, i64* [[OMP_IV7]],{{.+}}!llvm.access.group
+// OMP50RT: call void @__kmpc_critical(%struct.ident_t* {{.+}}, i32 [[GTID:%.+]], [8 x i32]* [[A_REGION:@.+]]),{{.+}}!llvm.access.group
+// OMP50-NEXT: [[LAST_IV_VAL:%.+]] = load i64, i64* [[LAST_IV]],{{.+}}!llvm.access.group
+// OMP50-NEXT: [[CMP:%.+]] = icmp sle i64 [[LAST_IV_VAL]], [[IV]]
+// OMP50-NEXT: br i1 [[CMP]], label %[[LP_THEN:.+]], label %[[LP_DONE:[^,]+]]
+// OMP50: [[LP_THEN]]:
+// OMP50-NEXT: store i64 [[IV]], i64* [[LAST_IV]],{{.+}}!llvm.access.group
+// OMP50-NEXT: [[A_VAL:%.+]] = load i32, i32* [[A_PRIV]],{{.+}}!llvm.access.group
+// OMP50-NEXT: store i32 [[A_VAL]], i32* [[LAST_A]],{{.+}}!llvm.access.group
+// OMP50-NEXT: br label %[[LP_DONE]]
+// OMP50: [[LP_DONE]]:
+// OMP50RT-NEXT: call void @__kmpc_end_critical(%struct.ident_t* {{.+}}, i32 [[GTID]], [8 x i32]* [[A_REGION]]),{{.+}}!llvm.access.group
+ A += i;
// CHECK: [[IV7_2:%.+]] = load i64, i64* [[OMP_IV7]]{{.*}}!llvm.access.group
// CHECK-NEXT: [[ADD7_2:%.+]] = add nsw i64 [[IV7_2]], 1
// CHECK-NEXT: store i64 [[ADD7_2]], i64* [[OMP_IV7]]{{.*}}!llvm.access.group
}
// CHECK: [[SIMPLE_LOOP7_END]]:
// CHECK-NEXT: store i64 11, i64*
+// OMP50-NEXT: [[LAST_A_VAL:%.+]] = load i32, i32* [[LAST_A]],
+// OMP50-NEXT: store i32 [[LAST_A_VAL]], i32* [[A_PRIV]],
// CHECK-NEXT: [[A_PRIV_VAL:%.+]] = load i32, i32* [[A_PRIV]],
// CHECK-NEXT: store i32 [[A_PRIV_VAL]], i32* [[A]],
int R;