|
| 1 | +//===-- FIROpenACCTypeInterfaces.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-exception |
| 6 | +// |
| 7 | +//===----------------------------------------------------------------------===// |
| 8 | +// |
| 9 | +// Implementation of external dialect interfaces for FIR. |
| 10 | +// |
| 11 | +//===----------------------------------------------------------------------===// |
| 12 | + |
| 13 | +#include "flang/Optimizer/OpenACC/FIROpenACCTypeInterfaces.h" |
| 14 | +#include "flang/Lower/DirectivesCommon.h" |
| 15 | +#include "flang/Optimizer/Builder/BoxValue.h" |
| 16 | +#include "flang/Optimizer/Builder/FIRBuilder.h" |
| 17 | +#include "flang/Optimizer/Builder/HLFIRTools.h" |
| 18 | +#include "flang/Optimizer/Dialect/FIROps.h" |
| 19 | +#include "flang/Optimizer/Dialect/FIROpsSupport.h" |
| 20 | +#include "flang/Optimizer/Dialect/FIRType.h" |
| 21 | +#include "flang/Optimizer/Dialect/Support/FIRContext.h" |
| 22 | +#include "flang/Optimizer/Dialect/Support/KindMapping.h" |
| 23 | +#include "mlir/Dialect/Arith/IR/Arith.h" |
| 24 | +#include "mlir/Dialect/OpenACC/OpenACC.h" |
| 25 | +#include "mlir/IR/BuiltinOps.h" |
| 26 | +#include "mlir/Support/LLVM.h" |
| 27 | + |
| 28 | +namespace fir::acc { |
| 29 | + |
| 30 | +static mlir::TypedValue<mlir::acc::PointerLikeType> |
| 31 | +getPtrFromVar(mlir::Value var) { |
| 32 | + if (auto ptr = |
| 33 | + mlir::dyn_cast<mlir::TypedValue<mlir::acc::PointerLikeType>>(var)) |
| 34 | + return ptr; |
| 35 | + |
| 36 | + if (auto load = mlir::dyn_cast_if_present<fir::LoadOp>(var.getDefiningOp())) { |
| 37 | + // All FIR reference types implement the PointerLikeType interface. |
| 38 | + return mlir::cast<mlir::TypedValue<mlir::acc::PointerLikeType>>( |
| 39 | + load.getMemref()); |
| 40 | + } |
| 41 | + |
| 42 | + return {}; |
| 43 | +} |
| 44 | + |
| 45 | +template <> |
| 46 | +mlir::TypedValue<mlir::acc::PointerLikeType> |
| 47 | +OpenACCMappableModel<fir::SequenceType>::getVarPtr(mlir::Type type, |
| 48 | + mlir::Value var) const { |
| 49 | + return getPtrFromVar(var); |
| 50 | +} |
| 51 | + |
| 52 | +template <> |
| 53 | +mlir::TypedValue<mlir::acc::PointerLikeType> |
| 54 | +OpenACCMappableModel<fir::BaseBoxType>::getVarPtr(mlir::Type type, |
| 55 | + mlir::Value var) const { |
| 56 | + return getPtrFromVar(var); |
| 57 | +} |
| 58 | + |
| 59 | +template <> |
| 60 | +std::optional<llvm::TypeSize> |
| 61 | +OpenACCMappableModel<fir::SequenceType>::getSizeInBytes( |
| 62 | + mlir::Type type, mlir::Value var, mlir::ValueRange accBounds, |
| 63 | + const mlir::DataLayout &dataLayout) const { |
| 64 | + // TODO: Bounds operation affect the total size - add support to take them |
| 65 | + // into account. |
| 66 | + if (!accBounds.empty()) |
| 67 | + return {}; |
| 68 | + |
| 69 | + // Dynamic extents or unknown ranks generally do not have compile-time |
| 70 | + // computable dimensions. |
| 71 | + auto seqType = mlir::cast<fir::SequenceType>(type); |
| 72 | + if (seqType.hasDynamicExtents() || seqType.hasUnknownShape()) |
| 73 | + return {}; |
| 74 | + |
| 75 | + // Attempt to find an operation that a lookup for KindMapping can be done |
| 76 | + // from. |
| 77 | + mlir::Operation *kindMapSrcOp = var.getDefiningOp(); |
| 78 | + if (!kindMapSrcOp) { |
| 79 | + kindMapSrcOp = var.getParentRegion()->getParentOp(); |
| 80 | + if (!kindMapSrcOp) |
| 81 | + return {}; |
| 82 | + } |
| 83 | + auto kindMap = fir::getKindMapping(kindMapSrcOp); |
| 84 | + |
| 85 | + auto sizeAndAlignment = |
| 86 | + fir::getTypeSizeAndAlignment(var.getLoc(), type, dataLayout, kindMap); |
| 87 | + if (!sizeAndAlignment.has_value()) |
| 88 | + return {}; |
| 89 | + |
| 90 | + return {llvm::TypeSize::getFixed(sizeAndAlignment->first)}; |
| 91 | +} |
| 92 | + |
| 93 | +template <> |
| 94 | +std::optional<llvm::TypeSize> |
| 95 | +OpenACCMappableModel<fir::BaseBoxType>::getSizeInBytes( |
| 96 | + mlir::Type type, mlir::Value var, mlir::ValueRange accBounds, |
| 97 | + const mlir::DataLayout &dataLayout) const { |
| 98 | + // If we have a box value instead of box reference, the intent is to |
| 99 | + // get the size of the data not the box itself. |
| 100 | + if (auto boxTy = mlir::dyn_cast<fir::BaseBoxType>(var.getType())) { |
| 101 | + if (auto mappableTy = mlir::dyn_cast<mlir::acc::MappableType>( |
| 102 | + fir::unwrapRefType(boxTy.getEleTy()))) { |
| 103 | + return mappableTy.getSizeInBytes(var, accBounds, dataLayout); |
| 104 | + } |
| 105 | + } |
| 106 | + // Size for boxes is not computable until it gets materialized. |
| 107 | + return {}; |
| 108 | +} |
| 109 | + |
| 110 | +template <> |
| 111 | +std::optional<int64_t> |
| 112 | +OpenACCMappableModel<fir::SequenceType>::getOffsetInBytes( |
| 113 | + mlir::Type type, mlir::Value var, mlir::ValueRange accBounds, |
| 114 | + const mlir::DataLayout &dataLayout) const { |
| 115 | + // TODO: Bounds operation affect the offset- add support to take them |
| 116 | + // into account. |
| 117 | + if (!accBounds.empty()) |
| 118 | + return {}; |
| 119 | + |
| 120 | + // Dynamic extents (aka descriptor-based arrays) - may have a offset. |
| 121 | + // For example, a negative stride may mean a negative offset to compute the |
| 122 | + // start of array. |
| 123 | + auto seqType = mlir::cast<fir::SequenceType>(type); |
| 124 | + if (seqType.hasDynamicExtents() || seqType.hasUnknownShape()) |
| 125 | + return {}; |
| 126 | + |
| 127 | + // We have non-dynamic extents - but if for some reason the size is not |
| 128 | + // computable - assume offset is not either. Otherwise, it is an offset of |
| 129 | + // zero. |
| 130 | + if (getSizeInBytes(type, var, accBounds, dataLayout).has_value()) { |
| 131 | + return {0}; |
| 132 | + } |
| 133 | + return {}; |
| 134 | +} |
| 135 | + |
| 136 | +template <> |
| 137 | +std::optional<int64_t> OpenACCMappableModel<fir::BaseBoxType>::getOffsetInBytes( |
| 138 | + mlir::Type type, mlir::Value var, mlir::ValueRange accBounds, |
| 139 | + const mlir::DataLayout &dataLayout) const { |
| 140 | + // If we have a box value instead of box reference, the intent is to |
| 141 | + // get the offset of the data not the offset of the box itself. |
| 142 | + if (auto boxTy = mlir::dyn_cast<fir::BaseBoxType>(var.getType())) { |
| 143 | + if (auto mappableTy = mlir::dyn_cast<mlir::acc::MappableType>( |
| 144 | + fir::unwrapRefType(boxTy.getEleTy()))) { |
| 145 | + return mappableTy.getOffsetInBytes(var, accBounds, dataLayout); |
| 146 | + } |
| 147 | + } |
| 148 | + // Until boxes get materialized, the offset is not evident because it is |
| 149 | + // relative to the pointer being held. |
| 150 | + return {}; |
| 151 | +} |
| 152 | + |
| 153 | +template <> |
| 154 | +llvm::SmallVector<mlir::Value> |
| 155 | +OpenACCMappableModel<fir::SequenceType>::generateAccBounds( |
| 156 | + mlir::Type type, mlir::Value var, mlir::OpBuilder &builder) const { |
| 157 | + assert((mlir::isa<mlir::acc::PointerLikeType>(var.getType()) || |
| 158 | + mlir::isa<mlir::acc::MappableType>(var.getType())) && |
| 159 | + "must be pointer-like or mappable"); |
| 160 | + |
| 161 | + fir::FirOpBuilder firBuilder(builder, var.getDefiningOp()); |
| 162 | + auto seqType = mlir::cast<fir::SequenceType>(type); |
| 163 | + mlir::Location loc = var.getLoc(); |
| 164 | + |
| 165 | + mlir::Value varPtr = |
| 166 | + mlir::isa<mlir::acc::PointerLikeType>(var.getType()) |
| 167 | + ? var |
| 168 | + : mlir::cast<mlir::acc::MappableType>(var.getType()).getVarPtr(var); |
| 169 | + |
| 170 | + if (seqType.hasDynamicExtents() || seqType.hasUnknownShape()) { |
| 171 | + if (auto boxAddr = |
| 172 | + mlir::dyn_cast_if_present<fir::BoxAddrOp>(varPtr.getDefiningOp())) { |
| 173 | + mlir::Value box = boxAddr.getVal(); |
| 174 | + auto res = |
| 175 | + hlfir::translateToExtendedValue(loc, firBuilder, hlfir::Entity(box)); |
| 176 | + fir::ExtendedValue exv = res.first; |
| 177 | + mlir::Value boxRef = box; |
| 178 | + if (auto boxPtr = getPtrFromVar(box)) { |
| 179 | + boxRef = boxPtr; |
| 180 | + } |
| 181 | + // TODO: Handle Fortran optional. |
| 182 | + const mlir::Value isPresent; |
| 183 | + Fortran::lower::AddrAndBoundsInfo info(box, boxRef, isPresent, |
| 184 | + box.getType()); |
| 185 | + return Fortran::lower::genBoundsOpsFromBox<mlir::acc::DataBoundsOp, |
| 186 | + mlir::acc::DataBoundsType>( |
| 187 | + firBuilder, loc, exv, info); |
| 188 | + } |
| 189 | + assert(false && "array with unknown dimension expected to have descriptor"); |
| 190 | + return {}; |
| 191 | + } |
| 192 | + |
| 193 | + // TODO: Detect assumed-size case. |
| 194 | + const bool isAssumedSize = false; |
| 195 | + auto valToCheck = varPtr; |
| 196 | + if (auto boxAddr = |
| 197 | + mlir::dyn_cast_if_present<fir::BoxAddrOp>(varPtr.getDefiningOp())) { |
| 198 | + valToCheck = boxAddr.getVal(); |
| 199 | + } |
| 200 | + auto res = hlfir::translateToExtendedValue(loc, firBuilder, |
| 201 | + hlfir::Entity(valToCheck)); |
| 202 | + fir::ExtendedValue exv = res.first; |
| 203 | + return Fortran::lower::genBaseBoundsOps<mlir::acc::DataBoundsOp, |
| 204 | + mlir::acc::DataBoundsType>( |
| 205 | + firBuilder, loc, exv, |
| 206 | + /*isAssumedSize=*/isAssumedSize); |
| 207 | +} |
| 208 | + |
| 209 | +template <> |
| 210 | +llvm::SmallVector<mlir::Value> |
| 211 | +OpenACCMappableModel<fir::BaseBoxType>::generateAccBounds( |
| 212 | + mlir::Type type, mlir::Value var, mlir::OpBuilder &builder) const { |
| 213 | + // If we have a box value instead of box reference, the intent is to |
| 214 | + // get the bounds of the data not the bounds of the box itself. |
| 215 | + if (auto boxTy = mlir::dyn_cast<fir::BaseBoxType>(var.getType())) { |
| 216 | + if (auto mappableTy = mlir::dyn_cast<mlir::acc::MappableType>( |
| 217 | + fir::unwrapRefType(boxTy.getEleTy()))) { |
| 218 | + mlir::Value data = builder.create<fir::BoxAddrOp>(var.getLoc(), var); |
| 219 | + return mappableTy.generateAccBounds(data, builder); |
| 220 | + } |
| 221 | + } |
| 222 | + // Box references are not arrays - thus generating acc.bounds does not make |
| 223 | + // sense. |
| 224 | + return {}; |
| 225 | +} |
| 226 | + |
| 227 | +} // namespace fir::acc |
0 commit comments