FLANG
HLFIRTools.h
1//===-- HLFIRTools.h -- HLFIR tools -----------------------*- 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-exception
6//
7//===----------------------------------------------------------------------===//
8//
9// Coding style: https://mlir.llvm.org/getting_started/DeveloperGuide/
10//
11//===----------------------------------------------------------------------===//
12
13#ifndef FORTRAN_OPTIMIZER_BUILDER_HLFIRTOOLS_H
14#define FORTRAN_OPTIMIZER_BUILDER_HLFIRTOOLS_H
15
16#include "flang/Optimizer/Builder/BoxValue.h"
17#include "flang/Optimizer/Dialect/FIROps.h"
18#include "flang/Optimizer/Dialect/FortranVariableInterface.h"
19#include "flang/Optimizer/HLFIR/HLFIRDialect.h"
20#include "flang/Optimizer/HLFIR/HLFIROps.h"
21#include <optional>
22
23namespace fir {
24class FirOpBuilder;
25}
26
27namespace mlir {
28class IRMapping;
29}
30
31namespace hlfir {
32
33class AssociateOp;
34class ElementalOp;
35class ElementalOpInterface;
36class ElementalAddrOp;
37class EvaluateInMemoryOp;
38class YieldElementOp;
39
42inline bool isFortranVariableWithAttributes(mlir::Value value) {
43 return value.getDefiningOp<fir::FortranVariableOpInterface>();
44}
45
48inline bool isFortranEntityWithAttributes(mlir::Value value) {
49 return isFortranValue(value) || isFortranVariableWithAttributes(value);
50}
51
52class Entity : public mlir::Value {
53public:
54 explicit Entity(mlir::Value value) : mlir::Value(value) {
55 assert(isFortranEntity(value) &&
56 "must be a value representing a Fortran value or variable like");
57 }
58 Entity(fir::FortranVariableOpInterface variable)
59 : mlir::Value(variable.getBase()) {}
60 bool isValue() const { return isFortranValue(*this); }
61 bool isVariable() const { return !isValue(); }
62 bool isMutableBox() const { return hlfir::isBoxAddressType(getType()); }
63 bool isProcedurePointer() const {
64 return hlfir::isFortranProcedurePointerType(getType());
65 }
66 bool isBoxAddressOrValue() const {
67 return hlfir::isBoxAddressOrValueType(getType());
68 }
69
71 bool isProcedure() const { return isFortranProcedureValue(getType()); }
72
74 bool isArray() const { return getRank() != 0; }
75
77 bool isAssumedRank() const { return getRank() == -1; }
78
80 int getRank() const {
81 mlir::Type type = fir::unwrapPassByRefType(fir::unwrapRefType(getType()));
82 if (auto seqTy = mlir::dyn_cast<fir::SequenceType>(type)) {
83 if (seqTy.hasUnknownShape())
84 return -1;
85 return seqTy.getDimension();
86 }
87 if (auto exprType = mlir::dyn_cast<hlfir::ExprType>(type))
88 return exprType.getRank();
89 return 0;
90 }
91 bool isScalar() const { return !isArray(); }
92
93 bool isPolymorphic() const { return hlfir::isPolymorphicType(getType()); }
94
95 mlir::Type getFortranElementType() const {
96 return hlfir::getFortranElementType(getType());
97 }
98 mlir::Type getElementOrSequenceType() const {
99 return hlfir::getFortranElementOrSequenceType(getType());
100 }
103 if (isBoxAddressOrValue())
104 return llvm::cast<fir::BaseBoxType>(fir::unwrapRefType(getType()));
105 const bool isVolatile = fir::isa_volatile_type(getType());
106 return fir::BoxType::get(getElementOrSequenceType(), isVolatile);
107 }
108
109 bool hasLengthParameters() const {
110 mlir::Type eleTy = getFortranElementType();
111 return mlir::isa<fir::CharacterType>(eleTy) ||
113 }
114
115 bool isCharacter() const {
116 return mlir::isa<fir::CharacterType>(getFortranElementType());
117 }
118
119 bool hasIntrinsicType() const {
120 mlir::Type eleTy = getFortranElementType();
121 return fir::isa_trivial(eleTy) || mlir::isa<fir::CharacterType>(eleTy);
122 }
123
124 bool isDerivedWithLengthParameters() const {
125 return fir::isRecordWithTypeParameters(getFortranElementType());
126 }
127
128 bool mayHaveNonDefaultLowerBounds() const;
129
130 // Is this entity known to be contiguous at compile time?
131 // Note that when this returns false, the entity may still
132 // turn-out to be contiguous at runtime.
133 bool isSimplyContiguous() const {
134 // If this can be described without a fir.box in FIR, this must
135 // be contiguous.
136 if (!hlfir::isBoxAddressOrValueType(getFirBase().getType()) || isScalar())
137 return true;
138 // Otherwise, if this entity has a visible declaration in FIR,
139 // or is the dereference of an allocatable or contiguous pointer
140 // it is simply contiguous.
141 if (auto varIface = getMaybeDereferencedVariableInterface())
142 return varIface.isAllocatable() || varIface.hasContiguousAttr();
143 return false;
144 }
145
146 fir::FortranVariableOpInterface getIfVariableInterface() const {
147 return this->getDefiningOp<fir::FortranVariableOpInterface>();
148 }
149
150 // Return a "declaration" operation for this variable if visible,
151 // or the "declaration" operation of the allocatable/pointer this
152 // variable was dereferenced from (if it is visible).
153 fir::FortranVariableOpInterface
154 getMaybeDereferencedVariableInterface() const {
155 mlir::Value base = *this;
156 if (auto loadOp = base.getDefiningOp<fir::LoadOp>())
157 base = loadOp.getMemref();
158 return base.getDefiningOp<fir::FortranVariableOpInterface>();
159 }
160
161 bool mayBeOptional() const;
162
163 bool isParameter() const {
164 auto varIface = getIfVariableInterface();
165 return varIface ? varIface.isParameter() : false;
166 }
167
168 bool isAllocatable() const {
169 auto varIface = getIfVariableInterface();
170 return varIface ? varIface.isAllocatable() : false;
171 }
172
173 bool isPointer() const {
174 auto varIface = getIfVariableInterface();
175 return varIface ? varIface.isPointer() : false;
176 }
177
178 // Get the entity as an mlir SSA value containing all the shape, type
179 // parameters and dynamic shape information.
180 mlir::Value getBase() const { return *this; }
181
182 // Get the entity as a FIR base. This may not carry the shape and type
183 // parameters information, and even when it is a box with shape information.
184 // it will not contain the local lower bounds of the entity. This should
185 // be used with care when generating FIR code that does not need this
186 // information, or has access to it in other ways. Its advantage is that
187 // it will never be a fir.box for explicit shape arrays, leading to simpler
188 // FIR code generation.
189 mlir::Value getFirBase() const;
190};
191
197class EntityWithAttributes : public Entity {
198public:
199 explicit EntityWithAttributes(mlir::Value value) : Entity(value) {
200 assert(isFortranEntityWithAttributes(value) &&
201 "must be a value representing a Fortran value or variable");
202 }
203 EntityWithAttributes(fir::FortranVariableOpInterface variable)
204 : Entity(variable) {}
205 fir::FortranVariableOpInterface getIfVariable() const {
206 return getIfVariableInterface();
207 }
208};
209
215using CleanupFunction = std::function<void()>;
216std::pair<fir::ExtendedValue, std::optional<CleanupFunction>>
217translateToExtendedValue(mlir::Location loc, fir::FirOpBuilder &builder,
218 Entity entity, bool contiguousHint = false,
219 bool keepScalarOptionalBoxed = false);
220
225translateToExtendedValue(mlir::Location loc, fir::FirOpBuilder &builder,
226 fir::FortranVariableOpInterface fortranVariable,
227 bool forceHlfirBase = false);
228
230fir::FortranVariableOpInterface
231genDeclare(mlir::Location loc, fir::FirOpBuilder &builder,
232 const fir::ExtendedValue &exv, llvm::StringRef name,
233 fir::FortranVariableFlagsAttr flags,
234 mlir::Value dummyScope = nullptr, mlir::Value storage = nullptr,
235 std::uint64_t storageOffset = 0,
236 cuf::DataAttributeAttr dataAttr = {});
237
241hlfir::AssociateOp
242genAssociateExpr(mlir::Location loc, fir::FirOpBuilder &builder,
243 hlfir::Entity value, mlir::Type variableType,
244 llvm::StringRef name,
245 std::optional<mlir::NamedAttribute> attr = std::nullopt);
246
251mlir::Value genVariableRawAddress(mlir::Location loc,
252 fir::FirOpBuilder &builder,
253 hlfir::Entity var);
254
257mlir::Value genVariableBoxChar(mlir::Location loc, fir::FirOpBuilder &builder,
258 hlfir::Entity var);
259
263hlfir::Entity genVariableBox(mlir::Location loc, fir::FirOpBuilder &builder,
264 hlfir::Entity var,
265 fir::BaseBoxType forceBoxType = {});
266
271Entity loadTrivialScalar(mlir::Location loc, fir::FirOpBuilder &builder,
272 Entity entity);
273
276hlfir::Entity derefPointersAndAllocatables(mlir::Location loc,
277 fir::FirOpBuilder &builder,
278 Entity entity);
279
283hlfir::Entity getElementAt(mlir::Location loc, fir::FirOpBuilder &builder,
284 Entity entity, mlir::ValueRange oneBasedIndices);
286llvm::SmallVector<std::pair<mlir::Value, mlir::Value>>
287genBounds(mlir::Location loc, fir::FirOpBuilder &builder, Entity entity);
290llvm::SmallVector<std::pair<mlir::Value, mlir::Value>>
291genBounds(mlir::Location loc, fir::FirOpBuilder &builder, mlir::Value shape);
292
295llvm::SmallVector<mlir::Value> genLowerbounds(mlir::Location loc,
296 fir::FirOpBuilder &builder,
297 mlir::Value shape, unsigned rank);
298
300mlir::Value genShape(mlir::Location loc, fir::FirOpBuilder &builder,
301 Entity entity);
302
305mlir::Value genExtent(mlir::Location loc, fir::FirOpBuilder &builder,
306 hlfir::Entity entity, unsigned dim);
307
310mlir::Value genLBound(mlir::Location loc, fir::FirOpBuilder &builder,
311 hlfir::Entity entity, unsigned dim);
312
315llvm::SmallVector<mlir::Value> getIndexExtents(mlir::Location loc,
316 fir::FirOpBuilder &builder,
317 mlir::Value shape);
318
321llvm::SmallVector<mlir::Value>
322getExplicitExtentsFromShape(mlir::Value shape, fir::FirOpBuilder &builder);
323
325void genLengthParameters(mlir::Location loc, fir::FirOpBuilder &builder,
326 Entity entity,
327 llvm::SmallVectorImpl<mlir::Value> &result);
328
331mlir::Value genCharLength(mlir::Location loc, fir::FirOpBuilder &builder,
332 Entity entity);
333
336std::optional<std::int64_t> getCharLengthIfConst(Entity entity);
337
338mlir::Value genRank(mlir::Location loc, fir::FirOpBuilder &builder,
339 Entity entity, mlir::Type resultType);
340
345std::pair<mlir::Value, mlir::Value> genVariableFirBaseShapeAndParams(
346 mlir::Location loc, fir::FirOpBuilder &builder, Entity entity,
347 llvm::SmallVectorImpl<mlir::Value> &typeParams);
348
352mlir::Type getVariableElementType(hlfir::Entity variable);
357mlir::Type getEntityElementType(hlfir::Entity entity);
358
359using ElementalKernelGenerator = std::function<hlfir::Entity(
360 mlir::Location, fir::FirOpBuilder &, mlir::ValueRange)>;
367hlfir::ElementalOp genElementalOp(
368 mlir::Location loc, fir::FirOpBuilder &builder, mlir::Type elementType,
369 mlir::Value shape, mlir::ValueRange typeParams,
370 const ElementalKernelGenerator &genKernel, bool isUnordered = false,
371 mlir::Value polymorphicMold = {}, mlir::Type exprType = mlir::Type{});
372
374struct LoopNest {
375 mlir::Operation *outerOp = nullptr;
376 mlir::Block *body = nullptr;
377 llvm::SmallVector<mlir::Value> oneBasedIndices;
378};
379
387LoopNest genLoopNest(mlir::Location loc, fir::FirOpBuilder &builder,
388 mlir::ValueRange extents, bool isUnordered = false,
389 bool emitWorkshareLoop = false,
390 bool couldVectorize = true);
391inline LoopNest genLoopNest(mlir::Location loc, fir::FirOpBuilder &builder,
392 mlir::Value shape, bool isUnordered = false,
393 bool emitWorkshareLoop = false,
394 bool couldVectorize = true) {
395 return genLoopNest(loc, builder, getIndexExtents(loc, builder, shape),
396 isUnordered, emitWorkshareLoop, couldVectorize);
397}
398
405using ReductionLoopBodyGenerator = std::function<llvm::SmallVector<mlir::Value>(
406 mlir::Location, fir::FirOpBuilder &, mlir::ValueRange, mlir::ValueRange)>;
407
425llvm::SmallVector<mlir::Value> genLoopNestWithReductions(
426 mlir::Location loc, fir::FirOpBuilder &builder, mlir::ValueRange extents,
427 mlir::ValueRange reductionInits, const ReductionLoopBodyGenerator &genBody,
428 bool isUnordered = false);
429
435hlfir::YieldElementOp inlineElementalOp(mlir::Location loc,
436 fir::FirOpBuilder &builder,
437 hlfir::ElementalOp elemental,
438 mlir::ValueRange oneBasedIndices);
439
447mlir::Value inlineElementalOp(
448 mlir::Location loc, fir::FirOpBuilder &builder,
449 hlfir::ElementalOpInterface elemental, mlir::ValueRange oneBasedIndices,
450 mlir::IRMapping &mapper,
451 const std::function<bool(hlfir::ElementalOp)> &mustRecursivelyInline);
452
457std::pair<hlfir::Entity, bool>
458computeEvaluateOpInNewTemp(mlir::Location, fir::FirOpBuilder &,
459 hlfir::EvaluateInMemoryOp evalInMem,
460 mlir::Value shape, mlir::ValueRange typeParams);
461
462// Clone the body of the hlfir.eval_in_mem operating on this the provided
463// storage. The provided storage must be a contiguous "raw" memory reference
464// (not a fir.box) big enough to hold the value computed by hlfir.eval_in_mem.
465// No runtime check is inserted by this utility to enforce that. It is also
466// usually invalid to provide some storage that is already addressed directly
467// or indirectly inside the hlfir.eval_in_mem body.
468void computeEvaluateOpIn(mlir::Location, fir::FirOpBuilder &,
469 hlfir::EvaluateInMemoryOp, mlir::Value storage);
470
471std::pair<fir::ExtendedValue, std::optional<hlfir::CleanupFunction>>
472convertToValue(mlir::Location loc, fir::FirOpBuilder &builder,
473 hlfir::Entity entity);
474
475std::pair<fir::ExtendedValue, std::optional<hlfir::CleanupFunction>>
476convertToAddress(mlir::Location loc, fir::FirOpBuilder &builder,
477 hlfir::Entity entity, mlir::Type targetType);
478
479std::pair<fir::ExtendedValue, std::optional<hlfir::CleanupFunction>>
480convertToBox(mlir::Location loc, fir::FirOpBuilder &builder,
481 hlfir::Entity entity, mlir::Type targetType);
482
484hlfir::ElementalOp cloneToElementalOp(mlir::Location loc,
485 fir::FirOpBuilder &builder,
486 hlfir::ElementalAddrOp elementalAddrOp);
487
493bool elementalOpMustProduceTemp(hlfir::ElementalOp elemental);
494
504std::pair<hlfir::Entity, bool> createTempFromMold(mlir::Location loc,
505 fir::FirOpBuilder &builder,
506 hlfir::Entity mold);
507
508// TODO: this does not support polymorphic molds
509hlfir::Entity createStackTempFromMold(mlir::Location loc,
510 fir::FirOpBuilder &builder,
511 hlfir::Entity mold);
512
513hlfir::EntityWithAttributes convertCharacterKind(mlir::Location loc,
514 fir::FirOpBuilder &builder,
515 hlfir::Entity scalarChar,
516 int toKind);
517
531std::pair<hlfir::Entity, std::optional<hlfir::CleanupFunction>>
532genTypeAndKindConvert(mlir::Location loc, fir::FirOpBuilder &builder,
533 hlfir::Entity source, mlir::Type toType,
534 bool preserveLowerBounds);
535
538Entity loadElementAt(mlir::Location loc, fir::FirOpBuilder &builder,
539 Entity entity, mlir::ValueRange oneBasedIndices);
540
545genExtentsVector(mlir::Location loc, fir::FirOpBuilder &builder, Entity entity);
546
554Entity gen1DSection(mlir::Location loc, fir::FirOpBuilder &builder,
555 Entity array, int64_t dim,
556 mlir::ArrayRef<mlir::Value> lbounds,
557 mlir::ArrayRef<mlir::Value> extents,
558 mlir::ValueRange oneBasedIndices,
559 mlir::ArrayRef<mlir::Value> typeParams);
560
564bool designatePreservesContinuity(hlfir::DesignateOp op);
565
572bool isSimplyContiguous(mlir::Value base, bool checkWhole = true);
573
574} // namespace hlfir
575
576#endif // FORTRAN_OPTIMIZER_BUILDER_HLFIRTOOLS_H
This class provides a shared interface for box and class types.
Definition FIRType.h:40
Definition BoxValue.h:478
Definition FIRBuilder.h:55
Definition HLFIRTools.h:197
Definition HLFIRTools.h:52
bool isAssumedRank() const
Is this an assumed ranked entity?
Definition HLFIRTools.h:77
int getRank() const
Return the rank of this entity or -1 if it is an assumed rank.
Definition HLFIRTools.h:80
bool isArray() const
Is this an array or an assumed ranked entity?
Definition HLFIRTools.h:74
bool isProcedure() const
Is this entity a procedure designator?
Definition HLFIRTools.h:71
fir::BaseBoxType getBoxType() const
Return the fir.class or fir.box type needed to describe this entity.
Definition HLFIRTools.h:102
Definition OpenACC.h:20
Definition AbstractConverter.h:34
bool isa_volatile_type(mlir::Type t)
Definition FIRType.cpp:748
mlir::Type unwrapPassByRefType(mlir::Type t)
Definition FIRType.h:292
bool isRecordWithTypeParameters(mlir::Type ty)
Return true iff ty is a RecordType with type parameters.
Definition FIRType.h:430
bool isa_trivial(mlir::Type t)
Definition FIRType.h:217
Definition AbstractConverter.h:29
Structure to describe a loop nest.
Definition HLFIRTools.h:374