Index: include/clang/AST/DataRecursiveASTVisitor.h =================================================================== --- include/clang/AST/DataRecursiveASTVisitor.h +++ include/clang/AST/DataRecursiveASTVisitor.h @@ -2580,6 +2580,15 @@ TRY_TO(TraverseNestedNameSpecifierLoc(C->getQualifierLoc())); TRY_TO(TraverseDeclarationNameInfo(C->getNameInfo())); TRY_TO(VisitOMPClauseList(C)); + for (auto *E : C->lhs_exprs()) { + TRY_TO(TraverseStmt(E)); + } + for (auto *E : C->rhs_exprs()) { + TRY_TO(TraverseStmt(E)); + } + for (auto *E : C->reduction_ops()) { + TRY_TO(TraverseStmt(E)); + } return true; } Index: include/clang/AST/OpenMPClause.h =================================================================== --- include/clang/AST/OpenMPClause.h +++ include/clang/AST/OpenMPClause.h @@ -1301,6 +1301,48 @@ /// \brief Sets the nested name specifier. void setQualifierLoc(NestedNameSpecifierLoc NSL) { QualifierLoc = NSL; } + /// \brief Set list of helper expressions, required for proper codegen of the + /// clause. These expressions represent LHS expression in the final + /// reduction expression performed by the reduction clause. + void setLHSExprs(ArrayRef LHSExprs); + + /// \brief Get the list of helper LHS expressions. + MutableArrayRef getLHSExprs() { + return MutableArrayRef(varlist_end(), varlist_size()); + } + ArrayRef getLHSExprs() const { + return llvm::makeArrayRef(varlist_end(), varlist_size()); + } + + /// \brief Set list of helper expressions, required for proper codegen of the + /// clause. These expressions represent RHS expression in the final + /// reduction expression performed by the reduction clause. + /// Also, variables in these expressions are used for proper initialization of + /// reduction copies. + void setRHSExprs(ArrayRef RHSExprs); + + /// \brief Get the list of helper destination expressions. + MutableArrayRef getRHSExprs() { + return MutableArrayRef(getLHSExprs().end(), varlist_size()); + } + ArrayRef getRHSExprs() const { + return llvm::makeArrayRef(getLHSExprs().end(), varlist_size()); + } + + /// \brief Set list of helper reduction expressions, required for proper + /// codegen of the clause. These expressions are binary expressions or + /// operator/custom reduction call that calculates new value from source + /// helper expressions to destination helper expressions. + void setReductionOps(ArrayRef ReductionOps); + + /// \brief Get the list of helper reduction expressions. + MutableArrayRef getReductionOps() { + return MutableArrayRef(getRHSExprs().end(), varlist_size()); + } + ArrayRef getReductionOps() const { + return llvm::makeArrayRef(getRHSExprs().end(), varlist_size()); + } + public: /// \brief Creates clause with a list of variables \a VL. /// @@ -1311,12 +1353,30 @@ /// \param VL The variables in the clause. /// \param QualifierLoc The nested-name qualifier with location information /// \param NameInfo The full name info for reduction identifier. + /// \param LHSExprs List of helper expressions for proper generation of + /// assignment operation required for copyprivate clause. This list represents + /// LHSs of the reduction expressions. + /// \param RHSExprs List of helper expressions for proper generation of + /// assignment operation required for copyprivate clause. This list represents + /// RHSs of the reduction expressions. + /// Also, variables in these expressions are used for proper initialization of + /// reduction copies. + /// \param ReductionOps List of helper expressions that represents reduction + /// expressions: + /// \code + /// LHSExprs binop RHSExprs; + /// operator binop(LHSExpr, RHSExpr); + /// (LHSExpr, RHSExpr); + /// \endcode + /// Required for proper codegen of final reduction operation performed by the + /// reduction clause. /// static OMPReductionClause * Create(const ASTContext &C, SourceLocation StartLoc, SourceLocation LParenLoc, SourceLocation ColonLoc, SourceLocation EndLoc, ArrayRef VL, NestedNameSpecifierLoc QualifierLoc, - const DeclarationNameInfo &NameInfo); + const DeclarationNameInfo &NameInfo, ArrayRef LHSExprs, + ArrayRef RHSExprs, ArrayRef ReductionOps); /// \brief Creates an empty clause with the place for \a N variables. /// /// \param C AST context. @@ -1331,6 +1391,33 @@ /// \brief Gets the nested name specifier. NestedNameSpecifierLoc getQualifierLoc() const { return QualifierLoc; } + typedef MutableArrayRef::iterator helper_expr_iterator; + typedef ArrayRef::iterator helper_expr_const_iterator; + typedef llvm::iterator_range helper_expr_range; + typedef llvm::iterator_range + helper_expr_const_range; + + helper_expr_const_range lhs_exprs() const { + return helper_expr_const_range(getLHSExprs().begin(), getLHSExprs().end()); + } + helper_expr_range lhs_exprs() { + return helper_expr_range(getLHSExprs().begin(), getLHSExprs().end()); + } + helper_expr_const_range rhs_exprs() const { + return helper_expr_const_range(getRHSExprs().begin(), getRHSExprs().end()); + } + helper_expr_range rhs_exprs() { + return helper_expr_range(getRHSExprs().begin(), getRHSExprs().end()); + } + helper_expr_const_range reduction_ops() const { + return helper_expr_const_range(getReductionOps().begin(), + getReductionOps().end()); + } + helper_expr_range reduction_ops() { + return helper_expr_range(getReductionOps().begin(), + getReductionOps().end()); + } + StmtRange children() { return StmtRange(reinterpret_cast(varlist_begin()), reinterpret_cast(varlist_end())); Index: include/clang/AST/RecursiveASTVisitor.h =================================================================== --- include/clang/AST/RecursiveASTVisitor.h +++ include/clang/AST/RecursiveASTVisitor.h @@ -2610,6 +2610,15 @@ TRY_TO(TraverseNestedNameSpecifierLoc(C->getQualifierLoc())); TRY_TO(TraverseDeclarationNameInfo(C->getNameInfo())); TRY_TO(VisitOMPClauseList(C)); + for (auto *E : C->lhs_exprs()) { + TRY_TO(TraverseStmt(E)); + } + for (auto *E : C->rhs_exprs()) { + TRY_TO(TraverseStmt(E)); + } + for (auto *E : C->reduction_ops()) { + TRY_TO(TraverseStmt(E)); + } return true; } Index: include/clang/Basic/DiagnosticSemaKinds.td =================================================================== --- include/clang/Basic/DiagnosticSemaKinds.td +++ include/clang/Basic/DiagnosticSemaKinds.td @@ -7447,7 +7447,7 @@ def err_omp_reduction_in_task : Error< "reduction variables may not be accessed in an explicit task">; def err_omp_reduction_id_not_compatible : Error< - "variable of type %0 is not valid for specified reduction operation">; + "variable of type %0 is not valid for specified reduction operation: unable to provide default initialization value">; def err_omp_prohibited_region : Error< "region cannot be%select{| closely}0 nested inside '%1' region" "%select{|; perhaps you forget to enclose 'omp %3' directive into a parallel region?|" Index: lib/AST/Stmt.cpp =================================================================== --- lib/AST/Stmt.cpp +++ lib/AST/Stmt.cpp @@ -1457,16 +1457,42 @@ std::copy(A.begin(), A.end(), getFinals().begin()); } +void OMPReductionClause::setLHSExprs(ArrayRef LHSExprs) { + assert( + LHSExprs.size() == varlist_size() && + "Number of LHS expressions is not the same as the preallocated buffer"); + std::copy(LHSExprs.begin(), LHSExprs.end(), varlist_end()); +} + +void OMPReductionClause::setRHSExprs(ArrayRef RHSExprs) { + assert( + RHSExprs.size() == varlist_size() && + "Number of RHS expressions is not the same as the preallocated buffer"); + std::copy(RHSExprs.begin(), RHSExprs.end(), getLHSExprs().end()); +} + +void OMPReductionClause::setReductionOps(ArrayRef ReductionOps) { + assert(ReductionOps.size() == varlist_size() && "Number of reduction " + "expressions is not the same " + "as the preallocated buffer"); + std::copy(ReductionOps.begin(), ReductionOps.end(), getRHSExprs().end()); +} + OMPReductionClause *OMPReductionClause::Create( const ASTContext &C, SourceLocation StartLoc, SourceLocation LParenLoc, SourceLocation EndLoc, SourceLocation ColonLoc, ArrayRef VL, - NestedNameSpecifierLoc QualifierLoc, const DeclarationNameInfo &NameInfo) { + NestedNameSpecifierLoc QualifierLoc, const DeclarationNameInfo &NameInfo, + ArrayRef LHSExprs, ArrayRef RHSExprs, + ArrayRef ReductionOps) { void *Mem = C.Allocate(llvm::RoundUpToAlignment(sizeof(OMPReductionClause), llvm::alignOf()) + - sizeof(Expr *) * VL.size()); + 4 * sizeof(Expr *) * VL.size()); OMPReductionClause *Clause = new (Mem) OMPReductionClause( StartLoc, LParenLoc, EndLoc, ColonLoc, VL.size(), QualifierLoc, NameInfo); Clause->setVarRefs(VL); + Clause->setLHSExprs(LHSExprs); + Clause->setRHSExprs(RHSExprs); + Clause->setReductionOps(ReductionOps); return Clause; } @@ -1474,7 +1500,7 @@ unsigned N) { void *Mem = C.Allocate(llvm::RoundUpToAlignment(sizeof(OMPReductionClause), llvm::alignOf()) + - sizeof(Expr *) * N); + 4 * sizeof(Expr *) * N); return new (Mem) OMPReductionClause(N); } Index: lib/AST/StmtProfile.cpp =================================================================== --- lib/AST/StmtProfile.cpp +++ lib/AST/StmtProfile.cpp @@ -356,6 +356,15 @@ C->getQualifierLoc().getNestedNameSpecifier()); Profiler->VisitName(C->getNameInfo().getName()); VisitOMPClauseList(C); + for (auto *E : C->lhs_exprs()) { + Profiler->VisitStmt(E); + } + for (auto *E : C->rhs_exprs()) { + Profiler->VisitStmt(E); + } + for (auto *E : C->reduction_ops()) { + Profiler->VisitStmt(E); + } } void OMPClauseProfiler::VisitOMPLinearClause(const OMPLinearClause *C) { VisitOMPClauseList(C); Index: lib/CodeGen/CGOpenMPRuntime.h =================================================================== --- lib/CodeGen/CGOpenMPRuntime.h +++ lib/CodeGen/CGOpenMPRuntime.h @@ -100,6 +100,21 @@ // kmp_int32 cpy_size, void *cpy_data, void(*cpy_func)(void *, void *), // kmp_int32 didit); OMPRTL__kmpc_copyprivate, + // Call to kmp_int32 __kmpc_reduce(ident_t *loc, kmp_int32 global_tid, + // kmp_int32 num_vars, size_t reduce_size, void *reduce_data, void + // (*reduce_func)(void *lhs_data, void *rhs_data), kmp_critical_name *lck); + OMPRTL__kmpc_reduce, + // Call to kmp_int32 __kmpc_reduce_nowait(ident_t *loc, kmp_int32 + // global_tid, kmp_int32 num_vars, size_t reduce_size, void *reduce_data, + // void (*reduce_func)(void *lhs_data, void *rhs_data), kmp_critical_name + // *lck); + OMPRTL__kmpc_reduce_nowait, + // Call to void __kmpc_end_reduce(ident_t *loc, kmp_int32 global_tid, + // kmp_critical_name *lck); + OMPRTL__kmpc_end_reduce, + // Call to void __kmpc_end_reduce_nowait(ident_t *loc, kmp_int32 global_tid, + // kmp_critical_name *lck); + OMPRTL__kmpc_end_reduce_nowait, }; /// \brief Values for bit flags used in the ident_t to describe the fields. @@ -506,6 +521,53 @@ llvm::PointerIntPair Final, llvm::Value *TaskFunction, QualType SharedsTy, llvm::Value *Shareds); + /// \brief Emit a code for reduction clause. Next code should be emitted for + /// reduction: + /// \code + /// + /// static kmp_critical_name lock = { 0 }; + /// + /// void reduce_func(void *lhs[], void *rhs[]) { + /// *(Type0*)lhs[0] = ReductionOperation0(*(Type0*)lhs[0], *(Type0*)rhs[0]); + /// ... + /// *(Type-1*)lhs[-1] = + /// ReductionOperation-1(*(Type-1*)lhs[-1], + /// *(Type-1*)rhs[-1]); + /// } + /// + /// ... + /// void *RedList[] = {&[0], ..., &[-1]}; + /// switch (__kmpc_reduce{_nowait}(, , , sizeof(RedList), + /// RedList, reduce_func, &)) { + /// case 1: + /// [0] = ReductionOperation0(*[0], *[0]); + /// ... + /// [-1] = ReductionOperation-1(*[-1], + /// *[-1]); + /// __kmpc_end_reduce{_nowait}(, , &); + /// break; + /// case 2: + /// Atomic([0] = ReductionOperation0(*[0], + /// *[0])); + /// ... + /// Atomic([-1] = ReductionOperation-1(*[-1], + /// *[-1])); + /// break; + /// default:; + /// } + /// \endcode + /// + /// \param LHSExprs List of LHS in \a ReductionOps reduction operations. + /// \param RHSExprs List of RHS in \a ReductionOps reduction operations. + /// \param ReductionOps List of reduction operations in form 'LHS binop RHS' + /// or 'operator binop(LHS, RHS)'. + /// \param WithNowait true if parent directive has also nowait clause, false + /// otherwise. + virtual void emitReduction(CodeGenFunction &CGF, SourceLocation Loc, + ArrayRef LHSExprs, + ArrayRef RHSExprs, + ArrayRef ReductionOps, + bool WithNowait); }; /// \brief RAII for emitting code of CapturedStmt without function outlining. Index: lib/CodeGen/CGOpenMPRuntime.cpp =================================================================== --- lib/CodeGen/CGOpenMPRuntime.cpp +++ lib/CodeGen/CGOpenMPRuntime.cpp @@ -176,11 +176,17 @@ CodeGenFunction::OMPPrivateScope PrivateScope(CGF); CGF.EmitOMPPrivateClause(Directive, PrivateScope); CGF.EmitOMPFirstprivateClause(Directive, PrivateScope); + CGF.EmitOMPReductionClauseInit(Directive, PrivateScope); if (PrivateScope.Privatize()) // Emit implicit barrier to synchronize threads and avoid data races. CGF.CGM.getOpenMPRuntime().emitBarrierCall(CGF, Directive.getLocStart(), OMPD_unknown); CGCapturedStmtInfo::EmitBody(CGF, S); + CGF.EmitOMPReductionClauseFinal(Directive); + // Emit implicit barrier at the end of the directive if there are no + // reductions. + CGF.CGM.getOpenMPRuntime().emitBarrierCall(CGF, Directive.getLocEnd(), + /*Kind=*/OMPD_parallel); } LValue CGOpenMPTaskOutlinedRegionInfo::getThreadIDVariableLValue( @@ -595,6 +601,62 @@ RTLFn = CGM.CreateRuntimeFunction(FnTy, /*Name=*/"__kmpc_copyprivate"); break; } + case OMPRTL__kmpc_reduce: { + // Build kmp_int32 __kmpc_reduce(ident_t *loc, kmp_int32 global_tid, + // kmp_int32 num_vars, size_t reduce_size, void *reduce_data, void + // (*reduce_func)(void *lhs_data, void *rhs_data), kmp_critical_name *lck); + llvm::Type *ReduceTypeParams[] = {CGM.VoidPtrTy, CGM.VoidPtrTy}; + auto *ReduceFnTy = llvm::FunctionType::get(CGM.VoidTy, ReduceTypeParams, + /*isVarArg=*/false); + llvm::Type *TypeParams[] = { + getIdentTyPointerTy(), CGM.Int32Ty, CGM.Int32Ty, CGM.SizeTy, + CGM.VoidPtrTy, ReduceFnTy->getPointerTo(), + llvm::PointerType::getUnqual(KmpCriticalNameTy)}; + llvm::FunctionType *FnTy = + llvm::FunctionType::get(CGM.Int32Ty, TypeParams, /*isVarArg=*/false); + RTLFn = CGM.CreateRuntimeFunction(FnTy, /*Name=*/"__kmpc_reduce"); + break; + } + case OMPRTL__kmpc_reduce_nowait: { + // Build kmp_int32 __kmpc_reduce_nowait(ident_t *loc, kmp_int32 + // global_tid, kmp_int32 num_vars, size_t reduce_size, void *reduce_data, + // void (*reduce_func)(void *lhs_data, void *rhs_data), kmp_critical_name + // *lck); + llvm::Type *ReduceTypeParams[] = {CGM.VoidPtrTy, CGM.VoidPtrTy}; + auto *ReduceFnTy = llvm::FunctionType::get(CGM.VoidTy, ReduceTypeParams, + /*isVarArg=*/false); + llvm::Type *TypeParams[] = { + getIdentTyPointerTy(), CGM.Int32Ty, CGM.Int32Ty, CGM.SizeTy, + CGM.VoidPtrTy, ReduceFnTy->getPointerTo(), + llvm::PointerType::getUnqual(KmpCriticalNameTy)}; + llvm::FunctionType *FnTy = + llvm::FunctionType::get(CGM.Int32Ty, TypeParams, /*isVarArg=*/false); + RTLFn = CGM.CreateRuntimeFunction(FnTy, /*Name=*/"__kmpc_reduce_nowait"); + break; + } + case OMPRTL__kmpc_end_reduce: { + // Build void __kmpc_end_reduce(ident_t *loc, kmp_int32 global_tid, + // kmp_critical_name *lck); + llvm::Type *TypeParams[] = { + getIdentTyPointerTy(), CGM.Int32Ty, + llvm::PointerType::getUnqual(KmpCriticalNameTy)}; + llvm::FunctionType *FnTy = + llvm::FunctionType::get(CGM.VoidTy, TypeParams, /*isVarArg=*/false); + RTLFn = CGM.CreateRuntimeFunction(FnTy, /*Name=*/"__kmpc_end_reduce"); + break; + } + case OMPRTL__kmpc_end_reduce_nowait: { + // Build __kmpc_end_reduce_nowait(ident_t *loc, kmp_int32 global_tid, + // kmp_critical_name *lck); + llvm::Type *TypeParams[] = { + getIdentTyPointerTy(), CGM.Int32Ty, + llvm::PointerType::getUnqual(KmpCriticalNameTy)}; + llvm::FunctionType *FnTy = + llvm::FunctionType::get(CGM.VoidTy, TypeParams, /*isVarArg=*/false); + RTLFn = + CGM.CreateRuntimeFunction(FnTy, /*Name=*/"__kmpc_end_reduce_nowait"); + break; + } } return RTLFn; } @@ -1522,6 +1584,285 @@ CGF.EmitRuntimeCall(createRuntimeFunction(OMPRTL__kmpc_omp_task), TaskArgs); } +static llvm::Value *emitReductionFunction(CodeGenModule &CGM, + llvm::Type *ArgsType, + ArrayRef LHSExprs, + ArrayRef RHSExprs, + ArrayRef ReductionOps) { + auto &C = CGM.getContext(); + + // void reduction_func(void *LHSArg, void *RHSArg); + FunctionArgList Args; + ImplicitParamDecl LHSArg(C, /*DC=*/nullptr, SourceLocation(), /*Id=*/nullptr, + C.VoidPtrTy); + ImplicitParamDecl RHSArg(C, /*DC=*/nullptr, SourceLocation(), /*Id=*/nullptr, + C.VoidPtrTy); + Args.push_back(&LHSArg); + Args.push_back(&RHSArg); + FunctionType::ExtInfo EI; + auto &CGFI = CGM.getTypes().arrangeFreeFunctionDeclaration( + C.VoidTy, Args, EI, /*isVariadic=*/false); + auto *Fn = llvm::Function::Create( + CGM.getTypes().GetFunctionType(CGFI), llvm::GlobalValue::InternalLinkage, + ".omp.reduction.reduction_func", &CGM.getModule()); + CGM.SetLLVMFunctionAttributes(/*D=*/nullptr, CGFI, Fn); + CodeGenFunction CGF(CGM); + CGF.StartFunction(GlobalDecl(), C.VoidTy, Fn, CGFI, Args); + + // Dst = (void*[n])(LHSArg); + // Src = (void*[n])(RHSArg); + auto *LHS = CGF.Builder.CreatePointerBitCastOrAddrSpaceCast( + CGF.Builder.CreateAlignedLoad(CGF.GetAddrOfLocalVar(&LHSArg), + CGF.PointerAlignInBytes), + ArgsType); + auto *RHS = CGF.Builder.CreatePointerBitCastOrAddrSpaceCast( + CGF.Builder.CreateAlignedLoad(CGF.GetAddrOfLocalVar(&RHSArg), + CGF.PointerAlignInBytes), + ArgsType); + + // *(Type0*)lhs[0] = ReductionOperation0(*(Type0*)lhs[0], *(Type0*)rhs[0]); + // ... + // *(Type-1*)lhs[-1] = ReductionOperation-1(*(Type-1*)lhs[-1], + // *(Type-1*)rhs[-1]); + CodeGenFunction::OMPPrivateScope Scope(CGF); + for (unsigned I = 0, E = ReductionOps.size(); I < E; ++I) { + Scope.addPrivate( + cast(cast(RHSExprs[I])->getDecl()), + [&]() -> llvm::Value *{ + return CGF.Builder.CreatePointerBitCastOrAddrSpaceCast( + CGF.Builder.CreateAlignedLoad( + CGF.Builder.CreateStructGEP(/*Ty=*/nullptr, RHS, I), + CGM.PointerAlignInBytes), + CGF.ConvertTypeForMem(C.getPointerType(RHSExprs[I]->getType()))); + }); + Scope.addPrivate( + cast(cast(LHSExprs[I])->getDecl()), + [&]() -> llvm::Value *{ + return CGF.Builder.CreatePointerBitCastOrAddrSpaceCast( + CGF.Builder.CreateAlignedLoad( + CGF.Builder.CreateStructGEP(/*Ty=*/nullptr, LHS, I), + CGM.PointerAlignInBytes), + CGF.ConvertTypeForMem(C.getPointerType(LHSExprs[I]->getType()))); + }); + } + Scope.Privatize(); + for (auto *E : ReductionOps) { + CGF.EmitIgnoredExpr(E); + } + Scope.ForceCleanup(); + CGF.FinishFunction(); + return Fn; +} + +namespace { +class CallEndCleanup : public EHScopeStack::Cleanup { +private: + const llvm::function_ref CodeGen; + +public: + CallEndCleanup(const llvm::function_ref &CodeGen) + : CodeGen(CodeGen) {} + void Emit(CodeGenFunction &CGF, Flags /*flags*/) override { CodeGen(CGF); } +}; +} // namespace + +void CGOpenMPRuntime::emitReduction(CodeGenFunction &CGF, SourceLocation Loc, + ArrayRef LHSExprs, + ArrayRef RHSExprs, + ArrayRef ReductionOps, + bool WithNowait) { + // Next code should be emitted for reduction: + // + // static kmp_critical_name lock = { 0 }; + // + // void reduce_func(void *lhs[], void *rhs[]) { + // *(Type0*)lhs[0] = ReductionOperation0(*(Type0*)lhs[0], *(Type0*)rhs[0]); + // ... + // *(Type-1*)lhs[-1] = ReductionOperation-1(*(Type-1*)lhs[-1], + // *(Type-1*)rhs[-1]); + // } + // + // ... + // void *RedList[] = {&[0], ..., &[-1]}; + // switch (__kmpc_reduce{_nowait}(, , , sizeof(RedList), + // RedList, reduce_func, &)) { + // case 1: + // [0] = ReductionOperation0(*[0], *[0]); + // ... + // [-1] = ReductionOperation-1(*[-1], + // *[-1]); + // __kmpc_end_reduce{_nowait}(, , &); + // break; + // case 2: + // Atomic([0] = ReductionOperation0(*[0], + // *[0])); + // ... + // Atomic([-1] = ReductionOperation-1(*[-1], + // *[-1])); + // break; + // default:; + // } + + auto &C = CGM.getContext(); + + // 1. Build a list of reduction variables. + // void *RedList[] = {[0], ..., [-1]}; + llvm::APInt ArraySize(/*unsigned int numBits=*/32, RHSExprs.size()); + QualType ReductionArrayTy = + C.getConstantArrayType(C.VoidPtrTy, ArraySize, ArrayType::Normal, + /*IndexTypeQuals=*/0); + auto *ReductionList = + CGF.CreateMemTemp(ReductionArrayTy, ".omp.reduction.red_list"); + for (unsigned I = 0, E = RHSExprs.size(); I < E; ++I) { + auto *Elem = CGF.Builder.CreateStructGEP(/*Ty=*/nullptr, ReductionList, I); + CGF.Builder.CreateAlignedStore( + CGF.Builder.CreatePointerBitCastOrAddrSpaceCast( + CGF.EmitLValue(RHSExprs[I]).getAddress(), CGF.VoidPtrTy), + Elem, CGM.PointerAlignInBytes); + } + + // 2. Emit reduce_func(). + auto *ReductionFn = emitReductionFunction( + CGM, CGF.ConvertTypeForMem(ReductionArrayTy)->getPointerTo(), LHSExprs, + RHSExprs, ReductionOps); + + // 3. Create static kmp_critical_name lock = { 0 }; + auto *Lock = getCriticalRegionLock(".reduction"); + + // 4. Build res = __kmpc_reduce{_nowait}(, , , sizeof(RedList), + // RedList, reduce_func, &); + auto *IdentTLoc = emitUpdateLocation( + CGF, Loc, + static_cast(OMP_IDENT_KMPC | OMP_ATOMIC_REDUCE)); + auto *ThreadId = getThreadID(CGF, Loc); + auto *ReductionArrayTySize = llvm::ConstantInt::get( + CGM.SizeTy, C.getTypeSizeInChars(ReductionArrayTy).getQuantity()); + auto *RL = CGF.Builder.CreatePointerBitCastOrAddrSpaceCast(ReductionList, + CGF.VoidPtrTy); + llvm::Value *Args[] = { + IdentTLoc, // ident_t * + ThreadId, // i32 + CGF.Builder.getInt32(RHSExprs.size()), // i32 + ReductionArrayTySize, // size_type sizeof(RedList) + RL, // void *RedList + ReductionFn, // void (*) (void *, void *) + Lock // kmp_critical_name *& + }; + auto Res = CGF.EmitRuntimeCall( + createRuntimeFunction(WithNowait ? OMPRTL__kmpc_reduce_nowait + : OMPRTL__kmpc_reduce), + Args); + + // 5. Build switch(res) + auto *DefaultBB = CGF.createBasicBlock(".omp.reduction.default"); + auto *SwInst = CGF.Builder.CreateSwitch(Res, DefaultBB, /*NumCases=*/2); + + // 6. Build case 1: + // [0] = ReductionOperation0(*[0], *[0]); + // ... + // [-1] = ReductionOperation-1(*[-1], + // *[-1]); + // __kmpc_end_reduce{_nowait}(, , &); + // break; + auto *Case1BB = CGF.createBasicBlock(".omp.reduction.case1"); + SwInst->addCase(CGF.Builder.getInt32(1), Case1BB); + CGF.EmitBlock(Case1BB); + + { + CodeGenFunction::RunCleanupsScope Scope(CGF); + for (auto *E : ReductionOps) { + CGF.EmitIgnoredExpr(E); + } + // Add emission of __kmpc_end_reduce{_nowait}(, , &); + llvm::Value *EndArgs[] = { + IdentTLoc, // ident_t * + ThreadId, // i32 + Lock // kmp_critical_name *& + }; + CGF.EHStack.pushCleanup( + NormalAndEHCleanup, [this, WithNowait, EndArgs](CodeGenFunction &CGF) { + CGF.EmitRuntimeCall( + createRuntimeFunction(WithNowait ? OMPRTL__kmpc_end_reduce_nowait + : OMPRTL__kmpc_end_reduce), + EndArgs); + }); + } + + CGF.EmitBranch(DefaultBB); + + // 7. Build case 2: + // Atomic([0] = ReductionOperation0(*[0], + // *[0])); + // ... + // Atomic([-1] = ReductionOperation-1(*[-1], + // *[-1])); + // break; + auto *Case2BB = CGF.createBasicBlock(".omp.reduction.case2"); + SwInst->addCase(CGF.Builder.getInt32(2), Case2BB); + CGF.EmitBlock(Case2BB); + + { + CodeGenFunction::RunCleanupsScope Scope(CGF); + auto I = LHSExprs.begin(); + for (auto *E : ReductionOps) { + const Expr *XExpr = nullptr; + const Expr *EExpr = nullptr; + const Expr *UpExpr = nullptr; + BinaryOperatorKind BO = BO_Comma; + // Try to emit update expression as a simple atomic. + if (auto *ACO = dyn_cast(E)) { + // If this is a conditional operator, analyze it's condition for + // min/max reduction operator. + E = ACO->getCond(); + } + if (auto *BO = dyn_cast(E)) { + if (BO->getOpcode() == BO_Assign) { + XExpr = BO->getLHS(); + UpExpr = BO->getRHS(); + } + } + // Analyze RHS part of the whole expression. + if (UpExpr) { + if (auto *BORHS = + dyn_cast(UpExpr->IgnoreParenImpCasts())) { + EExpr = BORHS->getRHS(); + BO = BORHS->getOpcode(); + } + } + if (XExpr) { + auto *VD = cast(cast(*I)->getDecl()); + LValue X = CGF.EmitLValue(XExpr); + RValue E; + if (EExpr) + E = CGF.EmitAnyExpr(EExpr); + CGF.EmitOMPAtomicSimpleUpdateExpr( + X, E, BO, /*IsXLHSInRHSPart=*/true, llvm::Monotonic, Loc, + [&CGF, UpExpr, VD](RValue XRValue) { + CodeGenFunction::OMPPrivateScope PrivateScope(CGF); + PrivateScope.addPrivate( + VD, [&CGF, VD, XRValue]() -> llvm::Value *{ + auto *LHSTemp = CGF.CreateMemTemp(VD->getType()); + CGF.EmitStoreThroughLValue( + XRValue, + CGF.MakeNaturalAlignAddrLValue(LHSTemp, VD->getType())); + return LHSTemp; + }); + (void)PrivateScope.Privatize(); + return CGF.EmitAnyExpr(UpExpr); + }); + } else { + // Emit as a critical region. + emitCriticalRegion(CGF, ".atomic_reduction", + [&CGF, E]() { CGF.EmitIgnoredExpr(E); }, Loc); + } + ++I; + } + } + + CGF.EmitBranch(DefaultBB); + CGF.EmitBlock(DefaultBB, /*IsFinished=*/true); +} + InlinedOpenMPRegionRAII::InlinedOpenMPRegionRAII( CodeGenFunction &CGF, const OMPExecutableDirective &D) : CGF(CGF) { Index: lib/CodeGen/CGStmtOpenMP.cpp =================================================================== --- lib/CodeGen/CGStmtOpenMP.cpp +++ lib/CodeGen/CGStmtOpenMP.cpp @@ -224,6 +224,73 @@ } } +void CodeGenFunction::EmitOMPReductionClauseInit( + const OMPExecutableDirective &D, + CodeGenFunction::OMPPrivateScope &PrivateScope) { + auto ReductionFilter = [](const OMPClause *C) -> bool { + return C->getClauseKind() == OMPC_reduction; + }; + for (OMPExecutableDirective::filtered_clause_iterator I(D.clauses(), ReductionFilter); + I; ++I) { + auto *C = cast(*I); + auto ILHS = C->lhs_exprs().begin(); + auto IRHS = C->rhs_exprs().begin(); + for (auto IRef : C->varlists()) { + auto *OrigVD = cast(cast(IRef)->getDecl()); + auto *LHSVD = cast(cast(*ILHS)->getDecl()); + auto *PrivateVD = cast(cast(*IRHS)->getDecl()); + // Store the address of the original variable associated with the LHS + // implicit variable. + PrivateScope.addPrivate(LHSVD, [this, OrigVD, IRef]() -> llvm::Value *{ + DeclRefExpr DRE(const_cast(OrigVD), + CapturedStmtInfo->lookup(OrigVD) != nullptr, + IRef->getType(), VK_LValue, IRef->getExprLoc()); + return EmitLValue(&DRE).getAddress(); + }); + // Emit reduction copy. + bool IsRegistered = + PrivateScope.addPrivate(OrigVD, [this, PrivateVD]() -> llvm::Value *{ + // Emit private VarDecl with reduction init. + EmitDecl(*PrivateVD); + return GetAddrOfLocalVar(PrivateVD); + }); + assert(IsRegistered && "private var already registered as private"); + // Silence the warning about unused variable. + (void)IsRegistered; + ++ILHS, ++IRHS; + } + } +} + +void CodeGenFunction::EmitOMPReductionClauseFinal( + const OMPExecutableDirective &D) { + llvm::SmallVector LHSExprs; + llvm::SmallVector RHSExprs; + llvm::SmallVector ReductionOps; + auto ReductionFilter = [](const OMPClause *C) -> bool { + return C->getClauseKind() == OMPC_reduction; + }; + bool HasAtLeastOneReduction = false; + for (OMPExecutableDirective::filtered_clause_iterator I(D.clauses(), ReductionFilter); + I; ++I) { + HasAtLeastOneReduction = true; + auto *C = cast(*I); + LHSExprs.append(C->lhs_exprs().begin(), C->lhs_exprs().end()); + RHSExprs.append(C->rhs_exprs().begin(), C->rhs_exprs().end()); + ReductionOps.append(C->reduction_ops().begin(), C->reduction_ops().end()); + } + if (HasAtLeastOneReduction) { + // Emit nowait reduction if nowait clause is present or directive is a + // parallel directive (it always has implicit barrier). + CGM.getOpenMPRuntime().emitReduction( + *this, D.getLocEnd(), LHSExprs, RHSExprs, ReductionOps, + D.getSingleClause(OMPC_nowait) || + isOpenMPParallelDirective(D.getDirectiveKind())); + } +} + /// \brief Emits code for OpenMP parallel directive in the parallel region. static void EmitOMPParallelCall(CodeGenFunction &CGF, const OMPParallelDirective &S, @@ -1119,73 +1186,113 @@ CGF.CGM.getOpenMPRuntime().emitFlush(CGF, llvm::None, Loc); } -static Optional -getCompatibleAtomicRMWBinOp(ASTContext &Context, BinaryOperatorKind Op, - bool IsXLHSInRHSPart, LValue XLValue, - RValue ExprRValue) { - Optional RMWOp; - // Allow atomicrmw only if 'x' and 'expr' are integer values, lvalue for 'x' +bool emitOMPAtomicRMW(CodeGenFunction &CGF, LValue X, RValue Update, + BinaryOperatorKind BO, llvm::AtomicOrdering AO, + bool IsXLHSInRHSPart) { + auto &Context = CGF.CGM.getContext(); + // Allow atomicrmw only if 'x' and 'update' are integer values, lvalue for 'x' // expression is simple and atomic is allowed for the given type for the // target platform. - if (ExprRValue.isScalar() && - ExprRValue.getScalarVal()->getType()->isIntegerTy() && - XLValue.isSimple() && - (isa(ExprRValue.getScalarVal()) || - (ExprRValue.getScalarVal()->getType() == - XLValue.getAddress()->getType()->getPointerElementType())) && - Context.getTargetInfo().hasBuiltinAtomic( - Context.getTypeSize(XLValue.getType()), - Context.toBits(XLValue.getAlignment()))) { - switch (Op) { - case BO_Add: - RMWOp = llvm::AtomicRMWInst::Add; - break; - case BO_Sub: - if (IsXLHSInRHSPart) { - RMWOp = llvm::AtomicRMWInst::Sub; - } - break; - case BO_And: - RMWOp = llvm::AtomicRMWInst::And; - break; - case BO_Or: - RMWOp = llvm::AtomicRMWInst::Or; - break; - case BO_Xor: - RMWOp = llvm::AtomicRMWInst::Xor; - break; - case BO_Mul: - case BO_Div: - case BO_Rem: - case BO_Shl: - case BO_Shr: - break; - case BO_PtrMemD: - case BO_PtrMemI: - case BO_LT: - case BO_GT: - case BO_LE: - case BO_GE: - case BO_EQ: - case BO_NE: - case BO_LAnd: - case BO_LOr: - case BO_Assign: - case BO_MulAssign: - case BO_DivAssign: - case BO_RemAssign: - case BO_AddAssign: - case BO_SubAssign: - case BO_ShlAssign: - case BO_ShrAssign: - case BO_AndAssign: - case BO_XorAssign: - case BO_OrAssign: - case BO_Comma: - llvm_unreachable("Unexpected binary operation in 'atomic update'."); + if (BO == BO_Comma || !Update.isScalar() || + !Update.getScalarVal()->getType()->isIntegerTy() || !X.isSimple() || + (!isa(Update.getScalarVal()) && + (Update.getScalarVal()->getType() != + X.getAddress()->getType()->getPointerElementType())) || + !Context.getTargetInfo().hasBuiltinAtomic( + Context.getTypeSize(X.getType()), Context.toBits(X.getAlignment()))) + return false; + + llvm::AtomicRMWInst::BinOp RMWOp; + switch (BO) { + case BO_Add: + RMWOp = llvm::AtomicRMWInst::Add; + break; + case BO_Sub: + if (!IsXLHSInRHSPart) + return false; + RMWOp = llvm::AtomicRMWInst::Sub; + break; + case BO_And: + RMWOp = llvm::AtomicRMWInst::And; + break; + case BO_Or: + RMWOp = llvm::AtomicRMWInst::Or; + break; + case BO_Xor: + RMWOp = llvm::AtomicRMWInst::Xor; + break; + case BO_LT: + RMWOp = X.getType()->hasSignedIntegerRepresentation() + ? (IsXLHSInRHSPart ? llvm::AtomicRMWInst::Min + : llvm::AtomicRMWInst::Max) + : (IsXLHSInRHSPart ? llvm::AtomicRMWInst::UMin + : llvm::AtomicRMWInst::UMax); + break; + case BO_GT: + RMWOp = X.getType()->hasSignedIntegerRepresentation() + ? (IsXLHSInRHSPart ? llvm::AtomicRMWInst::Max + : llvm::AtomicRMWInst::Min) + : (IsXLHSInRHSPart ? llvm::AtomicRMWInst::UMax + : llvm::AtomicRMWInst::UMin); + break; + case BO_Mul: + case BO_Div: + case BO_Rem: + case BO_Shl: + case BO_Shr: + case BO_LAnd: + case BO_LOr: + return false; + case BO_PtrMemD: + case BO_PtrMemI: + case BO_LE: + case BO_GE: + case BO_EQ: + case BO_NE: + case BO_Assign: + case BO_AddAssign: + case BO_SubAssign: + case BO_AndAssign: + case BO_OrAssign: + case BO_XorAssign: + case BO_MulAssign: + case BO_DivAssign: + case BO_RemAssign: + case BO_ShlAssign: + case BO_ShrAssign: + case BO_Comma: + llvm_unreachable("Unsupported atomic update operation"); + } + auto *UpdateVal = Update.getScalarVal(); + if (auto *IC = dyn_cast(UpdateVal)) { + UpdateVal = CGF.Builder.CreateIntCast( + IC, X.getAddress()->getType()->getPointerElementType(), + X.getType()->hasSignedIntegerRepresentation()); + } + CGF.Builder.CreateAtomicRMW(RMWOp, X.getAddress(), UpdateVal, AO); + return true; +} + +void CodeGenFunction::EmitOMPAtomicSimpleUpdateExpr( + LValue X, RValue E, BinaryOperatorKind BO, bool IsXLHSInRHSPart, + llvm::AtomicOrdering AO, SourceLocation Loc, + const llvm::function_ref &CommonGen) { + // Update expressions are allowed to have the following forms: + // x binop= expr; -> xrval + expr; + // x++, ++x -> xrval + 1; + // x--, --x -> xrval - 1; + // x = x binop expr; -> xrval binop expr + // x = expr Op x; - > expr binop xrval; + if (!emitOMPAtomicRMW(*this, X, E, BO, AO, IsXLHSInRHSPart)) { + if (X.isGlobalReg()) { + // Emit an update expression: 'xrval' binop 'expr' or 'expr' binop + // 'xrval'. + EmitStoreThroughLValue(CommonGen(EmitLoadOfLValue(X, Loc)), X); + } else { + // Perform compare-and-swap procedure. + EmitAtomicUpdate(X, AO, CommonGen, X.getType().isVolatileQualified()); } } - return std::move(RMWOp); } static void EmitOMPAtomicUpdateExpr(CodeGenFunction &CGF, bool IsSeqCst, @@ -1201,42 +1308,22 @@ // x--, --x -> xrval - 1; // x = x binop expr; -> xrval binop expr // x = expr Op x; - > expr binop xrval; - assert(X->isLValue() && "X of 'omp atomic write' is not lvalue"); + assert(X->isLValue() && "X of 'omp atomic update' is not lvalue"); LValue XLValue = CGF.EmitLValue(X); RValue ExprRValue = CGF.EmitAnyExpr(E); - const auto &Op = - getCompatibleAtomicRMWBinOp(CGF.CGM.getContext(), BOUE->getOpcode(), - IsXLHSInRHSPart, XLValue, ExprRValue); auto AO = IsSeqCst ? llvm::SequentiallyConsistent : llvm::Monotonic; - if (Op) { - auto *ExprVal = ExprRValue.getScalarVal(); - if (auto *IC = dyn_cast(ExprVal)) { - ExprVal = CGF.Builder.CreateIntCast( - IC, XLValue.getAddress()->getType()->getPointerElementType(), - XLValue.getType()->hasSignedIntegerRepresentation()); - } - CGF.Builder.CreateAtomicRMW(*Op, XLValue.getAddress(), ExprVal, AO); - } else { - auto *LHS = cast(BOUE->getLHS()->IgnoreImpCasts()); - auto *RHS = cast(BOUE->getRHS()->IgnoreImpCasts()); - CodeGenFunction::OpaqueValueMapping MapExpr( - CGF, IsXLHSInRHSPart ? RHS : LHS, ExprRValue); - auto *XRValExpr = IsXLHSInRHSPart ? LHS : RHS; - if (XLValue.isGlobalReg()) { - // Emit an update expression: 'xrval' binop 'expr' or 'expr' binop - // 'xrval'. - CodeGenFunction::OpaqueValueMapping MapX( - CGF, XRValExpr, CGF.EmitLoadOfLValue(XLValue, Loc)); - CGF.EmitStoreThroughLValue(CGF.EmitAnyExpr(UE), XLValue); - } else { - // Perform compare-and-swap procedure. - CGF.EmitAtomicUpdate( - XLValue, AO, [&CGF, &UE, &XRValExpr](RValue XRVal) -> RValue { - CodeGenFunction::OpaqueValueMapping MapX(CGF, XRValExpr, XRVal); - return CGF.EmitAnyExpr(UE); - }, /*IsVolatile=*/false); - } - } + auto *LHS = cast(BOUE->getLHS()->IgnoreImpCasts()); + auto *RHS = cast(BOUE->getRHS()->IgnoreImpCasts()); + auto *XRValExpr = IsXLHSInRHSPart ? LHS : RHS; + auto *ERValExpr = IsXLHSInRHSPart ? RHS : LHS; + auto Gen = + [&CGF, UE, ExprRValue, XRValExpr, ERValExpr](RValue XRValue) -> RValue { + CodeGenFunction::OpaqueValueMapping MapExpr(CGF, ERValExpr, ExprRValue); + CodeGenFunction::OpaqueValueMapping MapX(CGF, XRValExpr, XRValue); + return CGF.EmitAnyExpr(UE); + }; + CGF.EmitOMPAtomicSimpleUpdateExpr(XLValue, ExprRValue, BOUE->getOpcode(), + IsXLHSInRHSPart, AO, Loc, Gen); // OpenMP, 2.12.6, atomic Construct // Any atomic construct with a seq_cst clause forces the atomically // performed operation to include an implicit flush operation without a Index: lib/CodeGen/CodeGenFunction.h =================================================================== --- lib/CodeGen/CodeGenFunction.h +++ lib/CodeGen/CodeGenFunction.h @@ -2029,10 +2029,39 @@ void EmitOMPAggregateAssign(LValue OriginalAddr, llvm::Value *PrivateAddr, const Expr *AssignExpr, QualType Type, const VarDecl *VDInit); + /// \brief Emit atomic update code for constructs: \a X = \a X \a BO \a E or + /// \a X = \a E \a BO \a E. + /// + /// \param X Value to be updated. + /// \param E Update value. + /// \param BO Binary operation for update operation. + /// \param IsXLHSInRHSPart true if \a X is LHS in RHS part of the update + /// expression, false otherwise. + /// \param AO Atomic ordering of the generated atomic instructions. + /// \param CommonGen Code generator for complex expressions that cannot be + /// expressed through atomicrmw instruction. + void EmitOMPAtomicSimpleUpdateExpr( + LValue X, RValue E, BinaryOperatorKind BO, bool IsXLHSInRHSPart, + llvm::AtomicOrdering AO, SourceLocation Loc, + const llvm::function_ref &CommonGen); void EmitOMPFirstprivateClause(const OMPExecutableDirective &D, OMPPrivateScope &PrivateScope); void EmitOMPPrivateClause(const OMPExecutableDirective &D, OMPPrivateScope &PrivateScope); + /// \brief Emit initial code for reduction variables. Creates reduction copies + /// and initializes them with the values according to OpenMP standard. + /// + /// \param D Directive (possibly) with the 'reduction' clause. + /// \param PrivateScope Private scope for capturing reduction variables for + /// proper codegen in internal captured statement. + /// + void EmitOMPReductionClauseInit(const OMPExecutableDirective &D, + OMPPrivateScope &PrivateScope); + /// \brief Emit final update of reduction values to original variables at + /// the end of the directive. + /// + /// \param D Directive that has at least one 'reduction' directives. + void EmitOMPReductionClauseFinal(const OMPExecutableDirective &D); void EmitOMPParallelDirective(const OMPParallelDirective &S); void EmitOMPSimdDirective(const OMPSimdDirective &S); Index: lib/Sema/SemaOpenMP.cpp =================================================================== --- lib/Sema/SemaOpenMP.cpp +++ lib/Sema/SemaOpenMP.cpp @@ -5234,19 +5234,19 @@ switch (OOK) { case OO_Plus: case OO_Minus: - BOK = BO_AddAssign; + BOK = BO_Add; break; case OO_Star: - BOK = BO_MulAssign; + BOK = BO_Mul; break; case OO_Amp: - BOK = BO_AndAssign; + BOK = BO_And; break; case OO_Pipe: - BOK = BO_OrAssign; + BOK = BO_Or; break; case OO_Caret: - BOK = BO_XorAssign; + BOK = BO_Xor; break; case OO_AmpAmp: BOK = BO_LAnd; @@ -5254,7 +5254,44 @@ case OO_PipePipe: BOK = BO_LOr; break; - default: + case OO_New: + case OO_Delete: + case OO_Array_New: + case OO_Array_Delete: + case OO_Slash: + case OO_Percent: + case OO_Tilde: + case OO_Exclaim: + case OO_Equal: + case OO_Less: + case OO_Greater: + case OO_LessEqual: + case OO_GreaterEqual: + case OO_PlusEqual: + case OO_MinusEqual: + case OO_StarEqual: + case OO_SlashEqual: + case OO_PercentEqual: + case OO_CaretEqual: + case OO_AmpEqual: + case OO_PipeEqual: + case OO_LessLess: + case OO_GreaterGreater: + case OO_LessLessEqual: + case OO_GreaterGreaterEqual: + case OO_EqualEqual: + case OO_ExclaimEqual: + case OO_PlusPlus: + case OO_MinusMinus: + case OO_Comma: + case OO_ArrowStar: + case OO_Arrow: + case OO_Call: + case OO_Subscript: + case OO_Conditional: + case NUM_OVERLOADED_OPERATORS: + llvm_unreachable("Unexpected reduction identifier"); + case OO_None: if (auto II = DN.getAsIdentifierInfo()) { if (II->isStr("max")) BOK = BO_GT; @@ -5276,11 +5313,17 @@ } SmallVector Vars; + SmallVector LHSs; + SmallVector RHSs; + SmallVector ReductionOps; for (auto RefExpr : VarList) { assert(RefExpr && "nullptr expr in OpenMP reduction clause."); if (isa(RefExpr)) { // It will be analyzed later. Vars.push_back(RefExpr); + LHSs.push_back(nullptr); + RHSs.push_back(nullptr); + ReductionOps.push_back(nullptr); continue; } @@ -5289,6 +5332,9 @@ RefExpr->containsUnexpandedParameterPack()) { // It will be analyzed later. Vars.push_back(RefExpr); + LHSs.push_back(nullptr); + RHSs.push_back(nullptr); + ReductionOps.push_back(nullptr); continue; } @@ -5381,23 +5427,6 @@ << VD; continue; } - bool Suppress = getDiagnostics().getSuppressAllDiagnostics(); - getDiagnostics().setSuppressAllDiagnostics(true); - ExprResult ReductionOp = - BuildBinOp(DSAStack->getCurScope(), ReductionId.getLocStart(), BOK, - RefExpr, RefExpr); - getDiagnostics().setSuppressAllDiagnostics(Suppress); - if (ReductionOp.isInvalid()) { - Diag(ELoc, diag::err_omp_reduction_id_not_compatible) << Type - << ReductionIdRange; - bool IsDecl = - VD->isThisDeclarationADefinition(Context) == VarDecl::DeclarationOnly; - Diag(VD->getLocation(), - IsDecl ? diag::note_previous_decl : diag::note_defined_here) - << VD; - continue; - } - // OpenMP [2.14.1.1, Data-sharing Attribute Rules for Variables Referenced // in a Construct] // Variables with the predetermined data-sharing attributes may not be @@ -5440,55 +5469,160 @@ continue; } } - - CXXRecordDecl *RD = getLangOpts().CPlusPlus - ? Type.getNonReferenceType()->getAsCXXRecordDecl() - : nullptr; - // FIXME This code must be replaced by actual constructing/destructing of - // the reduction variable. - if (RD) { - CXXConstructorDecl *CD = LookupDefaultConstructor(RD); - PartialDiagnostic PD = - PartialDiagnostic(PartialDiagnostic::NullDiagnostic()); - if (!CD || - CheckConstructorAccess(ELoc, CD, - InitializedEntity::InitializeTemporary(Type), - CD->getAccess(), PD) == AR_inaccessible || - CD->isDeleted()) { - Diag(ELoc, diag::err_omp_required_method) - << getOpenMPClauseName(OMPC_reduction) << 0; - bool IsDecl = VD->isThisDeclarationADefinition(Context) == - VarDecl::DeclarationOnly; - Diag(VD->getLocation(), - IsDecl ? diag::note_previous_decl : diag::note_defined_here) - << VD; - Diag(RD->getLocation(), diag::note_previous_decl) << RD; - continue; + Type = Type.getNonLValueExprType(Context).getUnqualifiedType(); + auto *LHSVD = BuildVarDecl(*this, ELoc, Type, ".reduction.lhs"); + auto *RHSVD = BuildVarDecl(*this, ELoc, Type, VD->getName()); + // Add initializer for private variable. + Expr *Init = nullptr; + switch (BOK) { + case BO_Add: + case BO_Xor: + case BO_Or: + case BO_LOr: + // '+', '-', '^', '|', '||' reduction ops - initializer is '0'. + if (Type->isScalarType() || Type->isAnyComplexType()) { + Init = ActOnIntegerConstant(ELoc, /*Val=*/0).get(); } - MarkFunctionReferenced(ELoc, CD); - DiagnoseUseOfDecl(CD, ELoc); - - CXXDestructorDecl *DD = RD->getDestructor(); - if (DD) { - if (CheckDestructorAccess(ELoc, DD, PD) == AR_inaccessible || - DD->isDeleted()) { - Diag(ELoc, diag::err_omp_required_method) - << getOpenMPClauseName(OMPC_reduction) << 4; - bool IsDecl = VD->isThisDeclarationADefinition(Context) == - VarDecl::DeclarationOnly; - Diag(VD->getLocation(), - IsDecl ? diag::note_previous_decl : diag::note_defined_here) - << VD; - Diag(RD->getLocation(), diag::note_previous_decl) << RD; - continue; + break; + case BO_Mul: + case BO_LAnd: + if (Type->isScalarType() || Type->isAnyComplexType()) { + // '*' and '&&' reduction ops - initializer is '1'. + Init = ActOnIntegerConstant(ELoc, /*Val=*/1).get(); + } + break; + case BO_And: { + // '&' reduction op - initializer is '~0'. + QualType OrigType = Type; + if (auto *ComplexTy = OrigType->getAs()) { + Type = ComplexTy->getElementType(); + } + if (Type->isRealFloatingType()) { + llvm::APFloat InitValue = + llvm::APFloat::getAllOnesValue(Context.getTypeSize(Type), + /*isIEEE=*/true); + Init = FloatingLiteral::Create(Context, InitValue, /*isexact=*/true, + Type, ELoc); + } else if (Type->isScalarType()) { + auto Size = Context.getTypeSize(Type); + QualType IntTy = Context.getIntTypeForBitwidth(Size, /*Signed=*/0); + llvm::APInt InitValue = llvm::APInt::getAllOnesValue(Size); + Init = IntegerLiteral::Create(Context, InitValue, IntTy, ELoc); + } + if (Init && OrigType->isAnyComplexType()) { + // Init = 0xFFFF + 0xFFFFi; + auto *Im = new (Context) ImaginaryLiteral(Init, OrigType); + Init = CreateBuiltinBinOp(ELoc, BO_Add, Init, Im).get(); + } + Type = OrigType; + break; + } + case BO_LT: + case BO_GT: { + // 'min' reduction op - initializer is 'Largest representable number in + // the reduction list item type'. + // 'max' reduction op - initializer is 'Least representable number in + // the reduction list item type'. + if (Type->isIntegerType() || Type->isPointerType()) { + bool IsSigned = Type->hasSignedIntegerRepresentation(); + auto Size = Context.getTypeSize(Type); + QualType IntTy = + Context.getIntTypeForBitwidth(Size, /*Signed=*/IsSigned); + llvm::APInt InitValue = + (BOK != BO_LT) + ? IsSigned ? llvm::APInt::getSignedMinValue(Size) + : llvm::APInt::getMinValue(Size) + : IsSigned ? llvm::APInt::getSignedMaxValue(Size) + : llvm::APInt::getMaxValue(Size); + Init = IntegerLiteral::Create(Context, InitValue, IntTy, ELoc); + if (Type->isPointerType()) { + // Cast to pointer type. + auto CastExpr = BuildCStyleCastExpr( + SourceLocation(), Context.getTrivialTypeSourceInfo(Type, ELoc), + SourceLocation(), Init); + if (CastExpr.isInvalid()) + continue; + Init = CastExpr.get(); } - MarkFunctionReferenced(ELoc, DD); - DiagnoseUseOfDecl(DD, ELoc); + } else if (Type->isRealFloatingType()) { + llvm::APFloat InitValue = llvm::APFloat::getLargest( + Context.getFloatTypeSemantics(Type), BOK != BO_LT); + Init = FloatingLiteral::Create(Context, InitValue, /*isexact=*/true, + Type, ELoc); } + break; + } + case BO_PtrMemD: + case BO_PtrMemI: + case BO_MulAssign: + case BO_Div: + case BO_Rem: + case BO_Sub: + case BO_Shl: + case BO_Shr: + case BO_LE: + case BO_GE: + case BO_EQ: + case BO_NE: + case BO_AndAssign: + case BO_XorAssign: + case BO_OrAssign: + case BO_Assign: + case BO_AddAssign: + case BO_SubAssign: + case BO_DivAssign: + case BO_RemAssign: + case BO_ShlAssign: + case BO_ShrAssign: + case BO_Comma: + llvm_unreachable("Unexpected reduction operation"); + } + if (Init) { + AddInitializerToDecl(RHSVD, Init, /*DirectInit=*/false, + /*TypeMayContainAuto=*/false); + } else { + ActOnUninitializedDecl(RHSVD, /*TypeMayContainAuto=*/false); } + if (!RHSVD->hasInit()) { + Diag(ELoc, diag::err_omp_reduction_id_not_compatible) << Type + << ReductionIdRange; + bool IsDecl = + VD->isThisDeclarationADefinition(Context) == VarDecl::DeclarationOnly; + Diag(VD->getLocation(), + IsDecl ? diag::note_previous_decl : diag::note_defined_here) + << VD; + continue; + } + auto *LHSDRE = BuildDeclRefExpr(LHSVD, Type, VK_LValue, ELoc).get(); + auto *RHSDRE = BuildDeclRefExpr(RHSVD, Type, VK_LValue, ELoc).get(); + ExprResult ReductionOp = + BuildBinOp(DSAStack->getCurScope(), ReductionId.getLocStart(), BOK, + LHSDRE, RHSDRE); + if (ReductionOp.isUsable()) { + if (BOK != BO_LOr && BOK != BO_LAnd) { + ReductionOp = + BuildBinOp(DSAStack->getCurScope(), ReductionId.getLocStart(), + BO_Assign, LHSDRE, ReductionOp.get()); + } else { + auto *ConditionalOp = new (Context) ConditionalOperator( + ReductionOp.get(), SourceLocation(), LHSDRE, SourceLocation(), + RHSDRE, Type, VK_LValue, OK_Ordinary); + ReductionOp = + BuildBinOp(DSAStack->getCurScope(), ReductionId.getLocStart(), + BO_Assign, LHSDRE, ConditionalOp); + } + if (ReductionOp.isUsable()) { + ReductionOp = ActOnFinishFullExpr(ReductionOp.get()); + } + } + if (ReductionOp.isInvalid()) + continue; DSAStack->addDSA(VD, DE, OMPC_reduction); Vars.push_back(DE); + LHSs.push_back(LHSDRE); + RHSs.push_back(RHSDRE); + ReductionOps.push_back(ReductionOp.get()); } if (Vars.empty()) @@ -5496,7 +5630,8 @@ return OMPReductionClause::Create( Context, StartLoc, LParenLoc, ColonLoc, EndLoc, Vars, - ReductionIdScopeSpec.getWithLocInContext(Context), ReductionId); + ReductionIdScopeSpec.getWithLocInContext(Context), ReductionId, LHSs, + RHSs, ReductionOps); } OMPClause *Sema::ActOnOpenMPLinearClause(ArrayRef VarList, Expr *Step, Index: lib/Serialization/ASTReaderStmt.cpp =================================================================== --- lib/Serialization/ASTReaderStmt.cpp +++ lib/Serialization/ASTReaderStmt.cpp @@ -1917,6 +1917,18 @@ for (unsigned i = 0; i != NumVars; ++i) Vars.push_back(Reader->Reader.ReadSubExpr()); C->setVarRefs(Vars); + Vars.clear(); + for (unsigned i = 0; i != NumVars; ++i) + Vars.push_back(Reader->Reader.ReadSubExpr()); + C->setLHSExprs(Vars); + Vars.clear(); + for (unsigned i = 0; i != NumVars; ++i) + Vars.push_back(Reader->Reader.ReadSubExpr()); + C->setRHSExprs(Vars); + Vars.clear(); + for (unsigned i = 0; i != NumVars; ++i) + Vars.push_back(Reader->Reader.ReadSubExpr()); + C->setReductionOps(Vars); } void OMPClauseReader::VisitOMPLinearClause(OMPLinearClause *C) { Index: lib/Serialization/ASTWriterStmt.cpp =================================================================== --- lib/Serialization/ASTWriterStmt.cpp +++ lib/Serialization/ASTWriterStmt.cpp @@ -1815,6 +1815,12 @@ Writer->Writer.AddDeclarationNameInfo(C->getNameInfo(), Record); for (auto *VE : C->varlists()) Writer->Writer.AddStmt(VE); + for (auto *E : C->lhs_exprs()) + Writer->Writer.AddStmt(E); + for (auto *E : C->rhs_exprs()) + Writer->Writer.AddStmt(E); + for (auto *E : C->reduction_ops()) + Writer->Writer.AddStmt(E); } void OMPClauseWriter::VisitOMPLinearClause(OMPLinearClause *C) { Index: test/OpenMP/for_reduction_messages.cpp =================================================================== --- test/OpenMP/for_reduction_messages.cpp +++ test/OpenMP/for_reduction_messages.cpp @@ -1,4 +1,4 @@ -// RUN: %clang_cc1 -verify -fopenmp=libiomp5 -ferror-limit 100 -o - %s +// RUN: %clang_cc1 -verify -fopenmp=libiomp5 -ferror-limit 150 -o - %s void foo() { } @@ -11,7 +11,7 @@ extern S1 a; class S2 { mutable int a; - S2 &operator+=(const S2 &arg) { return (*this); } + S2 &operator+(const S2 &arg) { return (*this); } // expected-note 4 {{implicitly declared private here}} public: S2() : a(0) {} @@ -28,17 +28,17 @@ public: S3() : a(0) {} S3(const S3 &s3) : a(s3.a) {} - S3 operator+=(const S3 &arg1) { return arg1; } + S3 operator+(const S3 &arg1) { return arg1; } }; -int operator+=(const S3 &arg1, const S3 &arg2) { return 5; } +int operator+(const S3 &arg1, const S3 &arg2) { return 5; } S3 c; // expected-note 2 {{'c' defined here}} const S3 ca[5]; // expected-note 2 {{'ca' defined here}} extern const int f; // expected-note 4 {{'f' declared here}} -class S4 { // expected-note {{'S4' declared here}} +class S4 { int a; - S4(); + S4(); // expected-note {{implicitly declared private here}} S4(const S4 &s4); - S4 &operator+=(const S4 &arg) { return (*this); } + S4 &operator+(const S4 &arg) { return (*this); } public: S4(int v) : a(v) {} @@ -46,26 +46,26 @@ S4 &operator&=(S4 &arg1, S4 &arg2) { return arg1; } class S5 { int a; - S5() : a(0) {} + S5() : a(0) {} // expected-note {{implicitly declared private here}} S5(const S5 &s5) : a(s5.a) {} - S5 &operator+=(const S5 &arg); + S5 &operator+(const S5 &arg); public: S5(int v) : a(v) {} }; -class S6 { +class S6 { // expected-note 2 {{candidate function (the implicit copy assignment operator) not viable: no known conversion from 'int' to 'const S6' for 1st argument}} int a; public: S6() : a(6) {} operator int() { return 6; } -} o; // expected-note 2 {{'o' defined here}} +} o; S3 h, k; #pragma omp threadprivate(h) // expected-note 2 {{defined as threadprivate or thread local}} template // expected-note {{declared here}} -T tmain(T argc) { // expected-note 2 {{'argc' defined here}} +T tmain(T argc) { const T d = T(); // expected-note 4 {{'d' defined here}} const T da[5] = {T()}; // expected-note 2 {{'da' defined here}} T qa[5] = {T()}; @@ -74,7 +74,7 @@ S3 &p = k; // expected-note 2 {{'p' defined here}} const T &r = da[(int)i]; // expected-note 2 {{'r' defined here}} T &q = qa[(int)i]; // expected-note 2 {{'q' defined here}} - T fl; // expected-note {{'fl' defined here}} + T fl; #pragma omp parallel #pragma omp for reduction // expected-error {{expected '(' after 'reduction'}} for (int i = 0; i < 10; ++i) @@ -104,11 +104,11 @@ for (int i = 0; i < 10; ++i) foo(); #pragma omp parallel -#pragma omp for reduction(& : argc // expected-error {{expected ')'}} expected-note {{to match this '('}} expected-error {{variable of type 'float' is not valid for specified reduction operation}} +#pragma omp for reduction(& : argc // expected-error {{expected ')'}} expected-note {{to match this '('}} expected-error {{invalid operands to binary expression ('float' and 'float')}} for (int i = 0; i < 10; ++i) foo(); #pragma omp parallel -#pragma omp for reduction(| : argc, // expected-error {{expected expression}} expected-error {{expected ')'}} expected-note {{to match this '('}} expected-error {{variable of type 'float' is not valid for specified reduction operation}} +#pragma omp for reduction(| : argc, // expected-error {{expected expression}} expected-error {{expected ')'}} expected-note {{to match this '('}} expected-error {{invalid operands to binary expression ('float' and 'float')}} for (int i = 0; i < 10; ++i) foo(); #pragma omp parallel @@ -128,7 +128,7 @@ for (int i = 0; i < 10; ++i) foo(); #pragma omp parallel -#pragma omp for reduction(+ : a, b, c, d, f) // expected-error {{reduction variable with incomplete type 'S1'}} expected-error 3 {{const-qualified variable cannot be reduction}} +#pragma omp for reduction(+ : a, b, c, d, f) // expected-error {{reduction variable with incomplete type 'S1'}} expected-error 3 {{const-qualified variable cannot be reduction}} expected-error 3 {{'operator+' is a private member of 'S2'}} for (int i = 0; i < 10; ++i) foo(); #pragma omp parallel @@ -152,7 +152,7 @@ for (int i = 0; i < 10; ++i) foo(); #pragma omp parallel -#pragma omp for reduction(^ : fl) // expected-error {{variable of type 'float' is not valid for specified reduction operation}} +#pragma omp for reduction(^ : fl) // expected-error {{invalid operands to binary expression ('float' and 'float')}} for (int i = 0; i < 10; ++i) foo(); #pragma omp parallel @@ -168,7 +168,7 @@ for (int i = 0; i < 10; ++i) foo(); #pragma omp parallel -#pragma omp for reduction(+ : o) // expected-error {{variable of type 'class S6' is not valid for specified reduction operation}} +#pragma omp for reduction(+ : o) // expected-error {{no viable overloaded '='}} for (int i = 0; i < 10; ++i) foo(); #pragma omp parallel @@ -208,14 +208,14 @@ const int d = 5; // expected-note 2 {{'d' defined here}} const int da[5] = {0}; // expected-note {{'da' defined here}} int qa[5] = {0}; - S4 e(4); // expected-note {{'e' defined here}} - S5 g(5); // expected-note {{'g' defined here}} + S4 e(4); + S5 g(5); int i; int &j = i; // expected-note 2 {{'j' defined here}} S3 &p = k; // expected-note 2 {{'p' defined here}} const int &r = da[i]; // expected-note {{'r' defined here}} int &q = qa[i]; // expected-note {{'q' defined here}} - float fl; // expected-note {{'fl' defined here}} + float fl; #pragma omp parallel #pragma omp for reduction // expected-error {{expected '(' after 'reduction'}} for (int i = 0; i < 10; ++i) @@ -269,7 +269,7 @@ for (int i = 0; i < 10; ++i) foo(); #pragma omp parallel -#pragma omp for reduction(+ : a, b, c, d, f) // expected-error {{reduction variable with incomplete type 'S1'}} expected-error 2 {{const-qualified variable cannot be reduction}} +#pragma omp for reduction(+ : a, b, c, d, f) // expected-error {{reduction variable with incomplete type 'S1'}} expected-error 2 {{const-qualified variable cannot be reduction}} expected-error {{'operator+' is a private member of 'S2'}} for (int i = 0; i < 10; ++i) foo(); #pragma omp parallel @@ -293,7 +293,7 @@ for (int i = 0; i < 10; ++i) foo(); #pragma omp parallel -#pragma omp for reduction(^ : fl) // expected-error {{variable of type 'float' is not valid for specified reduction operation}} +#pragma omp for reduction(^ : fl) // expected-error {{invalid operands to binary expression ('float' and 'float')}} for (int i = 0; i < 10; ++i) foo(); #pragma omp parallel @@ -305,7 +305,7 @@ for (int i = 0; i < 10; ++i) foo(); #pragma omp parallel -#pragma omp for reduction(& : e, g) // expected-error {{reduction variable must have an accessible, unambiguous default constructor}} expected-error {{variable of type 'S5' is not valid for specified reduction operation}} +#pragma omp for reduction(& : e, g) // expected-error {{calling a private constructor of class 'S4'}} expected-error {{calling a private constructor of class 'S5'}} expected-error {{invalid operands to binary expression ('S4' and 'S4')}} expected-error {{invalid operands to binary expression ('S5' and 'S5')}} for (int i = 0; i < 10; ++i) foo(); #pragma omp parallel @@ -313,7 +313,7 @@ for (int i = 0; i < 10; ++i) foo(); #pragma omp parallel -#pragma omp for reduction(+ : o) // expected-error {{variable of type 'class S6' is not valid for specified reduction operation}} +#pragma omp for reduction(+ : o) // expected-error {{no viable overloaded '='}} for (int i = 0; i < 10; ++i) foo(); #pragma omp parallel Index: test/OpenMP/for_simd_reduction_messages.cpp =================================================================== --- test/OpenMP/for_simd_reduction_messages.cpp +++ test/OpenMP/for_simd_reduction_messages.cpp @@ -11,7 +11,7 @@ extern S1 a; class S2 { mutable int a; - S2 &operator+=(const S2 &arg) { return (*this); } + S2 &operator+(const S2 &arg) { return (*this); } // expected-note 4 {{implicitly declared private here}} public: S2() : a(0) {} @@ -28,17 +28,17 @@ public: S3() : a(0) {} S3(const S3 &s3) : a(s3.a) {} - S3 operator+=(const S3 &arg1) { return arg1; } + S3 operator+(const S3 &arg1) { return arg1; } }; -int operator+=(const S3 &arg1, const S3 &arg2) { return 5; } +int operator+(const S3 &arg1, const S3 &arg2) { return 5; } S3 c; // expected-note 2 {{'c' defined here}} const S3 ca[5]; // expected-note 2 {{'ca' defined here}} extern const int f; // expected-note 4 {{'f' declared here}} -class S4 { // expected-note {{'S4' declared here}} +class S4 { int a; - S4(); + S4(); // expected-note {{implicitly declared private here}} S4(const S4 &s4); - S4 &operator+=(const S4 &arg) { return (*this); } + S4 &operator+(const S4 &arg) { return (*this); } public: S4(int v) : a(v) {} @@ -46,26 +46,26 @@ S4 &operator&=(S4 &arg1, S4 &arg2) { return arg1; } class S5 { int a; - S5() : a(0) {} + S5() : a(0) {} // expected-note {{implicitly declared private here}} S5(const S5 &s5) : a(s5.a) {} - S5 &operator+=(const S5 &arg); + S5 &operator+(const S5 &arg); public: S5(int v) : a(v) {} }; -class S6 { +class S6 { // expected-note 2 {{candidate function (the implicit copy assignment operator) not viable: no known conversion from 'int' to 'const S6' for 1st argument}} int a; public: S6() : a(6) {} operator int() { return 6; } -} o; // expected-note 2 {{'o' defined here}} +} o; S3 h, k; #pragma omp threadprivate(h) // expected-note 2 {{defined as threadprivate or thread local}} template // expected-note {{declared here}} -T tmain(T argc) { // expected-note 2 {{'argc' defined here}} +T tmain(T argc) { const T d = T(); // expected-note 4 {{'d' defined here}} const T da[5] = {T()}; // expected-note 2 {{'da' defined here}} T qa[5] = {T()}; @@ -74,7 +74,7 @@ S3 &p = k; // expected-note 2 {{'p' defined here}} const T &r = da[(int)i]; // expected-note 2 {{'r' defined here}} T &q = qa[(int)i]; // expected-note 2 {{'q' defined here}} - T fl; // expected-note {{'fl' defined here}} + T fl; #pragma omp parallel #pragma omp for simd reduction // expected-error {{expected '(' after 'reduction'}} for (int i = 0; i < 10; ++i) @@ -104,11 +104,11 @@ for (int i = 0; i < 10; ++i) foo(); #pragma omp parallel -#pragma omp for simd reduction(& : argc // expected-error {{expected ')'}} expected-note {{to match this '('}} expected-error {{variable of type 'float' is not valid for specified reduction operation}} +#pragma omp for simd reduction(& : argc // expected-error {{expected ')'}} expected-note {{to match this '('}} expected-error {{invalid operands to binary expression ('float' and 'float')}} for (int i = 0; i < 10; ++i) foo(); #pragma omp parallel -#pragma omp for simd reduction(| : argc, // expected-error {{expected expression}} expected-error {{expected ')'}} expected-note {{to match this '('}} expected-error {{variable of type 'float' is not valid for specified reduction operation}} +#pragma omp for simd reduction(| : argc, // expected-error {{expected expression}} expected-error {{expected ')'}} expected-note {{to match this '('}} expected-error {{invalid operands to binary expression ('float' and 'float')}} for (int i = 0; i < 10; ++i) foo(); #pragma omp parallel @@ -128,7 +128,7 @@ for (int i = 0; i < 10; ++i) foo(); #pragma omp parallel -#pragma omp for simd reduction(+ : a, b, c, d, f) // expected-error {{reduction variable with incomplete type 'S1'}} expected-error 3 {{const-qualified variable cannot be reduction}} +#pragma omp for simd reduction(+ : a, b, c, d, f) // expected-error {{reduction variable with incomplete type 'S1'}} expected-error 3 {{const-qualified variable cannot be reduction}} expected-error 3 {{'operator+' is a private member of 'S2'}} for (int i = 0; i < 10; ++i) foo(); #pragma omp parallel @@ -152,7 +152,7 @@ for (int i = 0; i < 10; ++i) foo(); #pragma omp parallel -#pragma omp for simd reduction(^ : fl) // expected-error {{variable of type 'float' is not valid for specified reduction operation}} +#pragma omp for simd reduction(^ : fl) // expected-error {{invalid operands to binary expression ('float' and 'float')}} for (int i = 0; i < 10; ++i) foo(); #pragma omp parallel @@ -168,7 +168,7 @@ for (int i = 0; i < 10; ++i) foo(); #pragma omp parallel -#pragma omp for simd reduction(+ : o) // expected-error {{variable of type 'class S6' is not valid for specified reduction operation}} +#pragma omp for simd reduction(+ : o) // expected-error {{no viable overloaded '='}} for (int i = 0; i < 10; ++i) foo(); #pragma omp parallel @@ -208,14 +208,14 @@ const int d = 5; // expected-note 2 {{'d' defined here}} const int da[5] = {0}; // expected-note {{'da' defined here}} int qa[5] = {0}; - S4 e(4); // expected-note {{'e' defined here}} - S5 g(5); // expected-note {{'g' defined here}} + S4 e(4); + S5 g(5); int i; int &j = i; // expected-note 2 {{'j' defined here}} S3 &p = k; // expected-note 2 {{'p' defined here}} const int &r = da[i]; // expected-note {{'r' defined here}} int &q = qa[i]; // expected-note {{'q' defined here}} - float fl; // expected-note {{'fl' defined here}} + float fl; #pragma omp parallel #pragma omp for simd reduction // expected-error {{expected '(' after 'reduction'}} for (int i = 0; i < 10; ++i) @@ -269,7 +269,7 @@ for (int i = 0; i < 10; ++i) foo(); #pragma omp parallel -#pragma omp for simd reduction(+ : a, b, c, d, f) // expected-error {{reduction variable with incomplete type 'S1'}} expected-error 2 {{const-qualified variable cannot be reduction}} +#pragma omp for simd reduction(+ : a, b, c, d, f) // expected-error {{reduction variable with incomplete type 'S1'}} expected-error 2 {{const-qualified variable cannot be reduction}} expected-error {{'operator+' is a private member of 'S2'}} for (int i = 0; i < 10; ++i) foo(); #pragma omp parallel @@ -293,7 +293,7 @@ for (int i = 0; i < 10; ++i) foo(); #pragma omp parallel -#pragma omp for simd reduction(^ : fl) // expected-error {{variable of type 'float' is not valid for specified reduction operation}} +#pragma omp for simd reduction(^ : fl) // expected-error {{invalid operands to binary expression ('float' and 'float')}} for (int i = 0; i < 10; ++i) foo(); #pragma omp parallel @@ -305,7 +305,7 @@ for (int i = 0; i < 10; ++i) foo(); #pragma omp parallel -#pragma omp for simd reduction(& : e, g) // expected-error {{reduction variable must have an accessible, unambiguous default constructor}} expected-error {{variable of type 'S5' is not valid for specified reduction operation}} +#pragma omp for simd reduction(& : e, g) // expected-error {{calling a private constructor of class 'S4'}} expected-error {{invalid operands to binary expression ('S4' and 'S4')}} expected-error {{calling a private constructor of class 'S5'}} expected-error {{invalid operands to binary expression ('S5' and 'S5')}} for (int i = 0; i < 10; ++i) foo(); #pragma omp parallel @@ -313,7 +313,7 @@ for (int i = 0; i < 10; ++i) foo(); #pragma omp parallel -#pragma omp for simd reduction(+ : o) // expected-error {{variable of type 'class S6' is not valid for specified reduction operation}} +#pragma omp for simd reduction(+ : o) // expected-error {{no viable overloaded '='}} for (int i = 0; i < 10; ++i) foo(); #pragma omp parallel Index: test/OpenMP/parallel_codegen.cpp =================================================================== --- test/OpenMP/parallel_codegen.cpp +++ test/OpenMP/parallel_codegen.cpp @@ -70,6 +70,7 @@ // CHECK-NEXT: [[ARGC_REF:%.+]] = load i32*, i32** [[ARGC_PTR_REF]] // CHECK-NEXT: [[ARGC:%.+]] = load i32, i32* [[ARGC_REF]] // CHECK-NEXT: invoke void [[FOO:@.+foo.+]](i32{{[ ]?[a-z]*}} [[ARGC]]) +// CHECK: call i32 @__kmpc_cancel_barrier( // CHECK: ret void // CHECK: call void @{{.+terminate.*|abort}}( // CHECK-NEXT: unreachable @@ -83,6 +84,7 @@ // CHECK-DEBUG-NEXT: [[ARGC_REF:%.+]] = load i32*, i32** [[ARGC_PTR_REF]] // CHECK-DEBUG-NEXT: [[ARGC:%.+]] = load i32, i32* [[ARGC_REF]] // CHECK-DEBUG-NEXT: invoke void [[FOO:@.+foo.+]](i32 [[ARGC]]) +// CHECK-DEBUG: call i32 @__kmpc_cancel_barrier( // CHECK-DEBUG: ret void // CHECK-DEBUG: call void @{{.+terminate.*|abort}}( // CHECK-DEBUG-NEXT: unreachable @@ -124,6 +126,7 @@ // CHECK-NEXT: [[ARGC_REF:%.+]] = load i8***, i8**** [[ARGC_PTR_REF]] // CHECK-NEXT: [[ARGC:%.+]] = load i8**, i8*** [[ARGC_REF]] // CHECK-NEXT: invoke void [[FOO1:@.+foo.+]](i8** [[ARGC]]) +// CHECK: call i32 @__kmpc_cancel_barrier( // CHECK: ret void // CHECK: call void @{{.+terminate.*|abort}}( // CHECK-NEXT: unreachable @@ -136,6 +139,7 @@ // CHECK-DEBUG-NEXT: [[ARGC_REF:%.+]] = load i8***, i8**** [[ARGC_PTR_REF]] // CHECK-DEBUG-NEXT: [[ARGC:%.+]] = load i8**, i8*** [[ARGC_REF]] // CHECK-DEBUG-NEXT: invoke void [[FOO1:@.+foo.+]](i8** [[ARGC]]) +// CHECK-DEBUG: call i32 @__kmpc_cancel_barrier( // CHECK-DEBUG: ret void // CHECK-DEBUG: call void @{{.+terminate.*|abort}}( // CHECK-DEBUG-NEXT: unreachable Index: test/OpenMP/parallel_for_reduction_messages.cpp =================================================================== --- test/OpenMP/parallel_for_reduction_messages.cpp +++ test/OpenMP/parallel_for_reduction_messages.cpp @@ -11,7 +11,7 @@ extern S1 a; class S2 { mutable int a; - S2 &operator+=(const S2 &arg) { return (*this); } + S2 &operator+(const S2 &arg) { return (*this); } // expected-note 4 {{implicitly declared private here}} public: S2() : a(0) {} @@ -28,17 +28,17 @@ public: S3() : a(0) {} S3(const S3 &s3) : a(s3.a) {} - S3 operator+=(const S3 &arg1) { return arg1; } + S3 operator+(const S3 &arg1) { return arg1; } }; -int operator+=(const S3 &arg1, const S3 &arg2) { return 5; } +int operator+(const S3 &arg1, const S3 &arg2) { return 5; } S3 c; // expected-note 2 {{'c' defined here}} const S3 ca[5]; // expected-note 2 {{'ca' defined here}} extern const int f; // expected-note 4 {{'f' declared here}} -class S4 { // expected-note {{'S4' declared here}} +class S4 { int a; - S4(); + S4(); // expected-note {{implicitly declared private here}} S4(const S4 &s4); - S4 &operator+=(const S4 &arg) { return (*this); } + S4 &operator+(const S4 &arg) { return (*this); } public: S4(int v) : a(v) {} @@ -46,26 +46,26 @@ S4 &operator&=(S4 &arg1, S4 &arg2) { return arg1; } class S5 { int a; - S5() : a(0) {} + S5() : a(0) {} // expected-note {{implicitly declared private here}} S5(const S5 &s5) : a(s5.a) {} - S5 &operator+=(const S5 &arg); + S5 &operator+(const S5 &arg); public: S5(int v) : a(v) {} }; -class S6 { +class S6 { // expected-note 2 {{candidate function (the implicit copy assignment operator) not viable: no known conversion from 'int' to 'const S6' for 1st argument}} int a; public: S6() : a(6) {} operator int() { return 6; } -} o; // expected-note 2 {{'o' defined here}} +} o; S3 h, k; #pragma omp threadprivate(h) // expected-note 2 {{defined as threadprivate or thread local}} template // expected-note {{declared here}} -T tmain(T argc) { // expected-note 2 {{'argc' defined here}} +T tmain(T argc) { const T d = T(); // expected-note 4 {{'d' defined here}} const T da[5] = {T()}; // expected-note 2 {{'da' defined here}} T qa[5] = {T()}; @@ -74,7 +74,7 @@ S3 &p = k; // expected-note 2 {{'p' defined here}} const T &r = da[(int)i]; // expected-note 2 {{'r' defined here}} T &q = qa[(int)i]; // expected-note 2 {{'q' defined here}} - T fl; // expected-note {{'fl' defined here}} + T fl; #pragma omp parallel for reduction // expected-error {{expected '(' after 'reduction'}} for (int i = 0; i < 10; ++i) foo(); @@ -96,10 +96,10 @@ #pragma omp parallel for reduction(\) // expected-error {{expected unqualified-id}} expected-warning {{missing ':' after reduction identifier - ignoring}} for (int i = 0; i < 10; ++i) foo(); -#pragma omp parallel for reduction(& : argc // expected-error {{expected ')'}} expected-note {{to match this '('}} expected-error {{variable of type 'float' is not valid for specified reduction operation}} +#pragma omp parallel for reduction(& : argc // expected-error {{expected ')'}} expected-note {{to match this '('}} expected-error {{invalid operands to binary expression ('float' and 'float')}} for (int i = 0; i < 10; ++i) foo(); -#pragma omp parallel for reduction(| : argc, // expected-error {{expected expression}} expected-error {{expected ')'}} expected-note {{to match this '('}} expected-error {{variable of type 'float' is not valid for specified reduction operation}} +#pragma omp parallel for reduction(| : argc, // expected-error {{expected expression}} expected-error {{expected ')'}} expected-note {{to match this '('}} expected-error {{invalid operands to binary expression ('float' and 'float')}} for (int i = 0; i < 10; ++i) foo(); #pragma omp parallel for reduction(|| : argc ? i : argc) // expected-error 2 {{expected variable name}} @@ -114,7 +114,7 @@ #pragma omp parallel for reduction(^ : T) // expected-error {{'T' does not refer to a value}} for (int i = 0; i < 10; ++i) foo(); -#pragma omp parallel for reduction(+ : a, b, c, d, f) // expected-error {{reduction variable with incomplete type 'S1'}} expected-error 3 {{const-qualified variable cannot be reduction}} +#pragma omp parallel for reduction(+ : a, b, c, d, f) // expected-error {{reduction variable with incomplete type 'S1'}} expected-error 3 {{const-qualified variable cannot be reduction}} expected-error 3 {{'operator+' is a private member of 'S2'}} for (int i = 0; i < 10; ++i) foo(); #pragma omp parallel for reduction(min : a, b, c, d, f) // expected-error {{reduction variable with incomplete type 'S1'}} expected-error 2 {{arguments of OpenMP clause 'reduction' for 'min' or 'max' must be of arithmetic type}} expected-error 3 {{const-qualified variable cannot be reduction}} @@ -132,7 +132,7 @@ #pragma omp parallel for reduction(- : da) // expected-error {{a reduction variable with array type 'const int [5]'}} expected-error {{a reduction variable with array type 'const float [5]'}} for (int i = 0; i < 10; ++i) foo(); -#pragma omp parallel for reduction(^ : fl) // expected-error {{variable of type 'float' is not valid for specified reduction operation}} +#pragma omp parallel for reduction(^ : fl) // expected-error {{invalid operands to binary expression ('float' and 'float')}} for (int i = 0; i < 10; ++i) foo(); #pragma omp parallel for reduction(&& : S2::S2s) @@ -144,7 +144,7 @@ #pragma omp parallel for reduction(+ : h, k) // expected-error {{threadprivate or thread local variable cannot be reduction}} for (int i = 0; i < 10; ++i) foo(); -#pragma omp parallel for reduction(+ : o) // expected-error {{variable of type 'class S6' is not valid for specified reduction operation}} +#pragma omp parallel for reduction(+ : o) // expected-error {{no viable overloaded '='}} for (int i = 0; i < 10; ++i) foo(); #pragma omp parallel for private(i), reduction(+ : j), reduction(+ : q) // expected-error 4 {{argument of OpenMP clause 'reduction' must reference the same object in all threads}} @@ -181,14 +181,14 @@ const int d = 5; // expected-note 2 {{'d' defined here}} const int da[5] = {0}; // expected-note {{'da' defined here}} int qa[5] = {0}; - S4 e(4); // expected-note {{'e' defined here}} - S5 g(5); // expected-note {{'g' defined here}} + S4 e(4); + S5 g(5); int i; int &j = i; // expected-note 2 {{'j' defined here}} S3 &p = k; // expected-note 2 {{'p' defined here}} const int &r = da[i]; // expected-note {{'r' defined here}} int &q = qa[i]; // expected-note {{'q' defined here}} - float fl; // expected-note {{'fl' defined here}} + float fl; #pragma omp parallel for reduction // expected-error {{expected '(' after 'reduction'}} for (int i = 0; i < 10; ++i) foo(); @@ -228,7 +228,7 @@ #pragma omp parallel for reduction(^ : S1) // expected-error {{'S1' does not refer to a value}} for (int i = 0; i < 10; ++i) foo(); -#pragma omp parallel for reduction(+ : a, b, c, d, f) // expected-error {{reduction variable with incomplete type 'S1'}} expected-error 2 {{const-qualified variable cannot be reduction}} +#pragma omp parallel for reduction(+ : a, b, c, d, f) // expected-error {{reduction variable with incomplete type 'S1'}} expected-error 2 {{const-qualified variable cannot be reduction}} expected-error {{'operator+' is a private member of 'S2'}} for (int i = 0; i < 10; ++i) foo(); #pragma omp parallel for reduction(min : a, b, c, d, f) // expected-error {{reduction variable with incomplete type 'S1'}} expected-error 2 {{arguments of OpenMP clause 'reduction' for 'min' or 'max' must be of arithmetic type}} expected-error 2 {{const-qualified variable cannot be reduction}} @@ -246,7 +246,7 @@ #pragma omp parallel for reduction(- : da) // expected-error {{a reduction variable with array type 'const int [5]'}} for (int i = 0; i < 10; ++i) foo(); -#pragma omp parallel for reduction(^ : fl) // expected-error {{variable of type 'float' is not valid for specified reduction operation}} +#pragma omp parallel for reduction(^ : fl) // expected-error {{invalid operands to binary expression ('float' and 'float')}} for (int i = 0; i < 10; ++i) foo(); #pragma omp parallel for reduction(&& : S2::S2s) @@ -255,13 +255,13 @@ #pragma omp parallel for reduction(&& : S2::S2sc) // expected-error {{const-qualified variable cannot be reduction}} for (int i = 0; i < 10; ++i) foo(); -#pragma omp parallel for reduction(& : e, g) // expected-error {{reduction variable must have an accessible, unambiguous default constructor}} expected-error {{variable of type 'S5' is not valid for specified reduction operation}} +#pragma omp parallel for reduction(& : e, g) // expected-error {{calling a private constructor of class 'S4'}} expected-error {{invalid operands to binary expression ('S4' and 'S4')}} expected-error {{calling a private constructor of class 'S5'}} expected-error {{invalid operands to binary expression ('S5' and 'S5')}} for (int i = 0; i < 10; ++i) foo(); #pragma omp parallel for reduction(+ : h, k) // expected-error {{threadprivate or thread local variable cannot be reduction}} for (int i = 0; i < 10; ++i) foo(); -#pragma omp parallel for reduction(+ : o) // expected-error {{variable of type 'class S6' is not valid for specified reduction operation}} +#pragma omp parallel for reduction(+ : o) // expected-error {{no viable overloaded '='}} for (int i = 0; i < 10; ++i) foo(); #pragma omp parallel for private(i), reduction(+ : j), reduction(+ : q) // expected-error 2 {{argument of OpenMP clause 'reduction' must reference the same object in all threads}} Index: test/OpenMP/parallel_for_simd_reduction_messages.cpp =================================================================== --- test/OpenMP/parallel_for_simd_reduction_messages.cpp +++ test/OpenMP/parallel_for_simd_reduction_messages.cpp @@ -11,7 +11,7 @@ extern S1 a; class S2 { mutable int a; - S2 &operator+=(const S2 &arg) { return (*this); } + S2 &operator+(const S2 &arg) { return (*this); } // expected-note 4 {{implicitly declared private here}} public: S2() : a(0) {} @@ -28,17 +28,17 @@ public: S3() : a(0) {} S3(const S3 &s3) : a(s3.a) {} - S3 operator+=(const S3 &arg1) { return arg1; } + S3 operator+(const S3 &arg1) { return arg1; } }; -int operator+=(const S3 &arg1, const S3 &arg2) { return 5; } +int operator+(const S3 &arg1, const S3 &arg2) { return 5; } S3 c; // expected-note 2 {{'c' defined here}} const S3 ca[5]; // expected-note 2 {{'ca' defined here}} extern const int f; // expected-note 4 {{'f' declared here}} -class S4 { // expected-note {{'S4' declared here}} +class S4 { int a; - S4(); + S4(); // expected-note {{implicitly declared private here}} S4(const S4 &s4); - S4 &operator+=(const S4 &arg) { return (*this); } + S4 &operator+(const S4 &arg) { return (*this); } public: S4(int v) : a(v) {} @@ -46,26 +46,26 @@ S4 &operator&=(S4 &arg1, S4 &arg2) { return arg1; } class S5 { int a; - S5() : a(0) {} + S5() : a(0) {} // expected-note {{implicitly declared private here}} S5(const S5 &s5) : a(s5.a) {} - S5 &operator+=(const S5 &arg); + S5 &operator+(const S5 &arg); public: S5(int v) : a(v) {} }; -class S6 { +class S6 { // expected-note 2 {{candidate function (the implicit copy assignment operator) not viable: no known conversion from 'int' to 'const S6' for 1st argument}} int a; public: S6() : a(6) {} operator int() { return 6; } -} o; // expected-note 2 {{'o' defined here}} +} o; S3 h, k; #pragma omp threadprivate(h) // expected-note 2 {{defined as threadprivate or thread local}} template // expected-note {{declared here}} -T tmain(T argc) { // expected-note 2 {{'argc' defined here}} +T tmain(T argc) { const T d = T(); // expected-note 4 {{'d' defined here}} const T da[5] = {T()}; // expected-note 2 {{'da' defined here}} T qa[5] = {T()}; @@ -74,7 +74,7 @@ S3 &p = k; // expected-note 2 {{'p' defined here}} const T &r = da[(int)i]; // expected-note 2 {{'r' defined here}} T &q = qa[(int)i]; // expected-note 2 {{'q' defined here}} - T fl; // expected-note {{'fl' defined here}} + T fl; #pragma omp parallel for simd reduction // expected-error {{expected '(' after 'reduction'}} for (int i = 0; i < 10; ++i) foo(); @@ -96,10 +96,10 @@ #pragma omp parallel for simd reduction(\) // expected-error {{expected unqualified-id}} expected-warning {{missing ':' after reduction identifier - ignoring}} for (int i = 0; i < 10; ++i) foo(); -#pragma omp parallel for simd reduction(& : argc // expected-error {{expected ')'}} expected-note {{to match this '('}} expected-error {{variable of type 'float' is not valid for specified reduction operation}} +#pragma omp parallel for simd reduction(& : argc // expected-error {{expected ')'}} expected-note {{to match this '('}} expected-error {{invalid operands to binary expression ('float' and 'float')}} for (int i = 0; i < 10; ++i) foo(); -#pragma omp parallel for simd reduction(| : argc, // expected-error {{expected expression}} expected-error {{expected ')'}} expected-note {{to match this '('}} expected-error {{variable of type 'float' is not valid for specified reduction operation}} +#pragma omp parallel for simd reduction(| : argc, // expected-error {{expected expression}} expected-error {{expected ')'}} expected-note {{to match this '('}} expected-error {{invalid operands to binary expression ('float' and 'float')}} for (int i = 0; i < 10; ++i) foo(); #pragma omp parallel for simd reduction(|| : argc ? i : argc) // expected-error 2 {{expected variable name}} @@ -114,7 +114,7 @@ #pragma omp parallel for simd reduction(^ : T) // expected-error {{'T' does not refer to a value}} for (int i = 0; i < 10; ++i) foo(); -#pragma omp parallel for simd reduction(+ : a, b, c, d, f) // expected-error {{reduction variable with incomplete type 'S1'}} expected-error 3 {{const-qualified variable cannot be reduction}} +#pragma omp parallel for simd reduction(+ : a, b, c, d, f) // expected-error {{reduction variable with incomplete type 'S1'}} expected-error 3 {{const-qualified variable cannot be reduction}} expected-error 3 {{'operator+' is a private member of 'S2'}} for (int i = 0; i < 10; ++i) foo(); #pragma omp parallel for simd reduction(min : a, b, c, d, f) // expected-error {{reduction variable with incomplete type 'S1'}} expected-error 2 {{arguments of OpenMP clause 'reduction' for 'min' or 'max' must be of arithmetic type}} expected-error 3 {{const-qualified variable cannot be reduction}} @@ -132,7 +132,7 @@ #pragma omp parallel for simd reduction(- : da) // expected-error {{a reduction variable with array type 'const int [5]'}} expected-error {{a reduction variable with array type 'const float [5]'}} for (int i = 0; i < 10; ++i) foo(); -#pragma omp parallel for simd reduction(^ : fl) // expected-error {{variable of type 'float' is not valid for specified reduction operation}} +#pragma omp parallel for simd reduction(^ : fl) // expected-error {{invalid operands to binary expression ('float' and 'float')}} for (int i = 0; i < 10; ++i) foo(); #pragma omp parallel for simd reduction(&& : S2::S2s) @@ -144,7 +144,7 @@ #pragma omp parallel for simd reduction(+ : h, k) // expected-error {{threadprivate or thread local variable cannot be reduction}} for (int i = 0; i < 10; ++i) foo(); -#pragma omp parallel for simd reduction(+ : o) // expected-error {{variable of type 'class S6' is not valid for specified reduction operation}} +#pragma omp parallel for simd reduction(+ : o) // expected-error {{no viable overloaded '='}} for (int i = 0; i < 10; ++i) foo(); #pragma omp parallel for simd private(i), reduction(+ : j), reduction(+ : q) // expected-error 4 {{argument of OpenMP clause 'reduction' must reference the same object in all threads}} @@ -181,14 +181,14 @@ const int d = 5; // expected-note 2 {{'d' defined here}} const int da[5] = {0}; // expected-note {{'da' defined here}} int qa[5] = {0}; - S4 e(4); // expected-note {{'e' defined here}} - S5 g(5); // expected-note {{'g' defined here}} + S4 e(4); + S5 g(5); int i; int &j = i; // expected-note 2 {{'j' defined here}} S3 &p = k; // expected-note 2 {{'p' defined here}} const int &r = da[i]; // expected-note {{'r' defined here}} int &q = qa[i]; // expected-note {{'q' defined here}} - float fl; // expected-note {{'fl' defined here}} + float fl; #pragma omp parallel for simd reduction // expected-error {{expected '(' after 'reduction'}} for (int i = 0; i < 10; ++i) foo(); @@ -228,7 +228,7 @@ #pragma omp parallel for simd reduction(^ : S1) // expected-error {{'S1' does not refer to a value}} for (int i = 0; i < 10; ++i) foo(); -#pragma omp parallel for simd reduction(+ : a, b, c, d, f) // expected-error {{reduction variable with incomplete type 'S1'}} expected-error 2 {{const-qualified variable cannot be reduction}} +#pragma omp parallel for simd reduction(+ : a, b, c, d, f) // expected-error {{reduction variable with incomplete type 'S1'}} expected-error 2 {{const-qualified variable cannot be reduction}} expected-error {{'operator+' is a private member of 'S2'}} for (int i = 0; i < 10; ++i) foo(); #pragma omp parallel for simd reduction(min : a, b, c, d, f) // expected-error {{reduction variable with incomplete type 'S1'}} expected-error 2 {{arguments of OpenMP clause 'reduction' for 'min' or 'max' must be of arithmetic type}} expected-error 2 {{const-qualified variable cannot be reduction}} @@ -246,7 +246,7 @@ #pragma omp parallel for simd reduction(- : da) // expected-error {{a reduction variable with array type 'const int [5]'}} for (int i = 0; i < 10; ++i) foo(); -#pragma omp parallel for simd reduction(^ : fl) // expected-error {{variable of type 'float' is not valid for specified reduction operation}} +#pragma omp parallel for simd reduction(^ : fl) // expected-error {{invalid operands to binary expression ('float' and 'float')}} for (int i = 0; i < 10; ++i) foo(); #pragma omp parallel for simd reduction(&& : S2::S2s) @@ -255,13 +255,13 @@ #pragma omp parallel for simd reduction(&& : S2::S2sc) // expected-error {{const-qualified variable cannot be reduction}} for (int i = 0; i < 10; ++i) foo(); -#pragma omp parallel for simd reduction(& : e, g) // expected-error {{reduction variable must have an accessible, unambiguous default constructor}} expected-error {{variable of type 'S5' is not valid for specified reduction operation}} +#pragma omp parallel for simd reduction(& : e, g) // expected-error {{calling a private constructor of class 'S4'}} expected-error {{invalid operands to binary expression ('S4' and 'S4')}} expected-error {{calling a private constructor of class 'S5'}} expected-error {{invalid operands to binary expression ('S5' and 'S5')}} for (int i = 0; i < 10; ++i) foo(); #pragma omp parallel for simd reduction(+ : h, k) // expected-error {{threadprivate or thread local variable cannot be reduction}} for (int i = 0; i < 10; ++i) foo(); -#pragma omp parallel for simd reduction(+ : o) // expected-error {{variable of type 'class S6' is not valid for specified reduction operation}} +#pragma omp parallel for simd reduction(+ : o) // expected-error {{no viable overloaded '='}} for (int i = 0; i < 10; ++i) foo(); #pragma omp parallel for simd private(i), reduction(+ : j), reduction(+ : q) // expected-error 2 {{argument of OpenMP clause 'reduction' must reference the same object in all threads}} Index: test/OpenMP/parallel_reduction_codegen.cpp =================================================================== --- test/OpenMP/parallel_reduction_codegen.cpp +++ test/OpenMP/parallel_reduction_codegen.cpp @@ -0,0 +1,703 @@ +// RUN: %clang_cc1 -verify -fopenmp=libiomp5 -x c++ -triple x86_64-apple-darwin10 -emit-llvm %s -o - | FileCheck %s +// RUN: %clang_cc1 -fopenmp=libiomp5 -x c++ -std=c++11 -triple x86_64-apple-darwin10 -emit-pch -o %t %s +// RUN: %clang_cc1 -fopenmp=libiomp5 -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=libiomp5 -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=libiomp5 -x c++ -fblocks -DBLOCKS -triple x86_64-apple-darwin10 -emit-llvm %s -o - | FileCheck -check-prefix=BLOCKS %s +// expected-no-diagnostics +#ifndef HEADER +#define HEADER + +volatile int g = 1212; + +template +struct S { + T f; + S(T a) : f(a + g) {} + S() : f(g) {} + operator T() { return T(); } + S &operator&(const S &) { return *this; } + ~S() {} +}; + +// CHECK-DAG: [[S_FLOAT_TY:%.+]] = type { float } +// CHECK-DAG: [[S_INT_TY:%.+]] = type { i{{[0-9]+}} } +// CHECK-DAG: [[CAP_MAIN_TY:%.+]] = type { [2 x i{{[0-9]+}}]*, float*, [2 x [[S_FLOAT_TY]]]*, [[S_FLOAT_TY]]*, [[S_FLOAT_TY]]*, float* } +// CHECK-DAG: [[CAP_TMAIN_TY:%.+]] = type { [2 x i{{[0-9]+}}]*, i{{[0-9]+}}*, [2 x [[S_INT_TY]]]*, [[S_INT_TY]]*, [[S_INT_TY]]*, i{{[0-9]+}}* } +// CHECK-DAG: [[IMPLICIT_BARRIER_LOC:@.+]] = private unnamed_addr constant %{{.+}} { i32 0, i32 66, i32 0, i32 0, i8* +// CHECK-DAG: [[REDUCTION_LOC:@.+]] = private unnamed_addr constant %{{.+}} { i32 0, i32 18, i32 0, i32 0, i8* +// CHECK-DAG: [[REDUCTION_LOCK:@.+]] = common global [8 x i32] zeroinitializer + +template +T tmain() { + T t; + S test; + T t_var = T(), t_var1; + T vec[] = {1, 2}; + S s_arr[] = {1, 2}; + S var(3), var1; +#pragma omp parallel reduction(+:t_var) reduction(&:var) reduction(&& : var1) reduction(min: t_var1) + { + vec[0] = t_var; + s_arr[0] = var; + } + return T(); +} + +int main() { +#ifdef LAMBDA + // LAMBDA: [[G:@.+]] = global i{{[0-9]+}} 1212, + // LAMBDA-LABEL: @main + // LAMBDA: call void [[OUTER_LAMBDA:@.+]]( + [&]() { + // LAMBDA: define{{.*}} internal{{.*}} void [[OUTER_LAMBDA]]( + // LAMBDA: [[G_LOCAL_REF:%.+]] = getelementptr inbounds %{{.+}}, %{{.+}}* [[AGG_CAPTURED:%.+]], i{{[0-9]+}} 0, i{{[0-9]+}} 0 + // LAMBDA: store i{{[0-9]+}}* [[G]], i{{[0-9]+}}** [[G_LOCAL_REF]] + // LAMBDA: [[ARG:%.+]] = bitcast %{{.+}}* [[AGG_CAPTURED]] to i8* + // LAMBDA: call void {{.+}}* @__kmpc_fork_call({{.+}}, i32 1, {{.+}}* [[OMP_REGION:@.+]] to {{.+}}, i8* [[ARG]]) +#pragma omp parallel reduction(+:g) + { + // LAMBDA: define{{.*}} internal{{.*}} void [[OMP_REGION]](i32* %{{.+}}, i32* %{{.+}}, %{{.+}}* [[ARG:%.+]]) + // LAMBDA: [[G_PRIVATE_ADDR:%.+]] = alloca i{{[0-9]+}}, + + // Reduction list for runtime. + // LAMBDA: [[RED_LIST:%.+]] = alloca [1 x i8*], + + // LAMBDA: store %{{.+}}* [[ARG]], %{{.+}}** [[ARG_REF:%.+]], + // LAMBDA: [[ARG:%.+]] = load %{{.+}}*, %{{.+}}** [[ARG_REF]] + // LAMBDA: [[G_REF_ADDR:%.+]] = getelementptr inbounds %{{.+}}, %{{.+}}* [[ARG]], i{{[0-9]+}} 0, i{{[0-9]+}} 0 + // LAMBDA: [[G_REF:%.+]] = load i{{[0-9]+}}*, i{{[0-9]+}}** [[G_REF_ADDR]] + // LAMBDA: store i{{[0-9]+}} 0, i{{[0-9]+}}* [[G_PRIVATE_ADDR]] + // LAMBDA: call i32 @__kmpc_cancel_barrier( + g = 1; + // LAMBDA: store volatile i{{[0-9]+}} 1, i{{[0-9]+}}* [[G_PRIVATE_ADDR]], + // LAMBDA: [[G_PRIVATE_ADDR_REF:%.+]] = getelementptr inbounds %{{.+}}, %{{.+}}* [[ARG:%.+]], i{{[0-9]+}} 0, i{{[0-9]+}} 0 + // LAMBDA: store i{{[0-9]+}}* [[G_PRIVATE_ADDR]], i{{[0-9]+}}** [[G_PRIVATE_ADDR_REF]] + // LAMBDA: call void [[INNER_LAMBDA:@.+]](%{{.+}}* [[ARG]]) + + // LAMBDA: [[G_PRIV_REF:%.+]] = getelementptr inbounds [1 x i8*], [1 x i8*]* [[RED_LIST]], i32 0, i32 0 + // LAMBDA: [[BITCAST:%.+]] = bitcast i32* [[G_PRIVATE_ADDR]] to i8* + // LAMBDA: store i8* [[BITCAST]], i8** [[G_PRIV_REF]], + // LAMBDA: call i32 @__kmpc_reduce_nowait( + // LAMBDA: switch i32 %{{.+}}, label %[[REDUCTION_DONE:.+]] [ + // LAMBDA: i32 1, label %[[CASE1:.+]] + // LAMBDA: i32 2, label %[[CASE2:.+]] + // LAMBDA: [[CASE1]] + // LAMBDA: [[G_VAL:%.+]] = load i32, i32* [[G_REF]] + // LAMBDA: [[G_PRIV_VAL:%.+]] = load i32, i32* [[G_PRIVATE_ADDR]] + // LAMBDA: [[ADD:%.+]] = add nsw i32 [[G_VAL]], [[G_PRIV_VAL]] + // LAMBDA: store i32 [[ADD]], i32* [[G_REF]] + // LAMBDA: call void @__kmpc_end_reduce_nowait( + // LAMBDA: br label %[[REDUCTION_DONE]] + // LAMBDA: [[CASE2]] + // LAMBDA: [[G_PRIV_VAL:%.+]] = load i32, i32* [[G_PRIVATE_ADDR]] + // LAMBDA: atomicrmw add i32* [[G_REF]], i32 [[G_PRIV_VAL]] monotonic + // LAMBDA: br label %[[REDUCTION_DONE]] + // LAMBDA: [[REDUCTION_DONE]] + // LAMBDA: ret void + [&]() { + // LAMBDA: define {{.+}} void [[INNER_LAMBDA]](%{{.+}}* [[ARG_PTR:%.+]]) + // LAMBDA: store %{{.+}}* [[ARG_PTR]], %{{.+}}** [[ARG_PTR_REF:%.+]], + g = 2; + // LAMBDA: [[ARG_PTR:%.+]] = load %{{.+}}*, %{{.+}}** [[ARG_PTR_REF]] + // LAMBDA: [[G_PTR_REF:%.+]] = getelementptr inbounds %{{.+}}, %{{.+}}* [[ARG_PTR]], i{{[0-9]+}} 0, i{{[0-9]+}} 0 + // LAMBDA: [[G_REF:%.+]] = load i{{[0-9]+}}*, i{{[0-9]+}}** [[G_PTR_REF]] + // LAMBDA: store volatile i{{[0-9]+}} 2, i{{[0-9]+}}* [[G_REF]] + }(); + } + }(); + return 0; +#elif defined(BLOCKS) + // BLOCKS: [[G:@.+]] = global i{{[0-9]+}} 1212, + // BLOCKS-LABEL: @main + // BLOCKS: call void {{%.+}}(i8* + ^{ + // BLOCKS: define{{.*}} internal{{.*}} void {{.+}}(i8* + // BLOCKS: [[G_LOCAL_REF:%.+]] = getelementptr inbounds %{{.+}}, %{{.+}}* [[AGG_CAPTURED:%.+]], i{{[0-9]+}} 0, i{{[0-9]+}} 0 + // BLOCKS: store i{{[0-9]+}}* [[G]], i{{[0-9]+}}** [[G_LOCAL_REF]] + // BLOCKS: [[ARG:%.+]] = bitcast %{{.+}}* [[AGG_CAPTURED]] to i8* + // BLOCKS: call void {{.+}}* @__kmpc_fork_call({{.+}}, i32 1, {{.+}}* [[OMP_REGION:@.+]] to {{.+}}, i8* [[ARG]]) +#pragma omp parallel reduction(-:g) + { + // BLOCKS: define{{.*}} internal{{.*}} void [[OMP_REGION]](i32* %{{.+}}, i32* %{{.+}}, %{{.+}}* [[ARG:%.+]]) + // BLOCKS: [[G_PRIVATE_ADDR:%.+]] = alloca i{{[0-9]+}}, + + // Reduction list for runtime. + // BLOCKS: [[RED_LIST:%.+]] = alloca [1 x i8*], + + // BLOCKS: store %{{.+}}* [[ARG]], %{{.+}}** [[ARG_REF:%.+]], + // BLOCKS: [[ARG:%.+]] = load %{{.+}}*, %{{.+}}** [[ARG_REF]] + // BLOCKS: [[G_REF_ADDR:%.+]] = getelementptr inbounds %{{.+}}, %{{.+}}* [[ARG]], i{{[0-9]+}} 0, i{{[0-9]+}} 0 + // BLOCKS: [[G_REF:%.+]] = load i{{[0-9]+}}*, i{{[0-9]+}}** [[G_REF_ADDR]] + // BLOCKS: store i{{[0-9]+}} 0, i{{[0-9]+}}* [[G_PRIVATE_ADDR]] + // BLOCKS: call i32 @__kmpc_cancel_barrier( + g = 1; + // BLOCKS: store volatile i{{[0-9]+}} 1, i{{[0-9]+}}* [[G_PRIVATE_ADDR]], + // BLOCKS-NOT: [[G]]{{[[^:word:]]}} + // BLOCKS: i{{[0-9]+}}* [[G_PRIVATE_ADDR]] + // BLOCKS-NOT: [[G]]{{[[^:word:]]}} + // BLOCKS: call void {{%.+}}(i8* + + // BLOCKS: [[G_PRIV_REF:%.+]] = getelementptr inbounds [1 x i8*], [1 x i8*]* [[RED_LIST]], i32 0, i32 0 + // BLOCKS: [[BITCAST:%.+]] = bitcast i32* [[G_PRIVATE_ADDR]] to i8* + // BLOCKS: store i8* [[BITCAST]], i8** [[G_PRIV_REF]], + // BLOCKS: call i32 @__kmpc_reduce_nowait( + // BLOCKS: switch i32 %{{.+}}, label %[[REDUCTION_DONE:.+]] [ + // BLOCKS: i32 1, label %[[CASE1:.+]] + // BLOCKS: i32 2, label %[[CASE2:.+]] + // BLOCKS: [[CASE1]] + // BLOCKS: [[G_VAL:%.+]] = load i32, i32* [[G_REF]] + // BLOCKS: [[G_PRIV_VAL:%.+]] = load i32, i32* [[G_PRIVATE_ADDR]] + // BLOCKS: [[ADD:%.+]] = add nsw i32 [[G_VAL]], [[G_PRIV_VAL]] + // BLOCKS: store i32 [[ADD]], i32* [[G_REF]] + // BLOCKS: call void @__kmpc_end_reduce_nowait( + // BLOCKS: br label %[[REDUCTION_DONE]] + // BLOCKS: [[CASE2]] + // BLOCKS: [[G_PRIV_VAL:%.+]] = load i32, i32* [[G_PRIVATE_ADDR]] + // BLOCKS: atomicrmw add i32* [[G_REF]], i32 [[G_PRIV_VAL]] monotonic + // BLOCKS: br label %[[REDUCTION_DONE]] + // BLOCKS: [[REDUCTION_DONE]] + // BLOCKS: ret void + ^{ + // BLOCKS: define {{.+}} void {{@.+}}(i8* + g = 2; + // BLOCKS-NOT: [[G]]{{[[^:word:]]}} + // BLOCKS: store volatile i{{[0-9]+}} 2, i{{[0-9]+}}* + // BLOCKS-NOT: [[G]]{{[[^:word:]]}} + // BLOCKS: ret + }(); + } + }(); + return 0; +#else + S test; + float t_var = 0, t_var1; + int vec[] = {1, 2}; + S s_arr[] = {1, 2}; + S var(3), var1; +#pragma omp parallel reduction(+:t_var) reduction(&:var) reduction(&& : var1) reduction(min: t_var1) + { + vec[0] = t_var; + s_arr[0] = var; + } + return tmain(); +#endif +} + +// CHECK: define {{.*}}i{{[0-9]+}} @main() +// CHECK: [[TEST:%.+]] = alloca [[S_FLOAT_TY]], +// CHECK: call {{.*}} [[S_FLOAT_TY_CONSTR:@.+]]([[S_FLOAT_TY]]* [[TEST]]) +// CHECK: %{{.+}} = bitcast [[CAP_MAIN_TY]]* +// 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]+}}*, [[CAP_MAIN_TY]]*)* [[MAIN_MICROTASK:@.+]] to void +// CHECK: = call {{.*}}i{{.+}} [[TMAIN_INT:@.+]]() +// CHECK: call {{.*}} [[S_FLOAT_TY_DESTR:@.+]]([[S_FLOAT_TY]]* +// CHECK: ret +// +// CHECK: define internal void [[MAIN_MICROTASK]](i{{[0-9]+}}* [[GTID_ADDR:%.+]], i{{[0-9]+}}* %{{.+}}, [[CAP_MAIN_TY]]* %{{.+}}) +// CHECK: [[T_VAR_PRIV:%.+]] = alloca float, +// CHECK: [[VAR_PRIV:%.+]] = alloca [[S_FLOAT_TY]], +// CHECK: [[VAR1_PRIV:%.+]] = alloca [[S_FLOAT_TY]], +// CHECK: [[T_VAR1_PRIV:%.+]] = alloca float, + +// Reduction list for runtime. +// CHECK: [[RED_LIST:%.+]] = alloca [4 x i8*], + +// CHECK: store i{{[0-9]+}}* [[GTID_ADDR]], i{{[0-9]+}}** [[GTID_ADDR_ADDR:%.+]], + +// CHECK: [[T_VAR_PTR_REF:%.+]] = getelementptr inbounds [[CAP_MAIN_TY]], [[CAP_MAIN_TY]]* %{{.+}}, i{{[0-9]+}} 0, i{{[0-9]+}} {{[0-9]+}} +// CHECK: [[T_VAR_REF:%.+]] = load float*, float** [[T_VAR_PTR_REF]], +// For + reduction operation initial value of private variable is 0. +// CHECK: store float 0.0{{.+}}, float* [[T_VAR_PRIV]], + +// CHECK: [[VAR_PTR_REF:%.+]] = getelementptr inbounds [[CAP_MAIN_TY]], [[CAP_MAIN_TY]]* %{{.+}}, i{{[0-9]+}} 0, i{{[0-9]+}} {{[0-9]+}} +// CHECK: [[VAR_REF:%.+]] = load [[S_FLOAT_TY]]*, [[S_FLOAT_TY]]** [[VAR_PTR_REF:%.+]], +// For & reduction operation initial value of private variable is ones in all bits. +// CHECK: call {{.*}} [[S_FLOAT_TY_CONSTR:@.+]]([[S_FLOAT_TY]]* [[VAR_PRIV]]) + +// CHECK: [[VAR1_PTR_REF:%.+]] = getelementptr inbounds [[CAP_MAIN_TY]], [[CAP_MAIN_TY]]* %{{.+}}, i{{[0-9]+}} 0, i{{[0-9]+}} {{[0-9]+}} +// CHECK: [[VAR1_REF:%.+]] = load [[S_FLOAT_TY]]*, [[S_FLOAT_TY]]** [[VAR_PTR_REF:%.+]], +// For && reduction operation initial value of private variable is 1.0. +// CHECK: call {{.*}} [[S_FLOAT_TY_CONSTR:@.+]]([[S_FLOAT_TY]]* [[VAR1_PRIV]]) + +// CHECK: [[T_VAR1_PTR_REF:%.+]] = getelementptr inbounds [[CAP_MAIN_TY]], [[CAP_MAIN_TY]]* %{{.+}}, i{{[0-9]+}} 0, i{{[0-9]+}} {{[0-9]+}} +// CHECK: [[T_VAR1_REF:%.+]] = load float*, float** [[T_VAR1_PTR_REF]], +// For min reduction operation initial value of private variable is largest repesentable value. +// CHECK: store float 0x47EFFFFFE0000000, float* [[T_VAR1_PRIV]], + +// CHECK: [[GTID_REF:%.+]] = load i{{[0-9]+}}*, i{{[0-9]+}}** [[GTID_ADDR_ADDR]] +// CHECK: [[GTID:%.+]] = load i{{[0-9]+}}, i{{[0-9]+}}* [[GTID_REF]] +// CHECK: call i32 @__kmpc_cancel_barrier(%{{.+}}* [[IMPLICIT_BARRIER_LOC]], i{{[0-9]+}} [[GTID]]) + +// Skip checks for internal operations. + +// void *RedList[] = {[0], ..., [-1]}; + +// CHECK: [[T_VAR_PRIV_REF:%.+]] = getelementptr inbounds [4 x i8*], [4 x i8*]* [[RED_LIST]], i32 0, i32 0 +// CHECK: [[BITCAST:%.+]] = bitcast float* [[T_VAR_PRIV]] to i8* +// CHECK: store i8* [[BITCAST]], i8** [[T_VAR_PRIV_REF]], +// CHECK: [[VAR_PRIV_REF:%.+]] = getelementptr inbounds [4 x i8*], [4 x i8*]* [[RED_LIST]], i32 0, i32 1 +// CHECK: [[BITCAST:%.+]] = bitcast [[S_FLOAT_TY]]* [[VAR_PRIV]] to i8* +// CHECK: store i8* [[BITCAST]], i8** [[VAR_PRIV_REF]], +// CHECK: [[VAR1_PRIV_REF:%.+]] = getelementptr inbounds [4 x i8*], [4 x i8*]* [[RED_LIST]], i32 0, i32 2 +// CHECK: [[BITCAST:%.+]] = bitcast [[S_FLOAT_TY]]* [[VAR1_PRIV]] to i8* +// CHECK: store i8* [[BITCAST]], i8** [[VAR1_PRIV_REF]], +// CHECK: [[T_VAR1_PRIV_REF:%.+]] = getelementptr inbounds [4 x i8*], [4 x i8*]* [[RED_LIST]], i32 0, i32 3 +// CHECK: [[BITCAST:%.+]] = bitcast float* [[T_VAR1_PRIV]] to i8* +// CHECK: store i8* [[BITCAST]], i8** [[T_VAR1_PRIV_REF]], + +// res = __kmpc_reduce_nowait(, , , sizeof(RedList), RedList, reduce_func, &); + +// CHECK: [[BITCAST:%.+]] = bitcast [4 x i8*]* [[RED_LIST]] to i8* +// CHECK: [[RES:%.+]] = call i32 @__kmpc_reduce_nowait(%{{.+}}* [[REDUCTION_LOC]], i32 [[GTID]], i32 4, i64 32, i8* [[BITCAST]], void (i8*, i8*)* [[REDUCTION_FUNC:@.+]], [8 x i32]* [[REDUCTION_LOCK]]) + +// switch(res) +// CHECK: switch i32 [[RES]], label %[[RED_DONE:.+]] [ +// CHECK: i32 1, label %[[CASE1:.+]] +// CHECK: i32 2, label %[[CASE2:.+]] +// CHECK: ] + +// case 1: +// t_var += t_var_reduction; +// CHECK: [[T_VAR_VAL:%.+]] = load float, float* [[T_VAR_REF]], +// CHECK: [[T_VAR_PRIV_VAL:%.+]] = load float, float* [[T_VAR_PRIV]], +// CHECK: [[UP:%.+]] = fadd float [[T_VAR_VAL]], [[T_VAR_PRIV_VAL]] +// CHECK: store float [[UP]], float* [[T_VAR_REF]], + +// var = var.operator &(var_reduction); +// CHECK: [[UP:%.+]] = call dereferenceable(4) [[S_FLOAT_TY]]* @{{.+}}([[S_FLOAT_TY]]* [[VAR_REF]], [[S_FLOAT_TY]]* dereferenceable(4) [[VAR_PRIV]]) +// CHECK: [[BC1:%.+]] = bitcast [[S_FLOAT_TY]]* [[VAR_REF]] to i8* +// CHECK: [[BC2:%.+]] = bitcast [[S_FLOAT_TY]]* [[UP]] to i8* +// CHECK: call void @llvm.memcpy.p0i8.p0i8.i64(i8* [[BC1]], i8* [[BC2]], i64 4, i32 4, i1 false) + +// var1 = var1.operator &&(var1_reduction); +// CHECK: [[TO_FLOAT:%.+]] = call float @{{.+}}([[S_FLOAT_TY]]* [[VAR1_REF]]) +// CHECK: [[VAR1_BOOL:%.+]] = fcmp une float [[TO_FLOAT]], 0.0 +// CHECK: br i1 [[VAR1_BOOL]], label %[[TRUE:.+]], label %[[FALSE:.+]] +// CHECK: [[TRUE]] +// CHECK: [[TO_FLOAT:%.+]] = call float @{{.+}}([[S_FLOAT_TY]]* [[VAR1_PRIV]]) +// CHECK: [[VAR1_REDUCTION_BOOL:%.+]] = fcmp une float [[TO_FLOAT]], 0.0 +// CHECK: br i1 [[VAR1_REDUCTION_BOOL]], label %[[TRUE2:.+]], label %[[FALSE2:.+]] +// CHECK: [[TRUE2]] +// CHECK: br label %[[END2:.+]] +// CHECK: [[FALSE2]] +// CHECK: br label %[[END2]] +// CHECK: [[END2]] +// CHECK: [[COND_LVALUE:%.+]] = phi [[S_FLOAT_TY]]* [ [[VAR1_REF]], %[[TRUE2]] ], [ [[VAR1_PRIV]], %[[FALSE2]] ] +// CHECK: [[BC1:%.+]] = bitcast [[S_FLOAT_TY]]* [[VAR1_REF]] to i8* +// CHECK: [[BC2:%.+]] = bitcast [[S_FLOAT_TY]]* [[COND_LVALUE]] to i8* +// CHECK: call void @llvm.memcpy.p0i8.p0i8.i64(i8* [[BC1]], i8* [[BC2]], i64 4, i32 4, i1 false) + +// t_var1 = min(t_var1, t_var1_reduction); +// CHECK: [[T_VAR1_VAL:%.+]] = load float, float* [[T_VAR1_REF]], +// CHECK: [[T_VAR1_PRIV_VAL:%.+]] = load float, float* [[T_VAR1_PRIV]], +// CHECK: [[CMP:%.+]] = fcmp olt float [[T_VAR1_VAL]], [[T_VAR1_PRIV_VAL]] +// CHECK: [[UP:%.+]] = uitofp i1 [[CMP]] to float +// CHECK: store float [[UP]], float* [[T_VAR1_REF]], + +// __kmpc_end_reduce_nowait(, , &); +// CHECK: call void @__kmpc_end_reduce_nowait(%{{.+}}* [[REDUCTION_LOC]], i32 [[GTID]], [8 x i32]* [[REDUCTION_LOCK]]) + +// break; +// CHECK: br label %[[RED_DONE]] + +// case 2: +// t_var += t_var_reduction; +// CHECK: load float, float* [[T_VAR_PRIV]] +// CHECK: [[T_VAR_REF_INT:%.+]] = bitcast float* [[T_VAR_REF]] to i32* +// CHECK: load atomic i32, i32* [[T_VAR_REF_INT]] monotonic, +// CHECK: [[OLD1:%.+]] = bitcast i32 %{{.+}} to float +// CHECK: br label %[[CONT:.+]] +// CHECK: [[CONT]] +// CHECK: [[ORIG_OLD:%.+]] = phi float [ [[OLD1]], %{{.+}} ], [ [[OLD2:%.+]], %[[CONT]] ] +// CHECK: [[UP:%.+]] = fadd float +// CHECK: [[ORIG_OLD_INT:%.+]] = bitcast float [[ORIG_OLD]] to i32 +// CHECK: [[UP_INT:%.+]] = bitcast float [[UP]] to i32 +// CHECK: [[T_VAR_REF_INT:%.+]] = bitcast float* [[T_VAR_REF]] to i32* +// CHECK: [[RES:%.+]] = cmpxchg i32* [[T_VAR_REF_INT]], i32 [[ORIG_OLD_INT]], i32 [[UP_INT]] monotonic monotonic +// CHECK: [[OLD_VAL_INT:%.+]] = extractvalue { i32, i1 } [[RES]], 0 +// CHECK: [[SUCCESS_FAIL:%.+]] = extractvalue { i32, i1 } [[RES]], 1 +// CHECK: [[OLD2]] = bitcast i32 [[OLD_VAL_INT]] to float +// CHECK: br i1 [[SUCCESS_FAIL]], label %[[ATOMIC_DONE:.+]], label %[[CONT]] +// CHECK: [[ATOMIC_DONE]] + +// var = var.operator &(var_reduction); +// CHECK: call void @__kmpc_critical( +// CHECK: [[UP:%.+]] = call dereferenceable(4) [[S_FLOAT_TY]]* @{{.+}}([[S_FLOAT_TY]]* [[VAR_REF]], [[S_FLOAT_TY]]* dereferenceable(4) [[VAR_PRIV]]) +// CHECK: [[BC1:%.+]] = bitcast [[S_FLOAT_TY]]* [[VAR_REF]] to i8* +// CHECK: [[BC2:%.+]] = bitcast [[S_FLOAT_TY]]* [[UP]] to i8* +// CHECK: call void @llvm.memcpy.p0i8.p0i8.i64(i8* [[BC1]], i8* [[BC2]], i64 4, i32 4, i1 false) +// CHECK: call void @__kmpc_end_critical( + +// var1 = var1.operator &&(var1_reduction); +// CHECK: call void @__kmpc_critical( +// CHECK: [[TO_FLOAT:%.+]] = call float @{{.+}}([[S_FLOAT_TY]]* [[VAR1_REF]]) +// CHECK: [[VAR1_BOOL:%.+]] = fcmp une float [[TO_FLOAT]], 0.0 +// CHECK: br i1 [[VAR1_BOOL]], label %[[TRUE:.+]], label %[[FALSE:.+]] +// CHECK: [[TRUE]] +// CHECK: [[TO_FLOAT:%.+]] = call float @{{.+}}([[S_FLOAT_TY]]* [[VAR1_PRIV]]) +// CHECK: [[VAR1_REDUCTION_BOOL:%.+]] = fcmp une float [[TO_FLOAT]], 0.0 +// CHECK: br i1 [[VAR1_REDUCTION_BOOL]], label %[[TRUE2:.+]], label %[[FALSE2:.+]] +// CHECK: [[TRUE2]] +// CHECK: br label %[[END2:.+]] +// CHECK: [[FALSE2]] +// CHECK: br label %[[END2]] +// CHECK: [[END2]] +// CHECK: [[COND_LVALUE:%.+]] = phi [[S_FLOAT_TY]]* [ [[VAR1_REF]], %[[TRUE2]] ], [ [[VAR1_PRIV]], %[[FALSE2]] ] +// CHECK: [[BC1:%.+]] = bitcast [[S_FLOAT_TY]]* [[VAR1_REF]] to i8* +// CHECK: [[BC2:%.+]] = bitcast [[S_FLOAT_TY]]* [[COND_LVALUE]] to i8* +// CHECK: call void @llvm.memcpy.p0i8.p0i8.i64(i8* [[BC1]], i8* [[BC2]], i64 4, i32 4, i1 false) +// CHECK: call void @__kmpc_end_critical( + +// t_var1 = min(t_var1, t_var1_reduction); +// CHECK: load float, float* [[T_VAR1_PRIV]] +// CHECK: [[T_VAR1_REF_INT:%.+]] = bitcast float* [[T_VAR1_REF]] to i32* +// CHECK: load atomic i32, i32* [[T_VAR1_REF_INT]] monotonic, +// CHECK: [[OLD1:%.+]] = bitcast i32 %{{.+}} to float +// CHECK: br label %[[CONT:.+]] +// CHECK: [[CONT]] +// CHECK: [[ORIG_OLD:%.+]] = phi float [ [[OLD1]], %{{.+}} ], [ [[OLD2:%.+]], %[[CONT]] ] +// CHECK: [[CMP:%.+]] = fcmp olt float +// CHECK: [[UP:%.+]] = uitofp i1 [[CMP]] to float +// CHECK: [[ORIG_OLD_INT:%.+]] = bitcast float [[ORIG_OLD]] to i32 +// CHECK: [[UP_INT:%.+]] = bitcast float [[UP]] to i32 +// CHECK: [[T_VAR1_REF_INT:%.+]] = bitcast float* [[T_VAR1_REF]] to i32* +// CHECK: [[RES:%.+]] = cmpxchg i32* [[T_VAR1_REF_INT]], i32 [[ORIG_OLD_INT]], i32 [[UP_INT]] monotonic monotonic +// CHECK: [[OLD_VAL_INT:%.+]] = extractvalue { i32, i1 } [[RES]], 0 +// CHECK: [[SUCCESS_FAIL:%.+]] = extractvalue { i32, i1 } [[RES]], 1 +// CHECK: [[OLD2]] = bitcast i32 [[OLD_VAL_INT]] to float +// CHECK: br i1 [[SUCCESS_FAIL]], label %[[ATOMIC_DONE:.+]], label %[[CONT]] +// CHECK: [[ATOMIC_DONE]] + +// break; +// CHECK: br label %[[RED_DONE]] +// CHECK: [[RED_DONE]] +// CHECK: call i32 @__kmpc_cancel_barrier(%{{.+}}* [[IMPLICIT_BARRIER_LOC]], i{{[0-9]+}} [[GTID]]) + +// CHECK-DAG: call {{.*}} [[S_FLOAT_TY_DESTR]]([[S_FLOAT_TY]]* [[VAR_PRIV]]) +// CHECK-DAG: call {{.*}} [[S_FLOAT_TY_DESTR]]([[S_FLOAT_TY]]* +// CHECK: ret void + +// void reduce_func(void *lhs[], void *rhs[]) { +// *(Type0*)lhs[0] = ReductionOperation0(*(Type0*)lhs[0], *(Type0*)rhs[0]); +// ... +// *(Type-1*)lhs[-1] = ReductionOperation-1(*(Type-1*)lhs[-1], +// *(Type-1*)rhs[-1]); +// } +// CHECK: define internal void [[REDUCTION_FUNC]](i8*, i8*) +// t_var_lhs = (float*)lhs[0]; +// CHECK: [[T_VAR_RHS_REF:%.+]] = getelementptr inbounds [4 x i8*], [4 x i8*]* [[RED_LIST_RHS:%.+]], i32 0, i32 0 +// CHECK: [[T_VAR_RHS_VOID:%.+]] = load i8*, i8** [[T_VAR_RHS_REF]], +// CHECK: [[T_VAR_RHS:%.+]] = bitcast i8* [[T_VAR_RHS_VOID]] to float* +// t_var_rhs = (float*)rhs[0]; +// CHECK: [[T_VAR_LHS_REF:%.+]] = getelementptr inbounds [4 x i8*], [4 x i8*]* [[RED_LIST_LHS:%.+]], i32 0, i32 0 +// CHECK: [[T_VAR_LHS_VOID:%.+]] = load i8*, i8** [[T_VAR_LHS_REF]], +// CHECK: [[T_VAR_LHS:%.+]] = bitcast i8* [[T_VAR_LHS_VOID]] to float* + +// var_lhs = (S*)lhs[1]; +// CHECK: [[VAR_RHS_REF:%.+]] = getelementptr inbounds [4 x i8*], [4 x i8*]* [[RED_LIST_RHS]], i32 0, i32 1 +// CHECK: [[VAR_RHS_VOID:%.+]] = load i8*, i8** [[VAR_RHS_REF]], +// CHECK: [[VAR_RHS:%.+]] = bitcast i8* [[VAR_RHS_VOID]] to [[S_FLOAT_TY]]* +// var_rhs = (S*)rhs[1]; +// CHECK: [[VAR_LHS_REF:%.+]] = getelementptr inbounds [4 x i8*], [4 x i8*]* [[RED_LIST_LHS]], i32 0, i32 1 +// CHECK: [[VAR_LHS_VOID:%.+]] = load i8*, i8** [[VAR_LHS_REF]], +// CHECK: [[VAR_LHS:%.+]] = bitcast i8* [[VAR_LHS_VOID]] to [[S_FLOAT_TY]]* + +// var1_lhs = (S*)lhs[2]; +// CHECK: [[VAR1_RHS_REF:%.+]] = getelementptr inbounds [4 x i8*], [4 x i8*]* [[RED_LIST_RHS]], i32 0, i32 2 +// CHECK: [[VAR1_RHS_VOID:%.+]] = load i8*, i8** [[VAR1_RHS_REF]], +// CHECK: [[VAR1_RHS:%.+]] = bitcast i8* [[VAR1_RHS_VOID]] to [[S_FLOAT_TY]]* +// var1_rhs = (S*)rhs[2]; +// CHECK: [[VAR1_LHS_REF:%.+]] = getelementptr inbounds [4 x i8*], [4 x i8*]* [[RED_LIST_LHS]], i32 0, i32 2 +// CHECK: [[VAR1_LHS_VOID:%.+]] = load i8*, i8** [[VAR1_LHS_REF]], +// CHECK: [[VAR1_LHS:%.+]] = bitcast i8* [[VAR1_LHS_VOID]] to [[S_FLOAT_TY]]* + +// t_var1_lhs = (float*)lhs[3]; +// CHECK: [[T_VAR1_RHS_REF:%.+]] = getelementptr inbounds [4 x i8*], [4 x i8*]* [[RED_LIST_RHS]], i32 0, i32 3 +// CHECK: [[T_VAR1_RHS_VOID:%.+]] = load i8*, i8** [[T_VAR1_RHS_REF]], +// CHECK: [[T_VAR1_RHS:%.+]] = bitcast i8* [[T_VAR1_RHS_VOID]] to float* +// t_var1_rhs = (float*)rhs[3]; +// CHECK: [[T_VAR1_LHS_REF:%.+]] = getelementptr inbounds [4 x i8*], [4 x i8*]* [[RED_LIST_LHS]], i32 0, i32 3 +// CHECK: [[T_VAR1_LHS_VOID:%.+]] = load i8*, i8** [[T_VAR1_LHS_REF]], +// CHECK: [[T_VAR1_LHS:%.+]] = bitcast i8* [[T_VAR1_LHS_VOID]] to float* + +// t_var_lhs += t_var_rhs; +// CHECK: [[T_VAR_LHS_VAL:%.+]] = load float, float* [[T_VAR_LHS]], +// CHECK: [[T_VAR_RHS_VAL:%.+]] = load float, float* [[T_VAR_RHS]], +// CHECK: [[UP:%.+]] = fadd float [[T_VAR_LHS_VAL]], [[T_VAR_RHS_VAL]] +// CHECK: store float [[UP]], float* [[T_VAR_LHS]], + +// var_lhs = var_lhs.operator &(var_rhs); +// CHECK: [[UP:%.+]] = call dereferenceable(4) [[S_FLOAT_TY]]* @{{.+}}([[S_FLOAT_TY]]* [[VAR_LHS]], [[S_FLOAT_TY]]* dereferenceable(4) [[VAR_RHS]]) +// CHECK: [[BC1:%.+]] = bitcast [[S_FLOAT_TY]]* [[VAR_LHS]] to i8* +// CHECK: [[BC2:%.+]] = bitcast [[S_FLOAT_TY]]* [[UP]] to i8* +// CHECK: call void @llvm.memcpy.p0i8.p0i8.i64(i8* [[BC1]], i8* [[BC2]], i64 4, i32 4, i1 false) + +// var1_lhs = var1_lhs.operator &&(var1_rhs); +// CHECK: [[TO_FLOAT:%.+]] = call float @{{.+}}([[S_FLOAT_TY]]* [[VAR1_LHS]]) +// CHECK: [[VAR1_BOOL:%.+]] = fcmp une float [[TO_FLOAT]], 0.0 +// CHECK: br i1 [[VAR1_BOOL]], label %[[TRUE:.+]], label %[[FALSE:.+]] +// CHECK: [[TRUE]] +// CHECK: [[TO_FLOAT:%.+]] = call float @{{.+}}([[S_FLOAT_TY]]* [[VAR1_RHS]]) +// CHECK: [[VAR1_REDUCTION_BOOL:%.+]] = fcmp une float [[TO_FLOAT]], 0.0 +// CHECK: br i1 [[VAR1_REDUCTION_BOOL]], label %[[TRUE2:.+]], label %[[FALSE2:.+]] +// CHECK: [[TRUE2]] +// CHECK: br label %[[END2:.+]] +// CHECK: [[FALSE2]] +// CHECK: br label %[[END2]] +// CHECK: [[END2]] +// CHECK: [[COND_LVALUE:%.+]] = phi [[S_FLOAT_TY]]* [ [[VAR1_LHS]], %[[TRUE2]] ], [ [[VAR1_RHS]], %[[FALSE2]] ] +// CHECK: [[BC1:%.+]] = bitcast [[S_FLOAT_TY]]* [[VAR1_LHS]] to i8* +// CHECK: [[BC2:%.+]] = bitcast [[S_FLOAT_TY]]* [[COND_LVALUE]] to i8* +// CHECK: call void @llvm.memcpy.p0i8.p0i8.i64(i8* [[BC1]], i8* [[BC2]], i64 4, i32 4, i1 false) + +// t_var1_lhs = min(t_var1_lhs, t_var1_rhs); +// CHECK: [[T_VAR1_LHS_VAL:%.+]] = load float, float* [[T_VAR1_LHS]], +// CHECK: [[T_VAR1_RHS_VAL:%.+]] = load float, float* [[T_VAR1_RHS]], +// CHECK: [[CMP:%.+]] = fcmp olt float [[T_VAR1_LHS_VAL]], [[T_VAR1_RHS_VAL]] +// CHECK: [[UP:%.+]] = uitofp i1 [[CMP]] to float +// CHECK: store float [[UP]], float* [[T_VAR1_LHS]], +// CHECK: ret void + +// CHECK: define {{.*}} i{{[0-9]+}} [[TMAIN_INT]]() +// CHECK: [[TEST:%.+]] = alloca [[S_INT_TY]], +// CHECK: call {{.*}} [[S_INT_TY_CONSTR:@.+]]([[S_INT_TY]]* [[TEST]]) +// CHECK: %{{.+}} = bitcast [[CAP_TMAIN_TY]]* +// 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]+}}*, [[CAP_TMAIN_TY]]*)* [[TMAIN_MICROTASK:@.+]] to void +// CHECK: call {{.*}} [[S_INT_TY_DESTR:@.+]]([[S_INT_TY]]* +// CHECK: ret +// +// CHECK: define internal void [[TMAIN_MICROTASK]](i{{[0-9]+}}* [[GTID_ADDR:%.+]], i{{[0-9]+}}* %{{.+}}, [[CAP_TMAIN_TY]]* %{{.+}}) +// CHECK: [[T_VAR_PRIV:%.+]] = alloca i{{[0-9]+}}, +// CHECK: [[VAR_PRIV:%.+]] = alloca [[S_INT_TY]], +// CHECK: [[VAR1_PRIV:%.+]] = alloca [[S_INT_TY]], +// CHECK: [[T_VAR1_PRIV:%.+]] = alloca i{{[0-9]+}}, + +// Reduction list for runtime. +// CHECK: [[RED_LIST:%.+]] = alloca [4 x i8*], + +// CHECK: store i{{[0-9]+}}* [[GTID_ADDR]], i{{[0-9]+}}** [[GTID_ADDR_ADDR:%.+]], + +// CHECK: [[T_VAR_PTR_REF:%.+]] = getelementptr inbounds [[CAP_TMAIN_TY]], [[CAP_TMAIN_TY]]* %{{.+}}, i{{[0-9]+}} 0, i{{[0-9]+}} {{[0-9]+}} +// CHECK: [[T_VAR_REF:%.+]] = load i{{[0-9]+}}*, i{{[0-9]+}}** [[T_VAR_PTR_REF]], +// For + reduction operation initial value of private variable is 0. +// CHECK: store i{{[0-9]+}} 0, i{{[0-9]+}}* [[T_VAR_PRIV]], + +// CHECK: [[VAR_PTR_REF:%.+]] = getelementptr inbounds [[CAP_TMAIN_TY]], [[CAP_TMAIN_TY]]* %{{.+}}, i{{[0-9]+}} 0, i{{[0-9]+}} {{[0-9]+}} +// CHECK: [[VAR_REF:%.+]] = load [[S_INT_TY]]*, [[S_INT_TY]]** [[VAR_PTR_REF:%.+]], +// For & reduction operation initial value of private variable is ones in all bits. +// CHECK: call {{.*}} [[S_INT_TY_CONSTR:@.+]]([[S_INT_TY]]* [[VAR_PRIV]]) + +// CHECK: [[VAR1_PTR_REF:%.+]] = getelementptr inbounds [[CAP_TMAIN_TY]], [[CAP_TMAIN_TY]]* %{{.+}}, i{{[0-9]+}} 0, i{{[0-9]+}} {{[0-9]+}} +// CHECK: [[VAR1_REF:%.+]] = load [[S_INT_TY]]*, [[S_INT_TY]]** [[VAR_PTR_REF:%.+]], +// For && reduction operation initial value of private variable is 1.0. +// CHECK: call {{.*}} [[S_INT_TY_CONSTR:@.+]]([[S_INT_TY]]* [[VAR1_PRIV]]) + +// CHECK: [[T_VAR1_PTR_REF:%.+]] = getelementptr inbounds [[CAP_TMAIN_TY]], [[CAP_TMAIN_TY]]* %{{.+}}, i{{[0-9]+}} 0, i{{[0-9]+}} {{[0-9]+}} +// CHECK: [[T_VAR1_REF:%.+]] = load i{{[0-9]+}}*, i{{[0-9]+}}** [[T_VAR1_PTR_REF]], +// For min reduction operation initial value of private variable is largest repesentable value. +// CHECK: store i{{[0-9]+}} 2147483647, i{{[0-9]+}}* [[T_VAR1_PRIV]], + +// CHECK: [[GTID_REF:%.+]] = load i{{[0-9]+}}*, i{{[0-9]+}}** [[GTID_ADDR_ADDR]] +// CHECK: [[GTID:%.+]] = load i{{[0-9]+}}, i{{[0-9]+}}* [[GTID_REF]] +// CHECK: call i32 @__kmpc_cancel_barrier(%{{.+}}* [[IMPLICIT_BARRIER_LOC]], i{{[0-9]+}} [[GTID]]) + +// Skip checks for internal operations. + +// void *RedList[] = {[0], ..., [-1]}; + +// CHECK: [[T_VAR_PRIV_REF:%.+]] = getelementptr inbounds [4 x i8*], [4 x i8*]* [[RED_LIST]], i32 0, i32 0 +// CHECK: [[BITCAST:%.+]] = bitcast i{{[0-9]+}}* [[T_VAR_PRIV]] to i8* +// CHECK: store i8* [[BITCAST]], i8** [[T_VAR_PRIV_REF]], +// CHECK: [[VAR_PRIV_REF:%.+]] = getelementptr inbounds [4 x i8*], [4 x i8*]* [[RED_LIST]], i32 0, i32 1 +// CHECK: [[BITCAST:%.+]] = bitcast [[S_INT_TY]]* [[VAR_PRIV]] to i8* +// CHECK: store i8* [[BITCAST]], i8** [[VAR_PRIV_REF]], +// CHECK: [[VAR1_PRIV_REF:%.+]] = getelementptr inbounds [4 x i8*], [4 x i8*]* [[RED_LIST]], i32 0, i32 2 +// CHECK: [[BITCAST:%.+]] = bitcast [[S_INT_TY]]* [[VAR1_PRIV]] to i8* +// CHECK: store i8* [[BITCAST]], i8** [[VAR1_PRIV_REF]], +// CHECK: [[T_VAR1_PRIV_REF:%.+]] = getelementptr inbounds [4 x i8*], [4 x i8*]* [[RED_LIST]], i32 0, i32 3 +// CHECK: [[BITCAST:%.+]] = bitcast i{{[0-9]+}}* [[T_VAR1_PRIV]] to i8* +// CHECK: store i8* [[BITCAST]], i8** [[T_VAR1_PRIV_REF]], + +// res = __kmpc_reduce_nowait(, , , sizeof(RedList), RedList, reduce_func, &); + +// CHECK: [[BITCAST:%.+]] = bitcast [4 x i8*]* [[RED_LIST]] to i8* +// CHECK: [[RES:%.+]] = call i32 @__kmpc_reduce_nowait(%{{.+}}* [[REDUCTION_LOC]], i32 [[GTID]], i32 4, i64 32, i8* [[BITCAST]], void (i8*, i8*)* [[REDUCTION_FUNC:@.+]], [8 x i32]* [[REDUCTION_LOCK]]) + +// switch(res) +// CHECK: switch i32 [[RES]], label %[[RED_DONE:.+]] [ +// CHECK: i32 1, label %[[CASE1:.+]] +// CHECK: i32 2, label %[[CASE2:.+]] +// CHECK: ] + +// case 1: +// t_var += t_var_reduction; +// CHECK: [[T_VAR_VAL:%.+]] = load i{{[0-9]+}}, i{{[0-9]+}}* [[T_VAR_REF]], +// CHECK: [[T_VAR_PRIV_VAL:%.+]] = load i{{[0-9]+}}, i{{[0-9]+}}* [[T_VAR_PRIV]], +// CHECK: [[UP:%.+]] = add nsw i{{[0-9]+}} [[T_VAR_VAL]], [[T_VAR_PRIV_VAL]] +// CHECK: store i{{[0-9]+}} [[UP]], i{{[0-9]+}}* [[T_VAR_REF]], + +// var = var.operator &(var_reduction); +// CHECK: [[UP:%.+]] = call dereferenceable(4) [[S_INT_TY]]* @{{.+}}([[S_INT_TY]]* [[VAR_REF]], [[S_INT_TY]]* dereferenceable(4) [[VAR_PRIV]]) +// CHECK: [[BC1:%.+]] = bitcast [[S_INT_TY]]* [[VAR_REF]] to i8* +// CHECK: [[BC2:%.+]] = bitcast [[S_INT_TY]]* [[UP]] to i8* +// CHECK: call void @llvm.memcpy.p0i8.p0i8.i64(i8* [[BC1]], i8* [[BC2]], i64 4, i32 4, i1 false) + +// var1 = var1.operator &&(var1_reduction); +// CHECK: [[TO_INT:%.+]] = call i{{[0-9]+}} @{{.+}}([[S_INT_TY]]* [[VAR1_REF]]) +// CHECK: [[VAR1_BOOL:%.+]] = icmp ne i{{[0-9]+}} [[TO_INT]], 0 +// CHECK: br i1 [[VAR1_BOOL]], label %[[TRUE:.+]], label %[[FALSE:.+]] +// CHECK: [[TRUE]] +// CHECK: [[TO_INT:%.+]] = call i{{[0-9]+}} @{{.+}}([[S_INT_TY]]* [[VAR1_PRIV]]) +// CHECK: [[VAR1_REDUCTION_BOOL:%.+]] = icmp ne i{{[0-9]+}} [[TO_INT]], 0 +// CHECK: br i1 [[VAR1_REDUCTION_BOOL]], label %[[TRUE2:.+]], label %[[FALSE2:.+]] +// CHECK: [[TRUE2]] +// CHECK: br label %[[END2:.+]] +// CHECK: [[FALSE2]] +// CHECK: br label %[[END2]] +// CHECK: [[END2]] +// CHECK: [[COND_LVALUE:%.+]] = phi [[S_INT_TY]]* [ [[VAR1_REF]], %[[TRUE2]] ], [ [[VAR1_PRIV]], %[[FALSE2]] ] +// CHECK: [[BC1:%.+]] = bitcast [[S_INT_TY]]* [[VAR1_REF]] to i8* +// CHECK: [[BC2:%.+]] = bitcast [[S_INT_TY]]* [[COND_LVALUE]] to i8* +// CHECK: call void @llvm.memcpy.p0i8.p0i8.i64(i8* [[BC1]], i8* [[BC2]], i64 4, i32 4, i1 false) + +// t_var1 = min(t_var1, t_var1_reduction); +// CHECK: [[T_VAR1_VAL:%.+]] = load i{{[0-9]+}}, i{{[0-9]+}}* [[T_VAR1_REF]], +// CHECK: [[T_VAR1_PRIV_VAL:%.+]] = load i{{[0-9]+}}, i{{[0-9]+}}* [[T_VAR1_PRIV]], +// CHECK: [[CMP:%.+]] = icmp slt i{{[0-9]+}} [[T_VAR1_VAL]], [[T_VAR1_PRIV_VAL]] +// CHECK: [[UP:%.+]] = zext i1 [[CMP]] to i{{[0-9]+}} +// CHECK: store i{{[0-9]+}} [[UP]], i{{[0-9]+}}* [[T_VAR1_REF]], + +// __kmpc_end_reduce_nowait(, , &); +// CHECK: call void @__kmpc_end_reduce_nowait(%{{.+}}* [[REDUCTION_LOC]], i32 [[GTID]], [8 x i32]* [[REDUCTION_LOCK]]) + +// break; +// CHECK: br label %[[RED_DONE]] + +// case 2: +// t_var += t_var_reduction; +// CHECK: [[T_VAR_PRIV_VAL:%.+]] = load i{{[0-9]+}}, i{{[0-9]+}}* [[T_VAR_PRIV]] +// CHECK: atomicrmw add i32* [[T_VAR_REF]], i32 [[T_VAR_PRIV_VAL]] monotonic + +// var = var.operator &(var_reduction); +// CHECK: call void @__kmpc_critical( +// CHECK: [[UP:%.+]] = call dereferenceable(4) [[S_INT_TY]]* @{{.+}}([[S_INT_TY]]* [[VAR_REF]], [[S_INT_TY]]* dereferenceable(4) [[VAR_PRIV]]) +// CHECK: [[BC1:%.+]] = bitcast [[S_INT_TY]]* [[VAR_REF]] to i8* +// CHECK: [[BC2:%.+]] = bitcast [[S_INT_TY]]* [[UP]] to i8* +// CHECK: call void @llvm.memcpy.p0i8.p0i8.i64(i8* [[BC1]], i8* [[BC2]], i64 4, i32 4, i1 false) +// CHECK: call void @__kmpc_end_critical( + +// var1 = var1.operator &&(var1_reduction); +// CHECK: call void @__kmpc_critical( +// CHECK: [[TO_INT:%.+]] = call i{{[0-9]+}} @{{.+}}([[S_INT_TY]]* [[VAR1_REF]]) +// CHECK: [[VAR1_BOOL:%.+]] = icmp ne i{{[0-9]+}} [[TO_INT]], 0 +// CHECK: br i1 [[VAR1_BOOL]], label %[[TRUE:.+]], label %[[FALSE:.+]] +// CHECK: [[TRUE]] +// CHECK: [[TO_INT:%.+]] = call i{{[0-9]+}} @{{.+}}([[S_INT_TY]]* [[VAR1_PRIV]]) +// CHECK: [[VAR1_REDUCTION_BOOL:%.+]] = icmp ne i{{[0-9]+}} [[TO_INT]], 0 +// CHECK: br i1 [[VAR1_REDUCTION_BOOL]], label %[[TRUE2:.+]], label %[[FALSE2:.+]] +// CHECK: [[TRUE2]] +// CHECK: br label %[[END2:.+]] +// CHECK: [[FALSE2]] +// CHECK: br label %[[END2]] +// CHECK: [[END2]] +// CHECK: [[COND_LVALUE:%.+]] = phi [[S_INT_TY]]* [ [[VAR1_REF]], %[[TRUE2]] ], [ [[VAR1_PRIV]], %[[FALSE2]] ] +// CHECK: [[BC1:%.+]] = bitcast [[S_INT_TY]]* [[VAR1_REF]] to i8* +// CHECK: [[BC2:%.+]] = bitcast [[S_INT_TY]]* [[COND_LVALUE]] to i8* +// CHECK: call void @llvm.memcpy.p0i8.p0i8.i64(i8* [[BC1]], i8* [[BC2]], i64 4, i32 4, i1 false) +// CHECK: call void @__kmpc_end_critical( + +// t_var1 = min(t_var1, t_var1_reduction); +// CHECK: [[T_VAR1_PRIV_VAL:%.+]] = load i{{[0-9]+}}, i{{[0-9]+}}* [[T_VAR1_PRIV]] +// CHECK: atomicrmw min i32* [[T_VAR1_REF]], i32 [[T_VAR1_PRIV_VAL]] monotonic + +// break; +// CHECK: br label %[[RED_DONE]] +// CHECK: [[RED_DONE]] +// CHECK: call i32 @__kmpc_cancel_barrier(%{{.+}}* [[IMPLICIT_BARRIER_LOC]], i{{[0-9]+}} [[GTID]]) + +// CHECK-DAG: call {{.*}} [[S_INT_TY_DESTR]]([[S_INT_TY]]* [[VAR_PRIV]]) +// CHECK-DAG: call {{.*}} [[S_INT_TY_DESTR]]([[S_INT_TY]]* +// CHECK: ret void + +// void reduce_func(void *lhs[], void *rhs[]) { +// *(Type0*)lhs[0] = ReductionOperation0(*(Type0*)lhs[0], *(Type0*)rhs[0]); +// ... +// *(Type-1*)lhs[-1] = ReductionOperation-1(*(Type-1*)lhs[-1], +// *(Type-1*)rhs[-1]); +// } +// CHECK: define internal void [[REDUCTION_FUNC]](i8*, i8*) +// t_var_lhs = (i{{[0-9]+}}*)lhs[0]; +// CHECK: [[T_VAR_RHS_REF:%.+]] = getelementptr inbounds [4 x i8*], [4 x i8*]* [[RED_LIST_RHS:%.+]], i32 0, i32 0 +// CHECK: [[T_VAR_RHS_VOID:%.+]] = load i8*, i8** [[T_VAR_RHS_REF]], +// CHECK: [[T_VAR_RHS:%.+]] = bitcast i8* [[T_VAR_RHS_VOID]] to i{{[0-9]+}}* +// t_var_rhs = (i{{[0-9]+}}*)rhs[0]; +// CHECK: [[T_VAR_LHS_REF:%.+]] = getelementptr inbounds [4 x i8*], [4 x i8*]* [[RED_LIST_LHS:%.+]], i32 0, i32 0 +// CHECK: [[T_VAR_LHS_VOID:%.+]] = load i8*, i8** [[T_VAR_LHS_REF]], +// CHECK: [[T_VAR_LHS:%.+]] = bitcast i8* [[T_VAR_LHS_VOID]] to i{{[0-9]+}}* + +// var_lhs = (S*)lhs[1]; +// CHECK: [[VAR_RHS_REF:%.+]] = getelementptr inbounds [4 x i8*], [4 x i8*]* [[RED_LIST_RHS]], i32 0, i32 1 +// CHECK: [[VAR_RHS_VOID:%.+]] = load i8*, i8** [[VAR_RHS_REF]], +// CHECK: [[VAR_RHS:%.+]] = bitcast i8* [[VAR_RHS_VOID]] to [[S_INT_TY]]* +// var_rhs = (S*)rhs[1]; +// CHECK: [[VAR_LHS_REF:%.+]] = getelementptr inbounds [4 x i8*], [4 x i8*]* [[RED_LIST_LHS]], i32 0, i32 1 +// CHECK: [[VAR_LHS_VOID:%.+]] = load i8*, i8** [[VAR_LHS_REF]], +// CHECK: [[VAR_LHS:%.+]] = bitcast i8* [[VAR_LHS_VOID]] to [[S_INT_TY]]* + +// var1_lhs = (S*)lhs[2]; +// CHECK: [[VAR1_RHS_REF:%.+]] = getelementptr inbounds [4 x i8*], [4 x i8*]* [[RED_LIST_RHS]], i32 0, i32 2 +// CHECK: [[VAR1_RHS_VOID:%.+]] = load i8*, i8** [[VAR1_RHS_REF]], +// CHECK: [[VAR1_RHS:%.+]] = bitcast i8* [[VAR1_RHS_VOID]] to [[S_INT_TY]]* +// var1_rhs = (S*)rhs[2]; +// CHECK: [[VAR1_LHS_REF:%.+]] = getelementptr inbounds [4 x i8*], [4 x i8*]* [[RED_LIST_LHS]], i32 0, i32 2 +// CHECK: [[VAR1_LHS_VOID:%.+]] = load i8*, i8** [[VAR1_LHS_REF]], +// CHECK: [[VAR1_LHS:%.+]] = bitcast i8* [[VAR1_LHS_VOID]] to [[S_INT_TY]]* + +// t_var1_lhs = (i{{[0-9]+}}*)lhs[3]; +// CHECK: [[T_VAR1_RHS_REF:%.+]] = getelementptr inbounds [4 x i8*], [4 x i8*]* [[RED_LIST_RHS]], i32 0, i32 3 +// CHECK: [[T_VAR1_RHS_VOID:%.+]] = load i8*, i8** [[T_VAR1_RHS_REF]], +// CHECK: [[T_VAR1_RHS:%.+]] = bitcast i8* [[T_VAR1_RHS_VOID]] to i{{[0-9]+}}* +// t_var1_rhs = (i{{[0-9]+}}*)rhs[3]; +// CHECK: [[T_VAR1_LHS_REF:%.+]] = getelementptr inbounds [4 x i8*], [4 x i8*]* [[RED_LIST_LHS]], i32 0, i32 3 +// CHECK: [[T_VAR1_LHS_VOID:%.+]] = load i8*, i8** [[T_VAR1_LHS_REF]], +// CHECK: [[T_VAR1_LHS:%.+]] = bitcast i8* [[T_VAR1_LHS_VOID]] to i{{[0-9]+}}* + +// t_var_lhs += t_var_rhs; +// CHECK: [[T_VAR_LHS_VAL:%.+]] = load i{{[0-9]+}}, i{{[0-9]+}}* [[T_VAR_LHS]], +// CHECK: [[T_VAR_RHS_VAL:%.+]] = load i{{[0-9]+}}, i{{[0-9]+}}* [[T_VAR_RHS]], +// CHECK: [[UP:%.+]] = add nsw i{{[0-9]+}} [[T_VAR_LHS_VAL]], [[T_VAR_RHS_VAL]] +// CHECK: store i{{[0-9]+}} [[UP]], i{{[0-9]+}}* [[T_VAR_LHS]], + +// var_lhs = var_lhs.operator &(var_rhs); +// CHECK: [[UP:%.+]] = call dereferenceable(4) [[S_INT_TY]]* @{{.+}}([[S_INT_TY]]* [[VAR_LHS]], [[S_INT_TY]]* dereferenceable(4) [[VAR_RHS]]) +// CHECK: [[BC1:%.+]] = bitcast [[S_INT_TY]]* [[VAR_LHS]] to i8* +// CHECK: [[BC2:%.+]] = bitcast [[S_INT_TY]]* [[UP]] to i8* +// CHECK: call void @llvm.memcpy.p0i8.p0i8.i64(i8* [[BC1]], i8* [[BC2]], i64 4, i32 4, i1 false) + +// var1_lhs = var1_lhs.operator &&(var1_rhs); +// CHECK: [[TO_INT:%.+]] = call i{{[0-9]+}} @{{.+}}([[S_INT_TY]]* [[VAR1_LHS]]) +// CHECK: [[VAR1_BOOL:%.+]] = icmp ne i{{[0-9]+}} [[TO_INT]], 0 +// CHECK: br i1 [[VAR1_BOOL]], label %[[TRUE:.+]], label %[[FALSE:.+]] +// CHECK: [[TRUE]] +// CHECK: [[TO_INT:%.+]] = call i{{[0-9]+}} @{{.+}}([[S_INT_TY]]* [[VAR1_RHS]]) +// CHECK: [[VAR1_REDUCTION_BOOL:%.+]] = icmp ne i{{[0-9]+}} [[TO_INT]], 0 +// CHECK: br i1 [[VAR1_REDUCTION_BOOL]], label %[[TRUE2:.+]], label %[[FALSE2:.+]] +// CHECK: [[TRUE2]] +// CHECK: br label %[[END2:.+]] +// CHECK: [[FALSE2]] +// CHECK: br label %[[END2]] +// CHECK: [[END2]] +// CHECK: [[COND_LVALUE:%.+]] = phi [[S_INT_TY]]* [ [[VAR1_LHS]], %[[TRUE2]] ], [ [[VAR1_RHS]], %[[FALSE2]] ] +// CHECK: [[BC1:%.+]] = bitcast [[S_INT_TY]]* [[VAR1_LHS]] to i8* +// CHECK: [[BC2:%.+]] = bitcast [[S_INT_TY]]* [[COND_LVALUE]] to i8* +// CHECK: call void @llvm.memcpy.p0i8.p0i8.i64(i8* [[BC1]], i8* [[BC2]], i64 4, i32 4, i1 false) + +// t_var1_lhs = min(t_var1_lhs, t_var1_rhs); +// CHECK: [[T_VAR1_LHS_VAL:%.+]] = load i{{[0-9]+}}, i{{[0-9]+}}* [[T_VAR1_LHS]], +// CHECK: [[T_VAR1_RHS_VAL:%.+]] = load i{{[0-9]+}}, i{{[0-9]+}}* [[T_VAR1_RHS]], +// CHECK: [[CMP:%.+]] = icmp slt i{{[0-9]+}} [[T_VAR1_LHS_VAL]], [[T_VAR1_RHS_VAL]] +// CHECK: [[UP:%.+]] = zext i1 [[CMP]] to i{{[0-9]+}} +// CHECK: store i{{[0-9]+}} [[UP]], i{{[0-9]+}}* [[T_VAR1_LHS]], +// CHECK: ret void + +#endif + Index: test/OpenMP/parallel_reduction_messages.cpp =================================================================== --- test/OpenMP/parallel_reduction_messages.cpp +++ test/OpenMP/parallel_reduction_messages.cpp @@ -11,7 +11,7 @@ extern S1 a; class S2 { mutable int a; - S2 &operator+=(const S2 &arg) { return (*this); } + S2 &operator+(const S2 &arg) { return (*this); } // expected-note 4 {{implicitly declared private here}} public: S2() : a(0) {} @@ -28,17 +28,17 @@ public: S3() : a(0) {} S3(const S3 &s3) : a(s3.a) {} - S3 operator+=(const S3 &arg1) { return arg1; } + S3 operator+(const S3 &arg1) { return arg1; } }; -int operator+=(const S3 &arg1, const S3 &arg2) { return 5; } +int operator+(const S3 &arg1, const S3 &arg2) { return 5; } S3 c; // expected-note 2 {{'c' defined here}} const S3 ca[5]; // expected-note 2 {{'ca' defined here}} extern const int f; // expected-note 4 {{'f' declared here}} -class S4 { // expected-note {{'S4' declared here}} +class S4 { int a; - S4(); + S4(); // expected-note {{implicitly declared private here}} S4(const S4 &s4); - S4 &operator+=(const S4 &arg) { return (*this); } + S4 &operator+(const S4 &arg) { return (*this); } public: S4(int v) : a(v) {} @@ -46,26 +46,26 @@ S4 &operator&=(S4 &arg1, S4 &arg2) { return arg1; } class S5 { int a; - S5() : a(0) {} + S5() : a(0) {} // expected-note {{implicitly declared private here}} S5(const S5 &s5) : a(s5.a) {} - S5 &operator+=(const S5 &arg); + S5 &operator+(const S5 &arg); public: S5(int v) : a(v) {} }; -class S6 { +class S6 { // expected-note 2 {{candidate function (the implicit copy assignment operator) not viable: no known conversion from 'int' to 'const S6' for 1st argument}} int a; public: S6() : a(6) {} operator int() { return 6; } -} o; // expected-note 2 {{'o' defined here}} +} o; S3 h, k; #pragma omp threadprivate(h) // expected-note 2 {{defined as threadprivate or thread local}} template // expected-note {{declared here}} -T tmain(T argc) { // expected-note 2 {{'argc' defined here}} +T tmain(T argc) { const T d = T(); // expected-note 4 {{'d' defined here}} const T da[5] = {T()}; // expected-note 2 {{'da' defined here}} T qa[5] = {T()}; @@ -74,7 +74,7 @@ S3 &p = k; // expected-note 2 {{'p' defined here}} const T &r = da[(int)i]; // expected-note 2 {{'r' defined here}} T &q = qa[(int)i]; // expected-note 2 {{'q' defined here}} - T fl; // expected-note {{'fl' defined here}} + T fl; #pragma omp parallel reduction // expected-error {{expected '(' after 'reduction'}} foo(); #pragma omp parallel reduction + // expected-error {{expected '(' after 'reduction'}} expected-warning {{extra tokens at the end of '#pragma omp parallel' are ignored}} @@ -89,9 +89,9 @@ foo(); #pragma omp parallel reduction(\) // expected-error {{expected unqualified-id}} expected-warning {{missing ':' after reduction identifier - ignoring}} foo(); -#pragma omp parallel reduction(& : argc // expected-error {{expected ')'}} expected-note {{to match this '('}} expected-error {{variable of type 'float' is not valid for specified reduction operation}} +#pragma omp parallel reduction(& : argc // expected-error {{expected ')'}} expected-note {{to match this '('}} expected-error {{invalid operands to binary expression ('float' and 'float')}} foo(); -#pragma omp parallel reduction(| : argc, // expected-error {{expected expression}} expected-error {{expected ')'}} expected-note {{to match this '('}} expected-error {{variable of type 'float' is not valid for specified reduction operation}} +#pragma omp parallel reduction(| : argc, // expected-error {{expected expression}} expected-error {{expected ')'}} expected-note {{to match this '('}} expected-error {{invalid operands to binary expression ('float' and 'float')}} foo(); #pragma omp parallel reduction(|| : argc ? i : argc) // expected-error 2 {{expected variable name}} foo(); @@ -101,7 +101,7 @@ foo(); #pragma omp parallel reduction(^ : T) // expected-error {{'T' does not refer to a value}} foo(); -#pragma omp parallel reduction(+ : a, b, c, d, f) // expected-error {{reduction variable with incomplete type 'S1'}} expected-error 3 {{const-qualified variable cannot be reduction}} +#pragma omp parallel reduction(+ : a, b, c, d, f) // expected-error {{reduction variable with incomplete type 'S1'}} expected-error 3 {{const-qualified variable cannot be reduction}} expected-error 3 {{'operator+' is a private member of 'S2'}} foo(); #pragma omp parallel reduction(min : a, b, c, d, f) // expected-error {{reduction variable with incomplete type 'S1'}} expected-error 2 {{arguments of OpenMP clause 'reduction' for 'min' or 'max' must be of arithmetic type}} expected-error 3 {{const-qualified variable cannot be reduction}} foo(); @@ -113,7 +113,7 @@ foo(); #pragma omp parallel reduction(- : da) // expected-error {{a reduction variable with array type 'const int [5]'}} expected-error {{a reduction variable with array type 'const float [5]'}} foo(); -#pragma omp parallel reduction(^ : fl) // expected-error {{variable of type 'float' is not valid for specified reduction operation}} +#pragma omp parallel reduction(^ : fl) // expected-error {{invalid operands to binary expression ('float' and 'float')}} foo(); #pragma omp parallel reduction(&& : S2::S2s) foo(); @@ -121,7 +121,7 @@ foo(); #pragma omp parallel reduction(+ : h, k) // expected-error {{threadprivate or thread local variable cannot be reduction}} foo(); -#pragma omp parallel reduction(+ : o) // expected-error {{variable of type 'class S6' is not valid for specified reduction operation}} +#pragma omp parallel reduction(+ : o) // expected-error {{no viable overloaded '='}} foo(); #pragma omp parallel private(i), reduction(+ : j), reduction(+ : q) // expected-error 4 {{argument of OpenMP clause 'reduction' must reference the same object in all threads}} foo(); @@ -154,14 +154,14 @@ const int d = 5; // expected-note 2 {{'d' defined here}} const int da[5] = {0}; // expected-note {{'da' defined here}} int qa[5] = {0}; - S4 e(4); // expected-note {{'e' defined here}} - S5 g(5); // expected-note {{'g' defined here}} + S4 e(4); + S5 g(5); int i; int &j = i; // expected-note 2 {{'j' defined here}} S3 &p = k; // expected-note 2 {{'p' defined here}} const int &r = da[i]; // expected-note {{'r' defined here}} int &q = qa[i]; // expected-note {{'q' defined here}} - float fl; // expected-note {{'fl' defined here}} + float fl; #pragma omp parallel reduction // expected-error {{expected '(' after 'reduction'}} foo(); #pragma omp parallel reduction + // expected-error {{expected '(' after 'reduction'}} expected-warning {{extra tokens at the end of '#pragma omp parallel' are ignored}} @@ -188,7 +188,7 @@ foo(); #pragma omp parallel reduction(^ : S1) // expected-error {{'S1' does not refer to a value}} foo(); -#pragma omp parallel reduction(+ : a, b, c, d, f) // expected-error {{reduction variable with incomplete type 'S1'}} expected-error 2 {{const-qualified variable cannot be reduction}} +#pragma omp parallel reduction(+ : a, b, c, d, f) // expected-error {{reduction variable with incomplete type 'S1'}} expected-error 2 {{const-qualified variable cannot be reduction}} expected-error {{'operator+' is a private member of 'S2'}} foo(); #pragma omp parallel reduction(min : a, b, c, d, f) // expected-error {{reduction variable with incomplete type 'S1'}} expected-error 2 {{arguments of OpenMP clause 'reduction' for 'min' or 'max' must be of arithmetic type}} expected-error 2 {{const-qualified variable cannot be reduction}} foo(); @@ -200,17 +200,17 @@ foo(); #pragma omp parallel reduction(- : da) // expected-error {{a reduction variable with array type 'const int [5]'}} foo(); -#pragma omp parallel reduction(^ : fl) // expected-error {{variable of type 'float' is not valid for specified reduction operation}} +#pragma omp parallel reduction(^ : fl) // expected-error {{invalid operands to binary expression ('float' and 'float')}} foo(); #pragma omp parallel reduction(&& : S2::S2s) foo(); #pragma omp parallel reduction(&& : S2::S2sc) // expected-error {{const-qualified variable cannot be reduction}} foo(); -#pragma omp parallel reduction(& : e, g) // expected-error {{reduction variable must have an accessible, unambiguous default constructor}} expected-error {{variable of type 'S5' is not valid for specified reduction operation}} +#pragma omp parallel reduction(& : e, g) // expected-error {{calling a private constructor of class 'S4'}} expected-error {{nvalid operands to binary expression ('S4' and 'S4')}} expected-error {{calling a private constructor of class 'S5'}} expected-error {{invalid operands to binary expression ('S5' and 'S5')}} foo(); #pragma omp parallel reduction(+ : h, k) // expected-error {{threadprivate or thread local variable cannot be reduction}} foo(); -#pragma omp parallel reduction(+ : o) // expected-error {{variable of type 'class S6' is not valid for specified reduction operation}} +#pragma omp parallel reduction(+ : o) // expected-error {{no viable overloaded '='}} foo(); #pragma omp parallel private(i), reduction(+ : j), reduction(+ : q) // expected-error 2 {{argument of OpenMP clause 'reduction' must reference the same object in all threads}} foo(); Index: test/OpenMP/parallel_sections_reduction_messages.cpp =================================================================== --- test/OpenMP/parallel_sections_reduction_messages.cpp +++ test/OpenMP/parallel_sections_reduction_messages.cpp @@ -11,7 +11,7 @@ extern S1 a; class S2 { mutable int a; - S2 &operator+=(const S2 &arg) { return (*this); } + S2 &operator+(const S2 &arg) { return (*this); } // expected-note 4 {{implicitly declared private here}} public: S2() : a(0) {} @@ -28,17 +28,17 @@ public: S3() : a(0) {} S3(const S3 &s3) : a(s3.a) {} - S3 operator+=(const S3 &arg1) { return arg1; } + S3 operator+(const S3 &arg1) { return arg1; } }; -int operator+=(const S3 &arg1, const S3 &arg2) { return 5; } +int operator+(const S3 &arg1, const S3 &arg2) { return 5; } S3 c; // expected-note 2 {{'c' defined here}} const S3 ca[5]; // expected-note 2 {{'ca' defined here}} extern const int f; // expected-note 4 {{'f' declared here}} -class S4 { // expected-note {{'S4' declared here}} +class S4 { int a; - S4(); + S4(); // expected-note {{implicitly declared private here}} S4(const S4 &s4); - S4 &operator+=(const S4 &arg) { return (*this); } + S4 &operator+(const S4 &arg) { return (*this); } public: S4(int v) : a(v) {} @@ -46,26 +46,26 @@ S4 &operator&=(S4 &arg1, S4 &arg2) { return arg1; } class S5 { int a; - S5() : a(0) {} + S5() : a(0) {} // expected-note {{implicitly declared private here}} S5(const S5 &s5) : a(s5.a) {} - S5 &operator+=(const S5 &arg); + S5 &operator+(const S5 &arg); public: S5(int v) : a(v) {} }; -class S6 { +class S6 { // expected-note 2 {{candidate function (the implicit copy assignment operator) not viable: no known conversion from 'int' to 'const S6' for 1st argument}} int a; public: S6() : a(6) {} operator int() { return 6; } -} o; // expected-note 2 {{'o' defined here}} +} o; S3 h, k; #pragma omp threadprivate(h) // expected-note 2 {{defined as threadprivate or thread local}} template // expected-note {{declared here}} -T tmain(T argc) { // expected-note 2 {{'argc' defined here}} +T tmain(T argc) { const T d = T(); // expected-note 4 {{'d' defined here}} const T da[5] = {T()}; // expected-note 2 {{'da' defined here}} T qa[5] = {T()}; @@ -74,7 +74,7 @@ S3 &p = k; // expected-note 2 {{'p' defined here}} const T &r = da[(int)i]; // expected-note 2 {{'r' defined here}} T &q = qa[(int)i]; // expected-note 2 {{'q' defined here}} - T fl; // expected-note {{'fl' defined here}} + T fl; #pragma omp parallel sections reduction // expected-error {{expected '(' after 'reduction'}} { foo(); @@ -103,11 +103,11 @@ { foo(); } -#pragma omp parallel sections reduction(& : argc // expected-error {{expected ')'}} expected-note {{to match this '('}} expected-error {{variable of type 'float' is not valid for specified reduction operation}} +#pragma omp parallel sections reduction(& : argc // expected-error {{expected ')'}} expected-note {{to match this '('}} expected-error {{invalid operands to binary expression ('float' and 'float')}} { foo(); } -#pragma omp parallel sections reduction(| : argc, // expected-error {{expected expression}} expected-error {{expected ')'}} expected-note {{to match this '('}} expected-error {{variable of type 'float' is not valid for specified reduction operation}} +#pragma omp parallel sections reduction(| : argc, // expected-error {{expected expression}} expected-error {{expected ')'}} expected-note {{to match this '('}} expected-error {{invalid operands to binary expression ('float' and 'float')}} { foo(); } @@ -127,7 +127,7 @@ { foo(); } -#pragma omp parallel sections reduction(+ : a, b, c, d, f) // expected-error {{reduction variable with incomplete type 'S1'}} expected-error 3 {{const-qualified variable cannot be reduction}} +#pragma omp parallel sections reduction(+ : a, b, c, d, f) // expected-error {{reduction variable with incomplete type 'S1'}} expected-error 3 {{const-qualified variable cannot be reduction}} expected-error 3 {{'operator+' is a private member of 'S2'}} { foo(); } @@ -151,7 +151,7 @@ { foo(); } -#pragma omp parallel sections reduction(^ : fl) // expected-error {{variable of type 'float' is not valid for specified reduction operation}} +#pragma omp parallel sections reduction(^ : fl) // expected-error {{invalid operands to binary expression ('float' and 'float')}} { foo(); } @@ -167,7 +167,7 @@ { foo(); } -#pragma omp parallel sections reduction(+ : o) // expected-error {{variable of type 'class S6' is not valid for specified reduction operation}} +#pragma omp parallel sections reduction(+ : o) // expected-error {{no viable overloaded '='}} { foo(); } @@ -212,14 +212,14 @@ const int d = 5; // expected-note 2 {{'d' defined here}} const int da[5] = {0}; // expected-note {{'da' defined here}} int qa[5] = {0}; - S4 e(4); // expected-note {{'e' defined here}} - S5 g(5); // expected-note {{'g' defined here}} + S4 e(4); + S5 g(5); int i; int &j = i; // expected-note 2 {{'j' defined here}} S3 &p = k; // expected-note 2 {{'p' defined here}} const int &r = da[i]; // expected-note {{'r' defined here}} int &q = qa[i]; // expected-note {{'q' defined here}} - float fl; // expected-note {{'fl' defined here}} + float fl; #pragma omp parallel sections reduction // expected-error {{expected '(' after 'reduction'}} { foo(); @@ -272,7 +272,7 @@ { foo(); } -#pragma omp parallel sections reduction(+ : a, b, c, d, f) // expected-error {{reduction variable with incomplete type 'S1'}} expected-error 2 {{const-qualified variable cannot be reduction}} +#pragma omp parallel sections reduction(+ : a, b, c, d, f) // expected-error {{reduction variable with incomplete type 'S1'}} expected-error 2 {{const-qualified variable cannot be reduction}} expected-error {{'operator+' is a private member of 'S2'}} { foo(); } @@ -296,7 +296,7 @@ { foo(); } -#pragma omp parallel sections reduction(^ : fl) // expected-error {{variable of type 'float' is not valid for specified reduction operation}} +#pragma omp parallel sections reduction(^ : fl) // expected-error {{invalid operands to binary expression ('float' and 'float')}} { foo(); } @@ -308,7 +308,7 @@ { foo(); } -#pragma omp parallel sections reduction(& : e, g) // expected-error {{reduction variable must have an accessible, unambiguous default constructor}} expected-error {{variable of type 'S5' is not valid for specified reduction operation}} +#pragma omp parallel sections reduction(& : e, g) // expected-error {{calling a private constructor of class 'S4'}} expected-error {{invalid operands to binary expression ('S4' and 'S4')}} expected-error {{calling a private constructor of class 'S5'}} expected-error {{invalid operands to binary expression ('S5' and 'S5')}} { foo(); } @@ -316,7 +316,7 @@ { foo(); } -#pragma omp parallel sections reduction(+ : o) // expected-error {{variable of type 'class S6' is not valid for specified reduction operation}} +#pragma omp parallel sections reduction(+ : o) // expected-error {{no viable overloaded '='}} { foo(); } Index: test/OpenMP/sections_codegen.cpp =================================================================== --- test/OpenMP/sections_codegen.cpp +++ test/OpenMP/sections_codegen.cpp @@ -96,6 +96,7 @@ // CHECK-NEXT: br label %[[END]] // CHECK: [[END]] // CHECK-NEXT: call i32 @__kmpc_cancel_barrier(%{{.+}}* [[IMPLICIT_BARRIER_SINGLE_LOC]], +// CHECK-NEXT: call i32 @__kmpc_cancel_barrier( // CHECK-NEXT: ret // CHECK: [[TERM_LPAD]] // CHECK: call void @__clang_call_terminate(i8* Index: test/OpenMP/sections_reduction_messages.cpp =================================================================== --- test/OpenMP/sections_reduction_messages.cpp +++ test/OpenMP/sections_reduction_messages.cpp @@ -1,4 +1,4 @@ -// RUN: %clang_cc1 -verify -fopenmp=libiomp5 -ferror-limit 100 -o - %s +// RUN: %clang_cc1 -verify -fopenmp=libiomp5 -ferror-limit 150 -o - %s void foo() { } @@ -11,7 +11,7 @@ extern S1 a; class S2 { mutable int a; - S2 &operator+=(const S2 &arg) { return (*this); } + S2 &operator+(const S2 &arg) { return (*this); } // expected-note 4 {{implicitly declared private here}} public: S2() : a(0) {} @@ -28,17 +28,17 @@ public: S3() : a(0) {} S3(const S3 &s3) : a(s3.a) {} - S3 operator+=(const S3 &arg1) { return arg1; } + S3 operator+(const S3 &arg1) { return arg1; } }; -int operator+=(const S3 &arg1, const S3 &arg2) { return 5; } +int operator+(const S3 &arg1, const S3 &arg2) { return 5; } S3 c; // expected-note 2 {{'c' defined here}} const S3 ca[5]; // expected-note 2 {{'ca' defined here}} extern const int f; // expected-note 4 {{'f' declared here}} -class S4 { // expected-note {{'S4' declared here}} +class S4 { int a; - S4(); + S4(); // expected-note {{implicitly declared private here}} S4(const S4 &s4); - S4 &operator+=(const S4 &arg) { return (*this); } + S4 &operator+(const S4 &arg) { return (*this); } public: S4(int v) : a(v) {} @@ -46,26 +46,26 @@ S4 &operator&=(S4 &arg1, S4 &arg2) { return arg1; } class S5 { int a; - S5() : a(0) {} + S5() : a(0) {} // expected-note {{implicitly declared private here}} S5(const S5 &s5) : a(s5.a) {} - S5 &operator+=(const S5 &arg); + S5 &operator+(const S5 &arg); public: S5(int v) : a(v) {} }; -class S6 { +class S6 { // expected-note 2 {{candidate function (the implicit copy assignment operator) not viable: no known conversion from 'int' to 'const S6' for 1st argument}} int a; public: S6() : a(6) {} operator int() { return 6; } -} o; // expected-note 2 {{'o' defined here}} +} o; S3 h, k; #pragma omp threadprivate(h) // expected-note 2 {{defined as threadprivate or thread local}} template // expected-note {{declared here}} -T tmain(T argc) { // expected-note 2 {{'argc' defined here}} +T tmain(T argc) { const T d = T(); // expected-note 4 {{'d' defined here}} const T da[5] = {T()}; // expected-note 2 {{'da' defined here}} T qa[5] = {T()}; @@ -74,7 +74,7 @@ S3 &p = k; // expected-note 2 {{'p' defined here}} const T &r = da[(int)i]; // expected-note 2 {{'r' defined here}} T &q = qa[(int)i]; // expected-note 2 {{'q' defined here}} - T fl; // expected-note {{'fl' defined here}} + T fl; #pragma omp parallel #pragma omp sections reduction // expected-error {{expected '(' after 'reduction'}} { @@ -111,12 +111,12 @@ foo(); } #pragma omp parallel -#pragma omp sections reduction(& : argc // expected-error {{expected ')'}} expected-note {{to match this '('}} expected-error {{variable of type 'float' is not valid for specified reduction operation}} +#pragma omp sections reduction(& : argc // expected-error {{expected ')'}} expected-note {{to match this '('}} expected-error {{invalid operands to binary expression ('float' and 'float')}} { foo(); } #pragma omp parallel -#pragma omp sections reduction(| : argc, // expected-error {{expected expression}} expected-error {{expected ')'}} expected-note {{to match this '('}} expected-error {{variable of type 'float' is not valid for specified reduction operation}} +#pragma omp sections reduction(| : argc, // expected-error {{expected expression}} expected-error {{expected ')'}} expected-note {{to match this '('}} expected-error {{invalid operands to binary expression ('float' and 'float')}} { foo(); } @@ -141,7 +141,7 @@ foo(); } #pragma omp parallel -#pragma omp sections reduction(+ : a, b, c, d, f) // expected-error {{reduction variable with incomplete type 'S1'}} expected-error 3 {{const-qualified variable cannot be reduction}} +#pragma omp sections reduction(+ : a, b, c, d, f) // expected-error {{reduction variable with incomplete type 'S1'}} expected-error 3 {{const-qualified variable cannot be reduction}} expected-error 3 {{'operator+' is a private member of 'S2'}} { foo(); } @@ -171,7 +171,7 @@ foo(); } #pragma omp parallel -#pragma omp sections reduction(^ : fl) // expected-error {{variable of type 'float' is not valid for specified reduction operation}} +#pragma omp sections reduction(^ : fl) // expected-error {{invalid operands to binary expression ('float' and 'float')}} { foo(); } @@ -191,7 +191,7 @@ foo(); } #pragma omp parallel -#pragma omp sections reduction(+ : o) // expected-error {{variable of type 'class S6' is not valid for specified reduction operation}} +#pragma omp sections reduction(+ : o) // expected-error {{no viable overloaded '='}} { foo(); } @@ -239,14 +239,14 @@ const int d = 5; // expected-note 2 {{'d' defined here}} const int da[5] = {0}; // expected-note {{'da' defined here}} int qa[5] = {0}; - S4 e(4); // expected-note {{'e' defined here}} - S5 g(5); // expected-note {{'g' defined here}} + S4 e(4); + S5 g(5); int i; int &j = i; // expected-note 2 {{'j' defined here}} S3 &p = k; // expected-note 2 {{'p' defined here}} const int &r = da[i]; // expected-note {{'r' defined here}} int &q = qa[i]; // expected-note {{'q' defined here}} - float fl; // expected-note {{'fl' defined here}} + float fl; #pragma omp parallel #pragma omp sections reduction // expected-error {{expected '(' after 'reduction'}} { @@ -313,7 +313,7 @@ foo(); } #pragma omp parallel -#pragma omp sections reduction(+ : a, b, c, d, f) // expected-error {{reduction variable with incomplete type 'S1'}} expected-error 2 {{const-qualified variable cannot be reduction}} +#pragma omp sections reduction(+ : a, b, c, d, f) // expected-error {{reduction variable with incomplete type 'S1'}} expected-error 2 {{const-qualified variable cannot be reduction}} expected-error {{'operator+' is a private member of 'S2'}} { foo(); } @@ -343,7 +343,7 @@ foo(); } #pragma omp parallel -#pragma omp sections reduction(^ : fl) // expected-error {{variable of type 'float' is not valid for specified reduction operation}} +#pragma omp sections reduction(^ : fl) // expected-error {{invalid operands to binary expression ('float' and 'float')}} { foo(); } @@ -358,7 +358,7 @@ foo(); } #pragma omp parallel -#pragma omp sections reduction(& : e, g) // expected-error {{reduction variable must have an accessible, unambiguous default constructor}} expected-error {{variable of type 'S5' is not valid for specified reduction operation}} +#pragma omp sections reduction(& : e, g) // expected-error {{calling a private constructor of class 'S4'}} expected-error {{invalid operands to binary expression ('S4' and 'S4')}} expected-error {{calling a private constructor of class 'S5'}} expected-error {{invalid operands to binary expression ('S5' and 'S5')}} { foo(); } @@ -368,7 +368,7 @@ foo(); } #pragma omp parallel -#pragma omp sections reduction(+ : o) // expected-error {{variable of type 'class S6' is not valid for specified reduction operation}} +#pragma omp sections reduction(+ : o) // expected-error {{no viable overloaded '='}} { foo(); } Index: test/OpenMP/simd_reduction_messages.cpp =================================================================== --- test/OpenMP/simd_reduction_messages.cpp +++ test/OpenMP/simd_reduction_messages.cpp @@ -11,7 +11,7 @@ extern S1 a; class S2 { mutable int a; - S2 &operator+=(const S2 &arg) { return (*this); } + S2 &operator+(const S2 &arg) { return (*this); } // expected-note 4 {{implicitly declared private here}} public: S2() : a(0) {} @@ -28,17 +28,17 @@ public: S3() : a(0) {} S3(const S3 &s3) : a(s3.a) {} - S3 operator+=(const S3 &arg1) { return arg1; } + S3 operator+(const S3 &arg1) { return arg1; } }; -int operator+=(const S3 &arg1, const S3 &arg2) { return 5; } +int operator+(const S3 &arg1, const S3 &arg2) { return 5; } S3 c; // expected-note 2 {{'c' defined here}} const S3 ca[5]; // expected-note 2 {{'ca' defined here}} extern const int f; // expected-note 4 {{'f' declared here}} -class S4 { // expected-note {{'S4' declared here}} +class S4 { int a; - S4(); + S4(); // expected-note {{implicitly declared private here}} S4(const S4 &s4); - S4 &operator+=(const S4 &arg) { return (*this); } + S4 &operator+(const S4 &arg) { return (*this); } public: S4(int v) : a(v) {} @@ -46,26 +46,26 @@ S4 &operator&=(S4 &arg1, S4 &arg2) { return arg1; } class S5 { int a; - S5() : a(0) {} + S5() : a(0) {} // expected-note {{implicitly declared private here}} S5(const S5 &s5) : a(s5.a) {} - S5 &operator+=(const S5 &arg); + S5 &operator+(const S5 &arg); public: S5(int v) : a(v) {} }; -class S6 { +class S6 { // expected-note 2 {{candidate function (the implicit copy assignment operator) not viable: no known conversion from 'int' to 'const S6' for 1st argument}} int a; public: S6() : a(6) {} operator int() { return 6; } -} o; // expected-note 2 {{'o' defined here}} +} o; S3 h, k; #pragma omp threadprivate(h) // expected-note 2 {{defined as threadprivate or thread local}} template // expected-note {{declared here}} -T tmain(T argc) { // expected-note 2 {{'argc' defined here}} +T tmain(T argc) { const T d = T(); // expected-note 4 {{'d' defined here}} const T da[5] = {T()}; // expected-note 2 {{'da' defined here}} T qa[5] = {T()}; @@ -74,7 +74,7 @@ S3 &p = k; // expected-note 2 {{'p' defined here}} const T &r = da[(int)i]; // expected-note 2 {{'r' defined here}} T &q = qa[(int)i]; // expected-note 2 {{'q' defined here}} - T fl; // expected-note {{'fl' defined here}} + T fl; #pragma omp simd reduction // expected-error {{expected '(' after 'reduction'}} for (int i = 0; i < 10; ++i) foo(); @@ -96,10 +96,10 @@ #pragma omp simd reduction(\) // expected-error {{expected unqualified-id}} expected-warning {{missing ':' after reduction identifier - ignoring}} for (int i = 0; i < 10; ++i) foo(); -#pragma omp simd reduction(& : argc // expected-error {{expected ')'}} expected-note {{to match this '('}} expected-error {{variable of type 'float' is not valid for specified reduction operation}} +#pragma omp simd reduction(& : argc // expected-error {{expected ')'}} expected-note {{to match this '('}} expected-error {{invalid operands to binary expression ('float' and 'float')}} for (int i = 0; i < 10; ++i) foo(); -#pragma omp simd reduction(| : argc, // expected-error {{expected expression}} expected-error {{expected ')'}} expected-note {{to match this '('}} expected-error {{variable of type 'float' is not valid for specified reduction operation}} +#pragma omp simd reduction(| : argc, // expected-error {{expected expression}} expected-error {{expected ')'}} expected-note {{to match this '('}} expected-error {{invalid operands to binary expression ('float' and 'float')}} for (int i = 0; i < 10; ++i) foo(); #pragma omp simd reduction(|| : argc ? i : argc) // expected-error 2 {{expected variable name}} @@ -114,7 +114,7 @@ #pragma omp simd reduction(^ : T) // expected-error {{'T' does not refer to a value}} for (int i = 0; i < 10; ++i) foo(); -#pragma omp simd reduction(+ : a, b, c, d, f) // expected-error {{reduction variable with incomplete type 'S1'}} expected-error 3 {{const-qualified variable cannot be reduction}} +#pragma omp simd reduction(+ : a, b, c, d, f) // expected-error {{reduction variable with incomplete type 'S1'}} expected-error 3 {{const-qualified variable cannot be reduction}} expected-error 3 {{'operator+' is a private member of 'S2'}} for (int i = 0; i < 10; ++i) foo(); #pragma omp simd reduction(min : a, b, c, d, f) // expected-error {{reduction variable with incomplete type 'S1'}} expected-error 2 {{arguments of OpenMP clause 'reduction' for 'min' or 'max' must be of arithmetic type}} expected-error 3 {{const-qualified variable cannot be reduction}} @@ -132,7 +132,7 @@ #pragma omp simd reduction(- : da) // expected-error {{a reduction variable with array type 'const int [5]'}} expected-error {{a reduction variable with array type 'const float [5]'}} for (int i = 0; i < 10; ++i) foo(); -#pragma omp simd reduction(^ : fl) // expected-error {{variable of type 'float' is not valid for specified reduction operation}} +#pragma omp simd reduction(^ : fl) // expected-error {{invalid operands to binary expression ('float' and 'float')}} for (int i = 0; i < 10; ++i) foo(); #pragma omp simd reduction(&& : S2::S2s) // expected-error {{shared variable cannot be reduction}} @@ -144,7 +144,7 @@ #pragma omp simd reduction(+ : h, k) // expected-error {{threadprivate or thread local variable cannot be reduction}} for (int i = 0; i < 10; ++i) foo(); -#pragma omp simd reduction(+ : o) // expected-error {{variable of type 'class S6' is not valid for specified reduction operation}} +#pragma omp simd reduction(+ : o) // expected-error {{no viable overloaded '='}} for (int i = 0; i < 10; ++i) foo(); #pragma omp simd private(i), reduction(+ : j), reduction(+ : q) // expected-error 4 {{argument of OpenMP clause 'reduction' must reference the same object in all threads}} @@ -184,14 +184,14 @@ const int d = 5; // expected-note 2 {{'d' defined here}} const int da[5] = {0}; // expected-note {{'da' defined here}} int qa[5] = {0}; - S4 e(4); // expected-note {{'e' defined here}} - S5 g(5); // expected-note {{'g' defined here}} + S4 e(4); + S5 g(5); int i; int &j = i; // expected-note 2 {{'j' defined here}} S3 &p = k; // expected-note 2 {{'p' defined here}} const int &r = da[i]; // expected-note {{'r' defined here}} int &q = qa[i]; // expected-note {{'q' defined here}} - float fl; // expected-note {{'fl' defined here}} + float fl; #pragma omp simd reduction // expected-error {{expected '(' after 'reduction'}} for (int i = 0; i < 10; ++i) foo(); @@ -231,7 +231,7 @@ #pragma omp simd reduction(^ : S1) // expected-error {{'S1' does not refer to a value}} for (int i = 0; i < 10; ++i) foo(); -#pragma omp simd reduction(+ : a, b, c, d, f) // expected-error {{reduction variable with incomplete type 'S1'}} expected-error 2 {{const-qualified variable cannot be reduction}} +#pragma omp simd reduction(+ : a, b, c, d, f) // expected-error {{reduction variable with incomplete type 'S1'}} expected-error 2 {{const-qualified variable cannot be reduction}} expected-error {{'operator+' is a private member of 'S2'}} for (int i = 0; i < 10; ++i) foo(); #pragma omp simd reduction(min : a, b, c, d, f) // expected-error {{reduction variable with incomplete type 'S1'}} expected-error 2 {{arguments of OpenMP clause 'reduction' for 'min' or 'max' must be of arithmetic type}} expected-error 2 {{const-qualified variable cannot be reduction}} @@ -249,7 +249,7 @@ #pragma omp simd reduction(- : da) // expected-error {{a reduction variable with array type 'const int [5]'}} for (int i = 0; i < 10; ++i) foo(); -#pragma omp simd reduction(^ : fl) // expected-error {{variable of type 'float' is not valid for specified reduction operation}} +#pragma omp simd reduction(^ : fl) // expected-error {{invalid operands to binary expression ('float' and 'float')}} for (int i = 0; i < 10; ++i) foo(); #pragma omp simd reduction(&& : S2::S2s) // expected-error {{shared variable cannot be reduction}} @@ -258,13 +258,13 @@ #pragma omp simd reduction(&& : S2::S2sc) // expected-error {{const-qualified variable cannot be reduction}} for (int i = 0; i < 10; ++i) foo(); -#pragma omp simd reduction(& : e, g) // expected-error {{reduction variable must have an accessible, unambiguous default constructor}} expected-error {{variable of type 'S5' is not valid for specified reduction operation}} +#pragma omp simd reduction(& : e, g) // expected-error {{calling a private constructor of class 'S4'}} expected-error {{invalid operands to binary expression ('S4' and 'S4')}} expected-error {{calling a private constructor of class 'S5'}} expected-error {{invalid operands to binary expression ('S5' and 'S5')}} for (int i = 0; i < 10; ++i) foo(); #pragma omp simd reduction(+ : h, k) // expected-error {{threadprivate or thread local variable cannot be reduction}} for (int i = 0; i < 10; ++i) foo(); -#pragma omp simd reduction(+ : o) // expected-error {{variable of type 'class S6' is not valid for specified reduction operation}} +#pragma omp simd reduction(+ : o) // expected-error {{no viable overloaded '='}} for (int i = 0; i < 10; ++i) foo(); #pragma omp simd private(i), reduction(+ : j), reduction(+ : q) // expected-error 2 {{argument of OpenMP clause 'reduction' must reference the same object in all threads}} Index: test/OpenMP/teams_reduction_messages.cpp =================================================================== --- test/OpenMP/teams_reduction_messages.cpp +++ test/OpenMP/teams_reduction_messages.cpp @@ -11,7 +11,7 @@ extern S1 a; class S2 { mutable int a; - S2 &operator+=(const S2 &arg) { return (*this); } + S2 &operator+(const S2 &arg) { return (*this); } // expected-note 4 {{implicitly declared private here}} public: S2() : a(0) {} @@ -28,17 +28,17 @@ public: S3() : a(0) {} S3(const S3 &s3) : a(s3.a) {} - S3 operator+=(const S3 &arg1) { return arg1; } + S3 operator+(const S3 &arg1) { return arg1; } }; -int operator+=(const S3 &arg1, const S3 &arg2) { return 5; } +int operator+(const S3 &arg1, const S3 &arg2) { return 5; } S3 c; // expected-note 2 {{'c' defined here}} const S3 ca[5]; // expected-note 2 {{'ca' defined here}} extern const int f; // expected-note 4 {{'f' declared here}} -class S4 { // expected-note {{'S4' declared here}} +class S4 { int a; - S4(); + S4(); // expected-note {{implicitly declared private here}} S4(const S4 &s4); - S4 &operator+=(const S4 &arg) { return (*this); } + S4 &operator+(const S4 &arg) { return (*this); } public: S4(int v) : a(v) {} @@ -46,26 +46,26 @@ S4 &operator&=(S4 &arg1, S4 &arg2) { return arg1; } class S5 { int a; - S5() : a(0) {} + S5() : a(0) {} // expected-note {{implicitly declared private here}} S5(const S5 &s5) : a(s5.a) {} - S5 &operator+=(const S5 &arg); + S5 &operator+(const S5 &arg); public: S5(int v) : a(v) {} }; -class S6 { +class S6 { // expected-note 2 {{candidate function (the implicit copy assignment operator) not viable: no known conversion from 'int' to 'const S6' for 1st argument}} int a; public: S6() : a(6) {} operator int() { return 6; } -} o; // expected-note 2 {{'o' defined here}} +} o; S3 h, k; #pragma omp threadprivate(h) // expected-note 2 {{defined as threadprivate or thread local}} template // expected-note {{declared here}} -T tmain(T argc) { // expected-note 2 {{'argc' defined here}} +T tmain(T argc) { const T d = T(); // expected-note 4 {{'d' defined here}} const T da[5] = {T()}; // expected-note 2 {{'da' defined here}} T qa[5] = {T()}; @@ -74,7 +74,7 @@ S3 &p = k; // expected-note 2 {{'p' defined here}} const T &r = da[(int)i]; // expected-note 2 {{'r' defined here}} T &q = qa[(int)i]; // expected-note 2 {{'q' defined here}} - T fl; // expected-note {{'fl' defined here}} + T fl; #pragma omp target #pragma omp teams reduction // expected-error {{expected '(' after 'reduction'}} foo(); @@ -97,10 +97,10 @@ #pragma omp teams reduction(\) // expected-error {{expected unqualified-id}} expected-warning {{missing ':' after reduction identifier - ignoring}} foo(); #pragma omp target -#pragma omp teams reduction(& : argc // expected-error {{expected ')'}} expected-note {{to match this '('}} expected-error {{variable of type 'float' is not valid for specified reduction operation}} +#pragma omp teams reduction(& : argc // expected-error {{expected ')'}} expected-note {{to match this '('}} expected-error {{invalid operands to binary expression ('float' and 'float')}} foo(); #pragma omp target -#pragma omp teams reduction(| : argc, // expected-error {{expected expression}} expected-error {{expected ')'}} expected-note {{to match this '('}} expected-error {{variable of type 'float' is not valid for specified reduction operation}} +#pragma omp teams reduction(| : argc, // expected-error {{expected expression}} expected-error {{expected ')'}} expected-note {{to match this '('}} expected-error {{invalid operands to binary expression ('float' and 'float')}} foo(); #pragma omp target #pragma omp teams reduction(|| : argc ? i : argc) // expected-error 2 {{expected variable name}} @@ -115,7 +115,7 @@ #pragma omp teams reduction(^ : T) // expected-error {{'T' does not refer to a value}} foo(); #pragma omp target -#pragma omp teams reduction(+ : a, b, c, d, f) // expected-error {{reduction variable with incomplete type 'S1'}} expected-error 3 {{const-qualified variable cannot be reduction}} +#pragma omp teams reduction(+ : a, b, c, d, f) // expected-error {{reduction variable with incomplete type 'S1'}} expected-error 3 {{const-qualified variable cannot be reduction}} expected-error 3 {{'operator+' is a private member of 'S2'}} foo(); #pragma omp target #pragma omp teams reduction(min : a, b, c, d, f) // expected-error {{reduction variable with incomplete type 'S1'}} expected-error 2 {{arguments of OpenMP clause 'reduction' for 'min' or 'max' must be of arithmetic type}} expected-error 3 {{const-qualified variable cannot be reduction}} @@ -133,7 +133,7 @@ #pragma omp teams reduction(- : da) // expected-error {{a reduction variable with array type 'const int [5]'}} expected-error {{a reduction variable with array type 'const float [5]'}} foo(); #pragma omp target -#pragma omp teams reduction(^ : fl) // expected-error {{variable of type 'float' is not valid for specified reduction operation}} +#pragma omp teams reduction(^ : fl) // expected-error {{invalid operands to binary expression ('float' and 'float')}} foo(); #pragma omp target #pragma omp teams reduction(&& : S2::S2s) @@ -145,7 +145,7 @@ #pragma omp teams reduction(+ : h, k) // expected-error {{threadprivate or thread local variable cannot be reduction}} foo(); #pragma omp target -#pragma omp teams reduction(+ : o) // expected-error {{variable of type 'class S6' is not valid for specified reduction operation}} +#pragma omp teams reduction(+ : o) // expected-error {{no viable overloaded '='}} foo(); #pragma omp target #pragma omp teams private(i), reduction(+ : j), reduction(+ : q) // expected-error 4 {{argument of OpenMP clause 'reduction' must reference the same object in all threads}} @@ -187,14 +187,14 @@ const int d = 5; // expected-note 2 {{'d' defined here}} const int da[5] = {0}; // expected-note {{'da' defined here}} int qa[5] = {0}; - S4 e(4); // expected-note {{'e' defined here}} - S5 g(5); // expected-note {{'g' defined here}} + S4 e(4); + S5 g(5); int i; int &j = i; // expected-note 2 {{'j' defined here}} S3 &p = k; // expected-note 2 {{'p' defined here}} const int &r = da[i]; // expected-note {{'r' defined here}} int &q = qa[i]; // expected-note {{'q' defined here}} - float fl; // expected-note {{'fl' defined here}} + float fl; #pragma omp target #pragma omp teams reduction // expected-error {{expected '(' after 'reduction'}} foo(); @@ -235,7 +235,7 @@ #pragma omp teams reduction(^ : S1) // expected-error {{'S1' does not refer to a value}} foo(); #pragma omp target -#pragma omp teams reduction(+ : a, b, c, d, f) // expected-error {{reduction variable with incomplete type 'S1'}} expected-error 2 {{const-qualified variable cannot be reduction}} +#pragma omp teams reduction(+ : a, b, c, d, f) // expected-error {{reduction variable with incomplete type 'S1'}} expected-error 2 {{const-qualified variable cannot be reduction}} expected-error {{'operator+' is a private member of 'S2'}} foo(); #pragma omp target #pragma omp teams reduction(min : a, b, c, d, f) // expected-error {{reduction variable with incomplete type 'S1'}} expected-error 2 {{arguments of OpenMP clause 'reduction' for 'min' or 'max' must be of arithmetic type}} expected-error 2 {{const-qualified variable cannot be reduction}} @@ -253,7 +253,7 @@ #pragma omp teams reduction(- : da) // expected-error {{a reduction variable with array type 'const int [5]'}} foo(); #pragma omp target -#pragma omp teams reduction(^ : fl) // expected-error {{variable of type 'float' is not valid for specified reduction operation}} +#pragma omp teams reduction(^ : fl) // expected-error {{invalid operands to binary expression ('float' and 'float')}} foo(); #pragma omp target #pragma omp teams reduction(&& : S2::S2s) @@ -262,13 +262,13 @@ #pragma omp teams reduction(&& : S2::S2sc) // expected-error {{const-qualified variable cannot be reduction}} foo(); #pragma omp target -#pragma omp teams reduction(& : e, g) // expected-error {{reduction variable must have an accessible, unambiguous default constructor}} expected-error {{variable of type 'S5' is not valid for specified reduction operation}} +#pragma omp teams reduction(& : e, g) // expected-error {{calling a private constructor of class 'S4'}} expected-error {{invalid operands to binary expression ('S4' and 'S4')}} expected-error {{calling a private constructor of class 'S5'}} expected-error {{invalid operands to binary expression ('S5' and 'S5')}} foo(); #pragma omp target #pragma omp teams reduction(+ : h, k) // expected-error {{threadprivate or thread local variable cannot be reduction}} foo(); #pragma omp target -#pragma omp teams reduction(+ : o) // expected-error {{variable of type 'class S6' is not valid for specified reduction operation}} +#pragma omp teams reduction(+ : o) // expected-error {{no viable overloaded '='}} foo(); #pragma omp target #pragma omp teams private(i), reduction(+ : j), reduction(+ : q) // expected-error 2 {{argument of OpenMP clause 'reduction' must reference the same object in all threads}} Index: tools/libclang/CIndex.cpp =================================================================== --- tools/libclang/CIndex.cpp +++ tools/libclang/CIndex.cpp @@ -2028,6 +2028,15 @@ } void OMPClauseEnqueue::VisitOMPReductionClause(const OMPReductionClause *C) { VisitOMPClauseList(C); + for (auto *E : C->lhs_exprs()) { + Visitor->AddStmt(E); + } + for (auto *E : C->rhs_exprs()) { + Visitor->AddStmt(E); + } + for (auto *E : C->reduction_ops()) { + Visitor->AddStmt(E); + } } void OMPClauseEnqueue::VisitOMPLinearClause(const OMPLinearClause *C) { VisitOMPClauseList(C);