Skip to content
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
95 changes: 95 additions & 0 deletions clang/include/clang/AST/OpenMPClause.h
Original file line number Diff line number Diff line change
Expand Up @@ -5815,6 +5815,12 @@ class OMPClauseMappableExprCommon {
ValueDecl *getAssociatedDeclaration() const {
return AssociatedDeclaration;
}

bool operator==(const MappableComponent &Other) const {
return AssociatedExpressionNonContiguousPr ==
Other.AssociatedExpressionNonContiguousPr &&
AssociatedDeclaration == Other.AssociatedDeclaration;
}
};

// List of components of an expression. This first one is the whole
Expand All @@ -5828,6 +5834,95 @@ class OMPClauseMappableExprCommon {
using MappableExprComponentLists = SmallVector<MappableExprComponentList, 8>;
using MappableExprComponentListsRef = ArrayRef<MappableExprComponentList>;

// Hash function to allow usage as DenseMap keys.
friend llvm::hash_code hash_value(const MappableComponent &MC) {
return llvm::hash_combine(MC.getAssociatedExpression(),
MC.getAssociatedDeclaration(),
MC.isNonContiguous());
}

public:
/// Get the type of an element of a ComponentList Expr \p Exp.
///
/// For something like the following:
/// ```c
/// int *p, **p;
/// ```
/// The types for the following Exprs would be:
/// Expr | Type
/// ---------|-----------
/// p | int *
/// *p | int
/// p[0] | int
/// p[0:1] | int
/// pp | int **
/// pp[0] | int *
/// pp[0:1] | int *
/// Note: this assumes that if \p Exp is an array-section, it is contiguous.
static QualType getComponentExprElementType(const Expr *Exp);

/// Find the attach pointer expression from a list of mappable expression
/// components.
///
/// This function traverses the component list to find the first
/// expression that has a pointer type, which represents the attach
/// base pointer expr for the current component-list.
///
/// For example, given the following:
///
/// ```c
/// struct S {
/// int a;
/// int b[10];
/// int c[10][10];
/// int *p;
/// int **pp;
/// }
/// S s, *ps, **pps, *(pas[10]), ***ppps;
/// int i;
/// ```
///
/// The base-pointers for the following map operands would be:
/// map list-item | attach base-pointer | attach base-pointer
/// | for directives except | target_update (if
/// | target_update | different)
/// ----------------|-----------------------|---------------------
/// s | N/A |
/// s.a | N/A |
/// s.p | N/A |
/// ps | N/A |
/// ps->p | ps |
/// ps[1] | ps |
/// *(ps + 1) | ps |
/// (ps + 1)[1] | ps |
/// ps[1:10] | ps |
/// ps->b[10] | ps |
/// ps->p[10] | ps->p |
/// ps->c[1][2] | ps |
/// ps->c[1:2][2] | (error diagnostic) | N/A, TODO: ps
/// ps->c[1:1][2] | ps | N/A, TODO: ps
/// pps[1][2] | pps[1] |
/// pps[1:1][2] | pps[1:1] | N/A, TODO: pps[1:1]
/// pps[1:i][2] | pps[1:i] | N/A, TODO: pps[1:i]
/// pps[1:2][2] | (error diagnostic) | N/A
/// pps[1]->p | pps[1] |
/// pps[1]->p[10] | pps[1] |
/// pas[1] | N/A |
/// pas[1][2] | pas[1] |
/// ppps[1][2] | ppps[1] |
/// ppps[1][2][3] | ppps[1][2] |
/// ppps[1][2:1][3] | ppps[1][2:1] | N/A, TODO: ppps[1][2:1]
/// ppps[1][2:2][3] | (error diagnostic) | N/A
/// Returns a pair of the attach pointer expression and its depth in the
/// component list.
/// TODO: This may need to be updated to handle ref_ptr/ptee cases for byref
/// map operands.
/// TODO: Handle cases for target-update, where the list-item is a
/// non-contiguous array-section that still has a base-pointer.
static std::pair<const Expr *, std::optional<size_t>>
findAttachPtrExpr(MappableExprComponentListRef Components,
OpenMPDirectiveKind CurDirKind);

protected:
// Return the total number of elements in a list of component lists.
static unsigned
Expand Down
8 changes: 8 additions & 0 deletions clang/include/clang/Basic/OpenMPKinds.h
Original file line number Diff line number Diff line change
Expand Up @@ -301,6 +301,14 @@ bool isOpenMPTargetExecutionDirective(OpenMPDirectiveKind DKind);
/// otherwise - false.
bool isOpenMPTargetDataManagementDirective(OpenMPDirectiveKind DKind);

/// Checks if the specified directive is a map-entering target directive.
/// \param DKind Specified directive.
/// \return true - the directive is a map-entering target directive like
/// 'omp target', 'omp target data', 'omp target enter data',
/// 'omp target parallel', etc. (excludes 'omp target exit data', 'omp target
/// update') otherwise - false.
bool isOpenMPTargetMapEnteringDirective(OpenMPDirectiveKind DKind);

/// Checks if the specified composite/combined directive constitutes a teams
/// directive in the outermost nest. For example
/// 'omp teams distribute' or 'omp teams distribute parallel for'.
Expand Down
72 changes: 72 additions & 0 deletions clang/lib/AST/OpenMPClause.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
#include "clang/AST/Attr.h"
#include "clang/AST/Decl.h"
#include "clang/AST/DeclOpenMP.h"
#include "clang/AST/ExprOpenMP.h"
#include "clang/Basic/LLVM.h"
#include "clang/Basic/OpenMPKinds.h"
#include "clang/Basic/TargetInfo.h"
Expand Down Expand Up @@ -1156,6 +1157,77 @@ unsigned OMPClauseMappableExprCommon::getUniqueDeclarationsTotalNumber(
return UniqueDecls.size();
}

QualType
OMPClauseMappableExprCommon::getComponentExprElementType(const Expr *Exp) {
assert(!isa<OMPArrayShapingExpr>(Exp) &&
"Cannot get element-type from array-shaping expr.");

// Unless we are handling array-section expressions, including
// array-subscripts, derefs, we can rely on getType.
if (!isa<ArraySectionExpr>(Exp))
return Exp->getType().getNonReferenceType().getCanonicalType();

// For array-sections, we need to find the type of one element of
// the section.
const auto *OASE = cast<ArraySectionExpr>(Exp);

QualType BaseType = ArraySectionExpr::getBaseOriginalType(OASE->getBase());

QualType ElemTy;
if (const auto *ATy = BaseType->getAsArrayTypeUnsafe())
ElemTy = ATy->getElementType();
else
ElemTy = BaseType->getPointeeType();

ElemTy = ElemTy.getNonReferenceType().getCanonicalType();
return ElemTy;
}

std::pair<const Expr *, std::optional<size_t>>
OMPClauseMappableExprCommon::findAttachPtrExpr(
MappableExprComponentListRef Components, OpenMPDirectiveKind CurDirKind) {

// If we only have a single component, we have a map like "map(p)", which
// cannot have a base-pointer.
if (Components.size() < 2)
return {nullptr, std::nullopt};

// Only check for non-contiguous sections on target_update, since we can
// assume array-sections are contiguous on maps on other constructs, even if
// we are not sure of it at compile-time, like for a[1:x][2].
if (Components.back().isNonContiguous() && CurDirKind == OMPD_target_update)
return {nullptr, std::nullopt};

// To find the attach base-pointer, we start with the second component,
// stripping away one component at a time, until we reach a pointer Expr
// (that is not a binary operator). The first such pointer should be the
// attach base-pointer for the component list.
for (auto [I, Component] : llvm::enumerate(Components)) {
// Skip past the first component.
if (I == 0)
continue;

const Expr *CurExpr = Component.getAssociatedExpression();
if (!CurExpr)
break;

// If CurExpr is something like `p + 10`, we need to ignore it, since
// we are looking for `p`.
if (isa<BinaryOperator>(CurExpr))
continue;

// Keep going until we reach an Expr of pointer type.
QualType CurType = getComponentExprElementType(CurExpr);
if (!CurType->isPointerType())
continue;

// We have found a pointer Expr. This must be the attach pointer.
return {CurExpr, Components.size() - I};
}

return {nullptr, std::nullopt};
}

OMPMapClause *OMPMapClause::Create(
const ASTContext &C, const OMPVarListLocTy &Locs, ArrayRef<Expr *> Vars,
ArrayRef<ValueDecl *> Declarations,
Expand Down
5 changes: 5 additions & 0 deletions clang/lib/Basic/OpenMPKinds.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -650,6 +650,11 @@ bool clang::isOpenMPTargetDataManagementDirective(OpenMPDirectiveKind DKind) {
DKind == OMPD_target_exit_data || DKind == OMPD_target_update;
}

bool clang::isOpenMPTargetMapEnteringDirective(OpenMPDirectiveKind DKind) {
return DKind == OMPD_target_data || DKind == OMPD_target_enter_data ||
isOpenMPTargetExecutionDirective(DKind);
}

bool clang::isOpenMPNestingTeamsDirective(OpenMPDirectiveKind DKind) {
if (DKind == OMPD_teams)
return true;
Expand Down
Loading