[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:
parent
8ad3627e19
commit
794ba0dcb7
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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()));
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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?|"
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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}}
|
||||
|
|
|
@ -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}}
|
||||
|
|
|
@ -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
|
||||
|
|
@ -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();
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
|
|
@ -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}}
|
||||
|
|
|
@ -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}}
|
||||
|
|
|
@ -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);
|
||||
|
|
Loading…
Reference in New Issue