[clang] [NFC][Clang][OpenMP] Add helper functions/utils for finding/comparing attach base-ptrs. (PR #155625)
Abhinav Gaba via cfe-commits
cfe-commits at lists.llvm.org
Thu Sep 11 16:53:22 PDT 2025
https://github.com/abhinavgaba updated https://github.com/llvm/llvm-project/pull/155625
>From 8256e93c46ddd4e0fdd4125b769f040741e56890 Mon Sep 17 00:00:00 2001
From: Abhinav Gaba <abhinav.gaba at intel.com>
Date: Wed, 27 Aug 2025 07:02:36 -0700
Subject: [PATCH 1/5] [NFC][Clang] Add helper functions/utils for
finding/comparing attach base-ptrs.
These have been pulled out of the codegen PR #153683, to reduce the size
of that PR.
---
clang/include/clang/AST/OpenMPClause.h | 95 +++++++
clang/include/clang/Basic/OpenMPKinds.h | 8 +
clang/lib/AST/OpenMPClause.cpp | 68 +++++
clang/lib/Basic/OpenMPKinds.cpp | 5 +
clang/lib/CodeGen/CGOpenMPRuntime.cpp | 358 ++++++++++++++++++++++++
5 files changed, 534 insertions(+)
diff --git a/clang/include/clang/AST/OpenMPClause.h b/clang/include/clang/AST/OpenMPClause.h
index 1118d3e062e68..9627e99a306b4 100644
--- a/clang/include/clang/AST/OpenMPClause.h
+++ b/clang/include/clang/AST/OpenMPClause.h
@@ -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
@@ -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
diff --git a/clang/include/clang/Basic/OpenMPKinds.h b/clang/include/clang/Basic/OpenMPKinds.h
index f40db4c13c55a..e37887e8b86ba 100644
--- a/clang/include/clang/Basic/OpenMPKinds.h
+++ b/clang/include/clang/Basic/OpenMPKinds.h
@@ -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'.
diff --git a/clang/lib/AST/OpenMPClause.cpp b/clang/lib/AST/OpenMPClause.cpp
index 588b0dcc6d7b8..eff897a1a33b2 100644
--- a/clang/lib/AST/OpenMPClause.cpp
+++ b/clang/lib/AST/OpenMPClause.cpp
@@ -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"
@@ -1156,6 +1157,73 @@ 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 (size_t I = 1; I < Components.size(); ++I) {
+ const Expr *CurExpr = Components[I].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,
diff --git a/clang/lib/Basic/OpenMPKinds.cpp b/clang/lib/Basic/OpenMPKinds.cpp
index 220b31b0f19bc..2f2a5b66e4ca5 100644
--- a/clang/lib/Basic/OpenMPKinds.cpp
+++ b/clang/lib/Basic/OpenMPKinds.cpp
@@ -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;
diff --git a/clang/lib/CodeGen/CGOpenMPRuntime.cpp b/clang/lib/CodeGen/CGOpenMPRuntime.cpp
index f98339d472fa9..d592c29a412a9 100644
--- a/clang/lib/CodeGen/CGOpenMPRuntime.cpp
+++ b/clang/lib/CodeGen/CGOpenMPRuntime.cpp
@@ -6765,12 +6765,256 @@ llvm::Value *CGOpenMPRuntime::emitNumThreadsForTargetDirective(
namespace {
LLVM_ENABLE_BITMASK_ENUMS_IN_NAMESPACE();
+/// Utility to compare expression locations.
+/// Returns true if expr-loc of LHS is less-than that of RHS.
+/// This function asserts that both expressions have valid expr-locations.
+static bool compareExprLocs(const Expr *LHS, const Expr *RHS) {
+ // Assert that neither LHS nor RHS can be null
+ assert(LHS && "LHS expression cannot be null");
+ assert(RHS && "RHS expression cannot be null");
+
+ // Get source locations
+ SourceLocation LocLHS = LHS->getExprLoc();
+ SourceLocation LocRHS = RHS->getExprLoc();
+
+ // Assert that we have valid source locations
+ assert(LocLHS.isValid() && "LHS expression must have valid source location");
+ assert(LocRHS.isValid() && "RHS expression must have valid source location");
+
+ // Compare source locations for deterministic ordering
+ bool result = LocLHS < LocRHS;
+ return result;
+}
+
// Utility to handle information from clauses associated with a given
// construct that use mappable expressions (e.g. 'map' clause, 'to' clause).
// It provides a convenient interface to obtain the information and generate
// code for that information.
class MappableExprsHandler {
public:
+ /// Custom comparator for attach-pointer expressions that compares them by
+ /// complexity (i.e. their component-depth) first, then by their expr-locs if
+ /// they are semantically different.
+ struct AttachPtrExprComparator {
+ const MappableExprsHandler *Handler;
+ // Cache of previous equality comparison results.
+ mutable llvm::DenseMap<std::pair<const Expr *, const Expr *>, bool>
+ CachedEqualityComparisons;
+
+ AttachPtrExprComparator(const MappableExprsHandler *H) : Handler(H) {}
+
+ // Return true iff LHS is "less than" RHS.
+ bool operator()(const Expr *LHS, const Expr *RHS) const {
+ if (LHS == RHS)
+ return false;
+
+ // First, compare by complexity (depth)
+ auto ItLHS = Handler->AttachPtrComponentDepthMap.find(LHS);
+ auto ItRHS = Handler->AttachPtrComponentDepthMap.find(RHS);
+
+ std::optional<size_t> DepthLHS =
+ (ItLHS != Handler->AttachPtrComponentDepthMap.end()) ? ItLHS->second
+ : std::nullopt;
+ std::optional<size_t> DepthRHS =
+ (ItRHS != Handler->AttachPtrComponentDepthMap.end()) ? ItRHS->second
+ : std::nullopt;
+
+ // std::nullopt (no attach pointer) has lowest complexity
+ if (!DepthLHS.has_value() && !DepthRHS.has_value()) {
+ // Both have same complexity, now check semantic equality
+ if (areEqual(LHS, RHS))
+ return false;
+ // Different semantically, compare by location
+ return compareExprLocs(LHS, RHS);
+ }
+ if (!DepthLHS.has_value())
+ return true; // LHS has lower complexity
+ if (!DepthRHS.has_value())
+ return false; // RHS has lower complexity
+
+ // Both have values, compare by depth (lower depth = lower complexity)
+ if (DepthLHS.value() != DepthRHS.value())
+ return DepthLHS.value() < DepthRHS.value();
+
+ // Same complexity, now check semantic equality
+ if (areEqual(LHS, RHS))
+ return false;
+ // Different semantically, compare by location
+ return compareExprLocs(LHS, RHS);
+ }
+
+ public:
+ /// Return true if \p LHS and \p RHS are semantically equal. Uses pre-cached
+ /// results, if available, otherwise does a recursive semantic comparison.
+ bool areEqual(const Expr *LHS, const Expr *RHS) const {
+ // Check cache first for faster lookup
+ auto CachedResultIt = CachedEqualityComparisons.find({LHS, RHS});
+ if (CachedResultIt != CachedEqualityComparisons.end())
+ return CachedResultIt->second;
+
+ bool ComparisonResult = areSemanticallyEqual(LHS, RHS);
+
+ // Cache the result for future lookups (both orders since semantic
+ // equality is commutative)
+ CachedEqualityComparisons[{LHS, RHS}] = ComparisonResult;
+ CachedEqualityComparisons[{RHS, LHS}] = ComparisonResult;
+ return ComparisonResult;
+ }
+
+ private:
+ /// Helper function to compare attach-pointer expressions semantically.
+ /// This function handles various expression types that can be part of an
+ /// attach-pointer.
+ /// TODO: Not urgent, but we should ideally return true when comparing
+ /// `p[10]`, `*(p + 10)`, `*(p + 5 + 5)`, `p[10:1]` etc.
+ bool areSemanticallyEqual(const Expr *LHS, const Expr *RHS) const {
+ if (LHS == RHS)
+ return true;
+
+ // If only one is null, they aren't equal
+ if (!LHS || !RHS)
+ return false;
+
+ ASTContext &Ctx = Handler->CGF.getContext();
+ // Strip away parentheses and no-op casts to get to the core expression
+ LHS = LHS->IgnoreParenNoopCasts(Ctx);
+ RHS = RHS->IgnoreParenNoopCasts(Ctx);
+
+ // Direct pointer comparison of the underlying expressions
+ if (LHS == RHS)
+ return true;
+
+ // Check if the expression classes match
+ if (LHS->getStmtClass() != RHS->getStmtClass())
+ return false;
+
+ // Handle DeclRefExpr (variable references)
+ if (const auto *LD = dyn_cast<DeclRefExpr>(LHS)) {
+ const auto *RD = dyn_cast<DeclRefExpr>(RHS);
+ if (!RD)
+ return false;
+ return LD->getDecl()->getCanonicalDecl() ==
+ RD->getDecl()->getCanonicalDecl();
+ }
+
+ // Handle ArraySubscriptExpr (array indexing like a[i])
+ if (const auto *LA = dyn_cast<ArraySubscriptExpr>(LHS)) {
+ const auto *RA = dyn_cast<ArraySubscriptExpr>(RHS);
+ if (!RA)
+ return false;
+ return areSemanticallyEqual(LA->getBase(), RA->getBase()) &&
+ areSemanticallyEqual(LA->getIdx(), RA->getIdx());
+ }
+
+ // Handle MemberExpr (member access like s.m or p->m)
+ if (const auto *LM = dyn_cast<MemberExpr>(LHS)) {
+ const auto *RM = dyn_cast<MemberExpr>(RHS);
+ if (!RM)
+ return false;
+ if (LM->getMemberDecl()->getCanonicalDecl() !=
+ RM->getMemberDecl()->getCanonicalDecl())
+ return false;
+ return areSemanticallyEqual(LM->getBase(), RM->getBase());
+ }
+
+ // Handle UnaryOperator (unary operations like *p, &x, etc.)
+ if (const auto *LU = dyn_cast<UnaryOperator>(LHS)) {
+ const auto *RU = dyn_cast<UnaryOperator>(RHS);
+ if (!RU)
+ return false;
+ if (LU->getOpcode() != RU->getOpcode())
+ return false;
+ return areSemanticallyEqual(LU->getSubExpr(), RU->getSubExpr());
+ }
+
+ // Handle BinaryOperator (binary operations like p + offset)
+ if (const auto *LB = dyn_cast<BinaryOperator>(LHS)) {
+ const auto *RB = dyn_cast<BinaryOperator>(RHS);
+ if (!RB)
+ return false;
+ if (LB->getOpcode() != RB->getOpcode())
+ return false;
+ return areSemanticallyEqual(LB->getLHS(), RB->getLHS()) &&
+ areSemanticallyEqual(LB->getRHS(), RB->getRHS());
+ }
+
+ // Handle ArraySectionExpr (array sections like a[0:1])
+ // Attach pointers should not contain array-sections, but currently we
+ // don't emit an error.
+ if (const auto *LAS = dyn_cast<ArraySectionExpr>(LHS)) {
+ const auto *RAS = dyn_cast<ArraySectionExpr>(RHS);
+ if (!RAS)
+ return false;
+ return areSemanticallyEqual(LAS->getBase(), RAS->getBase()) &&
+ areSemanticallyEqual(LAS->getLowerBound(),
+ RAS->getLowerBound()) &&
+ areSemanticallyEqual(LAS->getLength(), RAS->getLength());
+ }
+
+ // Handle CastExpr (explicit casts)
+ if (const auto *LC = dyn_cast<CastExpr>(LHS)) {
+ const auto *RC = dyn_cast<CastExpr>(RHS);
+ if (!RC)
+ return false;
+ if (LC->getCastKind() != RC->getCastKind())
+ return false;
+ return areSemanticallyEqual(LC->getSubExpr(), RC->getSubExpr());
+ }
+
+ // Handle CXXThisExpr (this pointer)
+ if (isa<CXXThisExpr>(LHS) && isa<CXXThisExpr>(RHS))
+ return true;
+
+ // Handle IntegerLiteral (integer constants)
+ if (const auto *LI = dyn_cast<IntegerLiteral>(LHS)) {
+ const auto *RI = dyn_cast<IntegerLiteral>(RHS);
+ if (!RI)
+ return false;
+ return LI->getValue() == RI->getValue();
+ }
+
+ // Handle CharacterLiteral (character constants)
+ if (const auto *LC = dyn_cast<CharacterLiteral>(LHS)) {
+ const auto *RC = dyn_cast<CharacterLiteral>(RHS);
+ if (!RC)
+ return false;
+ return LC->getValue() == RC->getValue();
+ }
+
+ // Handle FloatingLiteral (floating point constants)
+ if (const auto *LF = dyn_cast<FloatingLiteral>(LHS)) {
+ const auto *RF = dyn_cast<FloatingLiteral>(RHS);
+ if (!RF)
+ return false;
+ // Use bitwise comparison for floating point literals
+ return LF->getValue().bitwiseIsEqual(RF->getValue());
+ }
+
+ // Handle StringLiteral (string constants)
+ if (const auto *LS = dyn_cast<StringLiteral>(LHS)) {
+ const auto *RS = dyn_cast<StringLiteral>(RHS);
+ if (!RS)
+ return false;
+ return LS->getString() == RS->getString();
+ }
+
+ // Handle CXXNullPtrLiteralExpr (nullptr)
+ if (isa<CXXNullPtrLiteralExpr>(LHS) && isa<CXXNullPtrLiteralExpr>(RHS))
+ return true;
+
+ // Handle CXXBoolLiteralExpr (true/false)
+ if (const auto *LB = dyn_cast<CXXBoolLiteralExpr>(LHS)) {
+ const auto *RB = dyn_cast<CXXBoolLiteralExpr>(RHS);
+ if (!RB)
+ return false;
+ return LB->getValue() == RB->getValue();
+ }
+
+ // Fallback for other forms - use the existing comparison method
+ return Expr::isSameComparisonOperand(LHS, RHS);
+ }
+ };
+
/// Get the offset of the OMP_MAP_MEMBER_OF field.
static unsigned getFlagMemberOffset() {
unsigned Offset = 0;
@@ -6846,8 +7090,42 @@ class MappableExprsHandler {
Address LB = Address::invalid();
bool IsArraySection = false;
bool HasCompleteRecord = false;
+ // ATTACH information for delayed processing
+ Address AttachPtrAddr = Address::invalid();
+ Address AttachPteeAddr = Address::invalid();
+ const ValueDecl *AttachPtrDecl = nullptr;
+ const Expr *AttachMapExpr = nullptr;
};
+ /// Check if there's any component list where the attach pointer expression
+ /// matches the given captured variable.
+ bool hasAttachEntryForCapturedVar(const ValueDecl *VD) const {
+ for (const auto &AttachEntry : AttachPtrExprMap) {
+ if (AttachEntry.second) {
+ // Check if the attach pointer expression is a DeclRefExpr that
+ // references the captured variable
+ if (const auto *DRE = dyn_cast<DeclRefExpr>(AttachEntry.second)) {
+ if (DRE->getDecl() == VD) {
+ return true;
+ }
+ }
+ }
+ }
+ return false;
+ }
+
+ /// Get the previously-cached attach pointer for a component list, if-any.
+ const Expr *getAttachPtrExpr(
+ OMPClauseMappableExprCommon::MappableExprComponentListRef Components)
+ const {
+ auto It = AttachPtrExprMap.find(Components);
+ if (It != AttachPtrExprMap.end()) {
+ return It->second;
+ }
+
+ return nullptr;
+ }
+
private:
/// Kind that defines how a device pointer has to be returned.
struct MapInfo {
@@ -6920,6 +7198,22 @@ class MappableExprsHandler {
/// Map between lambda declarations and their map type.
llvm::DenseMap<const ValueDecl *, const OMPMapClause *> LambdasMap;
+ /// Map from component lists to their attach pointer expressions.
+ mutable llvm::DenseMap<
+ OMPClauseMappableExprCommon::MappableExprComponentListRef, const Expr *>
+ AttachPtrExprMap;
+
+ /// Map from attach pointer expressions to their component depth.
+ /// nullptr key has std::nullopt depth. This can be used to order attach-ptr
+ /// expressions with increasing/decreasing depth.
+ /// The component-depth of `nullptr` (i.e. no attach-ptr) is `std::nullopt`.
+ /// TODO: Not urgent, but we should ideally use the number of pointer
+ /// dereferences in an expr as an indicator of its complexity, instead of the
+ /// component-depth. That would be needed for us to treat `p[1]`, `*(p + 10)`,
+ /// `*(p + 5 + 5)` together.
+ mutable llvm::DenseMap<const Expr *, std::optional<size_t>>
+ AttachPtrComponentDepthMap = {{nullptr, std::nullopt}};
+
llvm::Value *getExprTypeSize(const Expr *E) const {
QualType ExprTy = E->getType().getCanonicalType();
@@ -8139,6 +8433,70 @@ class MappableExprsHandler {
}
}
+ /// Returns the address corresponding to \p PointerExpr.
+ static Address getAttachPtrAddr(const Expr *PointerExpr,
+ CodeGenFunction &CGF) {
+ Address AttachPtrAddr = Address::invalid();
+ if (!PointerExpr)
+ return AttachPtrAddr;
+
+ if (auto *DRE = dyn_cast<DeclRefExpr>(PointerExpr)) {
+ // If the pointer is a variable, we can use its address directly.
+ AttachPtrAddr = CGF.EmitLValue(DRE).getAddress();
+ } else if (auto *OASE = dyn_cast<ArraySectionExpr>(PointerExpr)) {
+ AttachPtrAddr =
+ CGF.EmitArraySectionExpr(OASE, /*IsLowerBound=*/true).getAddress();
+ } else if (auto *ASE = dyn_cast<ArraySubscriptExpr>(PointerExpr)) {
+ AttachPtrAddr = CGF.EmitLValue(ASE).getAddress();
+ } else if (auto *ME = dyn_cast<MemberExpr>(PointerExpr)) {
+ AttachPtrAddr = CGF.EmitMemberExpr(ME).getAddress();
+ } else if (auto *UO = dyn_cast<UnaryOperator>(PointerExpr)) {
+ if (UO->getOpcode() == UO_Deref)
+ AttachPtrAddr = CGF.EmitLValue(UO).getAddress();
+ }
+ assert(AttachPtrAddr.isValid() &&
+ "Failed to get address for attach pointer expression");
+ return AttachPtrAddr;
+ }
+
+ /// Returns whether an attach entry should be emitted for a map on
+ /// \p MapBaseDecl on the directive \p CurDir.
+ static bool
+ shouldEmitAttachEntry(const Expr *PointerExpr, const ValueDecl *MapBaseDecl,
+ CodeGenFunction &CGF,
+ llvm::PointerUnion<const OMPExecutableDirective *,
+ const OMPDeclareMapperDecl *>
+ CurDir) {
+ if (!PointerExpr)
+ return false;
+
+ // Pointer attachment is needed at map-entering time or for declare
+ // mappers.
+ if (!isa<const OMPDeclareMapperDecl *>(CurDir) &&
+ !isOpenMPTargetMapEnteringDirective(
+ cast<const OMPExecutableDirective *>(CurDir)->getDirectiveKind()))
+ return false;
+
+ return true;
+ }
+
+ // A wrapper around OMPClauseMappableExprCommon::findAttachPtrExpr. that
+ // accepts \p CurDir instead of an OpenMPDirectiveKind.
+ static std::pair<const Expr *, std::optional<size_t>> findAttachPtrExpr(
+ OMPClauseMappableExprCommon::MappableExprComponentListRef Components,
+ llvm::PointerUnion<const OMPExecutableDirective *,
+ const OMPDeclareMapperDecl *>
+ CurDir) {
+
+ OpenMPDirectiveKind CurDirectiveID =
+ isa<const OMPDeclareMapperDecl *>(CurDir)
+ ? OMPD_declare_mapper
+ : cast<const OMPExecutableDirective *>(CurDir)->getDirectiveKind();
+
+ return OMPClauseMappableExprCommon::findAttachPtrExpr(Components,
+ CurDirectiveID);
+ }
+
/// Generate all the base pointers, section pointers, sizes, map types, and
/// mappers for the extracted mappable expressions (all included in \a
/// CombinedInfo). Also, for each item that relates with a device pointer, a
>From 0b8bb14618b49ba871cdd17ec5db113f3ee4a48e Mon Sep 17 00:00:00 2001
From: Abhinav Gaba <abhinav.gaba at intel.com>
Date: Thu, 28 Aug 2025 10:59:38 -0700
Subject: [PATCH 2/5] Minor comment change, use llvm::enumerage
---
clang/lib/AST/OpenMPClause.cpp | 8 ++++++--
clang/lib/CodeGen/CGOpenMPRuntime.cpp | 4 ++--
2 files changed, 8 insertions(+), 4 deletions(-)
diff --git a/clang/lib/AST/OpenMPClause.cpp b/clang/lib/AST/OpenMPClause.cpp
index eff897a1a33b2..027641b704823 100644
--- a/clang/lib/AST/OpenMPClause.cpp
+++ b/clang/lib/AST/OpenMPClause.cpp
@@ -1202,8 +1202,12 @@ OMPClauseMappableExprCommon::findAttachPtrExpr(
// 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 (size_t I = 1; I < Components.size(); ++I) {
- const Expr *CurExpr = Components[I].getAssociatedExpression();
+ for (auto [I, Component] : llvm::enumerate(Components)) {
+ // Skip past the first component.
+ if (I == 0)
+ continue;
+
+ const Expr *CurExpr = Component.getAssociatedExpression();
if (!CurExpr)
break;
diff --git a/clang/lib/CodeGen/CGOpenMPRuntime.cpp b/clang/lib/CodeGen/CGOpenMPRuntime.cpp
index d592c29a412a9..cec7318a5806e 100644
--- a/clang/lib/CodeGen/CGOpenMPRuntime.cpp
+++ b/clang/lib/CodeGen/CGOpenMPRuntime.cpp
@@ -7209,8 +7209,8 @@ class MappableExprsHandler {
/// The component-depth of `nullptr` (i.e. no attach-ptr) is `std::nullopt`.
/// TODO: Not urgent, but we should ideally use the number of pointer
/// dereferences in an expr as an indicator of its complexity, instead of the
- /// component-depth. That would be needed for us to treat `p[1]`, `*(p + 10)`,
- /// `*(p + 5 + 5)` together.
+ /// component-depth. That would be needed for us to treat `p[10]`,
+ /// `*(p + 10)`, `*(p + 5 + 5)` together.
mutable llvm::DenseMap<const Expr *, std::optional<size_t>>
AttachPtrComponentDepthMap = {{nullptr, std::nullopt}};
>From feea6bf0a290eb393a9ba792a0bb4e9ed3249595 Mon Sep 17 00:00:00 2001
From: Abhinav Gaba <abhinav.gaba at intel.com>
Date: Fri, 29 Aug 2025 00:37:30 -0700
Subject: [PATCH 3/5] Add another util that returns the pointer/pointee addrs,
remove a redundant variable, add some asserts.
---
clang/lib/CodeGen/CGOpenMPRuntime.cpp | 41 +++++++++++++++++++++++----
1 file changed, 36 insertions(+), 5 deletions(-)
diff --git a/clang/lib/CodeGen/CGOpenMPRuntime.cpp b/clang/lib/CodeGen/CGOpenMPRuntime.cpp
index cec7318a5806e..59028f8d55665 100644
--- a/clang/lib/CodeGen/CGOpenMPRuntime.cpp
+++ b/clang/lib/CodeGen/CGOpenMPRuntime.cpp
@@ -6782,8 +6782,7 @@ static bool compareExprLocs(const Expr *LHS, const Expr *RHS) {
assert(LocRHS.isValid() && "RHS expression must have valid source location");
// Compare source locations for deterministic ordering
- bool result = LocLHS < LocRHS;
- return result;
+ return LocLHS < LocRHS;
}
// Utility to handle information from clauses associated with a given
@@ -7090,11 +7089,19 @@ class MappableExprsHandler {
Address LB = Address::invalid();
bool IsArraySection = false;
bool HasCompleteRecord = false;
- // ATTACH information for delayed processing
+ };
+
+ /// A struct to store the attach pointer and pointee information, to be used
+ /// when emitting an attach entry.
+ struct AttachInfoTy {
Address AttachPtrAddr = Address::invalid();
Address AttachPteeAddr = Address::invalid();
const ValueDecl *AttachPtrDecl = nullptr;
const Expr *AttachMapExpr = nullptr;
+
+ bool isValid() const {
+ return AttachPtrAddr.isValid() && AttachPteeAddr.isValid();
+ }
};
/// Check if there's any component list where the attach pointer expression
@@ -8436,9 +8443,8 @@ class MappableExprsHandler {
/// Returns the address corresponding to \p PointerExpr.
static Address getAttachPtrAddr(const Expr *PointerExpr,
CodeGenFunction &CGF) {
+ assert(PointerExpr && "Cannot get addr from null attach-ptr expr");
Address AttachPtrAddr = Address::invalid();
- if (!PointerExpr)
- return AttachPtrAddr;
if (auto *DRE = dyn_cast<DeclRefExpr>(PointerExpr)) {
// If the pointer is a variable, we can use its address directly.
@@ -8459,6 +8465,31 @@ class MappableExprsHandler {
return AttachPtrAddr;
}
+ /// Get the address of the attach pointer, and a load from it, to get the
+ /// pointee base address.
+ /// \return A pair containing AttachPtrAddr and AttachPteeBaseAddr. The pair
+ /// contains invalid addresses if \p AttachPtrExpr is null.
+ static std::pair<Address, Address>
+ getAttachPtrAddrAndPteeBaseAddr(const Expr *AttachPtrExpr,
+ CodeGenFunction &CGF) {
+
+ if (!AttachPtrExpr)
+ return {Address::invalid(), Address::invalid()};
+
+ Address AttachPtrAddr = getAttachPtrAddr(AttachPtrExpr, CGF);
+ assert(AttachPtrAddr.isValid() && "Invalid attach pointer addr");
+
+ QualType AttachPtrType =
+ OMPClauseMappableExprCommon::getComponentExprElementType(AttachPtrExpr)
+ .getCanonicalType();
+
+ Address AttachPteeBaseAddr = CGF.EmitLoadOfPointer(
+ AttachPtrAddr, AttachPtrType->castAs<PointerType>());
+ assert(AttachPteeBaseAddr.isValid() && "Invalid attach pointee base addr");
+
+ return {AttachPtrAddr, AttachPteeBaseAddr};
+ }
+
/// Returns whether an attach entry should be emitted for a map on
/// \p MapBaseDecl on the directive \p CurDir.
static bool
>From 61030b25a8af085539d4edb548ad62a9bf720552 Mon Sep 17 00:00:00 2001
From: Abhinav Gaba <abhinav.gaba at intel.com>
Date: Tue, 9 Sep 2025 10:26:30 -0700
Subject: [PATCH 4/5] Remove some unnecessary braces
---
clang/lib/CodeGen/CGOpenMPRuntime.cpp | 9 +++------
1 file changed, 3 insertions(+), 6 deletions(-)
diff --git a/clang/lib/CodeGen/CGOpenMPRuntime.cpp b/clang/lib/CodeGen/CGOpenMPRuntime.cpp
index 59028f8d55665..89052b808c0a3 100644
--- a/clang/lib/CodeGen/CGOpenMPRuntime.cpp
+++ b/clang/lib/CodeGen/CGOpenMPRuntime.cpp
@@ -7111,11 +7111,9 @@ class MappableExprsHandler {
if (AttachEntry.second) {
// Check if the attach pointer expression is a DeclRefExpr that
// references the captured variable
- if (const auto *DRE = dyn_cast<DeclRefExpr>(AttachEntry.second)) {
- if (DRE->getDecl() == VD) {
+ if (const auto *DRE = dyn_cast<DeclRefExpr>(AttachEntry.second))
+ if (DRE->getDecl() == VD)
return true;
- }
- }
}
}
return false;
@@ -7126,9 +7124,8 @@ class MappableExprsHandler {
OMPClauseMappableExprCommon::MappableExprComponentListRef Components)
const {
auto It = AttachPtrExprMap.find(Components);
- if (It != AttachPtrExprMap.end()) {
+ if (It != AttachPtrExprMap.end())
return It->second;
- }
return nullptr;
}
>From 90e1f32388452184f733f34abe0ba40b8ed399a0 Mon Sep 17 00:00:00 2001
From: Abhinav Gaba <abhinav.gaba at intel.com>
Date: Thu, 11 Sep 2025 16:27:37 -0700
Subject: [PATCH 5/5] Remove mutable from two DenseMaps
---
clang/lib/CodeGen/CGOpenMPRuntime.cpp | 10 +++++-----
1 file changed, 5 insertions(+), 5 deletions(-)
diff --git a/clang/lib/CodeGen/CGOpenMPRuntime.cpp b/clang/lib/CodeGen/CGOpenMPRuntime.cpp
index 89052b808c0a3..6ee0ee7e03960 100644
--- a/clang/lib/CodeGen/CGOpenMPRuntime.cpp
+++ b/clang/lib/CodeGen/CGOpenMPRuntime.cpp
@@ -7203,8 +7203,8 @@ class MappableExprsHandler {
llvm::DenseMap<const ValueDecl *, const OMPMapClause *> LambdasMap;
/// Map from component lists to their attach pointer expressions.
- mutable llvm::DenseMap<
- OMPClauseMappableExprCommon::MappableExprComponentListRef, const Expr *>
+ llvm::DenseMap<OMPClauseMappableExprCommon::MappableExprComponentListRef,
+ const Expr *>
AttachPtrExprMap;
/// Map from attach pointer expressions to their component depth.
@@ -7213,9 +7213,9 @@ class MappableExprsHandler {
/// The component-depth of `nullptr` (i.e. no attach-ptr) is `std::nullopt`.
/// TODO: Not urgent, but we should ideally use the number of pointer
/// dereferences in an expr as an indicator of its complexity, instead of the
- /// component-depth. That would be needed for us to treat `p[10]`,
- /// `*(p + 10)`, `*(p + 5 + 5)` together.
- mutable llvm::DenseMap<const Expr *, std::optional<size_t>>
+ /// component-depth. That would be needed for us to treat `p[1]`, `*(p + 10)`,
+ /// `*(p + 5 + 5)` together.
+ llvm::DenseMap<const Expr *, std::optional<size_t>>
AttachPtrComponentDepthMap = {{nullptr, std::nullopt}};
llvm::Value *getExprTypeSize(const Expr *E) const {
More information about the cfe-commits
mailing list