[OPENMP] Codegen for 'reduction' clause in 'parallel' directive.

Emit a code for reduction clause. Next code should be emitted for reductions:

static kmp_critical_name lock = { 0 };

void reduce_func(void *lhs[<n>], void *rhs[<n>]) {
  ...
  *(Type<i> *)lhs[i] = RedOp<i>(*(Type<i> *)lhs[i], *(Type<i> *)rhs[i]);
  ...
}

... void *RedList[<n>] = {&<RHSExprs>[0], ..., &<RHSExprs>[<n> - 1]};
switch (__kmpc_reduce{_nowait}(<loc>, <gtid>, <n>, sizeof(RedList), RedList, reduce_func, &<lock>)) {
case 1:
  ...
  <LHSExprs>[i] = RedOp<i>(*<LHSExprs>[i], *<RHSExprs>[i]);
  ...
  __kmpc_end_reduce{_nowait}(<loc>, <gtid>, &<lock>);
  break;
case 2:
  ...
  Atomic(<LHSExprs>[i] = RedOp<i>(*<LHSExprs>[i], *<RHSExprs>[i]));
  ...
  break;
default:
  ;
}
Reduction variables are a kind of a private variables, they have private copies, but initial values are chosen in accordance with the reduction operation.

Differential Revision: http://reviews.llvm.org/D8915

llvm-svn: 234583
This commit is contained in:
Alexey Bataev 2015-04-10 10:43:45 +00:00
parent 8ad3627e19
commit 794ba0dcb7
24 changed files with 1886 additions and 420 deletions

View File

@ -2580,6 +2580,15 @@ RecursiveASTVisitor<Derived>::VisitOMPReductionClause(OMPReductionClause *C) {
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;
}

View File

@ -1301,6 +1301,48 @@ class OMPReductionClause : public OMPVarListClause<OMPReductionClause> {
/// \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<Expr *> LHSExprs);
/// \brief Get the list of helper LHS expressions.
MutableArrayRef<Expr *> getLHSExprs() {
return MutableArrayRef<Expr *>(varlist_end(), varlist_size());
}
ArrayRef<const Expr *> 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<Expr *> RHSExprs);
/// \brief Get the list of helper destination expressions.
MutableArrayRef<Expr *> getRHSExprs() {
return MutableArrayRef<Expr *>(getLHSExprs().end(), varlist_size());
}
ArrayRef<const Expr *> 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<Expr *> ReductionOps);
/// \brief Get the list of helper reduction expressions.
MutableArrayRef<Expr *> getReductionOps() {
return MutableArrayRef<Expr *>(getRHSExprs().end(), varlist_size());
}
ArrayRef<const Expr *> getReductionOps() const {
return llvm::makeArrayRef(getRHSExprs().end(), varlist_size());
}
public:
/// \brief Creates clause with a list of variables \a VL.
///
@ -1311,12 +1353,30 @@ public:
/// \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);
/// <CutomReduction>(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<Expr *> VL,
NestedNameSpecifierLoc QualifierLoc,
const DeclarationNameInfo &NameInfo);
const DeclarationNameInfo &NameInfo, ArrayRef<Expr *> LHSExprs,
ArrayRef<Expr *> RHSExprs, ArrayRef<Expr *> ReductionOps);
/// \brief Creates an empty clause with the place for \a N variables.
///
/// \param C AST context.
@ -1331,6 +1391,33 @@ public:
/// \brief Gets the nested name specifier.
NestedNameSpecifierLoc getQualifierLoc() const { return QualifierLoc; }
typedef MutableArrayRef<Expr *>::iterator helper_expr_iterator;
typedef ArrayRef<const Expr *>::iterator helper_expr_const_iterator;
typedef llvm::iterator_range<helper_expr_iterator> helper_expr_range;
typedef llvm::iterator_range<helper_expr_const_iterator>
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<Stmt **>(varlist_begin()),
reinterpret_cast<Stmt **>(varlist_end()));

View File

@ -2610,6 +2610,15 @@ RecursiveASTVisitor<Derived>::VisitOMPReductionClause(OMPReductionClause *C) {
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;
}

View File

@ -7451,7 +7451,7 @@ def note_omp_referenced : Note<
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?|"

View File

@ -1457,16 +1457,42 @@ void OMPLoopDirective::setFinals(ArrayRef<Expr *> A) {
std::copy(A.begin(), A.end(), getFinals().begin());
}
void OMPReductionClause::setLHSExprs(ArrayRef<Expr *> 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<Expr *> 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<Expr *> 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<Expr *> VL,
NestedNameSpecifierLoc QualifierLoc, const DeclarationNameInfo &NameInfo) {
NestedNameSpecifierLoc QualifierLoc, const DeclarationNameInfo &NameInfo,
ArrayRef<Expr *> LHSExprs, ArrayRef<Expr *> RHSExprs,
ArrayRef<Expr *> ReductionOps) {
void *Mem = C.Allocate(llvm::RoundUpToAlignment(sizeof(OMPReductionClause),
llvm::alignOf<Expr *>()) +
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 @@ OMPReductionClause *OMPReductionClause::CreateEmpty(const ASTContext &C,
unsigned N) {
void *Mem = C.Allocate(llvm::RoundUpToAlignment(sizeof(OMPReductionClause),
llvm::alignOf<Expr *>()) +
sizeof(Expr *) * N);
4 * sizeof(Expr *) * N);
return new (Mem) OMPReductionClause(N);
}

View File

@ -356,6 +356,15 @@ void OMPClauseProfiler::VisitOMPReductionClause(
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);

View File

@ -657,6 +657,62 @@ CGOpenMPRuntime::createRuntimeFunction(OpenMPRTLFunction Function) {
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;
}
@ -998,11 +1054,11 @@ void CGOpenMPRuntime::emitCriticalRegion(CodeGenFunction &CGF,
llvm::Value *Args[] = {emitUpdateLocation(CGF, Loc), getThreadID(CGF, Loc),
getCriticalRegionLock(CriticalName)};
CGF.EmitRuntimeCall(createRuntimeFunction(OMPRTL__kmpc_critical), Args);
emitInlinedDirective(CGF, CriticalOpGen);
// Build a call to __kmpc_end_critical
CGF.EHStack.pushCleanup<CallEndCleanup>(
NormalAndEHCleanup, createRuntimeFunction(OMPRTL__kmpc_end_critical),
llvm::makeArrayRef(Args));
emitInlinedDirective(CGF, CriticalOpGen);
}
}
@ -1037,26 +1093,10 @@ void CGOpenMPRuntime::emitMasterRegion(CodeGenFunction &CGF,
CGF.EmitRuntimeCall(createRuntimeFunction(OMPRTL__kmpc_master), Args);
emitIfStmt(CGF, IsMaster, [&](CodeGenFunction &CGF) -> void {
CodeGenFunction::RunCleanupsScope Scope(CGF);
MasterOpGen(CGF);
// Build a call to __kmpc_end_master.
// OpenMP [1.2.2 OpenMP Language Terminology]
// For C/C++, an executable statement, possibly compound, with a single
// entry at the top and a single exit at the bottom, or an OpenMP
// construct.
// * Access to the structured block must not be the result of a branch.
// * The point of exit cannot be a branch out of the structured block.
// * The point of entry must not be a call to setjmp().
// * longjmp() and throw() must not violate the entry/exit criteria.
// * An expression statement, iteration statement, selection statement, or
// try block is considered to be a structured block if the corresponding
// compound statement obtained by enclosing it in { and } would be a
// structured block.
// It is analyzed in Sema, so we can just call __kmpc_end_master() on
// fallthrough rather than pushing a normal cleanup for it.
// Build a call to __kmpc_end_critical
CGF.EHStack.pushCleanup<CallEndCleanup>(
NormalAndEHCleanup, createRuntimeFunction(OMPRTL__kmpc_end_master),
llvm::makeArrayRef(Args));
MasterOpGen(CGF);
});
}
@ -1167,29 +1207,15 @@ void CGOpenMPRuntime::emitSingleRegion(CodeGenFunction &CGF,
CGF.EmitRuntimeCall(createRuntimeFunction(OMPRTL__kmpc_single), Args);
emitIfStmt(CGF, IsSingle, [&](CodeGenFunction &CGF) -> void {
CodeGenFunction::RunCleanupsScope Scope(CGF);
CGF.EHStack.pushCleanup<CallEndCleanup>(
NormalAndEHCleanup, createRuntimeFunction(OMPRTL__kmpc_end_single),
llvm::makeArrayRef(Args));
SingleOpGen(CGF);
if (DidIt) {
// did_it = 1;
CGF.Builder.CreateAlignedStore(CGF.Builder.getInt32(1), DidIt,
DidIt->getAlignment());
}
// Build a call to __kmpc_end_single.
// OpenMP [1.2.2 OpenMP Language Terminology]
// For C/C++, an executable statement, possibly compound, with a single
// entry at the top and a single exit at the bottom, or an OpenMP construct.
// * Access to the structured block must not be the result of a branch.
// * The point of exit cannot be a branch out of the structured block.
// * The point of entry must not be a call to setjmp().
// * longjmp() and throw() must not violate the entry/exit criteria.
// * An expression statement, iteration statement, selection statement, or
// try block is considered to be a structured block if the corresponding
// compound statement obtained by enclosing it in { and } would be a
// structured block.
// It is analyzed in Sema, so we can just call __kmpc_end_single() on
// fallthrough rather than pushing a normal cleanup for it.
CGF.EHStack.pushCleanup<CallEndCleanup>(
NormalAndEHCleanup, createRuntimeFunction(OMPRTL__kmpc_end_single),
llvm::makeArrayRef(Args));
});
// call __kmpc_copyprivate(ident_t *, gtid, <buf_size>, <copyprivate list>,
// <copy_func>, did_it);
@ -1615,6 +1641,265 @@ void CGOpenMPRuntime::emitTaskCall(
CGF.EmitRuntimeCall(createRuntimeFunction(OMPRTL__kmpc_omp_task), TaskArgs);
}
static llvm::Value *emitReductionFunction(CodeGenModule &CGM,
llvm::Type *ArgsType,
ArrayRef<const Expr *> LHSExprs,
ArrayRef<const Expr *> RHSExprs,
ArrayRef<const Expr *> 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);
// ...
// *(Type<i>*)lhs[i] = RedOp<i>(*(Type<i>*)lhs[i], *(Type<i>*)rhs[i]);
// ...
CodeGenFunction::OMPPrivateScope Scope(CGF);
for (unsigned I = 0, E = ReductionOps.size(); I < E; ++I) {
Scope.addPrivate(
cast<VarDecl>(cast<DeclRefExpr>(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<VarDecl>(cast<DeclRefExpr>(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;
}
void CGOpenMPRuntime::emitReduction(CodeGenFunction &CGF, SourceLocation Loc,
ArrayRef<const Expr *> LHSExprs,
ArrayRef<const Expr *> RHSExprs,
ArrayRef<const Expr *> ReductionOps,
bool WithNowait) {
// Next code should be emitted for reduction:
//
// static kmp_critical_name lock = { 0 };
//
// void reduce_func(void *lhs[<n>], void *rhs[<n>]) {
// *(Type0*)lhs[0] = ReductionOperation0(*(Type0*)lhs[0], *(Type0*)rhs[0]);
// ...
// *(Type<n>-1*)lhs[<n>-1] = ReductionOperation<n>-1(*(Type<n>-1*)lhs[<n>-1],
// *(Type<n>-1*)rhs[<n>-1]);
// }
//
// ...
// void *RedList[<n>] = {&<RHSExprs>[0], ..., &<RHSExprs>[<n>-1]};
// switch (__kmpc_reduce{_nowait}(<loc>, <gtid>, <n>, sizeof(RedList),
// RedList, reduce_func, &<lock>)) {
// case 1:
// ...
// <LHSExprs>[i] = RedOp<i>(*<LHSExprs>[i], *<RHSExprs>[i]);
// ...
// __kmpc_end_reduce{_nowait}(<loc>, <gtid>, &<lock>);
// break;
// case 2:
// ...
// Atomic(<LHSExprs>[i] = RedOp<i>(*<LHSExprs>[i], *<RHSExprs>[i]));
// ...
// break;
// default:;
// }
auto &C = CGM.getContext();
// 1. Build a list of reduction variables.
// void *RedList[<n>] = {<ReductionVars>[0], ..., <ReductionVars>[<n>-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}(<loc>, <gtid>, <n>, sizeof(RedList),
// RedList, reduce_func, &<lock>);
auto *IdentTLoc = emitUpdateLocation(
CGF, Loc,
static_cast<OpenMPLocationFlags>(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 *<loc>
ThreadId, // i32 <gtid>
CGF.Builder.getInt32(RHSExprs.size()), // i32 <n>
ReductionArrayTySize, // size_type sizeof(RedList)
RL, // void *RedList
ReductionFn, // void (*) (void *, void *) <reduce_func>
Lock // kmp_critical_name *&<lock>
};
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:
// ...
// <LHSExprs>[i] = RedOp<i>(*<LHSExprs>[i], *<RHSExprs>[i]);
// ...
// __kmpc_end_reduce{_nowait}(<loc>, <gtid>, &<lock>);
// break;
auto *Case1BB = CGF.createBasicBlock(".omp.reduction.case1");
SwInst->addCase(CGF.Builder.getInt32(1), Case1BB);
CGF.EmitBlock(Case1BB);
{
CodeGenFunction::RunCleanupsScope Scope(CGF);
// Add emission of __kmpc_end_reduce{_nowait}(<loc>, <gtid>, &<lock>);
llvm::Value *EndArgs[] = {
IdentTLoc, // ident_t *<loc>
ThreadId, // i32 <gtid>
Lock // kmp_critical_name *&<lock>
};
CGF.EHStack.pushCleanup<CallEndCleanup>(
NormalAndEHCleanup,
createRuntimeFunction(WithNowait ? OMPRTL__kmpc_end_reduce_nowait
: OMPRTL__kmpc_end_reduce),
llvm::makeArrayRef(EndArgs));
for (auto *E : ReductionOps) {
CGF.EmitIgnoredExpr(E);
}
}
CGF.EmitBranch(DefaultBB);
// 7. Build case 2:
// ...
// Atomic(<LHSExprs>[i] = RedOp<i>(*<LHSExprs>[i], *<RHSExprs>[i]));
// ...
// 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<AbstractConditionalOperator>(E)) {
// If this is a conditional operator, analyze it's condition for
// min/max reduction operator.
E = ACO->getCond();
}
if (auto *BO = dyn_cast<BinaryOperator>(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<BinaryOperator>(UpExpr->IgnoreParenImpCasts())) {
EExpr = BORHS->getRHS();
BO = BORHS->getOpcode();
}
}
if (XExpr) {
auto *VD = cast<VarDecl>(cast<DeclRefExpr>(*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", [E](CodeGenFunction &CGF) {
CGF.EmitIgnoredExpr(E);
}, Loc);
}
++I;
}
}
CGF.EmitBranch(DefaultBB);
CGF.EmitBlock(DefaultBB, /*IsFinished=*/true);
}
void CGOpenMPRuntime::emitInlinedDirective(CodeGenFunction &CGF,
const RegionCodeGenTy &CodeGen) {
InlinedOpenMPRegionRAII Region(CGF, CodeGen);

View File

@ -103,6 +103,21 @@ private:
// 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.
@ -511,11 +526,54 @@ public:
llvm::PointerIntPair<llvm::Value *, 1, bool> Final,
llvm::Value *TaskFunction, QualType SharedsTy,
llvm::Value *Shareds);
/// \brief Emit code for the directive that does not require outlining.
///
/// \param CodeGen Code generation sequence for the \a D directive.
virtual void emitInlinedDirective(CodeGenFunction &CGF,
const RegionCodeGenTy &CodeGen);
/// \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[<n>], void *rhs[<n>]) {
/// ...
/// *(Type<i>*)lhs[i] = RedOp<i>(*(Type<i>*)lhs[i], *(Type<i>*)rhs[i]);
/// ...
/// }
///
/// ...
/// void *RedList[<n>] = {&<RHSExprs>[0], ..., &<RHSExprs>[<n>-1]};
/// switch (__kmpc_reduce{_nowait}(<loc>, <gtid>, <n>, sizeof(RedList),
/// RedList, reduce_func, &<lock>)) {
/// case 1:
/// ...
/// <LHSExprs>[i] = RedOp<i>(*<LHSExprs>[i], *<RHSExprs>[i]);
/// ...
/// __kmpc_end_reduce{_nowait}(<loc>, <gtid>, &<lock>);
/// break;
/// case 2:
/// ...
/// Atomic(<LHSExprs>[i] = RedOp<i>(*<LHSExprs>[i], *<RHSExprs>[i]));
/// ...
/// 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<const Expr *> LHSExprs,
ArrayRef<const Expr *> RHSExprs,
ArrayRef<const Expr *> ReductionOps,
bool WithNowait);
};
} // namespace CodeGen

View File

@ -209,6 +209,73 @@ void CodeGenFunction::EmitOMPPrivateClause(
}
}
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<decltype(
ReductionFilter)> I(D.clauses(), ReductionFilter);
I; ++I) {
auto *C = cast<OMPReductionClause>(*I);
auto ILHS = C->lhs_exprs().begin();
auto IRHS = C->rhs_exprs().begin();
for (auto IRef : C->varlists()) {
auto *OrigVD = cast<VarDecl>(cast<DeclRefExpr>(IRef)->getDecl());
auto *LHSVD = cast<VarDecl>(cast<DeclRefExpr>(*ILHS)->getDecl());
auto *PrivateVD = cast<VarDecl>(cast<DeclRefExpr>(*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<VarDecl *>(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<const Expr *, 8> LHSExprs;
llvm::SmallVector<const Expr *, 8> RHSExprs;
llvm::SmallVector<const Expr *, 8> ReductionOps;
auto ReductionFilter = [](const OMPClause *C) -> bool {
return C->getClauseKind() == OMPC_reduction;
};
bool HasAtLeastOneReduction = false;
for (OMPExecutableDirective::filtered_clause_iterator<decltype(
ReductionFilter)> I(D.clauses(), ReductionFilter);
I; ++I) {
HasAtLeastOneReduction = true;
auto *C = cast<OMPReductionClause>(*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 OMPExecutableDirective &S,
@ -253,11 +320,13 @@ void CodeGenFunction::EmitOMPParallelDirective(const OMPParallelDirective &S) {
OMPPrivateScope PrivateScope(CGF);
CGF.EmitOMPPrivateClause(S, PrivateScope);
CGF.EmitOMPFirstprivateClause(S, PrivateScope);
CGF.EmitOMPReductionClauseInit(S, PrivateScope);
if (PrivateScope.Privatize())
// Emit implicit barrier to synchronize threads and avoid data races.
CGF.CGM.getOpenMPRuntime().emitBarrierCall(CGF, S.getLocStart(),
OMPD_unknown);
CGF.EmitStmt(cast<CapturedStmt>(S.getAssociatedStmt())->getCapturedStmt());
CGF.EmitOMPReductionClauseFinal(S);
// Emit implicit barrier at the end of the 'parallel' directive.
CGF.CGM.getOpenMPRuntime().emitBarrierCall(CGF, S.getLocStart(),
OMPD_unknown);
@ -1155,73 +1224,113 @@ static void EmitOMPAtomicWriteExpr(CodeGenFunction &CGF, bool IsSeqCst,
CGF.CGM.getOpenMPRuntime().emitFlush(CGF, llvm::None, Loc);
}
static Optional<llvm::AtomicRMWInst::BinOp>
getCompatibleAtomicRMWBinOp(ASTContext &Context, BinaryOperatorKind Op,
bool IsXLHSInRHSPart, LValue XLValue,
RValue ExprRValue) {
Optional<llvm::AtomicRMWInst::BinOp> 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<llvm::ConstantInt>(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<llvm::ConstantInt>(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<llvm::ConstantInt>(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<RValue(RValue)> &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,
@ -1237,42 +1346,22 @@ static void EmitOMPAtomicUpdateExpr(CodeGenFunction &CGF, bool IsSeqCst,
// 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<llvm::ConstantInt>(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<OpaqueValueExpr>(BOUE->getLHS()->IgnoreImpCasts());
auto *RHS = cast<OpaqueValueExpr>(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<OpaqueValueExpr>(BOUE->getLHS()->IgnoreImpCasts());
auto *RHS = cast<OpaqueValueExpr>(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

View File

@ -2032,10 +2032,39 @@ public:
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<RValue(RValue)> &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);

View File

@ -5234,19 +5234,19 @@ OMPClause *Sema::ActOnOpenMPReductionClause(
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 @@ OMPClause *Sema::ActOnOpenMPReductionClause(
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 @@ OMPClause *Sema::ActOnOpenMPReductionClause(
}
SmallVector<Expr *, 8> Vars;
SmallVector<Expr *, 8> LHSs;
SmallVector<Expr *, 8> RHSs;
SmallVector<Expr *, 8> ReductionOps;
for (auto RefExpr : VarList) {
assert(RefExpr && "nullptr expr in OpenMP reduction clause.");
if (isa<DependentScopeDeclRefExpr>(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 @@ OMPClause *Sema::ActOnOpenMPReductionClause(
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 @@ OMPClause *Sema::ActOnOpenMPReductionClause(
<< 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 @@ OMPClause *Sema::ActOnOpenMPReductionClause(
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<ComplexType>()) {
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 @@ OMPClause *Sema::ActOnOpenMPReductionClause(
return OMPReductionClause::Create(
Context, StartLoc, LParenLoc, ColonLoc, EndLoc, Vars,
ReductionIdScopeSpec.getWithLocInContext(Context), ReductionId);
ReductionIdScopeSpec.getWithLocInContext(Context), ReductionId, LHSs,
RHSs, ReductionOps);
}
OMPClause *Sema::ActOnOpenMPLinearClause(ArrayRef<Expr *> VarList, Expr *Step,

View File

@ -1917,6 +1917,18 @@ void OMPClauseReader::VisitOMPReductionClause(OMPReductionClause *C) {
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) {

View File

@ -1815,6 +1815,12 @@ void OMPClauseWriter::VisitOMPReductionClause(OMPReductionClause *C) {
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) {

View File

@ -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 @@ struct S1; // expected-note {{declared here}} expected-note 4 {{forward declarat
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 @@ class S3 {
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 @@ public:
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 <class T> // 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 @@ T tmain(T argc) { // expected-note 2 {{'argc' defined here}}
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 @@ T tmain(T argc) { // expected-note 2 {{'argc' defined here}}
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 @@ T tmain(T argc) { // expected-note 2 {{'argc' defined here}}
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 @@ T tmain(T argc) { // expected-note 2 {{'argc' defined here}}
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 @@ T tmain(T argc) { // expected-note 2 {{'argc' defined here}}
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 @@ int main(int argc, char **argv) {
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 @@ int main(int argc, char **argv) {
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 @@ int main(int argc, char **argv) {
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 @@ int main(int argc, char **argv) {
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 @@ int main(int argc, char **argv) {
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

View File

@ -11,7 +11,7 @@ struct S1; // expected-note {{declared here}} expected-note 4 {{forward declarat
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 @@ class S3 {
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 @@ public:
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 <class T> // 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 @@ T tmain(T argc) { // expected-note 2 {{'argc' defined here}}
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 @@ T tmain(T argc) { // expected-note 2 {{'argc' defined here}}
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 @@ T tmain(T argc) { // expected-note 2 {{'argc' defined here}}
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 @@ T tmain(T argc) { // expected-note 2 {{'argc' defined here}}
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 @@ T tmain(T argc) { // expected-note 2 {{'argc' defined here}}
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 @@ int main(int argc, char **argv) {
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 @@ int main(int argc, char **argv) {
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 @@ int main(int argc, char **argv) {
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 @@ int main(int argc, char **argv) {
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 @@ int main(int argc, char **argv) {
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

View File

@ -11,7 +11,7 @@ struct S1; // expected-note {{declared here}} expected-note 4 {{forward declarat
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 @@ class S3 {
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 @@ public:
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 <class T> // 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 @@ T tmain(T argc) { // expected-note 2 {{'argc' defined here}}
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 @@ T tmain(T argc) { // expected-note 2 {{'argc' defined here}}
#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 @@ T tmain(T argc) { // expected-note 2 {{'argc' defined here}}
#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 @@ T tmain(T argc) { // expected-note 2 {{'argc' defined here}}
#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 @@ T tmain(T argc) { // expected-note 2 {{'argc' defined here}}
#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 @@ int main(int argc, char **argv) {
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 @@ int main(int argc, char **argv) {
#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 @@ int main(int argc, char **argv) {
#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 @@ int main(int argc, char **argv) {
#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}}

View File

@ -11,7 +11,7 @@ struct S1; // expected-note {{declared here}} expected-note 4 {{forward declarat
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 @@ class S3 {
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 @@ public:
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 <class T> // 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 @@ T tmain(T argc) { // expected-note 2 {{'argc' defined here}}
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 @@ T tmain(T argc) { // expected-note 2 {{'argc' defined here}}
#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 @@ T tmain(T argc) { // expected-note 2 {{'argc' defined here}}
#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 @@ T tmain(T argc) { // expected-note 2 {{'argc' defined here}}
#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 @@ T tmain(T argc) { // expected-note 2 {{'argc' defined here}}
#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 @@ int main(int argc, char **argv) {
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 @@ int main(int argc, char **argv) {
#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 @@ int main(int argc, char **argv) {
#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 @@ int main(int argc, char **argv) {
#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}}

View File

@ -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 <class T>
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 <typename T>
T tmain() {
T t;
S<T> test;
T t_var = T(), t_var1;
T vec[] = {1, 2};
S<T> s_arr[] = {1, 2};
S<T> 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<float> test;
float t_var = 0, t_var1;
int vec[] = {1, 2};
S<float> s_arr[] = {1, 2};
S<float> 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<int>();
#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[<n>] = {<ReductionVars>[0], ..., <ReductionVars>[<n>-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(<loc>, <gtid>, <n>, sizeof(RedList), RedList, reduce_func, &<lock>);
// 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(<loc>, <gtid>, &<lock>);
// 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[<n>], void *rhs[<n>]) {
// *(Type0*)lhs[0] = ReductionOperation0(*(Type0*)lhs[0], *(Type0*)rhs[0]);
// ...
// *(Type<n>-1*)lhs[<n>-1] = ReductionOperation<n>-1(*(Type<n>-1*)lhs[<n>-1],
// *(Type<n>-1*)rhs[<n>-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<float>*)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<float>*)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<float>*)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<float>*)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[<n>] = {<ReductionVars>[0], ..., <ReductionVars>[<n>-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(<loc>, <gtid>, <n>, sizeof(RedList), RedList, reduce_func, &<lock>);
// 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(<loc>, <gtid>, &<lock>);
// 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[<n>], void *rhs[<n>]) {
// *(Type0*)lhs[0] = ReductionOperation0(*(Type0*)lhs[0], *(Type0*)rhs[0]);
// ...
// *(Type<n>-1*)lhs[<n>-1] = ReductionOperation<n>-1(*(Type<n>-1*)lhs[<n>-1],
// *(Type<n>-1*)rhs[<n>-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<i{{[0-9]+}}>*)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<i{{[0-9]+}}>*)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<i{{[0-9]+}}>*)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<i{{[0-9]+}}>*)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

View File

@ -11,7 +11,7 @@ struct S1; // expected-note {{declared here}} expected-note 4 {{forward declarat
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 @@ class S3 {
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 @@ public:
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 <class T> // 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 @@ T tmain(T argc) { // expected-note 2 {{'argc' defined here}}
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 @@ T tmain(T argc) { // expected-note 2 {{'argc' defined here}}
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 @@ T tmain(T argc) { // expected-note 2 {{'argc' defined here}}
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 @@ T tmain(T argc) { // expected-note 2 {{'argc' defined here}}
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 @@ T tmain(T argc) { // expected-note 2 {{'argc' defined here}}
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 @@ int main(int argc, char **argv) {
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 @@ int main(int argc, char **argv) {
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 @@ int main(int argc, char **argv) {
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();

View File

@ -11,7 +11,7 @@ struct S1; // expected-note {{declared here}} expected-note 4 {{forward declarat
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 @@ class S3 {
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 @@ public:
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 <class T> // 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 @@ T tmain(T argc) { // expected-note 2 {{'argc' defined here}}
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 @@ T tmain(T argc) { // expected-note 2 {{'argc' defined here}}
{
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 @@ T tmain(T argc) { // expected-note 2 {{'argc' defined here}}
{
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 @@ T tmain(T argc) { // expected-note 2 {{'argc' defined here}}
{
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 @@ T tmain(T argc) { // expected-note 2 {{'argc' defined here}}
{
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 @@ int main(int argc, char **argv) {
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 @@ int main(int argc, char **argv) {
{
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 @@ int main(int argc, char **argv) {
{
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 @@ int main(int argc, char **argv) {
{
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 @@ int main(int argc, char **argv) {
{
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();
}

View File

@ -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 @@ struct S1; // expected-note {{declared here}} expected-note 4 {{forward declarat
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 @@ class S3 {
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 @@ public:
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 <class T> // 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 @@ T tmain(T argc) { // expected-note 2 {{'argc' defined here}}
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 @@ T tmain(T argc) { // expected-note 2 {{'argc' defined here}}
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 @@ T tmain(T argc) { // expected-note 2 {{'argc' defined here}}
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 @@ T tmain(T argc) { // expected-note 2 {{'argc' defined here}}
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 @@ T tmain(T argc) { // expected-note 2 {{'argc' defined here}}
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 @@ int main(int argc, char **argv) {
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 @@ int main(int argc, char **argv) {
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 @@ int main(int argc, char **argv) {
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 @@ int main(int argc, char **argv) {
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 @@ int main(int argc, char **argv) {
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();
}

View File

@ -11,7 +11,7 @@ struct S1; // expected-note {{declared here}} expected-note 4 {{forward declarat
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 @@ class S3 {
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 @@ public:
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 <class T> // 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 @@ T tmain(T argc) { // expected-note 2 {{'argc' defined here}}
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 @@ T tmain(T argc) { // expected-note 2 {{'argc' defined here}}
#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 @@ T tmain(T argc) { // expected-note 2 {{'argc' defined here}}
#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 @@ T tmain(T argc) { // expected-note 2 {{'argc' defined here}}
#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 @@ T tmain(T argc) { // expected-note 2 {{'argc' defined here}}
#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 @@ int main(int argc, char **argv) {
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 @@ int main(int argc, char **argv) {
#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 @@ int main(int argc, char **argv) {
#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 @@ int main(int argc, char **argv) {
#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}}

View File

@ -11,7 +11,7 @@ struct S1; // expected-note {{declared here}} expected-note 4 {{forward declarat
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 @@ class S3 {
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 @@ public:
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 <class T> // 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 @@ T tmain(T argc) { // expected-note 2 {{'argc' defined here}}
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 @@ T tmain(T argc) { // expected-note 2 {{'argc' defined here}}
#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 @@ T tmain(T argc) { // expected-note 2 {{'argc' defined here}}
#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 @@ T tmain(T argc) { // expected-note 2 {{'argc' defined here}}
#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 @@ T tmain(T argc) { // expected-note 2 {{'argc' defined here}}
#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 @@ int main(int argc, char **argv) {
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 @@ int main(int argc, char **argv) {
#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 @@ int main(int argc, char **argv) {
#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 @@ int main(int argc, char **argv) {
#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}}

View File

@ -2028,6 +2028,15 @@ void OMPClauseEnqueue::VisitOMPSharedClause(const OMPSharedClause *C) {
}
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);