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/Support/FIROpenACCTypeInterfaces.h"
14#include "flang/Optimizer/Builder/BoxValue.h"
15#include "flang/Optimizer/Builder/DirectivesCommon.h"
16#include "flang/Optimizer/Builder/FIRBuilder.h"
17#include "flang/Optimizer/Builder/HLFIRTools.h"
18#include "flang/Optimizer/Dialect/FIRCG/CGOps.h"
19#include "flang/Optimizer/Dialect/FIROps.h"
20#include "flang/Optimizer/Dialect/FIROpsSupport.h"
21#include "flang/Optimizer/Dialect/FIRType.h"
22#include "flang/Optimizer/Dialect/Support/FIRContext.h"
23#include "flang/Optimizer/Dialect/Support/KindMapping.h"
24#include "mlir/Dialect/Arith/IR/Arith.h"
25#include "mlir/Dialect/OpenACC/OpenACC.h"
26#include "mlir/IR/BuiltinOps.h"
27#include "mlir/Support/LLVM.h"
28#include "llvm/ADT/SmallVector.h"
29#include "llvm/ADT/TypeSwitch.h"
30
31namespace fir::acc {
32
33template <typename Ty>
34mlir::TypedValue<mlir::acc::PointerLikeType>
35OpenACCMappableModel<Ty>::getVarPtr(mlir::Type type, mlir::Value var) const {
36 if (auto ptr =
37 mlir::dyn_cast<mlir::TypedValue<mlir::acc::PointerLikeType>>(var))
38 return ptr;
39
40 if (auto load = mlir::dyn_cast_if_present<fir::LoadOp>(var.getDefiningOp())) {
41 // All FIR reference types implement the PointerLikeType interface.
42 return mlir::cast<mlir::TypedValue<mlir::acc::PointerLikeType>>(
43 load.getMemref());
44 }
45
46 return {};
47}
48
49template mlir::TypedValue<mlir::acc::PointerLikeType>
50OpenACCMappableModel<fir::BaseBoxType>::getVarPtr(mlir::Type type,
51 mlir::Value var) const;
52
53template mlir::TypedValue<mlir::acc::PointerLikeType>
54OpenACCMappableModel<fir::ReferenceType>::getVarPtr(mlir::Type type,
55 mlir::Value var) const;
56
57template mlir::TypedValue<mlir::acc::PointerLikeType>
58OpenACCMappableModel<fir::HeapType>::getVarPtr(mlir::Type type,
59 mlir::Value var) const;
60
61template mlir::TypedValue<mlir::acc::PointerLikeType>
62OpenACCMappableModel<fir::PointerType>::getVarPtr(mlir::Type type,
63 mlir::Value var) const;
64
65template <typename Ty>
66std::optional<llvm::TypeSize> OpenACCMappableModel<Ty>::getSizeInBytes(
67 mlir::Type type, mlir::Value var, mlir::ValueRange accBounds,
68 const mlir::DataLayout &dataLayout) const {
69 // TODO: Bounds operation affect the size - add support to take them
70 // into account.
71 if (!accBounds.empty())
72 return {};
73
74 // Class-type is either a polymorphic or unlimited polymorphic. In the latter
75 // case, the size is not computable. But in the former it should be - however,
76 // fir::getTypeSizeAndAlignment does not support polymorphic types.
77 if (mlir::isa<fir::ClassType>(type)) {
78 return {};
79 }
80
81 // When requesting the size of a box entity or a reference, the intent
82 // is to get the size of the data that it is referring to.
83 mlir::Type eleTy = fir::dyn_cast_ptrOrBoxEleTy(type);
84 assert(eleTy && "expect to be able to unwrap the element type");
85
86 // If the type enclosed is a mappable type, then have it provide the size.
87 if (auto mappableTy = mlir::dyn_cast<mlir::acc::MappableType>(eleTy))
88 return mappableTy.getSizeInBytes(var, accBounds, dataLayout);
89
90 // Dynamic extents or unknown ranks generally do not have compile-time
91 // computable dimensions.
92 auto seqType = mlir::dyn_cast<fir::SequenceType>(eleTy);
93 if (seqType && (seqType.hasDynamicExtents() || seqType.hasUnknownShape()))
94 return {};
95
96 // Attempt to find an operation that a lookup for KindMapping can be done
97 // from.
98 mlir::Operation *kindMapSrcOp = var.getDefiningOp();
99 if (!kindMapSrcOp) {
100 kindMapSrcOp = var.getParentRegion()->getParentOp();
101 if (!kindMapSrcOp)
102 return {};
103 }
104 auto kindMap = fir::getKindMapping(kindMapSrcOp);
105
106 auto sizeAndAlignment =
107 fir::getTypeSizeAndAlignment(var.getLoc(), eleTy, dataLayout, kindMap);
108 if (!sizeAndAlignment.has_value())
109 return {};
110
111 return {llvm::TypeSize::getFixed(sizeAndAlignment->first)};
112}
113
114template std::optional<llvm::TypeSize>
115OpenACCMappableModel<fir::BaseBoxType>::getSizeInBytes(
116 mlir::Type type, mlir::Value var, mlir::ValueRange accBounds,
117 const mlir::DataLayout &dataLayout) const;
118
119template std::optional<llvm::TypeSize>
120OpenACCMappableModel<fir::ReferenceType>::getSizeInBytes(
121 mlir::Type type, mlir::Value var, mlir::ValueRange accBounds,
122 const mlir::DataLayout &dataLayout) const;
123
124template std::optional<llvm::TypeSize>
125OpenACCMappableModel<fir::HeapType>::getSizeInBytes(
126 mlir::Type type, mlir::Value var, mlir::ValueRange accBounds,
127 const mlir::DataLayout &dataLayout) const;
128
129template std::optional<llvm::TypeSize>
130OpenACCMappableModel<fir::PointerType>::getSizeInBytes(
131 mlir::Type type, mlir::Value var, mlir::ValueRange accBounds,
132 const mlir::DataLayout &dataLayout) const;
133
134template <typename Ty>
135std::optional<int64_t> OpenACCMappableModel<Ty>::getOffsetInBytes(
136 mlir::Type type, mlir::Value var, mlir::ValueRange accBounds,
137 const mlir::DataLayout &dataLayout) const {
138 // TODO: Bounds operation affect the offset - add support to take them
139 // into account.
140 if (!accBounds.empty())
141 return {};
142
143 // Class-type does not behave like a normal box because it does not hold an
144 // element type. Thus special handle it here.
145 if (mlir::isa<fir::ClassType>(type)) {
146 // The pointer to the class-type is always at the start address.
147 return {0};
148 }
149
150 mlir::Type eleTy = fir::dyn_cast_ptrOrBoxEleTy(type);
151 assert(eleTy && "expect to be able to unwrap the element type");
152
153 // If the type enclosed is a mappable type, then have it provide the offset.
154 if (auto mappableTy = mlir::dyn_cast<mlir::acc::MappableType>(eleTy))
155 return mappableTy.getOffsetInBytes(var, accBounds, dataLayout);
156
157 // Dynamic extents (aka descriptor-based arrays) - may have a offset.
158 // For example, a negative stride may mean a negative offset to compute the
159 // start of array.
160 auto seqType = mlir::dyn_cast<fir::SequenceType>(eleTy);
161 if (seqType && (seqType.hasDynamicExtents() || seqType.hasUnknownShape()))
162 return {};
163
164 // If the size is computable and since there are no bounds or dynamic extents,
165 // then the offset relative to pointer must be zero.
166 if (getSizeInBytes(type, var, accBounds, dataLayout).has_value()) {
167 return {0};
168 }
169
170 // The offset is not evident because it is relative to the pointer being held.
171 // And we don't have any further details about this type.
172 return {};
173}
174
175template std::optional<int64_t>
176OpenACCMappableModel<fir::BaseBoxType>::getOffsetInBytes(
177 mlir::Type type, mlir::Value var, mlir::ValueRange accBounds,
178 const mlir::DataLayout &dataLayout) const;
179
180template std::optional<int64_t>
181OpenACCMappableModel<fir::ReferenceType>::getOffsetInBytes(
182 mlir::Type type, mlir::Value var, mlir::ValueRange accBounds,
183 const mlir::DataLayout &dataLayout) const;
184
185template std::optional<int64_t>
186OpenACCMappableModel<fir::HeapType>::getOffsetInBytes(
187 mlir::Type type, mlir::Value var, mlir::ValueRange accBounds,
188 const mlir::DataLayout &dataLayout) const;
189
190template std::optional<int64_t>
191OpenACCMappableModel<fir::PointerType>::getOffsetInBytes(
192 mlir::Type type, mlir::Value var, mlir::ValueRange accBounds,
193 const mlir::DataLayout &dataLayout) const;
194
195static llvm::SmallVector<mlir::Value>
196generateSeqTyAccBounds(fir::SequenceType seqType, mlir::Value var,
197 mlir::OpBuilder &builder) {
198 assert((mlir::isa<mlir::acc::PointerLikeType>(var.getType()) ||
199 mlir::isa<mlir::acc::MappableType>(var.getType())) &&
200 "must be pointer-like or mappable");
201 fir::FirOpBuilder firBuilder(builder, var.getDefiningOp());
202 mlir::Location loc = var.getLoc();
203
204 if (seqType.hasDynamicExtents() || seqType.hasUnknownShape()) {
205 if (auto boxAddr =
206 mlir::dyn_cast_if_present<fir::BoxAddrOp>(var.getDefiningOp())) {
207 mlir::Value box = boxAddr.getVal();
208 auto res =
209 hlfir::translateToExtendedValue(loc, firBuilder, hlfir::Entity(box));
210 fir::ExtendedValue exv = res.first;
211 mlir::Value boxRef = box;
212 if (auto boxPtr = mlir::cast<mlir::acc::MappableType>(box.getType())
213 .getVarPtr(box)) {
214 boxRef = boxPtr;
215 }
216 // TODO: Handle Fortran optional.
217 const mlir::Value isPresent;
218 fir::factory::AddrAndBoundsInfo info(box, boxRef, isPresent,
219 box.getType());
220 return fir::factory::genBoundsOpsFromBox<mlir::acc::DataBoundsOp,
221 mlir::acc::DataBoundsType>(
222 firBuilder, loc, exv, info);
223 }
224
225 if (mlir::isa<hlfir::DeclareOp, fir::DeclareOp>(var.getDefiningOp())) {
226 mlir::Value zero =
227 firBuilder.createIntegerConstant(loc, builder.getIndexType(), 0);
228 mlir::Value one =
229 firBuilder.createIntegerConstant(loc, builder.getIndexType(), 1);
230
231 mlir::Value shape;
232 if (auto declareOp =
233 mlir::dyn_cast_if_present<fir::DeclareOp>(var.getDefiningOp()))
234 shape = declareOp.getShape();
235 else if (auto declareOp = mlir::dyn_cast_if_present<hlfir::DeclareOp>(
236 var.getDefiningOp()))
237 shape = declareOp.getShape();
238
239 const bool strideIncludeLowerExtent = true;
240
241 llvm::SmallVector<mlir::Value> accBounds;
242 if (auto shapeOp =
243 mlir::dyn_cast_if_present<fir::ShapeOp>(shape.getDefiningOp())) {
244 mlir::Value cummulativeExtent = one;
245 for (auto extent : shapeOp.getExtents()) {
246 mlir::Value upperbound =
247 builder.create<mlir::arith::SubIOp>(loc, extent, one);
248 mlir::Value stride = one;
249 if (strideIncludeLowerExtent) {
250 stride = cummulativeExtent;
251 cummulativeExtent = builder.create<mlir::arith::MulIOp>(
252 loc, cummulativeExtent, extent);
253 }
254 auto accBound = builder.create<mlir::acc::DataBoundsOp>(
255 loc, mlir::acc::DataBoundsType::get(builder.getContext()),
256 /*lowerbound=*/zero, /*upperbound=*/upperbound,
257 /*extent=*/extent, /*stride=*/stride, /*strideInBytes=*/false,
258 /*startIdx=*/one);
259 accBounds.push_back(accBound);
260 }
261 } else if (auto shapeShiftOp =
262 mlir::dyn_cast_if_present<fir::ShapeShiftOp>(
263 shape.getDefiningOp())) {
264 mlir::Value lowerbound;
265 mlir::Value cummulativeExtent = one;
266 for (auto [idx, val] : llvm::enumerate(shapeShiftOp.getPairs())) {
267 if (idx % 2 == 0) {
268 lowerbound = val;
269 } else {
270 mlir::Value extent = val;
271 mlir::Value upperbound =
272 builder.create<mlir::arith::SubIOp>(loc, extent, one);
273 upperbound = builder.create<mlir::arith::AddIOp>(loc, lowerbound,
274 upperbound);
275 mlir::Value stride = one;
276 if (strideIncludeLowerExtent) {
277 stride = cummulativeExtent;
278 cummulativeExtent = builder.create<mlir::arith::MulIOp>(
279 loc, cummulativeExtent, extent);
280 }
281 auto accBound = builder.create<mlir::acc::DataBoundsOp>(
282 loc, mlir::acc::DataBoundsType::get(builder.getContext()),
283 /*lowerbound=*/zero, /*upperbound=*/upperbound,
284 /*extent=*/extent, /*stride=*/stride, /*strideInBytes=*/false,
285 /*startIdx=*/lowerbound);
286 accBounds.push_back(accBound);
287 }
288 }
289 }
290
291 if (!accBounds.empty())
292 return accBounds;
293 }
294
295 assert(false && "array with unknown dimension expected to have descriptor");
296 return {};
297 }
298
299 // TODO: Detect assumed-size case.
300 const bool isAssumedSize = false;
301 auto valToCheck = var;
302 if (auto boxAddr =
303 mlir::dyn_cast_if_present<fir::BoxAddrOp>(var.getDefiningOp())) {
304 valToCheck = boxAddr.getVal();
305 }
306 auto res = hlfir::translateToExtendedValue(loc, firBuilder,
307 hlfir::Entity(valToCheck));
308 fir::ExtendedValue exv = res.first;
309 return fir::factory::genBaseBoundsOps<mlir::acc::DataBoundsOp,
310 mlir::acc::DataBoundsType>(
311 firBuilder, loc, exv,
312 /*isAssumedSize=*/isAssumedSize);
313}
314
315template <typename Ty>
316llvm::SmallVector<mlir::Value>
317OpenACCMappableModel<Ty>::generateAccBounds(mlir::Type type, mlir::Value var,
318 mlir::OpBuilder &builder) const {
319 // acc bounds only make sense for arrays - thus look for sequence type.
320 mlir::Type eleTy = fir::dyn_cast_ptrOrBoxEleTy(type);
321 if (auto seqTy = mlir::dyn_cast_if_present<fir::SequenceType>(eleTy)) {
322 return generateSeqTyAccBounds(seqTy, var, builder);
323 }
324
325 return {};
326}
327
328template llvm::SmallVector<mlir::Value>
329OpenACCMappableModel<fir::BaseBoxType>::generateAccBounds(
330 mlir::Type type, mlir::Value var, mlir::OpBuilder &builder) const;
331
332template llvm::SmallVector<mlir::Value>
333OpenACCMappableModel<fir::ReferenceType>::generateAccBounds(
334 mlir::Type type, mlir::Value var, mlir::OpBuilder &builder) const;
335
336template llvm::SmallVector<mlir::Value>
337OpenACCMappableModel<fir::HeapType>::generateAccBounds(
338 mlir::Type type, mlir::Value var, mlir::OpBuilder &builder) const;
339
340template llvm::SmallVector<mlir::Value>
341OpenACCMappableModel<fir::PointerType>::generateAccBounds(
342 mlir::Type type, mlir::Value var, mlir::OpBuilder &builder) const;
343
344static mlir::Value
345getBaseRef(mlir::TypedValue<mlir::acc::PointerLikeType> varPtr) {
346 // If there is no defining op - the unwrapped reference is the base one.
347 mlir::Operation *op = varPtr.getDefiningOp();
348 if (!op)
349 return varPtr;
350
351 // Look to find if this value originates from an interior pointer
352 // calculation op.
353 mlir::Value baseRef =
354 llvm::TypeSwitch<mlir::Operation *, mlir::Value>(op)
355 .Case<hlfir::DesignateOp>([&](auto op) {
356 // Get the base object.
357 return op.getMemref();
358 })
359 .Case<fir::ArrayCoorOp, fir::cg::XArrayCoorOp>([&](auto op) {
360 // Get the base array on which the coordinate is being applied.
361 return op.getMemref();
362 })
363 .Case<fir::CoordinateOp>([&](auto op) {
364 // For coordinate operation which is applied on derived type
365 // object, get the base object.
366 return op.getRef();
367 })
368 .Default([&](mlir::Operation *) { return varPtr; });
369
370 return baseRef;
371}
372
373static bool isScalarLike(mlir::Type type) {
374 return fir::isa_trivial(type) || fir::isa_ref_type(type);
375}
376
377static bool isArrayLike(mlir::Type type) {
378 return mlir::isa<fir::SequenceType>(type);
379}
380
381static bool isCompositeLike(mlir::Type type) {
382 // class(*) is not a composite type since it does not have a determined type.
383 if (fir::isUnlimitedPolymorphicType(type))
384 return false;
385
386 return mlir::isa<fir::RecordType, fir::ClassType, mlir::TupleType>(type);
387}
388
389static mlir::acc::VariableTypeCategory
390categorizeElemType(mlir::Type enclosingTy, mlir::Type eleTy, mlir::Value var) {
391 // If the type enclosed is a mappable type, then have it provide the type
392 // category.
393 if (auto mappableTy = mlir::dyn_cast<mlir::acc::MappableType>(eleTy))
394 return mappableTy.getTypeCategory(var);
395
396 // For all arrays, despite whether they are allocatable, pointer, assumed,
397 // etc, we'd like to categorize them as "array".
398 if (isArrayLike(eleTy))
399 return mlir::acc::VariableTypeCategory::array;
400
401 if (isCompositeLike(eleTy))
402 return mlir::acc::VariableTypeCategory::composite;
403 if (mlir::isa<fir::BoxType>(enclosingTy)) {
404 // Even if we have a scalar type - simply because it is wrapped in a box
405 // we want to categorize it as "nonscalar". Anything else would've been
406 // non-scalar anyway.
407 return mlir::acc::VariableTypeCategory::nonscalar;
408 }
409 if (isScalarLike(eleTy))
410 return mlir::acc::VariableTypeCategory::scalar;
411 if (mlir::isa<fir::CharacterType, mlir::FunctionType>(eleTy))
412 return mlir::acc::VariableTypeCategory::nonscalar;
413 // Assumed-type (type(*))does not have a determined type that can be
414 // categorized.
415 if (mlir::isa<mlir::NoneType>(eleTy))
416 return mlir::acc::VariableTypeCategory::uncategorized;
417 // "pointers" - in the sense of raw address point-of-view, are considered
418 // scalars.
419 if (mlir::isa<fir::LLVMPointerType>(eleTy))
420 return mlir::acc::VariableTypeCategory::scalar;
421
422 // Without further checking, this type cannot be categorized.
423 return mlir::acc::VariableTypeCategory::uncategorized;
424}
425
426template <typename Ty>
427mlir::acc::VariableTypeCategory
428OpenACCMappableModel<Ty>::getTypeCategory(mlir::Type type,
429 mlir::Value var) const {
430 // FIR uses operations to compute interior pointers.
431 // So for example, an array element or composite field access to a float
432 // value would both be represented as !fir.ref<f32>. We do not want to treat
433 // such a reference as a scalar. Thus unwrap interior pointer calculations.
434 mlir::Type eleTy = fir::dyn_cast_ptrOrBoxEleTy(type);
435 if (eleTy && isScalarLike(eleTy)) {
436 if (auto ptrLikeVar = mlir::dyn_cast_if_present<
437 mlir::TypedValue<mlir::acc::PointerLikeType>>(var)) {
438 auto baseRef = getBaseRef(ptrLikeVar);
439 if (baseRef != var) {
440 type = baseRef.getType();
441 if (auto mappableTy = mlir::dyn_cast<mlir::acc::MappableType>(type))
442 return mappableTy.getTypeCategory(baseRef);
443 }
444 }
445 }
446
447 // Class-type does not behave like a normal box because it does not hold an
448 // element type. Thus special handle it here.
449 if (mlir::isa<fir::ClassType>(type)) {
450 // class(*) is not a composite type since it does not have a determined
451 // type.
452 if (fir::isUnlimitedPolymorphicType(type))
453 return mlir::acc::VariableTypeCategory::uncategorized;
454 return mlir::acc::VariableTypeCategory::composite;
455 }
456
457 assert(eleTy && "expect to be able to unwrap the element type");
458 return categorizeElemType(type, eleTy, var);
459}
460
461template mlir::acc::VariableTypeCategory
462OpenACCMappableModel<fir::BaseBoxType>::getTypeCategory(mlir::Type type,
463 mlir::Value var) const;
464
465template mlir::acc::VariableTypeCategory
466OpenACCMappableModel<fir::ReferenceType>::getTypeCategory(
467 mlir::Type type, mlir::Value var) const;
468
469template mlir::acc::VariableTypeCategory
470OpenACCMappableModel<fir::HeapType>::getTypeCategory(mlir::Type type,
471 mlir::Value var) const;
472
473template mlir::acc::VariableTypeCategory
474OpenACCMappableModel<fir::PointerType>::getTypeCategory(mlir::Type type,
475 mlir::Value var) const;
476
477static mlir::acc::VariableTypeCategory
478categorizePointee(mlir::Type pointer,
479 mlir::TypedValue<mlir::acc::PointerLikeType> varPtr,
480 mlir::Type varType) {
481 // FIR uses operations to compute interior pointers.
482 // So for example, an array element or composite field access to a float
483 // value would both be represented as !fir.ref<f32>. We do not want to treat
484 // such a reference as a scalar. Thus unwrap interior pointer calculations.
485 auto baseRef = getBaseRef(varPtr);
486
487 if (auto mappableTy =
488 mlir::dyn_cast<mlir::acc::MappableType>(baseRef.getType()))
489 return mappableTy.getTypeCategory(baseRef);
490
491 // It must be a pointer-like type since it is not a MappableType.
492 auto ptrLikeTy = mlir::cast<mlir::acc::PointerLikeType>(baseRef.getType());
493 mlir::Type eleTy = ptrLikeTy.getElementType();
494 return categorizeElemType(pointer, eleTy, varPtr);
495}
496
497template <>
498mlir::acc::VariableTypeCategory
499OpenACCPointerLikeModel<fir::ReferenceType>::getPointeeTypeCategory(
500 mlir::Type pointer, mlir::TypedValue<mlir::acc::PointerLikeType> varPtr,
501 mlir::Type varType) const {
502 return categorizePointee(pointer, varPtr, varType);
503}
504
505template <>
506mlir::acc::VariableTypeCategory
507OpenACCPointerLikeModel<fir::PointerType>::getPointeeTypeCategory(
508 mlir::Type pointer, mlir::TypedValue<mlir::acc::PointerLikeType> varPtr,
509 mlir::Type varType) const {
510 return categorizePointee(pointer, varPtr, varType);
511}
512
513template <>
514mlir::acc::VariableTypeCategory
515OpenACCPointerLikeModel<fir::HeapType>::getPointeeTypeCategory(
516 mlir::Type pointer, mlir::TypedValue<mlir::acc::PointerLikeType> varPtr,
517 mlir::Type varType) const {
518 return categorizePointee(pointer, varPtr, varType);
519}
520
521template <>
522mlir::acc::VariableTypeCategory
523OpenACCPointerLikeModel<fir::LLVMPointerType>::getPointeeTypeCategory(
524 mlir::Type pointer, mlir::TypedValue<mlir::acc::PointerLikeType> varPtr,
525 mlir::Type varType) const {
526 return categorizePointee(pointer, varPtr, varType);
527}
528
529static fir::ShapeOp genShapeOp(mlir::OpBuilder &builder,
530 fir::SequenceType seqTy, mlir::Location loc) {
531 llvm::SmallVector<mlir::Value> extents;
532 mlir::Type idxTy = builder.getIndexType();
533 for (auto extent : seqTy.getShape())
534 extents.push_back(builder.create<mlir::arith::ConstantOp>(
535 loc, idxTy, builder.getIntegerAttr(idxTy, extent)));
536 return builder.create<fir::ShapeOp>(loc, extents);
537}
538
539template <typename Ty>
540mlir::Value OpenACCMappableModel<Ty>::generatePrivateInit(
541 mlir::Type type, mlir::OpBuilder &builder, mlir::Location loc,
542 mlir::TypedValue<mlir::acc::MappableType> var, llvm::StringRef varName,
543 mlir::ValueRange extents, mlir::Value initVal) const {
544 mlir::Value retVal;
545 mlir::Type unwrappedTy = fir::unwrapRefType(type);
546 mlir::ModuleOp mod = builder.getInsertionBlock()
547 ->getParent()
548 ->getParentOfType<mlir::ModuleOp>();
549 fir::FirOpBuilder firBuilder(builder, mod);
550
551 auto getDeclareOpForType = [&](mlir::Type ty) -> hlfir::DeclareOp {
552 auto alloca = firBuilder.create<fir::AllocaOp>(loc, ty);
553 return firBuilder.create<hlfir::DeclareOp>(
554 loc, alloca, varName, /*shape=*/nullptr, llvm::ArrayRef<mlir::Value>{},
555 /*dummy_scope=*/nullptr, fir::FortranVariableFlagsAttr{});
556 };
557
558 if (fir::isa_trivial(unwrappedTy)) {
559 auto declareOp = getDeclareOpForType(unwrappedTy);
560 if (initVal) {
561 auto convert = firBuilder.createConvert(loc, unwrappedTy, initVal);
562 firBuilder.create<fir::StoreOp>(loc, convert, declareOp.getBase());
563 }
564 retVal = declareOp.getBase();
565 } else if (auto seqTy =
566 mlir::dyn_cast_or_null<fir::SequenceType>(unwrappedTy)) {
567 if (fir::isa_trivial(seqTy.getEleTy())) {
568 mlir::Value shape;
569 if (seqTy.hasDynamicExtents()) {
570 shape = firBuilder.create<fir::ShapeOp>(loc, llvm::to_vector(extents));
571 } else {
572 shape = genShapeOp(firBuilder, seqTy, loc);
573 }
574 auto alloca = firBuilder.create<fir::AllocaOp>(
575 loc, seqTy, /*typeparams=*/mlir::ValueRange{}, extents);
576 auto declareOp = firBuilder.create<hlfir::DeclareOp>(
577 loc, alloca, varName, shape, llvm::ArrayRef<mlir::Value>{},
578 /*dummy_scope=*/nullptr, fir::FortranVariableFlagsAttr{});
579
580 if (initVal) {
581 mlir::Type idxTy = firBuilder.getIndexType();
582 mlir::Type refTy = fir::ReferenceType::get(seqTy.getEleTy());
583 llvm::SmallVector<fir::DoLoopOp> loops;
584 llvm::SmallVector<mlir::Value> ivs;
585
586 if (seqTy.hasDynamicExtents()) {
587 firBuilder.create<hlfir::AssignOp>(loc, initVal, declareOp.getBase());
588 } else {
589 for (auto ext : seqTy.getShape()) {
590 auto lb = firBuilder.createIntegerConstant(loc, idxTy, 0);
591 auto ub = firBuilder.createIntegerConstant(loc, idxTy, ext - 1);
592 auto step = firBuilder.createIntegerConstant(loc, idxTy, 1);
593 auto loop = firBuilder.create<fir::DoLoopOp>(loc, lb, ub, step,
594 /*unordered=*/false);
595 firBuilder.setInsertionPointToStart(loop.getBody());
596 loops.push_back(loop);
597 ivs.push_back(loop.getInductionVar());
598 }
599 auto coord = firBuilder.create<fir::CoordinateOp>(
600 loc, refTy, declareOp.getBase(), ivs);
601 firBuilder.create<fir::StoreOp>(loc, initVal, coord);
602 firBuilder.setInsertionPointAfter(loops[0]);
603 }
604 }
605 retVal = declareOp.getBase();
606 }
607 } else if (auto boxTy =
608 mlir::dyn_cast_or_null<fir::BaseBoxType>(unwrappedTy)) {
609 mlir::Type innerTy = fir::unwrapRefType(boxTy.getEleTy());
610 if (fir::isa_trivial(innerTy)) {
611 retVal = getDeclareOpForType(unwrappedTy).getBase();
612 } else if (mlir::isa<fir::SequenceType>(innerTy)) {
613 hlfir::Entity source = hlfir::Entity{var};
614 auto [temp, cleanup] = hlfir::createTempFromMold(loc, firBuilder, source);
615 if (fir::isa_ref_type(type)) {
616 // When the temp is created - it is not a reference - thus we can
617 // end up with a type inconsistency. Therefore ensure storage is created
618 // for it.
619 retVal = getDeclareOpForType(unwrappedTy).getBase();
620 mlir::Value storeDst = retVal;
621 if (fir::unwrapRefType(retVal.getType()) != temp.getType()) {
622 // `createTempFromMold` makes the unfortunate choice to lose the
623 // `fir.heap` and `fir.ptr` types when wrapping with a box. Namely,
624 // when wrapping a `fir.heap<fir.array>`, it will create instead a
625 // `fir.box<fir.array>`. Cast here to deal with this inconsistency.
626 storeDst = firBuilder.createConvert(
627 loc, firBuilder.getRefType(temp.getType()), retVal);
628 }
629 builder.create<fir::StoreOp>(loc, temp, storeDst);
630 } else {
631 retVal = temp;
632 }
633 } else {
634 TODO(loc, "Unsupported boxed type for OpenACC private-like recipe");
635 }
636 if (initVal) {
637 builder.create<hlfir::AssignOp>(loc, initVal, retVal);
638 }
639 }
640 return retVal;
641}
642
643template mlir::Value
644OpenACCMappableModel<fir::BaseBoxType>::generatePrivateInit(
645 mlir::Type type, mlir::OpBuilder &builder, mlir::Location loc,
646 mlir::TypedValue<mlir::acc::MappableType> var, llvm::StringRef varName,
647 mlir::ValueRange extents, mlir::Value initVal) const;
648
649template mlir::Value
650OpenACCMappableModel<fir::ReferenceType>::generatePrivateInit(
651 mlir::Type type, mlir::OpBuilder &builder, mlir::Location loc,
652 mlir::TypedValue<mlir::acc::MappableType> var, llvm::StringRef varName,
653 mlir::ValueRange extents, mlir::Value initVal) const;
654
655template mlir::Value OpenACCMappableModel<fir::HeapType>::generatePrivateInit(
656 mlir::Type type, mlir::OpBuilder &builder, mlir::Location loc,
657 mlir::TypedValue<mlir::acc::MappableType> var, llvm::StringRef varName,
658 mlir::ValueRange extents, mlir::Value initVal) const;
659
660template mlir::Value
661OpenACCMappableModel<fir::PointerType>::generatePrivateInit(
662 mlir::Type type, mlir::OpBuilder &builder, mlir::Location loc,
663 mlir::TypedValue<mlir::acc::MappableType> var, llvm::StringRef varName,
664 mlir::ValueRange extents, mlir::Value initVal) const;
665
666} // namespace fir::acc
667

source code of flang/lib/Optimizer/OpenACC/Support/FIROpenACCTypeInterfaces.cpp