https://github.com/jtb20 created https://github.com/llvm/llvm-project/pull/153672
This patch is an early outline for a rework of several mapping features, intended to support 'containing structures' in the middle of expressions as well as at the top level (https://github.com/llvm/llvm-project/issues/141042). Key ideas are: - struct information is gathered using several pre-passes before `generateInfoForComponentList`. - "PartialStruct" is turned into a map, keyed on the "effective base" of each containing structure in a set of expressions in OpenMP 'map' clauses. - the reverse iterator over component lists (visiting the base decl, then walking out to the full expression) has a new 'ComponentListRefPtrPteeIterator' adapter that (a) visits reference-type list components twice, and (b) provides a few useful utility methods. The current state is that a couple of tests work up to a point, but I'm hitting problems with the runtime that will probably be helped by the in-progress patches to support ATTACH operations. This is obviously all full of debug code and not at all ready for review! Posting FYI. >From 806a34cf4ef936f22d0738f9bf34446b54d9fa21 Mon Sep 17 00:00:00 2001 From: Julian Brown <julian.br...@amd.com> Date: Thu, 24 Jul 2025 09:35:36 -0500 Subject: [PATCH 1/3] [OpenMP] Fix initialization order for CopyOverlappedEntryGaps NFC. --- clang/lib/CodeGen/CGOpenMPRuntime.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/clang/lib/CodeGen/CGOpenMPRuntime.cpp b/clang/lib/CodeGen/CGOpenMPRuntime.cpp index f1698a0bec373..91237cfe3a372 100644 --- a/clang/lib/CodeGen/CGOpenMPRuntime.cpp +++ b/clang/lib/CodeGen/CGOpenMPRuntime.cpp @@ -7108,8 +7108,8 @@ class MappableExprsHandler { Address BP, Address LB, bool IsNonContiguous, uint64_t DimSize) : CGF(CGF), CombinedInfo(CombinedInfo), Flags(Flags), MapDecl(MapDecl), - MapExpr(MapExpr), BP(BP), LB(LB), IsNonContiguous(IsNonContiguous), - DimSize(DimSize) {} + MapExpr(MapExpr), BP(BP), IsNonContiguous(IsNonContiguous), + DimSize(DimSize), LB(LB) {} void processField( const OMPClauseMappableExprCommon::MappableComponent &MC, >From a0b521344ba96cd47b70dca969ae836579c29dfc Mon Sep 17 00:00:00 2001 From: Julian Brown <julian.br...@amd.com> Date: Tue, 10 Jun 2025 08:11:06 -0500 Subject: [PATCH 2/3] Revert "[Clang][OpenMP] Fix mapping of structs to device (#75642)" This reverts commit 4ef6587715bec4520332528c4a71fe5a9ac10477. --- clang/lib/CodeGen/CGOpenMPRuntime.cpp | 116 +++++--------------------- 1 file changed, 20 insertions(+), 96 deletions(-) diff --git a/clang/lib/CodeGen/CGOpenMPRuntime.cpp b/clang/lib/CodeGen/CGOpenMPRuntime.cpp index 91237cfe3a372..3bfb01cccf1a0 100644 --- a/clang/lib/CodeGen/CGOpenMPRuntime.cpp +++ b/clang/lib/CodeGen/CGOpenMPRuntime.cpp @@ -7193,10 +7193,8 @@ class MappableExprsHandler { OpenMPMapClauseKind MapType, ArrayRef<OpenMPMapModifierKind> MapModifiers, ArrayRef<OpenMPMotionModifierKind> MotionModifiers, OMPClauseMappableExprCommon::MappableExprComponentListRef Components, - MapCombinedInfoTy &CombinedInfo, - MapCombinedInfoTy &StructBaseCombinedInfo, - StructRangeInfoTy &PartialStruct, bool IsFirstComponentList, - bool IsImplicit, bool GenerateAllInfoForClauses, + MapCombinedInfoTy &CombinedInfo, StructRangeInfoTy &PartialStruct, + bool IsFirstComponentList, bool IsImplicit, const ValueDecl *Mapper = nullptr, bool ForDeviceAddr = false, const ValueDecl *BaseDecl = nullptr, const Expr *MapExpr = nullptr, ArrayRef<OMPClauseMappableExprCommon::MappableExprComponentListRef> @@ -7493,25 +7491,6 @@ class MappableExprsHandler { bool IsPartialMapped = !PartialStruct.PreliminaryMapData.BasePointers.empty(); - // We need to check if we will be encountering any MEs. If we do not - // encounter any ME expression it means we will be mapping the whole struct. - // In that case we need to skip adding an entry for the struct to the - // CombinedInfo list and instead add an entry to the StructBaseCombinedInfo - // list only when generating all info for clauses. - bool IsMappingWholeStruct = true; - if (!GenerateAllInfoForClauses) { - IsMappingWholeStruct = false; - } else { - for (auto TempI = I; TempI != CE; ++TempI) { - const MemberExpr *PossibleME = - dyn_cast<MemberExpr>(TempI->getAssociatedExpression()); - if (PossibleME) { - IsMappingWholeStruct = false; - break; - } - } - } - for (; I != CE; ++I) { // If the current component is member of a struct (parent struct) mark it. if (!EncounteredME) { @@ -7701,7 +7680,6 @@ class MappableExprsHandler { // PartialStruct.PreliminaryMapData.BasePointers has been mapped. if ((!IsMemberPointerOrAddr && !IsPartialMapped) || (Next == CE && MapType != OMPC_MAP_unknown)) { - if (!IsMappingWholeStruct) { CombinedInfo.Exprs.emplace_back(MapDecl, MapExpr); CombinedInfo.BasePointers.push_back(BP.emitRawPointer(CGF)); CombinedInfo.DevicePtrDecls.push_back(nullptr); @@ -7711,26 +7689,9 @@ class MappableExprsHandler { Size, CGF.Int64Ty, /*isSigned=*/true)); CombinedInfo.NonContigInfo.Dims.push_back(IsNonContiguous ? DimSize : 1); - } else { - StructBaseCombinedInfo.Exprs.emplace_back(MapDecl, MapExpr); - StructBaseCombinedInfo.BasePointers.push_back( - BP.emitRawPointer(CGF)); - StructBaseCombinedInfo.DevicePtrDecls.push_back(nullptr); - StructBaseCombinedInfo.DevicePointers.push_back(DeviceInfoTy::None); - StructBaseCombinedInfo.Pointers.push_back(LB.emitRawPointer(CGF)); - StructBaseCombinedInfo.Sizes.push_back(CGF.Builder.CreateIntCast( - Size, CGF.Int64Ty, /*isSigned=*/true)); - StructBaseCombinedInfo.NonContigInfo.Dims.push_back( - IsNonContiguous ? DimSize : 1); - } - // If Mapper is valid, the last component inherits the mapper. bool HasMapper = Mapper && Next == CE; - if (!IsMappingWholeStruct) - CombinedInfo.Mappers.push_back(HasMapper ? Mapper : nullptr); - else - StructBaseCombinedInfo.Mappers.push_back(HasMapper ? Mapper - : nullptr); + CombinedInfo.Mappers.push_back(HasMapper ? Mapper : nullptr); // We need to add a pointer flag for each map that comes from the // same expression except for the first one. We also need to signal @@ -7764,10 +7725,7 @@ class MappableExprsHandler { } } - if (!IsMappingWholeStruct) - CombinedInfo.Types.push_back(Flags); - else - StructBaseCombinedInfo.Types.push_back(Flags); + CombinedInfo.Types.push_back(Flags); } // If we have encountered a member expression so far, keep track of the @@ -8359,10 +8317,8 @@ class MappableExprsHandler { for (const auto &Data : Info) { StructRangeInfoTy PartialStruct; - // Current struct information: + // Temporary generated information. MapCombinedInfoTy CurInfo; - // Current struct base information: - MapCombinedInfoTy StructBaseCurInfo; const Decl *D = Data.first; const ValueDecl *VD = cast_or_null<ValueDecl>(D); bool HasMapBasePtr = false; @@ -8387,56 +8343,31 @@ class MappableExprsHandler { // Remember the current base pointer index. unsigned CurrentBasePointersIdx = CurInfo.BasePointers.size(); - unsigned StructBasePointersIdx = - StructBaseCurInfo.BasePointers.size(); CurInfo.NonContigInfo.IsNonContiguous = L.Components.back().isNonContiguous(); generateInfoForComponentList( L.MapType, L.MapModifiers, L.MotionModifiers, L.Components, - CurInfo, StructBaseCurInfo, PartialStruct, - /*IsFirstComponentList=*/false, L.IsImplicit, - /*GenerateAllInfoForClauses*/ true, L.Mapper, L.ForDeviceAddr, VD, - L.VarRef, /*OverlappedElements*/ {}, + CurInfo, PartialStruct, /*IsFirstComponentList=*/false, + L.IsImplicit, /*GenerateAllInfoForClauses*/ true, L.Mapper, + L.ForDeviceAddr, VD, L.VarRef, /*OverlappedElements*/ {}, HasMapBasePtr && HasMapArraySec); - // If this entry relates to a device pointer, set the relevant + // If this entry relates with a device pointer, set the relevant // declaration and add the 'return pointer' flag. if (L.ReturnDevicePointer) { - // Check whether a value was added to either CurInfo or - // StructBaseCurInfo and error if no value was added to either of - // them: - assert((CurrentBasePointersIdx < CurInfo.BasePointers.size() || - StructBasePointersIdx < - StructBaseCurInfo.BasePointers.size()) && + assert(CurInfo.BasePointers.size() > CurrentBasePointersIdx && "Unexpected number of mapped base pointers."); - // Choose a base pointer index which is always valid: const ValueDecl *RelevantVD = L.Components.back().getAssociatedDeclaration(); assert(RelevantVD && "No relevant declaration related with device pointer??"); - // If StructBaseCurInfo has been updated this iteration then work on - // the first new entry added to it i.e. make sure that when multiple - // values are added to any of the lists, the first value added is - // being modified by the assignments below (not the last value - // added). - if (StructBasePointersIdx < StructBaseCurInfo.BasePointers.size()) { - StructBaseCurInfo.DevicePtrDecls[StructBasePointersIdx] = - RelevantVD; - StructBaseCurInfo.DevicePointers[StructBasePointersIdx] = - L.ForDeviceAddr ? DeviceInfoTy::Address - : DeviceInfoTy::Pointer; - StructBaseCurInfo.Types[StructBasePointersIdx] |= - OpenMPOffloadMappingFlags::OMP_MAP_RETURN_PARAM; - } else { - CurInfo.DevicePtrDecls[CurrentBasePointersIdx] = RelevantVD; - CurInfo.DevicePointers[CurrentBasePointersIdx] = - L.ForDeviceAddr ? DeviceInfoTy::Address - : DeviceInfoTy::Pointer; - CurInfo.Types[CurrentBasePointersIdx] |= - OpenMPOffloadMappingFlags::OMP_MAP_RETURN_PARAM; - } + CurInfo.DevicePtrDecls[CurrentBasePointersIdx] = RelevantVD; + CurInfo.DevicePointers[CurrentBasePointersIdx] = + L.ForDeviceAddr ? DeviceInfoTy::Address : DeviceInfoTy::Pointer; + CurInfo.Types[CurrentBasePointersIdx] |= + OpenMPOffloadMappingFlags::OMP_MAP_RETURN_PARAM; } } } @@ -8483,24 +8414,17 @@ class MappableExprsHandler { CurInfo.Mappers.push_back(nullptr); } } - - // Unify entries in one list making sure the struct mapping precedes the - // individual fields: - MapCombinedInfoTy UnionCurInfo; - UnionCurInfo.append(StructBaseCurInfo); - UnionCurInfo.append(CurInfo); - // If there is an entry in PartialStruct it means we have a struct with // individual members mapped. Emit an extra combined entry. if (PartialStruct.Base.isValid()) { - UnionCurInfo.NonContigInfo.Dims.push_back(0); - // Emit a combined entry: - emitCombinedEntry(CombinedInfo, UnionCurInfo.Types, PartialStruct, + CurInfo.NonContigInfo.Dims.push_back(0); + emitCombinedEntry(CombinedInfo, CurInfo.Types, PartialStruct, /*IsMapThis*/ !VD, OMPBuilder, VD); } - // We need to append the results of this capture to what we already have. - CombinedInfo.append(UnionCurInfo); + // We need to append the results of this capture to what we already + // have. + CombinedInfo.append(CurInfo); } // Append data for use_device_ptr clauses. CombinedInfo.append(UseDeviceDataCombinedInfo); >From 67db4820e3fa4412c8e69be8091e3ca4332ee041 Mon Sep 17 00:00:00 2001 From: Julian Brown <julian.br...@amd.com> Date: Thu, 12 Jun 2025 08:20:12 -0500 Subject: [PATCH 3/3] [OpenMP][wip] Rework 'containing struct'/overlapped mapping handling This patch is an early outline for a rework of several mapping features, intended to support 'containing structures' in the middle of expressions as well as at the top level (https://github.com/llvm/llvm-project/issues/141042). Key ideas are: - struct information is gathered as several pre-passes before generateInfoForComponentList. - "PartialStruct" is turned into a map, keyed on the "effective base" of each containing structure in a set of expressions in OpenMP 'map' clauses. - the reverse iterator over component lists (visiting the base decl, then walking out to the full expression) has a new 'ComponentListRefPtrPteeIterator' adapter that (a) visits reference-type list components twice, and (b) provides a few useful utility methods. The current state is that a couple of tests work up to a point, but I'm hitting problems with the runtime that will probably be helped by the in-progress patches to support ATTACH operations. --- clang/lib/CodeGen/CGOpenMPRuntime.cpp | 1384 ++++++++++++++++++++++--- 1 file changed, 1265 insertions(+), 119 deletions(-) diff --git a/clang/lib/CodeGen/CGOpenMPRuntime.cpp b/clang/lib/CodeGen/CGOpenMPRuntime.cpp index 3bfb01cccf1a0..3587096f8c6ec 100644 --- a/clang/lib/CodeGen/CGOpenMPRuntime.cpp +++ b/clang/lib/CodeGen/CGOpenMPRuntime.cpp @@ -18,25 +18,32 @@ #include "CGRecordLayout.h" #include "CodeGenFunction.h" #include "TargetInfo.h" +#include "clang-c/Index.h" #include "clang/AST/APValue.h" +#include "clang/AST/ASTContext.h" #include "clang/AST/Attr.h" #include "clang/AST/Decl.h" +#include "clang/AST/ExprOpenMP.h" #include "clang/AST/OpenMPClause.h" #include "clang/AST/StmtOpenMP.h" #include "clang/AST/StmtVisitor.h" #include "clang/Basic/OpenMPKinds.h" #include "clang/Basic/SourceManager.h" +#include "clang/CodeGen/CodeGenABITypes.h" #include "clang/CodeGen/ConstantInitBuilder.h" #include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/FoldingSet.h" #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/StringExtras.h" #include "llvm/Bitcode/BitcodeReader.h" +#include "llvm/Frontend/OpenMP/OMPConstants.h" #include "llvm/IR/Constants.h" #include "llvm/IR/DerivedTypes.h" #include "llvm/IR/GlobalValue.h" #include "llvm/IR/InstrTypes.h" #include "llvm/IR/Value.h" #include "llvm/Support/AtomicOrdering.h" +#include "llvm/Support/TypeSize.h" #include "llvm/Support/raw_ostream.h" #include <cassert> #include <cstdint> @@ -6755,6 +6762,51 @@ llvm::Value *CGOpenMPRuntime::emitNumThreadsForTargetDirective( return NumThreadsVal; } +class EffectiveBaseMapKey { + llvm::FoldingSetNodeID ID; + bool Indirect = false; + +public: + EffectiveBaseMapKey(ASTContext &Ctx, const Expr *EB, bool Ind) { + EB->Profile(ID, Ctx, /*Canonical=*/true); + Indirect = Ind; + } + + EffectiveBaseMapKey(llvm::FoldingSetNodeID FromID) : ID(FromID) { } + + llvm::FoldingSetNodeID getID() const { return ID; } + bool getIndirect() const { return Indirect; } +}; + +template <> struct llvm::DenseMapInfo<EffectiveBaseMapKey> { + + static EffectiveBaseMapKey getEmptyKey() { + llvm::FoldingSetNodeID ID; + ID.AddInteger(std::numeric_limits<unsigned>::max()); + return EffectiveBaseMapKey(ID); + } + + static EffectiveBaseMapKey getTombstoneKey() { + llvm::FoldingSetNodeID ID; + for (unsigned I = 0; I < sizeof(ID) / sizeof(unsigned); ++I) { + ID.AddInteger(std::numeric_limits<unsigned>::max()); + } + return EffectiveBaseMapKey(ID); + } + + static unsigned getHashValue(const EffectiveBaseMapKey &Val) { + auto ID = Val.getID(); + ID.AddBoolean(Val.getIndirect()); + return ID.ComputeHash(); + } + + static bool isEqual(const EffectiveBaseMapKey &LHS, + const EffectiveBaseMapKey &RHS) { + return LHS.getID() == RHS.getID() && + LHS.getIndirect() == RHS.getIndirect(); + } +}; + namespace { LLVM_ENABLE_BITMASK_ENUMS_IN_NAMESPACE(); @@ -6787,7 +6839,6 @@ class MappableExprsHandler { public: MappingExprInfo(const ValueDecl *MapDecl, const Expr *MapExpr = nullptr) : MapDecl(MapDecl), MapExpr(MapExpr) {} - const ValueDecl *getMapDecl() const { return MapDecl; } const Expr *getMapExpr() const { return MapExpr; } }; @@ -6825,22 +6876,50 @@ class MappableExprsHandler { } }; + struct MappableExprMetadata { + OMPClauseMappableExprCommon::MappableExprComponentListRef Components; + const MapData *MD = nullptr; + bool CompleteExpression = false; + Address Base = Address::invalid(); + Address Pointer = Address::invalid(); + + //MappableExprMetadata() {} + + /*MappableExprMetadata(OMPClauseMappableExprCommon::MappableExprComponentListRef Components, + const MapData *MD, bool CompleteExpression) + : Components(Components), MD(MD), + CompleteExpression(CompleteExpression) {} + + MappableExprMetadata(MappableExprMetadata &Other) { + + }*/ + }; + + using ExprComponentMap = llvm::MapVector<EffectiveBaseMapKey, MappableExprMetadata>; + /// Map between a struct and the its lowest & highest elements which have been /// mapped. /// [ValueDecl *] --> {LE(FieldIndex, Pointer), /// HE(FieldIndex, Pointer)} struct StructRangeInfoTy { - MapCombinedInfoTy PreliminaryMapData; + //MapCombinedInfoTy PreliminaryMapData; + const Expr *BaseExpr = nullptr; + ExprComponentMap ChildComponents; + unsigned MemberDepth = -1u; std::pair<unsigned /*FieldIndex*/, Address /*Pointer*/> LowestElem = { 0, Address::invalid()}; std::pair<unsigned /*FieldIndex*/, Address /*Pointer*/> HighestElem = { 0, Address::invalid()}; Address Base = Address::invalid(); + Address BaseAddr = Address::invalid(); Address LB = Address::invalid(); bool IsArraySection = false; - bool HasCompleteRecord = false; + const MapData *ContainingStructMap = nullptr; }; + // A map from effective base addresses to struct range info for that base. + using PartialStructMap = llvm::DenseMap<EffectiveBaseMapKey, StructRangeInfoTy>; + private: /// Kind that defines how a device pointer has to be returned. struct MapInfo { @@ -7113,16 +7192,20 @@ class MappableExprsHandler { void processField( const OMPClauseMappableExprCommon::MappableComponent &MC, + llvm::DenseMap<const FieldDecl *, uint64_t> &Layout, const FieldDecl *FD, llvm::function_ref<LValue(CodeGenFunction &, const MemberExpr *)> EmitMemberExprBase) { - const RecordDecl *RD = FD->getParent(); - const ASTRecordLayout &RL = CGF.getContext().getASTRecordLayout(RD); - uint64_t FieldOffset = RL.getFieldOffset(FD->getFieldIndex()); + uint64_t FieldOffset = CGF.getContext().toBits(CharUnits::fromQuantity(Layout[FD])); uint64_t FieldSize = CGF.getContext().getTypeSize(FD->getType().getCanonicalType()); Address ComponentLB = Address::invalid(); + fprintf(stderr, "Process field: "); + MC.getAssociatedExpression()->dumpPretty(CGF.getContext()); + fprintf(stderr, " offset: %d index: %d cursor: %d\n", (int) FieldOffset, (int) FD->getFieldIndex(), + (int) Cursor); + if (FD->getType()->isLValueReferenceType()) { const auto *ME = cast<MemberExpr>(MC.getAssociatedExpression()); LValue BaseLVal = EmitMemberExprBase(CGF, ME); @@ -7133,8 +7216,6 @@ class MappableExprsHandler { CGF.EmitOMPSharedLValue(MC.getAssociatedExpression()).getAddress(); } - if (!LastParent) - LastParent = RD; if (FD->getParent() == LastParent) { if (FD->getFieldIndex() != LastIndex + 1) copyUntilField(FD, ComponentLB); @@ -7156,13 +7237,11 @@ class MappableExprsHandler { copySizedChunk(LBPtr, Size); } - void copyUntilEnd(Address HB) { - if (LastParent) { - const ASTRecordLayout &RL = - CGF.getContext().getASTRecordLayout(LastParent); - if ((uint64_t)CGF.getContext().toBits(RL.getSize()) <= Cursor) - return; - } + void copyUntilEnd(Address HB, CharUnits TypeSize) { + fprintf(stderr, "copyUntilEnd: Cursor=%d TypeSize=%d\n", + (int) Cursor, (int) CGF.getContext().toBits(TypeSize)); + if ((uint64_t)CGF.getContext().toBits(TypeSize) <= Cursor) + return; llvm::Value *LBPtr = LB.emitRawPointer(CGF); llvm::Value *Size = CGF.Builder.CreatePtrDiff( CGF.Int8Ty, CGF.Builder.CreateConstGEP(HB, 1).emitRawPointer(CGF), @@ -7184,6 +7263,544 @@ class MappableExprsHandler { } }; + /// Given a MemberExpr \c ME, find the containing structure as understood by + /// OpenMP (OpenMP 6.0, "2 Glossary"). + const Expr *getEffectiveBase(const MemberExpr *ME, const MemberExpr **IME, bool &Ind) const { + const Expr *Base = ME->getBase()->IgnoreParenImpCasts(); + + Ind = false; + + /*fprintf(stderr, "getEffectiveBase, input="); + ME->dumpPretty(CGF.getContext()); + fprintf(stderr, "\nbase="); + Base->dumpPretty(CGF.getContext()); + fprintf(stderr, "\n");*/ + + // Strip off any outer "." member accesses first + while (const auto *MEB = dyn_cast<MemberExpr>(Base)) { + if (ME->isArrow() || Base->getType()->isReferenceType()) { + break; + } else { + ME = MEB; + if (IME) + *IME = ME; + Base = ME->getBase()->IgnoreParenImpCasts(); + } + } + + /*fprintf(stderr, "now base="); + Base->dumpPretty(CGF.getContext()); + fprintf(stderr, "\n");*/ + + if (ME->isArrow() || Base->getType()->isReferenceType()) { + Ind = true; + return Base; + } + + return indirectOnce(Base, Ind); + } + + // Iterate a component list from the base of an expression to the complete + // expression. Components which are references are visited twice: firstly + // as the pointer, second as the pointee. + struct ComponentListRefPtrPteeIterator { + using iterator_category = std::forward_iterator_tag; + using value_type = const OMPClauseMappableExprCommon::MappableComponent; + using difference_type = std::ptrdiff_t; + using pointer = const OMPClauseMappableExprCommon::MappableComponent*; + using reference = const OMPClauseMappableExprCommon::MappableComponent&; + + std::reverse_iterator<const OMPClauseMappableExprCommon::MappableComponent *> Pos; + bool RefPtee = false; + const ValueDecl *BaseDecl = nullptr; + // We repeat on references -- this is the position in the underlying list. + unsigned ComponentPos = 0; + + ComponentListRefPtrPteeIterator(std::reverse_iterator<const OMPClauseMappableExprCommon::MappableComponent *> From) : Pos(From) + { } + + reference operator*() const { return *Pos; } + pointer operator->() { return &*Pos; } + + void setBaseDecl(const ValueDecl *Decl) { + BaseDecl = Decl; + } + + bool isRefPtee() { + return RefPtee; + } + + bool isRef() { + const OMPClauseMappableExprCommon::MappableComponent *Comp = &*Pos; + if (isa<MemberExpr>(Pos->getAssociatedExpression())) { + const ValueDecl *MapDecl = Comp->getAssociatedDeclaration(); + assert(MapDecl && "Expected associated declaration for member expr"); + return MapDecl->getType()->isLValueReferenceType(); + } + return false; + } + + bool isPointer(bool AllowDeref) { + const OMPClauseMappableExprCommon::MappableComponent *Comp = &*Pos; + const Expr *AE = Comp->getAssociatedExpression(); + const auto *OASE = dyn_cast<ArraySectionExpr>(AE); + bool IsPointer = + isa<OMPArrayShapingExpr>(AE) || + (OASE && ArraySectionExpr::getBaseOriginalType(OASE).getCanonicalType()->isAnyPointerType()) || + AE->getType()->isAnyPointerType(); + + if (AllowDeref) + return IsPointer; + else if (!IsPointer) + return false; + + if (const auto *UO = dyn_cast<UnaryOperator>(AE)) + return UO->getOpcode() != UO_Deref; + + return !isa<BinaryOperator>(AE); + } + + unsigned getComponentPos() { + return ComponentPos; + } + + ComponentListRefPtrPteeIterator& operator++() { + if (isRef()) { + if (!RefPtee) + RefPtee = true; + else { + RefPtee = false; + ++Pos; + } + } else { + RefPtee = false; + // This could skip to outermost MemberExprs (over "."). + ++Pos; + ++ComponentPos; + /*while (auto ME = dyn_cast<MemberExpr>(Pos->getAssociatedExpression()->IgnoreParenImpCasts())) { + if (ME->isArrow() || ME->getBase()->getType()->isReferenceType()) + break; + else + ++Pos; + }*/ + } + return *this; + } + + ComponentListRefPtrPteeIterator operator++(int) { + ComponentListRefPtrPteeIterator tmp = *this; + ++(*this); + return tmp; + } + + friend bool operator==(const ComponentListRefPtrPteeIterator& a, + const ComponentListRefPtrPteeIterator& b) { + return a.Pos == b.Pos && a.RefPtee == b.RefPtee; + } + + friend bool operator!=(const ComponentListRefPtrPteeIterator &a, + const ComponentListRefPtrPteeIterator &b) { + return a.Pos != b.Pos || a.RefPtee != b.RefPtee; + } + }; + + bool exprsEqual(Expr *One, Expr *Two) const { + if (One == nullptr || Two == nullptr) + return One == Two; + + if (One->getStmtClass() != Two->getStmtClass()) + return false; + + llvm::FoldingSetNodeID ProfOne, ProfTwo; + One->Profile(ProfOne, CGF.getContext(), true); + Two->Profile(ProfTwo, CGF.getContext(), true); + + return ProfOne == ProfTwo; + } + + const Expr *indirectOnce(const Expr *E, bool &Ind) const { + Ind = false; + + // Treat (*foo).bar the same as foo->bar + if (const auto *UO = dyn_cast<UnaryOperator>(E)) { + if (UO->getOpcode() == UO_Deref) { + Ind = true; + return UO->getSubExpr()->IgnoreParenImpCasts(); + } + } + + // Treat foo[0].bar the same as foo->bar + while (const auto *ASE = dyn_cast<ArraySubscriptExpr>(E)) { + const Expr *ArrayBase = ASE->getBase()->IgnoreParenImpCasts(); + const Expr *Index = ASE->getIdx(); + Expr::EvalResult Result; + if (!Index->EvaluateAsInt(Result, CGF.getContext())) { + return E; + } + llvm::APSInt ConstIndex = Result.Val.getInt(); + if (ConstIndex == 0) { + Ind = true; + E = ArrayBase; + } + if (!E->getType()->isArrayType()) + break; + } + + // Treat foo[:1].bar & foo[0:1].bar the same as foo->bar + if (const auto *ASecE = dyn_cast<ArraySectionExpr>(E)) { + const Expr *ArrayBase = ASecE->getBase()->IgnoreParenImpCasts(); + const Expr *LB = ASecE->getLowerBound(); + const Expr *Len = ASecE->getLength(); + bool LBZero = false, LenOne = false; + Expr::EvalResult Result; + if (!LB) { + LBZero = true; + } else if (LB->EvaluateAsInt(Result, CGF.getContext())) { + llvm::APSInt ConstLB = Result.Val.getInt(); + if (ConstLB == 0) + LBZero = true; + } + if (Len && Len->EvaluateAsInt(Result, CGF.getContext())) { + llvm::APSInt ConstLen = Result.Val.getInt(); + if (ConstLen == 1) { + LenOne = true; + } + } + if (LBZero && LenOne) { + Ind = true; + return ArrayBase; + } + } + + return E; + } + + bool componentsEqual(const OMPClauseMappableExprCommon::MappableComponent &One, + const OMPClauseMappableExprCommon::MappableComponent &Two) const { + if (One.isNonContiguous() != Two.isNonContiguous()) + return false; + + ValueDecl *DeclOne = One.getAssociatedDeclaration(); + ValueDecl *DeclTwo = Two.getAssociatedDeclaration(); + + if (DeclOne == nullptr || DeclTwo == nullptr) + return DeclOne == DeclTwo; + + if (DeclOne->getCanonicalDecl() != DeclTwo->getCanonicalDecl()) + return false; + + return exprsEqual(One.getAssociatedExpression(), + Two.getAssociatedExpression()); + } + + bool hasMemberExpr(const OMPClauseMappableExprCommon::MappableExprComponentListRef Components) const { + return llvm::any_of(Components, [](const OMPClauseMappableExprCommon::MappableComponent &M) { + return isa<MemberExpr>(M.getAssociatedExpression()); + }); + } + + void gatherStructDataForComponentList(const MapData &MD, OpenMPMapClauseKind MapType, ArrayRef<OpenMPMapModifierKind> MapModifiers, + OMPClauseMappableExprCommon::MappableExprComponentListRef Components, + MapCombinedInfoTy &CombinedInfo, PartialStructMap &PartialStructs, + bool IsImplicit, const ValueDecl *Mapper = nullptr, + const ValueDecl *BaseDecl = nullptr, const Expr *MapExpr = nullptr) const { + // Scan the components from the base to the complete expression. + auto CI = ComponentListRefPtrPteeIterator(Components.rbegin()); + auto CE = ComponentListRefPtrPteeIterator(Components.rend()); + auto I = CI; + + I.setBaseDecl(BaseDecl); + + Address BPP = Address::invalid(); + Address BP = Address::invalid(); + + const Expr *AssocExpr = I->getAssociatedExpression(); + /*const auto *AE = dyn_cast<ArraySubscriptExpr>(AssocExpr); + const auto *OASE = dyn_cast<ArraySectionExpr>(AssocExpr); + const auto *OAShE = dyn_cast<OMPArrayShapingExpr>(AssocExpr);*/ + + auto &&EmitMemberExprBase = [](CodeGenFunction &CGF, + const MemberExpr *E) { + const Expr *BaseExpr = E->getBase(); + // If this is s.x, emit s as an lvalue. If it is s->x, emit s as a + // scalar. + LValue BaseLV; + if (E->isArrow()) { + LValueBaseInfo BaseInfo; + TBAAAccessInfo TBAAInfo; + Address Addr = + CGF.EmitPointerWithAlignment(BaseExpr, &BaseInfo, &TBAAInfo); + QualType PtrTy = BaseExpr->getType()->getPointeeType(); + BaseLV = CGF.MakeAddrLValue(Addr, PtrTy, BaseInfo, TBAAInfo); + } else { + BaseLV = CGF.EmitOMPSharedLValue(BaseExpr); + } + return BaseLV; + }; + + if (!hasMemberExpr(Components)) + return; + + /* + if (isa<MemberExpr>(AssocExpr)) { + // The base is the 'this' pointer. The content of the pointer is going + // to be the base of the field being mapped. + BP = CGF.LoadCXXThisAddress(); + } else if ((AE && isa<CXXThisExpr>(AE->getBase()->IgnoreParenImpCasts())) || + (OASE && + isa<CXXThisExpr>(OASE->getBase()->IgnoreParenImpCasts()))) { + BP = CGF.EmitOMPSharedLValue(AssocExpr).getAddress(); + } else if (OAShE && + isa<CXXThisExpr>(OAShE->getBase()->IgnoreParenCasts())) { + BP = Address( + CGF.EmitScalarExpr(OAShE->getBase()), + CGF.ConvertTypeForMem(OAShE->getBase()->getType()->getPointeeType()), + CGF.getContext().getTypeAlignInChars(OAShE->getBase()->getType())); + } else {*/ + // The base is the reference to the variable. + // BP = &Var. + fprintf(stderr, "Init new BP from "); + AssocExpr->dumpPretty(CGF.getContext()); + fprintf(stderr, "\n"); + BP = CGF.EmitOMPSharedLValue(AssocExpr).getAddress(); + BPP = Address::invalid(); + QualType Ty = CI->getAssociatedDeclaration()->getType().getNonReferenceType(); + if (Ty->isAnyPointerType()) { + BPP = BP; + BP = CGF.EmitLoadOfPointer(BP, Ty->castAs<PointerType>()); + } + //} + + bool IsNonContiguous = CombinedInfo.NonContigInfo.IsNonContiguous; + // Maybe this needs to be "number of indirections". We want something + // similar to topological sort, but simpler. + unsigned MemberDepth = 0; + + MemberExpr *FirstMemberExpr = nullptr; + MemberExpr *LastMemberExpr = nullptr; + + for (; I != CE; ++I) { + StructRangeInfoTy *PartialStruct = nullptr; + bool Indirected = false; + + //auto Next = std::next(I); + if (auto ME = dyn_cast<MemberExpr>(I->getAssociatedExpression()->IgnoreParenImpCasts())) { + /*if (!FirstMemberExpr) { + QualType Ty = CI->getAssociatedDeclaration()->getType().getNonReferenceType(); + if (Ty->isAnyPointerType()) { + BP = CGF.EmitLoadOfPointer(BP, Ty->castAs<PointerType>()); + Indirected = true; + } + FirstMemberExpr = ME; + }*/ + ++MemberDepth; + } + + // Peek at the next outer expression to see if it's a "." member access + if (auto ME = dyn_cast<MemberExpr>(I->getAssociatedExpression()->IgnoreParenImpCasts())) { + auto Next = std::next(I); + if (Next != CE) { + if (auto NME = dyn_cast<MemberExpr>(Next->getAssociatedExpression()->IgnoreParenImpCasts())) { + if (!NME->isArrow()) + continue; + } + } + /*QualType Ty = I->getAssociatedDeclaration()->getType().getNonReferenceType(); + fprintf(stderr, "expr: "); + I->getAssociatedExpression()->dumpPretty(CGF.getContext()); + fprintf(stderr, "\n"); + bool Ind; + const Expr *EB = getEffectiveBase(ME, nullptr, Ind); + if (Ind) { + BPP = BP; + BP = CGF.EmitLoadOfPointer(BP, Ty->castAs<PointerType>()); + } else { + BPP = Address::invalid(); + }*/ + } + + bool LastIter = std::next(I) == CE; + + const auto *OASE = + dyn_cast<ArraySectionExpr>(I->getAssociatedExpression()); + const auto *OAShE = + dyn_cast<OMPArrayShapingExpr>(I->getAssociatedExpression()); + const auto *UO = + dyn_cast<UnaryOperator>(I->getAssociatedExpression()); + bool IsDeref = UO && UO->getOpcode() == UO_Deref; + + // A final array section, is one whose length can't be proved to be one. + // If the map item is non-contiguous then we don't treat any array section + // as final array section. + bool IsFinalArraySection = + !IsNonContiguous && + isFinalArraySectionExpression(I->getAssociatedExpression()); + + // If we have a declaration for the mapping use that, otherwise use + // the base declaration of the map clause. + const ValueDecl *MapDecl = (I->getAssociatedDeclaration()) + ? I->getAssociatedDeclaration() + : BaseDecl; + + //if (OASE) + // ++DimSize; + + if (LastIter || I.isRef() || I.isPointer(false) || IsFinalArraySection) { + Address LB = Address::invalid(); + //Address LowestElem = Address::invalid(); + + if (OAShE) { + /*LowestElem = */LB = + Address(CGF.EmitScalarExpr(OAShE->getBase()), + CGF.ConvertTypeForMem(OAShE->getBase()->getType()->getPointeeType()), + CGF.getContext().getTypeAlignInChars( + OAShE->getBase()->getType())); + } else if (I.isRef()) { + const auto *ME = cast<MemberExpr>(I->getAssociatedExpression()); + LValue BaseLVal = EmitMemberExprBase(CGF, ME); + /*LowestElem =*/ + LB = CGF.EmitLValueForFieldInitialization( + BaseLVal, cast<FieldDecl>(MapDecl)) + .getAddress(); + if (I.isRefPtee()) + LB = CGF.EmitLoadOfReferenceLValue(LB, MapDecl->getType()) + .getAddress(); + } else { + /*LowestElem = */LB = + CGF.EmitOMPSharedLValue(I->getAssociatedExpression()) + .getAddress(); + fprintf(stderr, "Calculated LB from: "); + I->getAssociatedExpression()->dumpPretty(CGF.getContext()); + fprintf(stderr, "\n"); + } + + if (MemberExpr *ME = dyn_cast<MemberExpr>(I->getAssociatedExpression())) { + const MemberExpr *IME = ME; + bool Ind; + const Expr *EB = getEffectiveBase(ME, &IME, Ind); + EffectiveBaseMapKey EBKey(CGF.getContext(), EB, Ind); + if (PartialStructs.find(EBKey) == PartialStructs.end()) { + PartialStructs[EBKey] = StructRangeInfoTy{}; + } + PartialStruct = &PartialStructs[EBKey]; + if (PartialStruct->MemberDepth == -1u) + PartialStruct->MemberDepth = MemberDepth; + else { + if (PartialStruct->MemberDepth > MemberDepth) { + fprintf(stderr, "Member depth changed! %u->%u\n", + PartialStruct->MemberDepth, MemberDepth); + } + } + const auto *FD = cast<FieldDecl>(IME->getMemberDecl()); + unsigned FieldIndex = FD->getFieldIndex(); + + // FIXME: Inadequate. + //if (MemberDepth > 1) { + // QualType Ty = ME->getBase()->getType().getNonReferenceType(); + // if (Ty->isAnyPointerType()) { + // fprintf(stderr, "Indirect BP\n"); + // BP = CGF.EmitLoadOfPointer(BP, Ty->castAs<PointerType>()); + // } + // } + + // Update info about the lowest and highest elements for this struct + if (!PartialStruct->Base.isValid()) { + PartialStruct->LowestElem = {FieldIndex, LB/*LowestElem*/}; + if (IsFinalArraySection && OASE) { + Address HB = + CGF.EmitArraySectionExpr(OASE, /*IsLowerBound=*/false) + .getAddress(); + PartialStruct->HighestElem = {FieldIndex, HB}; + } else { + PartialStruct->HighestElem = {FieldIndex, LB/*LowestElem*/}; + } + // This gets overridden (to the beginning of the struct) in the + // second pass, when we know if we're also mapping the whole struct. + PartialStruct->LB = LB; + fprintf(stderr, "Set partial struct base to BP\n"); + PartialStruct->Base = BP; + PartialStruct->BaseAddr = BPP; + PartialStruct->BaseExpr = EB; + } else if (FieldIndex < PartialStruct->LowestElem.first) { + PartialStruct->LowestElem = {FieldIndex, LB/*LowestElem*/}; + } else if (FieldIndex > PartialStruct->HighestElem.first) { + if (IsFinalArraySection && OASE) { + Address HB = + CGF.EmitArraySectionExpr(OASE, /*IsLowerBound=*/false) + .getAddress(); + PartialStruct->HighestElem = {FieldIndex, HB}; + } else { + PartialStruct->HighestElem = {FieldIndex, LB/*LowestElem*/}; + } + } + LastMemberExpr = ME; + } + + /*auto Next = std::next(I); + if (Next != CE) { + const Expr *NE = Next->getAssociatedExpression(); + bool Ind; + const Expr *INE = indirectOnce(NE, Ind); + if (Ind) { + fprintf(stderr, "Indirected once, from: "); + NE->dumpPretty(CGF.getContext()); + fprintf(stderr, "\nto: "); + INE->dumpPretty(CGF.getContext()); + fprintf(stderr, "\n"); + if (isa<MemberExpr>(INE) || + isa<DeclRefExpr>(INE)) { + fprintf(stderr, "continuing\n"); + continue; + } else { + fprintf(stderr, "breaking\n"); + break; + } + } + }*/ + + do { + if (isa<MemberExpr>(I->getAssociatedExpression()) || LastIter) { + EffectiveBaseMapKey IKey(CGF.getContext(), I->getAssociatedExpression(), false); + if (!PartialStruct) { + assert(LastIter && "only expected null PartialStruct on last iter"); + if (!LastMemberExpr) + break; + bool Ind; + const Expr *EB = getEffectiveBase(LastMemberExpr, nullptr, Ind); + EffectiveBaseMapKey EBKey(CGF.getContext(), EB, Ind); + PartialStruct = &PartialStructs[EBKey]; + } + if (PartialStruct->ChildComponents.find(IKey) == PartialStruct->ChildComponents.end()) { + int CutElems = Components.size() - I.getComponentPos() - 1; + ArrayRef<OMPClauseMappableExprCommon::MappableComponent> Tmp = + Components.drop_front(CutElems); + bool CompleteExpr = CutElems == 0; + auto CI = Tmp.rbegin(); + auto CE = Tmp.rend(); + auto I = CI; + fprintf(stderr, "Made a chopped list:\n"); + for (; I != CE; ++I) { + I->getAssociatedExpression()->dumpPretty(CGF.getContext()); + fprintf(stderr, "\n"); + } + PartialStruct->ChildComponents[IKey] = {Tmp, &MD, CompleteExpr, BP, LB}; + } + } + } while (false); + + fprintf(stderr, "copy LB to BP\n"); + BPP = LB; + QualType Ty = I->getAssociatedExpression()->getType().getCanonicalType(); + if (Ty->isAnyPointerType()) { + BP = CGF.EmitLoadOfPointer(BPP, Ty->castAs<PointerType>()); + } else { + fprintf(stderr, "Non-pointer BPP\n"); + BP = BPP; + } + } + } + } + /// Generate the base pointers, section pointers, sizes, map type bits, and /// user-defined mappers (all included in \a CombinedInfo) for the provided /// map type, map or motion modifiers, and expression components. @@ -7193,12 +7810,12 @@ class MappableExprsHandler { OpenMPMapClauseKind MapType, ArrayRef<OpenMPMapModifierKind> MapModifiers, ArrayRef<OpenMPMotionModifierKind> MotionModifiers, OMPClauseMappableExprCommon::MappableExprComponentListRef Components, - MapCombinedInfoTy &CombinedInfo, StructRangeInfoTy &PartialStruct, + MapCombinedInfoTy &CombinedInfo, PartialStructMap &PartialStructs, bool IsFirstComponentList, bool IsImplicit, const ValueDecl *Mapper = nullptr, bool ForDeviceAddr = false, const ValueDecl *BaseDecl = nullptr, const Expr *MapExpr = nullptr, - ArrayRef<OMPClauseMappableExprCommon::MappableExprComponentListRef> - OverlappedElements = {}, + /*ArrayRef<OMPClauseMappableExprCommon::MappableExprComponentListRef> + OverlappedElements = {},*/ bool AreBothBasePtrAndPteeMapped = false) const { // The following summarizes what has to be generated for each map and the // types below. The generated information is expressed in this order: @@ -7388,8 +8005,8 @@ class MappableExprsHandler { bool RequiresReference = false; // Scan the components from the base to the complete expression. - auto CI = Components.rbegin(); - auto CE = Components.rend(); + auto CI = ComponentListRefPtrPteeIterator(Components.rbegin()); + auto CE = ComponentListRefPtrPteeIterator(Components.rend()); auto I = CI; // Track if the map information being generated is the first for a list of @@ -7402,22 +8019,35 @@ class MappableExprsHandler { const auto *OASE = dyn_cast<ArraySectionExpr>(AssocExpr); const auto *OAShE = dyn_cast<OMPArrayShapingExpr>(AssocExpr); + fprintf(stderr, "generateInfoForComponentList\n"); + //fprintf(stderr, "Preliminary data length: %d\n", + // (int) PartialStruct.PreliminaryMapData.Exprs.size()); + fprintf(stderr, "Combined info length: %d\n", + (int) CombinedInfo.Exprs.size()); + + /* fprintf(stderr, "last component list entry:\n"); + std::prev(CE)->getAssociatedExpression()->dumpPretty(CGF.getContext()); + fprintf(stderr, "\n");*/ + if (AreBothBasePtrAndPteeMapped && std::next(I) == CE) return; if (isa<MemberExpr>(AssocExpr)) { // The base is the 'this' pointer. The content of the pointer is going // to be the base of the field being mapped. BP = CGF.LoadCXXThisAddress(); + assert(false && "unreachable 1"); } else if ((AE && isa<CXXThisExpr>(AE->getBase()->IgnoreParenImpCasts())) || (OASE && isa<CXXThisExpr>(OASE->getBase()->IgnoreParenImpCasts()))) { BP = CGF.EmitOMPSharedLValue(AssocExpr).getAddress(); + assert(false && "unreachable 2"); } else if (OAShE && isa<CXXThisExpr>(OAShE->getBase()->IgnoreParenCasts())) { BP = Address( CGF.EmitScalarExpr(OAShE->getBase()), CGF.ConvertTypeForMem(OAShE->getBase()->getType()->getPointeeType()), CGF.getContext().getTypeAlignInChars(OAShE->getBase()->getType())); + assert(false && "unreachable 3"); } else { // The base is the reference to the variable. // BP = &Var. @@ -7488,8 +8118,8 @@ class MappableExprsHandler { bool IsNonContiguous = CombinedInfo.NonContigInfo.IsNonContiguous; bool IsPrevMemberReference = false; - bool IsPartialMapped = - !PartialStruct.PreliminaryMapData.BasePointers.empty(); + //bool IsPartialMapped = + // !PartialStruct.PreliminaryMapData.BasePointers.empty(); for (; I != CE; ++I) { // If the current component is member of a struct (parent struct) mark it. @@ -7623,54 +8253,7 @@ class MappableExprsHandler { (IsPrevMemberReference && !IsPointer) || (IsMemberReference && Next != CE && !Next->getAssociatedExpression()->getType()->isPointerType())); - if (!OverlappedElements.empty() && Next == CE) { - // Handle base element with the info for overlapped elements. - assert(!PartialStruct.Base.isValid() && "The base element is set."); - assert(!IsPointer && - "Unexpected base element with the pointer type."); - // Mark the whole struct as the struct that requires allocation on the - // device. - PartialStruct.LowestElem = {0, LowestElem}; - CharUnits TypeSize = CGF.getContext().getTypeSizeInChars( - I->getAssociatedExpression()->getType()); - Address HB = CGF.Builder.CreateConstGEP( - CGF.Builder.CreatePointerBitCastOrAddrSpaceCast( - LowestElem, CGF.VoidPtrTy, CGF.Int8Ty), - TypeSize.getQuantity() - 1); - PartialStruct.HighestElem = { - std::numeric_limits<decltype( - PartialStruct.HighestElem.first)>::max(), - HB}; - PartialStruct.Base = BP; - PartialStruct.LB = LB; - assert( - PartialStruct.PreliminaryMapData.BasePointers.empty() && - "Overlapped elements must be used only once for the variable."); - std::swap(PartialStruct.PreliminaryMapData, CombinedInfo); - // Emit data for non-overlapped data. - OpenMPOffloadMappingFlags Flags = - OpenMPOffloadMappingFlags::OMP_MAP_MEMBER_OF | - getMapTypeBits(MapType, MapModifiers, MotionModifiers, IsImplicit, - /*AddPtrFlag=*/false, - /*AddIsTargetParamFlag=*/false, IsNonContiguous); - CopyOverlappedEntryGaps CopyGaps(CGF, CombinedInfo, Flags, MapDecl, - MapExpr, BP, LB, IsNonContiguous, - DimSize); - // Do bitcopy of all non-overlapped structure elements. - for (OMPClauseMappableExprCommon::MappableExprComponentListRef - Component : OverlappedElements) { - for (const OMPClauseMappableExprCommon::MappableComponent &MC : - Component) { - if (const ValueDecl *VD = MC.getAssociatedDeclaration()) { - if (const auto *FD = dyn_cast<FieldDecl>(VD)) { - CopyGaps.processField(MC, FD, EmitMemberExprBase); - } - } - } - } - CopyGaps.copyUntilEnd(HB); - break; - } + llvm::Value *Size = getExprTypeSize(I->getAssociatedExpression()); // Skip adding an entry in the CurInfo of this combined entry if the // whole struct is currently being mapped. The struct needs to be added @@ -7678,7 +8261,7 @@ class MappableExprsHandler { // mapped. // Skip adding an entry in the CurInfo of this combined entry if the // PartialStruct.PreliminaryMapData.BasePointers has been mapped. - if ((!IsMemberPointerOrAddr && !IsPartialMapped) || + if ((!IsMemberPointerOrAddr /*&& !IsPartialMapped*/) || (Next == CE && MapType != OMPC_MAP_unknown)) { CombinedInfo.Exprs.emplace_back(MapDecl, MapExpr); CombinedInfo.BasePointers.push_back(BP.emitRawPointer(CGF)); @@ -7728,6 +8311,7 @@ class MappableExprsHandler { CombinedInfo.Types.push_back(Flags); } +#if 0 // If we have encountered a member expression so far, keep track of the // mapped member. If the parent is "*this", then the value declaration // is nullptr. @@ -7761,10 +8345,11 @@ class MappableExprsHandler { } } } +#endif // Need to emit combined struct for array sections. - if (IsFinalArraySection || IsNonContiguous) - PartialStruct.IsArraySection = true; + //if (IsFinalArraySection || IsNonContiguous) + // PartialStruct.IsArraySection = true; // If we have a final array section, we are done with this expression. if (IsFinalArraySection) @@ -7773,7 +8358,7 @@ class MappableExprsHandler { // The pointer becomes the base for the next element. if (Next != CE) BP = IsMemberReference ? LowestElem : LB; - if (!IsPartialMapped) + if (true /*!IsPartialMapped*/) IsExpressionFirstInfo = false; IsCaptureFirstInfo = false; FirstPointerInComplexData = false; @@ -7789,8 +8374,8 @@ class MappableExprsHandler { } // If ran into the whole component - allocate the space for the whole // record. - if (!EncounteredME) - PartialStruct.HasCompleteRecord = true; + //if (!EncounteredME) + // PartialStruct.HasCompleteRecord = true; if (!IsNonContiguous) return; @@ -8065,6 +8650,93 @@ class MappableExprsHandler { } } + void getFieldOffsets(const CXXRecordDecl *RD, + llvm::DenseMap<const FieldDecl *, uint64_t> &Layout, + llvm::SmallPtrSetImpl<const CXXRecordDecl *> &Processed, + uint64_t ParentOffset, + bool AsBase) const { + const CGRecordLayout &RL = CGF.getTypes().getCGRecordLayout(RD); + + fprintf(stderr, "Getting field offsets for decl:\n"); + RD->dump(); + + llvm::StructType *St = + AsBase ? RL.getBaseSubobjectLLVMType() : RL.getLLVMType(); + auto &DL = CGF.CGM.getDataLayout(); + const llvm::StructLayout *SL = + DL.getStructLayout(St); + + Processed.insert(RD); + + unsigned NumElements = St->getNumElements(); + llvm::SmallVector< + llvm::PointerUnion<const CXXRecordDecl *, const FieldDecl *>, 4> + RecordLayout(NumElements * 2); + + // Fill bases. + for (const auto &I : RD->bases()) { + if (I.isVirtual()) + continue; + + QualType BaseTy = I.getType(); + const auto *Base = BaseTy->getAsCXXRecordDecl(); + // Ignore empty bases. + if (isEmptyRecordForLayout(CGF.getContext(), BaseTy) || + CGF.getContext() + .getASTRecordLayout(Base) + .getNonVirtualSize() + .isZero()) + continue; + + unsigned FieldIndex = RL.getNonVirtualBaseLLVMFieldNo(Base); + RecordLayout[FieldIndex] = Base; + } + assert(RD->vbases().empty() && "FIXME, virtual bases"); + // Fill in all the fields. + assert(!RD->isUnion() && "Unexpected union."); + for (const auto *Field : RD->fields()) { + // Fill in non-bitfields. (Bitfields always use a zero pattern, which we + // will fill in later.) + if (!Field->isBitField() && + !isEmptyFieldForLayout(CGF.getContext(), Field)) { + unsigned FieldIndex = RL.getLLVMFieldNo(Field); + RecordLayout[FieldIndex] = Field; + if (Field->getType().getCanonicalType().getTypePtr()->isRecordType()) { + const CXXRecordDecl *RD2 = Field->getType().getCanonicalType().getTypePtr()->getAsCXXRecordDecl(); + if (!Processed.contains(RD2)) { + llvm::TypeSize Offset = SL->getElementOffset(FieldIndex); + getFieldOffsets(RD2, Layout, Processed, ParentOffset + Offset, /*AsBase=*/true); + } + } + } + } + for (const llvm::PointerUnion<const CXXRecordDecl *, const FieldDecl *> + &Data : RecordLayout) { + if (Data.isNull()) + continue; + if (const auto *Base = dyn_cast<const CXXRecordDecl *>(Data)) { + if (RL.hasNonVirtualBaseLLVMField(Base)) { + unsigned FieldNo = RL.getNonVirtualBaseLLVMFieldNo(Base); + llvm::TypeSize Offset = SL->getElementOffset(FieldNo); + getFieldOffsets(Base, Layout, Processed, Offset, /*AsBase=*/true); + } else { + assert(false && "Unhandled virtual base"); + } + } else { + const auto *FD = cast<const FieldDecl *>(Data); + //const auto *RD = FD->getParent(); + unsigned FieldNo = RL.getLLVMFieldNo(FD); + llvm::TypeSize FieldOffset = SL->getElementOffset(FieldNo); + if (Layout.find(FD) == Layout.end()) { + Layout[FD] = ParentOffset + FieldOffset; + } else { + fprintf(stderr, "FD already in layout?\n"); + } + } + } + fprintf(stderr, "Returning...\n"); + } + /// 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 @@ -8083,6 +8755,8 @@ class MappableExprsHandler { SmallVector<SmallVector<MapInfo, 8>, 4>> Info; + fprintf(stderr, "generateAllInfoForClauses\n"); + // Helper function to fill the information map for the different supported // clauses. auto &&InfoGen = @@ -8316,7 +8990,7 @@ class MappableExprsHandler { } for (const auto &Data : Info) { - StructRangeInfoTy PartialStruct; + PartialStructMap PartialStructs; // Temporary generated information. MapCombinedInfoTy CurInfo; const Decl *D = Data.first; @@ -8345,12 +9019,12 @@ class MappableExprsHandler { unsigned CurrentBasePointersIdx = CurInfo.BasePointers.size(); CurInfo.NonContigInfo.IsNonContiguous = L.Components.back().isNonContiguous(); + fprintf(stderr, "*** From generateAllInfoForClauses...\n"); generateInfoForComponentList( L.MapType, L.MapModifiers, L.MotionModifiers, L.Components, - CurInfo, PartialStruct, /*IsFirstComponentList=*/false, - L.IsImplicit, /*GenerateAllInfoForClauses*/ true, L.Mapper, - L.ForDeviceAddr, VD, L.VarRef, /*OverlappedElements*/ {}, - HasMapBasePtr && HasMapArraySec); + CurInfo, PartialStructs, /*IsFirstComponentList=*/false, + L.IsImplicit, L.Mapper, L.ForDeviceAddr, VD, L.VarRef, + /*OverlappedElements {},*/ HasMapBasePtr && HasMapArraySec); // If this entry relates with a device pointer, set the relevant // declaration and add the 'return pointer' flag. @@ -8415,12 +9089,12 @@ class MappableExprsHandler { } } // If there is an entry in PartialStruct it means we have a struct with - // individual members mapped. Emit an extra combined entry. - if (PartialStruct.Base.isValid()) { - CurInfo.NonContigInfo.Dims.push_back(0); - emitCombinedEntry(CombinedInfo, CurInfo.Types, PartialStruct, - /*IsMapThis*/ !VD, OMPBuilder, VD); - } + // individual members mapped. Emit an extra combined entry. FIXME. + //if (PartialStruct.Base.isValid()) { + // CurInfo.NonContigInfo.Dims.push_back(0); + // emitCombinedEntry(CombinedInfo, CurInfo.Types, PartialStruct, + // /*IsMapThis*/ !VD, OMPBuilder, VD); + // } // We need to append the results of this capture to what we already // have. @@ -8489,7 +9163,8 @@ class MappableExprsHandler { llvm::OpenMPIRBuilder &OMPBuilder, const ValueDecl *VD = nullptr, unsigned OffsetForMemberOfFlag = 0, - bool NotTargetParams = true) const { + OpenMPOffloadMappingFlags Flags = OpenMPOffloadMappingFlags::OMP_MAP_NONE) const { + fprintf(stderr, "emitCombinedEntry\n"); if (CurTypes.size() == 1 && ((CurTypes.back() & OpenMPOffloadMappingFlags::OMP_MAP_MEMBER_OF) != OpenMPOffloadMappingFlags::OMP_MAP_MEMBER_OF) && @@ -8497,13 +9172,16 @@ class MappableExprsHandler { return; Address LBAddr = PartialStruct.LowestElem.second; Address HBAddr = PartialStruct.HighestElem.second; - if (PartialStruct.HasCompleteRecord) { + if (PartialStruct.ContainingStructMap) { LBAddr = PartialStruct.LB; HBAddr = PartialStruct.LB; } CombinedInfo.Exprs.push_back(VD); // Base is the base of the struct - CombinedInfo.BasePointers.push_back(PartialStruct.Base.emitRawPointer(CGF)); + if (Flags == OpenMPOffloadMappingFlags::OMP_MAP_PTR_AND_OBJ) + CombinedInfo.BasePointers.push_back(PartialStruct.BaseAddr.emitRawPointer(CGF)); + else + CombinedInfo.BasePointers.push_back(PartialStruct.Base.emitRawPointer(CGF)); CombinedInfo.DevicePtrDecls.push_back(nullptr); CombinedInfo.DevicePointers.push_back(DeviceInfoTy::None); // Pointer is the address of the lowest element @@ -8542,11 +9220,11 @@ class MappableExprsHandler { } CombinedInfo.Mappers.push_back(nullptr); // Map type is always TARGET_PARAM, if generate info for captures. - CombinedInfo.Types.push_back( - NotTargetParams ? OpenMPOffloadMappingFlags::OMP_MAP_NONE - : !PartialStruct.PreliminaryMapData.BasePointers.empty() - ? OpenMPOffloadMappingFlags::OMP_MAP_PTR_AND_OBJ - : OpenMPOffloadMappingFlags::OMP_MAP_TARGET_PARAM); + CombinedInfo.Types.push_back(Flags); + //NotTargetParams ? OpenMPOffloadMappingFlags::OMP_MAP_NONE + //: /*!PartialStruct.PreliminaryMapData.BasePointers.empty() + // ? OpenMPOffloadMappingFlags::OMP_MAP_PTR_AND_OBJ + // :*/ OpenMPOffloadMappingFlags::OMP_MAP_TARGET_PARAM); // If any element has the present modifier, then make sure the runtime // doesn't attempt to allocate the struct. if (CurTypes.end() != @@ -8591,6 +9269,7 @@ class MappableExprsHandler { MapCombinedInfoTy &CombinedInfo, llvm::OpenMPIRBuilder &OMPBuilder, const llvm::DenseSet<CanonicalDeclPtr<const Decl>> &SkipVarSet = llvm::DenseSet<CanonicalDeclPtr<const Decl>>()) const { + fprintf(stderr, "generateAllInfo\n"); assert(isa<const OMPExecutableDirective *>(CurDir) && "Expect a executable directive"); const auto *CurExecDir = cast<const OMPExecutableDirective *>(CurDir); @@ -8725,7 +9404,8 @@ class MappableExprsHandler { /// \a CurCaptureVarInfo). void generateInfoForCaptureFromClauseInfo( const CapturedStmt::Capture *Cap, llvm::Value *Arg, - MapCombinedInfoTy &CurCaptureVarInfo, llvm::OpenMPIRBuilder &OMPBuilder, + MapCombinedInfoTy &CurCaptureVarInfo, PartialStructMap &PartialStructs, + llvm::OpenMPIRBuilder &OMPBuilder, unsigned OffsetForMemberOfFlag) const { assert(!Cap->capturesVariableArrayType() && "Not expecting to generate map info for a variable array type!"); @@ -8740,6 +9420,8 @@ class MappableExprsHandler { if (LambdasMap.count(VD)) return; + fprintf(stderr, "generateInfoForCapture\n"); + // If this declaration appears in a is_device_ptr clause we just have to // pass the pointer by value. If it is a reference to a declaration, we just // pass its value. @@ -8821,27 +9503,26 @@ class MappableExprsHandler { [&](ArrayRef<MapData> DeclComponentLists, bool IsEligibleForTargetParamFlag) { MapCombinedInfoTy CurInfoForComponentLists; - StructRangeInfoTy PartialStruct; if (DeclComponentLists.empty()) return; generateInfoForCaptureFromComponentLists( - VD, DeclComponentLists, CurInfoForComponentLists, PartialStruct, + OMPBuilder, VD, DeclComponentLists, CurInfoForComponentLists, PartialStructs, IsEligibleForTargetParamFlag, /*AreBothBasePtrAndPteeMapped=*/HasMapBasePtr && HasMapArraySec); // If there is an entry in PartialStruct it means we have a // struct with individual members mapped. Emit an extra combined // entry. - if (PartialStruct.Base.isValid()) { - CurCaptureVarInfo.append(PartialStruct.PreliminaryMapData); - emitCombinedEntry( - CurCaptureVarInfo, CurInfoForComponentLists.Types, - PartialStruct, Cap->capturesThis(), OMPBuilder, nullptr, - OffsetForMemberOfFlag, - /*NotTargetParams*/ !IsEligibleForTargetParamFlag); - } + //if (PartialStruct.Base.isValid()) { + // CurCaptureVarInfo.append(PartialStruct.PreliminaryMapData); + // emitCombinedEntry( + // CurCaptureVarInfo, CurInfoForComponentLists.Types, + // PartialStruct, Cap->capturesThis(), OMPBuilder, nullptr, + // OffsetForMemberOfFlag, + // /*NotTargetParams*/ !IsEligibleForTargetParamFlag); + // } // Return if we didn't add any entries. if (CurInfoForComponentLists.BasePointers.empty()) @@ -8858,10 +9539,11 @@ class MappableExprsHandler { /// mappers associated to \a DeclComponentLists for a given capture /// \a VD (all included in \a CurComponentListInfo). void generateInfoForCaptureFromComponentLists( - const ValueDecl *VD, ArrayRef<MapData> DeclComponentLists, - MapCombinedInfoTy &CurComponentListInfo, StructRangeInfoTy &PartialStruct, + llvm::OpenMPIRBuilder &OMPBuilder, const ValueDecl *VD, ArrayRef<MapData> DeclComponentLists, + MapCombinedInfoTy &CurComponentListInfo, PartialStructMap &PartialStructs, bool IsListEligibleForTargetParamFlag, bool AreBothBasePtrAndPteeMapped = false) const { +#if 0 // Find overlapping elements (including the offset from the base element). llvm::SmallDenseMap< const MapData *, @@ -8982,11 +9664,421 @@ class MappableExprsHandler { return *It == FD1; }); } + #endif + + fprintf(stderr, "Gather structs, pass 1\n"); + + // Pass 1: Gather data about structs (effective bases, low-high ranges) + for (const MapData &L : DeclComponentLists) { + OMPClauseMappableExprCommon::MappableExprComponentListRef Components; + OpenMPMapClauseKind MapType; + ArrayRef<OpenMPMapModifierKind> MapModifiers; + bool IsImplicit; + const ValueDecl *Mapper; + const Expr *MapExpr; + std::tie(Components, MapType, MapModifiers, IsImplicit, Mapper, MapExpr) = + L; + gatherStructDataForComponentList(L, MapType, MapModifiers, Components, + CurComponentListInfo, PartialStructs, + IsImplicit, Mapper, VD, MapExpr); + } + fprintf(stderr, "Gather structs, pass 2\n"); + + llvm::SmallPtrSet<const MapData *, 8> ProcessedMappings; + + // Pass 2: Find whole-struct mappings which overlap with member accesses. + // This only handles fairly simple cases, and will fail for things like: + // map(tofrom: arr[5]) map(tofrom: arr[5].x) + // That could probably be improved a bit. + for (const MapData &L : DeclComponentLists) { + OMPClauseMappableExprCommon::MappableExprComponentListRef Components; + OpenMPMapClauseKind MapType; + ArrayRef<OpenMPMapModifierKind> MapModifiers; + bool IsImplicit; + const ValueDecl *Mapper; + const Expr *MapExpr; + std::tie(Components, MapType, MapModifiers, IsImplicit, Mapper, MapExpr) = + L; + const Expr *MapExprOrig = MapExpr; + if (const auto *UO = dyn_cast<UnaryOperator>(MapExpr)) { + if (UO->getOpcode() == UO_Deref) { + MapExpr = UO->getSubExpr()->IgnoreParenImpCasts(); + } + } else if (const auto *ASE = dyn_cast<ArraySubscriptExpr>(MapExpr)) { + const Expr *ArrayBase = ASE->getBase()->IgnoreParenImpCasts(); + const Expr *Index = ASE->getIdx(); + Expr::EvalResult Result; + if (Index->EvaluateAsInt(Result, CGF.getContext())) { + llvm::APSInt ConstIndex = Result.Val.getInt(); + if (ConstIndex == 0) { + MapExpr = ArrayBase; + } + } + } else if (const auto *ASecE = dyn_cast<ArraySectionExpr>(MapExpr)) { + const Expr *ArrayBase = ASecE->getBase()->IgnoreParenImpCasts(); + // In general, we can't tell if we're mapping the whole struct here, + // so this is somewhat best-effort. + // Maybe this should be a compile-time warning, or we should arrange + // so the runtime does the right thing regardless (e.g. with + // potentially redundant mappings). + bool CheckLength = false; + if (!ASecE->getLowerBound()) + CheckLength = true; + else { + const Expr *Lower = ASecE->getLowerBound(); + Expr::EvalResult Result; + if (Lower->EvaluateAsInt(Result, CGF.getContext())) { + llvm::APSInt ConstLow = Result.Val.getInt(); + if (ConstLow == 0) { + CheckLength = true; + } + } + } + if (CheckLength) { + if (ArrayBase->getType()->isArrayType() && + !ASecE->getLength()) { + MapExpr = ArrayBase; + } else if (ASecE->getLength()) { + const Expr *Upper = ASecE->getLength(); + Expr::EvalResult Result; + if (Upper->EvaluateAsInt(Result, CGF.getContext())) { + llvm::APSInt ConstLength = Result.Val.getInt(); + if (ConstLength != 0) { + MapExpr = ArrayBase; + } + } + } + } + } + if (MapExpr == MapExprOrig && MapExpr->getType()->isPointerType()) { + // It's just a base pointer, ignore it here. + continue; + } + bool Indirect = MapExpr->getType()->isPointerType(); + // The only things used as keys in PartialStructs are known to be used + // as the base expressions of MemberExprs, so this is safer than it looks. + EffectiveBaseMapKey EBKey(CGF.getContext(), MapExpr, Indirect); + if (PartialStructs.find(EBKey) != PartialStructs.end()) { + StructRangeInfoTy *PartialStruct = &PartialStructs[EBKey]; + fprintf(stderr, "Mapped whole of struct, marking: "); + MapExprOrig->dumpPretty(CGF.getContext()); + fprintf(stderr, "\n"); + PartialStruct->ContainingStructMap = &L; + QualType Ty = PartialStruct->BaseExpr->getType().getCanonicalType(); + fprintf(stderr, "BaseExpr Type:\n"); + Ty.dump(); + //if (PartialStruct->MemberDepth > 1) { + // PartialStruct->LB = + // CGF.EmitLoadOfPointer(PartialStruct->Base, Ty->castAs<PointerType>()); + //} else { + // The first one is indirected already. + PartialStruct->LB = CGF.EmitLoadOfPointer(PartialStruct->BaseAddr, Ty->castAs<PointerType>()); + ProcessedMappings.insert(&L); + //} else { + // } + } + } + + fprintf(stderr, "Sorting partial structs, pass 3:\n"); + for (auto &PS : PartialStructs) { + auto &PartialStruct = PS.getSecond(); + + llvm::DenseMap<const FieldDecl *, uint64_t> Layout; + + const Type *BaseType = PartialStruct.BaseExpr->getType().getCanonicalType().getTypePtr(); + const Type *OrigType = BaseType->getPointeeOrArrayElementType(); + + while (BaseType != OrigType) { + BaseType = OrigType->getCanonicalTypeInternal().getTypePtr(); + OrigType = BaseType->getPointeeOrArrayElementType(); + } + + if (const auto *CRD = BaseType->getAsCXXRecordDecl()) { + llvm::SmallPtrSet<const CXXRecordDecl *, 4> Processed; + getFieldOffsets(CRD, Layout, Processed, 0, /*AsBase=*/false); + } else { + assert(false && "Not CXX record decl"); + } + + llvm::stable_sort(PartialStruct.ChildComponents, + [this, &Layout](auto &a, auto &b) { + OMPClauseMappableExprCommon::MappableExprComponentListRef First = a.second.Components; + OMPClauseMappableExprCommon::MappableExprComponentListRef Second = b.second.Components; + + auto CI = First.begin(); + auto CE = First.end(); + auto SI = Second.begin(); + auto SE = Second.end(); + + // We may have a member expression, or an ArraySectionExpr. Find the + // outermost member expression. + while (CI != CE) { + if (isa<MemberExpr>(CI->getAssociatedExpression())) + break; + else + ++CI; + } + + if (CI == CE) + return false; + + while (SI != SE) { + if (isa<MemberExpr>(SI->getAssociatedExpression())) + break; + else + ++SI; + } + + if (SI == SE) + return false; + + fprintf(stderr, "Compare CI expr: "); + CI->getAssociatedExpression()->dumpPretty(CGF.getContext()); + fprintf(stderr, "\nwith SI expr: "); + SI->getAssociatedExpression()->dumpPretty(CGF.getContext()); + fprintf(stderr, "\n"); + + const auto *FD1 = cast<FieldDecl>(CI->getAssociatedDeclaration()); + const auto *FD2 = cast<FieldDecl>(SI->getAssociatedDeclaration()); + + /*while (auto *ME = dyn_cast<MemberExpr>(CI->getAssociatedExpression())) { + if (ME->isArrow()) + break; + auto *Next = std::next(CI); + if (Next == CE) + break; + if (isa<MemberExpr>(Next->getAssociatedExpression())) + ++CI; + else + break; + } + + while (auto *ME = dyn_cast<MemberExpr>(SI->getAssociatedExpression())) { + if (ME->isArrow()) + break; + auto *Next = std::next(SI); + if (Next == SE) + break; + if (isa<MemberExpr>(Next->getAssociatedExpression())) + ++SI; + else + break; + } + + const RecordDecl *RD = FD1->getParent(); + const RecordDecl *RD2 = FD2->getParent(); + + assert(RD == RD2 && "expected the same record decl"); + + const ASTRecordLayout &RL = CGF.getContext().getASTRecordLayout(RD);*/ + uint64_t FieldOffset1 = Layout[FD1]; + uint64_t FieldOffset2 = Layout[FD2]; + + fprintf(stderr, "Field offset 1: %llu\n", (unsigned long long) FieldOffset1); + fprintf(stderr, "Field offset 2: %llu\n", (unsigned long long) FieldOffset2); + + return FieldOffset2 > FieldOffset1; + }); + } + + // FIXME + bool IsNonContiguous = false; + int DimSize = 1; + + std::vector<EffectiveBaseMapKey> StructOrder; + + for (auto &PS : PartialStructs) { + StructOrder.push_back(PS.getFirst()); + } + + llvm::stable_sort(StructOrder, [&PartialStructs](auto First, auto Second) { + auto FirstInfo = PartialStructs[First]; + auto SecondInfo = PartialStructs[Second]; + return FirstInfo.MemberDepth < SecondInfo.MemberDepth; + }); + + auto &&EmitMemberExprBase = [](CodeGenFunction &CGF, + const MemberExpr *E) { + const Expr *BaseExpr = E->getBase(); + // If this is s.x, emit s as an lvalue. If it is s->x, emit s as a + // scalar. + LValue BaseLV; + if (E->isArrow()) { + LValueBaseInfo BaseInfo; + TBAAAccessInfo TBAAInfo; + Address Addr = + CGF.EmitPointerWithAlignment(BaseExpr, &BaseInfo, &TBAAInfo); + QualType PtrTy = BaseExpr->getType()->getPointeeType(); + BaseLV = CGF.MakeAddrLValue(Addr, PtrTy, BaseInfo, TBAAInfo); + } else { + BaseLV = CGF.EmitOMPSharedLValue(BaseExpr); + } + return BaseLV; + }; + + bool ParamFlag = true; + + fprintf(stderr, "Emit partial struct nodes, pass 4:\n"); + for (auto &Ord : StructOrder) { + auto &PartialStruct = PartialStructs[Ord]; + MapCombinedInfoTy CombinedInfo; + + fprintf(stderr, "A partial struct (depth %d):\n", PartialStruct.MemberDepth); + if (PartialStruct.Base.isValid()) { + llvm::dbgs() << "Base expr: "; + PartialStruct.BaseExpr->dumpPretty(CGF.getContext()); + fprintf(stderr, "\n"); + llvm::dbgs() << "Name: " << PartialStruct.Base.getName() << "\n"; + llvm::dbgs() << "Is valid: " << (PartialStruct.Base.isValid() ? "true" : "false") << "\n"; + } else { + llvm::dbgs() << "(no base set)\n"; + } + llvm::dbgs() << "Lo elem: " << PartialStruct.LowestElem.first << "\n"; + llvm::dbgs() << "Hi elem: " << PartialStruct.HighestElem.first << "\n"; + //CombinedInfo.append(PartialStruct.PreliminaryMapData); + fprintf(stderr, "Child components:\n"); + for (auto &CC : PartialStruct.ChildComponents) { + auto Comp = CC.second.Components; + Comp[0].getAssociatedExpression()->dumpPretty(CGF.getContext()); + fprintf(stderr, "\n"); + } + fprintf(stderr, "Map whole struct: %s\n", PartialStruct.ContainingStructMap ? "yes" : "no"); + + if (PartialStruct.ContainingStructMap) { + OMPClauseMappableExprCommon::MappableExprComponentListRef Components; + OpenMPMapClauseKind MapType; + ArrayRef<OpenMPMapModifierKind> MapModifiers; + bool IsImplicit; + const ValueDecl *Mapper; + const Expr *MapExpr; + std::tie(Components, MapType, MapModifiers, IsImplicit, Mapper, MapExpr) = + *PartialStruct.ContainingStructMap; + const Type *BaseType = PartialStruct.BaseExpr->getType().getCanonicalType().getTypePtr(); + const Type *OrigType = BaseType->getPointeeOrArrayElementType(); + + while (BaseType != OrigType) { + BaseType = OrigType->getCanonicalTypeInternal().getTypePtr(); + OrigType = BaseType->getPointeeOrArrayElementType(); + } + + fprintf(stderr, "Base expr type:\n"); + BaseType->dump(); + + CharUnits TypeSize = CGF.getContext().getTypeSizeInChars(BaseType); + Address HB = CGF.Builder.CreateConstGEP( + CGF.Builder.CreatePointerBitCastOrAddrSpaceCast( + PartialStruct.Base, CGF.VoidPtrTy, CGF.Int8Ty), + TypeSize.getQuantity() - 1); + PartialStruct.HighestElem = { + std::numeric_limits<decltype( + PartialStruct.HighestElem.first)>::max(), + HB}; + OpenMPOffloadMappingFlags Flags = + OpenMPOffloadMappingFlags::OMP_MAP_MEMBER_OF | + getMapTypeBits(MapType, MapModifiers, {}, IsImplicit, + /*AddPtrFlag=*/false, + /*AddIsTargetParamFlag=*/false, IsNonContiguous); + fprintf(stderr, "Starting CopyGaps...\n"); + CopyOverlappedEntryGaps CopyGaps(CGF, CombinedInfo, Flags, nullptr, + PartialStruct.BaseExpr, PartialStruct.Base, + PartialStruct.LB, IsNonContiguous, DimSize); + + llvm::DenseMap<const FieldDecl *, uint64_t> Layout; + + if (const auto *CRD = BaseType->getAsCXXRecordDecl()) { + llvm::SmallPtrSet<const CXXRecordDecl *, 4> Processed; + getFieldOffsets(CRD, Layout, Processed, 0, /*AsBase=*/false); + } else { + assert(false && "Not CXX record decl"); + } + + for (auto &CC : PartialStruct.ChildComponents) { + const OMPClauseMappableExprCommon::MappableComponent &MC = CC.second.Components.front(); + if (const ValueDecl *VD = MC.getAssociatedDeclaration()) { + if (const auto *FD = dyn_cast<FieldDecl>(VD)) { + CopyGaps.processField(MC, Layout, FD, EmitMemberExprBase); + } + } + } + CopyGaps.copyUntilEnd(HB, TypeSize); + } + + for (auto &CC : PartialStruct.ChildComponents) { + MappableExprMetadata Metadata = CC.second; + auto Field = Metadata.Components.front().getAssociatedExpression(); + // Address Ptr = CGF.EmitOMPSharedLValue(Field).getAddress(); + llvm::Value *Size = getExprTypeSize(Field); + + fprintf(stderr, "Emitting expr: "); + Field->dumpPretty(CGF.getContext()); + fprintf(stderr, "\n"); + + if (Metadata.CompleteExpression || PartialStruct.ContainingStructMap) { + OMPClauseMappableExprCommon::MappableExprComponentListRef Components; + OpenMPMapClauseKind MapType; + ArrayRef<OpenMPMapModifierKind> MapModifiers; + bool IsImplicit; + const ValueDecl *Mapper; + const Expr *MapExpr; + //if (PartialStruct.ContainingStructMap) { + // std::tie(Components, MapType, MapModifiers, IsImplicit, Mapper, MapExpr) = + // *PartialStruct.ContainingStructMap; + //} else { + std::tie(Components, MapType, MapModifiers, IsImplicit, Mapper, MapExpr) = + *Metadata.MD; + //} + + CombinedInfo.Exprs.push_back(nullptr); + CombinedInfo.BasePointers.push_back(Metadata.Base.emitRawPointer(CGF)); + CombinedInfo.DevicePtrDecls.push_back(nullptr); + CombinedInfo.DevicePointers.push_back(DeviceInfoTy::None); + CombinedInfo.Pointers.push_back(Metadata.Pointer.emitRawPointer(CGF)); + CombinedInfo.Sizes.push_back(CGF.Builder.CreateIntCast( + Size, CGF.Int64Ty, /*isSigned=*/true)); + CombinedInfo.NonContigInfo.Dims.push_back(IsNonContiguous ? DimSize : 1); + CombinedInfo.Mappers.push_back(nullptr); + + bool PointerAndObj = false; + if (isa<ArraySectionExpr>(Field) || + isa<ArraySubscriptExpr>(Field) || + isa<OMPArrayShapingExpr>(Field) || + isa<UnaryOperator>(Field)) + PointerAndObj = true; + + OpenMPOffloadMappingFlags Flags = + getMapTypeBits(MapType, MapModifiers, {}, IsImplicit, PointerAndObj, false, IsNonContiguous); + Flags |= OpenMPOffloadMappingFlags::OMP_MAP_MEMBER_OF; + + CombinedInfo.Types.push_back(Flags); + + fprintf(stderr, "Marking %p as processed\n", (void*) Metadata.MD); + ProcessedMappings.insert(Metadata.MD); + } + } + + if (ParamFlag || !PartialStruct.ContainingStructMap) { + OpenMPOffloadMappingFlags Flags = ParamFlag ? OpenMPOffloadMappingFlags::OMP_MAP_TARGET_PARAM + : OpenMPOffloadMappingFlags::OMP_MAP_PTR_AND_OBJ; + emitCombinedEntry(CurComponentListInfo, CombinedInfo.Types, PartialStruct, + false, OMPBuilder, VD, 0, Flags); + } else { + OpenMPOffloadMappingFlags MemberOfFlag = OMPBuilder.getMemberOfFlag( + CurComponentListInfo.BasePointers.size() - 1); + for (auto &M : CombinedInfo.Types) + OMPBuilder.setCorrectMemberOfFlag(M, MemberOfFlag); + } + + CurComponentListInfo.append(CombinedInfo); + ParamFlag = false; + } + fprintf(stderr, "That's all\n"); + + #if 0 // Associated with a capture, because the mapping flags depend on it. // Go through all of the elements with the overlapped elements. bool AddTargetParamFlag = IsListEligibleForTargetParamFlag; - MapCombinedInfoTy StructBaseCombinedInfo; + //MapCombinedInfoTy StructBaseCombinedInfo; for (const auto &Pair : OverlappedData) { const MapData &L = *Pair.getFirst(); OMPClauseMappableExprCommon::MappableExprComponentListRef Components; @@ -8999,15 +10091,26 @@ class MappableExprsHandler { L; ArrayRef<OMPClauseMappableExprCommon::MappableExprComponentListRef> OverlappedComponents = Pair.getSecond(); + fprintf(stderr, "*** From generateInfoForCaptureFromComponentLists (overlapped)...\n"); generateInfoForComponentList( MapType, MapModifiers, {}, Components, CurComponentListInfo, - StructBaseCombinedInfo, PartialStruct, AddTargetParamFlag, IsImplicit, - /*GenerateAllInfoForClauses*/ false, Mapper, + PartialStructs, AddTargetParamFlag, IsImplicit, Mapper, /*ForDeviceAddr=*/false, VD, VarRef, OverlappedComponents); AddTargetParamFlag = false; } + #endif + + // FIXME: Check this. + bool AddTargetParamFlag = IsListEligibleForTargetParamFlag; + // Go through other elements without overlapped elements. for (const MapData &L : DeclComponentLists) { + if (ProcessedMappings.contains(&L)) { + fprintf(stderr, "Already processed map data for %p, skipping\n", + (void*) &L); + continue; + } + OMPClauseMappableExprCommon::MappableExprComponentListRef Components; OpenMPMapClauseKind MapType; ArrayRef<OpenMPMapModifierKind> MapModifiers; @@ -9016,14 +10119,17 @@ class MappableExprsHandler { const Expr *VarRef; std::tie(Components, MapType, MapModifiers, IsImplicit, Mapper, VarRef) = L; - auto It = OverlappedData.find(&L); - if (It == OverlappedData.end()) + //auto It = OverlappedData.find(&L); + //if (It == OverlappedData.end()) { + fprintf(stderr, "*** From generateInfoForCaptureFromComponentLists (non-overlapped)...\n"); +#if 1 generateInfoForComponentList( MapType, MapModifiers, {}, Components, CurComponentListInfo, - StructBaseCombinedInfo, PartialStruct, AddTargetParamFlag, - IsImplicit, /*GenerateAllInfoForClauses*/ false, Mapper, + PartialStructs, AddTargetParamFlag, IsImplicit, Mapper, /*ForDeviceAddr=*/false, VD, VarRef, - /*OverlappedElements*/ {}, AreBothBasePtrAndPteeMapped); + /*OverlappedElements {},*/ AreBothBasePtrAndPteeMapped); +#endif + //} AddTargetParamFlag = false; } } @@ -9110,6 +10216,7 @@ class MappableExprsHandler { CombinedInfo.Mappers.push_back(nullptr); } }; + } // anonymous namespace // Try to extract the base declaration from a `this->x` expression if possible. @@ -9496,6 +10603,8 @@ static void genMapInfoForCaptures( llvm::DenseSet<CanonicalDeclPtr<const Decl>> &MappedVarSet, MappableExprsHandler::MapCombinedInfoTy &CombinedInfo) { + fprintf(stderr, "genMapInfoForCaptures\n"); + llvm::DenseMap<llvm::Value *, llvm::Value *> LambdaPointers; auto RI = CS.getCapturedRecordDecl()->field_begin(); auto *CV = CapturedVars.begin(); @@ -9503,6 +10612,18 @@ static void genMapInfoForCaptures( CE = CS.capture_end(); CI != CE; ++CI, ++RI, ++CV) { MappableExprsHandler::MapCombinedInfoTy CurInfo; + MappableExprsHandler::PartialStructMap PartialStructs; + + auto V = CI->getCapturedVar(); + llvm::dbgs() << "var:\n"; + V->dump(); + llvm::dbgs() << "\ncaptured by:\n"; + switch (CI->getCaptureKind()) { + case CapturedStmt::VCK_This: llvm::dbgs() << "this\n"; break; + case CapturedStmt::VCK_ByRef: llvm::dbgs() << "byref\n"; break; + case CapturedStmt::VCK_ByCopy: llvm::dbgs() << "bycopy\n"; break; + case CapturedStmt::VCK_VLAType: llvm::dbgs() << "vlatype\n"; break; + } // VLA sizes are passed to the outlined region by copy and do not have map // information associated. @@ -9524,15 +10645,14 @@ static void genMapInfoForCaptures( // If we have any information in the map clause, we use it, otherwise we // just do a default mapping. MEHandler.generateInfoForCaptureFromClauseInfo( - CI, *CV, CurInfo, OMPBuilder, + CI, *CV, CurInfo, PartialStructs, OMPBuilder, /*OffsetForMemberOfFlag=*/CombinedInfo.BasePointers.size()); if (!CI->capturesThis()) MappedVarSet.insert(CI->getCapturedVar()); else MappedVarSet.insert(nullptr); - - if (CurInfo.BasePointers.empty()) + if (CurInfo.BasePointers.empty() && PartialStructs.empty()) MEHandler.generateDefaultMapInfo(*CI, **RI, *CV, CurInfo); // Generate correct mapping for variables captured by reference in @@ -9550,6 +10670,32 @@ static void genMapInfoForCaptures( CurInfo.BasePointers.size() == CurInfo.Mappers.size() && "Inconsistent map information sizes!"); + // If there is an entry in PartialStruct it means we have a struct with + // individual members mapped. Emit an extra combined entry. FIXME. + //if (PartialStruct.Base.isValid()) { + // CombinedInfo.append(PartialStruct.PreliminaryMapData); + // MEHandler.emitCombinedEntry(CombinedInfo, CurInfo.Types, PartialStruct, + // CI->capturesThis(), OMPBuilder, nullptr, + // /*NotTargetParams*/ false); + //} + +#if 0 + fprintf(stderr, "Gathered up partial structs (2):\n"); + for (auto &PS : PartialStructs) { + auto &PartialStruct = PS.getSecond(); + fprintf(stderr, "A partial struct:\n"); + llvm::dbgs() << "Name: " << PartialStruct.Base.getName() << "\n"; + llvm::dbgs() << "Is valid: " << (PartialStruct.Base.isValid() ? "true" : "false") << "\n"; + llvm::dbgs() << "Lo elem: " << PartialStruct.LowestElem.first << "\n"; + llvm::dbgs() << "Hi elem: " << PartialStruct.HighestElem.first << "\n"; + //CombinedInfo.append(PartialStruct.PreliminaryMapData); + //MEHandler.emitCombinedEntry(CombinedInfo, CurInfo.Types, PartialStruct, + // CI->capturesThis(), OMPBuilder, nullptr, + // /*NotTargetParams*/ false); + } +#endif + fprintf(stderr, "That's all\n"); + // We need to append the results of this capture to what we already have. CombinedInfo.append(CurInfo); } _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits