@@ -305,10 +305,6 @@ static LogicalResult checkImplementationStatus(Operation &op) {
305305 if (privatizer.getDataSharingType () ==
306306 omp::DataSharingClauseType::FirstPrivate)
307307 result = todo (" firstprivate" );
308-
309- if (!privatizer.getDeallocRegion ().empty ())
310- result = op.emitError (" not yet implemented: privatization of "
311- " structures in omp.target operation" );
312308 }
313309 }
314310 checkThreadLimit (op, result);
@@ -3814,6 +3810,43 @@ createDeviceArgumentAccessor(MapInfoData &mapData, llvm::Argument &arg,
38143810 return builder.saveIP ();
38153811}
38163812
3813+ // / Return the llvm::Value * corresponding to the `privateVar` that
3814+ // / is being privatized. It isn't always as simple as looking up
3815+ // / moduleTranslation with privateVar. For instance, in case of
3816+ // / an allocatable, the descriptor for the allocatable is privatized.
3817+ // / This descriptor is mapped using an MapInfoOp. So, this function
3818+ // / will return a pointer to the llvm::Value corresponding to the
3819+ // / block argument for the mapped descriptor.
3820+ static llvm::Value *
3821+ findHostAssociatedValue (Value privateVar, omp::TargetOp targetOp,
3822+ llvm::DenseMap<Value, int > &mappedPrivateVars,
3823+ llvm::IRBuilderBase &builder,
3824+ LLVM::ModuleTranslation &moduleTranslation) {
3825+ if (mappedPrivateVars.contains (privateVar)) {
3826+ int blockArgIndex = mappedPrivateVars[privateVar];
3827+ Value blockArg = targetOp.getRegion ().getArgument (blockArgIndex);
3828+ Type privVarType = privateVar.getType ();
3829+ Type blockArgType = blockArg.getType ();
3830+ assert (isa<LLVM::LLVMPointerType>(blockArgType) &&
3831+ " A block argument corresponding to a mapped var should have "
3832+ " !llvm.ptr type" );
3833+
3834+ if (privVarType == blockArg.getType ())
3835+ return moduleTranslation.lookupValue (blockArg);
3836+
3837+ if (!isa<LLVM::LLVMPointerType>(privVarType)) {
3838+ // This typically happens when the privatized type is lowered from
3839+ // boxchar<KIND> and gets lowered to !llvm.struct<(ptr, i64)>. That is the
3840+ // struct/pair is passed by value. But, mapped values are passed only as
3841+ // pointers, so before we privatize, we must load the pointer.
3842+ llvm::Value *load =
3843+ builder.CreateLoad (moduleTranslation.convertType (privVarType),
3844+ moduleTranslation.lookupValue (blockArg));
3845+ return load;
3846+ }
3847+ }
3848+ return moduleTranslation.lookupValue (privateVar);
3849+ }
38173850static LogicalResult
38183851convertOmpTarget (Operation &opInst, llvm::IRBuilderBase &builder,
38193852 LLVM::ModuleTranslation &moduleTranslation) {
@@ -3825,6 +3858,19 @@ convertOmpTarget(Operation &opInst, llvm::IRBuilderBase &builder,
38253858 bool isTargetDevice = ompBuilder->Config .isTargetDevice ();
38263859 auto parentFn = opInst.getParentOfType <LLVM::LLVMFuncOp>();
38273860 auto &targetRegion = targetOp.getRegion ();
3861+ // Holds the private vars that have been mapped along with
3862+ // the block argument that corresponds to the MapInfoOp
3863+ // corresponding to the private var in question.
3864+ // So, for instance
3865+ //
3866+ // %10 = omp.map.info var_ptr(%6#0 : !fir.ref<!fir.box<!fir.heap<i32>>>, ..)
3867+ // omp.target map_entries(%10 -> %arg0) private(@box.privatizer %6#0-> %arg1)
3868+ //
3869+ // Then, %10 has been created so that the descriptor can be used by the
3870+ // privatizer
3871+ // @box.privatizer on the device side. Here we'd record {%6#0, 0} in the
3872+ // mappedPrivateVars map.
3873+ llvm::DenseMap<Value, int > mappedPrivateVars;
38283874 DataLayout dl = DataLayout (opInst.getParentOfType <ModuleOp>());
38293875 SmallVector<Value> mapVars = targetOp.getMapVars ();
38303876 ArrayRef<BlockArgument> mapBlockArgs =
@@ -3836,6 +3882,55 @@ convertOmpTarget(Operation &opInst, llvm::IRBuilderBase &builder,
38363882 bool isOffloadEntry =
38373883 isTargetDevice || !ompBuilder->Config .TargetTriples .empty ();
38383884
3885+ // For some private variables, the MapsForPrivatizedVariablesPass
3886+ // creates MapInfoOp instances. Go through the private variables and
3887+ // the mapped variables so that during codegeneration we are able
3888+ // to quickly look up the corresponding map variable, if any for each
3889+ // private variable.
3890+ if (!targetOp.getPrivateVars ().empty () && !targetOp.getMapVars ().empty ()) {
3891+ auto argIface = llvm::cast<omp::BlockArgOpenMPOpInterface>(*targetOp);
3892+ OperandRange privateVars = targetOp.getPrivateVars ();
3893+ std::optional<ArrayAttr> privateSyms = targetOp.getPrivateSyms ();
3894+ std::optional<DenseI64ArrayAttr> privateMapIndices =
3895+ targetOp.getPrivateMapsAttr ();
3896+
3897+ for (auto [privVarIdx, privVarSymPair] :
3898+ llvm::enumerate (llvm::zip_equal (privateVars, *privateSyms))) {
3899+ auto privVar = std::get<0 >(privVarSymPair);
3900+ auto privSym = std::get<1 >(privVarSymPair);
3901+
3902+ SymbolRefAttr privatizerName = llvm::cast<SymbolRefAttr>(privSym);
3903+ omp::PrivateClauseOp privatizer =
3904+ findPrivatizer (targetOp, privatizerName);
3905+
3906+ if (!privatizer.needsMap ())
3907+ continue ;
3908+
3909+ mlir::Value mappedValue =
3910+ targetOp.getMappedValueForPrivateVar (privVarIdx);
3911+ assert (mappedValue);
3912+
3913+ // The MapInfoOp defining the map var isn't really needed later.
3914+ // So, we don't store it in any datastructure. Instead, we just
3915+ // do some sanity checks on it right now.
3916+ auto mapInfoOp = mappedValue.getDefiningOp <omp::MapInfoOp>();
3917+ Type varType = mapInfoOp.getVarType ();
3918+
3919+ // Check #1: Check that the type of the private variable matches
3920+ // the type of the variable being mapped.
3921+ if (!isa<LLVM::LLVMPointerType>(privVar.getType ()))
3922+ assert (
3923+ varType == privVar.getType () &&
3924+ " Type of private var doesn't match the type of the mapped value" );
3925+
3926+ // Ok, only 1 sanity check for now.
3927+ // Record the index of the block argument corresponding to this
3928+ // mapvar.
3929+ mappedPrivateVars.insert ({privVar, argIface.getMapBlockArgsStart () +
3930+ (*privateMapIndices)[privVarIdx]});
3931+ }
3932+ }
3933+
38393934 using InsertPointTy = llvm::OpenMPIRBuilder::InsertPointTy;
38403935 auto bodyCB = [&](InsertPointTy allocaIP, InsertPointTy codeGenIP)
38413936 -> llvm::OpenMPIRBuilder::InsertPointOrErrorTy {
@@ -3862,9 +3957,10 @@ convertOmpTarget(Operation &opInst, llvm::IRBuilderBase &builder,
38623957 moduleTranslation.lookupValue (mapInfoOp.getVarPtr ());
38633958 moduleTranslation.mapValue (arg, mapOpValue);
38643959 }
3865-
38663960 // Do privatization after moduleTranslation has already recorded
38673961 // mapped values.
3962+ SmallVector<llvm::Value *> llvmPrivateVars;
3963+ SmallVector<Region *> privateCleanupRegions;
38683964 if (!targetOp.getPrivateVars ().empty ()) {
38693965 builder.restoreIP (allocaIP);
38703966
@@ -3880,11 +3976,13 @@ convertOmpTarget(Operation &opInst, llvm::IRBuilderBase &builder,
38803976 omp::PrivateClauseOp privatizer = findPrivatizer (&opInst, privSym);
38813977 assert (privatizer.getDataSharingType () !=
38823978 omp::DataSharingClauseType::FirstPrivate &&
3883- privatizer.getDeallocRegion ().empty () &&
38843979 " unsupported privatizer" );
3885- moduleTranslation.mapValue (privatizer.getAllocMoldArg (),
3886- moduleTranslation.lookupValue (privVar));
38873980 Region &allocRegion = privatizer.getAllocRegion ();
3981+ BlockArgument allocRegionArg = allocRegion.getArgument (0 );
3982+ moduleTranslation.mapValue (
3983+ allocRegionArg,
3984+ findHostAssociatedValue (privVar, targetOp, mappedPrivateVars,
3985+ builder, moduleTranslation));
38883986 SmallVector<llvm::Value *, 1 > yieldedValues;
38893987 if (failed (inlineConvertOmpRegions (
38903988 allocRegion, " omp.targetop.privatizer" , builder,
@@ -3893,7 +3991,12 @@ convertOmpTarget(Operation &opInst, llvm::IRBuilderBase &builder,
38933991 " failed to inline `alloc` region of `omp.private`" );
38943992 }
38953993 assert (yieldedValues.size () == 1 );
3896- moduleTranslation.mapValue (privBlockArg, yieldedValues.front ());
3994+ llvm::Value *llvmReplacementValue = yieldedValues.front ();
3995+ moduleTranslation.mapValue (privBlockArg, llvmReplacementValue);
3996+ if (!privatizer.getDeallocRegion ().empty ()) {
3997+ llvmPrivateVars.push_back (llvmReplacementValue);
3998+ privateCleanupRegions.push_back (&privatizer.getDeallocRegion ());
3999+ }
38974000 moduleTranslation.forgetMapping (allocRegion);
38984001 builder.restoreIP (builder.saveIP ());
38994002 }
@@ -3905,6 +4008,19 @@ convertOmpTarget(Operation &opInst, llvm::IRBuilderBase &builder,
39054008 return exitBlock.takeError ();
39064009
39074010 builder.SetInsertPoint (*exitBlock);
4011+ if (!llvmPrivateVars.empty ()) {
4012+ assert (llvmPrivateVars.size () == privateCleanupRegions.size () &&
4013+ " Number of private variables needing cleanup not equal to number"
4014+ " of privatizers with dealloc regions" );
4015+ if (failed (inlineOmpRegionCleanup (
4016+ privateCleanupRegions, llvmPrivateVars, moduleTranslation,
4017+ builder, " omp.targetop.private.cleanup" ,
4018+ /* shouldLoadCleanupRegionArg=*/ false ))) {
4019+ return llvm::createStringError (
4020+ " failed to inline `dealloc` region of `omp.private` "
4021+ " op in the target region" );
4022+ }
4023+ }
39084024 return builder.saveIP ();
39094025 };
39104026
0 commit comments