159 lines · cpp
1//===-- lib/Utisl/OpenMP.cpp ------------------------------------*- C++ -*-===//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/Utils/OpenMP.h"10 11#include "flang/Lower/ConvertExprToHLFIR.h"12#include "flang/Optimizer/Builder/DirectivesCommon.h"13#include "flang/Optimizer/Builder/FIRBuilder.h"14#include "flang/Optimizer/Dialect/FIROps.h"15#include "flang/Optimizer/Dialect/FIRType.h"16 17#include "mlir/Dialect/OpenMP/OpenMPDialect.h"18#include "mlir/Transforms/RegionUtils.h"19 20namespace Fortran::utils::openmp {21mlir::omp::MapInfoOp createMapInfoOp(mlir::OpBuilder &builder,22 mlir::Location loc, mlir::Value baseAddr, mlir::Value varPtrPtr,23 llvm::StringRef name, llvm::ArrayRef<mlir::Value> bounds,24 llvm::ArrayRef<mlir::Value> members, mlir::ArrayAttr membersIndex,25 mlir::omp::ClauseMapFlags mapType,26 mlir::omp::VariableCaptureKind mapCaptureType, mlir::Type retTy,27 bool partialMap, mlir::FlatSymbolRefAttr mapperId) {28 29 if (auto boxTy = llvm::dyn_cast<fir::BaseBoxType>(baseAddr.getType())) {30 baseAddr = fir::BoxAddrOp::create(builder, loc, baseAddr);31 retTy = baseAddr.getType();32 }33 34 mlir::TypeAttr varType = mlir::TypeAttr::get(35 llvm::cast<mlir::omp::PointerLikeType>(retTy).getElementType());36 37 // For types with unknown extents such as <2x?xi32> we discard the incomplete38 // type info and only retain the base type. The correct dimensions are later39 // recovered through the bounds info.40 if (auto seqType = llvm::dyn_cast<fir::SequenceType>(varType.getValue()))41 if (seqType.hasDynamicExtents())42 varType = mlir::TypeAttr::get(seqType.getEleTy());43 44 mlir::omp::MapInfoOp op =45 mlir::omp::MapInfoOp::create(builder, loc, retTy, baseAddr, varType,46 builder.getAttr<mlir::omp::ClauseMapFlagsAttr>(mapType),47 builder.getAttr<mlir::omp::VariableCaptureKindAttr>(mapCaptureType),48 varPtrPtr, members, membersIndex, bounds, mapperId,49 builder.getStringAttr(name), builder.getBoolAttr(partialMap));50 return op;51}52 53mlir::Value mapTemporaryValue(fir::FirOpBuilder &firOpBuilder,54 mlir::omp::TargetOp targetOp, mlir::Value val, llvm::StringRef name) {55 mlir::OpBuilder::InsertionGuard guard(firOpBuilder);56 mlir::Operation *valOp = val.getDefiningOp();57 58 if (valOp)59 firOpBuilder.setInsertionPointAfter(valOp);60 else61 // This means val is a block argument62 firOpBuilder.setInsertionPoint(targetOp);63 64 auto copyVal = firOpBuilder.createTemporary(val.getLoc(), val.getType());65 firOpBuilder.createStoreWithConvert(copyVal.getLoc(), val, copyVal);66 67 fir::factory::AddrAndBoundsInfo info = fir::factory::getDataOperandBaseAddr(68 firOpBuilder, val, /*isOptional=*/false, val.getLoc());69 llvm::SmallVector<mlir::Value> bounds =70 fir::factory::genImplicitBoundsOps<mlir::omp::MapBoundsOp,71 mlir::omp::MapBoundsType>(firOpBuilder, info,72 hlfir::translateToExtendedValue(73 val.getLoc(), firOpBuilder, hlfir::Entity{val})74 .first,75 /*dataExvIsAssumedSize=*/false, val.getLoc());76 77 firOpBuilder.setInsertionPoint(targetOp);78 79 mlir::omp::ClauseMapFlags mapFlag = mlir::omp::ClauseMapFlags::implicit;80 mlir::omp::VariableCaptureKind captureKind =81 mlir::omp::VariableCaptureKind::ByRef;82 83 mlir::Type eleType = copyVal.getType();84 if (auto refType = mlir::dyn_cast<fir::ReferenceType>(copyVal.getType())) {85 eleType = refType.getElementType();86 }87 88 if (fir::isa_trivial(eleType) || fir::isa_char(eleType)) {89 captureKind = mlir::omp::VariableCaptureKind::ByCopy;90 } else if (!fir::isa_builtin_cptr_type(eleType)) {91 mapFlag |= mlir::omp::ClauseMapFlags::to;92 }93 94 mlir::Value mapOp = createMapInfoOp(firOpBuilder, copyVal.getLoc(), copyVal,95 /*varPtrPtr=*/mlir::Value{}, name.str(), bounds,96 /*members=*/llvm::SmallVector<mlir::Value>{},97 /*membersIndex=*/mlir::ArrayAttr{}, mapFlag, captureKind,98 copyVal.getType());99 100 auto argIface = llvm::cast<mlir::omp::BlockArgOpenMPOpInterface>(*targetOp);101 mlir::Region ®ion = targetOp.getRegion();102 103 // Get the index of the first non-map argument before modifying mapVars,104 // then append an element to mapVars and an associated entry block105 // argument at that index.106 unsigned insertIndex =107 argIface.getMapBlockArgsStart() + argIface.numMapBlockArgs();108 targetOp.getMapVarsMutable().append(mapOp);109 mlir::Value clonedValArg =110 region.insertArgument(insertIndex, copyVal.getType(), copyVal.getLoc());111 112 mlir::Block *entryBlock = ®ion.getBlocks().front();113 firOpBuilder.setInsertionPointToStart(entryBlock);114 auto loadOp =115 fir::LoadOp::create(firOpBuilder, clonedValArg.getLoc(), clonedValArg);116 return loadOp.getResult();117}118 119void cloneOrMapRegionOutsiders(120 fir::FirOpBuilder &firOpBuilder, mlir::omp::TargetOp targetOp) {121 mlir::Region ®ion = targetOp.getRegion();122 mlir::Block *entryBlock = ®ion.getBlocks().front();123 124 llvm::SetVector<mlir::Value> valuesDefinedAbove;125 mlir::getUsedValuesDefinedAbove(region, valuesDefinedAbove);126 while (!valuesDefinedAbove.empty()) {127 for (mlir::Value val : valuesDefinedAbove) {128 mlir::Operation *valOp = val.getDefiningOp();129 130 // NOTE: We skip BoxDimsOp's as the lesser of two evils is to map the131 // indices separately, as the alternative is to eventually map the Box,132 // which comes with a fairly large overhead comparatively. We could be133 // more robust about this and check using a BackwardsSlice to see if we134 // run the risk of mapping a box.135 if (valOp && mlir::isMemoryEffectFree(valOp) &&136 !mlir::isa<fir::BoxDimsOp>(valOp)) {137 mlir::Operation *clonedOp = valOp->clone();138 entryBlock->push_front(clonedOp);139 140 auto replace = [entryBlock](mlir::OpOperand &use) {141 return use.getOwner()->getBlock() == entryBlock;142 };143 144 valOp->getResults().replaceUsesWithIf(clonedOp->getResults(), replace);145 valOp->replaceUsesWithIf(clonedOp, replace);146 } else {147 mlir::Value mappedTemp = mapTemporaryValue(firOpBuilder, targetOp, val,148 /*name=*/{});149 val.replaceUsesWithIf(mappedTemp, [entryBlock](mlir::OpOperand &use) {150 return use.getOwner()->getBlock() == entryBlock;151 });152 }153 }154 valuesDefinedAbove.clear();155 mlir::getUsedValuesDefinedAbove(region, valuesDefinedAbove);156 }157}158} // namespace Fortran::utils::openmp159