FLANG
BoxValue.h
1//===-- BoxValue.h -- internal box values -----------------------*- 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_BOXVALUE_H
14#define FORTRAN_OPTIMIZER_BUILDER_BOXVALUE_H
15
16#include "flang/Optimizer/Dialect/FIRType.h"
17#include "flang/Optimizer/Support/FatalError.h"
18#include "flang/Optimizer/Support/Matcher.h"
19#include "mlir/IR/OperationSupport.h"
20#include "mlir/IR/Value.h"
21#include "llvm/ADT/SmallVector.h"
22#include "llvm/Support/Compiler.h"
23#include "llvm/Support/raw_ostream.h"
24#include <utility>
25
26namespace fir {
27class FirOpBuilder;
28class ArrayLoadOp;
29
30class ArrayBoxValue;
31class BoxValue;
32class CharBoxValue;
33class CharArrayBoxValue;
34class MutableBoxValue;
35class PolymorphicValue;
36class ProcBoxValue;
37
38llvm::raw_ostream &operator<<(llvm::raw_ostream &, const CharBoxValue &);
39llvm::raw_ostream &operator<<(llvm::raw_ostream &, const ArrayBoxValue &);
40llvm::raw_ostream &operator<<(llvm::raw_ostream &, const CharArrayBoxValue &);
41llvm::raw_ostream &operator<<(llvm::raw_ostream &, const ProcBoxValue &);
42llvm::raw_ostream &operator<<(llvm::raw_ostream &, const MutableBoxValue &);
43llvm::raw_ostream &operator<<(llvm::raw_ostream &, const BoxValue &);
44llvm::raw_ostream &operator<<(llvm::raw_ostream &, const PolymorphicValue &);
45
46//===----------------------------------------------------------------------===//
47//
48// Boxed values
49//
50// Define a set of containers used internally by the lowering bridge to keep
51// track of extended values associated with a Fortran subexpression. These
52// associations are maintained during the construction of FIR.
53//
54//===----------------------------------------------------------------------===//
55
58using UnboxedValue = mlir::Value;
59
62public:
63 AbstractBox() = delete;
64 AbstractBox(mlir::Value addr) : addr{addr} {}
65
69 mlir::Value getAddr() const { return addr; }
70
71protected:
72 mlir::Value addr;
73};
74
77class CharBoxValue : public AbstractBox {
78public:
79 CharBoxValue(mlir::Value addr, mlir::Value len)
80 : AbstractBox{addr}, len{len} {
81 if (addr && mlir::isa<fir::BoxCharType>(addr.getType()))
82 fir::emitFatalError(addr.getLoc(),
83 "BoxChar should not be in CharBoxValue");
84 }
85
86 CharBoxValue clone(mlir::Value newBase) const { return {newBase, len}; }
87
89 mlir::Value getBuffer() const { return getAddr(); }
90
91 mlir::Value getLen() const { return len; }
92
93 friend llvm::raw_ostream &operator<<(llvm::raw_ostream &,
94 const CharBoxValue &);
95 LLVM_DUMP_METHOD void dump() const { llvm::errs() << *this; }
96
97protected:
98 mlir::Value len;
99};
100
103public:
104 PolymorphicValue(mlir::Value addr, mlir::Value sourceBox)
105 : AbstractBox{addr}, sourceBox{sourceBox} {}
106
107 PolymorphicValue clone(mlir::Value newBase) const {
108 return {newBase, sourceBox};
109 }
110
111 mlir::Value getSourceBox() const { return sourceBox; }
112
113 friend llvm::raw_ostream &operator<<(llvm::raw_ostream &,
114 const PolymorphicValue &);
115 LLVM_DUMP_METHOD void dump() const { llvm::errs() << *this; }
116
117protected:
118 mlir::Value sourceBox;
119};
120
126public:
127 AbstractArrayBox() = default;
130 : extents{extents}, lbounds{lbounds} {}
131
132 // Every array has extents that describe its shape.
133 const llvm::SmallVectorImpl<mlir::Value> &getExtents() const {
134 return extents;
135 }
136
137 // An array expression may have user-defined lower bound values.
138 // If this vector is empty, the default in all dimensions in `1`.
139 const llvm::SmallVectorImpl<mlir::Value> &getLBounds() const {
140 return lbounds;
141 }
142
143 bool lboundsAllOne() const { return lbounds.empty(); }
144 std::size_t rank() const { return extents.size(); }
145
146protected:
149};
150
154public:
155 ArrayBoxValue(mlir::Value addr, llvm::ArrayRef<mlir::Value> extents,
156 llvm::ArrayRef<mlir::Value> lbounds = {},
157 mlir::Value sourceBox = {})
158 : PolymorphicValue{addr, sourceBox}, AbstractArrayBox{extents, lbounds} {}
159
160 ArrayBoxValue clone(mlir::Value newBase) const {
161 return {newBase, extents, lbounds};
162 }
163
164 friend llvm::raw_ostream &operator<<(llvm::raw_ostream &,
165 const ArrayBoxValue &);
166 LLVM_DUMP_METHOD void dump() const { llvm::errs() << *this; }
167};
168
171public:
172 CharArrayBoxValue(mlir::Value addr, mlir::Value len,
174 llvm::ArrayRef<mlir::Value> lbounds = {})
175 : CharBoxValue{addr, len}, AbstractArrayBox{extents, lbounds} {}
176
177 CharArrayBoxValue clone(mlir::Value newBase) const {
178 return {newBase, len, extents, lbounds};
179 }
180
181 CharBoxValue cloneElement(mlir::Value newBase) const {
182 return {newBase, len};
183 }
184
185 friend llvm::raw_ostream &operator<<(llvm::raw_ostream &,
186 const CharArrayBoxValue &);
187 LLVM_DUMP_METHOD void dump() const { llvm::errs() << *this; }
188};
189
192class ProcBoxValue : public AbstractBox {
193public:
194 ProcBoxValue(mlir::Value addr, mlir::Value context)
195 : AbstractBox{addr}, hostContext{context} {}
196
197 ProcBoxValue clone(mlir::Value newBase) const {
198 return {newBase, hostContext};
199 }
200
201 mlir::Value getHostContext() const { return hostContext; }
202
203 friend llvm::raw_ostream &operator<<(llvm::raw_ostream &,
204 const ProcBoxValue &);
205 LLVM_DUMP_METHOD void dump() const { llvm::errs() << *this; }
206
207protected:
208 mlir::Value hostContext;
209};
210
213public:
214 AbstractIrBox(mlir::Value addr) : AbstractBox{addr} {}
215 AbstractIrBox(mlir::Value addr, llvm::ArrayRef<mlir::Value> lbounds,
217 : AbstractBox{addr}, AbstractArrayBox(extents, lbounds) {}
220 auto type = getAddr().getType();
221 if (auto pointedTy = fir::dyn_cast_ptrEleTy(type))
222 type = pointedTy;
223 return mlir::cast<fir::BaseBoxType>(type);
224 }
227 mlir::Type getBaseTy() const {
229 }
230
235 mlir::Type getMemTy() const {
236 auto ty = getBoxTy().getEleTy();
237 if (fir::isa_ref_type(ty))
238 return ty;
239 return fir::ReferenceType::get(ty);
240 }
241
243 mlir::Type getEleTy() const {
244 auto type = getBaseTy();
245 if (auto seqTy = mlir::dyn_cast<fir::SequenceType>(type))
246 return seqTy.getEleTy();
247 return type;
248 }
249
251 bool hasRank() const { return mlir::isa<fir::SequenceType>(getBaseTy()); }
253 bool hasAssumedRank() const {
254 auto seqTy = mlir::dyn_cast<fir::SequenceType>(getBaseTy());
255 return seqTy && seqTy.hasUnknownShape();
256 }
259 unsigned rank() const {
260 if (auto seqTy = mlir::dyn_cast<fir::SequenceType>(getBaseTy()))
261 return seqTy.getDimension();
262 return 0;
263 }
264
266 bool isCharacter() const { return fir::isa_char(getEleTy()); }
267
269 bool isDerived() const { return mlir::isa<fir::RecordType>(getEleTy()); }
270
271 bool isDerivedWithLenParameters() const {
273 }
274
277
281 }
282};
283
291class BoxValue : public AbstractIrBox {
292public:
293 BoxValue(mlir::Value addr) : AbstractIrBox{addr} { assert(verify()); }
294 BoxValue(mlir::Value addr, llvm::ArrayRef<mlir::Value> lbounds,
295 llvm::ArrayRef<mlir::Value> explicitParams,
296 llvm::ArrayRef<mlir::Value> explicitExtents = {})
297 : AbstractIrBox{addr, lbounds, explicitExtents},
298 explicitParams{explicitParams} {
299 assert(verify());
300 }
301 // TODO: check contiguous attribute of addr
302 bool isContiguous() const { return false; }
303
304 // Replace the fir.box, keeping any non-deferred parameters.
305 BoxValue clone(mlir::Value newBox) const {
306 return {newBox, lbounds, explicitParams, extents};
307 }
308
309 friend llvm::raw_ostream &operator<<(llvm::raw_ostream &, const BoxValue &);
310 LLVM_DUMP_METHOD void dump() const { llvm::errs() << *this; }
311
312 llvm::ArrayRef<mlir::Value> getLBounds() const { return lbounds; }
313
314 // The extents member is not guaranteed to be field for arrays. It is only
315 // guaranteed to be field for explicit shape arrays. In general,
316 // explicit-shape will not come as descriptors, so this field will be empty in
317 // most cases. The exception are derived types with LEN parameters and
318 // polymorphic dummy argument arrays. It may be possible for the explicit
319 // extents to conflict with the shape information that is in the box according
320 // to 15.5.2.11 sequence association rules.
321 llvm::ArrayRef<mlir::Value> getExplicitExtents() const { return extents; }
322
323 llvm::ArrayRef<mlir::Value> getExplicitParameters() const {
324 return explicitParams;
325 }
326
327protected:
328 // Verify constructor invariants.
329 bool verify() const;
330
331 // Only field when the BoxValue has explicit LEN parameters.
332 // Otherwise, the LEN parameters are in the fir.box.
334};
335
343public:
344 bool isEmpty() const { return !addr; }
345 mlir::Value addr;
354};
355
361public:
366 MutableBoxValue(mlir::Value addr, mlir::ValueRange lenParameters,
368 : AbstractIrBox(addr), lenParams{lenParameters.begin(),
369 lenParameters.end()},
371 // Currently only accepts fir.(ref/ptr/heap)<fir.box<type>> mlir::Value for
372 // the address. This may change if we accept
373 // fir.(ref/ptr/heap)<fir.heap<type>> for scalar without LEN parameters.
374 assert(verify() &&
375 "MutableBoxValue requires mem ref to fir.box<fir.[heap|ptr]<type>>");
376 }
378 bool isPointer() const {
379 return mlir::isa<fir::PointerType>(getBoxTy().getEleTy());
380 }
382 bool isAllocatable() const {
383 return mlir::isa<fir::HeapType>(getBoxTy().getEleTy());
384 }
385 // Replace the fir.ref<fir.box>, keeping any non-deferred parameters.
386 MutableBoxValue clone(mlir::Value newBox) const {
387 return {newBox, lenParams, mutableProperties};
388 }
390 bool hasNonDeferredLenParams() const { return !lenParams.empty(); }
393 friend llvm::raw_ostream &operator<<(llvm::raw_ostream &,
394 const MutableBoxValue &);
395 LLVM_DUMP_METHOD void dump() const { llvm::errs() << *this; }
396
399 bool isDescribedByVariables() const { return !mutableProperties.isEmpty(); }
400
401 const MutableProperties &getMutableProperties() const {
402 return mutableProperties;
403 }
404
405protected:
407 bool verify() const;
416};
417
418class ExtendedValue;
419
422mlir::Value getBase(const ExtendedValue &exv);
423
426mlir::Value getLen(const ExtendedValue &exv);
427
429llvm::raw_ostream &operator<<(llvm::raw_ostream &, const ExtendedValue &);
430
433ExtendedValue substBase(const ExtendedValue &exv, mlir::Value base);
434
437bool isArray(const ExtendedValue &exv);
438
441
442//===----------------------------------------------------------------------===//
443// Functions that may generate IR to recover properties from extended values.
444//===----------------------------------------------------------------------===//
445namespace factory {
446
452 FirOpBuilder &builder,
453 const ExtendedValue &exv);
454
458getTypeParams(mlir::Location loc, FirOpBuilder &builder, ArrayLoadOp load);
459
460// The generalized function to get a vector of extents is
464getExtents(mlir::Location loc, FirOpBuilder &builder, const ExtendedValue &box);
465
468mlir::Value getExtentAtDimension(mlir::Location loc, FirOpBuilder &builder,
469 const ExtendedValue &exv, unsigned dim);
470
471} // namespace factory
472
478class ExtendedValue : public details::matcher<ExtendedValue> {
479public:
480 using VT =
483
484 ExtendedValue() : box{UnboxedValue{}} {}
485 template <typename A, typename = std::enable_if_t<
486 !std::is_same_v<std::decay_t<A>, ExtendedValue>>>
487 constexpr ExtendedValue(A &&a) : box{std::forward<A>(a)} {
488 if (const auto *b = getUnboxed()) {
489 if (*b) {
490 auto type = b->getType();
491 if (mlir::isa<fir::BoxCharType>(type))
492 fir::emitFatalError(b->getLoc(), "BoxChar should be unboxed");
493 type = fir::unwrapSequenceType(fir::unwrapRefType(type));
494 if (fir::isa_char(type))
495 fir::emitFatalError(b->getLoc(),
496 "character buffer should be in CharBoxValue");
497 }
498 }
499 }
500
501 template <typename A>
502 constexpr const A *getBoxOf() const {
503 return std::get_if<A>(&box);
504 }
505
506 constexpr const CharBoxValue *getCharBox() const {
507 return getBoxOf<CharBoxValue>();
508 }
509
510 constexpr const UnboxedValue *getUnboxed() const {
511 return getBoxOf<UnboxedValue>();
512 }
513
514 unsigned rank() const {
515 return match([](const fir::UnboxedValue &box) -> unsigned { return 0; },
516 [](const fir::CharBoxValue &box) -> unsigned { return 0; },
517 [](const fir::ProcBoxValue &box) -> unsigned { return 0; },
518 [](const fir::PolymorphicValue &box) -> unsigned { return 0; },
519 [](const auto &box) -> unsigned { return box.rank(); });
520 }
521
522 bool isPolymorphic() const {
523 return match([](const fir::PolymorphicValue &box) -> bool { return true; },
524 [](const fir::ArrayBoxValue &box) -> bool {
525 return box.getSourceBox() ? true : false;
526 },
527 [](const auto &box) -> bool { return false; });
528 }
529
530 bool hasAssumedRank() const {
531 return match(
532 [](const fir::BoxValue &box) -> bool { return box.hasAssumedRank(); },
533 [](const fir::MutableBoxValue &box) -> bool {
534 return box.hasAssumedRank();
535 },
536 [](const auto &box) -> bool { return false; });
537 }
538
540 LLVM_DUMP_METHOD void dump() const { llvm::errs() << *this << '\n'; }
541
542 friend llvm::raw_ostream &operator<<(llvm::raw_ostream &,
543 const ExtendedValue &);
544
545 const VT &matchee() const { return box; }
546
547private:
548 VT box;
549};
550
552inline bool isUnboxedValue(const ExtendedValue &exv) {
553 return exv.match(
554 [](const fir::UnboxedValue &box) { return box ? true : false; },
555 [](const auto &) { return false; });
556}
557
560inline mlir::Type getBaseTypeOf(const ExtendedValue &exv) {
561 return exv.match(
562 [](const fir::MutableBoxValue &box) { return box.getBaseTy(); },
563 [](const fir::BoxValue &box) { return box.getBaseTy(); },
564 [&](const auto &) {
565 return fir::unwrapRefType(fir::getBase(exv).getType());
566 });
567}
568
571inline mlir::Type getElementTypeOf(const ExtendedValue &exv) {
573}
574
578}
579
580} // namespace fir
581
582#endif // FORTRAN_OPTIMIZER_BUILDER_BOXVALUE_H
Definition: BoxValue.h:125
Abstract base class.
Definition: BoxValue.h:61
mlir::Value getAddr() const
Definition: BoxValue.h:69
Base class for values associated to a fir.box or fir.ref<fir.box>.
Definition: BoxValue.h:212
fir::BaseBoxType getBoxTy() const
Get the fir.box<type> part of the address type.
Definition: BoxValue.h:219
bool isUnlimitedPolymorphic() const
Is this a CLASS(*)/TYPE(*)?
Definition: BoxValue.h:279
bool isDerived() const
Is this a derived type entity ?
Definition: BoxValue.h:269
mlir::Type getBaseTy() const
Definition: BoxValue.h:227
mlir::Type getEleTy() const
Get the scalar type related to the described entity.
Definition: BoxValue.h:243
bool isCharacter() const
Is this a character entity ?
Definition: BoxValue.h:266
bool hasRank() const
Is the entity an array or an assumed rank ?
Definition: BoxValue.h:251
bool hasAssumedRank() const
Is this an assumed rank ?
Definition: BoxValue.h:253
unsigned rank() const
Definition: BoxValue.h:259
mlir::Type getMemTy() const
Definition: BoxValue.h:235
bool isPolymorphic() const
Is this a polymorphic entity?
Definition: BoxValue.h:276
Definition: BoxValue.h:153
This class provides a shared interface for box and class types.
Definition: FIRType.h:40
mlir::Type getEleTy() const
Returns the element type of this box type.
Definition: FIRType.cpp:1274
Definition: BoxValue.h:291
bool verify() const
Definition: BoxValue.cpp:212
Expressions of type CHARACTER and with rank > 0.
Definition: BoxValue.h:170
Definition: BoxValue.h:77
mlir::Value getBuffer() const
Convenience alias to get the memory reference to the buffer.
Definition: BoxValue.h:89
Definition: BoxValue.h:478
LLVM_DUMP_METHOD void dump() const
LLVM style debugging of extended values.
Definition: BoxValue.h:540
friend llvm::raw_ostream & operator<<(llvm::raw_ostream &, const ExtendedValue &)
Pretty-print an extended value.
Definition: FIRBuilder.h:55
Definition: BoxValue.h:360
MutableBoxValue(mlir::Value addr, mlir::ValueRange lenParameters, MutableProperties mutableProperties)
Definition: BoxValue.h:366
bool hasNonDeferredLenParams() const
Does this entity has any non deferred LEN parameters?
Definition: BoxValue.h:390
bool isAllocatable() const
Is this an allocatable ?
Definition: BoxValue.h:382
llvm::SmallVector< mlir::Value, 2 > lenParams
Definition: BoxValue.h:411
bool isDescribedByVariables() const
Definition: BoxValue.h:399
bool isPointer() const
Is this a Fortran pointer ?
Definition: BoxValue.h:378
MutableProperties mutableProperties
Definition: BoxValue.h:415
bool verify() const
Validate the address type form in the constructor.
Definition: BoxValue.cpp:190
llvm::ArrayRef< mlir::Value > nonDeferredLenParams() const
Return the non deferred LEN parameters.
Definition: BoxValue.h:392
Definition: BoxValue.h:342
llvm::SmallVector< mlir::Value, 2 > deferredParams
Definition: BoxValue.h:353
Polymorphic value associated with a dynamic type descriptor.
Definition: BoxValue.h:102
Definition: BoxValue.h:192
Definition: FIRType.h:77
Definition: OpenACC.h:20
Definition: AbstractConverter.h:31
bool isa_ref_type(mlir::Type t)
Is t a FIR dialect type that implies a memory (de)reference?
Definition: FIRType.h:106
bool isUnlimitedPolymorphicType(mlir::Type ty)
Definition: FIRType.cpp:366
mlir::Value getLen(const ExtendedValue &exv)
Definition: BoxValue.cpp:26
bool isa_char(mlir::Type t)
Is t a CHARACTER type? Does not check the length.
Definition: FIRType.h:191
llvm::SmallVector< mlir::Value > getTypeParams(const ExtendedValue &exv)
Get the type parameters for exv.
Definition: BoxValue.cpp:47
bool isUnboxedValue(const ExtendedValue &exv)
Is the extended value exv unboxed and non-null?
Definition: BoxValue.h:552
mlir::Type dyn_cast_ptrEleTy(mlir::Type t)
Definition: FIRType.cpp:216
mlir::Type getElementTypeOf(const ExtendedValue &exv)
Definition: BoxValue.h:571
mlir::Value getBase(const ExtendedValue &exv)
Definition: BoxValue.cpp:21
mlir::Type dyn_cast_ptrOrBoxEleTy(mlir::Type t)
Definition: FIRType.cpp:223
mlir::Value UnboxedValue
Definition: BoxValue.h:58
bool isPolymorphicType(mlir::Type ty)
Definition: FIRType.cpp:358
ExtendedValue substBase(const ExtendedValue &exv, mlir::Value base)
Definition: BoxValue.cpp:39
bool isArray(const ExtendedValue &exv)
Definition: BoxValue.cpp:72
bool isRecordWithTypeParameters(mlir::Type ty)
Return true iff ty is a RecordType with type parameters.
Definition: FIRType.h:394
void emitFatalError(mlir::Location loc, const llvm::Twine &message, bool genCrashDiag=true)
Definition: FatalError.h:25
mlir::Type getBaseTypeOf(const ExtendedValue &exv)
Definition: BoxValue.h:560
mlir::Type unwrapSequenceType(mlir::Type t)
If t is a SequenceType return its element type, otherwise return t.
Definition: FIRType.h:249
bool isDerivedWithLenParameters(const ExtendedValue &exv)
Is the extended value exv a derived type with LEN parameters?
Definition: BoxValue.h:576
Definition: Matcher.h:25