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 <optional>
21
22namespace fir {
23class FirOpBuilder;
24}
25
26namespace mlir {
27class IRMapping;
28}
29
30namespace hlfir {
31
32class AssociateOp;
33class ElementalOp;
34class ElementalOpInterface;
35class ElementalAddrOp;
36class EvaluateInMemoryOp;
37class YieldElementOp;
38
41inline bool isFortranVariableWithAttributes(mlir::Value value) {
42 return value.getDefiningOp<fir::FortranVariableOpInterface>();
43}
44
47inline bool isFortranEntityWithAttributes(mlir::Value value) {
48 return isFortranValue(value) || isFortranVariableWithAttributes(value);
49}
50
51class Entity : public mlir::Value {
52public:
53 explicit Entity(mlir::Value value) : mlir::Value(value) {
54 assert(isFortranEntity(value) &&
55 "must be a value representing a Fortran value or variable like");
56 }
57 Entity(fir::FortranVariableOpInterface variable)
58 : mlir::Value(variable.getBase()) {}
59 bool isValue() const { return isFortranValue(*this); }
60 bool isVariable() const { return !isValue(); }
61 bool isMutableBox() const { return hlfir::isBoxAddressType(getType()); }
62 bool isProcedurePointer() const {
63 return fir::isBoxProcAddressType(getType());
64 }
65 bool isBoxAddressOrValue() const {
66 return hlfir::isBoxAddressOrValueType(getType());
67 }
68
70 bool isProcedure() const { return isFortranProcedureValue(getType()); }
71
73 bool isArray() const { return getRank() != 0; }
74
76 bool isAssumedRank() const { return getRank() == -1; }
77
79 int getRank() const {
80 mlir::Type type = fir::unwrapPassByRefType(fir::unwrapRefType(getType()));
81 if (auto seqTy = mlir::dyn_cast<fir::SequenceType>(type)) {
82 if (seqTy.hasUnknownShape())
83 return -1;
84 return seqTy.getDimension();
85 }
86 if (auto exprType = mlir::dyn_cast<hlfir::ExprType>(type))
87 return exprType.getRank();
88 return 0;
89 }
90 bool isScalar() const { return !isArray(); }
91
92 bool isPolymorphic() const { return hlfir::isPolymorphicType(getType()); }
93
94 mlir::Type getFortranElementType() const {
95 return hlfir::getFortranElementType(getType());
96 }
97 mlir::Type getElementOrSequenceType() const {
98 return hlfir::getFortranElementOrSequenceType(getType());
99 }
100
101 bool hasLengthParameters() const {
102 mlir::Type eleTy = getFortranElementType();
103 return mlir::isa<fir::CharacterType>(eleTy) ||
105 }
106
107 bool isCharacter() const {
108 return mlir::isa<fir::CharacterType>(getFortranElementType());
109 }
110
111 bool hasIntrinsicType() const {
112 mlir::Type eleTy = getFortranElementType();
113 return fir::isa_trivial(eleTy) || mlir::isa<fir::CharacterType>(eleTy);
114 }
115
116 bool isDerivedWithLengthParameters() const {
117 return fir::isRecordWithTypeParameters(getFortranElementType());
118 }
119
120 bool mayHaveNonDefaultLowerBounds() const;
121
122 // Is this entity known to be contiguous at compile time?
123 // Note that when this returns false, the entity may still
124 // turn-out to be contiguous at runtime.
125 bool isSimplyContiguous() const {
126 // If this can be described without a fir.box in FIR, this must
127 // be contiguous.
128 if (!hlfir::isBoxAddressOrValueType(getFirBase().getType()))
129 return true;
130 // Otherwise, if this entity has a visible declaration in FIR,
131 // or is the dereference of an allocatable or contiguous pointer
132 // it is simply contiguous.
133 if (auto varIface = getMaybeDereferencedVariableInterface())
134 return varIface.isAllocatable() || varIface.hasContiguousAttr();
135 return false;
136 }
137
138 fir::FortranVariableOpInterface getIfVariableInterface() const {
139 return this->getDefiningOp<fir::FortranVariableOpInterface>();
140 }
141
142 // Return a "declaration" operation for this variable if visible,
143 // or the "declaration" operation of the allocatable/pointer this
144 // variable was dereferenced from (if it is visible).
145 fir::FortranVariableOpInterface
146 getMaybeDereferencedVariableInterface() const {
147 mlir::Value base = *this;
148 if (auto loadOp = base.getDefiningOp<fir::LoadOp>())
149 base = loadOp.getMemref();
150 return base.getDefiningOp<fir::FortranVariableOpInterface>();
151 }
152
153 bool isOptional() const {
154 auto varIface = getIfVariableInterface();
155 return varIface ? varIface.isOptional() : false;
156 }
157
158 bool isParameter() const {
159 auto varIface = getIfVariableInterface();
160 return varIface ? varIface.isParameter() : false;
161 }
162
163 bool isAllocatable() const {
164 auto varIface = getIfVariableInterface();
165 return varIface ? varIface.isAllocatable() : false;
166 }
167
168 bool isPointer() const {
169 auto varIface = getIfVariableInterface();
170 return varIface ? varIface.isPointer() : false;
171 }
172
173 // Get the entity as an mlir SSA value containing all the shape, type
174 // parameters and dynamic shape information.
175 mlir::Value getBase() const { return *this; }
176
177 // Get the entity as a FIR base. This may not carry the shape and type
178 // parameters information, and even when it is a box with shape information.
179 // it will not contain the local lower bounds of the entity. This should
180 // be used with care when generating FIR code that does not need this
181 // information, or has access to it in other ways. Its advantage is that
182 // it will never be a fir.box for explicit shape arrays, leading to simpler
183 // FIR code generation.
184 mlir::Value getFirBase() const;
185};
186
193public:
194 explicit EntityWithAttributes(mlir::Value value) : Entity(value) {
195 assert(isFortranEntityWithAttributes(value) &&
196 "must be a value representing a Fortran value or variable");
197 }
198 EntityWithAttributes(fir::FortranVariableOpInterface variable)
199 : Entity(variable) {}
200 fir::FortranVariableOpInterface getIfVariable() const {
201 return getIfVariableInterface();
202 }
203};
204
210using CleanupFunction = std::function<void()>;
211std::pair<fir::ExtendedValue, std::optional<CleanupFunction>>
212translateToExtendedValue(mlir::Location loc, fir::FirOpBuilder &builder,
213 Entity entity, bool contiguousHint = false);
214
219translateToExtendedValue(mlir::Location loc, fir::FirOpBuilder &builder,
220 fir::FortranVariableOpInterface fortranVariable,
221 bool forceHlfirBase = false);
222
224fir::FortranVariableOpInterface
225genDeclare(mlir::Location loc, fir::FirOpBuilder &builder,
226 const fir::ExtendedValue &exv, llvm::StringRef name,
227 fir::FortranVariableFlagsAttr flags,
228 mlir::Value dummyScope = nullptr,
229 cuf::DataAttributeAttr dataAttr = {});
230
234hlfir::AssociateOp
235genAssociateExpr(mlir::Location loc, fir::FirOpBuilder &builder,
236 hlfir::Entity value, mlir::Type variableType,
237 llvm::StringRef name,
238 std::optional<mlir::NamedAttribute> attr = std::nullopt);
239
244mlir::Value genVariableRawAddress(mlir::Location loc,
245 fir::FirOpBuilder &builder,
246 hlfir::Entity var);
247
250mlir::Value genVariableBoxChar(mlir::Location loc, fir::FirOpBuilder &builder,
251 hlfir::Entity var);
252
254hlfir::Entity genVariableBox(mlir::Location loc, fir::FirOpBuilder &builder,
255 hlfir::Entity var);
256
261Entity loadTrivialScalar(mlir::Location loc, fir::FirOpBuilder &builder,
262 Entity entity);
263
266hlfir::Entity derefPointersAndAllocatables(mlir::Location loc,
267 fir::FirOpBuilder &builder,
268 Entity entity);
269
273hlfir::Entity getElementAt(mlir::Location loc, fir::FirOpBuilder &builder,
274 Entity entity, mlir::ValueRange oneBasedIndices);
277genBounds(mlir::Location loc, fir::FirOpBuilder &builder, Entity entity);
281genBounds(mlir::Location loc, fir::FirOpBuilder &builder, mlir::Value shape);
282
285llvm::SmallVector<mlir::Value> genLowerbounds(mlir::Location loc,
286 fir::FirOpBuilder &builder,
287 mlir::Value shape, unsigned rank);
288
290mlir::Value genShape(mlir::Location loc, fir::FirOpBuilder &builder,
291 Entity entity);
292
295mlir::Value genExtent(mlir::Location loc, fir::FirOpBuilder &builder,
296 hlfir::Entity entity, unsigned dim);
297
300mlir::Value genLBound(mlir::Location loc, fir::FirOpBuilder &builder,
301 hlfir::Entity entity, unsigned dim);
302
305llvm::SmallVector<mlir::Value> getIndexExtents(mlir::Location loc,
306 fir::FirOpBuilder &builder,
307 mlir::Value shape);
308
312getExplicitExtentsFromShape(mlir::Value shape, fir::FirOpBuilder &builder);
313
315void genLengthParameters(mlir::Location loc, fir::FirOpBuilder &builder,
316 Entity entity,
317 llvm::SmallVectorImpl<mlir::Value> &result);
318
321mlir::Value genCharLength(mlir::Location loc, fir::FirOpBuilder &builder,
322 Entity entity);
323
324mlir::Value genRank(mlir::Location loc, fir::FirOpBuilder &builder,
325 Entity entity, mlir::Type resultType);
326
331std::pair<mlir::Value, mlir::Value> genVariableFirBaseShapeAndParams(
332 mlir::Location loc, fir::FirOpBuilder &builder, Entity entity,
333 llvm::SmallVectorImpl<mlir::Value> &typeParams);
334
338mlir::Type getVariableElementType(hlfir::Entity variable);
343mlir::Type getEntityElementType(hlfir::Entity entity);
344
345using ElementalKernelGenerator = std::function<hlfir::Entity(
346 mlir::Location, fir::FirOpBuilder &, mlir::ValueRange)>;
353hlfir::ElementalOp genElementalOp(
354 mlir::Location loc, fir::FirOpBuilder &builder, mlir::Type elementType,
355 mlir::Value shape, mlir::ValueRange typeParams,
356 const ElementalKernelGenerator &genKernel, bool isUnordered = false,
357 mlir::Value polymorphicMold = {}, mlir::Type exprType = mlir::Type{});
358
360struct LoopNest {
361 mlir::Operation *outerOp = nullptr;
362 mlir::Block *body = nullptr;
363 llvm::SmallVector<mlir::Value> oneBasedIndices;
364};
365
373LoopNest genLoopNest(mlir::Location loc, fir::FirOpBuilder &builder,
374 mlir::ValueRange extents, bool isUnordered = false,
375 bool emitWorkshareLoop = false);
376inline LoopNest genLoopNest(mlir::Location loc, fir::FirOpBuilder &builder,
377 mlir::Value shape, bool isUnordered = false,
378 bool emitWorkshareLoop = false) {
379 return genLoopNest(loc, builder, getIndexExtents(loc, builder, shape),
380 isUnordered, emitWorkshareLoop);
381}
382
389using ReductionLoopBodyGenerator = std::function<llvm::SmallVector<mlir::Value>(
390 mlir::Location, fir::FirOpBuilder &, mlir::ValueRange, mlir::ValueRange)>;
391
409llvm::SmallVector<mlir::Value> genLoopNestWithReductions(
410 mlir::Location loc, fir::FirOpBuilder &builder, mlir::ValueRange extents,
411 mlir::ValueRange reductionInits, const ReductionLoopBodyGenerator &genBody,
412 bool isUnordered = false);
413
419hlfir::YieldElementOp inlineElementalOp(mlir::Location loc,
420 fir::FirOpBuilder &builder,
421 hlfir::ElementalOp elemental,
422 mlir::ValueRange oneBasedIndices);
423
431mlir::Value inlineElementalOp(
432 mlir::Location loc, fir::FirOpBuilder &builder,
433 hlfir::ElementalOpInterface elemental, mlir::ValueRange oneBasedIndices,
434 mlir::IRMapping &mapper,
435 const std::function<bool(hlfir::ElementalOp)> &mustRecursivelyInline);
436
441std::pair<hlfir::Entity, bool>
442computeEvaluateOpInNewTemp(mlir::Location, fir::FirOpBuilder &,
443 hlfir::EvaluateInMemoryOp evalInMem,
444 mlir::Value shape, mlir::ValueRange typeParams);
445
446// Clone the body of the hlfir.eval_in_mem operating on this the provided
447// storage. The provided storage must be a contiguous "raw" memory reference
448// (not a fir.box) big enough to hold the value computed by hlfir.eval_in_mem.
449// No runtime check is inserted by this utility to enforce that. It is also
450// usually invalid to provide some storage that is already addressed directly
451// or indirectly inside the hlfir.eval_in_mem body.
452void computeEvaluateOpIn(mlir::Location, fir::FirOpBuilder &,
453 hlfir::EvaluateInMemoryOp, mlir::Value storage);
454
455std::pair<fir::ExtendedValue, std::optional<hlfir::CleanupFunction>>
456convertToValue(mlir::Location loc, fir::FirOpBuilder &builder,
457 hlfir::Entity entity);
458
459std::pair<fir::ExtendedValue, std::optional<hlfir::CleanupFunction>>
460convertToAddress(mlir::Location loc, fir::FirOpBuilder &builder,
461 hlfir::Entity entity, mlir::Type targetType);
462
463std::pair<fir::ExtendedValue, std::optional<hlfir::CleanupFunction>>
464convertToBox(mlir::Location loc, fir::FirOpBuilder &builder,
465 hlfir::Entity entity, mlir::Type targetType);
466
468hlfir::ElementalOp cloneToElementalOp(mlir::Location loc,
469 fir::FirOpBuilder &builder,
470 hlfir::ElementalAddrOp elementalAddrOp);
471
477bool elementalOpMustProduceTemp(hlfir::ElementalOp elemental);
478
479std::pair<hlfir::Entity, mlir::Value>
480createTempFromMold(mlir::Location loc, fir::FirOpBuilder &builder,
481 hlfir::Entity mold);
482
483// TODO: this does not support polymorphic molds
484hlfir::Entity createStackTempFromMold(mlir::Location loc,
485 fir::FirOpBuilder &builder,
486 hlfir::Entity mold);
487
488hlfir::EntityWithAttributes convertCharacterKind(mlir::Location loc,
489 fir::FirOpBuilder &builder,
490 hlfir::Entity scalarChar,
491 int toKind);
492
506std::pair<hlfir::Entity, std::optional<hlfir::CleanupFunction>>
507genTypeAndKindConvert(mlir::Location loc, fir::FirOpBuilder &builder,
508 hlfir::Entity source, mlir::Type toType,
509 bool preserveLowerBounds);
510
513Entity loadElementAt(mlir::Location loc, fir::FirOpBuilder &builder,
514 Entity entity, mlir::ValueRange oneBasedIndices);
515
516} // namespace hlfir
517
518#endif // FORTRAN_OPTIMIZER_BUILDER_HLFIRTOOLS_H
Definition: BoxValue.h:478
Definition: FIRBuilder.h:55
Definition: HLFIRTools.h:192
Definition: HLFIRTools.h:51
bool isAssumedRank() const
Is this an assumed ranked entity?
Definition: HLFIRTools.h:76
int getRank() const
Return the rank of this entity or -1 if it is an assumed rank.
Definition: HLFIRTools.h:79
bool isArray() const
Is this an array or an assumed ranked entity?
Definition: HLFIRTools.h:73
bool isProcedure() const
Is this entity a procedure designator?
Definition: HLFIRTools.h:70
Definition: OpenACC.h:20
Definition: AbstractConverter.h:31
mlir::Type unwrapPassByRefType(mlir::Type t)
Definition: FIRType.h:266
bool isBoxProcAddressType(mlir::Type t)
Is this a fir.boxproc address type?
Definition: FIRType.h:479
bool isRecordWithTypeParameters(mlir::Type ty)
Return true iff ty is a RecordType with type parameters.
Definition: FIRType.h:394
bool isa_trivial(mlir::Type t)
Definition: FIRType.h:195
Definition: AbstractConverter.h:27
Structure to describe a loop nest.
Definition: HLFIRTools.h:360