summaryrefslogtreecommitdiffstats
path: root/clang/lib
diff options
context:
space:
mode:
authorAlexey Bataev <a.bataev@hotmail.com>2018-07-19 16:34:13 +0000
committerAlexey Bataev <a.bataev@hotmail.com>2018-07-19 16:34:13 +0000
commitb3638135432b66aa56831556b51963aef44a352c (patch)
treeef6df191f64ea3fac121d0de28059ace739c2642 /clang/lib
parentd4143bc77274a9184219dc457029c0f25187ee77 (diff)
downloadbcm5719-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.cpp785
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.
OpenPOWER on IntegriCloud