From a26c55e49e5b23da0dce2a856d861b711f471892 Mon Sep 17 00:00:00 2001 From: Manoel Roemmer Date: Wed, 25 Sep 2019 14:51:00 +0200 Subject: [PATCH 1/6] Add interface of new variable handling API --- clang/tools/sotoc/src/TargetCode.cpp | 162 ++++++------------- clang/tools/sotoc/src/TargetRegionVariable.h | 67 ++++++++ 2 files changed, 118 insertions(+), 111 deletions(-) create mode 100644 clang/tools/sotoc/src/TargetRegionVariable.h diff --git a/clang/tools/sotoc/src/TargetCode.cpp b/clang/tools/sotoc/src/TargetCode.cpp index 3e1aea0901959b..72addb792fb9e1 100644 --- a/clang/tools/sotoc/src/TargetCode.cpp +++ b/clang/tools/sotoc/src/TargetCode.cpp @@ -108,109 +108,71 @@ 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.variableSizedArrayDimensions()) { + Out << "unsinged long long __sotoc_vla_dim" << d << "_" << Var.name() << ", "; } - - // set type to void* to avoid warnings from the compiler - Out << "void *__sotoc_var_"; - nDim.push_back(dim); // push total number of dimensions - } 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_"; - } - } - } } - Out << VarName; + // 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. + Out << Var.typeName() << " "; + if (Var.passedByPointer()) { + Out << "*__sotoc_var_"; + } + Out << Var.name(); } + 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(); + if ((auto LowerBound = Var.arrayLowerBound()) != 0) { + Out << " - " << LowerBound; } + Out << ";"; } + + } 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(); @@ -235,31 +197,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() << ";"; } } diff --git a/clang/tools/sotoc/src/TargetRegionVariable.h b/clang/tools/sotoc/src/TargetRegionVariable.h new file mode 100644 index 00000000000000..28b582c5b0a701 --- /dev/null +++ b/clang/tools/sotoc/src/TargetRegionVariable.h @@ -0,0 +1,67 @@ +//===-- 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. +// +//===----------------------------------------------------------------------===// + +/// 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 { + clang::VarDecl *Decl; + std::string VarName; + std::string TypeName; + std::vector DimensionSizes; + std::vector VarSizedDimensions; + + void determineDimensionSizes(const clang::ArrayType *T); + +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>; + /// The name of the variable + llvm::StringRef name() { return llvm::StringRef(VarName); } + /// The name of the type variable + llvm::StringRef typeName() { return llvm::StringRef(TypeName); } + /// Wether this variable is an array or not + bool isArray(); + /// 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(); + /// 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() { + 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. + size_t arrayLowerBound(); + /// 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() { + return const_array_dimension_sizes(DimensionSizes.cbegin(), + DimensionSizes.cend()); + } + + TargetRegionVariable(clang::VarDecl *Decl); +} From 7a988f633634e3e743b4106c54b425892000f54d Mon Sep 17 00:00:00 2001 From: Manoel Roemmer Date: Tue, 1 Oct 2019 14:30:03 +0200 Subject: [PATCH 2/6] Add new Variable handling API still needs Visitors. --- clang/tools/sotoc/src/TargetCode.cpp | 45 ----------- clang/tools/sotoc/src/TargetCode.h | 13 --- .../tools/sotoc/src/TargetRegionVariable.cpp | 80 +++++++++++++++++++ clang/tools/sotoc/src/TargetRegionVariable.h | 23 +++++- 4 files changed, 99 insertions(+), 62 deletions(-) create mode 100644 clang/tools/sotoc/src/TargetRegionVariable.cpp diff --git a/clang/tools/sotoc/src/TargetCode.cpp b/clang/tools/sotoc/src/TargetCode.cpp index 72addb792fb9e1..2bfe3fa73ce384 100644 --- a/clang/tools/sotoc/src/TargetCode.cpp +++ b/clang/tools/sotoc/src/TargetCode.cpp @@ -223,48 +223,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 369cefa804f39a..02bd263044d21b 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/TargetRegionVariable.cpp b/clang/tools/sotoc/src/TargetRegionVariable.cpp new file mode 100644 index 00000000000000..68f5dc6cedfab9 --- /dev/null +++ b/clang/tools/sotoc/src/TargetRegionVariable.cpp @@ -0,0 +1,80 @@ +//===-- 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 +/// +//===----------------------------------------------------------------------===// + +TargetRegionVariable::TargetRegionVariable( + clang::VarDecl *Decl, const_clause_kind_multimap &OmpClauses, + const std::map MappingLowerBounds) + : Decl(Decl), OmpClauseMap(OmpClauses), + OmpMappingLowerBound(MappingLowerBounds) { + VarName = Decl->getDeclName().getAsString(); + TypeName = Decl->getType().getAsString(); + if (auto ArrayDecl = llvm : dyn_cast(Decl)) { + determineDimensionSizes(ArrayDecl, 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() { + return llvm::isa(Decl); +} + +bool TargetRegionVariable::passedByPointer() { + if (isArray()) { + // Arrays are always passed by pointer + return true; + } + + if (Decl->getType().getTypePtr()->isPointerType()) { + // Pointers are already pointers and thus do not need to be converted to + // pointers + // TODO: Check if this is true. We hadn't had a use case for passing plain + // pointers (i.e. not arrays), yet. + return false; + } + + // We have a scalar. Check if it is mapped as private or firstprivate. + // TODO: Is this the correct handling. This is the way it was handled prior + // to refactoring. But what about private/lastprivate? + auto ClauseFindIter = OmpClausesMap.find(Decl); + for (auto I = ClauseFindIter; I != OmpClauseMap.cend(); ++I) { + if ((*I) == clang::OpenMPClauseKind::OMPC_private || + (*I) == clang::OpenMPClauseKind::OMPC_fristprivate) { + return false; + } + } + // TODO: the default should be false and we catch lastprivate + shared + return true; +} diff --git a/clang/tools/sotoc/src/TargetRegionVariable.h b/clang/tools/sotoc/src/TargetRegionVariable.h index 28b582c5b0a701..81875257018601 100644 --- a/clang/tools/sotoc/src/TargetRegionVariable.h +++ b/clang/tools/sotoc/src/TargetRegionVariable.h @@ -12,15 +12,18 @@ /// is passed to the target region, whether it is a slice or array and how it's /// dimensionality is declared class TargetRegionVariable { + clang::VarDecl *Decl; std::string VarName; std::string TypeName; std::vector DimensionSizes; std::vector VarSizedDimensions; - - void determineDimensionSizes(const clang::ArrayType *T); + void determineDimensionSizes(const clang::ArrayType *T, + unsigned int CurrentDimension); public: + using const_clause_kind_multimap = + std::multimap; /// Const range over strings that specify the size of each dimension of an /// array. using const_dimension_sizes_range = @@ -28,6 +31,12 @@ class TargetRegionVariable { /// Const size over indices of variable sized dimensions. using variable_sized_dimensions_range = llvm::iterator_range::const_iterator>; + +private: + const_clause_kind_multimap &OmpClauseMap; + const std::map &OmpMappingLowerBound; + +public: /// The name of the variable llvm::StringRef name() { return llvm::StringRef(VarName); } /// The name of the type variable @@ -63,5 +72,11 @@ class TargetRegionVariable { DimensionSizes.cend()); } - TargetRegionVariable(clang::VarDecl *Decl); -} + bool operator==(const TargetRegionVariable &Other) { + return Decl == Other.Decl; + } + + TargetRegionVariable( + clang::VarDecl *Decl, const_clause_kind_multimap &OmpClauses, + const std::map MappingLowerBounds); +}; From d521046309dc8c519a5c1a2790652d2c01cc4324 Mon Sep 17 00:00:00 2001 From: Manoel Roemmer Date: Thu, 17 Oct 2019 18:33:15 +0200 Subject: [PATCH 3/6] Implement new variable handling --- clang/tools/sotoc/CMakeLists.txt | 1 + clang/tools/sotoc/src/OmpPragma.h | 2 +- clang/tools/sotoc/src/TargetCode.cpp | 39 +++++--- clang/tools/sotoc/src/TargetCodeFragment.cpp | 91 +------------------ clang/tools/sotoc/src/TargetCodeFragment.h | 56 +++++++----- .../tools/sotoc/src/TargetRegionVariable.cpp | 64 +++++++------ clang/tools/sotoc/src/TargetRegionVariable.h | 51 +++++++---- clang/tools/sotoc/src/Visitors.cpp | 55 ++++++++--- clang/tools/sotoc/src/Visitors.h | 17 ++++ 9 files changed, 191 insertions(+), 185 deletions(-) diff --git a/clang/tools/sotoc/CMakeLists.txt b/clang/tools/sotoc/CMakeLists.txt index abed06d81526e9..6eb1382e75a96d 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 a5bdf20baaa70c..5c006007629777 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 2bfe3fa73ce384..5dd0db128a50b0 100644 --- a/clang/tools/sotoc/src/TargetCode.cpp +++ b/clang/tools/sotoc/src/TargetCode.cpp @@ -116,14 +116,19 @@ void TargetCode::generateFunctionPrologue(TargetCodeRegion *TCR, first = false; if (Var.isArray()) { - for (const unsigned int &d : Var.variableSizedArrayDimensions()) { - Out << "unsinged long long __sotoc_vla_dim" << d << "_" << Var.name() + 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. - Out << Var.typeName() << " "; + if (Var.isArray()) { + Out << "void "; + } else { + Out << Var.typeName() << " "; + } + if (Var.passedByPointer()) { Out << "*__sotoc_var_"; } @@ -135,7 +140,7 @@ void TargetCode::generateFunctionPrologue(TargetCodeRegion *TCR, // bring captured scalars into scope for (auto &Var : TCR->capturedVars()) { // Ignore everything not passed by reference here - if (Var->passedByPointer()) { + if (Var.passedByPointer()) { // Handle multi-dimensional arrays if (Var.isArray()) { // Declare the arrays as a pointer. This way we can assign it a pointer @@ -154,17 +159,18 @@ void TargetCode::generateFunctionPrologue(TargetCodeRegion *TCR, 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(); - if ((auto LowerBound = Var.arrayLowerBound()) != 0) { - Out << " - " << LowerBound; - } - Out << ";"; } + // 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(); + auto LowerBound = Var.arrayLowerBound(); + if (LowerBound.hasValue()) { + Out << " - "; + LowerBound.getValue()->printPretty(Out, NULL, TCR->getPP()); + } + Out << ";\n"; } else { // Handle all other types passed by reference @@ -175,7 +181,10 @@ void TargetCode::generateFunctionPrologue(TargetCodeRegion *TCR, } // Generate local declarations. - Out << TCR->PrintLocalVarsFromClauses(); + for (auto privateVar: TCR->privateVars()) { + privateVar->print(Out); + Out << "\n"; + } // The runtime can decide to only create one team. // Therfore, replace target teams constructs. diff --git a/clang/tools/sotoc/src/TargetCodeFragment.cpp b/clang/tools/sotoc/src/TargetCodeFragment.cpp index 5478ef403039fe..0fa6181cef30a4 100644 --- a/clang/tools/sotoc/src/TargetCodeFragment.cpp +++ b/clang/tools/sotoc/src/TargetCodeFragment.cpp @@ -28,54 +28,12 @@ #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); - +void TargetCodeRegion::addOMPClause(clang::OMPClause *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::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); - } - } - } - } - - for (auto v : CapturedVars) { - if (tmpSet.find(v) != tmpSet.end()) - tmpSet.erase(tmpSet.find(v)); - } - - for (auto v: tmpSet) { - addCapturedVar(v); - } - } static bool hasRegionCompoundStmt(const clang::Stmt *S) { @@ -214,49 +172,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; diff --git a/clang/tools/sotoc/src/TargetCodeFragment.h b/clang/tools/sotoc/src/TargetCodeFragment.h index 0dd781b8080c7f..12c2442f68e773 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,16 @@ 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; + /// 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 +131,28 @@ 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; + + 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()); + }; + void addOMPClause(clang::OMPClause *Clause); + const std::vector &getOMPClauses() const { + return OMPClauses; + }; 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; @@ -167,6 +173,14 @@ class TargetCodeRegion : public TargetCodeFragment { /// shifted to the right if the lower bound of that slice is not 0. /// If this is the case, the lower bound is saved into this map. std::map CapturedLowerBounds; + /// Adds a declaration as private variable + void setPrivateVars(const std::set &VarSet) { + PrivateVars = VarSet; + }; + /// Retruns a range over the private variables of this region. + private_vars_const_range privateVars() { + return private_vars_const_range(PrivateVars.cbegin(), PrivateVars.cend()); + }; }; /// This class represents a declaration, i.e. a function, global varialbe, or diff --git a/clang/tools/sotoc/src/TargetRegionVariable.cpp b/clang/tools/sotoc/src/TargetRegionVariable.cpp index 68f5dc6cedfab9..cfed696e16ed99 100644 --- a/clang/tools/sotoc/src/TargetRegionVariable.cpp +++ b/clang/tools/sotoc/src/TargetRegionVariable.cpp @@ -12,15 +12,31 @@ /// //===----------------------------------------------------------------------===// -TargetRegionVariable::TargetRegionVariable( - clang::VarDecl *Decl, const_clause_kind_multimap &OmpClauses, - const std::map MappingLowerBounds) - : Decl(Decl), OmpClauseMap(OmpClauses), + +#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(); - TypeName = Decl->getType().getAsString(); - if (auto ArrayDecl = llvm : dyn_cast(Decl)) { - determineDimensionSizes(ArrayDecl, 0); + + 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); } } @@ -40,41 +56,29 @@ void TargetRegionVariable::determineDimensionSizes( } CurrentDimension++; - auto *NextDimensionArray = clang::dyn_cast_or_null( + auto *NextDimensionArray = clang::dyn_cast_or_null( T->getElementType().getTypePtr()); if (NextDimensionArray) { determineDimensionSizes(NextDimensionArray, CurrentDimension); } } -bool TargetRegionVariable::isArray() { - return llvm::isa(Decl); +bool TargetRegionVariable::isArray() const { + return llvm::isa(Decl->getType().getTypePtr()); } -bool TargetRegionVariable::passedByPointer() { +bool TargetRegionVariable::passedByPointer() const { if (isArray()) { // Arrays are always passed by pointer return true; } + return Capture->capturesVariable(); +} - if (Decl->getType().getTypePtr()->isPointerType()) { - // Pointers are already pointers and thus do not need to be converted to - // pointers - // TODO: Check if this is true. We hadn't had a use case for passing plain - // pointers (i.e. not arrays), yet. - return false; - } - - // We have a scalar. Check if it is mapped as private or firstprivate. - // TODO: Is this the correct handling. This is the way it was handled prior - // to refactoring. But what about private/lastprivate? - auto ClauseFindIter = OmpClausesMap.find(Decl); - for (auto I = ClauseFindIter; I != OmpClauseMap.cend(); ++I) { - if ((*I) == clang::OpenMPClauseKind::OMPC_private || - (*I) == clang::OpenMPClauseKind::OMPC_fristprivate) { - return false; - } +llvm::Optional TargetRegionVariable::arrayLowerBound() const { + auto FindBound = OmpMappingLowerBound.find(Decl); + if (FindBound != OmpMappingLowerBound.cend()) { + return llvm::Optional(FindBound->second); } - // TODO: the default should be false and we catch lastprivate + shared - return true; + return llvm::Optional(); } diff --git a/clang/tools/sotoc/src/TargetRegionVariable.h b/clang/tools/sotoc/src/TargetRegionVariable.h index 81875257018601..38700a5c8e1d63 100644 --- a/clang/tools/sotoc/src/TargetRegionVariable.h +++ b/clang/tools/sotoc/src/TargetRegionVariable.h @@ -7,12 +7,24 @@ // //===----------------------------------------------------------------------===// +#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; @@ -22,8 +34,6 @@ class TargetRegionVariable { unsigned int CurrentDimension); public: - using const_clause_kind_multimap = - std::multimap; /// Const range over strings that specify the size of each dimension of an /// array. using const_dimension_sizes_range = @@ -33,24 +43,31 @@ class TargetRegionVariable { llvm::iterator_range::const_iterator>; private: - const_clause_kind_multimap &OmpClauseMap; - const std::map &OmpMappingLowerBound; + const std::map &OmpMappingLowerBound; public: - /// The name of the variable - llvm::StringRef name() { return llvm::StringRef(VarName); } - /// The name of the type variable - llvm::StringRef typeName() { return llvm::StringRef(TypeName); } + /// 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(); + 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(); + 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() { + variable_sized_dimensions_range variabledSizedArrayDimensions() const { return variable_sized_dimensions_range(VarSizedDimensions.cbegin(), VarSizedDimensions.cend()); } @@ -59,7 +76,7 @@ class TargetRegionVariable { /// continuous data. /// In case of a scalar (or an array which is mapped completly in the first /// dimension) this returns 0. - size_t arrayLowerBound(); + 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 @@ -67,16 +84,14 @@ class TargetRegionVariable { /// 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() { - return const_array_dimension_sizes(DimensionSizes.cbegin(), + const_dimension_sizes_range arrayDimensionSizes() const { + return const_dimension_sizes_range(DimensionSizes.cbegin(), DimensionSizes.cend()); } - bool operator==(const TargetRegionVariable &Other) { + bool operator==(const TargetRegionVariable &Other) const { return Decl == Other.Decl; } - TargetRegionVariable( - clang::VarDecl *Decl, const_clause_kind_multimap &OmpClauses, - const std::map MappingLowerBounds); + 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 71024dc696bfe7..597364046f8dcc 100644 --- a/clang/tools/sotoc/src/Visitors.cpp +++ b/clang/tools/sotoc/src/Visitors.cpp @@ -140,7 +140,7 @@ class CollectOMPClausesVisitor bool VisitStmt(clang::Stmt *S) { if (auto *OED = llvm::dyn_cast(S)) { for (auto *Clause : OED->clauses()) { - TCR->addOpenMPClause(Clause); + TCR->addOMPClause(Clause); } } return true; @@ -166,13 +166,10 @@ 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 @@ -194,9 +191,8 @@ void FindTargetCodeVisitor::addTargetRegionArgs( 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,7 +200,21 @@ void FindTargetCodeVisitor::addTargetRegionArgs( } } - FindLoopStmtVisitor FindLoopVisitor; + // Find all not locally declared variables in the region + FindPrivateVariablesVisitor PrivateVarsVisitor(S->getBeginLoc(), + Context.getSourceManager()); + PrivateVarsVisitor.TraverseStmt(S); + + // Remove any not locally declared variables which are already captured + auto VarSet = PrivateVarsVisitor.getVarSet(); + for (auto &CapturedVar : TCR->capturedVars()) { + VarSet.erase(CapturedVar.getDecl()); + } + + // Add non-local, non-capured variable as private variables + TCR->setPrivateVars(VarSet); + + /*FindLoopStmtVisitor FindLoopVisitor; FindLoopVisitor.TraverseStmt(S); std::unordered_set tmpSet; @@ -218,7 +228,7 @@ void FindTargetCodeVisitor::addTargetRegionArgs( tmpSet.insert(i); continue; } - for (auto j : *TCR->getOMPClauses()) { + for (auto j : TCR->getOMPClauses()) { for (auto CC : j->children()) { if (auto CC_DeclRefExpr = llvm::dyn_cast_or_null(CC)) { @@ -250,7 +260,7 @@ void FindTargetCodeVisitor::addTargetRegionArgs( for (const auto i : *FindLoopVisitor.getVarSet()) { // i->print(llvm::outs()); TCR->addCapturedVar(i); - } + }*/ } bool FindTargetCodeVisitor::VisitDecl(clang::Decl *D) { @@ -411,3 +421,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 ba3ef6110780ea..812f8b1cc00b2b 100644 --- a/clang/tools/sotoc/src/Visitors.h +++ b/clang/tools/sotoc/src/Visitors.h @@ -162,3 +162,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; + } +}; From 71759581235a3af5348de6108867a1587bd5f5e6 Mon Sep 17 00:00:00 2001 From: Manoel Roemmer Date: Sat, 26 Oct 2019 20:48:46 +0200 Subject: [PATCH 4/6] Handle parameters of OMP clauses correctly --- clang/tools/sotoc/src/TargetCode.cpp | 39 +++++++++--- clang/tools/sotoc/src/TargetCodeFragment.cpp | 16 +++++ clang/tools/sotoc/src/TargetCodeFragment.h | 36 ++++++++--- clang/tools/sotoc/src/Visitors.cpp | 65 +++++++++++++++++--- clang/tools/sotoc/src/Visitors.h | 1 + 5 files changed, 131 insertions(+), 26 deletions(-) diff --git a/clang/tools/sotoc/src/TargetCode.cpp b/clang/tools/sotoc/src/TargetCode.cpp index 5dd0db128a50b0..9233d21f6a5d8c 100644 --- a/clang/tools/sotoc/src/TargetCode.cpp +++ b/clang/tools/sotoc/src/TargetCode.cpp @@ -135,6 +135,27 @@ void TargetCode::generateFunctionPrologue(TargetCodeRegion *TCR, Out << Var.name(); } + for (auto *ClauseVar : TCR->ompClausesParams()) { + if (!first) { + Out << ", "; + } else { + 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 << ClauseVar->getName(); + } + Out << ")\n{\n"; // bring captured scalars into scope @@ -146,7 +167,7 @@ void TargetCode::generateFunctionPrologue(TargetCodeRegion *TCR, // 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() << ")"; + 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 @@ -164,14 +185,14 @@ void TargetCode::generateFunctionPrologue(TargetCodeRegion *TCR, // 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(); + Out << " = __sotoc_var_" << Var.name() << ";\n"; + // Move the bounds if we have a slice auto LowerBound = Var.arrayLowerBound(); if (LowerBound.hasValue()) { - Out << " - "; + Out << " " << Var.name() << " = " << Var.name() << " - "; LowerBound.getValue()->printPretty(Out, NULL, TCR->getPP()); + Out << ";\n"; } - Out << ";\n"; - } else { // Handle all other types passed by reference Out << Var.typeName() << " " << Var.name() << " = " @@ -181,9 +202,9 @@ void TargetCode::generateFunctionPrologue(TargetCodeRegion *TCR, } // Generate local declarations. - for (auto privateVar: TCR->privateVars()) { - privateVar->print(Out); - Out << "\n"; + for (auto *privateVar: TCR->privateVars()) { + Out << " " << privateVar->getType().getAsString() << " " + << privateVar->getName() << ";\n"; } // The runtime can decide to only create one team. @@ -208,7 +229,7 @@ void TargetCode::generateFunctionEpilogue(TargetCodeRegion *TCR, // copy values from scalars from scoped vars back into pointers for (auto &Var : TCR->capturedVars()) { if (Var.passedByPointer() && !Var.isArray()) { - Out << "\n __sotoc_var_" << Var.name() << " = " << Var.name() << ";"; + Out << "\n *__sotoc_var_" << Var.name() << " = " << Var.name() << ";"; } } diff --git a/clang/tools/sotoc/src/TargetCodeFragment.cpp b/clang/tools/sotoc/src/TargetCodeFragment.cpp index 0fa6181cef30a4..4c8b1e3e528ffd 100644 --- a/clang/tools/sotoc/src/TargetCodeFragment.cpp +++ b/clang/tools/sotoc/src/TargetCodeFragment.cpp @@ -25,6 +25,7 @@ #include "clang/Lex/Lexer.h" #include "clang/Lex/Token.h" +#include "Debug.h" #include "OmpPragma.h" #include "TargetCodeFragment.h" @@ -32,6 +33,21 @@ void TargetCodeRegion::addCapture(const clang::CapturedStmt::Capture *Capture) { CapturedVars.push_back(TargetRegionVariable(Capture, CapturedLowerBounds)); } +void TargetCodeRegion::addOMPClauseParam(clang::VarDecl *Param) { + for (auto &CV : capturedVars()) { + if (CV.getDecl() == Param) { + return; + } + } + + if (std::find(OMPClausesParams.begin(), OMPClausesParams.end(), Param) != OMPClausesParams.end()) { + return; + } + + DEBUGP("Adding variable " << Param->getName() << "as OpenMP clause parameter"); + OMPClausesParams.push_back(Param); +} + void TargetCodeRegion::addOMPClause(clang::OMPClause *Clause) { OMPClauses.push_back(Clause); } diff --git a/clang/tools/sotoc/src/TargetCodeFragment.h b/clang/tools/sotoc/src/TargetCodeFragment.h index 12c2442f68e773..6d83f784874797 100644 --- a/clang/tools/sotoc/src/TargetCodeFragment.h +++ b/clang/tools/sotoc/src/TargetCodeFragment.h @@ -117,6 +117,10 @@ class TargetCodeRegion : public TargetCodeFragment { 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. @@ -135,7 +139,13 @@ class TargetCodeRegion : public TargetCodeFragment { 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(); @@ -146,10 +156,28 @@ class TargetCodeRegion : public TargetCodeFragment { 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; } @@ -173,14 +201,6 @@ class TargetCodeRegion : public TargetCodeFragment { /// shifted to the right if the lower bound of that slice is not 0. /// If this is the case, the lower bound is saved into this map. std::map CapturedLowerBounds; - /// Adds a declaration as private variable - void setPrivateVars(const std::set &VarSet) { - PrivateVars = VarSet; - }; - /// Retruns a range over the private variables of this region. - private_vars_const_range privateVars() { - return private_vars_const_range(PrivateVars.cbegin(), PrivateVars.cend()); - }; }; /// This class represents a declaration, i.e. a function, global varialbe, or diff --git a/clang/tools/sotoc/src/Visitors.cpp b/clang/tools/sotoc/src/Visitors.cpp index 597364046f8dcc..1e9f0eaa6559ee 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(); @@ -147,6 +147,53 @@ class CollectOMPClausesVisitor }; }; +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 { + //std::shared_ptr TCR; + CollectOMPClauseParamsVarsVisitor VarsVisitor; + bool InExplicitCast; +public: + CollectOMPClauseParamsVisitor(std::shared_ptr &TCR) + : VarsVisitor(TCR), InExplicitCast(false) {}; + bool VisitStmt(clang::Stmt *S) { + // 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; + }; +}; + bool FindTargetCodeVisitor::processTargetRegion( clang::OMPExecutableDirective *TargetDirective) { // TODO: Not sure why to iterate the children, because I think there @@ -176,7 +223,7 @@ bool FindTargetCodeVisitor::processTargetRegion( // tree DiscoverTypeVisitor.TraverseStmt(CS); DiscoverFunctionVisitor.TraverseStmt(CS); - addTargetRegionArgs(CS, TCR); + addTargetRegionArgs(CS, TargetDirective, TCR); TCR->NeedsSemicolon = stmtNeedsSemicolon(CS); TCR->TargetCodeKind = TargetDirective->getDirectiveKind(); } @@ -186,7 +233,8 @@ 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()) { @@ -211,6 +259,10 @@ void FindTargetCodeVisitor::addTargetRegionArgs( VarSet.erase(CapturedVar.getDecl()); } + // Add variables used in OMP clauses which are not captured as first-private + // variables + CollectOMPClauseParamsVisitor(TCR).TraverseStmt(TargetDirective); + // Add non-local, non-capured variable as private variables TCR->setPrivateVars(VarSet); @@ -301,11 +353,6 @@ bool FindLoopStmtVisitor::VisitStmt(clang::Stmt *S) { return true; } -// bool FindDeclRefExprVisitor::VisitDecl(clang::Decl *D) { -// printf("VisitDecl\n"); -// D->dumpColor(); -// return true; -// } bool FindDeclRefExprVisitor::VisitStmt(clang::Stmt *S) { // printf("VisitStmt\n"); @@ -430,7 +477,7 @@ bool FindPrivateVariablesVisitor::VisitExpr(clang::Expr *E) { if (attr->getKind() == clang::attr::OMPDeclareTargetDecl) { return true; } - } + } // If the variable is declared outside of the target region it may be a // private variable diff --git a/clang/tools/sotoc/src/Visitors.h b/clang/tools/sotoc/src/Visitors.h index 812f8b1cc00b2b..c9bb512dad90e1 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); }; From c4cc30a008902c6295f0737a731bc3d55ad305d2 Mon Sep 17 00:00:00 2001 From: Manoel Roemmer Date: Sat, 26 Oct 2019 20:56:25 +0200 Subject: [PATCH 5/6] Remove obsolete code --- clang/tools/sotoc/src/TargetCodeFragment.cpp | 5 -- clang/tools/sotoc/src/Visitors.cpp | 78 +------------------- 2 files changed, 2 insertions(+), 81 deletions(-) diff --git a/clang/tools/sotoc/src/TargetCodeFragment.cpp b/clang/tools/sotoc/src/TargetCodeFragment.cpp index 4c8b1e3e528ffd..e3ed02e003dda5 100644 --- a/clang/tools/sotoc/src/TargetCodeFragment.cpp +++ b/clang/tools/sotoc/src/TargetCodeFragment.cpp @@ -225,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/Visitors.cpp b/clang/tools/sotoc/src/Visitors.cpp index 1e9f0eaa6559ee..f54bf066e7e334 100644 --- a/clang/tools/sotoc/src/Visitors.cpp +++ b/clang/tools/sotoc/src/Visitors.cpp @@ -131,22 +131,6 @@ bool FindTargetCodeVisitor::VisitStmt(clang::Stmt *S) { return true; } -class CollectOMPClausesVisitor - : public clang::RecursiveASTVisitor { - std::shared_ptr TCR; - -public: - CollectOMPClausesVisitor(std::shared_ptr &TCR) : TCR(TCR){}; - bool VisitStmt(clang::Stmt *S) { - if (auto *OED = llvm::dyn_cast(S)) { - for (auto *Clause : OED->clauses()) { - TCR->addOMPClause(Clause); - } - } - return true; - }; -}; - class CollectOMPClauseParamsVarsVisitor : public clang::RecursiveASTVisitor { std::shared_ptr TCR; @@ -166,8 +150,8 @@ class CollectOMPClauseParamsVarsVisitor class CollectOMPClauseParamsVisitor : public clang::RecursiveASTVisitor { - //std::shared_ptr TCR; - CollectOMPClauseParamsVarsVisitor VarsVisitor; + + CollectOMPClauseParamsVarsVisitor VarsVisitor; bool InExplicitCast; public: CollectOMPClauseParamsVisitor(std::shared_ptr &TCR) @@ -265,54 +249,6 @@ void FindTargetCodeVisitor::addTargetRegionArgs( // Add non-local, non-capured variable as private variables TCR->setPrivateVars(VarSet); - - /*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); - } - } - } - - for (const auto i : tmpSet) { - FindLoopVisitor.getVarSet()->erase(FindLoopVisitor.getVarSet()->find(i)); - } - - tmpSet.clear(); - - // printf("%lu \n", FindLoopVisitor.getVarSet()->size()); - for (const auto i : *FindLoopVisitor.getVarSet()) { - // i->print(llvm::outs()); - TCR->addCapturedVar(i); - }*/ } bool FindTargetCodeVisitor::VisitDecl(clang::Decl *D) { @@ -342,27 +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::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); } } From e9aba95125a82f2cbf4693b03e06415264ec2db7 Mon Sep 17 00:00:00 2001 From: Manoel Roemmer Date: Mon, 28 Oct 2019 13:24:28 +0100 Subject: [PATCH 6/6] Silence init reorder warnings --- clang/tools/sotoc/src/TargetRegionVariable.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/clang/tools/sotoc/src/TargetRegionVariable.cpp b/clang/tools/sotoc/src/TargetRegionVariable.cpp index cfed696e16ed99..b99b261a6b4f3e 100644 --- a/clang/tools/sotoc/src/TargetRegionVariable.cpp +++ b/clang/tools/sotoc/src/TargetRegionVariable.cpp @@ -22,8 +22,9 @@ 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())) {