@@ -299,10 +299,6 @@ static LogicalResult checkImplementationStatus(Operation &op) {
299
299
if (privatizer.getDataSharingType () ==
300
300
omp::DataSharingClauseType::FirstPrivate)
301
301
result = todo (" firstprivate" );
302
-
303
- if (!privatizer.getDeallocRegion ().empty ())
304
- result = op.emitError (" not yet implemented: privatization of "
305
- " structures in omp.target operation" );
306
302
}
307
303
}
308
304
checkThreadLimit (op, result);
@@ -1290,6 +1286,41 @@ static LogicalResult allocAndInitializeReductionVars(
1290
1286
isByRef, deferredStores);
1291
1287
}
1292
1288
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
+
1293
1324
// / Allocate delayed private variables. Returns the basic block which comes
1294
1325
// / after all of these allocations. llvm::Value * for each of these private
1295
1326
// / variables are populated in llvmPrivateVars.
@@ -1300,7 +1331,8 @@ allocatePrivateVars(llvm::IRBuilderBase &builder,
1300
1331
MutableArrayRef<omp::PrivateClauseOp> privateDecls,
1301
1332
MutableArrayRef<mlir::Value> mlirPrivateVars,
1302
1333
llvm::SmallVectorImpl<llvm::Value *> &llvmPrivateVars,
1303
- const llvm::OpenMPIRBuilder::InsertPointTy &allocaIP) {
1334
+ const llvm::OpenMPIRBuilder::InsertPointTy &allocaIP,
1335
+ llvm::DenseMap<Value, Value> *mappedPrivateVars = nullptr ) {
1304
1336
llvm::IRBuilderBase::InsertPointGuard guard (builder);
1305
1337
// Allocate private vars
1306
1338
llvm::BranchInst *allocaTerminator =
@@ -1330,7 +1362,8 @@ allocatePrivateVars(llvm::IRBuilderBase &builder,
1330
1362
Region &allocRegion = privDecl.getAllocRegion ();
1331
1363
1332
1364
// map allocation region block argument
1333
- llvm::Value *nonPrivateVar = moduleTranslation.lookupValue (mlirPrivVar);
1365
+ llvm::Value *nonPrivateVar = findAssociatedValue (
1366
+ mlirPrivVar, builder, moduleTranslation, mappedPrivateVars);
1334
1367
assert (nonPrivateVar);
1335
1368
moduleTranslation.mapValue (privDecl.getAllocMoldArg (), nonPrivateVar);
1336
1369
@@ -1345,6 +1378,7 @@ allocatePrivateVars(llvm::IRBuilderBase &builder,
1345
1378
} else {
1346
1379
builder.SetInsertPoint (privAllocBlock->getTerminator ());
1347
1380
}
1381
+
1348
1382
if (failed (inlineConvertOmpRegions (allocRegion, " omp.private.alloc" ,
1349
1383
builder, moduleTranslation, &phis)))
1350
1384
return llvm::createStringError (
@@ -3829,6 +3863,17 @@ convertOmpTarget(Operation &opInst, llvm::IRBuilderBase &builder,
3829
3863
bool isTargetDevice = ompBuilder->Config .isTargetDevice ();
3830
3864
auto parentFn = opInst.getParentOfType <LLVM::LLVMFuncOp>();
3831
3865
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;
3832
3877
DataLayout dl = DataLayout (opInst.getParentOfType <ModuleOp>());
3833
3878
SmallVector<Value> mapVars = targetOp.getMapVars ();
3834
3879
ArrayRef<BlockArgument> mapBlockArgs =
@@ -3840,6 +3885,57 @@ convertOmpTarget(Operation &opInst, llvm::IRBuilderBase &builder,
3840
3885
bool isOffloadEntry =
3841
3886
isTargetDevice || !ompBuilder->Config .TargetTriples .empty ();
3842
3887
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
+
3843
3939
using InsertPointTy = llvm::OpenMPIRBuilder::InsertPointTy;
3844
3940
auto bodyCB = [&](InsertPointTy allocaIP, InsertPointTy codeGenIP)
3845
3941
-> llvm::OpenMPIRBuilder::InsertPointOrErrorTy {
@@ -3859,7 +3955,6 @@ convertOmpTarget(Operation &opInst, llvm::IRBuilderBase &builder,
3859
3955
attr.isStringAttribute ())
3860
3956
llvmOutlinedFn->addFnAttr (attr);
3861
3957
3862
- builder.restoreIP (codeGenIP);
3863
3958
for (auto [arg, mapOp] : llvm::zip_equal (mapBlockArgs, mapVars)) {
3864
3959
auto mapInfoOp = cast<omp::MapInfoOp>(mapOp.getDefiningOp ());
3865
3960
llvm::Value *mapOpValue =
@@ -3869,50 +3964,52 @@ convertOmpTarget(Operation &opInst, llvm::IRBuilderBase &builder,
3869
3964
3870
3965
// Do privatization after moduleTranslation has already recorded
3871
3966
// 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);
3905
3981
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);
3906
3992
llvm::Expected<llvm::BasicBlock *> exitBlock = convertOmpOpRegions (
3907
3993
targetRegion, " omp.target" , builder, moduleTranslation);
3994
+
3908
3995
if (!exitBlock)
3909
3996
return exitBlock.takeError ();
3910
3997
3911
3998
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 ());
3913
4011
};
3914
4012
3915
- llvm::OpenMPIRBuilder::LocationDescription ompLoc (builder);
3916
4013
StringRef parentName = parentFn.getName ();
3917
4014
3918
4015
llvm::TargetRegionEntryInfo entryInfo;
@@ -3923,9 +4020,6 @@ convertOmpTarget(Operation &opInst, llvm::IRBuilderBase &builder,
3923
4020
int32_t defaultValTeams = -1 ;
3924
4021
int32_t defaultValThreads = 0 ;
3925
4022
3926
- llvm::OpenMPIRBuilder::InsertPointTy allocaIP =
3927
- findAllocaInsertPoint (builder, moduleTranslation);
3928
-
3929
4023
MapInfoData mapData;
3930
4024
collectMapDataFromMapOperands (mapData, mapVars, moduleTranslation, dl,
3931
4025
builder);
@@ -3973,6 +4067,10 @@ convertOmpTarget(Operation &opInst, llvm::IRBuilderBase &builder,
3973
4067
buildDependData (targetOp.getDependKinds (), targetOp.getDependVars (),
3974
4068
moduleTranslation, dds);
3975
4069
4070
+ llvm::OpenMPIRBuilder::InsertPointTy allocaIP =
4071
+ findAllocaInsertPoint (builder, moduleTranslation);
4072
+ llvm::OpenMPIRBuilder::LocationDescription ompLoc (builder);
4073
+
3976
4074
llvm::OpenMPIRBuilder::InsertPointOrErrorTy afterIP =
3977
4075
moduleTranslation.getOpenMPBuilder ()->createTarget (
3978
4076
ompLoc, isOffloadEntry, allocaIP, builder.saveIP (), entryInfo,
0 commit comments