forked from OSchip/llvm-project
[OPENMP 4.1] Codegen for array sections/subscripts in 'reduction' clause.
OpenMP 4.1 adds support for array sections/subscripts in 'reduction' clause. Patch adds codegen for this feature. llvm-svn: 249672
This commit is contained in:
parent
3ddef773ad
commit
f24e7b1f60
|
@ -2664,6 +2664,9 @@ RecursiveASTVisitor<Derived>::VisitOMPReductionClause(OMPReductionClause *C) {
|
||||||
TRY_TO(TraverseNestedNameSpecifierLoc(C->getQualifierLoc()));
|
TRY_TO(TraverseNestedNameSpecifierLoc(C->getQualifierLoc()));
|
||||||
TRY_TO(TraverseDeclarationNameInfo(C->getNameInfo()));
|
TRY_TO(TraverseDeclarationNameInfo(C->getNameInfo()));
|
||||||
TRY_TO(VisitOMPClauseList(C));
|
TRY_TO(VisitOMPClauseList(C));
|
||||||
|
for (auto *E : C->privates()) {
|
||||||
|
TRY_TO(TraverseStmt(E));
|
||||||
|
}
|
||||||
for (auto *E : C->lhs_exprs()) {
|
for (auto *E : C->lhs_exprs()) {
|
||||||
TRY_TO(TraverseStmt(E));
|
TRY_TO(TraverseStmt(E));
|
||||||
}
|
}
|
||||||
|
|
|
@ -1588,6 +1588,19 @@ class OMPReductionClause : public OMPVarListClause<OMPReductionClause> {
|
||||||
/// \brief Sets the nested name specifier.
|
/// \brief Sets the nested name specifier.
|
||||||
void setQualifierLoc(NestedNameSpecifierLoc NSL) { QualifierLoc = NSL; }
|
void setQualifierLoc(NestedNameSpecifierLoc NSL) { QualifierLoc = NSL; }
|
||||||
|
|
||||||
|
/// \brief Set list of helper expressions, required for proper codegen of the
|
||||||
|
/// clause. These expressions represent private copy of the reduction
|
||||||
|
/// variable.
|
||||||
|
void setPrivates(ArrayRef<Expr *> Privates);
|
||||||
|
|
||||||
|
/// \brief Get the list of helper privates.
|
||||||
|
MutableArrayRef<Expr *> getPrivates() {
|
||||||
|
return MutableArrayRef<Expr *>(varlist_end(), varlist_size());
|
||||||
|
}
|
||||||
|
ArrayRef<const Expr *> getPrivates() const {
|
||||||
|
return llvm::makeArrayRef(varlist_end(), varlist_size());
|
||||||
|
}
|
||||||
|
|
||||||
/// \brief Set list of helper expressions, required for proper codegen of the
|
/// \brief Set list of helper expressions, required for proper codegen of the
|
||||||
/// clause. These expressions represent LHS expression in the final
|
/// clause. These expressions represent LHS expression in the final
|
||||||
/// reduction expression performed by the reduction clause.
|
/// reduction expression performed by the reduction clause.
|
||||||
|
@ -1595,10 +1608,10 @@ class OMPReductionClause : public OMPVarListClause<OMPReductionClause> {
|
||||||
|
|
||||||
/// \brief Get the list of helper LHS expressions.
|
/// \brief Get the list of helper LHS expressions.
|
||||||
MutableArrayRef<Expr *> getLHSExprs() {
|
MutableArrayRef<Expr *> getLHSExprs() {
|
||||||
return MutableArrayRef<Expr *>(varlist_end(), varlist_size());
|
return MutableArrayRef<Expr *>(getPrivates().end(), varlist_size());
|
||||||
}
|
}
|
||||||
ArrayRef<const Expr *> getLHSExprs() const {
|
ArrayRef<const Expr *> getLHSExprs() const {
|
||||||
return llvm::makeArrayRef(varlist_end(), varlist_size());
|
return llvm::makeArrayRef(getPrivates().end(), varlist_size());
|
||||||
}
|
}
|
||||||
|
|
||||||
/// \brief Set list of helper expressions, required for proper codegen of the
|
/// \brief Set list of helper expressions, required for proper codegen of the
|
||||||
|
@ -1640,6 +1653,8 @@ public:
|
||||||
/// \param VL The variables in the clause.
|
/// \param VL The variables in the clause.
|
||||||
/// \param QualifierLoc The nested-name qualifier with location information
|
/// \param QualifierLoc The nested-name qualifier with location information
|
||||||
/// \param NameInfo The full name info for reduction identifier.
|
/// \param NameInfo The full name info for reduction identifier.
|
||||||
|
/// \param Privates List of helper expressions for proper generation of
|
||||||
|
/// private copies.
|
||||||
/// \param LHSExprs List of helper expressions for proper generation of
|
/// \param LHSExprs List of helper expressions for proper generation of
|
||||||
/// assignment operation required for copyprivate clause. This list represents
|
/// assignment operation required for copyprivate clause. This list represents
|
||||||
/// LHSs of the reduction expressions.
|
/// LHSs of the reduction expressions.
|
||||||
|
@ -1662,8 +1677,9 @@ public:
|
||||||
Create(const ASTContext &C, SourceLocation StartLoc, SourceLocation LParenLoc,
|
Create(const ASTContext &C, SourceLocation StartLoc, SourceLocation LParenLoc,
|
||||||
SourceLocation ColonLoc, SourceLocation EndLoc, ArrayRef<Expr *> VL,
|
SourceLocation ColonLoc, SourceLocation EndLoc, ArrayRef<Expr *> VL,
|
||||||
NestedNameSpecifierLoc QualifierLoc,
|
NestedNameSpecifierLoc QualifierLoc,
|
||||||
const DeclarationNameInfo &NameInfo, ArrayRef<Expr *> LHSExprs,
|
const DeclarationNameInfo &NameInfo, ArrayRef<Expr *> Privates,
|
||||||
ArrayRef<Expr *> RHSExprs, ArrayRef<Expr *> ReductionOps);
|
ArrayRef<Expr *> LHSExprs, ArrayRef<Expr *> RHSExprs,
|
||||||
|
ArrayRef<Expr *> ReductionOps);
|
||||||
/// \brief Creates an empty clause with the place for \a N variables.
|
/// \brief Creates an empty clause with the place for \a N variables.
|
||||||
///
|
///
|
||||||
/// \param C AST context.
|
/// \param C AST context.
|
||||||
|
@ -1684,6 +1700,12 @@ public:
|
||||||
typedef llvm::iterator_range<helper_expr_const_iterator>
|
typedef llvm::iterator_range<helper_expr_const_iterator>
|
||||||
helper_expr_const_range;
|
helper_expr_const_range;
|
||||||
|
|
||||||
|
helper_expr_const_range privates() const {
|
||||||
|
return helper_expr_const_range(getPrivates().begin(), getPrivates().end());
|
||||||
|
}
|
||||||
|
helper_expr_range privates() {
|
||||||
|
return helper_expr_range(getPrivates().begin(), getPrivates().end());
|
||||||
|
}
|
||||||
helper_expr_const_range lhs_exprs() const {
|
helper_expr_const_range lhs_exprs() const {
|
||||||
return helper_expr_const_range(getLHSExprs().begin(), getLHSExprs().end());
|
return helper_expr_const_range(getLHSExprs().begin(), getLHSExprs().end());
|
||||||
}
|
}
|
||||||
|
|
|
@ -2704,6 +2704,9 @@ RecursiveASTVisitor<Derived>::VisitOMPReductionClause(OMPReductionClause *C) {
|
||||||
TRY_TO(TraverseNestedNameSpecifierLoc(C->getQualifierLoc()));
|
TRY_TO(TraverseNestedNameSpecifierLoc(C->getQualifierLoc()));
|
||||||
TRY_TO(TraverseDeclarationNameInfo(C->getNameInfo()));
|
TRY_TO(TraverseDeclarationNameInfo(C->getNameInfo()));
|
||||||
TRY_TO(VisitOMPClauseList(C));
|
TRY_TO(VisitOMPClauseList(C));
|
||||||
|
for (auto *E : C->privates()) {
|
||||||
|
TRY_TO(TraverseStmt(E));
|
||||||
|
}
|
||||||
for (auto *E : C->lhs_exprs()) {
|
for (auto *E : C->lhs_exprs()) {
|
||||||
TRY_TO(TraverseStmt(E));
|
TRY_TO(TraverseStmt(E));
|
||||||
}
|
}
|
||||||
|
|
|
@ -7754,6 +7754,8 @@ def note_omp_ordered_param : Note<
|
||||||
"'ordered' clause with specified parameter">;
|
"'ordered' clause with specified parameter">;
|
||||||
def err_omp_expected_array_sect_reduction_lb_not_zero : Error<
|
def err_omp_expected_array_sect_reduction_lb_not_zero : Error<
|
||||||
"lower bound expected to be evaluated to zero">;
|
"lower bound expected to be evaluated to zero">;
|
||||||
|
def err_omp_expected_base_var_name : Error<
|
||||||
|
"expected variable name as a base of the array %select{subscript|section}0">;
|
||||||
} // end of OpenMP category
|
} // end of OpenMP category
|
||||||
|
|
||||||
let CategoryName = "Related Result Type Issue" in {
|
let CategoryName = "Related Result Type Issue" in {
|
||||||
|
|
|
@ -3984,6 +3984,10 @@ QualType OMPArraySectionExpr::getBaseOriginalType(Expr *Base) {
|
||||||
Base = OASE->getBase();
|
Base = OASE->getBase();
|
||||||
++ArraySectionCount;
|
++ArraySectionCount;
|
||||||
}
|
}
|
||||||
|
while (auto *ASE = dyn_cast<ArraySubscriptExpr>(Base->IgnoreParens())) {
|
||||||
|
Base = ASE->getBase();
|
||||||
|
++ArraySectionCount;
|
||||||
|
}
|
||||||
auto OriginalTy = Base->getType();
|
auto OriginalTy = Base->getType();
|
||||||
if (auto *DRE = dyn_cast<DeclRefExpr>(Base))
|
if (auto *DRE = dyn_cast<DeclRefExpr>(Base))
|
||||||
if (auto *PVD = dyn_cast<ParmVarDecl>(DRE->getDecl()))
|
if (auto *PVD = dyn_cast<ParmVarDecl>(DRE->getDecl()))
|
||||||
|
|
|
@ -340,11 +340,17 @@ OMPCopyprivateClause *OMPCopyprivateClause::CreateEmpty(const ASTContext &C,
|
||||||
return new (Mem) OMPCopyprivateClause(N);
|
return new (Mem) OMPCopyprivateClause(N);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void OMPReductionClause::setPrivates(ArrayRef<Expr *> Privates) {
|
||||||
|
assert(Privates.size() == varlist_size() &&
|
||||||
|
"Number of private copies is not the same as the preallocated buffer");
|
||||||
|
std::copy(Privates.begin(), Privates.end(), varlist_end());
|
||||||
|
}
|
||||||
|
|
||||||
void OMPReductionClause::setLHSExprs(ArrayRef<Expr *> LHSExprs) {
|
void OMPReductionClause::setLHSExprs(ArrayRef<Expr *> LHSExprs) {
|
||||||
assert(
|
assert(
|
||||||
LHSExprs.size() == varlist_size() &&
|
LHSExprs.size() == varlist_size() &&
|
||||||
"Number of LHS expressions is not the same as the preallocated buffer");
|
"Number of LHS expressions is not the same as the preallocated buffer");
|
||||||
std::copy(LHSExprs.begin(), LHSExprs.end(), varlist_end());
|
std::copy(LHSExprs.begin(), LHSExprs.end(), getPrivates().end());
|
||||||
}
|
}
|
||||||
|
|
||||||
void OMPReductionClause::setRHSExprs(ArrayRef<Expr *> RHSExprs) {
|
void OMPReductionClause::setRHSExprs(ArrayRef<Expr *> RHSExprs) {
|
||||||
|
@ -365,14 +371,15 @@ OMPReductionClause *OMPReductionClause::Create(
|
||||||
const ASTContext &C, SourceLocation StartLoc, SourceLocation LParenLoc,
|
const ASTContext &C, SourceLocation StartLoc, SourceLocation LParenLoc,
|
||||||
SourceLocation EndLoc, SourceLocation ColonLoc, ArrayRef<Expr *> VL,
|
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 *> Privates, ArrayRef<Expr *> LHSExprs,
|
||||||
ArrayRef<Expr *> ReductionOps) {
|
ArrayRef<Expr *> RHSExprs, ArrayRef<Expr *> ReductionOps) {
|
||||||
void *Mem = C.Allocate(llvm::RoundUpToAlignment(sizeof(OMPReductionClause),
|
void *Mem = C.Allocate(llvm::RoundUpToAlignment(sizeof(OMPReductionClause),
|
||||||
llvm::alignOf<Expr *>()) +
|
llvm::alignOf<Expr *>()) +
|
||||||
4 * sizeof(Expr *) * VL.size());
|
5 * sizeof(Expr *) * VL.size());
|
||||||
OMPReductionClause *Clause = new (Mem) OMPReductionClause(
|
OMPReductionClause *Clause = new (Mem) OMPReductionClause(
|
||||||
StartLoc, LParenLoc, EndLoc, ColonLoc, VL.size(), QualifierLoc, NameInfo);
|
StartLoc, LParenLoc, EndLoc, ColonLoc, VL.size(), QualifierLoc, NameInfo);
|
||||||
Clause->setVarRefs(VL);
|
Clause->setVarRefs(VL);
|
||||||
|
Clause->setPrivates(Privates);
|
||||||
Clause->setLHSExprs(LHSExprs);
|
Clause->setLHSExprs(LHSExprs);
|
||||||
Clause->setRHSExprs(RHSExprs);
|
Clause->setRHSExprs(RHSExprs);
|
||||||
Clause->setReductionOps(ReductionOps);
|
Clause->setReductionOps(ReductionOps);
|
||||||
|
@ -383,7 +390,7 @@ OMPReductionClause *OMPReductionClause::CreateEmpty(const ASTContext &C,
|
||||||
unsigned N) {
|
unsigned N) {
|
||||||
void *Mem = C.Allocate(llvm::RoundUpToAlignment(sizeof(OMPReductionClause),
|
void *Mem = C.Allocate(llvm::RoundUpToAlignment(sizeof(OMPReductionClause),
|
||||||
llvm::alignOf<Expr *>()) +
|
llvm::alignOf<Expr *>()) +
|
||||||
4 * sizeof(Expr *) * N);
|
5 * sizeof(Expr *) * N);
|
||||||
return new (Mem) OMPReductionClause(N);
|
return new (Mem) OMPReductionClause(N);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -382,6 +382,9 @@ void OMPClauseProfiler::VisitOMPReductionClause(
|
||||||
C->getQualifierLoc().getNestedNameSpecifier());
|
C->getQualifierLoc().getNestedNameSpecifier());
|
||||||
Profiler->VisitName(C->getNameInfo().getName());
|
Profiler->VisitName(C->getNameInfo().getName());
|
||||||
VisitOMPClauseList(C);
|
VisitOMPClauseList(C);
|
||||||
|
for (auto *E : C->privates()) {
|
||||||
|
Profiler->VisitStmt(E);
|
||||||
|
}
|
||||||
for (auto *E : C->lhs_exprs()) {
|
for (auto *E : C->lhs_exprs()) {
|
||||||
Profiler->VisitStmt(E);
|
Profiler->VisitStmt(E);
|
||||||
}
|
}
|
||||||
|
|
|
@ -922,6 +922,26 @@ CGOpenMPRuntime::createRuntimeFunction(OpenMPRTLFunction Function) {
|
||||||
return RTLFn;
|
return RTLFn;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static llvm::Value *getTypeSize(CodeGenFunction &CGF, QualType Ty) {
|
||||||
|
auto &C = CGF.getContext();
|
||||||
|
llvm::Value *Size = nullptr;
|
||||||
|
auto SizeInChars = C.getTypeSizeInChars(Ty);
|
||||||
|
if (SizeInChars.isZero()) {
|
||||||
|
// getTypeSizeInChars() returns 0 for a VLA.
|
||||||
|
while (auto *VAT = C.getAsVariableArrayType(Ty)) {
|
||||||
|
llvm::Value *ArraySize;
|
||||||
|
std::tie(ArraySize, Ty) = CGF.getVLASize(VAT);
|
||||||
|
Size = Size ? CGF.Builder.CreateNUWMul(Size, ArraySize) : ArraySize;
|
||||||
|
}
|
||||||
|
SizeInChars = C.getTypeSizeInChars(Ty);
|
||||||
|
assert(!SizeInChars.isZero());
|
||||||
|
Size = CGF.Builder.CreateNUWMul(
|
||||||
|
Size, llvm::ConstantInt::get(CGF.SizeTy, SizeInChars.getQuantity()));
|
||||||
|
} else
|
||||||
|
Size = llvm::ConstantInt::get(CGF.SizeTy, SizeInChars.getQuantity());
|
||||||
|
return Size;
|
||||||
|
}
|
||||||
|
|
||||||
llvm::Constant *CGOpenMPRuntime::createForStaticInitFunction(unsigned IVSize,
|
llvm::Constant *CGOpenMPRuntime::createForStaticInitFunction(unsigned IVSize,
|
||||||
bool IVSigned) {
|
bool IVSigned) {
|
||||||
assert((IVSize == 32 || IVSize == 64) &&
|
assert((IVSize == 32 || IVSize == 64) &&
|
||||||
|
@ -1438,17 +1458,16 @@ void CGOpenMPRuntime::emitTaskgroupRegion(CodeGenFunction &CGF,
|
||||||
|
|
||||||
/// Given an array of pointers to variables, project the address of a
|
/// Given an array of pointers to variables, project the address of a
|
||||||
/// given variable.
|
/// given variable.
|
||||||
static Address emitAddrOfVarFromArray(CodeGenFunction &CGF,
|
static Address emitAddrOfVarFromArray(CodeGenFunction &CGF, Address Array,
|
||||||
Address Array, unsigned Index,
|
unsigned Index, const VarDecl *Var) {
|
||||||
const VarDecl *Var) {
|
|
||||||
// Pull out the pointer to the variable.
|
// Pull out the pointer to the variable.
|
||||||
Address PtrAddr =
|
Address PtrAddr =
|
||||||
CGF.Builder.CreateConstArrayGEP(Array, Index, CGF.getPointerSize());
|
CGF.Builder.CreateConstArrayGEP(Array, Index, CGF.getPointerSize());
|
||||||
llvm::Value *Ptr = CGF.Builder.CreateLoad(PtrAddr);
|
llvm::Value *Ptr = CGF.Builder.CreateLoad(PtrAddr);
|
||||||
|
|
||||||
Address Addr = Address(Ptr, CGF.getContext().getDeclAlign(Var));
|
Address Addr = Address(Ptr, CGF.getContext().getDeclAlign(Var));
|
||||||
Addr = CGF.Builder.CreateElementBitCast(Addr,
|
Addr = CGF.Builder.CreateElementBitCast(
|
||||||
CGF.ConvertTypeForMem(Var->getType()));
|
Addr, CGF.ConvertTypeForMem(Var->getType()));
|
||||||
return Addr;
|
return Addr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1569,8 +1588,7 @@ void CGOpenMPRuntime::emitSingleRegion(CodeGenFunction &CGF,
|
||||||
auto *CpyFn = emitCopyprivateCopyFunction(
|
auto *CpyFn = emitCopyprivateCopyFunction(
|
||||||
CGM, CGF.ConvertTypeForMem(CopyprivateArrayTy)->getPointerTo(),
|
CGM, CGF.ConvertTypeForMem(CopyprivateArrayTy)->getPointerTo(),
|
||||||
CopyprivateVars, SrcExprs, DstExprs, AssignmentOps);
|
CopyprivateVars, SrcExprs, DstExprs, AssignmentOps);
|
||||||
auto *BufSize = llvm::ConstantInt::get(
|
auto *BufSize = getTypeSize(CGF, CopyprivateArrayTy);
|
||||||
CGM.SizeTy, C.getTypeSizeInChars(CopyprivateArrayTy).getQuantity());
|
|
||||||
Address CL =
|
Address CL =
|
||||||
CGF.Builder.CreatePointerBitCastOrAddrSpaceCast(CopyprivateList,
|
CGF.Builder.CreatePointerBitCastOrAddrSpaceCast(CopyprivateList,
|
||||||
CGF.VoidPtrTy);
|
CGF.VoidPtrTy);
|
||||||
|
@ -2199,27 +2217,6 @@ emitTaskPrivateMappingFunction(CodeGenModule &CGM, SourceLocation Loc,
|
||||||
return TaskPrivatesMap;
|
return TaskPrivatesMap;
|
||||||
}
|
}
|
||||||
|
|
||||||
static llvm::Value *getTypeSize(CodeGenFunction &CGF, QualType Ty) {
|
|
||||||
auto &C = CGF.getContext();
|
|
||||||
llvm::Value *Size;
|
|
||||||
auto SizeInChars = C.getTypeSizeInChars(Ty);
|
|
||||||
if (SizeInChars.isZero()) {
|
|
||||||
// getTypeSizeInChars() returns 0 for a VLA.
|
|
||||||
Size = nullptr;
|
|
||||||
while (auto *VAT = C.getAsVariableArrayType(Ty)) {
|
|
||||||
llvm::Value *ArraySize;
|
|
||||||
std::tie(ArraySize, Ty) = CGF.getVLASize(VAT);
|
|
||||||
Size = Size ? CGF.Builder.CreateNUWMul(Size, ArraySize) : ArraySize;
|
|
||||||
}
|
|
||||||
SizeInChars = C.getTypeSizeInChars(Ty);
|
|
||||||
assert(!SizeInChars.isZero());
|
|
||||||
Size = CGF.Builder.CreateNUWMul(
|
|
||||||
Size, llvm::ConstantInt::get(CGF.SizeTy, SizeInChars.getQuantity()));
|
|
||||||
} else
|
|
||||||
Size = llvm::ConstantInt::get(CGF.SizeTy, SizeInChars.getQuantity());
|
|
||||||
return Size;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int array_pod_sort_comparator(const PrivateDataTy *P1,
|
static int array_pod_sort_comparator(const PrivateDataTy *P1,
|
||||||
const PrivateDataTy *P2) {
|
const PrivateDataTy *P2) {
|
||||||
return P1->first < P2->first ? 1 : (P2->first < P1->first ? -1 : 0);
|
return P1->first < P2->first ? 1 : (P2->first < P1->first ? -1 : 0);
|
||||||
|
@ -2277,8 +2274,7 @@ void CGOpenMPRuntime::emitTaskCall(
|
||||||
C.getPointerType(KmpTaskTWithPrivatesQTy);
|
C.getPointerType(KmpTaskTWithPrivatesQTy);
|
||||||
auto *KmpTaskTWithPrivatesTy = CGF.ConvertType(KmpTaskTWithPrivatesQTy);
|
auto *KmpTaskTWithPrivatesTy = CGF.ConvertType(KmpTaskTWithPrivatesQTy);
|
||||||
auto *KmpTaskTWithPrivatesPtrTy = KmpTaskTWithPrivatesTy->getPointerTo();
|
auto *KmpTaskTWithPrivatesPtrTy = KmpTaskTWithPrivatesTy->getPointerTo();
|
||||||
auto KmpTaskTWithPrivatesTySize =
|
auto *KmpTaskTWithPrivatesTySize = getTypeSize(CGF, KmpTaskTWithPrivatesQTy);
|
||||||
CGM.getSize(C.getTypeSizeInChars(KmpTaskTWithPrivatesQTy));
|
|
||||||
QualType SharedsPtrTy = C.getPointerType(SharedsTy);
|
QualType SharedsPtrTy = C.getPointerType(SharedsTy);
|
||||||
|
|
||||||
// Emit initial values for private copies (if any).
|
// Emit initial values for private copies (if any).
|
||||||
|
@ -2319,12 +2315,12 @@ void CGOpenMPRuntime::emitTaskCall(
|
||||||
CGF.Builder.getInt32(/*C=*/0))
|
CGF.Builder.getInt32(/*C=*/0))
|
||||||
: CGF.Builder.getInt32(Final.getInt() ? FinalFlag : 0);
|
: CGF.Builder.getInt32(Final.getInt() ? FinalFlag : 0);
|
||||||
TaskFlags = CGF.Builder.CreateOr(TaskFlags, CGF.Builder.getInt32(Flags));
|
TaskFlags = CGF.Builder.CreateOr(TaskFlags, CGF.Builder.getInt32(Flags));
|
||||||
auto SharedsSize = C.getTypeSizeInChars(SharedsTy);
|
auto *SharedsSize = getTypeSize(CGF, SharedsTy);
|
||||||
llvm::Value *AllocArgs[] = {
|
llvm::Value *AllocArgs[] = {emitUpdateLocation(CGF, Loc),
|
||||||
emitUpdateLocation(CGF, Loc), getThreadID(CGF, Loc), TaskFlags,
|
getThreadID(CGF, Loc), TaskFlags,
|
||||||
KmpTaskTWithPrivatesTySize, CGM.getSize(SharedsSize),
|
KmpTaskTWithPrivatesTySize, SharedsSize,
|
||||||
CGF.Builder.CreatePointerBitCastOrAddrSpaceCast(TaskEntry,
|
CGF.Builder.CreatePointerBitCastOrAddrSpaceCast(
|
||||||
KmpRoutineEntryPtrTy)};
|
TaskEntry, KmpRoutineEntryPtrTy)};
|
||||||
auto *NewTask = CGF.EmitRuntimeCall(
|
auto *NewTask = CGF.EmitRuntimeCall(
|
||||||
createRuntimeFunction(OMPRTL__kmpc_omp_task_alloc), AllocArgs);
|
createRuntimeFunction(OMPRTL__kmpc_omp_task_alloc), AllocArgs);
|
||||||
auto *NewTaskNewTaskTTy = CGF.Builder.CreatePointerBitCastOrAddrSpaceCast(
|
auto *NewTaskNewTaskTTy = CGF.Builder.CreatePointerBitCastOrAddrSpaceCast(
|
||||||
|
@ -2442,8 +2438,8 @@ void CGOpenMPRuntime::emitTaskCall(
|
||||||
enum RTLDependenceKindTy { DepIn = 1, DepOut = 2, DepInOut = 3 };
|
enum RTLDependenceKindTy { DepIn = 1, DepOut = 2, DepInOut = 3 };
|
||||||
enum RTLDependInfoFieldsTy { BaseAddr, Len, Flags };
|
enum RTLDependInfoFieldsTy { BaseAddr, Len, Flags };
|
||||||
RecordDecl *KmpDependInfoRD;
|
RecordDecl *KmpDependInfoRD;
|
||||||
QualType FlagsTy = C.getIntTypeForBitwidth(
|
QualType FlagsTy =
|
||||||
C.toBits(C.getTypeSizeInChars(C.BoolTy)), /*Signed=*/false);
|
C.getIntTypeForBitwidth(C.getTypeSize(C.BoolTy), /*Signed=*/false);
|
||||||
llvm::Type *LLVMFlagsTy = CGF.ConvertTypeForMem(FlagsTy);
|
llvm::Type *LLVMFlagsTy = CGF.ConvertTypeForMem(FlagsTy);
|
||||||
if (KmpDependInfoTy.isNull()) {
|
if (KmpDependInfoTy.isNull()) {
|
||||||
KmpDependInfoRD = C.buildImplicitRecord("kmp_depend_info");
|
KmpDependInfoRD = C.buildImplicitRecord("kmp_depend_info");
|
||||||
|
@ -2477,9 +2473,8 @@ void CGOpenMPRuntime::emitTaskCall(
|
||||||
CGF.Builder.CreatePtrToInt(Addr.getPointer(), CGM.SizeTy);
|
CGF.Builder.CreatePtrToInt(Addr.getPointer(), CGM.SizeTy);
|
||||||
llvm::Value *UpIntPtr = CGF.Builder.CreatePtrToInt(UpAddr, CGM.SizeTy);
|
llvm::Value *UpIntPtr = CGF.Builder.CreatePtrToInt(UpAddr, CGM.SizeTy);
|
||||||
Size = CGF.Builder.CreateNUWSub(UpIntPtr, LowIntPtr);
|
Size = CGF.Builder.CreateNUWSub(UpIntPtr, LowIntPtr);
|
||||||
} else {
|
} else
|
||||||
Size = getTypeSize(CGF, Ty);
|
Size = getTypeSize(CGF, Ty);
|
||||||
}
|
|
||||||
auto Base = CGF.MakeAddrLValue(
|
auto Base = CGF.MakeAddrLValue(
|
||||||
CGF.Builder.CreateConstArrayGEP(DependenciesArray, i, DependencySize),
|
CGF.Builder.CreateConstArrayGEP(DependenciesArray, i, DependencySize),
|
||||||
KmpDependInfoTy);
|
KmpDependInfoTy);
|
||||||
|
@ -2596,8 +2591,89 @@ void CGOpenMPRuntime::emitTaskCall(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// \brief Emit reduction operation for each element of array (required for
|
||||||
|
/// array sections) LHS op = RHS.
|
||||||
|
/// \param Type Type of array.
|
||||||
|
/// \param LHSVar Variable on the left side of the reduction operation
|
||||||
|
/// (references element of array in original variable).
|
||||||
|
/// \param RHSVar Variable on the right side of the reduction operation
|
||||||
|
/// (references element of array in original variable).
|
||||||
|
/// \param RedOpGen Generator of reduction operation with use of LHSVar and
|
||||||
|
/// RHSVar.
|
||||||
|
void EmitOMPAggregateReduction(
|
||||||
|
CodeGenFunction &CGF, QualType Type, const VarDecl *LHSVar,
|
||||||
|
const VarDecl *RHSVar,
|
||||||
|
const llvm::function_ref<void(CodeGenFunction &CGF, const Expr *,
|
||||||
|
const Expr *, const Expr *)> &RedOpGen,
|
||||||
|
const Expr *XExpr = nullptr, const Expr *EExpr = nullptr,
|
||||||
|
const Expr *UpExpr = nullptr) {
|
||||||
|
// Perform element-by-element initialization.
|
||||||
|
QualType ElementTy;
|
||||||
|
Address LHSAddr = CGF.GetAddrOfLocalVar(LHSVar);
|
||||||
|
Address RHSAddr = CGF.GetAddrOfLocalVar(RHSVar);
|
||||||
|
|
||||||
|
// Drill down to the base element type on both arrays.
|
||||||
|
auto ArrayTy = Type->getAsArrayTypeUnsafe();
|
||||||
|
auto NumElements = CGF.emitArrayLength(ArrayTy, ElementTy, LHSAddr);
|
||||||
|
|
||||||
|
auto RHSBegin = RHSAddr.getPointer();
|
||||||
|
auto LHSBegin = LHSAddr.getPointer();
|
||||||
|
// Cast from pointer to array type to pointer to single element.
|
||||||
|
auto LHSEnd = CGF.Builder.CreateGEP(LHSBegin, NumElements);
|
||||||
|
// The basic structure here is a while-do loop.
|
||||||
|
auto BodyBB = CGF.createBasicBlock("omp.arraycpy.body");
|
||||||
|
auto DoneBB = CGF.createBasicBlock("omp.arraycpy.done");
|
||||||
|
auto IsEmpty =
|
||||||
|
CGF.Builder.CreateICmpEQ(LHSBegin, LHSEnd, "omp.arraycpy.isempty");
|
||||||
|
CGF.Builder.CreateCondBr(IsEmpty, DoneBB, BodyBB);
|
||||||
|
|
||||||
|
// Enter the loop body, making that address the current address.
|
||||||
|
auto EntryBB = CGF.Builder.GetInsertBlock();
|
||||||
|
CGF.EmitBlock(BodyBB);
|
||||||
|
|
||||||
|
CharUnits ElementSize = CGF.getContext().getTypeSizeInChars(ElementTy);
|
||||||
|
|
||||||
|
llvm::PHINode *RHSElementPHI = CGF.Builder.CreatePHI(
|
||||||
|
RHSBegin->getType(), 2, "omp.arraycpy.srcElementPast");
|
||||||
|
RHSElementPHI->addIncoming(RHSBegin, EntryBB);
|
||||||
|
Address RHSElementCurrent =
|
||||||
|
Address(RHSElementPHI,
|
||||||
|
RHSAddr.getAlignment().alignmentOfArrayElement(ElementSize));
|
||||||
|
|
||||||
|
llvm::PHINode *LHSElementPHI = CGF.Builder.CreatePHI(
|
||||||
|
LHSBegin->getType(), 2, "omp.arraycpy.destElementPast");
|
||||||
|
LHSElementPHI->addIncoming(LHSBegin, EntryBB);
|
||||||
|
Address LHSElementCurrent =
|
||||||
|
Address(LHSElementPHI,
|
||||||
|
LHSAddr.getAlignment().alignmentOfArrayElement(ElementSize));
|
||||||
|
|
||||||
|
// Emit copy.
|
||||||
|
CodeGenFunction::OMPPrivateScope Scope(CGF);
|
||||||
|
Scope.addPrivate(LHSVar, [=]() -> Address { return LHSElementCurrent; });
|
||||||
|
Scope.addPrivate(RHSVar, [=]() -> Address { return RHSElementCurrent; });
|
||||||
|
Scope.Privatize();
|
||||||
|
RedOpGen(CGF, XExpr, EExpr, UpExpr);
|
||||||
|
Scope.ForceCleanup();
|
||||||
|
|
||||||
|
// Shift the address forward by one element.
|
||||||
|
auto LHSElementNext = CGF.Builder.CreateConstGEP1_32(
|
||||||
|
LHSElementPHI, /*Idx0=*/1, "omp.arraycpy.dest.element");
|
||||||
|
auto RHSElementNext = CGF.Builder.CreateConstGEP1_32(
|
||||||
|
RHSElementPHI, /*Idx0=*/1, "omp.arraycpy.src.element");
|
||||||
|
// Check whether we've reached the end.
|
||||||
|
auto Done =
|
||||||
|
CGF.Builder.CreateICmpEQ(LHSElementNext, LHSEnd, "omp.arraycpy.done");
|
||||||
|
CGF.Builder.CreateCondBr(Done, DoneBB, BodyBB);
|
||||||
|
LHSElementPHI->addIncoming(LHSElementNext, CGF.Builder.GetInsertBlock());
|
||||||
|
RHSElementPHI->addIncoming(RHSElementNext, CGF.Builder.GetInsertBlock());
|
||||||
|
|
||||||
|
// Done.
|
||||||
|
CGF.EmitBlock(DoneBB, /*IsFinished=*/true);
|
||||||
|
}
|
||||||
|
|
||||||
static llvm::Value *emitReductionFunction(CodeGenModule &CGM,
|
static llvm::Value *emitReductionFunction(CodeGenModule &CGM,
|
||||||
llvm::Type *ArgsType,
|
llvm::Type *ArgsType,
|
||||||
|
ArrayRef<const Expr *> Privates,
|
||||||
ArrayRef<const Expr *> LHSExprs,
|
ArrayRef<const Expr *> LHSExprs,
|
||||||
ArrayRef<const Expr *> RHSExprs,
|
ArrayRef<const Expr *> RHSExprs,
|
||||||
ArrayRef<const Expr *> ReductionOps) {
|
ArrayRef<const Expr *> ReductionOps) {
|
||||||
|
@ -2634,19 +2710,49 @@ static llvm::Value *emitReductionFunction(CodeGenModule &CGM,
|
||||||
// *(Type<i>*)lhs[i] = RedOp<i>(*(Type<i>*)lhs[i], *(Type<i>*)rhs[i]);
|
// *(Type<i>*)lhs[i] = RedOp<i>(*(Type<i>*)lhs[i], *(Type<i>*)rhs[i]);
|
||||||
// ...
|
// ...
|
||||||
CodeGenFunction::OMPPrivateScope Scope(CGF);
|
CodeGenFunction::OMPPrivateScope Scope(CGF);
|
||||||
for (unsigned I = 0, E = ReductionOps.size(); I < E; ++I) {
|
auto IPriv = Privates.begin();
|
||||||
|
unsigned Idx = 0;
|
||||||
|
for (unsigned I = 0, E = ReductionOps.size(); I < E; ++I, ++IPriv, ++Idx) {
|
||||||
auto RHSVar = cast<VarDecl>(cast<DeclRefExpr>(RHSExprs[I])->getDecl());
|
auto RHSVar = cast<VarDecl>(cast<DeclRefExpr>(RHSExprs[I])->getDecl());
|
||||||
Scope.addPrivate(RHSVar, [&]() -> Address {
|
Scope.addPrivate(RHSVar, [&]() -> Address {
|
||||||
return emitAddrOfVarFromArray(CGF, RHS, I, RHSVar);
|
return emitAddrOfVarFromArray(CGF, RHS, Idx, RHSVar);
|
||||||
});
|
});
|
||||||
auto LHSVar = cast<VarDecl>(cast<DeclRefExpr>(LHSExprs[I])->getDecl());
|
auto LHSVar = cast<VarDecl>(cast<DeclRefExpr>(LHSExprs[I])->getDecl());
|
||||||
Scope.addPrivate(LHSVar, [&]() -> Address {
|
Scope.addPrivate(LHSVar, [&]() -> Address {
|
||||||
return emitAddrOfVarFromArray(CGF, LHS, I, LHSVar);
|
return emitAddrOfVarFromArray(CGF, LHS, Idx, LHSVar);
|
||||||
});
|
});
|
||||||
|
QualType PrivTy = (*IPriv)->getType();
|
||||||
|
if (PrivTy->isArrayType()) {
|
||||||
|
// Get array size and emit VLA type.
|
||||||
|
++Idx;
|
||||||
|
Address Elem =
|
||||||
|
CGF.Builder.CreateConstArrayGEP(LHS, Idx, CGF.getPointerSize());
|
||||||
|
llvm::Value *Ptr = CGF.Builder.CreateLoad(Elem);
|
||||||
|
CodeGenFunction::OpaqueValueMapping OpaqueMap(
|
||||||
|
CGF,
|
||||||
|
cast<OpaqueValueExpr>(
|
||||||
|
CGF.getContext().getAsVariableArrayType(PrivTy)->getSizeExpr()),
|
||||||
|
RValue::get(CGF.Builder.CreatePtrToInt(Ptr, CGF.SizeTy)));
|
||||||
|
CGF.EmitVariablyModifiedType(PrivTy);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Scope.Privatize();
|
Scope.Privatize();
|
||||||
|
IPriv = Privates.begin();
|
||||||
|
auto ILHS = LHSExprs.begin();
|
||||||
|
auto IRHS = RHSExprs.begin();
|
||||||
for (auto *E : ReductionOps) {
|
for (auto *E : ReductionOps) {
|
||||||
CGF.EmitIgnoredExpr(E);
|
if ((*IPriv)->getType()->isArrayType()) {
|
||||||
|
// Emit reduction for array section.
|
||||||
|
auto *LHSVar = cast<VarDecl>(cast<DeclRefExpr>(*ILHS)->getDecl());
|
||||||
|
auto *RHSVar = cast<VarDecl>(cast<DeclRefExpr>(*IRHS)->getDecl());
|
||||||
|
EmitOMPAggregateReduction(CGF, (*IPriv)->getType(), LHSVar, RHSVar,
|
||||||
|
[=](CodeGenFunction &CGF, const Expr *,
|
||||||
|
const Expr *,
|
||||||
|
const Expr *) { CGF.EmitIgnoredExpr(E); });
|
||||||
|
} else
|
||||||
|
// Emit reduction for array subscript or single variable.
|
||||||
|
CGF.EmitIgnoredExpr(E);
|
||||||
|
++IPriv, ++ILHS, ++IRHS;
|
||||||
}
|
}
|
||||||
Scope.ForceCleanup();
|
Scope.ForceCleanup();
|
||||||
CGF.FinishFunction();
|
CGF.FinishFunction();
|
||||||
|
@ -2654,6 +2760,7 @@ static llvm::Value *emitReductionFunction(CodeGenModule &CGM,
|
||||||
}
|
}
|
||||||
|
|
||||||
void CGOpenMPRuntime::emitReduction(CodeGenFunction &CGF, SourceLocation Loc,
|
void CGOpenMPRuntime::emitReduction(CodeGenFunction &CGF, SourceLocation Loc,
|
||||||
|
ArrayRef<const Expr *> Privates,
|
||||||
ArrayRef<const Expr *> LHSExprs,
|
ArrayRef<const Expr *> LHSExprs,
|
||||||
ArrayRef<const Expr *> RHSExprs,
|
ArrayRef<const Expr *> RHSExprs,
|
||||||
ArrayRef<const Expr *> ReductionOps,
|
ArrayRef<const Expr *> ReductionOps,
|
||||||
|
@ -2697,33 +2804,68 @@ void CGOpenMPRuntime::emitReduction(CodeGenFunction &CGF, SourceLocation Loc,
|
||||||
|
|
||||||
if (SimpleReduction) {
|
if (SimpleReduction) {
|
||||||
CodeGenFunction::RunCleanupsScope Scope(CGF);
|
CodeGenFunction::RunCleanupsScope Scope(CGF);
|
||||||
|
auto IPriv = Privates.begin();
|
||||||
|
auto ILHS = LHSExprs.begin();
|
||||||
|
auto IRHS = RHSExprs.begin();
|
||||||
for (auto *E : ReductionOps) {
|
for (auto *E : ReductionOps) {
|
||||||
CGF.EmitIgnoredExpr(E);
|
if ((*IPriv)->getType()->isArrayType()) {
|
||||||
|
auto *LHSVar = cast<VarDecl>(cast<DeclRefExpr>(*ILHS)->getDecl());
|
||||||
|
auto *RHSVar = cast<VarDecl>(cast<DeclRefExpr>(*IRHS)->getDecl());
|
||||||
|
EmitOMPAggregateReduction(
|
||||||
|
CGF, (*IPriv)->getType(), LHSVar, RHSVar,
|
||||||
|
[=](CodeGenFunction &CGF, const Expr *, const Expr *,
|
||||||
|
const Expr *) { CGF.EmitIgnoredExpr(E); });
|
||||||
|
} else
|
||||||
|
CGF.EmitIgnoredExpr(E);
|
||||||
|
++IPriv, ++ILHS, ++IRHS;
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 1. Build a list of reduction variables.
|
// 1. Build a list of reduction variables.
|
||||||
// void *RedList[<n>] = {<ReductionVars>[0], ..., <ReductionVars>[<n>-1]};
|
// void *RedList[<n>] = {<ReductionVars>[0], ..., <ReductionVars>[<n>-1]};
|
||||||
llvm::APInt ArraySize(/*unsigned int numBits=*/32, RHSExprs.size());
|
auto Size = RHSExprs.size();
|
||||||
|
for (auto *E : Privates) {
|
||||||
|
if (E->getType()->isArrayType())
|
||||||
|
// Reserve place for array size.
|
||||||
|
++Size;
|
||||||
|
}
|
||||||
|
llvm::APInt ArraySize(/*unsigned int numBits=*/32, Size);
|
||||||
QualType ReductionArrayTy =
|
QualType ReductionArrayTy =
|
||||||
C.getConstantArrayType(C.VoidPtrTy, ArraySize, ArrayType::Normal,
|
C.getConstantArrayType(C.VoidPtrTy, ArraySize, ArrayType::Normal,
|
||||||
/*IndexTypeQuals=*/0);
|
/*IndexTypeQuals=*/0);
|
||||||
Address ReductionList =
|
Address ReductionList =
|
||||||
CGF.CreateMemTemp(ReductionArrayTy, ".omp.reduction.red_list");
|
CGF.CreateMemTemp(ReductionArrayTy, ".omp.reduction.red_list");
|
||||||
for (unsigned I = 0, E = RHSExprs.size(); I < E; ++I) {
|
auto IPriv = Privates.begin();
|
||||||
|
unsigned Idx = 0;
|
||||||
|
for (unsigned I = 0, E = RHSExprs.size(); I < E; ++I, ++IPriv, ++Idx) {
|
||||||
Address Elem =
|
Address Elem =
|
||||||
CGF.Builder.CreateConstArrayGEP(ReductionList, I, CGF.getPointerSize());
|
CGF.Builder.CreateConstArrayGEP(ReductionList, Idx, CGF.getPointerSize());
|
||||||
CGF.Builder.CreateStore(
|
CGF.Builder.CreateStore(
|
||||||
CGF.Builder.CreatePointerBitCastOrAddrSpaceCast(
|
CGF.Builder.CreatePointerBitCastOrAddrSpaceCast(
|
||||||
CGF.EmitLValue(RHSExprs[I]).getPointer(), CGF.VoidPtrTy),
|
CGF.EmitLValue(RHSExprs[I]).getPointer(), CGF.VoidPtrTy),
|
||||||
Elem);
|
Elem);
|
||||||
|
if ((*IPriv)->getType()->isArrayType()) {
|
||||||
|
// Store array size.
|
||||||
|
++Idx;
|
||||||
|
Elem = CGF.Builder.CreateConstArrayGEP(ReductionList, Idx,
|
||||||
|
CGF.getPointerSize());
|
||||||
|
CGF.Builder.CreateStore(
|
||||||
|
CGF.Builder.CreateIntToPtr(
|
||||||
|
CGF.Builder.CreateIntCast(
|
||||||
|
CGF.getVLASize(CGF.getContext().getAsVariableArrayType(
|
||||||
|
(*IPriv)->getType()))
|
||||||
|
.first,
|
||||||
|
CGF.SizeTy, /*isSigned=*/false),
|
||||||
|
CGF.VoidPtrTy),
|
||||||
|
Elem);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 2. Emit reduce_func().
|
// 2. Emit reduce_func().
|
||||||
auto *ReductionFn = emitReductionFunction(
|
auto *ReductionFn = emitReductionFunction(
|
||||||
CGM, CGF.ConvertTypeForMem(ReductionArrayTy)->getPointerTo(), LHSExprs,
|
CGM, CGF.ConvertTypeForMem(ReductionArrayTy)->getPointerTo(), Privates,
|
||||||
RHSExprs, ReductionOps);
|
LHSExprs, RHSExprs, ReductionOps);
|
||||||
|
|
||||||
// 3. Create static kmp_critical_name lock = { 0 };
|
// 3. Create static kmp_critical_name lock = { 0 };
|
||||||
auto *Lock = getCriticalRegionLock(".reduction");
|
auto *Lock = getCriticalRegionLock(".reduction");
|
||||||
|
@ -2734,8 +2876,7 @@ void CGOpenMPRuntime::emitReduction(CodeGenFunction &CGF, SourceLocation Loc,
|
||||||
CGF, Loc,
|
CGF, Loc,
|
||||||
static_cast<OpenMPLocationFlags>(OMP_IDENT_KMPC | OMP_ATOMIC_REDUCE));
|
static_cast<OpenMPLocationFlags>(OMP_IDENT_KMPC | OMP_ATOMIC_REDUCE));
|
||||||
auto *ThreadId = getThreadID(CGF, Loc);
|
auto *ThreadId = getThreadID(CGF, Loc);
|
||||||
auto *ReductionArrayTySize = llvm::ConstantInt::get(
|
auto *ReductionArrayTySize = getTypeSize(CGF, ReductionArrayTy);
|
||||||
CGM.SizeTy, C.getTypeSizeInChars(ReductionArrayTy).getQuantity());
|
|
||||||
auto *RL =
|
auto *RL =
|
||||||
CGF.Builder.CreatePointerBitCastOrAddrSpaceCast(ReductionList.getPointer(),
|
CGF.Builder.CreatePointerBitCastOrAddrSpaceCast(ReductionList.getPointer(),
|
||||||
CGF.VoidPtrTy);
|
CGF.VoidPtrTy);
|
||||||
|
@ -2781,8 +2922,22 @@ void CGOpenMPRuntime::emitReduction(CodeGenFunction &CGF, SourceLocation Loc,
|
||||||
createRuntimeFunction(WithNowait ? OMPRTL__kmpc_end_reduce_nowait
|
createRuntimeFunction(WithNowait ? OMPRTL__kmpc_end_reduce_nowait
|
||||||
: OMPRTL__kmpc_end_reduce),
|
: OMPRTL__kmpc_end_reduce),
|
||||||
llvm::makeArrayRef(EndArgs));
|
llvm::makeArrayRef(EndArgs));
|
||||||
|
auto IPriv = Privates.begin();
|
||||||
|
auto ILHS = LHSExprs.begin();
|
||||||
|
auto IRHS = RHSExprs.begin();
|
||||||
for (auto *E : ReductionOps) {
|
for (auto *E : ReductionOps) {
|
||||||
CGF.EmitIgnoredExpr(E);
|
if ((*IPriv)->getType()->isArrayType()) {
|
||||||
|
// Emit reduction for array section.
|
||||||
|
auto *LHSVar = cast<VarDecl>(cast<DeclRefExpr>(*ILHS)->getDecl());
|
||||||
|
auto *RHSVar = cast<VarDecl>(cast<DeclRefExpr>(*IRHS)->getDecl());
|
||||||
|
EmitOMPAggregateReduction(
|
||||||
|
CGF, (*IPriv)->getType(), LHSVar, RHSVar,
|
||||||
|
[=](CodeGenFunction &CGF, const Expr *, const Expr *,
|
||||||
|
const Expr *) { CGF.EmitIgnoredExpr(E); });
|
||||||
|
} else
|
||||||
|
// Emit reduction for array subscript or single variable.
|
||||||
|
CGF.EmitIgnoredExpr(E);
|
||||||
|
++IPriv, ++ILHS, ++IRHS;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2812,62 +2967,84 @@ void CGOpenMPRuntime::emitReduction(CodeGenFunction &CGF, SourceLocation Loc,
|
||||||
createRuntimeFunction(OMPRTL__kmpc_end_reduce),
|
createRuntimeFunction(OMPRTL__kmpc_end_reduce),
|
||||||
llvm::makeArrayRef(EndArgs));
|
llvm::makeArrayRef(EndArgs));
|
||||||
}
|
}
|
||||||
auto I = LHSExprs.begin();
|
auto ILHS = LHSExprs.begin();
|
||||||
|
auto IRHS = RHSExprs.begin();
|
||||||
|
auto IPriv = Privates.begin();
|
||||||
for (auto *E : ReductionOps) {
|
for (auto *E : ReductionOps) {
|
||||||
const Expr *XExpr = nullptr;
|
const Expr *XExpr = nullptr;
|
||||||
const Expr *EExpr = nullptr;
|
const Expr *EExpr = nullptr;
|
||||||
const Expr *UpExpr = nullptr;
|
const Expr *UpExpr = nullptr;
|
||||||
BinaryOperatorKind BO = BO_Comma;
|
BinaryOperatorKind BO = BO_Comma;
|
||||||
if (auto *BO = dyn_cast<BinaryOperator>(E)) {
|
if (auto *BO = dyn_cast<BinaryOperator>(E)) {
|
||||||
if (BO->getOpcode() == BO_Assign) {
|
if (BO->getOpcode() == BO_Assign) {
|
||||||
XExpr = BO->getLHS();
|
XExpr = BO->getLHS();
|
||||||
UpExpr = BO->getRHS();
|
UpExpr = BO->getRHS();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
// Try to emit update expression as a simple atomic.
|
||||||
// Try to emit update expression as a simple atomic.
|
auto *RHSExpr = UpExpr;
|
||||||
auto *RHSExpr = UpExpr;
|
if (RHSExpr) {
|
||||||
if (RHSExpr) {
|
// Analyze RHS part of the whole expression.
|
||||||
// Analyze RHS part of the whole expression.
|
if (auto *ACO = dyn_cast<AbstractConditionalOperator>(
|
||||||
if (auto *ACO = dyn_cast<AbstractConditionalOperator>(
|
RHSExpr->IgnoreParenImpCasts())) {
|
||||||
RHSExpr->IgnoreParenImpCasts())) {
|
// If this is a conditional operator, analyze its condition for
|
||||||
// If this is a conditional operator, analyze its condition for
|
// min/max reduction operator.
|
||||||
// min/max reduction operator.
|
RHSExpr = ACO->getCond();
|
||||||
RHSExpr = ACO->getCond();
|
}
|
||||||
|
if (auto *BORHS =
|
||||||
|
dyn_cast<BinaryOperator>(RHSExpr->IgnoreParenImpCasts())) {
|
||||||
|
EExpr = BORHS->getRHS();
|
||||||
|
BO = BORHS->getOpcode();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (auto *BORHS =
|
if (XExpr) {
|
||||||
dyn_cast<BinaryOperator>(RHSExpr->IgnoreParenImpCasts())) {
|
auto *VD = cast<VarDecl>(cast<DeclRefExpr>(*ILHS)->getDecl());
|
||||||
EExpr = BORHS->getRHS();
|
auto &&AtomicRedGen = [this, BO, VD, IPriv,
|
||||||
BO = BORHS->getOpcode();
|
Loc](CodeGenFunction &CGF, const Expr *XExpr,
|
||||||
}
|
const Expr *EExpr, const Expr *UpExpr) {
|
||||||
}
|
LValue X = CGF.EmitLValue(XExpr);
|
||||||
if (XExpr) {
|
RValue E;
|
||||||
auto *VD = cast<VarDecl>(cast<DeclRefExpr>(*I)->getDecl());
|
if (EExpr)
|
||||||
LValue X = CGF.EmitLValue(XExpr);
|
E = CGF.EmitAnyExpr(EExpr);
|
||||||
RValue E;
|
CGF.EmitOMPAtomicSimpleUpdateExpr(
|
||||||
if (EExpr)
|
X, E, BO, /*IsXLHSInRHSPart=*/true, llvm::Monotonic, Loc,
|
||||||
E = CGF.EmitAnyExpr(EExpr);
|
[&CGF, UpExpr, VD, IPriv](RValue XRValue) {
|
||||||
CGF.EmitOMPAtomicSimpleUpdateExpr(
|
CodeGenFunction::OMPPrivateScope PrivateScope(CGF);
|
||||||
X, E, BO, /*IsXLHSInRHSPart=*/true, llvm::Monotonic, Loc,
|
PrivateScope.addPrivate(VD, [&CGF, VD, XRValue]() -> Address {
|
||||||
[&CGF, UpExpr, VD](RValue XRValue) {
|
|
||||||
CodeGenFunction::OMPPrivateScope PrivateScope(CGF);
|
|
||||||
PrivateScope.addPrivate(
|
|
||||||
VD, [&CGF, VD, XRValue]() -> Address {
|
|
||||||
Address LHSTemp = CGF.CreateMemTemp(VD->getType());
|
Address LHSTemp = CGF.CreateMemTemp(VD->getType());
|
||||||
CGF.EmitStoreThroughLValue(
|
CGF.EmitStoreThroughLValue(
|
||||||
XRValue,
|
XRValue, CGF.MakeAddrLValue(LHSTemp, VD->getType()));
|
||||||
CGF.MakeAddrLValue(LHSTemp, VD->getType()));
|
|
||||||
return LHSTemp;
|
return LHSTemp;
|
||||||
});
|
});
|
||||||
(void)PrivateScope.Privatize();
|
(void)PrivateScope.Privatize();
|
||||||
return CGF.EmitAnyExpr(UpExpr);
|
return CGF.EmitAnyExpr(UpExpr);
|
||||||
});
|
});
|
||||||
} else {
|
};
|
||||||
// Emit as a critical region.
|
if ((*IPriv)->getType()->isArrayType()) {
|
||||||
emitCriticalRegion(CGF, ".atomic_reduction", [E](CodeGenFunction &CGF) {
|
// Emit atomic reduction for array section.
|
||||||
CGF.EmitIgnoredExpr(E);
|
auto *RHSVar = cast<VarDecl>(cast<DeclRefExpr>(*IRHS)->getDecl());
|
||||||
}, Loc);
|
EmitOMPAggregateReduction(CGF, (*IPriv)->getType(), VD, RHSVar,
|
||||||
}
|
AtomicRedGen, XExpr, EExpr, UpExpr);
|
||||||
++I;
|
} else
|
||||||
|
// Emit atomic reduction for array subscript or single variable.
|
||||||
|
AtomicRedGen(CGF, XExpr, EExpr, UpExpr);
|
||||||
|
} else {
|
||||||
|
// Emit as a critical region.
|
||||||
|
auto &&CritRedGen = [this, E, Loc](CodeGenFunction &CGF, const Expr *,
|
||||||
|
const Expr *, const Expr *) {
|
||||||
|
emitCriticalRegion(
|
||||||
|
CGF, ".atomic_reduction",
|
||||||
|
[E](CodeGenFunction &CGF) { CGF.EmitIgnoredExpr(E); }, Loc);
|
||||||
|
};
|
||||||
|
if ((*IPriv)->getType()->isArrayType()) {
|
||||||
|
auto *LHSVar = cast<VarDecl>(cast<DeclRefExpr>(*ILHS)->getDecl());
|
||||||
|
auto *RHSVar = cast<VarDecl>(cast<DeclRefExpr>(*IRHS)->getDecl());
|
||||||
|
EmitOMPAggregateReduction(CGF, (*IPriv)->getType(), LHSVar, RHSVar,
|
||||||
|
CritRedGen);
|
||||||
|
} else
|
||||||
|
CritRedGen(CGF, nullptr, nullptr, nullptr);
|
||||||
|
}
|
||||||
|
++ILHS, ++IRHS, ++IPriv;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -702,6 +702,7 @@ public:
|
||||||
/// }
|
/// }
|
||||||
/// \endcode
|
/// \endcode
|
||||||
///
|
///
|
||||||
|
/// \param Privates List of private copies for original reduction arguments.
|
||||||
/// \param LHSExprs List of LHS in \a ReductionOps reduction operations.
|
/// \param LHSExprs List of LHS in \a ReductionOps reduction operations.
|
||||||
/// \param RHSExprs List of RHS 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'
|
/// \param ReductionOps List of reduction operations in form 'LHS binop RHS'
|
||||||
|
@ -709,6 +710,7 @@ public:
|
||||||
/// \param WithNowait true if parent directive has also nowait clause, false
|
/// \param WithNowait true if parent directive has also nowait clause, false
|
||||||
/// otherwise.
|
/// otherwise.
|
||||||
virtual void emitReduction(CodeGenFunction &CGF, SourceLocation Loc,
|
virtual void emitReduction(CodeGenFunction &CGF, SourceLocation Loc,
|
||||||
|
ArrayRef<const Expr *> Privates,
|
||||||
ArrayRef<const Expr *> LHSExprs,
|
ArrayRef<const Expr *> LHSExprs,
|
||||||
ArrayRef<const Expr *> RHSExprs,
|
ArrayRef<const Expr *> RHSExprs,
|
||||||
ArrayRef<const Expr *> ReductionOps,
|
ArrayRef<const Expr *> ReductionOps,
|
||||||
|
|
|
@ -212,6 +212,65 @@ void CodeGenFunction::EmitOMPAggregateAssign(
|
||||||
EmitBlock(DoneBB, /*IsFinished=*/true);
|
EmitBlock(DoneBB, /*IsFinished=*/true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// \brief Emit initialization of arrays of complex types.
|
||||||
|
/// \param Type Type of array.
|
||||||
|
/// \param DestAddr Address of the array.
|
||||||
|
/// \param Type Type of array.
|
||||||
|
/// \param Init Initial expression of array.
|
||||||
|
static void EmitOMPAggregateInit(CodeGenFunction &CGF, Address DestAddr,
|
||||||
|
QualType Type, const Expr *Init) {
|
||||||
|
// Perform element-by-element initialization.
|
||||||
|
QualType ElementTy;
|
||||||
|
|
||||||
|
// Drill down to the base element type on both arrays.
|
||||||
|
auto ArrayTy = Type->getAsArrayTypeUnsafe();
|
||||||
|
auto NumElements = CGF.emitArrayLength(ArrayTy, ElementTy, DestAddr);
|
||||||
|
DestAddr =
|
||||||
|
CGF.Builder.CreateElementBitCast(DestAddr, DestAddr.getElementType());
|
||||||
|
|
||||||
|
auto DestBegin = DestAddr.getPointer();
|
||||||
|
// Cast from pointer to array type to pointer to single element.
|
||||||
|
auto DestEnd = CGF.Builder.CreateGEP(DestBegin, NumElements);
|
||||||
|
// The basic structure here is a while-do loop.
|
||||||
|
auto BodyBB = CGF.createBasicBlock("omp.arrayinit.body");
|
||||||
|
auto DoneBB = CGF.createBasicBlock("omp.arrayinit.done");
|
||||||
|
auto IsEmpty =
|
||||||
|
CGF.Builder.CreateICmpEQ(DestBegin, DestEnd, "omp.arrayinit.isempty");
|
||||||
|
CGF.Builder.CreateCondBr(IsEmpty, DoneBB, BodyBB);
|
||||||
|
|
||||||
|
// Enter the loop body, making that address the current address.
|
||||||
|
auto EntryBB = CGF.Builder.GetInsertBlock();
|
||||||
|
CGF.EmitBlock(BodyBB);
|
||||||
|
|
||||||
|
CharUnits ElementSize = CGF.getContext().getTypeSizeInChars(ElementTy);
|
||||||
|
|
||||||
|
llvm::PHINode *DestElementPHI = CGF.Builder.CreatePHI(
|
||||||
|
DestBegin->getType(), 2, "omp.arraycpy.destElementPast");
|
||||||
|
DestElementPHI->addIncoming(DestBegin, EntryBB);
|
||||||
|
Address DestElementCurrent =
|
||||||
|
Address(DestElementPHI,
|
||||||
|
DestAddr.getAlignment().alignmentOfArrayElement(ElementSize));
|
||||||
|
|
||||||
|
// Emit copy.
|
||||||
|
{
|
||||||
|
CodeGenFunction::RunCleanupsScope InitScope(CGF);
|
||||||
|
CGF.EmitAnyExprToMem(Init, DestElementCurrent, ElementTy.getQualifiers(),
|
||||||
|
/*IsInitializer=*/false);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Shift the address forward by one element.
|
||||||
|
auto DestElementNext = CGF.Builder.CreateConstGEP1_32(
|
||||||
|
DestElementPHI, /*Idx0=*/1, "omp.arraycpy.dest.element");
|
||||||
|
// Check whether we've reached the end.
|
||||||
|
auto Done =
|
||||||
|
CGF.Builder.CreateICmpEQ(DestElementNext, DestEnd, "omp.arraycpy.done");
|
||||||
|
CGF.Builder.CreateCondBr(Done, DoneBB, BodyBB);
|
||||||
|
DestElementPHI->addIncoming(DestElementNext, CGF.Builder.GetInsertBlock());
|
||||||
|
|
||||||
|
// Done.
|
||||||
|
CGF.EmitBlock(DoneBB, /*IsFinished=*/true);
|
||||||
|
}
|
||||||
|
|
||||||
void CodeGenFunction::EmitOMPCopy(QualType OriginalType, Address DestAddr,
|
void CodeGenFunction::EmitOMPCopy(QualType OriginalType, Address DestAddr,
|
||||||
Address SrcAddr, const VarDecl *DestVD,
|
Address SrcAddr, const VarDecl *DestVD,
|
||||||
const VarDecl *SrcVD, const Expr *Copy) {
|
const VarDecl *SrcVD, const Expr *Copy) {
|
||||||
|
@ -546,41 +605,167 @@ void CodeGenFunction::EmitOMPReductionClauseInit(
|
||||||
for (const auto *C : D.getClausesOfKind<OMPReductionClause>()) {
|
for (const auto *C : D.getClausesOfKind<OMPReductionClause>()) {
|
||||||
auto ILHS = C->lhs_exprs().begin();
|
auto ILHS = C->lhs_exprs().begin();
|
||||||
auto IRHS = C->rhs_exprs().begin();
|
auto IRHS = C->rhs_exprs().begin();
|
||||||
|
auto IPriv = C->privates().begin();
|
||||||
for (auto IRef : C->varlists()) {
|
for (auto IRef : C->varlists()) {
|
||||||
auto *OrigVD = cast<VarDecl>(cast<DeclRefExpr>(IRef)->getDecl());
|
|
||||||
auto *LHSVD = cast<VarDecl>(cast<DeclRefExpr>(*ILHS)->getDecl());
|
auto *LHSVD = cast<VarDecl>(cast<DeclRefExpr>(*ILHS)->getDecl());
|
||||||
auto *PrivateVD = cast<VarDecl>(cast<DeclRefExpr>(*IRHS)->getDecl());
|
auto *RHSVD = cast<VarDecl>(cast<DeclRefExpr>(*IRHS)->getDecl());
|
||||||
// Store the address of the original variable associated with the LHS
|
auto *PrivateVD = cast<VarDecl>(cast<DeclRefExpr>(*IPriv)->getDecl());
|
||||||
// implicit variable.
|
if (auto *OASE = dyn_cast<OMPArraySectionExpr>(IRef)) {
|
||||||
PrivateScope.addPrivate(LHSVD, [this, OrigVD, IRef]() -> Address {
|
auto *Base = OASE->getBase()->IgnoreParenImpCasts();
|
||||||
DeclRefExpr DRE(const_cast<VarDecl *>(OrigVD),
|
while (auto *TempOASE = dyn_cast<OMPArraySectionExpr>(Base))
|
||||||
CapturedStmtInfo->lookup(OrigVD) != nullptr,
|
Base = TempOASE->getBase()->IgnoreParenImpCasts();
|
||||||
IRef->getType(), VK_LValue, IRef->getExprLoc());
|
while (auto *TempASE = dyn_cast<ArraySubscriptExpr>(Base))
|
||||||
return EmitLValue(&DRE).getAddress();
|
Base = TempASE->getBase()->IgnoreParenImpCasts();
|
||||||
});
|
auto *DE = cast<DeclRefExpr>(Base);
|
||||||
// Emit reduction copy.
|
auto *OrigVD = cast<VarDecl>(DE->getDecl());
|
||||||
bool IsRegistered =
|
auto OASELValueLB = EmitOMPArraySectionExpr(OASE);
|
||||||
PrivateScope.addPrivate(OrigVD, [this, PrivateVD]() -> Address {
|
auto OASELValueUB =
|
||||||
// Emit private VarDecl with reduction init.
|
EmitOMPArraySectionExpr(OASE, /*IsLowerBound=*/false);
|
||||||
EmitDecl(*PrivateVD);
|
auto OriginalBaseLValue = EmitLValue(DE);
|
||||||
return GetAddrOfLocalVar(PrivateVD);
|
auto BaseLValue = OriginalBaseLValue;
|
||||||
});
|
auto *Zero = Builder.getInt64(/*C=*/0);
|
||||||
assert(IsRegistered && "private var already registered as private");
|
llvm::SmallVector<llvm::Value *, 4> Indexes;
|
||||||
// Silence the warning about unused variable.
|
Indexes.push_back(Zero);
|
||||||
(void)IsRegistered;
|
auto *ItemTy =
|
||||||
++ILHS, ++IRHS;
|
OASELValueLB.getPointer()->getType()->getPointerElementType();
|
||||||
|
auto *Ty = BaseLValue.getPointer()->getType()->getPointerElementType();
|
||||||
|
while (Ty != ItemTy) {
|
||||||
|
Indexes.push_back(Zero);
|
||||||
|
Ty = Ty->getPointerElementType();
|
||||||
|
}
|
||||||
|
BaseLValue = MakeAddrLValue(
|
||||||
|
Address(Builder.CreateInBoundsGEP(BaseLValue.getPointer(), Indexes),
|
||||||
|
OASELValueLB.getAlignment()),
|
||||||
|
OASELValueLB.getType(), OASELValueLB.getAlignmentSource());
|
||||||
|
// Store the address of the original variable associated with the LHS
|
||||||
|
// implicit variable.
|
||||||
|
PrivateScope.addPrivate(LHSVD, [this, OASELValueLB]() -> Address {
|
||||||
|
return OASELValueLB.getAddress();
|
||||||
|
});
|
||||||
|
// Emit reduction copy.
|
||||||
|
bool IsRegistered = PrivateScope.addPrivate(
|
||||||
|
OrigVD, [this, PrivateVD, BaseLValue, OASELValueLB, OASELValueUB,
|
||||||
|
OriginalBaseLValue]() -> Address {
|
||||||
|
// Emit VarDecl with copy init for arrays.
|
||||||
|
// Get the address of the original variable captured in current
|
||||||
|
// captured region.
|
||||||
|
auto *Size = Builder.CreatePtrDiff(OASELValueUB.getPointer(),
|
||||||
|
OASELValueLB.getPointer());
|
||||||
|
Size = Builder.CreateNUWAdd(
|
||||||
|
Size, llvm::ConstantInt::get(Size->getType(), /*V=*/1));
|
||||||
|
CodeGenFunction::OpaqueValueMapping OpaqueMap(
|
||||||
|
*this, cast<OpaqueValueExpr>(
|
||||||
|
getContext()
|
||||||
|
.getAsVariableArrayType(PrivateVD->getType())
|
||||||
|
->getSizeExpr()),
|
||||||
|
RValue::get(Size));
|
||||||
|
EmitVariablyModifiedType(PrivateVD->getType());
|
||||||
|
auto Emission = EmitAutoVarAlloca(*PrivateVD);
|
||||||
|
auto Addr = Emission.getAllocatedAddress();
|
||||||
|
auto *Init = PrivateVD->getInit();
|
||||||
|
EmitOMPAggregateInit(*this, Addr, PrivateVD->getType(), Init);
|
||||||
|
EmitAutoVarCleanups(Emission);
|
||||||
|
// Emit private VarDecl with reduction init.
|
||||||
|
auto *Offset = Builder.CreatePtrDiff(BaseLValue.getPointer(),
|
||||||
|
OASELValueLB.getPointer());
|
||||||
|
auto *Ptr = Builder.CreateGEP(Addr.getPointer(), Offset);
|
||||||
|
Ptr = Builder.CreatePointerBitCastOrAddrSpaceCast(
|
||||||
|
Ptr, OriginalBaseLValue.getPointer()->getType());
|
||||||
|
return Address(Ptr, OriginalBaseLValue.getAlignment());
|
||||||
|
});
|
||||||
|
assert(IsRegistered && "private var already registered as private");
|
||||||
|
// Silence the warning about unused variable.
|
||||||
|
(void)IsRegistered;
|
||||||
|
PrivateScope.addPrivate(RHSVD, [this, PrivateVD]() -> Address {
|
||||||
|
return GetAddrOfLocalVar(PrivateVD);
|
||||||
|
});
|
||||||
|
} else if (auto *ASE = dyn_cast<ArraySubscriptExpr>(IRef)) {
|
||||||
|
auto *Base = ASE->getBase()->IgnoreParenImpCasts();
|
||||||
|
while (auto *TempASE = dyn_cast<ArraySubscriptExpr>(Base))
|
||||||
|
Base = TempASE->getBase()->IgnoreParenImpCasts();
|
||||||
|
auto *DE = cast<DeclRefExpr>(Base);
|
||||||
|
auto *OrigVD = cast<VarDecl>(DE->getDecl());
|
||||||
|
auto ASELValue = EmitLValue(ASE);
|
||||||
|
auto OriginalBaseLValue = EmitLValue(DE);
|
||||||
|
auto BaseLValue = OriginalBaseLValue;
|
||||||
|
auto *Zero = Builder.getInt64(/*C=*/0);
|
||||||
|
llvm::SmallVector<llvm::Value *, 4> Indexes;
|
||||||
|
Indexes.push_back(Zero);
|
||||||
|
auto *ItemTy =
|
||||||
|
ASELValue.getPointer()->getType()->getPointerElementType();
|
||||||
|
auto *Ty = BaseLValue.getPointer()->getType()->getPointerElementType();
|
||||||
|
while (Ty != ItemTy) {
|
||||||
|
Indexes.push_back(Zero);
|
||||||
|
Ty = Ty->getPointerElementType();
|
||||||
|
}
|
||||||
|
BaseLValue = MakeAddrLValue(
|
||||||
|
Address(Builder.CreateInBoundsGEP(BaseLValue.getPointer(), Indexes),
|
||||||
|
ASELValue.getAlignment()),
|
||||||
|
ASELValue.getType(), ASELValue.getAlignmentSource());
|
||||||
|
// Store the address of the original variable associated with the LHS
|
||||||
|
// implicit variable.
|
||||||
|
PrivateScope.addPrivate(LHSVD, [this, ASELValue]() -> Address {
|
||||||
|
return ASELValue.getAddress();
|
||||||
|
});
|
||||||
|
// Emit reduction copy.
|
||||||
|
bool IsRegistered = PrivateScope.addPrivate(
|
||||||
|
OrigVD, [this, PrivateVD, BaseLValue, ASELValue,
|
||||||
|
OriginalBaseLValue]() -> Address {
|
||||||
|
// Emit private VarDecl with reduction init.
|
||||||
|
EmitDecl(*PrivateVD);
|
||||||
|
auto Addr = GetAddrOfLocalVar(PrivateVD);
|
||||||
|
auto *Offset = Builder.CreatePtrDiff(BaseLValue.getPointer(),
|
||||||
|
ASELValue.getPointer());
|
||||||
|
auto *Ptr = Builder.CreateGEP(Addr.getPointer(), Offset);
|
||||||
|
Ptr = Builder.CreatePointerBitCastOrAddrSpaceCast(
|
||||||
|
Ptr, OriginalBaseLValue.getPointer()->getType());
|
||||||
|
return Address(Ptr, OriginalBaseLValue.getAlignment());
|
||||||
|
});
|
||||||
|
assert(IsRegistered && "private var already registered as private");
|
||||||
|
// Silence the warning about unused variable.
|
||||||
|
(void)IsRegistered;
|
||||||
|
PrivateScope.addPrivate(RHSVD, [this, PrivateVD]() -> Address {
|
||||||
|
return GetAddrOfLocalVar(PrivateVD);
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
auto *OrigVD = cast<VarDecl>(cast<DeclRefExpr>(IRef)->getDecl());
|
||||||
|
// Store the address of the original variable associated with the LHS
|
||||||
|
// implicit variable.
|
||||||
|
PrivateScope.addPrivate(LHSVD, [this, OrigVD, IRef]() -> Address {
|
||||||
|
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]() -> Address {
|
||||||
|
// 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;
|
||||||
|
PrivateScope.addPrivate(RHSVD, [this, PrivateVD]() -> Address {
|
||||||
|
return GetAddrOfLocalVar(PrivateVD);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
++ILHS, ++IRHS, ++IPriv;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void CodeGenFunction::EmitOMPReductionClauseFinal(
|
void CodeGenFunction::EmitOMPReductionClauseFinal(
|
||||||
const OMPExecutableDirective &D) {
|
const OMPExecutableDirective &D) {
|
||||||
|
llvm::SmallVector<const Expr *, 8> Privates;
|
||||||
llvm::SmallVector<const Expr *, 8> LHSExprs;
|
llvm::SmallVector<const Expr *, 8> LHSExprs;
|
||||||
llvm::SmallVector<const Expr *, 8> RHSExprs;
|
llvm::SmallVector<const Expr *, 8> RHSExprs;
|
||||||
llvm::SmallVector<const Expr *, 8> ReductionOps;
|
llvm::SmallVector<const Expr *, 8> ReductionOps;
|
||||||
bool HasAtLeastOneReduction = false;
|
bool HasAtLeastOneReduction = false;
|
||||||
for (const auto *C : D.getClausesOfKind<OMPReductionClause>()) {
|
for (const auto *C : D.getClausesOfKind<OMPReductionClause>()) {
|
||||||
HasAtLeastOneReduction = true;
|
HasAtLeastOneReduction = true;
|
||||||
|
Privates.append(C->privates().begin(), C->privates().end());
|
||||||
LHSExprs.append(C->lhs_exprs().begin(), C->lhs_exprs().end());
|
LHSExprs.append(C->lhs_exprs().begin(), C->lhs_exprs().end());
|
||||||
RHSExprs.append(C->rhs_exprs().begin(), C->rhs_exprs().end());
|
RHSExprs.append(C->rhs_exprs().begin(), C->rhs_exprs().end());
|
||||||
ReductionOps.append(C->reduction_ops().begin(), C->reduction_ops().end());
|
ReductionOps.append(C->reduction_ops().begin(), C->reduction_ops().end());
|
||||||
|
@ -589,7 +774,7 @@ void CodeGenFunction::EmitOMPReductionClauseFinal(
|
||||||
// Emit nowait reduction if nowait clause is present or directive is a
|
// Emit nowait reduction if nowait clause is present or directive is a
|
||||||
// parallel directive (it always has implicit barrier).
|
// parallel directive (it always has implicit barrier).
|
||||||
CGM.getOpenMPRuntime().emitReduction(
|
CGM.getOpenMPRuntime().emitReduction(
|
||||||
*this, D.getLocEnd(), LHSExprs, RHSExprs, ReductionOps,
|
*this, D.getLocEnd(), Privates, LHSExprs, RHSExprs, ReductionOps,
|
||||||
D.getSingleClause<OMPNowaitClause>() ||
|
D.getSingleClause<OMPNowaitClause>() ||
|
||||||
isOpenMPParallelDirective(D.getDirectiveKind()) ||
|
isOpenMPParallelDirective(D.getDirectiveKind()) ||
|
||||||
D.getDirectiveKind() == OMPD_simd,
|
D.getDirectiveKind() == OMPD_simd,
|
||||||
|
|
|
@ -6047,6 +6047,8 @@ OMPClause *Sema::ActOnOpenMPFirstprivateClause(ArrayRef<Expr *> VarList,
|
||||||
VDPrivate->setInvalidDecl();
|
VDPrivate->setInvalidDecl();
|
||||||
else
|
else
|
||||||
VDPrivate->setInit(Result.getAs<Expr>());
|
VDPrivate->setInit(Result.getAs<Expr>());
|
||||||
|
// Remove temp variable declaration.
|
||||||
|
Context.Deallocate(VDInitTemp);
|
||||||
} else {
|
} else {
|
||||||
auto *VDInit =
|
auto *VDInit =
|
||||||
buildVarDecl(*this, DE->getLocStart(), Type, ".firstprivate.temp");
|
buildVarDecl(*this, DE->getLocStart(), Type, ".firstprivate.temp");
|
||||||
|
@ -6407,6 +6409,7 @@ OMPClause *Sema::ActOnOpenMPReductionClause(
|
||||||
}
|
}
|
||||||
|
|
||||||
SmallVector<Expr *, 8> Vars;
|
SmallVector<Expr *, 8> Vars;
|
||||||
|
SmallVector<Expr *, 8> Privates;
|
||||||
SmallVector<Expr *, 8> LHSs;
|
SmallVector<Expr *, 8> LHSs;
|
||||||
SmallVector<Expr *, 8> RHSs;
|
SmallVector<Expr *, 8> RHSs;
|
||||||
SmallVector<Expr *, 8> ReductionOps;
|
SmallVector<Expr *, 8> ReductionOps;
|
||||||
|
@ -6415,6 +6418,7 @@ OMPClause *Sema::ActOnOpenMPReductionClause(
|
||||||
if (isa<DependentScopeDeclRefExpr>(RefExpr)) {
|
if (isa<DependentScopeDeclRefExpr>(RefExpr)) {
|
||||||
// It will be analyzed later.
|
// It will be analyzed later.
|
||||||
Vars.push_back(RefExpr);
|
Vars.push_back(RefExpr);
|
||||||
|
Privates.push_back(nullptr);
|
||||||
LHSs.push_back(nullptr);
|
LHSs.push_back(nullptr);
|
||||||
RHSs.push_back(nullptr);
|
RHSs.push_back(nullptr);
|
||||||
ReductionOps.push_back(nullptr);
|
ReductionOps.push_back(nullptr);
|
||||||
|
@ -6426,6 +6430,7 @@ OMPClause *Sema::ActOnOpenMPReductionClause(
|
||||||
RefExpr->containsUnexpandedParameterPack()) {
|
RefExpr->containsUnexpandedParameterPack()) {
|
||||||
// It will be analyzed later.
|
// It will be analyzed later.
|
||||||
Vars.push_back(RefExpr);
|
Vars.push_back(RefExpr);
|
||||||
|
Privates.push_back(nullptr);
|
||||||
LHSs.push_back(nullptr);
|
LHSs.push_back(nullptr);
|
||||||
RHSs.push_back(nullptr);
|
RHSs.push_back(nullptr);
|
||||||
ReductionOps.push_back(nullptr);
|
ReductionOps.push_back(nullptr);
|
||||||
|
@ -6454,24 +6459,38 @@ OMPClause *Sema::ActOnOpenMPReductionClause(
|
||||||
auto D = DE->getDecl();
|
auto D = DE->getDecl();
|
||||||
VD = cast<VarDecl>(D);
|
VD = cast<VarDecl>(D);
|
||||||
Type = VD->getType();
|
Type = VD->getType();
|
||||||
} else if (ASE)
|
} else if (ASE) {
|
||||||
Type = ASE->getType();
|
Type = ASE->getType();
|
||||||
else if (OASE) {
|
auto *Base = ASE->getBase()->IgnoreParenImpCasts();
|
||||||
|
while (auto *TempASE = dyn_cast<ArraySubscriptExpr>(Base))
|
||||||
|
Base = TempASE->getBase()->IgnoreParenImpCasts();
|
||||||
|
DE = dyn_cast<DeclRefExpr>(Base);
|
||||||
|
if (DE)
|
||||||
|
VD = dyn_cast<VarDecl>(DE->getDecl());
|
||||||
|
if (!VD) {
|
||||||
|
Diag(Base->getExprLoc(), diag::err_omp_expected_base_var_name)
|
||||||
|
<< 0 << Base->getSourceRange();
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
} else if (OASE) {
|
||||||
auto BaseType = OMPArraySectionExpr::getBaseOriginalType(OASE->getBase());
|
auto BaseType = OMPArraySectionExpr::getBaseOriginalType(OASE->getBase());
|
||||||
if (auto *ATy = BaseType->getAsArrayTypeUnsafe())
|
if (auto *ATy = BaseType->getAsArrayTypeUnsafe())
|
||||||
Type = ATy->getElementType();
|
Type = ATy->getElementType();
|
||||||
else
|
else
|
||||||
Type = BaseType->getPointeeType();
|
Type = BaseType->getPointeeType();
|
||||||
}
|
auto *Base = OASE->getBase()->IgnoreParenImpCasts();
|
||||||
// OpenMP [2.15.3.6, reduction Clause]
|
while (auto *TempOASE = dyn_cast<OMPArraySectionExpr>(Base))
|
||||||
// If a list item is an array section, its lower-bound must be zero.
|
Base = TempOASE->getBase()->IgnoreParenImpCasts();
|
||||||
llvm::APSInt Result;
|
while (auto *TempASE = dyn_cast<ArraySubscriptExpr>(Base))
|
||||||
if (OASE && OASE->getLowerBound() &&
|
Base = TempASE->getBase()->IgnoreParenImpCasts();
|
||||||
OASE->getLowerBound()->EvaluateAsInt(Result, Context) && Result != 0) {
|
DE = dyn_cast<DeclRefExpr>(Base);
|
||||||
Diag(OASE->getLowerBound()->getExprLoc(),
|
if (DE)
|
||||||
diag::err_omp_expected_array_sect_reduction_lb_not_zero)
|
VD = dyn_cast<VarDecl>(DE->getDecl());
|
||||||
<< OASE->getLowerBound()->getSourceRange();
|
if (!VD) {
|
||||||
continue;
|
Diag(Base->getExprLoc(), diag::err_omp_expected_base_var_name)
|
||||||
|
<< 1 << Base->getSourceRange();
|
||||||
|
continue;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// OpenMP [2.9.3.3, Restrictions, C/C++, p.3]
|
// OpenMP [2.9.3.3, Restrictions, C/C++, p.3]
|
||||||
|
@ -6484,7 +6503,7 @@ OMPClause *Sema::ActOnOpenMPReductionClause(
|
||||||
// Arrays may not appear in a reduction clause.
|
// Arrays may not appear in a reduction clause.
|
||||||
if (Type.getNonReferenceType()->isArrayType()) {
|
if (Type.getNonReferenceType()->isArrayType()) {
|
||||||
Diag(ELoc, diag::err_omp_reduction_type_array) << Type << ERange;
|
Diag(ELoc, diag::err_omp_reduction_type_array) << Type << ERange;
|
||||||
if (VD) {
|
if (!ASE && !OASE) {
|
||||||
bool IsDecl = VD->isThisDeclarationADefinition(Context) ==
|
bool IsDecl = VD->isThisDeclarationADefinition(Context) ==
|
||||||
VarDecl::DeclarationOnly;
|
VarDecl::DeclarationOnly;
|
||||||
Diag(VD->getLocation(),
|
Diag(VD->getLocation(),
|
||||||
|
@ -6499,7 +6518,7 @@ OMPClause *Sema::ActOnOpenMPReductionClause(
|
||||||
if (Type.getNonReferenceType().isConstant(Context)) {
|
if (Type.getNonReferenceType().isConstant(Context)) {
|
||||||
Diag(ELoc, diag::err_omp_const_reduction_list_item)
|
Diag(ELoc, diag::err_omp_const_reduction_list_item)
|
||||||
<< getOpenMPClauseName(OMPC_reduction) << Type << ERange;
|
<< getOpenMPClauseName(OMPC_reduction) << Type << ERange;
|
||||||
if (VD) {
|
if (!ASE && !OASE) {
|
||||||
bool IsDecl = VD->isThisDeclarationADefinition(Context) ==
|
bool IsDecl = VD->isThisDeclarationADefinition(Context) ==
|
||||||
VarDecl::DeclarationOnly;
|
VarDecl::DeclarationOnly;
|
||||||
Diag(VD->getLocation(),
|
Diag(VD->getLocation(),
|
||||||
|
@ -6511,7 +6530,7 @@ OMPClause *Sema::ActOnOpenMPReductionClause(
|
||||||
// OpenMP [2.9.3.6, Restrictions, C/C++, p.4]
|
// OpenMP [2.9.3.6, Restrictions, C/C++, p.4]
|
||||||
// If a list-item is a reference type then it must bind to the same object
|
// If a list-item is a reference type then it must bind to the same object
|
||||||
// for all threads of the team.
|
// for all threads of the team.
|
||||||
if (VD) {
|
if (!ASE && !OASE) {
|
||||||
VarDecl *VDDef = VD->getDefinition();
|
VarDecl *VDDef = VD->getDefinition();
|
||||||
if (Type->isReferenceType() && VDDef) {
|
if (Type->isReferenceType() && VDDef) {
|
||||||
DSARefChecker Check(DSAStack);
|
DSARefChecker Check(DSAStack);
|
||||||
|
@ -6535,7 +6554,7 @@ OMPClause *Sema::ActOnOpenMPReductionClause(
|
||||||
(getLangOpts().CPlusPlus && Type->isArithmeticType()))) {
|
(getLangOpts().CPlusPlus && Type->isArithmeticType()))) {
|
||||||
Diag(ELoc, diag::err_omp_clause_not_arithmetic_type_arg)
|
Diag(ELoc, diag::err_omp_clause_not_arithmetic_type_arg)
|
||||||
<< getLangOpts().CPlusPlus;
|
<< getLangOpts().CPlusPlus;
|
||||||
if (VD) {
|
if (!ASE && !OASE) {
|
||||||
bool IsDecl = VD->isThisDeclarationADefinition(Context) ==
|
bool IsDecl = VD->isThisDeclarationADefinition(Context) ==
|
||||||
VarDecl::DeclarationOnly;
|
VarDecl::DeclarationOnly;
|
||||||
Diag(VD->getLocation(),
|
Diag(VD->getLocation(),
|
||||||
|
@ -6547,7 +6566,7 @@ OMPClause *Sema::ActOnOpenMPReductionClause(
|
||||||
if ((BOK == BO_OrAssign || BOK == BO_AndAssign || BOK == BO_XorAssign) &&
|
if ((BOK == BO_OrAssign || BOK == BO_AndAssign || BOK == BO_XorAssign) &&
|
||||||
!getLangOpts().CPlusPlus && Type->isFloatingType()) {
|
!getLangOpts().CPlusPlus && Type->isFloatingType()) {
|
||||||
Diag(ELoc, diag::err_omp_clause_floating_type_arg);
|
Diag(ELoc, diag::err_omp_clause_floating_type_arg);
|
||||||
if (VD) {
|
if (!ASE && !OASE) {
|
||||||
bool IsDecl = VD->isThisDeclarationADefinition(Context) ==
|
bool IsDecl = VD->isThisDeclarationADefinition(Context) ==
|
||||||
VarDecl::DeclarationOnly;
|
VarDecl::DeclarationOnly;
|
||||||
Diag(VD->getLocation(),
|
Diag(VD->getLocation(),
|
||||||
|
@ -6568,48 +6587,58 @@ OMPClause *Sema::ActOnOpenMPReductionClause(
|
||||||
// but a list item can appear only once in the reduction clauses for that
|
// but a list item can appear only once in the reduction clauses for that
|
||||||
// directive.
|
// directive.
|
||||||
DSAStackTy::DSAVarData DVar;
|
DSAStackTy::DSAVarData DVar;
|
||||||
if (VD) {
|
DVar = DSAStack->getTopDSA(VD, false);
|
||||||
DVar = DSAStack->getTopDSA(VD, false);
|
if (DVar.CKind == OMPC_reduction) {
|
||||||
if (DVar.CKind == OMPC_reduction) {
|
Diag(ELoc, diag::err_omp_once_referenced)
|
||||||
Diag(ELoc, diag::err_omp_once_referenced)
|
<< getOpenMPClauseName(OMPC_reduction);
|
||||||
<< getOpenMPClauseName(OMPC_reduction);
|
if (DVar.RefExpr) {
|
||||||
if (DVar.RefExpr) {
|
Diag(DVar.RefExpr->getExprLoc(), diag::note_omp_referenced);
|
||||||
Diag(DVar.RefExpr->getExprLoc(), diag::note_omp_referenced);
|
|
||||||
}
|
|
||||||
} else if (DVar.CKind != OMPC_unknown) {
|
|
||||||
Diag(ELoc, diag::err_omp_wrong_dsa)
|
|
||||||
<< getOpenMPClauseName(DVar.CKind)
|
|
||||||
<< getOpenMPClauseName(OMPC_reduction);
|
|
||||||
ReportOriginalDSA(*this, DSAStack, VD, DVar);
|
|
||||||
continue;
|
|
||||||
}
|
}
|
||||||
|
} else if (DVar.CKind != OMPC_unknown) {
|
||||||
|
Diag(ELoc, diag::err_omp_wrong_dsa)
|
||||||
|
<< getOpenMPClauseName(DVar.CKind)
|
||||||
|
<< getOpenMPClauseName(OMPC_reduction);
|
||||||
|
ReportOriginalDSA(*this, DSAStack, VD, DVar);
|
||||||
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
// OpenMP [2.14.3.6, Restrictions, p.1]
|
// OpenMP [2.14.3.6, Restrictions, p.1]
|
||||||
// A list item that appears in a reduction clause of a worksharing
|
// A list item that appears in a reduction clause of a worksharing
|
||||||
// construct must be shared in the parallel regions to which any of the
|
// construct must be shared in the parallel regions to which any of the
|
||||||
// worksharing regions arising from the worksharing construct bind.
|
// worksharing regions arising from the worksharing construct bind.
|
||||||
if (VD) {
|
OpenMPDirectiveKind CurrDir = DSAStack->getCurrentDirective();
|
||||||
OpenMPDirectiveKind CurrDir = DSAStack->getCurrentDirective();
|
if (isOpenMPWorksharingDirective(CurrDir) &&
|
||||||
if (isOpenMPWorksharingDirective(CurrDir) &&
|
!isOpenMPParallelDirective(CurrDir)) {
|
||||||
!isOpenMPParallelDirective(CurrDir)) {
|
DVar = DSAStack->getImplicitDSA(VD, true);
|
||||||
DVar = DSAStack->getImplicitDSA(VD, true);
|
if (DVar.CKind != OMPC_shared) {
|
||||||
if (DVar.CKind != OMPC_shared) {
|
Diag(ELoc, diag::err_omp_required_access)
|
||||||
Diag(ELoc, diag::err_omp_required_access)
|
<< getOpenMPClauseName(OMPC_reduction)
|
||||||
<< getOpenMPClauseName(OMPC_reduction)
|
<< getOpenMPClauseName(OMPC_shared);
|
||||||
<< getOpenMPClauseName(OMPC_shared);
|
ReportOriginalDSA(*this, DSAStack, VD, DVar);
|
||||||
ReportOriginalDSA(*this, DSAStack, VD, DVar);
|
continue;
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Type = Type.getNonLValueExprType(Context).getUnqualifiedType();
|
Type = Type.getNonLValueExprType(Context).getUnqualifiedType();
|
||||||
auto *LHSVD =
|
auto *LHSVD = buildVarDecl(*this, ELoc, Type, ".reduction.lhs",
|
||||||
buildVarDecl(*this, ELoc, Type, ".reduction.lhs",
|
VD->hasAttrs() ? &VD->getAttrs() : nullptr);
|
||||||
VD && VD->hasAttrs() ? &VD->getAttrs() : nullptr);
|
auto *RHSVD = buildVarDecl(*this, ELoc, Type, VD->getName(),
|
||||||
auto *RHSVD =
|
VD->hasAttrs() ? &VD->getAttrs() : nullptr);
|
||||||
buildVarDecl(*this, ELoc, Type, VD ? VD->getName() : ".item.",
|
auto PrivateTy = Type;
|
||||||
VD && VD->hasAttrs() ? &VD->getAttrs() : nullptr);
|
if (OASE) {
|
||||||
|
// For array sections only:
|
||||||
|
// Create pseudo array type for private copy. The size for this array will
|
||||||
|
// be generated during codegen.
|
||||||
|
// For array subscripts or single variables Private Ty is the same as Type
|
||||||
|
// (type of the variable or single array element).
|
||||||
|
PrivateTy = Context.getVariableArrayType(
|
||||||
|
Type, new (Context) OpaqueValueExpr(SourceLocation(),
|
||||||
|
Context.getSizeType(), VK_RValue),
|
||||||
|
ArrayType::Normal, /*IndexTypeQuals=*/0, SourceRange());
|
||||||
|
}
|
||||||
|
// Private copy.
|
||||||
|
auto *PrivateVD = buildVarDecl(*this, ELoc, PrivateTy, VD->getName(),
|
||||||
|
VD->hasAttrs() ? &VD->getAttrs() : nullptr);
|
||||||
// Add initializer for private variable.
|
// Add initializer for private variable.
|
||||||
Expr *Init = nullptr;
|
Expr *Init = nullptr;
|
||||||
switch (BOK) {
|
switch (BOK) {
|
||||||
|
@ -6718,9 +6747,8 @@ OMPClause *Sema::ActOnOpenMPReductionClause(
|
||||||
if (Init) {
|
if (Init) {
|
||||||
AddInitializerToDecl(RHSVD, Init, /*DirectInit=*/false,
|
AddInitializerToDecl(RHSVD, Init, /*DirectInit=*/false,
|
||||||
/*TypeMayContainAuto=*/false);
|
/*TypeMayContainAuto=*/false);
|
||||||
} else {
|
} else
|
||||||
ActOnUninitializedDecl(RHSVD, /*TypeMayContainAuto=*/false);
|
ActOnUninitializedDecl(RHSVD, /*TypeMayContainAuto=*/false);
|
||||||
}
|
|
||||||
if (!RHSVD->hasInit()) {
|
if (!RHSVD->hasInit()) {
|
||||||
Diag(ELoc, diag::err_omp_reduction_id_not_compatible) << Type
|
Diag(ELoc, diag::err_omp_reduction_id_not_compatible) << Type
|
||||||
<< ReductionIdRange;
|
<< ReductionIdRange;
|
||||||
|
@ -6733,8 +6761,13 @@ OMPClause *Sema::ActOnOpenMPReductionClause(
|
||||||
}
|
}
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
// Store initializer for single element in private copy. Will be used during
|
||||||
|
// codegen.
|
||||||
|
PrivateVD->setInit(RHSVD->getInit());
|
||||||
|
PrivateVD->setInitStyle(RHSVD->getInitStyle());
|
||||||
auto *LHSDRE = buildDeclRefExpr(*this, LHSVD, Type, ELoc);
|
auto *LHSDRE = buildDeclRefExpr(*this, LHSVD, Type, ELoc);
|
||||||
auto *RHSDRE = buildDeclRefExpr(*this, RHSVD, Type, ELoc);
|
auto *RHSDRE = buildDeclRefExpr(*this, RHSVD, Type, ELoc);
|
||||||
|
auto *PrivateDRE = buildDeclRefExpr(*this, PrivateVD, PrivateTy, ELoc);
|
||||||
ExprResult ReductionOp =
|
ExprResult ReductionOp =
|
||||||
BuildBinOp(DSAStack->getCurScope(), ReductionId.getLocStart(), BOK,
|
BuildBinOp(DSAStack->getCurScope(), ReductionId.getLocStart(), BOK,
|
||||||
LHSDRE, RHSDRE);
|
LHSDRE, RHSDRE);
|
||||||
|
@ -6756,9 +6789,9 @@ OMPClause *Sema::ActOnOpenMPReductionClause(
|
||||||
if (ReductionOp.isInvalid())
|
if (ReductionOp.isInvalid())
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (VD)
|
DSAStack->addDSA(VD, DE, OMPC_reduction);
|
||||||
DSAStack->addDSA(VD, DE, OMPC_reduction);
|
|
||||||
Vars.push_back(RefExpr);
|
Vars.push_back(RefExpr);
|
||||||
|
Privates.push_back(PrivateDRE);
|
||||||
LHSs.push_back(LHSDRE);
|
LHSs.push_back(LHSDRE);
|
||||||
RHSs.push_back(RHSDRE);
|
RHSs.push_back(RHSDRE);
|
||||||
ReductionOps.push_back(ReductionOp.get());
|
ReductionOps.push_back(ReductionOp.get());
|
||||||
|
@ -6769,8 +6802,8 @@ OMPClause *Sema::ActOnOpenMPReductionClause(
|
||||||
|
|
||||||
return OMPReductionClause::Create(
|
return OMPReductionClause::Create(
|
||||||
Context, StartLoc, LParenLoc, ColonLoc, EndLoc, Vars,
|
Context, StartLoc, LParenLoc, ColonLoc, EndLoc, Vars,
|
||||||
ReductionIdScopeSpec.getWithLocInContext(Context), ReductionId, LHSs,
|
ReductionIdScopeSpec.getWithLocInContext(Context), ReductionId, Privates,
|
||||||
RHSs, ReductionOps);
|
LHSs, RHSs, ReductionOps);
|
||||||
}
|
}
|
||||||
|
|
||||||
OMPClause *Sema::ActOnOpenMPLinearClause(
|
OMPClause *Sema::ActOnOpenMPLinearClause(
|
||||||
|
|
|
@ -1994,6 +1994,10 @@ void OMPClauseReader::VisitOMPReductionClause(OMPReductionClause *C) {
|
||||||
Vars.push_back(Reader->Reader.ReadSubExpr());
|
Vars.push_back(Reader->Reader.ReadSubExpr());
|
||||||
C->setVarRefs(Vars);
|
C->setVarRefs(Vars);
|
||||||
Vars.clear();
|
Vars.clear();
|
||||||
|
for (unsigned i = 0; i != NumVars; ++i)
|
||||||
|
Vars.push_back(Reader->Reader.ReadSubExpr());
|
||||||
|
C->setPrivates(Vars);
|
||||||
|
Vars.clear();
|
||||||
for (unsigned i = 0; i != NumVars; ++i)
|
for (unsigned i = 0; i != NumVars; ++i)
|
||||||
Vars.push_back(Reader->Reader.ReadSubExpr());
|
Vars.push_back(Reader->Reader.ReadSubExpr());
|
||||||
C->setLHSExprs(Vars);
|
C->setLHSExprs(Vars);
|
||||||
|
|
|
@ -1869,6 +1869,8 @@ void OMPClauseWriter::VisitOMPReductionClause(OMPReductionClause *C) {
|
||||||
Writer->Writer.AddDeclarationNameInfo(C->getNameInfo(), Record);
|
Writer->Writer.AddDeclarationNameInfo(C->getNameInfo(), Record);
|
||||||
for (auto *VE : C->varlists())
|
for (auto *VE : C->varlists())
|
||||||
Writer->Writer.AddStmt(VE);
|
Writer->Writer.AddStmt(VE);
|
||||||
|
for (auto *VE : C->privates())
|
||||||
|
Writer->Writer.AddStmt(VE);
|
||||||
for (auto *E : C->lhs_exprs())
|
for (auto *E : C->lhs_exprs())
|
||||||
Writer->Writer.AddStmt(E);
|
Writer->Writer.AddStmt(E);
|
||||||
for (auto *E : C->rhs_exprs())
|
for (auto *E : C->rhs_exprs())
|
||||||
|
|
|
@ -181,13 +181,17 @@ int main() {
|
||||||
int vec[] = {1, 2};
|
int vec[] = {1, 2};
|
||||||
S<float> s_arr[] = {1, 2};
|
S<float> s_arr[] = {1, 2};
|
||||||
S<float> &var = test;
|
S<float> &var = test;
|
||||||
S<float> var1;
|
S<float> var1, arrs[10][4];
|
||||||
#pragma omp parallel
|
#pragma omp parallel
|
||||||
#pragma omp for reduction(+:t_var) reduction(&:var) reduction(&& : var1) reduction(min: t_var1)
|
#pragma omp for reduction(+:t_var) reduction(&:var) reduction(&& : var1) reduction(min: t_var1)
|
||||||
for (int i = 0; i < 2; ++i) {
|
for (int i = 0; i < 2; ++i) {
|
||||||
vec[i] = t_var;
|
vec[i] = t_var;
|
||||||
s_arr[i] = var;
|
s_arr[i] = var;
|
||||||
}
|
}
|
||||||
|
int arr[10][vec[1]];
|
||||||
|
#pragma omp parallel for reduction(+:arr[1][:vec[1]]) reduction(&:arrs[1:vec[1]][1:2])
|
||||||
|
for (int i = 0; i < 10; ++i)
|
||||||
|
++arr[1][i];
|
||||||
return tmain<int>();
|
return tmain<int>();
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
@ -196,6 +200,7 @@ int main() {
|
||||||
// CHECK: [[TEST:%.+]] = alloca [[S_FLOAT_TY]],
|
// CHECK: [[TEST:%.+]] = alloca [[S_FLOAT_TY]],
|
||||||
// CHECK: call {{.*}} [[S_FLOAT_TY_CONSTR:@.+]]([[S_FLOAT_TY]]* [[TEST]])
|
// CHECK: call {{.*}} [[S_FLOAT_TY_CONSTR:@.+]]([[S_FLOAT_TY]]* [[TEST]])
|
||||||
// CHECK: call void (%{{.+}}*, i{{[0-9]+}}, void (i{{[0-9]+}}*, i{{[0-9]+}}*, ...)*, ...) @__kmpc_fork_call(%{{.+}}* @{{.+}}, i{{[0-9]+}} 6, void (i{{[0-9]+}}*, i{{[0-9]+}}*, ...)* bitcast (void (i{{[0-9]+}}*, i{{[0-9]+}}*, float*, [[S_FLOAT_TY]]*, [[S_FLOAT_TY]]*, float*, [2 x i32]*, [2 x [[S_FLOAT_TY]]]*)* [[MAIN_MICROTASK:@.+]] to void
|
// CHECK: call void (%{{.+}}*, i{{[0-9]+}}, void (i{{[0-9]+}}*, i{{[0-9]+}}*, ...)*, ...) @__kmpc_fork_call(%{{.+}}* @{{.+}}, i{{[0-9]+}} 6, void (i{{[0-9]+}}*, i{{[0-9]+}}*, ...)* bitcast (void (i{{[0-9]+}}*, i{{[0-9]+}}*, float*, [[S_FLOAT_TY]]*, [[S_FLOAT_TY]]*, float*, [2 x i32]*, [2 x [[S_FLOAT_TY]]]*)* [[MAIN_MICROTASK:@.+]] to void
|
||||||
|
// CHECK: call void (%{{.+}}*, i{{[0-9]+}}, void (i{{[0-9]+}}*, i{{[0-9]+}}*, ...)*, ...) @__kmpc_fork_call(%{{.+}}* @{{.+}}, i{{[0-9]+}} 5, void (i{{[0-9]+}}*, i{{[0-9]+}}*, ...)* bitcast (void (i{{[0-9]+}}*, i{{[0-9]+}}*, i64, i64, i32*, [2 x i32]*, [10 x [4 x [[S_FLOAT_TY]]]]*)* [[MAIN_MICROTASK1:@.+]] to void
|
||||||
// CHECK: = call {{.*}}i{{.+}} [[TMAIN_INT:@.+]]()
|
// CHECK: = call {{.*}}i{{.+}} [[TMAIN_INT:@.+]]()
|
||||||
// CHECK: call {{.*}} [[S_FLOAT_TY_DESTR:@.+]]([[S_FLOAT_TY]]*
|
// CHECK: call {{.*}} [[S_FLOAT_TY_DESTR:@.+]]([[S_FLOAT_TY]]*
|
||||||
// CHECK: ret
|
// CHECK: ret
|
||||||
|
@ -458,6 +463,213 @@ int main() {
|
||||||
// CHECK: store float [[UP]], float* [[T_VAR1_LHS]],
|
// CHECK: store float [[UP]], float* [[T_VAR1_LHS]],
|
||||||
// CHECK: ret void
|
// CHECK: ret void
|
||||||
|
|
||||||
|
// CHECK: define internal void [[MAIN_MICROTASK1]](i{{[0-9]+}}* noalias [[GTID_ADDR:%.+]], i{{[0-9]+}}* noalias %{{.+}}, i64 %{{.+}}, i64 %{{.+}}, i32* nonnull %{{.+}}, [2 x i32]* dereferenceable(8) %{{.+}}, [10 x [4 x [[S_FLOAT_TY]]]]* dereferenceable(160) %{{.+}})
|
||||||
|
|
||||||
|
// 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: [[IDX1:%.+]] = mul nsw i64 1, %{{.+}}
|
||||||
|
// CHECK: [[LB1:%.+]] = getelementptr inbounds i32, i32* %{{.+}}, i64 [[IDX1]]
|
||||||
|
// CHECK: [[LB1_0:%.+]] = getelementptr inbounds i32, i32* [[LB1]], i64 0
|
||||||
|
// CHECK: [[IDX1:%.+]] = mul nsw i64 1, %{{.+}}
|
||||||
|
// CHECK: [[UB1:%.+]] = getelementptr inbounds i32, i32* %{{.+}}, i64 [[IDX1]]
|
||||||
|
// CHECK: [[UB1_UP:%.+]] = getelementptr inbounds i32, i32* [[UB1]], i64 %
|
||||||
|
// CHECK: [[UB_CAST:%.+]] = ptrtoint i32* [[UB1_UP]] to i64
|
||||||
|
// CHECK: [[LB_CAST:%.+]] = ptrtoint i32* [[LB1_0]] to i64
|
||||||
|
// CHECK: [[DIFF:%.+]] = sub i64 [[UB_CAST]], [[LB_CAST]]
|
||||||
|
// CHECK: [[SIZE_1:%.+]] = sdiv exact i64 [[DIFF]], ptrtoint (i32* getelementptr (i32, i32* null, i32 1) to i64)
|
||||||
|
// CHECK: [[ARR_SIZE:%.+]] = add nuw i64 [[SIZE_1]], 1
|
||||||
|
// CHECK: call i8* @llvm.stacksave()
|
||||||
|
// CHECK: [[ARR_PRIV:%.+]] = alloca i32, i64 [[ARR_SIZE]],
|
||||||
|
|
||||||
|
// Check initialization of private copy.
|
||||||
|
// CHECK: [[END:%.+]] = getelementptr i32, i32* [[ARR_PRIV]], i64 [[ARR_SIZE]]
|
||||||
|
// CHECK: [[ISEMPTY:%.+]] = icmp eq i32* [[ARR_PRIV]], [[END]]
|
||||||
|
// CHECK: br i1 [[ISEMPTY]],
|
||||||
|
// CHECK: phi i32*
|
||||||
|
// CHECK: store i32 0, i32* %
|
||||||
|
// CHECK: [[DONE:%.+]] = icmp eq i32* %{{.+}}, [[END]]
|
||||||
|
// CHECK: br i1 [[DONE]],
|
||||||
|
|
||||||
|
// CHECK: [[ARRS_PRIV:%.+]] = alloca [[S_FLOAT_TY]], i64 [[ARRS_SIZE:%.+]],
|
||||||
|
|
||||||
|
// Check initialization of private copy.
|
||||||
|
// CHECK: [[END:%.+]] = getelementptr [[S_FLOAT_TY]], [[S_FLOAT_TY]]* [[ARRS_PRIV]], i64 [[ARRS_SIZE]]
|
||||||
|
// CHECK: [[ISEMPTY:%.+]] = icmp eq [[S_FLOAT_TY]]* [[ARRS_PRIV]], [[END]]
|
||||||
|
// CHECK: br i1 [[ISEMPTY]],
|
||||||
|
// CHECK: phi [[S_FLOAT_TY]]*
|
||||||
|
// CHECK: call void @_ZN1SIfEC1Ev([[S_FLOAT_TY]]* %
|
||||||
|
// CHECK: [[DONE:%.+]] = icmp eq [[S_FLOAT_TY]]* %{{.+}}, [[END]]
|
||||||
|
// CHECK: br i1 [[DONE]],
|
||||||
|
|
||||||
|
// 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 void @__kmpc_for_static_init_4(
|
||||||
|
// Skip checks for internal operations.
|
||||||
|
// CHECK: call void @__kmpc_for_static_fini(
|
||||||
|
|
||||||
|
// void *RedList[<n>] = {<ReductionVars>[0], ..., <ReductionVars>[<n>-1]};
|
||||||
|
|
||||||
|
// CHECK: [[ARR_PRIV_REF:%.+]] = getelementptr inbounds [4 x i8*], [4 x i8*]* [[RED_LIST]], i64 0, i64 0
|
||||||
|
// CHECK: [[BITCAST:%.+]] = bitcast i32* [[ARR_PRIV]] to i8*
|
||||||
|
// CHECK: store i8* [[BITCAST]], i8** [[ARR_PRIV_REF]],
|
||||||
|
// CHECK: [[ARR_SIZE_REF:%.+]] = getelementptr inbounds [4 x i8*], [4 x i8*]* [[RED_LIST]], i64 0, i64 1
|
||||||
|
// CHECK: [[BITCAST:%.+]] = inttoptr i64 [[ARR_SIZE]] to i8*
|
||||||
|
// CHECK: store i8* [[BITCAST]], i8** [[ARR_SIZE_REF]],
|
||||||
|
// CHECK: [[ARRS_PRIV_REF:%.+]] = getelementptr inbounds [4 x i8*], [4 x i8*]* [[RED_LIST]], i64 0, i64 2
|
||||||
|
// CHECK: [[BITCAST:%.+]] = bitcast [[S_FLOAT_TY]]* [[ARRS_PRIV]] to i8*
|
||||||
|
// CHECK: store i8* [[BITCAST]], i8** [[ARRS_PRIV_REF]],
|
||||||
|
// CHECK: [[ARRS_SIZE_REF:%.+]] = getelementptr inbounds [4 x i8*], [4 x i8*]* [[RED_LIST]], i64 0, i64 3
|
||||||
|
// CHECK: [[BITCAST:%.+]] = inttoptr i64 [[ARRS_SIZE]] to i8*
|
||||||
|
// CHECK: store i8* [[BITCAST]], i8** [[ARRS_SIZE_REF]],
|
||||||
|
|
||||||
|
// res = __kmpc_reduce(<loc>, <gtid>, <n>, sizeof(RedList), RedList, reduce_func, &<lock>);
|
||||||
|
|
||||||
|
// 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: [[BITCAST:%.+]] = bitcast [4 x i8*]* [[RED_LIST]] to i8*
|
||||||
|
// CHECK: [[RES:%.+]] = call i32 @__kmpc_reduce_nowait(%{{.+}}* [[REDUCTION_LOC]], i32 [[GTID]], i32 2, 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:
|
||||||
|
// CHECK: [[CASE1]]
|
||||||
|
|
||||||
|
// arr[:] += arr_reduction[:];
|
||||||
|
// CHECK: [[END:%.+]] = getelementptr i32, i32* [[LB1_0]], i64 [[ARR_SIZE]]
|
||||||
|
// CHECK: [[ISEMPTY:%.+]] = icmp eq i32* [[LB1_0]], [[END]]
|
||||||
|
// CHECK: br i1 [[ISEMPTY]],
|
||||||
|
// CHECK: phi i32*
|
||||||
|
// CHECK: [[ADD:%.+]] = add nsw i32 %
|
||||||
|
// CHECK: store i32 [[ADD]], i32* %
|
||||||
|
// CHECK: [[DONE:%.+]] = icmp eq i32* %{{.+}}, [[END]]
|
||||||
|
// CHECK: br i1 [[DONE]],
|
||||||
|
|
||||||
|
// arrs[:] = var.operator &(arrs_reduction[:]);
|
||||||
|
// CHECK: [[END:%.+]] = getelementptr [[S_FLOAT_TY]], [[S_FLOAT_TY]]* [[ARRS_LB:%.+]], i64 [[ARRS_SIZE]]
|
||||||
|
// CHECK: [[ISEMPTY:%.+]] = icmp eq [[S_FLOAT_TY]]* [[ARRS_LB]], [[END]]
|
||||||
|
// CHECK: br i1 [[ISEMPTY]],
|
||||||
|
// CHECK: phi [[S_FLOAT_TY]]*
|
||||||
|
// CHECK: [[AND:%.+]] = call dereferenceable(4) [[S_FLOAT_TY]]* @_ZN1SIfEanERKS0_([[S_FLOAT_TY]]* %{{.+}}, [[S_FLOAT_TY]]* dereferenceable(4) %{{.+}})
|
||||||
|
// CHECK: [[BITCAST:%.+]] = bitcast [[S_FLOAT_TY]]* [[AND]] to i8*
|
||||||
|
// CHECK: call void @llvm.memcpy.p0i8.p0i8.i64(i8* %{{.+}}, i8* [[BITCAST]], i64 4, i32 4, i1 false)
|
||||||
|
// CHECK: [[DONE:%.+]] = icmp eq [[S_FLOAT_TY]]* %{{.+}}, [[END]]
|
||||||
|
// CHECK: br i1 [[DONE]],
|
||||||
|
|
||||||
|
// __kmpc_end_reduce(<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:
|
||||||
|
// CHECK: [[CASE2]]
|
||||||
|
|
||||||
|
// arr[:] += arr_reduction[:];
|
||||||
|
// CHECK: [[END:%.+]] = getelementptr i32, i32* [[LB1_0]], i64 [[ARR_SIZE]]
|
||||||
|
// CHECK: [[ISEMPTY:%.+]] = icmp eq i32* [[LB1_0]], [[END]]
|
||||||
|
// CHECK: br i1 [[ISEMPTY]],
|
||||||
|
// CHECK: phi i32*
|
||||||
|
// CHECK: atomicrmw add i32* %{{.+}}, i32 %{{.+}} monotonic
|
||||||
|
// CHECK: [[DONE:%.+]] = icmp eq i32* %{{.+}}, [[END]]
|
||||||
|
// CHECK: br i1 [[DONE]],
|
||||||
|
|
||||||
|
// arrs[:] = var.operator &(arrs_reduction[:]);
|
||||||
|
// CHECK: [[END:%.+]] = getelementptr [[S_FLOAT_TY]], [[S_FLOAT_TY]]* [[ARRS_LB:%.+]], i64 [[ARRS_SIZE]]
|
||||||
|
// CHECK: [[ISEMPTY:%.+]] = icmp eq [[S_FLOAT_TY]]* [[ARRS_LB]], [[END]]
|
||||||
|
// CHECK: br i1 [[ISEMPTY]],
|
||||||
|
// CHECK: phi [[S_FLOAT_TY]]*
|
||||||
|
// CHECK: call void @__kmpc_critical(
|
||||||
|
// CHECK: [[AND:%.+]] = call dereferenceable(4) [[S_FLOAT_TY]]* @_ZN1SIfEanERKS0_([[S_FLOAT_TY]]* %{{.+}}, [[S_FLOAT_TY]]* dereferenceable(4) %{{.+}})
|
||||||
|
// CHECK: [[BITCAST:%.+]] = bitcast [[S_FLOAT_TY]]* [[AND]] to i8*
|
||||||
|
// CHECK: call void @llvm.memcpy.p0i8.p0i8.i64(i8* %{{.+}}, i8* [[BITCAST]], i64 4, i32 4, i1 false)
|
||||||
|
// CHECK: call void @__kmpc_end_critical(
|
||||||
|
// CHECK: [[DONE:%.+]] = icmp eq [[S_FLOAT_TY]]* %{{.+}}, [[END]]
|
||||||
|
// CHECK: br i1 [[DONE]],
|
||||||
|
|
||||||
|
// break;
|
||||||
|
// CHECK: br label %[[RED_DONE]]
|
||||||
|
// CHECK: [[RED_DONE]]
|
||||||
|
|
||||||
|
// Check destruction of private copy.
|
||||||
|
// CHECK: [[END:%.+]] = getelementptr inbounds [[S_FLOAT_TY]], [[S_FLOAT_TY]]* [[ARRS_PRIV]], i64 [[ARRS_SIZE]]
|
||||||
|
// CHECK: [[ISEMPTY:%.+]] = icmp eq [[S_FLOAT_TY]]* [[ARRS_PRIV]], [[END]]
|
||||||
|
// CHECK: br i1 [[ISEMPTY]],
|
||||||
|
// CHECK: phi [[S_FLOAT_TY]]*
|
||||||
|
// CHECK: call void @_ZN1SIfED1Ev([[S_FLOAT_TY]]* %
|
||||||
|
// CHECK: [[DONE:%.+]] = icmp eq [[S_FLOAT_TY]]* %{{.+}}, [[ARRS_PRIV]]
|
||||||
|
// CHECK: br i1 [[DONE]],
|
||||||
|
// CHECK: call void @llvm.stackrestore(i8*
|
||||||
|
// 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 void @__kmpc_barrier(%{{.+}}* [[IMPLICIT_BARRIER_LOC]], i{{[0-9]+}} [[GTID]])
|
||||||
|
|
||||||
|
// 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*)
|
||||||
|
// arr_rhs = (int*)rhs[0];
|
||||||
|
// CHECK: [[ARR_RHS_REF:%.+]] = getelementptr inbounds [4 x i8*], [4 x i8*]* [[RED_LIST_RHS:%.+]], i64 0, i64 0
|
||||||
|
// CHECK: [[ARR_RHS_VOID:%.+]] = load i8*, i8** [[ARR_RHS_REF]],
|
||||||
|
// CHECK: [[ARR_RHS:%.+]] = bitcast i8* [[ARR_RHS_VOID]] to i32*
|
||||||
|
// arr_lhs = (int*)lhs[0];
|
||||||
|
// CHECK: [[ARR_LHS_REF:%.+]] = getelementptr inbounds [4 x i8*], [4 x i8*]* [[RED_LIST_LHS:%.+]], i64 0, i64 0
|
||||||
|
// CHECK: [[ARR_LHS_VOID:%.+]] = load i8*, i8** [[ARR_LHS_REF]],
|
||||||
|
// CHECK: [[ARR_LHS:%.+]] = bitcast i8* [[ARR_LHS_VOID]] to i32*
|
||||||
|
|
||||||
|
// arr_size = (size_t)lhs[1];
|
||||||
|
// CHECK: [[ARR_SIZE_REF:%.+]] = getelementptr inbounds [4 x i8*], [4 x i8*]* [[RED_LIST_LHS]], i64 0, i64 1
|
||||||
|
// CHECK: [[ARR_SIZE_VOID:%.+]] = load i8*, i8** [[ARR_SIZE_REF]],
|
||||||
|
// CHECK: [[ARR_SIZE:%.+]] = ptrtoint i8* [[ARR_SIZE_VOID]] to i64
|
||||||
|
|
||||||
|
// arrs_rhs = (S<float>*)rhs[2];
|
||||||
|
// CHECK: [[ARRS_RHS_REF:%.+]] = getelementptr inbounds [4 x i8*], [4 x i8*]* [[RED_LIST_RHS]], i64 0, i64 2
|
||||||
|
// CHECK: [[ARRS_RHS_VOID:%.+]] = load i8*, i8** [[ARRS_RHS_REF]],
|
||||||
|
// CHECK: [[ARRS_RHS:%.+]] = bitcast i8* [[ARRS_RHS_VOID]] to [[S_FLOAT_TY]]*
|
||||||
|
// arrs_lhs = (S<float>*)lhs[2];
|
||||||
|
// CHECK: [[ARRS_LHS_REF:%.+]] = getelementptr inbounds [4 x i8*], [4 x i8*]* [[RED_LIST_LHS]], i64 0, i64 2
|
||||||
|
// CHECK: [[ARRS_LHS_VOID:%.+]] = load i8*, i8** [[ARRS_LHS_REF]],
|
||||||
|
// CHECK: [[ARRS_LHS:%.+]] = bitcast i8* [[ARRS_LHS_VOID]] to [[S_FLOAT_TY]]*
|
||||||
|
|
||||||
|
// arrs_size = (size_t)lhs[3];
|
||||||
|
// CHECK: [[ARRS_SIZE_REF:%.+]] = getelementptr inbounds [4 x i8*], [4 x i8*]* [[RED_LIST_LHS]], i64 0, i64 3
|
||||||
|
// CHECK: [[ARRS_SIZE_VOID:%.+]] = load i8*, i8** [[ARRS_SIZE_REF]],
|
||||||
|
// CHECK: [[ARRS_SIZE:%.+]] = ptrtoint i8* [[ARRS_SIZE_VOID]] to i64
|
||||||
|
|
||||||
|
// arr_lhs[:] += arr_rhs[:];
|
||||||
|
// CHECK: [[END:%.+]] = getelementptr i32, i32* [[ARR_LHS]], i64 [[ARR_SIZE]]
|
||||||
|
// CHECK: [[ISEMPTY:%.+]] = icmp eq i32* [[ARR_LHS]], [[END]]
|
||||||
|
// CHECK: br i1 [[ISEMPTY]],
|
||||||
|
// CHECK: phi i32*
|
||||||
|
// CHECK: [[ADD:%.+]] = add nsw i32 %
|
||||||
|
// CHECK: store i32 [[ADD]], i32* %
|
||||||
|
// CHECK: [[DONE:%.+]] = icmp eq i32* %{{.+}}, [[END]]
|
||||||
|
// CHECK: br i1 [[DONE]],
|
||||||
|
|
||||||
|
// arrs_lhs = arrs_lhs.operator &(arrs_rhs);
|
||||||
|
// CHECK: [[END:%.+]] = getelementptr [[S_FLOAT_TY]], [[S_FLOAT_TY]]* [[ARRS_LB:%.+]], i64 [[ARRS_SIZE]]
|
||||||
|
// CHECK: [[ISEMPTY:%.+]] = icmp eq [[S_FLOAT_TY]]* [[ARRS_LB]], [[END]]
|
||||||
|
// CHECK: br i1 [[ISEMPTY]],
|
||||||
|
// CHECK: phi [[S_FLOAT_TY]]*
|
||||||
|
// CHECK: [[AND:%.+]] = call dereferenceable(4) [[S_FLOAT_TY]]* @_ZN1SIfEanERKS0_([[S_FLOAT_TY]]* %{{.+}}, [[S_FLOAT_TY]]* dereferenceable(4) %{{.+}})
|
||||||
|
// CHECK: [[BITCAST:%.+]] = bitcast [[S_FLOAT_TY]]* [[AND]] to i8*
|
||||||
|
// CHECK: call void @llvm.memcpy.p0i8.p0i8.i64(i8* %{{.+}}, i8* [[BITCAST]], i64 4, i32 4, i1 false)
|
||||||
|
// CHECK: [[DONE:%.+]] = icmp eq [[S_FLOAT_TY]]* %{{.+}}, [[END]]
|
||||||
|
// CHECK: br i1 [[DONE]],
|
||||||
|
|
||||||
|
// CHECK: ret void
|
||||||
|
|
||||||
// CHECK: define {{.*}} i{{[0-9]+}} [[TMAIN_INT]]()
|
// CHECK: define {{.*}} i{{[0-9]+}} [[TMAIN_INT]]()
|
||||||
// CHECK: [[TEST:%.+]] = alloca [[S_INT_TY]],
|
// CHECK: [[TEST:%.+]] = alloca [[S_INT_TY]],
|
||||||
// CHECK: call {{.*}} [[S_INT_TY_CONSTR:@.+]]([[S_INT_TY]]* [[TEST]])
|
// CHECK: call {{.*}} [[S_INT_TY_CONSTR:@.+]]([[S_INT_TY]]* [[TEST]])
|
||||||
|
|
|
@ -64,6 +64,8 @@ public:
|
||||||
S3 h, k;
|
S3 h, k;
|
||||||
#pragma omp threadprivate(h) // expected-note 2 {{defined as threadprivate or thread local}}
|
#pragma omp threadprivate(h) // expected-note 2 {{defined as threadprivate or thread local}}
|
||||||
|
|
||||||
|
char *get();
|
||||||
|
|
||||||
template <class T> // expected-note {{declared here}}
|
template <class T> // expected-note {{declared here}}
|
||||||
T tmain(T argc) {
|
T tmain(T argc) {
|
||||||
const T d = T(); // expected-note 4 {{'d' defined here}}
|
const T d = T(); // expected-note 4 {{'d' defined here}}
|
||||||
|
@ -196,6 +198,14 @@ T tmain(T argc) {
|
||||||
#pragma omp for reduction(+ : fl) // expected-error 2 {{reduction variable must be shared}}
|
#pragma omp for reduction(+ : fl) // expected-error 2 {{reduction variable must be shared}}
|
||||||
for (int i = 0; i < 10; ++i)
|
for (int i = 0; i < 10; ++i)
|
||||||
foo();
|
foo();
|
||||||
|
#pragma omp parallel private(qa) // expected-note 2 {{defined as private}}
|
||||||
|
#pragma omp for reduction(+ : qa[1], get()[0]) // expected-error 2 {{reduction variable must be shared}} expected-error {{expected variable name as a base of the array subscript}}
|
||||||
|
for (int i = 0; i < 10; ++i)
|
||||||
|
foo();
|
||||||
|
#pragma omp parallel shared(qa)
|
||||||
|
#pragma omp for reduction(+ : qa[1], qa[0]) // expected-error 2 {{variable can appear only once in OpenMP 'reduction' clause}} expected-note 2 {{previously referenced here}}
|
||||||
|
for (int i = 0; i < 10; ++i)
|
||||||
|
foo();
|
||||||
#pragma omp parallel reduction(* : fl) // expected-note 2 {{defined as reduction}}
|
#pragma omp parallel reduction(* : fl) // expected-note 2 {{defined as reduction}}
|
||||||
#pragma omp for reduction(+ : fl) // expected-error 2 {{reduction variable must be shared}}
|
#pragma omp for reduction(+ : fl) // expected-error 2 {{reduction variable must be shared}}
|
||||||
for (int i = 0; i < 10; ++i)
|
for (int i = 0; i < 10; ++i)
|
||||||
|
@ -353,6 +363,14 @@ int main(int argc, char **argv) {
|
||||||
#pragma omp for reduction(+ : fl) // expected-error {{reduction variable must be shared}}
|
#pragma omp for reduction(+ : fl) // expected-error {{reduction variable must be shared}}
|
||||||
for (int i = 0; i < 10; ++i)
|
for (int i = 0; i < 10; ++i)
|
||||||
foo();
|
foo();
|
||||||
|
#pragma omp parallel private(argv) // expected-note {{defined as private}}
|
||||||
|
#pragma omp for reduction(+ : argv[1], get()[0]) // expected-error {{reduction variable must be shared}} expected-error {{expected variable name as a base of the array subscript}}
|
||||||
|
for (int i = 0; i < 10; ++i)
|
||||||
|
foo();
|
||||||
|
#pragma omp parallel shared(qa)
|
||||||
|
#pragma omp for reduction(+ : qa[1], qa[0]) // expected-error {{variable can appear only once in OpenMP 'reduction' clause}} expected-note {{previously referenced here}}
|
||||||
|
for (int i = 0; i < 10; ++i)
|
||||||
|
foo();
|
||||||
#pragma omp parallel reduction(* : fl) // expected-note {{defined as reduction}}
|
#pragma omp parallel reduction(* : fl) // expected-note {{defined as reduction}}
|
||||||
#pragma omp for reduction(+ : fl) // expected-error {{reduction variable must be shared}}
|
#pragma omp for reduction(+ : fl) // expected-error {{reduction variable must be shared}}
|
||||||
for (int i = 0; i < 10; ++i)
|
for (int i = 0; i < 10; ++i)
|
||||||
|
|
|
@ -2106,6 +2106,9 @@ void OMPClauseEnqueue::VisitOMPSharedClause(const OMPSharedClause *C) {
|
||||||
}
|
}
|
||||||
void OMPClauseEnqueue::VisitOMPReductionClause(const OMPReductionClause *C) {
|
void OMPClauseEnqueue::VisitOMPReductionClause(const OMPReductionClause *C) {
|
||||||
VisitOMPClauseList(C);
|
VisitOMPClauseList(C);
|
||||||
|
for (auto *E : C->privates()) {
|
||||||
|
Visitor->AddStmt(E);
|
||||||
|
}
|
||||||
for (auto *E : C->lhs_exprs()) {
|
for (auto *E : C->lhs_exprs()) {
|
||||||
Visitor->AddStmt(E);
|
Visitor->AddStmt(E);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue