diff options
| author | Alexey Bataev <a.bataev@hotmail.com> | 2018-07-19 16:34:13 +0000 |
|---|---|---|
| committer | Alexey Bataev <a.bataev@hotmail.com> | 2018-07-19 16:34:13 +0000 |
| commit | b3638135432b66aa56831556b51963aef44a352c (patch) | |
| tree | ef6df191f64ea3fac121d0de28059ace739c2642 /clang/lib | |
| parent | d4143bc77274a9184219dc457029c0f25187ee77 (diff) | |
| download | bcm5719-llvm-b3638135432b66aa56831556b51963aef44a352c.tar.gz bcm5719-llvm-b3638135432b66aa56831556b51963aef44a352c.zip | |
The patch adds support for the new map interface between clang and libomptarget. The changes in the interface are the following:
device IDs are now 64-bit integers (as opposed to 32-bit)
map flags are 64-bit long (used to be 32-bit)
mappings for partially mapped structs are now calculated at compile time and members of partially mapped structs are flagged using the MEMBER_OF field
Support for is_device_ptr on struct members was dropped - this functionality is not supported by the OpenMP standard and its implementation is technically infeasible (however, use_device_ptr on struct members works as a non-standard extension of the compiler)
llvm-svn: 337468
Diffstat (limited to 'clang/lib')
| -rw-r--r-- | clang/lib/CodeGen/CGOpenMPRuntime.cpp | 785 |
1 files changed, 492 insertions, 293 deletions
diff --git a/clang/lib/CodeGen/CGOpenMPRuntime.cpp b/clang/lib/CodeGen/CGOpenMPRuntime.cpp index 5594dd44381..8d4e83bf935 100644 --- a/clang/lib/CodeGen/CGOpenMPRuntime.cpp +++ b/clang/lib/CodeGen/CGOpenMPRuntime.cpp @@ -6503,6 +6503,8 @@ emitNumThreadsForTargetDirective(CGOpenMPRuntime &OMPRuntime, } namespace { +LLVM_ENABLE_BITMASK_ENUMS_IN_NAMESPACE(); + // 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 @@ -6511,7 +6513,9 @@ class MappableExprsHandler { public: /// Values for bit flags used to specify the mapping type for /// offloading. - enum OpenMPOffloadMappingFlags { + enum OpenMPOffloadMappingFlags : uint64_t { + /// No flags + OMP_MAP_NONE = 0x0, /// Allocate memory on the device and move data from host to device. OMP_MAP_TO = 0x01, /// Allocate memory on the device and move data from device to host. @@ -6539,6 +6543,10 @@ public: OMP_MAP_LITERAL = 0x100, /// Implicit map OMP_MAP_IMPLICIT = 0x200, + /// The 16 MSBs of the flags indicate whether the entry is member of some + /// struct/class. + OMP_MAP_MEMBER_OF = 0xffff000000000000, + LLVM_MARK_AS_BITMASK_ENUM(/* LargestFlag = */ OMP_MAP_MEMBER_OF), }; /// Class that associates information with a base pointer to be passed to the @@ -6558,11 +6566,52 @@ public: void setDevicePtrDecl(const ValueDecl *D) { DevPtrDecl = D; } }; - typedef SmallVector<BasePointerInfo, 16> MapBaseValuesArrayTy; - typedef SmallVector<llvm::Value *, 16> MapValuesArrayTy; - typedef SmallVector<uint64_t, 16> MapFlagsArrayTy; + using MapBaseValuesArrayTy = SmallVector<BasePointerInfo, 4>; + using MapValuesArrayTy = SmallVector<llvm::Value *, 4>; + using MapFlagsArrayTy = SmallVector<OpenMPOffloadMappingFlags, 4>; + + /// Map between a struct and the its lowest & highest elements which have been + /// mapped. + /// [ValueDecl *] --> {LE(FieldIndex, Pointer), + /// HE(FieldIndex, Pointer)} + struct StructRangeInfoTy { + std::pair<unsigned /*FieldIndex*/, Address /*Pointer*/> LowestElem = { + 0, Address::invalid()}; + std::pair<unsigned /*FieldIndex*/, Address /*Pointer*/> HighestElem = { + 0, Address::invalid()}; + Address Base = Address::invalid(); + }; private: + /// Kind that defines how a device pointer has to be returned. + struct MapInfo { + OMPClauseMappableExprCommon::MappableExprComponentListRef Components; + OpenMPMapClauseKind MapType = OMPC_MAP_unknown; + OpenMPMapClauseKind MapTypeModifier = OMPC_MAP_unknown; + bool ReturnDevicePointer = false; + bool IsImplicit = false; + + MapInfo() = default; + MapInfo( + OMPClauseMappableExprCommon::MappableExprComponentListRef Components, + OpenMPMapClauseKind MapType, OpenMPMapClauseKind MapTypeModifier, + bool ReturnDevicePointer, bool IsImplicit) + : Components(Components), MapType(MapType), + MapTypeModifier(MapTypeModifier), + ReturnDevicePointer(ReturnDevicePointer), IsImplicit(IsImplicit) {} + }; + + /// If use_device_ptr is used on a pointer which is a struct member and there + /// is no map information about it, then emission of that entry is deferred + /// until the whole struct has been processed. + struct DeferredDevicePtrEntryTy { + const Expr *IE = nullptr; + const ValueDecl *VD = nullptr; + + DeferredDevicePtrEntryTy(const Expr *IE, const ValueDecl *VD) + : IE(IE), VD(VD) {} + }; + /// Directive from where the map clauses were extracted. const OMPExecutableDirective &CurDir; @@ -6571,8 +6620,6 @@ private: /// Set of all first private variables in the current directive. llvm::SmallPtrSet<const VarDecl *, 8> FirstPrivateDecls; - /// Set of all reduction variables in the current directive. - llvm::SmallPtrSet<const VarDecl *, 8> ReductionDecls; /// Map between device pointer declarations and their expression components. /// The key value for declarations in 'this' is null. @@ -6627,10 +6674,12 @@ private: /// a flag marking the map as a pointer if requested. Add a flag marking the /// map as the first one of a series of maps that relate to the same map /// expression. - uint64_t getMapTypeBits(OpenMPMapClauseKind MapType, - OpenMPMapClauseKind MapTypeModifier, bool AddPtrFlag, - bool AddIsTargetParamFlag) const { - uint64_t Bits = 0u; + OpenMPOffloadMappingFlags getMapTypeBits(OpenMPMapClauseKind MapType, + OpenMPMapClauseKind MapTypeModifier, + bool IsImplicit, bool AddPtrFlag, + bool AddIsTargetParamFlag) const { + OpenMPOffloadMappingFlags Bits = + IsImplicit ? OMP_MAP_IMPLICIT : OMP_MAP_NONE; switch (MapType) { case OMPC_MAP_alloc: case OMPC_MAP_release: @@ -6640,20 +6689,20 @@ private: // type modifiers. break; case OMPC_MAP_to: - Bits = OMP_MAP_TO; + Bits |= OMP_MAP_TO; break; case OMPC_MAP_from: - Bits = OMP_MAP_FROM; + Bits |= OMP_MAP_FROM; break; case OMPC_MAP_tofrom: - Bits = OMP_MAP_TO | OMP_MAP_FROM; + Bits |= OMP_MAP_TO | OMP_MAP_FROM; break; case OMPC_MAP_delete: - Bits = OMP_MAP_DELETE; + Bits |= OMP_MAP_DELETE; break; - default: + case OMPC_MAP_always: + case OMPC_MAP_unknown: llvm_unreachable("Unexpected map type!"); - break; } if (AddPtrFlag) Bits |= OMP_MAP_PTR_AND_OBJ; @@ -6702,50 +6751,6 @@ private: return ConstLength.getSExtValue() != 1; } - /// Return the adjusted map modifiers if the declaration a capture - /// refers to appears in a first-private clause. This is expected to be used - /// only with directives that start with 'target'. - unsigned adjustMapModifiersForPrivateClauses(const CapturedStmt::Capture &Cap, - unsigned CurrentModifiers) { - assert(Cap.capturesVariable() && "Expected capture by reference only!"); - - // A first private variable captured by reference will use only the - // 'private ptr' and 'map to' flag. Return the right flags if the captured - // declaration is known as first-private in this handler. - if (FirstPrivateDecls.count(Cap.getCapturedVar())) - return MappableExprsHandler::OMP_MAP_PRIVATE | - MappableExprsHandler::OMP_MAP_TO; - // Reduction variable will use only the 'private ptr' and 'map to_from' - // flag. - if (ReductionDecls.count(Cap.getCapturedVar())) { - return MappableExprsHandler::OMP_MAP_TO | - MappableExprsHandler::OMP_MAP_FROM; - } - - // We didn't modify anything. - return CurrentModifiers; - } - -public: - MappableExprsHandler(const OMPExecutableDirective &Dir, CodeGenFunction &CGF) - : CurDir(Dir), CGF(CGF) { - // Extract firstprivate clause information. - for (const auto *C : Dir.getClausesOfKind<OMPFirstprivateClause>()) - for (const Expr *D : C->varlists()) - FirstPrivateDecls.insert( - cast<VarDecl>(cast<DeclRefExpr>(D)->getDecl())->getCanonicalDecl()); - for (const auto *C : Dir.getClausesOfKind<OMPReductionClause>()) { - for (const Expr *D : C->varlists()) { - ReductionDecls.insert( - cast<VarDecl>(cast<DeclRefExpr>(D)->getDecl())->getCanonicalDecl()); - } - } - // Extract device pointer clause information. - for (const auto *C : Dir.getClausesOfKind<OMPIsDevicePtrClause>()) - for (const auto &L : C->component_lists()) - DevPointersMap[L.first].push_back(L.second); - } - /// Generate the base pointers, section pointers, sizes and map type /// bits for the provided map type, map modifier, and expression components. /// \a IsFirstComponent should be set to true if the provided set of @@ -6755,8 +6760,8 @@ public: OMPClauseMappableExprCommon::MappableExprComponentListRef Components, MapBaseValuesArrayTy &BasePointers, MapValuesArrayTy &Pointers, MapValuesArrayTy &Sizes, MapFlagsArrayTy &Types, - bool IsFirstComponentList, bool IsImplicit) const { - + StructRangeInfoTy &PartialStruct, bool IsFirstComponentList, + bool IsImplicit) const { // The following summarizes what has to be generated for each map and the // types below. The generated information is expressed in this order: // base pointer, section pointer, size, flags @@ -6781,93 +6786,137 @@ public: // S2 *ps; // // map(d) - // &d, &d, sizeof(double), noflags + // &d, &d, sizeof(double), TARGET_PARAM | TO | FROM // // map(i) - // &i, &i, 100*sizeof(int), noflags + // &i, &i, 100*sizeof(int), TARGET_PARAM | TO | FROM // // map(i[1:23]) - // &i(=&i[0]), &i[1], 23*sizeof(int), noflags + // &i(=&i[0]), &i[1], 23*sizeof(int), TARGET_PARAM | TO | FROM // // map(p) - // &p, &p, sizeof(float*), noflags + // &p, &p, sizeof(float*), TARGET_PARAM | TO | FROM // // map(p[1:24]) - // p, &p[1], 24*sizeof(float), noflags + // p, &p[1], 24*sizeof(float), TARGET_PARAM | TO | FROM // // map(s) - // &s, &s, sizeof(S2), noflags + // &s, &s, sizeof(S2), TARGET_PARAM | TO | FROM // // map(s.i) - // &s, &(s.i), sizeof(int), noflags + // &s, &(s.i), sizeof(int), TARGET_PARAM | TO | FROM // // map(s.s.f) - // &s, &(s.i.f), 50*sizeof(int), noflags + // &s, &(s.s.f[0]), 50*sizeof(float), TARGET_PARAM | TO | FROM // // map(s.p) - // &s, &(s.p), sizeof(double*), noflags + // &s, &(s.p), sizeof(double*), TARGET_PARAM | TO | FROM // - // map(s.p[:22], s.a s.b) - // &s, &(s.p), sizeof(double*), noflags - // &(s.p), &(s.p[0]), 22*sizeof(double), ptr_flag + // map(to: s.p[:22]) + // &s, &(s.p), sizeof(double*), TARGET_PARAM (*) + // &s, &(s.p), sizeof(double*), MEMBER_OF(1) (**) + // &(s.p), &(s.p[0]), 22*sizeof(double), + // MEMBER_OF(1) | PTR_AND_OBJ | TO (***) + // (*) alloc space for struct members, only this is a target parameter + // (**) map the pointer (nothing to be mapped in this example) (the compiler + // optimizes this entry out, same in the examples below) + // (***) map the pointee (map: to) // // map(s.ps) - // &s, &(s.ps), sizeof(S2*), noflags + // &s, &(s.ps), sizeof(S2*), TARGET_PARAM | TO | FROM // - // map(s.ps->s.i) - // &s, &(s.ps), sizeof(S2*), noflags - // &(s.ps), &(s.ps->s.i), sizeof(int), ptr_flag + // map(from: s.ps->s.i) + // &s, &(s.ps), sizeof(S2*), TARGET_PARAM + // &s, &(s.ps), sizeof(S2*), MEMBER_OF(1) + // &(s.ps), &(s.ps->s.i), sizeof(int), MEMBER_OF(1) | PTR_AND_OBJ | FROM // - // map(s.ps->ps) - // &s, &(s.ps), sizeof(S2*), noflags - // &(s.ps), &(s.ps->ps), sizeof(S2*), ptr_flag + // map(to: s.ps->ps) + // &s, &(s.ps), sizeof(S2*), TARGET_PARAM + // &s, &(s.ps), sizeof(S2*), MEMBER_OF(1) + // &(s.ps), &(s.ps->ps), sizeof(S2*), MEMBER_OF(1) | PTR_AND_OBJ | TO // // map(s.ps->ps->ps) - // &s, &(s.ps), sizeof(S2*), noflags - // &(s.ps), &(s.ps->ps), sizeof(S2*), ptr_flag - // &(s.ps->ps), &(s.ps->ps->ps), sizeof(S2*), ptr_flag + // &s, &(s.ps), sizeof(S2*), TARGET_PARAM + // &s, &(s.ps), sizeof(S2*), MEMBER_OF(1) + // &(s.ps), &(s.ps->ps), sizeof(S2*), MEMBER_OF(1) | PTR_AND_OBJ + // &(s.ps->ps), &(s.ps->ps->ps), sizeof(S2*), PTR_AND_OBJ | TO | FROM // - // map(s.ps->ps->s.f[:22]) - // &s, &(s.ps), sizeof(S2*), noflags - // &(s.ps), &(s.ps->ps), sizeof(S2*), ptr_flag - // &(s.ps->ps), &(s.ps->ps->s.f[0]), 22*sizeof(float), ptr_flag + // map(to: s.ps->ps->s.f[:22]) + // &s, &(s.ps), sizeof(S2*), TARGET_PARAM + // &s, &(s.ps), sizeof(S2*), MEMBER_OF(1) + // &(s.ps), &(s.ps->ps), sizeof(S2*), MEMBER_OF(1) | PTR_AND_OBJ + // &(s.ps->ps), &(s.ps->ps->s.f[0]), 22*sizeof(float), PTR_AND_OBJ | TO // // map(ps) - // &ps, &ps, sizeof(S2*), noflags + // &ps, &ps, sizeof(S2*), TARGET_PARAM | TO | FROM // // map(ps->i) - // ps, &(ps->i), sizeof(int), noflags + // ps, &(ps->i), sizeof(int), TARGET_PARAM | TO | FROM // // map(ps->s.f) - // ps, &(ps->s.f[0]), 50*sizeof(float), noflags + // ps, &(ps->s.f[0]), 50*sizeof(float), TARGET_PARAM | TO | FROM // - // map(ps->p) - // ps, &(ps->p), sizeof(double*), noflags + // map(from: ps->p) + // ps, &(ps->p), sizeof(double*), TARGET_PARAM | FROM // - // map(ps->p[:22]) - // ps, &(ps->p), sizeof(double*), noflags - // &(ps->p), &(ps->p[0]), 22*sizeof(double), ptr_flag + // map(to: ps->p[:22]) + // ps, &(ps->p), sizeof(double*), TARGET_PARAM + // ps, &(ps->p), sizeof(double*), MEMBER_OF(1) + // &(ps->p), &(ps->p[0]), 22*sizeof(double), MEMBER_OF(1) | PTR_AND_OBJ | TO // // map(ps->ps) - // ps, &(ps->ps), sizeof(S2*), noflags + // ps, &(ps->ps), sizeof(S2*), TARGET_PARAM | TO | FROM // - // map(ps->ps->s.i) - // ps, &(ps->ps), sizeof(S2*), noflags - // &(ps->ps), &(ps->ps->s.i), sizeof(int), ptr_flag + // map(from: ps->ps->s.i) + // ps, &(ps->ps), sizeof(S2*), TARGET_PARAM + // ps, &(ps->ps), sizeof(S2*), MEMBER_OF(1) + // &(ps->ps), &(ps->ps->s.i), sizeof(int), MEMBER_OF(1) | PTR_AND_OBJ | FROM // - // map(ps->ps->ps) - // ps, &(ps->ps), sizeof(S2*), noflags - // &(ps->ps), &(ps->ps->ps), sizeof(S2*), ptr_flag + // map(from: ps->ps->ps) + // ps, &(ps->ps), sizeof(S2*), TARGET_PARAM + // ps, &(ps->ps), sizeof(S2*), MEMBER_OF(1) + // &(ps->ps), &(ps->ps->ps), sizeof(S2*), MEMBER_OF(1) | PTR_AND_OBJ | FROM // // map(ps->ps->ps->ps) - // ps, &(ps->ps), sizeof(S2*), noflags - // &(ps->ps), &(ps->ps->ps), sizeof(S2*), ptr_flag - // &(ps->ps->ps), &(ps->ps->ps->ps), sizeof(S2*), ptr_flag + // ps, &(ps->ps), sizeof(S2*), TARGET_PARAM + // ps, &(ps->ps), sizeof(S2*), MEMBER_OF(1) + // &(ps->ps), &(ps->ps->ps), sizeof(S2*), MEMBER_OF(1) | PTR_AND_OBJ + // &(ps->ps->ps), &(ps->ps->ps->ps), sizeof(S2*), PTR_AND_OBJ | TO | FROM + // + // map(to: ps->ps->ps->s.f[:22]) + // ps, &(ps->ps), sizeof(S2*), TARGET_PARAM + // ps, &(ps->ps), sizeof(S2*), MEMBER_OF(1) + // &(ps->ps), &(ps->ps->ps), sizeof(S2*), MEMBER_OF(1) | PTR_AND_OBJ + // &(ps->ps->ps), &(ps->ps->ps->s.f[0]), 22*sizeof(float), PTR_AND_OBJ | TO + // + // map(to: s.f[:22]) map(from: s.p[:33]) + // &s, &(s.f[0]), 50*sizeof(float) + sizeof(struct S1) + + // sizeof(double*) (**), TARGET_PARAM + // &s, &(s.f[0]), 22*sizeof(float), MEMBER_OF(1) | TO + // &s, &(s.p), sizeof(double*), MEMBER_OF(1) + // &(s.p), &(s.p[0]), 33*sizeof(double), MEMBER_OF(1) | PTR_AND_OBJ | FROM + // (*) allocate contiguous space needed to fit all mapped members even if + // we allocate space for members not mapped (in this example, + // s.f[22..49] and s.s are not mapped, yet we must allocate space for + // them as well because they fall between &s.f[0] and &s.p) + // + // map(from: s.f[:22]) map(to: ps->p[:33]) + // &s, &(s.f[0]), 22*sizeof(float), TARGET_PARAM | FROM + // ps, &(ps->p), sizeof(S2*), TARGET_PARAM + // ps, &(ps->p), sizeof(double*), MEMBER_OF(2) (*) + // &(ps->p), &(ps->p[0]), 33*sizeof(double), MEMBER_OF(2) | PTR_AND_OBJ | TO + // (*) the struct this entry pertains to is the 2nd element in the list of + // arguments, hence MEMBER_OF(2) // - // map(ps->ps->ps->s.f[:22]) - // ps, &(ps->ps), sizeof(S2*), noflags - // &(ps->ps), &(ps->ps->ps), sizeof(S2*), ptr_flag - // &(ps->ps->ps), &(ps->ps->ps->s.f[0]), 22*sizeof(float), ptr_flag + // map(from: s.f[:22], s.s) map(to: ps->p[:33]) + // &s, &(s.f[0]), 50*sizeof(float) + sizeof(struct S1), TARGET_PARAM + // &s, &(s.f[0]), 22*sizeof(float), MEMBER_OF(1) | FROM + // &s, &(s.s), sizeof(struct S1), MEMBER_OF(1) | FROM + // ps, &(ps->p), sizeof(S2*), TARGET_PARAM + // ps, &(ps->p), sizeof(double*), MEMBER_OF(4) (*) + // &(ps->p), &(ps->p[0]), 33*sizeof(double), MEMBER_OF(4) | PTR_AND_OBJ | TO + // (*) the struct this entry pertains to is the 4th element in the list + // of arguments, hence MEMBER_OF(4) // Track if the map information being generated is the first for a capture. bool IsCaptureFirstInfo = IsFirstComponentList; @@ -6881,25 +6930,23 @@ public: // Track if the map information being generated is the first for a list of // components. bool IsExpressionFirstInfo = true; - llvm::Value *BP = nullptr; + Address BP = Address::invalid(); if (const auto *ME = dyn_cast<MemberExpr>(I->getAssociatedExpression())) { // The base is the 'this' pointer. The content of the pointer is going // to be the base of the field being mapped. - BP = CGF.EmitScalarExpr(ME->getBase()); + BP = CGF.LoadCXXThisAddress(); } else { // The base is the reference to the variable. // BP = &Var. - BP = CGF.EmitOMPSharedLValue(I->getAssociatedExpression()).getPointer(); + BP = CGF.EmitOMPSharedLValue(I->getAssociatedExpression()).getAddress(); if (const auto *VD = dyn_cast_or_null<VarDecl>(I->getAssociatedDeclaration())) { if (llvm::Optional<OMPDeclareTargetDeclAttr::MapTypeTy> Res = - isDeclareTargetDeclaration(VD)) + isDeclareTargetDeclaration(VD)) if (*Res == OMPDeclareTargetDeclAttr::MT_Link) { IsLink = true; - BP = CGF.CGM.getOpenMPRuntime() - .getAddrOfDeclareTargetLink(VD) - .getPointer(); + BP = CGF.CGM.getOpenMPRuntime().getAddrOfDeclareTargetLink(VD); } } @@ -6909,10 +6956,7 @@ public: QualType Ty = I->getAssociatedDeclaration()->getType().getNonReferenceType(); if (Ty->isAnyPointerType() && std::next(I) != CE) { - LValue PtrAddr = CGF.MakeNaturalAlignAddrLValue(BP, Ty); - BP = CGF.EmitLoadOfPointerLValue(PtrAddr.getAddress(), - Ty->castAs<PointerType>()) - .getPointer(); + BP = CGF.EmitLoadOfPointer(BP, Ty->castAs<PointerType>()); // We do not need to generate individual map information for the // pointer, it can be associated with the combined storage. @@ -6920,8 +6964,41 @@ public: } } - uint64_t DefaultFlags = IsImplicit ? OMP_MAP_IMPLICIT : 0; + // Track whether a component of the list should be marked as MEMBER_OF some + // combined entry (for partial structs). Only the first PTR_AND_OBJ entry + // in a component list should be marked as MEMBER_OF, all subsequent entries + // do not belong to the base struct. E.g. + // struct S2 s; + // s.ps->ps->ps->f[:] + // (1) (2) (3) (4) + // ps(1) is a member pointer, ps(2) is a pointee of ps(1), so it is a + // PTR_AND_OBJ entry; the PTR is ps(1), so MEMBER_OF the base struct. ps(3) + // is the pointee of ps(2) which is not member of struct s, so it should not + // be marked as such (it is still PTR_AND_OBJ). + // The variable is initialized to false so that PTR_AND_OBJ entries which + // are not struct members are not considered (e.g. array of pointers to + // data). + bool ShouldBeMemberOf = false; + + // Variable keeping track of whether or not we have encountered a component + // in the component list which is a member expression. Useful when we have a + // pointer or a final array section, in which case it is the previous + // component in the list which tells us whether we have a member expression. + // E.g. X.f[:] + // While processing the final array section "[:]" it is "f" which tells us + // whether we are dealing with a member of a declared struct. + const MemberExpr *EncounteredME = nullptr; + for (; I != CE; ++I) { + // If the current component is member of a struct (parent struct) mark it. + if (!EncounteredME) { + EncounteredME = dyn_cast<MemberExpr>(I->getAssociatedExpression()); + // If we encounter a PTR_AND_OBJ entry from now on it should be marked + // as MEMBER_OF the parent struct. + if (EncounteredME) + ShouldBeMemberOf = true; + } + auto Next = std::next(I); // We need to generate the addresses and sizes if this is the last @@ -6939,10 +7016,9 @@ public: const auto *OASE = dyn_cast<OMPArraySectionExpr>(I->getAssociatedExpression()); bool IsPointer = - (OASE && - OMPArraySectionExpr::getBaseOriginalType(OASE) - .getCanonicalType() - ->isAnyPointerType()) || + (OASE && OMPArraySectionExpr::getBaseOriginalType(OASE) + .getCanonicalType() + ->isAnyPointerType()) || I->getAssociatedExpression()->getType()->isAnyPointerType(); if (Next == CE || IsPointer || IsFinalArraySection) { @@ -6954,45 +7030,68 @@ public: isa<OMPArraySectionExpr>(Next->getAssociatedExpression())) && "Unexpected expression"); - llvm::Value *LB = - CGF.EmitOMPSharedLValue(I->getAssociatedExpression()).getPointer(); + Address LB = + CGF.EmitOMPSharedLValue(I->getAssociatedExpression()).getAddress(); llvm::Value *Size = getExprTypeSize(I->getAssociatedExpression()); - // If we have a member expression and the current component is a - // reference, we have to map the reference too. Whenever we have a - // reference, the section that reference refers to is going to be a - // load instruction from the storage assigned to the reference. - if (isa<MemberExpr>(I->getAssociatedExpression()) && - I->getAssociatedDeclaration()->getType()->isReferenceType()) { - auto *LI = cast<llvm::LoadInst>(LB); - llvm::Value *RefAddr = LI->getPointerOperand(); - - BasePointers.push_back(BP); - Pointers.push_back(RefAddr); - Sizes.push_back(CGF.getTypeSize(CGF.getContext().VoidPtrTy)); - Types.push_back(DefaultFlags | - getMapTypeBits( - /*MapType*/ OMPC_MAP_alloc, - /*MapTypeModifier=*/OMPC_MAP_unknown, - !IsExpressionFirstInfo, IsCaptureFirstInfo)); - IsExpressionFirstInfo = false; - IsCaptureFirstInfo = false; - // The reference will be the next base address. - BP = RefAddr; - } + // If this component is a pointer inside the base struct then we don't + // need to create any entry for it - it will be combined with the object + // it is pointing to into a single PTR_AND_OBJ entry. + bool IsMemberPointer = + IsPointer && EncounteredME && + (dyn_cast<MemberExpr>(I->getAssociatedExpression()) == + EncounteredME); + if (!IsMemberPointer) { + BasePointers.push_back(BP.getPointer()); + Pointers.push_back(LB.getPointer()); + Sizes.push_back(Size); + + // 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 + // this map is the first one that relates with the current capture + // (there is a set of entries for each capture). + OpenMPOffloadMappingFlags Flags = getMapTypeBits( + MapType, MapTypeModifier, IsImplicit, + !IsExpressionFirstInfo || IsLink, IsCaptureFirstInfo && !IsLink); + + if (!IsExpressionFirstInfo) { + // If we have a PTR_AND_OBJ pair where the OBJ is a pointer as well, + // then we reset the TO/FROM/ALWAYS/DELETE flags. + if (IsPointer) + Flags &= ~(OMP_MAP_TO | OMP_MAP_FROM | OMP_MAP_ALWAYS | + OMP_MAP_DELETE); + + if (ShouldBeMemberOf) { + // Set placeholder value MEMBER_OF=FFFF to indicate that the flag + // should be later updated with the correct value of MEMBER_OF. + Flags |= OMP_MAP_MEMBER_OF; + // From now on, all subsequent PTR_AND_OBJ entries should not be + // marked as MEMBER_OF. + ShouldBeMemberOf = false; + } + } - BasePointers.push_back(BP); - Pointers.push_back(LB); - Sizes.push_back(Size); + Types.push_back(Flags); + } - // 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 - // this map is the first one that relates with the current capture - // (there is a set of entries for each capture). - Types.push_back(DefaultFlags | - getMapTypeBits(MapType, MapTypeModifier, - !IsExpressionFirstInfo || IsLink, - IsCaptureFirstInfo && !IsLink)); + // 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. + if (EncounteredME) { + const auto *FD = dyn_cast<FieldDecl>(EncounteredME->getMemberDecl()); + unsigned FieldIndex = FD->getFieldIndex(); + + // Update info about the lowest and highest elements for this struct + if (!PartialStruct.Base.isValid()) { + PartialStruct.LowestElem = {FieldIndex, LB}; + PartialStruct.HighestElem = {FieldIndex, LB}; + PartialStruct.Base = BP; + } else if (FieldIndex < PartialStruct.LowestElem.first) { + PartialStruct.LowestElem = {FieldIndex, LB}; + } else if (FieldIndex > PartialStruct.HighestElem.first) { + PartialStruct.HighestElem = {FieldIndex, LB}; + } + } // If we have a final array section, we are done with this expression. if (IsFinalArraySection) @@ -7008,6 +7107,93 @@ public: } } + /// Return the adjusted map modifiers if the declaration a capture refers to + /// appears in a first-private clause. This is expected to be used only with + /// directives that start with 'target'. + MappableExprsHandler::OpenMPOffloadMappingFlags + getMapModifiersForPrivateClauses(const CapturedStmt::Capture &Cap) const { + assert(Cap.capturesVariable() && "Expected capture by reference only!"); + + // A first private variable captured by reference will use only the + // 'private ptr' and 'map to' flag. Return the right flags if the captured + // declaration is known as first-private in this handler. + if (FirstPrivateDecls.count(Cap.getCapturedVar())) + return MappableExprsHandler::OMP_MAP_PRIVATE | + MappableExprsHandler::OMP_MAP_TO; + return MappableExprsHandler::OMP_MAP_TO | + MappableExprsHandler::OMP_MAP_FROM; + } + + static OpenMPOffloadMappingFlags getMemberOfFlag(unsigned Position) { + // Member of is given by the 16 MSB of the flag, so rotate by 48 bits. + return static_cast<OpenMPOffloadMappingFlags>(((uint64_t)Position + 1) + << 48); + } + + static void setCorrectMemberOfFlag(OpenMPOffloadMappingFlags &Flags, + OpenMPOffloadMappingFlags MemberOfFlag) { + // If the entry is PTR_AND_OBJ but has not been marked with the special + // placeholder value 0xFFFF in the MEMBER_OF field, then it should not be + // marked as MEMBER_OF. + if ((Flags & OMP_MAP_PTR_AND_OBJ) && + ((Flags & OMP_MAP_MEMBER_OF) != OMP_MAP_MEMBER_OF)) + return; + + // Reset the placeholder value to prepare the flag for the assignment of the + // proper MEMBER_OF value. + Flags &= ~OMP_MAP_MEMBER_OF; + Flags |= MemberOfFlag; + } + +public: + MappableExprsHandler(const OMPExecutableDirective &Dir, CodeGenFunction &CGF) + : CurDir(Dir), CGF(CGF) { + // Extract firstprivate clause information. + for (const auto *C : Dir.getClausesOfKind<OMPFirstprivateClause>()) + for (const auto *D : C->varlists()) + FirstPrivateDecls.insert( + cast<VarDecl>(cast<DeclRefExpr>(D)->getDecl())->getCanonicalDecl()); + // Extract device pointer clause information. + for (const auto *C : Dir.getClausesOfKind<OMPIsDevicePtrClause>()) + for (auto L : C->component_lists()) + DevPointersMap[L.first].push_back(L.second); + } + + /// Generate code for the combined entry if we have a partially mapped struct + /// and take care of the mapping flags of the arguments corresponding to + /// individual struct members. + void emitCombinedEntry(MapBaseValuesArrayTy &BasePointers, + MapValuesArrayTy &Pointers, MapValuesArrayTy &Sizes, + MapFlagsArrayTy &Types, MapFlagsArrayTy &CurTypes, + const StructRangeInfoTy &PartialStruct) const { + // Base is the base of the struct + BasePointers.push_back(PartialStruct.Base.getPointer()); + // Pointer is the address of the lowest element + llvm::Value *LB = PartialStruct.LowestElem.second.getPointer(); + Pointers.push_back(LB); + // Size is (addr of {highest+1} element) - (addr of lowest element) + llvm::Value *HB = PartialStruct.HighestElem.second.getPointer(); + llvm::Value *HAddr = CGF.Builder.CreateConstGEP1_32(HB, /*Idx0=*/1); + llvm::Value *CLAddr = CGF.Builder.CreatePointerCast(LB, CGF.VoidPtrTy); + llvm::Value *CHAddr = CGF.Builder.CreatePointerCast(HAddr, CGF.VoidPtrTy); + llvm::Value *Diff = CGF.Builder.CreatePtrDiff(CHAddr, CLAddr); + llvm::Value *Size = CGF.Builder.CreateIntCast(Diff, CGF.SizeTy, + /*isSinged=*/false); + Sizes.push_back(Size); + // Map type is always TARGET_PARAM + Types.push_back(OMP_MAP_TARGET_PARAM); + // Remove TARGET_PARAM flag from the first element + (*CurTypes.begin()) &= ~OMP_MAP_TARGET_PARAM; + + // All other current entries will be MEMBER_OF the combined entry + // (except for PTR_AND_OBJ entries which do not have a placeholder value + // 0xFFFF in the MEMBER_OF field). + OpenMPOffloadMappingFlags MemberOfFlag = + getMemberOfFlag(BasePointers.size() - 1); + for (auto &M : CurTypes) + setCorrectMemberOfFlag(M, MemberOfFlag); + } + /// Generate all the base pointers, section pointers, sizes and map /// types for the extracted mappable expressions. Also, for each item that /// relates with a device pointer, a pair of the relevant declaration and @@ -7015,39 +7201,6 @@ public: void generateAllInfo(MapBaseValuesArrayTy &BasePointers, MapValuesArrayTy &Pointers, MapValuesArrayTy &Sizes, MapFlagsArrayTy &Types) const { - BasePointers.clear(); - Pointers.clear(); - Sizes.clear(); - Types.clear(); - - struct MapInfo { - /// Kind that defines how a device pointer has to be returned. - enum ReturnPointerKind { - // Don't have to return any pointer. - RPK_None, - // Pointer is the base of the declaration. - RPK_Base, - // Pointer is a member of the base declaration - 'this' - RPK_Member, - // Pointer is a reference and a member of the base declaration - 'this' - RPK_MemberReference, - }; - OMPClauseMappableExprCommon::MappableExprComponentListRef Components; - OpenMPMapClauseKind MapType = OMPC_MAP_unknown; - OpenMPMapClauseKind MapTypeModifier = OMPC_MAP_unknown; - ReturnPointerKind ReturnDevicePointer = RPK_None; - bool IsImplicit = false; - - MapInfo() = default; - MapInfo( - OMPClauseMappableExprCommon::MappableExprComponentListRef Components, - OpenMPMapClauseKind MapType, OpenMPMapClauseKind MapTypeModifier, - ReturnPointerKind ReturnDevicePointer, bool IsImplicit) - : Components(Components), MapType(MapType), - MapTypeModifier(MapTypeModifier), - ReturnDevicePointer(ReturnDevicePointer), IsImplicit(IsImplicit) {} - }; - // We have to process the component lists that relate with the same // declaration in a single chunk so that we can generate the map flags // correctly. Therefore, we organize all lists in a map. @@ -7059,7 +7212,7 @@ public: const ValueDecl *D, OMPClauseMappableExprCommon::MappableExprComponentListRef L, OpenMPMapClauseKind MapType, OpenMPMapClauseKind MapModifier, - MapInfo::ReturnPointerKind ReturnDevicePointer, bool IsImplicit) { + bool ReturnDevicePointer, bool IsImplicit) { const ValueDecl *VD = D ? cast<ValueDecl>(D->getCanonicalDecl()) : nullptr; Info[VD].emplace_back(L, MapType, MapModifier, ReturnDevicePointer, @@ -7070,25 +7223,31 @@ public: for (const auto *C : this->CurDir.getClausesOfKind<OMPMapClause>()) for (const auto &L : C->component_lists()) { InfoGen(L.first, L.second, C->getMapType(), C->getMapTypeModifier(), - MapInfo::RPK_None, C->isImplicit()); + /*ReturnDevicePointer=*/false, C->isImplicit()); } for (const auto *C : this->CurDir.getClausesOfKind<OMPToClause>()) for (const auto &L : C->component_lists()) { InfoGen(L.first, L.second, OMPC_MAP_to, OMPC_MAP_unknown, - MapInfo::RPK_None, C->isImplicit()); + /*ReturnDevicePointer=*/false, C->isImplicit()); } for (const auto *C : this->CurDir.getClausesOfKind<OMPFromClause>()) for (const auto &L : C->component_lists()) { InfoGen(L.first, L.second, OMPC_MAP_from, OMPC_MAP_unknown, - MapInfo::RPK_None, C->isImplicit()); + /*ReturnDevicePointer=*/false, C->isImplicit()); } // Look at the use_device_ptr clause information and mark the existing map // entries as such. If there is no map information for an entry in the // use_device_ptr list, we create one with map type 'alloc' and zero size - // section. It is the user fault if that was not mapped before. + // section. It is the user fault if that was not mapped before. If there is + // no map information and the pointer is a struct member, then we defer the + // emission of that entry until the whole struct has been processed. + llvm::MapVector<const ValueDecl *, SmallVector<DeferredDevicePtrEntryTy, 4>> + DeferredInfo; + // FIXME: MSVC 2013 seems to require this-> to find member CurDir. - for (const auto *C : this->CurDir.getClausesOfKind<OMPUseDevicePtrClause>()) + for (const auto *C : + this->CurDir.getClausesOfKind<OMPUseDevicePtrClause>()) { for (const auto &L : C->component_lists()) { assert(!L.second.empty() && "Not expecting empty list of components!"); const ValueDecl *VD = L.second.back().getAssociatedDeclaration(); @@ -7109,54 +7268,65 @@ public: // If we found a map entry, signal that the pointer has to be returned // and move on to the next declaration. if (CI != It->second.end()) { - CI->ReturnDevicePointer = isa<MemberExpr>(IE) - ? (VD->getType()->isReferenceType() - ? MapInfo::RPK_MemberReference - : MapInfo::RPK_Member) - : MapInfo::RPK_Base; + CI->ReturnDevicePointer = true; continue; } } // We didn't find any match in our map information - generate a zero - // size array section. + // size array section - if the pointer is a struct member we defer this + // action until the whole struct has been processed. // FIXME: MSVC 2013 seems to require this-> to find member CGF. - llvm::Value *Ptr = this->CGF.EmitLoadOfScalar(this->CGF.EmitLValue(IE), - IE->getExprLoc()); - BasePointers.push_back({Ptr, VD}); - Pointers.push_back(Ptr); - Sizes.push_back(llvm::Constant::getNullValue(this->CGF.SizeTy)); - Types.push_back(OMP_MAP_RETURN_PARAM | OMP_MAP_TARGET_PARAM); + if (isa<MemberExpr>(IE)) { + // Insert the pointer into Info to be processed by + // generateInfoForComponentList. Because it is a member pointer + // without a pointee, no entry will be generated for it, therefore + // we need to generate one after the whole struct has been processed. + // Nonetheless, generateInfoForComponentList must be called to take + // the pointer into account for the calculation of the range of the + // partial struct. + InfoGen(nullptr, L.second, OMPC_MAP_unknown, OMPC_MAP_unknown, + /*ReturnDevicePointer=*/false, C->isImplicit()); + DeferredInfo[nullptr].emplace_back(IE, VD); + } else { + llvm::Value *Ptr = this->CGF.EmitLoadOfScalar( + this->CGF.EmitLValue(IE), IE->getExprLoc()); + BasePointers.emplace_back(Ptr, VD); + Pointers.push_back(Ptr); + Sizes.push_back(llvm::Constant::getNullValue(this->CGF.SizeTy)); + Types.push_back(OMP_MAP_RETURN_PARAM | OMP_MAP_TARGET_PARAM); + } } + } for (const auto &M : Info) { // We need to know when we generate information for the first component // associated with a capture, because the mapping flags depend on it. bool IsFirstComponentList = true; + + // Temporary versions of arrays + MapBaseValuesArrayTy CurBasePointers; + MapValuesArrayTy CurPointers; + MapValuesArrayTy CurSizes; + MapFlagsArrayTy CurTypes; + StructRangeInfoTy PartialStruct; + for (const MapInfo &L : M.second) { assert(!L.Components.empty() && "Not expecting declaration with no component lists."); // Remember the current base pointer index. - unsigned CurrentBasePointersIdx = BasePointers.size(); + unsigned CurrentBasePointersIdx = CurBasePointers.size(); // FIXME: MSVC 2013 seems to require this-> to find the member method. this->generateInfoForComponentList( - L.MapType, L.MapTypeModifier, L.Components, BasePointers, Pointers, - Sizes, Types, IsFirstComponentList, L.IsImplicit); + L.MapType, L.MapTypeModifier, L.Components, CurBasePointers, + CurPointers, CurSizes, CurTypes, PartialStruct, + IsFirstComponentList, L.IsImplicit); // If this entry relates with a device pointer, set the relevant // declaration and add the 'return pointer' flag. - if (IsFirstComponentList && - L.ReturnDevicePointer != MapInfo::RPK_None) { - // If the pointer is not the base of the map, we need to skip the - // base. If it is a reference in a member field, we also need to skip - // the map of the reference. - if (L.ReturnDevicePointer != MapInfo::RPK_Base) { - ++CurrentBasePointersIdx; - if (L.ReturnDevicePointer == MapInfo::RPK_MemberReference) - ++CurrentBasePointersIdx; - } - assert(BasePointers.size() > CurrentBasePointersIdx && + if (L.ReturnDevicePointer) { + assert(CurBasePointers.size() > CurrentBasePointersIdx && "Unexpected number of mapped base pointers."); const ValueDecl *RelevantVD = @@ -7164,11 +7334,42 @@ public: assert(RelevantVD && "No relevant declaration related with device pointer??"); - BasePointers[CurrentBasePointersIdx].setDevicePtrDecl(RelevantVD); - Types[CurrentBasePointersIdx] |= OMP_MAP_RETURN_PARAM; + CurBasePointers[CurrentBasePointersIdx].setDevicePtrDecl(RelevantVD); + CurTypes[CurrentBasePointersIdx] |= OMP_MAP_RETURN_PARAM; } IsFirstComponentList = false; } + + // Append any pending zero-length pointers which are struct members and + // used with use_device_ptr. + auto CI = DeferredInfo.find(M.first); + if (CI != DeferredInfo.end()) { + for (const DeferredDevicePtrEntryTy &L : CI->second) { + llvm::Value *BasePtr = this->CGF.EmitLValue(L.IE).getPointer(); + llvm::Value *Ptr = this->CGF.EmitLoadOfScalar( + this->CGF.EmitLValue(L.IE), L.IE->getExprLoc()); + CurBasePointers.emplace_back(BasePtr, L.VD); + CurPointers.push_back(Ptr); + CurSizes.push_back(llvm::Constant::getNullValue(this->CGF.SizeTy)); + // Entry is PTR_AND_OBJ and RETURN_PARAM. Also, set the placeholder + // value MEMBER_OF=FFFF so that the entry is later updated with the + // correct value of MEMBER_OF. + CurTypes.push_back(OMP_MAP_PTR_AND_OBJ | OMP_MAP_RETURN_PARAM | + OMP_MAP_MEMBER_OF); + } + } + + // 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()) + emitCombinedEntry(BasePointers, Pointers, Sizes, Types, CurTypes, + PartialStruct); + + // We need to append the results of this capture to what we already have. + BasePointers.append(CurBasePointers.begin(), CurBasePointers.end()); + Pointers.append(CurPointers.begin(), CurPointers.end()); + Sizes.append(CurSizes.begin(), CurSizes.end()); + Types.append(CurTypes.begin(), CurTypes.end()); } } @@ -7178,43 +7379,23 @@ public: llvm::Value *Arg, MapBaseValuesArrayTy &BasePointers, MapValuesArrayTy &Pointers, - MapValuesArrayTy &Sizes, - MapFlagsArrayTy &Types) const { + MapValuesArrayTy &Sizes, MapFlagsArrayTy &Types, + StructRangeInfoTy &PartialStruct) const { assert(!Cap->capturesVariableArrayType() && "Not expecting to generate map info for a variable array type!"); - BasePointers.clear(); - Pointers.clear(); - Sizes.clear(); - Types.clear(); - // We need to know when we generating information for the first component // associated with a capture, because the mapping flags depend on it. bool IsFirstComponentList = true; - const ValueDecl *VD = - Cap->capturesThis() - ? nullptr - : Cap->getCapturedVar()->getCanonicalDecl(); + const ValueDecl *VD = Cap->capturesThis() + ? nullptr + : Cap->getCapturedVar()->getCanonicalDecl(); // 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, otherwise, if it is a member expression, we need to map - // 'to' the field. - if (!VD) { - auto It = DevPointersMap.find(VD); - if (It != DevPointersMap.end()) { - for (ArrayRef<OMPClauseMappableExprCommon::MappableComponent> L : - It->second) { - generateInfoForComponentList( - /*MapType=*/OMPC_MAP_to, /*MapTypeModifier=*/OMPC_MAP_unknown, L, - BasePointers, Pointers, Sizes, Types, IsFirstComponentList, - /*IsImplicit=*/false); - IsFirstComponentList = false; - } - return; - } - } else if (DevPointersMap.count(VD)) { + // pass its value. + if (DevPointersMap.count(VD)) { BasePointers.emplace_back(Arg, VD); Pointers.push_back(Arg); Sizes.push_back(CGF.getTypeSize(CGF.getContext().VoidPtrTy)); @@ -7229,13 +7410,42 @@ public: "We got information for the wrong declaration??"); assert(!L.second.empty() && "Not expecting declaration with no component lists."); - generateInfoForComponentList( - C->getMapType(), C->getMapTypeModifier(), L.second, BasePointers, - Pointers, Sizes, Types, IsFirstComponentList, C->isImplicit()); + generateInfoForComponentList(C->getMapType(), C->getMapTypeModifier(), + L.second, BasePointers, Pointers, Sizes, + Types, PartialStruct, IsFirstComponentList, + C->isImplicit()); IsFirstComponentList = false; } + } - return; + /// Generate the base pointers, section pointers, sizes and map types + /// associated with the declare target link variables. + void generateInfoForDeclareTargetLink(MapBaseValuesArrayTy &BasePointers, + MapValuesArrayTy &Pointers, + MapValuesArrayTy &Sizes, + MapFlagsArrayTy &Types) const { + // Map other list items in the map clause which are not captured variables + // but "declare target link" global variables., + for (const auto *C : this->CurDir.getClausesOfKind<OMPMapClause>()) { + for (const auto &L : C->component_lists()) { + if (!L.first) + continue; + const auto *VD = dyn_cast<VarDecl>(L.first); + if (!VD) + continue; + llvm::Optional<OMPDeclareTargetDeclAttr::MapTypeTy> Res = + isDeclareTargetDeclaration(VD); + if (!Res || *Res != OMPDeclareTargetDeclAttr::MT_Link) + continue; + StructRangeInfoTy PartialStruct; + generateInfoForComponentList( + C->getMapType(), C->getMapTypeModifier(), L.second, BasePointers, + Pointers, Sizes, Types, PartialStruct, + /*IsFirstComponentList=*/true, C->isImplicit()); + assert(!PartialStruct.Base.isValid() && + "No partial structs for declare target link expected."); + } + } } /// Generate the default map information for a given capture \a CI, @@ -7245,8 +7455,7 @@ public: MapBaseValuesArrayTy &CurBasePointers, MapValuesArrayTy &CurPointers, MapValuesArrayTy &CurSizes, - MapFlagsArrayTy &CurMapTypes) { - + MapFlagsArrayTy &CurMapTypes) const { // Do the default mapping. if (CI.capturesThis()) { CurBasePointers.push_back(CV); @@ -7266,7 +7475,7 @@ public: } else { // Pointers are implicitly mapped with a zero size and no flags // (other than first map that is added for all implicit maps). - CurMapTypes.push_back(0u); + CurMapTypes.push_back(OMP_MAP_NONE); CurSizes.push_back(llvm::Constant::getNullValue(CGF.SizeTy)); } } else { @@ -7280,12 +7489,13 @@ public: // The default map type for a scalar/complex type is 'to' because by // default the value doesn't have to be retrieved. For an aggregate // type, the default is 'tofrom'. - CurMapTypes.emplace_back(adjustMapModifiersForPrivateClauses( - CI, ElementType->isAggregateType() ? (OMP_MAP_TO | OMP_MAP_FROM) - : OMP_MAP_TO)); + CurMapTypes.push_back(getMapModifiersForPrivateClauses(CI)); } // Every default map produces a single argument which is a target parameter. CurMapTypes.back() |= OMP_MAP_TARGET_PARAM; + + // Add flag stating this is an implicit map. + CurMapTypes.back() |= OMP_MAP_IMPLICIT; } }; @@ -7362,8 +7572,10 @@ emitOffloadingArrays(CodeGenFunction &CGF, // The map types are always constant so we don't need to generate code to // fill arrays. Instead, we create an array constant. + SmallVector<uint64_t, 4> Mapping(MapTypes.size(), 0); + llvm::copy(MapTypes, Mapping.begin()); llvm::Constant *MapTypesArrayInit = - llvm::ConstantDataArray::get(CGF.Builder.getContext(), MapTypes); + llvm::ConstantDataArray::get(CGF.Builder.getContext(), Mapping); std::string MaptypesName = CGM.getOpenMPRuntime().getName({"offload_maptypes"}); auto *MapTypesArrayGbl = new llvm::GlobalVariable( @@ -7602,11 +7814,6 @@ void CGOpenMPRuntime::emitTargetCall(CodeGenFunction &CGF, MappableExprsHandler::MapValuesArrayTy Sizes; MappableExprsHandler::MapFlagsArrayTy MapTypes; - MappableExprsHandler::MapBaseValuesArrayTy CurBasePointers; - MappableExprsHandler::MapValuesArrayTy CurPointers; - MappableExprsHandler::MapValuesArrayTy CurSizes; - MappableExprsHandler::MapFlagsArrayTy CurMapTypes; - // Get mappable expression information. MappableExprsHandler MEHandler(D, CGF); @@ -7615,10 +7822,11 @@ void CGOpenMPRuntime::emitTargetCall(CodeGenFunction &CGF, for (CapturedStmt::const_capture_iterator CI = CS.capture_begin(), CE = CS.capture_end(); CI != CE; ++CI, ++RI, ++CV) { - CurBasePointers.clear(); - CurPointers.clear(); - CurSizes.clear(); - CurMapTypes.clear(); + MappableExprsHandler::MapBaseValuesArrayTy CurBasePointers; + MappableExprsHandler::MapValuesArrayTy CurPointers; + MappableExprsHandler::MapValuesArrayTy CurSizes; + MappableExprsHandler::MapFlagsArrayTy CurMapTypes; + MappableExprsHandler::StructRangeInfoTy PartialStruct; // VLA sizes are passed to the outlined region by copy and do not have map // information associated. @@ -7633,7 +7841,7 @@ void CGOpenMPRuntime::emitTargetCall(CodeGenFunction &CGF, // If we have any information in the map clause, we use it, otherwise we // just do a default mapping. MEHandler.generateInfoForCapture(CI, *CV, CurBasePointers, CurPointers, - CurSizes, CurMapTypes); + CurSizes, CurMapTypes, PartialStruct); if (CurBasePointers.empty()) MEHandler.generateDefaultMapInfo(*CI, **RI, *CV, CurBasePointers, CurPointers, CurSizes, CurMapTypes); @@ -7646,6 +7854,12 @@ void CGOpenMPRuntime::emitTargetCall(CodeGenFunction &CGF, CurBasePointers.size() == CurMapTypes.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. + if (PartialStruct.Base.isValid()) + MEHandler.emitCombinedEntry(BasePointers, Pointers, Sizes, MapTypes, + CurMapTypes, PartialStruct); + // We need to append the results of this capture to what we already have. BasePointers.append(CurBasePointers.begin(), CurBasePointers.end()); Pointers.append(CurPointers.begin(), CurPointers.end()); @@ -7654,23 +7868,8 @@ void CGOpenMPRuntime::emitTargetCall(CodeGenFunction &CGF, } // Map other list items in the map clause which are not captured variables // but "declare target link" global variables. - for (const auto *C : D.getClausesOfKind<OMPMapClause>()) { - for (const auto &L : C->component_lists()) { - if (!L.first) - continue; - const auto *VD = dyn_cast<VarDecl>(L.first); - if (!VD) - continue; - llvm::Optional<OMPDeclareTargetDeclAttr::MapTypeTy> Res = - isDeclareTargetDeclaration(VD); - if (!Res || *Res != OMPDeclareTargetDeclAttr::MT_Link) - continue; - MEHandler.generateInfoForComponentList( - C->getMapType(), C->getMapTypeModifier(), L.second, BasePointers, - Pointers, Sizes, MapTypes, /*IsFirstComponentList=*/true, - C->isImplicit()); - } - } + MEHandler.generateInfoForDeclareTargetLink(BasePointers, Pointers, Sizes, + MapTypes); TargetDataInfo Info; // Fill up the arrays and create the arguments. |

