155 lines · cpp
1//===- AutomapToTargetData.cpp -------------------------------------------===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8 9#include "flang/Optimizer/Builder/DirectivesCommon.h"10#include "flang/Optimizer/Builder/FIRBuilder.h"11#include "flang/Optimizer/Builder/HLFIRTools.h"12#include "flang/Optimizer/Dialect/FIROps.h"13#include "flang/Optimizer/Dialect/FIRType.h"14#include "flang/Optimizer/Dialect/Support/KindMapping.h"15#include "flang/Optimizer/HLFIR/HLFIROps.h"16 17#include "mlir/Dialect/OpenMP/OpenMPDialect.h"18#include "mlir/Dialect/OpenMP/OpenMPInterfaces.h"19#include "mlir/IR/BuiltinAttributes.h"20#include "mlir/IR/Operation.h"21#include "mlir/Pass/Pass.h"22 23namespace flangomp {24#define GEN_PASS_DEF_AUTOMAPTOTARGETDATAPASS25#include "flang/Optimizer/OpenMP/Passes.h.inc"26} // namespace flangomp27 28using namespace mlir;29 30namespace {31class AutomapToTargetDataPass32 : public flangomp::impl::AutomapToTargetDataPassBase<33 AutomapToTargetDataPass> {34 35 // Returns true if the variable has a dynamic size and therefore requires36 // bounds operations to describe its extents.37 inline bool needsBoundsOps(mlir::Value var) {38 assert(mlir::isa<mlir::omp::PointerLikeType>(var.getType()) &&39 "only pointer like types expected");40 mlir::Type t = fir::unwrapRefType(var.getType());41 if (mlir::Type inner = fir::dyn_cast_ptrOrBoxEleTy(t))42 return fir::hasDynamicSize(inner);43 return fir::hasDynamicSize(t);44 }45 46 // Generate MapBoundsOp operations for the variable if required.47 inline void genBoundsOps(fir::FirOpBuilder &builder, mlir::Value var,48 llvm::SmallVectorImpl<mlir::Value> &boundsOps) {49 mlir::Location loc = var.getLoc();50 fir::factory::AddrAndBoundsInfo info =51 fir::factory::getDataOperandBaseAddr(builder, var,52 /*isOptional=*/false, loc);53 fir::ExtendedValue exv =54 hlfir::translateToExtendedValue(loc, builder, hlfir::Entity{info.addr},55 /*contiguousHint=*/true)56 .first;57 llvm::SmallVector<mlir::Value> tmp =58 fir::factory::genImplicitBoundsOps<mlir::omp::MapBoundsOp,59 mlir::omp::MapBoundsType>(60 builder, info, exv, /*dataExvIsAssumedSize=*/false, loc);61 llvm::append_range(boundsOps, tmp);62 }63 64 void findRelatedAllocmemFreemem(fir::AddrOfOp addressOfOp,65 llvm::DenseSet<fir::StoreOp> &allocmems,66 llvm::DenseSet<fir::LoadOp> &freemems) {67 assert(addressOfOp->hasOneUse() && "op must have single use");68 69 auto declaredRef =70 cast<hlfir::DeclareOp>(*addressOfOp->getUsers().begin())->getResult(0);71 72 for (Operation *refUser : declaredRef.getUsers()) {73 if (auto storeOp = dyn_cast<fir::StoreOp>(refUser))74 if (auto emboxOp = storeOp.getValue().getDefiningOp<fir::EmboxOp>())75 if (auto allocmemOp =76 emboxOp.getOperand(0).getDefiningOp<fir::AllocMemOp>())77 allocmems.insert(storeOp);78 79 if (auto loadOp = dyn_cast<fir::LoadOp>(refUser))80 for (Operation *loadUser : loadOp.getResult().getUsers())81 if (auto boxAddrOp = dyn_cast<fir::BoxAddrOp>(loadUser))82 for (Operation *boxAddrUser : boxAddrOp.getResult().getUsers())83 if (auto freememOp = dyn_cast<fir::FreeMemOp>(boxAddrUser))84 freemems.insert(loadOp);85 }86 }87 88 void runOnOperation() override {89 ModuleOp module = getOperation()->getParentOfType<ModuleOp>();90 if (!module)91 module = dyn_cast<ModuleOp>(getOperation());92 if (!module)93 return;94 95 // Build FIR builder for helper utilities.96 fir::KindMapping kindMap = fir::getKindMapping(module);97 fir::FirOpBuilder builder{module, std::move(kindMap)};98 99 // Collect global variables with AUTOMAP flag.100 llvm::DenseSet<fir::GlobalOp> automapGlobals;101 module.walk([&](fir::GlobalOp globalOp) {102 if (auto iface =103 dyn_cast<omp::DeclareTargetInterface>(globalOp.getOperation()))104 if (iface.isDeclareTarget() && iface.getDeclareTargetAutomap() &&105 iface.getDeclareTargetDeviceType() !=106 omp::DeclareTargetDeviceType::host)107 automapGlobals.insert(globalOp);108 });109 110 auto addMapInfo = [&](auto globalOp, auto memOp) {111 builder.setInsertionPointAfter(memOp);112 SmallVector<Value> bounds;113 if (needsBoundsOps(memOp.getMemref()))114 genBoundsOps(builder, memOp.getMemref(), bounds);115 116 omp::TargetEnterExitUpdateDataOperands clauses;117 mlir::omp::MapInfoOp mapInfo = mlir::omp::MapInfoOp::create(118 builder, memOp.getLoc(), memOp.getMemref().getType(),119 memOp.getMemref(),120 TypeAttr::get(fir::unwrapRefType(memOp.getMemref().getType())),121 builder.getAttr<omp::ClauseMapFlagsAttr>(122 isa<fir::StoreOp>(memOp) ? omp::ClauseMapFlags::to123 : omp::ClauseMapFlags::del),124 builder.getAttr<omp::VariableCaptureKindAttr>(125 omp::VariableCaptureKind::ByCopy),126 /*var_ptr_ptr=*/mlir::Value{},127 /*members=*/SmallVector<Value>{},128 /*members_index=*/ArrayAttr{}, bounds,129 /*mapperId=*/mlir::FlatSymbolRefAttr(), globalOp.getSymNameAttr(),130 builder.getBoolAttr(false));131 clauses.mapVars.push_back(mapInfo);132 isa<fir::StoreOp>(memOp)133 ? omp::TargetEnterDataOp::create(builder, memOp.getLoc(), clauses)134 : omp::TargetExitDataOp::create(builder, memOp.getLoc(), clauses);135 };136 137 for (fir::GlobalOp globalOp : automapGlobals) {138 if (auto uses = globalOp.getSymbolUses(module.getOperation())) {139 llvm::DenseSet<fir::StoreOp> allocmemStores;140 llvm::DenseSet<fir::LoadOp> freememLoads;141 for (auto &x : *uses)142 if (auto addrOp = dyn_cast<fir::AddrOfOp>(x.getUser()))143 findRelatedAllocmemFreemem(addrOp, allocmemStores, freememLoads);144 145 for (auto storeOp : allocmemStores)146 addMapInfo(globalOp, storeOp);147 148 for (auto loadOp : freememLoads)149 addMapInfo(globalOp, loadOp);150 }151 }152 }153};154} // namespace155