diff --git a/clang/tools/sotoc/CMakeLists.txt b/clang/tools/sotoc/CMakeLists.txt index abed06d81526e..6eb1382e75a96 100644 --- a/clang/tools/sotoc/CMakeLists.txt +++ b/clang/tools/sotoc/CMakeLists.txt @@ -28,6 +28,7 @@ set(USE_CLANG_LIBS clangFrontend set(SOTOC_SOURCES src/main.cpp src/TargetCode.cpp src/TargetCodeFragment.cpp + src/TargetRegionVariable.cpp src/Visitors.cpp src/DeclResolver.cpp src/OmpPragma.cpp) diff --git a/clang/tools/sotoc/src/OmpPragma.h b/clang/tools/sotoc/src/OmpPragma.h index a5bdf20baaa70..5c00600762977 100644 --- a/clang/tools/sotoc/src/OmpPragma.h +++ b/clang/tools/sotoc/src/OmpPragma.h @@ -37,7 +37,7 @@ class OmpPragma { public: OmpPragma(TargetCodeRegion *TCR) - : PP(TCR->getPP()), Clauses(*TCR->getOMPClauses()), + : PP(TCR->getPP()), Clauses(TCR->getOMPClauses()), Kind(TCR->getTargetCodeKind()){}; OmpPragma(clang::OMPExecutableDirective *Directive, clang::PrintingPolicy PP) : PP(PP), Clauses(Directive->clauses()), diff --git a/clang/tools/sotoc/src/TargetCode.cpp b/clang/tools/sotoc/src/TargetCode.cpp index 3e1aea0901959..9233d21f6a5d8 100644 --- a/clang/tools/sotoc/src/TargetCode.cpp +++ b/clang/tools/sotoc/src/TargetCode.cpp @@ -108,112 +108,104 @@ void TargetCode::generateFunctionPrologue(TargetCodeRegion *TCR, std::string elemType; bool first = true; Out << "void " << generateFunctionName(TCR) << "("; - for (auto i = TCR->getCapturedVarsBegin(), e = TCR->getCapturedVarsEnd(); - i != e; ++i) { - std::string VarName = (*i)->getDeclName().getAsString(); - auto C = TCR->GetReferredOMPClause(*i); + + for (auto &Var : TCR->capturedVars()) { if (!first) { Out << ", "; } first = false; - // check for constant or variable length arrays, because of - // AST representation and naive getType - if (auto t = clang::dyn_cast_or_null( - (*i)->getType().getTypePtr())) { - DEBUGP("Generating code for array type"); - int dim = 0; - - std::vector VariableDimensions; - handleArrays(&t, DimString, dim, VariableDimensions, TCR, elemType, - VarName); - - for (int d : VariableDimensions) { - Out << "unsigned long long __sotoc_vla_dim" << d << "_" << VarName + if (Var.isArray()) { + for (const unsigned int &d : Var.variabledSizedArrayDimensions()) { + Out << "unsigned long long __sotoc_vla_dim" << d << "_" << Var.name() << ", "; } + } + // Because arrays are passed by reference and (for our purposes) their type + // is 'void', the rest of their handling ist the same as for scalars. + if (Var.isArray()) { + Out << "void "; + } else { + Out << Var.typeName() << " "; + } - // set type to void* to avoid warnings from the compiler - Out << "void *__sotoc_var_"; - nDim.push_back(dim); // push total number of dimensions + if (Var.passedByPointer()) { + Out << "*__sotoc_var_"; + } + Out << Var.name(); + } + + for (auto *ClauseVar : TCR->ompClausesParams()) { + if (!first) { + Out << ", "; } else { - Out << (*i)->getType().getAsString() << " "; - if (!(*i)->getType().getTypePtr()->isPointerType()) { - if (C) { - // Parameters which are not first private (e.g., explicit mapped vars) - // are passed by reference, all others by value. - if (C->getClauseKind() != - clang::OpenMPClauseKind::OMPC_firstprivate && - C->getClauseKind() != - clang::OpenMPClauseKind::OMPC_private && - C->getClauseKind() != - clang::OpenMPClauseKind::OMPC_depend) { - Out << "*__sotoc_var_"; - } - } + first = false; + } + + // TODO: this is the same code as in TargetRegionVariable.cpp, so we might + // want to deduplicated this. + auto *ClauseVarType = ClauseVar->getType().getTypePtr(); + if (auto *AT = llvm::dyn_cast(ClauseVarType)) { + while (auto *NAT = llvm::dyn_cast(AT->getElementType().getTypePtr())) { + AT = NAT; } + Out << AT->getElementType().getAsString() << " *"; + } else { + Out << ClauseVar->getType().getAsString() << " "; } - Out << VarName; + Out << ClauseVar->getName(); } + Out << ")\n{\n"; // bring captured scalars into scope - for (auto I = TCR->getCapturedVarsBegin(), E = TCR->getCapturedVarsEnd(); - I != E; ++I) { - auto C = TCR->GetReferredOMPClause(*I); - // again check for constant and variable-length arrays - if (auto t = clang::dyn_cast_or_null( - (*I)->getType().getTypePtr())) { - auto VarName = (*I)->getDeclName().getAsString(); - - do { - t = clang::dyn_cast_or_null( - t->getElementType().getTypePtr()); - } while (t != NULL); - - Out << " " << elemType << " (*" << VarName << ")"; - - // Get number of Dimensions(nDim) and write sizes(DimString) - for (int i = 1; i < nDim.front(); i++) { - DimString.pop_front(); - Out << "[" << DimString.front() << "]"; - } - DimString.pop_front(); // remove last size - nDim.pop_front(); // remove number of dimensions of last variable - - Out << " = __sotoc_var_" << VarName << ";\n"; - - auto LowerBound = TCR->CapturedLowerBounds.find(*I); - if (LowerBound != TCR->CapturedLowerBounds.end()) { - Out << VarName << " = " << VarName << " - ("; - LowerBound->second->printPretty(Out, NULL, TCR->getPP()); - Out << ");\n"; - } - - } else { - if (!(*I)->getType().getTypePtr()->isPointerType()) { - if (C) { - // Parameters which are not first private (e.g., explicit mapped vars) - // are passed by reference, all others by value. - if (C->getClauseKind() != - clang::OpenMPClauseKind::OMPC_firstprivate && - C->getClauseKind() != - clang::OpenMPClauseKind::OMPC_private && - C->getClauseKind() != - clang::OpenMPClauseKind::OMPC_depend) { - auto VarName = (*I)->getDeclName().getAsString(); - Out << " " << (*I)->getType().getAsString() << " " << VarName - << " = " - << "*__sotoc_var_" << VarName << ";\n"; + for (auto &Var : TCR->capturedVars()) { + // Ignore everything not passed by reference here + if (Var.passedByPointer()) { + // Handle multi-dimensional arrays + if (Var.isArray()) { + // Declare the arrays as a pointer. This way we can assign it a pointer + // However, this also means we have to ignore the first array + // dimension. + Out << " " << Var.typeName() << " (*" << Var.name() << ")"; + + // For every array dimension other then the first: declare them by + // adding the array brackets ('[', ']') to the declaration. Also add + // the size of this dimension if we have it. + bool first = true; + for (auto &dimensionSize: Var.arrayDimensionSizes()) { + //We need to discard the first element + if (first) { + first = false; + continue; } + Out << "[" << dimensionSize << "]"; + } + // After we have declare the array, we also need to assign it. + // We may also have to adjust the array bounds if we only get a slice + // of the array (in the first dimesion. All other dimensions should + // not require adjustment as their slicing is ignored) + Out << " = __sotoc_var_" << Var.name() << ";\n"; + // Move the bounds if we have a slice + auto LowerBound = Var.arrayLowerBound(); + if (LowerBound.hasValue()) { + Out << " " << Var.name() << " = " << Var.name() << " - "; + LowerBound.getValue()->printPretty(Out, NULL, TCR->getPP()); + Out << ";\n"; } + } else { + // Handle all other types passed by reference + Out << Var.typeName() << " " << Var.name() << " = " + << "*__sotoc_var_" << Var.name() << ";\n"; } } } - Out << "\n"; // Generate local declarations. - Out << TCR->PrintLocalVarsFromClauses(); + for (auto *privateVar: TCR->privateVars()) { + Out << " " << privateVar->getType().getAsString() << " " + << privateVar->getName() << ";\n"; + } // The runtime can decide to only create one team. // Therfore, replace target teams constructs. @@ -235,31 +227,9 @@ void TargetCode::generateFunctionEpilogue(TargetCodeRegion *TCR, Out << "\n"; // copy values from scalars from scoped vars back into pointers - for (auto I = TCR->getCapturedVarsBegin(), E = TCR->getCapturedVarsEnd(); - I != E; ++I) { - auto C = TCR->GetReferredOMPClause(*I); - - // if array then already pointer - if (auto t = clang::dyn_cast_or_null( - (*I)->getType().getTypePtr())) { - auto VarName = (*I)->getDeclName().getAsString(); - Out << "\n __sotoc_var_" << VarName << " = " << VarName << ";"; - } else { - if (!(*I)->getType().getTypePtr()->isPointerType()) { - if (C) { - // Parameters which are not first private (e.g., explicit mapped vars) - // are passed by reference, all others by value. - if (C->getClauseKind() != - clang::OpenMPClauseKind::OMPC_firstprivate && - C->getClauseKind() != - clang::OpenMPClauseKind::OMPC_private && - C->getClauseKind() != - clang::OpenMPClauseKind::OMPC_depend) { - auto VarName = (*I)->getDeclName().getAsString(); - Out << "\n *__sotoc_var_" << VarName << " = " << VarName << ";"; - } - } - } + for (auto &Var : TCR->capturedVars()) { + if (Var.passedByPointer() && !Var.isArray()) { + Out << "\n *__sotoc_var_" << Var.name() << " = " << Var.name() << ";"; } } @@ -283,48 +253,3 @@ std::string TargetCode::generateFunctionName(TargetCodeRegion *TCR) { << LineNum; return FunctionName; } - -void TargetCode::handleArrays(const clang::ArrayType **t, - std::list &DimString, int &dim, - std::vector &VariableDims, - TargetCodeRegion *TCR, std::string &elemType, - const std::string &ArrayName) { - auto OrigT = *t; - - if (!t) { - return; - } else { - // We just remember the last element type - elemType = OrigT->getElementType().getAsString(); - DEBUGP("The last QualType of the array is: " + elemType); - } - - if (auto t1 = clang::dyn_cast_or_null(OrigT)) { - DEBUGP("ArrayType is CAT"); - DimString.push_back(t1->getSize().toString(10, false)); - ++dim; - - } else if (auto t1 = - clang::dyn_cast_or_null(OrigT)) { - DEBUGP("ArrayType VAT"); - std::string PrettyStr = ""; - llvm::raw_string_ostream PrettyOS(PrettyStr); - PrettyOS << "__sotoc_vla_dim" << dim << "_" << ArrayName; - DimString.push_back(PrettyOS.str()); - VariableDims.push_back(dim); - ++dim; - - } else { - DEBUGP("No more array dimensions"); - // Restore t if we dont have an array type anymore - *t = OrigT; - return; - } - - (*t) = clang::dyn_cast_or_null( - OrigT->getElementType().getTypePtr()); - if (*t) { - // Recursively handle all dimensions - handleArrays(t, DimString, dim, VariableDims, TCR, elemType, ArrayName); - } -} diff --git a/clang/tools/sotoc/src/TargetCode.h b/clang/tools/sotoc/src/TargetCode.h index 369cefa804f39..02bd263044d21 100644 --- a/clang/tools/sotoc/src/TargetCode.h +++ b/clang/tools/sotoc/src/TargetCode.h @@ -74,17 +74,4 @@ class TargetCode { void generateFunctionEpilogue(TargetCodeRegion *TCR, llvm::raw_ostream &Out); /// Generate a function name for a target region. std::string generateFunctionName(TargetCodeRegion *TCR); - - /// This function recursively handles constant and variable-length array types - /// and any mixed forms. Incomplete array types are not supported at the - /// moment. - /// \param t The (n-dimensional) array - /// \param DimString A list of string which returns one entry per dimension - /// \param dim The dimension count - /// \param TCR The target code region - /// \param returns the last element type (i.e., the type of the array) - void handleArrays(const clang::ArrayType **t, - std::list &DimString, int &dim, - std::vector &VariableDimensions, TargetCodeRegion *TCR, - std::string &elemType, const std::string &ArrayName); }; diff --git a/clang/tools/sotoc/src/TargetCodeFragment.cpp b/clang/tools/sotoc/src/TargetCodeFragment.cpp index 5478ef403039f..e3ed02e003dda 100644 --- a/clang/tools/sotoc/src/TargetCodeFragment.cpp +++ b/clang/tools/sotoc/src/TargetCodeFragment.cpp @@ -25,57 +25,31 @@ #include "clang/Lex/Lexer.h" #include "clang/Lex/Token.h" +#include "Debug.h" #include "OmpPragma.h" #include "TargetCodeFragment.h" -void TargetCodeRegion::addCapturedVar(clang::VarDecl *Var) { - CapturedVars.push_back(Var); +void TargetCodeRegion::addCapture(const clang::CapturedStmt::Capture *Capture) { + CapturedVars.push_back(TargetRegionVariable(Capture, CapturedLowerBounds)); } -void TargetCodeRegion::addOpenMPClause(clang::OMPClause *Clause) { - if (Clause->getClauseKind() != clang::OMPC_device) - addClauseVars(Clause); - - OMPClauses.push_back(Clause); - -} - -void TargetCodeRegion::hAddClauseVars(std::set *tmpSet, clang::Stmt* Cc) { - if (llvm::isa(Cc)) { - tmpSet->insert(llvm::dyn_cast_or_null(llvm::dyn_cast_or_null(Cc)->getDecl())); - } - for (auto *Ccc : Cc->children()) { - if (llvm::isa(Ccc)) { - for (auto *Cccc : Ccc->children()) { - hAddClauseVars(tmpSet,Cccc); - } +void TargetCodeRegion::addOMPClauseParam(clang::VarDecl *Param) { + for (auto &CV : capturedVars()) { + if (CV.getDecl() == Param) { + return; } } -} -void TargetCodeRegion::addClauseVars(clang::OMPClause *Clause) { - std::set tmpSet; - - // If an Clause uses an variable then find them and add - for (auto *C : Clause->children()) { - if (llvm::isa(C)) { - for (auto *Cc : C->children()) { - for (auto *Ccc : llvm::dyn_cast_or_null(llvm::dyn_cast_or_null(Cc)->getDecl())->getInit()->children()){ - hAddClauseVars(&tmpSet,Ccc); - } - } - } + if (std::find(OMPClausesParams.begin(), OMPClausesParams.end(), Param) != OMPClausesParams.end()) { + return; } - for (auto v : CapturedVars) { - if (tmpSet.find(v) != tmpSet.end()) - tmpSet.erase(tmpSet.find(v)); - } - - for (auto v: tmpSet) { - addCapturedVar(v); - } + DEBUGP("Adding variable " << Param->getName() << "as OpenMP clause parameter"); + OMPClausesParams.push_back(Param); +} +void TargetCodeRegion::addOMPClause(clang::OMPClause *Clause) { + OMPClauses.push_back(Clause); } static bool hasRegionCompoundStmt(const clang::Stmt *S) { @@ -214,49 +188,6 @@ clang::SourceRange TargetCodeRegion::getInnerRange() { return clang::SourceRange(InnerLocStart, InnerLocEnd); } -std::string TargetCodeRegion::PrintLocalVarsFromClauses() { - std::stringstream Out; - std::set Printed; - for (auto C : OMPClauses) { - if (C->getClauseKind() == clang::OpenMPClauseKind::OMPC_private) { - auto PC = llvm::dyn_cast(C); - for (auto Var : PC->varlists()) { - - // If the variable is already captured -> do not print - if (auto *DRE = llvm::dyn_cast(Var)) { - auto *VarDecl = DRE->getDecl(); - if(std::find(CapturedVars.begin(), CapturedVars.end(), VarDecl) != CapturedVars.end()) { - continue; - } - } - std::string PrettyStr = ""; - llvm::raw_string_ostream PrettyOS(PrettyStr); - Var->printPretty(PrettyOS, NULL, PP); - std::string VarName = PrettyOS.str(); - if (!Printed.count(VarName)) { - Out << " " << Var->getType().getAsString() << " " << VarName - << ";\n"; - Printed.insert(VarName); - } - } - } - } - return Out.str(); -} - -clang::OMPClause *TargetCodeRegion::GetReferredOMPClause(clang::VarDecl *i) { - for (auto C : OMPClauses) { - for (auto CC : C->children()) { - if (auto CC_DeclRefExpr = - llvm::dyn_cast_or_null(CC)) { - if (i->getCanonicalDecl() == CC_DeclRefExpr->getDecl()) - return C; - } - } - } - return NULL; -} - class TargetRegionPrinterHelper : public clang::PrinterHelper { clang::PrintingPolicy PP; @@ -294,11 +225,6 @@ std::string TargetCodeRegion::PrintPretty() { } clang::SourceRange TargetCodeDecl::getRealRange() { - // return DeclNode->getSourceRange(); - // return DeclNode->getSourceRange(); - // auto &SM = DeclNode->getASTContext().getSourceManager(); - // return clang::SourceRange(SM.getSpellingLoc(DeclNode->getBeginLoc()), - // SM.getSpellingLoc(DeclNode->getEndLoc())); return DeclNode->getSourceRange(); } diff --git a/clang/tools/sotoc/src/TargetCodeFragment.h b/clang/tools/sotoc/src/TargetCodeFragment.h index 0dd781b8080c7..6d83f78487479 100644 --- a/clang/tools/sotoc/src/TargetCodeFragment.h +++ b/clang/tools/sotoc/src/TargetCodeFragment.h @@ -18,6 +18,8 @@ #include "clang/AST/StmtOpenMP.h" #include "clang/Basic/OpenMPKinds.h" +#include "TargetRegionVariable.h" + // forward declaration of clang types namespace clang { class SourceLocation; @@ -102,12 +104,6 @@ class TargetCodeRegion : public TargetCodeFragment { }; private: - /// All variable captured by this target region. We will need to generated - /// pointers to them as arguments to the generated functions and copy the - /// variables into scope. - std::vector CapturedVars; - /// All omp clauses relevant to the execution of the region. - std::vector OMPClauses; /// The AST node for the captured statement of the target region. clang::CapturedStmt *CapturedStmtNode; /// AST node for the target directive @@ -115,6 +111,20 @@ class TargetCodeRegion : public TargetCodeFragment { /// Declaration of the function this region is declared in. Necessary to /// compose the function name of this region in the generated code. clang::FunctionDecl *ParentFunctionDecl; + /// All variable captured by this target region. We will need to generated + /// pointers to them as arguments to the generated functions and copy the + /// variables into scope. + std::vector CapturedVars; + /// All omp clauses relevant to the execution of the region. + std::vector OMPClauses; + /// The variables which are parameters for top level OpenMP clauses. + /// These are not captured but still needs passed as (first private) arguments + /// to the target region. + std::vector OMPClausesParams; + /// All private variables in a Target Region i.e. all variables that are not + /// passed as arguments into the region. + /// For these, we need to generate declarations inside the target region. + std::set PrivateVars; public: TargetCodeRegion(clang::CapturedStmt *CapturedStmtNode, @@ -125,28 +135,52 @@ class TargetCodeRegion : public TargetCodeFragment { CapturedStmtNode(CapturedStmtNode), TargetDirective(TargetDirective), ParentFunctionDecl(ParentFunctionDecl){}; - void addCapturedVar(clang::VarDecl *Var); - void addOpenMPClause(clang::OMPClause *Clause); - void hAddClauseVars(std::set* tmpSet, clang::Stmt* Cc); - void addClauseVars(clang::OMPClause *Clause); - std::vector::const_iterator getCapturedVarsBegin() { + using captured_vars_const_iterator = std::vector::const_iterator; + using captured_vars_const_range = llvm::iterator_range; + using private_vars_const_iterator = std::set::const_iterator; + using private_vars_const_range = llvm::iterator_range; + using ompclauses_params_const_iterator = std::vector::const_iterator; + using ompclauses_params_const_range = llvm::iterator_range; + + /// Add a captured variable of the target region. + /// This will automatically create and save a \ref TargetRegionVariable + /// which holds all information to generate parameters for the generated + /// target region function. + void addCapture(const clang::CapturedStmt::Capture *Capture); + captured_vars_const_iterator getCapturedVarsBegin() { return CapturedVars.begin(); }; - std::vector::const_iterator getCapturedVarsEnd() { + captured_vars_const_iterator getCapturedVarsEnd() { return CapturedVars.end(); }; - std::vector *getOMPClauses() { return &OMPClauses; } - std::vector::const_iterator getOMPClausesBegin() { - return OMPClauses.begin(); - } - std::vector::const_iterator getOMPClausesEnd() { - return OMPClauses.end(); - } + captured_vars_const_range capturedVars() { + return captured_vars_const_range(getCapturedVarsBegin(), getCapturedVarsEnd()); + }; + /// Adds a (top level) OpenMP clause for the target region. + /// These clauses are later used to determine which OpenMP #pragma needs to be + /// generated at the top level of the target region function. + void addOMPClause(clang::OMPClause *Clause); + const std::vector &getOMPClauses() const { + return OMPClauses; + }; + /// Sets the private variables of this target region. + void setPrivateVars(const std::set &VarSet) { + PrivateVars = VarSet; + }; + /// Returns a range over the private variables of this region. + private_vars_const_range privateVars() { + return private_vars_const_range(PrivateVars.cbegin(), PrivateVars.cend()); + }; + /// Returns a range over the parameters to the top level OpenMP clauses. + ompclauses_params_const_range ompClausesParams() { + return ompclauses_params_const_range(OMPClausesParams.cbegin(), OMPClausesParams.cend()); + }; + /// Adds a parameter of a top level OpenMP clause to the target regions + /// function as a function parameter. + void addOMPClauseParam(clang::VarDecl *Param); bool hasCombineConstruct() { return TargetCodeKind != clang::OpenMPDirectiveKind::OMPD_target; } - std::string PrintLocalVarsFromClauses(); - clang::OMPClause *GetReferredOMPClause(clang::VarDecl *i); virtual std::string PrintPretty() override; clang::SourceRange getRealRange() override; clang::SourceRange getInnerRange() override; diff --git a/clang/tools/sotoc/src/TargetRegionVariable.cpp b/clang/tools/sotoc/src/TargetRegionVariable.cpp new file mode 100644 index 0000000000000..b99b261a6b4f3 --- /dev/null +++ b/clang/tools/sotoc/src/TargetRegionVariable.cpp @@ -0,0 +1,85 @@ +//===-- sotoc/src/TargetRegionVariable.cpp --------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// This file implements the class TargetRegionVariable +/// +//===----------------------------------------------------------------------===// + + +#include "clang/AST/Decl.h" +#include "clang/AST/Expr.h" +#include "clang/AST/Type.h" + +#include "TargetRegionVariable.h" + +TargetRegionVariable::TargetRegionVariable(const clang::CapturedStmt::Capture *Capture, const std::map &MappingLowerBounds) + : Capture(Capture), Decl(Capture->getCapturedVar()), + OmpMappingLowerBound(MappingLowerBounds) { + + VarName = Decl->getDeclName().getAsString(); + + auto DeclType = Decl->getType(); + // If Decl is an array: get to the base type + if (auto *AT = llvm::dyn_cast(DeclType.getTypePtr())) { + while (auto *NAT = llvm::dyn_cast(AT->getElementType().getTypePtr())) { + AT = NAT; + } + TypeName = AT->getElementType().getAsString(); + } else { + TypeName = DeclType.getAsString(); + } + + if (auto ArrayType = llvm::dyn_cast(Decl->getType().getTypePtr())) { + determineDimensionSizes(ArrayType, 0); + } +} + +void TargetRegionVariable::determineDimensionSizes( + const clang::ArrayType *T, unsigned int CurrentDimension) { + if (auto *SubArray = llvm::dyn_cast_or_null(T)) { + DimensionSizes.push_back(SubArray->getSize().toString(10, false)); + } else if (auto *SubArray = + llvm::dyn_cast_or_null(T)) { + // For variable sized array dimension we get the size as an additonal + // parameter to the target function. + std::string PrettyStr = ""; + llvm::raw_string_ostream PrettyOS(PrettyStr); + PrettyOS << "__sotoc_vla_dim" << CurrentDimension << "_" << VarName; + DimensionSizes.push_back(PrettyOS.str()); + VarSizedDimensions.push_back(CurrentDimension); + } + + CurrentDimension++; + auto *NextDimensionArray = clang::dyn_cast_or_null( + T->getElementType().getTypePtr()); + if (NextDimensionArray) { + determineDimensionSizes(NextDimensionArray, CurrentDimension); + } +} + +bool TargetRegionVariable::isArray() const { + return llvm::isa(Decl->getType().getTypePtr()); +} + +bool TargetRegionVariable::passedByPointer() const { + if (isArray()) { + // Arrays are always passed by pointer + return true; + } + return Capture->capturesVariable(); +} + +llvm::Optional TargetRegionVariable::arrayLowerBound() const { + auto FindBound = OmpMappingLowerBound.find(Decl); + if (FindBound != OmpMappingLowerBound.cend()) { + return llvm::Optional(FindBound->second); + } + return llvm::Optional(); +} diff --git a/clang/tools/sotoc/src/TargetRegionVariable.h b/clang/tools/sotoc/src/TargetRegionVariable.h new file mode 100644 index 0000000000000..38700a5c8e1d6 --- /dev/null +++ b/clang/tools/sotoc/src/TargetRegionVariable.h @@ -0,0 +1,97 @@ +//===-- sotoc/src/TargetRegionVariable.h ----------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#pragma once + +#include +#include + +namespace clang { + class Expr; + class VarDecl; + class CapturedStmt; +} + +/// Represents a variable captured by a target region. +/// This class is an abstraction that provides information on how the variable +/// is passed to the target region, whether it is a slice or array and how it's +/// dimensionality is declared +class TargetRegionVariable { + + const clang::CapturedStmt::Capture *Capture; + clang::VarDecl *Decl; + std::string VarName; + std::string TypeName; + std::vector DimensionSizes; + std::vector VarSizedDimensions; + void determineDimensionSizes(const clang::ArrayType *T, + unsigned int CurrentDimension); + +public: + /// Const range over strings that specify the size of each dimension of an + /// array. + using const_dimension_sizes_range = + llvm::iterator_range::const_iterator>; + /// Const size over indices of variable sized dimensions. + using variable_sized_dimensions_range = + llvm::iterator_range::const_iterator>; + +private: + const std::map &OmpMappingLowerBound; + +public: + /// The name of the variable. + llvm::StringRef name() const { + return llvm::StringRef(VarName); + }; + /// The name of the type variable. + llvm::StringRef typeName() const { + return llvm::StringRef(TypeName); + }; + /// The Decl node of the variable. + clang::VarDecl *getDecl() const { + return Decl; + }; + /// Wether this variable is an array or not + bool isArray() const; + /// Returns true if this variable is passed by pointer. + /// This is the case for shared and first-private variables scalars and for + /// arrays. + bool passedByPointer() const; + /// Returns the (ordered) indices of the array dimensions which are variable + /// (i.e. non-constants). + /// Does not yield any values if the variable is a scalar. + variable_sized_dimensions_range variabledSizedArrayDimensions() const { + return variable_sized_dimensions_range(VarSizedDimensions.cbegin(), + VarSizedDimensions.cend()); + } + /// The lower bound of an array slice in the first dimension. + /// All other dimension can be ignored because libomptarget only transfers + /// continuous data. + /// In case of a scalar (or an array which is mapped completly in the first + /// dimension) this returns 0. + llvm::Optional arrayLowerBound() const; + /// Returns the size of each dimension of an array, as strings taken from the + /// declaration. + /// Because these sizes are only used when printing them back into the target + /// code, strings are returned. + /// When the class represents a scalar, then there are no elements to iterate + /// over. When the size of a dimension is not declared, then an empty string + /// is returned. + const_dimension_sizes_range arrayDimensionSizes() const { + return const_dimension_sizes_range(DimensionSizes.cbegin(), + DimensionSizes.cend()); + } + + bool operator==(const TargetRegionVariable &Other) const { + return Decl == Other.Decl; + } + + TargetRegionVariable(const clang::CapturedStmt::Capture* Capture, const std::map &MappingLowerBounds); +}; diff --git a/clang/tools/sotoc/src/Visitors.cpp b/clang/tools/sotoc/src/Visitors.cpp index 71024dc696bfe..f54bf066e7e33 100644 --- a/clang/tools/sotoc/src/Visitors.cpp +++ b/clang/tools/sotoc/src/Visitors.cpp @@ -87,7 +87,7 @@ llvm::Optional getSystemHeaderForDecl(clang::Decl *D) { bool FindTargetCodeVisitor::TraverseDecl(clang::Decl *D) { if (auto *FD = llvm::dyn_cast(D)) { LastVisitedFuncDecl.push(FD); - } + } bool ret = clang::RecursiveASTVisitor::TraverseDecl(D); if (auto *FD = llvm::dyn_cast(D)) { LastVisitedFuncDecl.pop(); @@ -131,18 +131,49 @@ bool FindTargetCodeVisitor::VisitStmt(clang::Stmt *S) { return true; } -class CollectOMPClausesVisitor - : public clang::RecursiveASTVisitor { +class CollectOMPClauseParamsVarsVisitor + : public clang::RecursiveASTVisitor { std::shared_ptr TCR; +public: + CollectOMPClauseParamsVarsVisitor(std::shared_ptr &TCR) + : TCR(TCR) {}; + + bool VisitStmt(clang::Stmt *S) { + if (auto *DRE = llvm::dyn_cast(S)) { + if (auto *VD = llvm::dyn_cast(DRE->getDecl())) { + TCR->addOMPClauseParam(VD->getCanonicalDecl()); + } + } + return true; + }; +}; +class CollectOMPClauseParamsVisitor + : public clang::RecursiveASTVisitor { + + CollectOMPClauseParamsVarsVisitor VarsVisitor; + bool InExplicitCast; public: - CollectOMPClausesVisitor(std::shared_ptr &TCR) : TCR(TCR){}; + CollectOMPClauseParamsVisitor(std::shared_ptr &TCR) + : VarsVisitor(TCR), InExplicitCast(false) {}; bool VisitStmt(clang::Stmt *S) { - if (auto *OED = llvm::dyn_cast(S)) { - for (auto *Clause : OED->clauses()) { - TCR->addOpenMPClause(Clause); + // THis relies on the captured statement being the last child + if (llvm::isa(S)) { + return false; + } + + if (llvm::isa(S)) { + InExplicitCast = true; + return true; + } + + auto *DRE = llvm::dyn_cast(S); + if (DRE && InExplicitCast) { + if (auto *VD = llvm::dyn_cast(DRE->getDecl())) { + VarsVisitor.TraverseStmt(VD->getInit()); } } + InExplicitCast = false; return true; }; }; @@ -166,20 +197,17 @@ bool FindTargetCodeVisitor::processTargetRegion( // if the target region cannot be added we dont want to parse its args if (TargetCodeInfo.addCodeFragment(TCR)) { - FindArraySectionVisitor ArraySectionVisitor(TCR->CapturedLowerBounds); - ArraySectionVisitor.TraverseStmt(TargetDirective); + FindArraySectionVisitor(TCR->CapturedLowerBounds).TraverseStmt(TargetDirective); - // look for nested clause - CollectOMPClausesVisitor(TCR).TraverseStmt(CS); for (auto C : TargetDirective->clauses()) { - TCR->addOpenMPClause(C); + TCR->addOMPClause(C); } // For more complex data types (like structs) we need to traverse the // tree DiscoverTypeVisitor.TraverseStmt(CS); DiscoverFunctionVisitor.TraverseStmt(CS); - addTargetRegionArgs(CS, TCR); + addTargetRegionArgs(CS, TargetDirective, TCR); TCR->NeedsSemicolon = stmtNeedsSemicolon(CS); TCR->TargetCodeKind = TargetDirective->getDirectiveKind(); } @@ -189,14 +217,14 @@ bool FindTargetCodeVisitor::processTargetRegion( } void FindTargetCodeVisitor::addTargetRegionArgs( - clang::CapturedStmt *S, std::shared_ptr TCR) { + clang::CapturedStmt *S, clang::OMPExecutableDirective *TargetDirective, + std::shared_ptr TCR) { DEBUGP("Add target region args"); for (const auto &i : S->captures()) { if (!(i.capturesVariableArrayType())) { - clang::VarDecl *var = i.getCapturedVar(); - DEBUGP("captured Var: " + var->getNameAsString()); - TCR->addCapturedVar(var); + DEBUGP("captured Var: " + i.getCapturedVar()->getNameAsString()); + TCR->addCapture(&i); } else { // Not sure what exactly is caputred here. It looks like we have an // additional capture in cases of VATs. @@ -204,53 +232,23 @@ void FindTargetCodeVisitor::addTargetRegionArgs( } } - FindLoopStmtVisitor FindLoopVisitor; - FindLoopVisitor.TraverseStmt(S); - - std::unordered_set tmpSet; - - // printf("%lu \n", FindLoopVisitor.getVarSet()->size()); - for (const auto i : *FindLoopVisitor.getVarSet()) { - DEBUGP("Iterating var set"); - // i->print(llvm::outs()); - if (Context.getSourceManager().isBeforeInTranslationUnit( - S->getBeginLoc(), i->getSourceRange().getBegin())) { - tmpSet.insert(i); - continue; - } - for (auto j : *TCR->getOMPClauses()) { - for (auto CC : j->children()) { - if (auto CC_DeclRefExpr = - llvm::dyn_cast_or_null(CC)) { - // CC_DeclRefExpr->dumpColor(); - if (i->getCanonicalDecl() == CC_DeclRefExpr->getDecl()) - tmpSet.insert(i); - } - } - } - - for (auto j = TCR->getCapturedVarsBegin(), e = TCR->getCapturedVarsEnd(); - j != e; ++j) { - if (i->getCanonicalDecl() == *j) { - // i->print(llvm::outs()); - DEBUGPDECL(i, "Add captured var: "); - // FindLoopVisitor.getVarSet()->erase(i); - tmpSet.insert(i); - } - } - } + // Find all not locally declared variables in the region + FindPrivateVariablesVisitor PrivateVarsVisitor(S->getBeginLoc(), + Context.getSourceManager()); + PrivateVarsVisitor.TraverseStmt(S); - for (const auto i : tmpSet) { - FindLoopVisitor.getVarSet()->erase(FindLoopVisitor.getVarSet()->find(i)); + // Remove any not locally declared variables which are already captured + auto VarSet = PrivateVarsVisitor.getVarSet(); + for (auto &CapturedVar : TCR->capturedVars()) { + VarSet.erase(CapturedVar.getDecl()); } - tmpSet.clear(); + // Add variables used in OMP clauses which are not captured as first-private + // variables + CollectOMPClauseParamsVisitor(TCR).TraverseStmt(TargetDirective); - // printf("%lu \n", FindLoopVisitor.getVarSet()->size()); - for (const auto i : *FindLoopVisitor.getVarSet()) { - // i->print(llvm::outs()); - TCR->addCapturedVar(i); - } + // Add non-local, non-capured variable as private variables + TCR->setPrivateVars(VarSet); } bool FindTargetCodeVisitor::VisitDecl(clang::Decl *D) { @@ -280,32 +278,17 @@ bool FindTargetCodeVisitor::VisitDecl(clang::Decl *D) { bool FindLoopStmtVisitor::VisitStmt(clang::Stmt *S) { if (auto LS = llvm::dyn_cast(S)) { - // LS->getInit()->dumpColor(); FindDeclRefVisitor.TraverseStmt(LS->getInit()); } - // else if (auto LS = llvm::dyn_cast(S)) { - // FindDeclRefVisitor.TraverseStmt(LS); - // } else if (auto LS = llvm::dyn_cast(S)) { - // FindDeclRefVisitor.TraverseStmt(LS); - // } return true; } -// bool FindDeclRefExprVisitor::VisitDecl(clang::Decl *D) { -// printf("VisitDecl\n"); -// D->dumpColor(); -// return true; -// } bool FindDeclRefExprVisitor::VisitStmt(clang::Stmt *S) { - // printf("VisitStmt\n"); - // S->dumpColor(); if (auto DRE = llvm::dyn_cast(S)) { if (auto DD = llvm::dyn_cast(DRE->getDecl())) { if (auto VD = llvm::dyn_cast(DD)) { if (VD->getNameAsString() != ".reduction.lhs") { - // printf("VarDecl\n"); - // VD->print(llvm::outs()); VarSet.insert(VD); } } @@ -411,3 +394,24 @@ bool FindArraySectionVisitor::VisitExpr(clang::Expr *E) { } return true; } + +bool FindPrivateVariablesVisitor::VisitExpr(clang::Expr *E) { + if (auto *DRE = llvm::dyn_cast(E)) { + if (auto *VD = llvm::dyn_cast(DRE->getDecl())) { + // We do not collect variables in 'collect target' declarations. + for (auto &attr : VD->attrs()) { + if (attr->getKind() == clang::attr::OMPDeclareTargetDecl) { + return true; + } + } + + // If the variable is declared outside of the target region it may be a + // private variable + if (SM.isBeforeInTranslationUnit(VD->getLocation(), RegionTopSourceLocation)) { + // Add the Variable to our set + VarSet.insert(VD); + } + } + } + return true; +} diff --git a/clang/tools/sotoc/src/Visitors.h b/clang/tools/sotoc/src/Visitors.h index ba3ef6110780e..c9bb512dad90e 100644 --- a/clang/tools/sotoc/src/Visitors.h +++ b/clang/tools/sotoc/src/Visitors.h @@ -148,6 +148,7 @@ class FindTargetCodeVisitor /// Finds and adds all variables required by the target regions as arguments /// to the generated function. void addTargetRegionArgs(clang::CapturedStmt *S, + clang::OMPExecutableDirective *TargetDirective, std::shared_ptr TCR); }; @@ -162,3 +163,20 @@ class FindArraySectionVisitor : LowerBoundsMap(LowerBoundsMap) {} bool VisitExpr(clang::Expr *E); }; + +class FindPrivateVariablesVisitor + : public clang::RecursiveASTVisitor { + + clang::SourceManager &SM; + clang::SourceLocation RegionTopSourceLocation; + std::set VarSet; + +public: + FindPrivateVariablesVisitor(clang::SourceLocation TopSourceLocation, clang::SourceManager &SM) + : RegionTopSourceLocation(TopSourceLocation), SM(SM) {} + + bool VisitExpr(clang::Expr *E); + std::set &getVarSet() { + return VarSet; + } +};