@@ -299,10 +299,6 @@ static LogicalResult checkImplementationStatus(Operation &op) {
299299 if (privatizer.getDataSharingType () ==
300300 omp::DataSharingClauseType::FirstPrivate)
301301 result = todo (" firstprivate" );
302-
303- if (!privatizer.getDeallocRegion ().empty ())
304- result = op.emitError (" not yet implemented: privatization of "
305- " structures in omp.target operation" );
306302 }
307303 }
308304 checkThreadLimit (op, result);
@@ -1290,6 +1286,41 @@ static LogicalResult allocAndInitializeReductionVars(
12901286 isByRef, deferredStores);
12911287}
12921288
1289+ // / Return the llvm::Value * corresponding to the `privateVar` that
1290+ // / is being privatized. It isn't always as simple as looking up
1291+ // / moduleTranslation with privateVar. For instance, in case of
1292+ // / an allocatable, the descriptor for the allocatable is privatized.
1293+ // / This descriptor is mapped using an MapInfoOp. So, this function
1294+ // / will return a pointer to the llvm::Value corresponding to the
1295+ // / block argument for the mapped descriptor.
1296+ static llvm::Value *
1297+ findAssociatedValue (Value privateVar, llvm::IRBuilderBase &builder,
1298+ LLVM::ModuleTranslation &moduleTranslation,
1299+ llvm::DenseMap<Value, Value> *mappedPrivateVars = nullptr ) {
1300+ if (mappedPrivateVars == nullptr || !mappedPrivateVars->contains (privateVar))
1301+ return moduleTranslation.lookupValue (privateVar);
1302+
1303+ Value blockArg = (*mappedPrivateVars)[privateVar];
1304+ Type privVarType = privateVar.getType ();
1305+ Type blockArgType = blockArg.getType ();
1306+ assert (isa<LLVM::LLVMPointerType>(blockArgType) &&
1307+ " A block argument corresponding to a mapped var should have "
1308+ " !llvm.ptr type" );
1309+
1310+ if (privVarType == blockArgType)
1311+ return moduleTranslation.lookupValue (blockArg);
1312+
1313+ // This typically happens when the privatized type is lowered from
1314+ // boxchar<KIND> and gets lowered to !llvm.struct<(ptr, i64)>. That is the
1315+ // struct/pair is passed by value. But, mapped values are passed only as
1316+ // pointers, so before we privatize, we must load the pointer.
1317+ if (!isa<LLVM::LLVMPointerType>(privVarType))
1318+ return builder.CreateLoad (moduleTranslation.convertType (privVarType),
1319+ moduleTranslation.lookupValue (blockArg));
1320+
1321+ return moduleTranslation.lookupValue (privateVar);
1322+ }
1323+
12931324// / Allocate delayed private variables. Returns the basic block which comes
12941325// / after all of these allocations. llvm::Value * for each of these private
12951326// / variables are populated in llvmPrivateVars.
@@ -1300,7 +1331,8 @@ allocatePrivateVars(llvm::IRBuilderBase &builder,
13001331 MutableArrayRef<omp::PrivateClauseOp> privateDecls,
13011332 MutableArrayRef<mlir::Value> mlirPrivateVars,
13021333 llvm::SmallVectorImpl<llvm::Value *> &llvmPrivateVars,
1303- const llvm::OpenMPIRBuilder::InsertPointTy &allocaIP) {
1334+ const llvm::OpenMPIRBuilder::InsertPointTy &allocaIP,
1335+ llvm::DenseMap<Value, Value> *mappedPrivateVars = nullptr ) {
13041336 llvm::IRBuilderBase::InsertPointGuard guard (builder);
13051337 // Allocate private vars
13061338 llvm::BranchInst *allocaTerminator =
@@ -1330,7 +1362,8 @@ allocatePrivateVars(llvm::IRBuilderBase &builder,
13301362 Region &allocRegion = privDecl.getAllocRegion ();
13311363
13321364 // map allocation region block argument
1333- llvm::Value *nonPrivateVar = moduleTranslation.lookupValue (mlirPrivVar);
1365+ llvm::Value *nonPrivateVar = findAssociatedValue (
1366+ mlirPrivVar, builder, moduleTranslation, mappedPrivateVars);
13341367 assert (nonPrivateVar);
13351368 moduleTranslation.mapValue (privDecl.getAllocMoldArg (), nonPrivateVar);
13361369
@@ -1345,6 +1378,7 @@ allocatePrivateVars(llvm::IRBuilderBase &builder,
13451378 } else {
13461379 builder.SetInsertPoint (privAllocBlock->getTerminator ());
13471380 }
1381+
13481382 if (failed (inlineConvertOmpRegions (allocRegion, " omp.private.alloc" ,
13491383 builder, moduleTranslation, &phis)))
13501384 return llvm::createStringError (
@@ -3829,6 +3863,17 @@ convertOmpTarget(Operation &opInst, llvm::IRBuilderBase &builder,
38293863 bool isTargetDevice = ompBuilder->Config .isTargetDevice ();
38303864 auto parentFn = opInst.getParentOfType <LLVM::LLVMFuncOp>();
38313865 auto &targetRegion = targetOp.getRegion ();
3866+ // Holds the private vars that have been mapped along with the block argument
3867+ // that corresponds to the MapInfoOp corresponding to the private var in
3868+ // question. So, for instance:
3869+ //
3870+ // %10 = omp.map.info var_ptr(%6#0 : !fir.ref<!fir.box<!fir.heap<i32>>>, ..)
3871+ // omp.target map_entries(%10 -> %arg0) private(@box.privatizer %6#0-> %arg1)
3872+ //
3873+ // Then, %10 has been created so that the descriptor can be used by the
3874+ // privatizer @box.privatizer on the device side. Here we'd record {%6#0,
3875+ // %arg0} in the mappedPrivateVars map.
3876+ llvm::DenseMap<Value, Value> mappedPrivateVars;
38323877 DataLayout dl = DataLayout (opInst.getParentOfType <ModuleOp>());
38333878 SmallVector<Value> mapVars = targetOp.getMapVars ();
38343879 ArrayRef<BlockArgument> mapBlockArgs =
@@ -3840,6 +3885,57 @@ convertOmpTarget(Operation &opInst, llvm::IRBuilderBase &builder,
38403885 bool isOffloadEntry =
38413886 isTargetDevice || !ompBuilder->Config .TargetTriples .empty ();
38423887
3888+ // For some private variables, the MapsForPrivatizedVariablesPass
3889+ // creates MapInfoOp instances. Go through the private variables and
3890+ // the mapped variables so that during codegeneration we are able
3891+ // to quickly look up the corresponding map variable, if any for each
3892+ // private variable.
3893+ if (!targetOp.getPrivateVars ().empty () && !targetOp.getMapVars ().empty ()) {
3894+ auto argIface = llvm::cast<omp::BlockArgOpenMPOpInterface>(*targetOp);
3895+ OperandRange privateVars = targetOp.getPrivateVars ();
3896+ std::optional<ArrayAttr> privateSyms = targetOp.getPrivateSyms ();
3897+ std::optional<DenseI64ArrayAttr> privateMapIndices =
3898+ targetOp.getPrivateMapsAttr ();
3899+
3900+ for (auto [privVarIdx, privVarSymPair] :
3901+ llvm::enumerate (llvm::zip_equal (privateVars, *privateSyms))) {
3902+ auto privVar = std::get<0 >(privVarSymPair);
3903+ auto privSym = std::get<1 >(privVarSymPair);
3904+
3905+ SymbolRefAttr privatizerName = llvm::cast<SymbolRefAttr>(privSym);
3906+ omp::PrivateClauseOp privatizer =
3907+ findPrivatizer (targetOp, privatizerName);
3908+
3909+ if (!privatizer.needsMap ())
3910+ continue ;
3911+
3912+ mlir::Value mappedValue =
3913+ targetOp.getMappedValueForPrivateVar (privVarIdx);
3914+ assert (mappedValue && " Expected to find mapped value for a privatized "
3915+ " variable that needs mapping" );
3916+
3917+ // The MapInfoOp defining the map var isn't really needed later.
3918+ // So, we don't store it in any datastructure. Instead, we just
3919+ // do some sanity checks on it right now.
3920+ auto mapInfoOp = mappedValue.getDefiningOp <omp::MapInfoOp>();
3921+ Type varType = mapInfoOp.getVarType ();
3922+
3923+ // Check #1: Check that the type of the private variable matches
3924+ // the type of the variable being mapped.
3925+ if (!isa<LLVM::LLVMPointerType>(privVar.getType ()))
3926+ assert (
3927+ varType == privVar.getType () &&
3928+ " Type of private var doesn't match the type of the mapped value" );
3929+
3930+ // Ok, only 1 sanity check for now.
3931+ // Record the block argument corresponding to this mapvar.
3932+ mappedPrivateVars.insert (
3933+ {privVar,
3934+ targetRegion.getArgument (argIface.getMapBlockArgsStart () +
3935+ (*privateMapIndices)[privVarIdx])});
3936+ }
3937+ }
3938+
38433939 using InsertPointTy = llvm::OpenMPIRBuilder::InsertPointTy;
38443940 auto bodyCB = [&](InsertPointTy allocaIP, InsertPointTy codeGenIP)
38453941 -> llvm::OpenMPIRBuilder::InsertPointOrErrorTy {
@@ -3859,7 +3955,6 @@ convertOmpTarget(Operation &opInst, llvm::IRBuilderBase &builder,
38593955 attr.isStringAttribute ())
38603956 llvmOutlinedFn->addFnAttr (attr);
38613957
3862- builder.restoreIP (codeGenIP);
38633958 for (auto [arg, mapOp] : llvm::zip_equal (mapBlockArgs, mapVars)) {
38643959 auto mapInfoOp = cast<omp::MapInfoOp>(mapOp.getDefiningOp ());
38653960 llvm::Value *mapOpValue =
@@ -3869,50 +3964,52 @@ convertOmpTarget(Operation &opInst, llvm::IRBuilderBase &builder,
38693964
38703965 // Do privatization after moduleTranslation has already recorded
38713966 // mapped values.
3872- if (!targetOp.getPrivateVars ().empty ()) {
3873- builder.restoreIP (allocaIP);
3874-
3875- OperandRange privateVars = targetOp.getPrivateVars ();
3876- std::optional<ArrayAttr> privateSyms = targetOp.getPrivateSyms ();
3877- MutableArrayRef<BlockArgument> privateBlockArgs =
3878- cast<omp::BlockArgOpenMPOpInterface>(opInst).getPrivateBlockArgs ();
3879-
3880- for (auto [privVar, privatizerNameAttr, privBlockArg] :
3881- llvm::zip_equal (privateVars, *privateSyms, privateBlockArgs)) {
3882-
3883- SymbolRefAttr privSym = cast<SymbolRefAttr>(privatizerNameAttr);
3884- omp::PrivateClauseOp privatizer = findPrivatizer (&opInst, privSym);
3885- assert (privatizer.getDataSharingType () !=
3886- omp::DataSharingClauseType::FirstPrivate &&
3887- privatizer.getDeallocRegion ().empty () &&
3888- " unsupported privatizer" );
3889- moduleTranslation.mapValue (privatizer.getAllocMoldArg (),
3890- moduleTranslation.lookupValue (privVar));
3891- Region &allocRegion = privatizer.getAllocRegion ();
3892- SmallVector<llvm::Value *, 1 > yieldedValues;
3893- if (failed (inlineConvertOmpRegions (
3894- allocRegion, " omp.targetop.privatizer" , builder,
3895- moduleTranslation, &yieldedValues))) {
3896- return llvm::createStringError (
3897- " failed to inline `alloc` region of `omp.private`" );
3898- }
3899- assert (yieldedValues.size () == 1 );
3900- moduleTranslation.mapValue (privBlockArg, yieldedValues.front ());
3901- moduleTranslation.forgetMapping (allocRegion);
3902- builder.restoreIP (builder.saveIP ());
3903- }
3904- }
3967+ MutableArrayRef<BlockArgument> privateBlockArgs =
3968+ cast<omp::BlockArgOpenMPOpInterface>(opInst).getPrivateBlockArgs ();
3969+ SmallVector<mlir::Value> mlirPrivateVars;
3970+ SmallVector<llvm::Value *> llvmPrivateVars;
3971+ SmallVector<omp::PrivateClauseOp> privateDecls;
3972+ mlirPrivateVars.reserve (privateBlockArgs.size ());
3973+ llvmPrivateVars.reserve (privateBlockArgs.size ());
3974+ collectPrivatizationDecls (targetOp, privateDecls);
3975+ for (mlir::Value privateVar : targetOp.getPrivateVars ())
3976+ mlirPrivateVars.push_back (privateVar);
3977+
3978+ llvm::Expected<llvm::BasicBlock *> afterAllocas = allocatePrivateVars (
3979+ builder, moduleTranslation, privateBlockArgs, privateDecls,
3980+ mlirPrivateVars, llvmPrivateVars, allocaIP, &mappedPrivateVars);
39053981
3982+ if (failed (handleError (afterAllocas, *targetOp)))
3983+ return llvm::make_error<PreviouslyReportedError>();
3984+
3985+ SmallVector<Region *> privateCleanupRegions;
3986+ llvm::transform (privateDecls, std::back_inserter (privateCleanupRegions),
3987+ [](omp::PrivateClauseOp privatizer) {
3988+ return &privatizer.getDeallocRegion ();
3989+ });
3990+
3991+ builder.restoreIP (codeGenIP);
39063992 llvm::Expected<llvm::BasicBlock *> exitBlock = convertOmpOpRegions (
39073993 targetRegion, " omp.target" , builder, moduleTranslation);
3994+
39083995 if (!exitBlock)
39093996 return exitBlock.takeError ();
39103997
39113998 builder.SetInsertPoint (*exitBlock);
3912- return builder.saveIP ();
3999+ if (!privateCleanupRegions.empty ()) {
4000+ if (failed (inlineOmpRegionCleanup (
4001+ privateCleanupRegions, llvmPrivateVars, moduleTranslation,
4002+ builder, " omp.targetop.private.cleanup" ,
4003+ /* shouldLoadCleanupRegionArg=*/ false ))) {
4004+ return llvm::createStringError (
4005+ " failed to inline `dealloc` region of `omp.private` "
4006+ " op in the target region" );
4007+ }
4008+ }
4009+
4010+ return InsertPointTy (exitBlock.get (), exitBlock.get ()->end ());
39134011 };
39144012
3915- llvm::OpenMPIRBuilder::LocationDescription ompLoc (builder);
39164013 StringRef parentName = parentFn.getName ();
39174014
39184015 llvm::TargetRegionEntryInfo entryInfo;
@@ -3923,9 +4020,6 @@ convertOmpTarget(Operation &opInst, llvm::IRBuilderBase &builder,
39234020 int32_t defaultValTeams = -1 ;
39244021 int32_t defaultValThreads = 0 ;
39254022
3926- llvm::OpenMPIRBuilder::InsertPointTy allocaIP =
3927- findAllocaInsertPoint (builder, moduleTranslation);
3928-
39294023 MapInfoData mapData;
39304024 collectMapDataFromMapOperands (mapData, mapVars, moduleTranslation, dl,
39314025 builder);
@@ -3973,6 +4067,10 @@ convertOmpTarget(Operation &opInst, llvm::IRBuilderBase &builder,
39734067 buildDependData (targetOp.getDependKinds (), targetOp.getDependVars (),
39744068 moduleTranslation, dds);
39754069
4070+ llvm::OpenMPIRBuilder::InsertPointTy allocaIP =
4071+ findAllocaInsertPoint (builder, moduleTranslation);
4072+ llvm::OpenMPIRBuilder::LocationDescription ompLoc (builder);
4073+
39764074 llvm::OpenMPIRBuilder::InsertPointOrErrorTy afterIP =
39774075 moduleTranslation.getOpenMPBuilder ()->createTarget (
39784076 ompLoc, isOffloadEntry, allocaIP, builder.saveIP (), entryInfo,
0 commit comments