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;
28
29class ArrayBoxValue;
30class BoxValue;
31class CharBoxValue;
33class MutableBoxValue;
35class ProcBoxValue;
36
37llvm::raw_ostream &operator<<(llvm::raw_ostream &, const CharBoxValue &);
38llvm::raw_ostream &operator<<(llvm::raw_ostream &, const ArrayBoxValue &);
39llvm::raw_ostream &operator<<(llvm::raw_ostream &, const CharArrayBoxValue &);
40llvm::raw_ostream &operator<<(llvm::raw_ostream &, const ProcBoxValue &);
41llvm::raw_ostream &operator<<(llvm::raw_ostream &, const MutableBoxValue &);
42llvm::raw_ostream &operator<<(llvm::raw_ostream &, const BoxValue &);
43llvm::raw_ostream &operator<<(llvm::raw_ostream &, const PolymorphicValue &);
44
45//===----------------------------------------------------------------------===//
46//
47// Boxed values
48//
49// Define a set of containers used internally by the lowering bridge to keep
50// track of extended values associated with a Fortran subexpression. These
51// associations are maintained during the construction of FIR.
52//
53//===----------------------------------------------------------------------===//
54
57using UnboxedValue = mlir::Value;
58
60class AbstractBox {
61public:
62 AbstractBox() = delete;
63 AbstractBox(mlir::Value addr) : addr{addr} {}
64
68 mlir::Value getAddr() const { return addr; }
69
70protected:
71 mlir::Value addr;
72};
73
76class CharBoxValue : public AbstractBox {
77public:
78 CharBoxValue(mlir::Value addr, mlir::Value len)
79 : AbstractBox{addr}, len{len} {
80 if (addr && mlir::isa<fir::BoxCharType>(addr.getType()))
81 fir::emitFatalError(addr.getLoc(),
82 "BoxChar should not be in CharBoxValue");
83 }
84
85 CharBoxValue clone(mlir::Value newBase) const { return {newBase, len}; }
86
88 mlir::Value getBuffer() const { return getAddr(); }
89
90 mlir::Value getLen() const { return len; }
91
92 friend llvm::raw_ostream &operator<<(llvm::raw_ostream &,
93 const CharBoxValue &);
94 LLVM_DUMP_METHOD void dump() const { llvm::errs() << *this; }
95
96protected:
97 mlir::Value len;
98};
99
101class PolymorphicValue : public AbstractBox {
102public:
103 PolymorphicValue(mlir::Value addr, mlir::Value sourceBox)
104 : AbstractBox{addr}, sourceBox{sourceBox} {}
105
106 PolymorphicValue clone(mlir::Value newBase) const {
107 return {newBase, sourceBox};
108 }
109
110 mlir::Value getSourceBox() const { return sourceBox; }
111
112 friend llvm::raw_ostream &operator<<(llvm::raw_ostream &,
113 const PolymorphicValue &);
114 LLVM_DUMP_METHOD void dump() const { llvm::errs() << *this; }
115
116protected:
117 mlir::Value sourceBox;
118};
119
124class AbstractArrayBox {
125public:
126 AbstractArrayBox() = default;
127 AbstractArrayBox(llvm::ArrayRef<mlir::Value> extents,
129 : extents{extents}, lbounds{lbounds} {}
130
131 // Every array has extents that describe its shape.
132 const llvm::SmallVectorImpl<mlir::Value> &getExtents() const {
133 return extents;
134 }
135
136 // An array expression may have user-defined lower bound values.
137 // If this vector is empty, the default in all dimensions in `1`.
138 const llvm::SmallVectorImpl<mlir::Value> &getLBounds() const {
139 return lbounds;
140 }
141
142 bool lboundsAllOne() const { return lbounds.empty(); }
143 std::size_t rank() const { return extents.size(); }
144
145protected:
148};
149
152class ArrayBoxValue : public PolymorphicValue, public AbstractArrayBox {
153public:
154 ArrayBoxValue(mlir::Value addr, llvm::ArrayRef<mlir::Value> extents,
155 llvm::ArrayRef<mlir::Value> lbounds = {},
156 mlir::Value sourceBox = {})
157 : PolymorphicValue{addr, sourceBox}, AbstractArrayBox{extents, lbounds} {}
158
159 ArrayBoxValue clone(mlir::Value newBase) const {
160 return {newBase, extents, lbounds};
161 }
162
163 friend llvm::raw_ostream &operator<<(llvm::raw_ostream &,
164 const ArrayBoxValue &);
165 LLVM_DUMP_METHOD void dump() const { llvm::errs() << *this; }
166};
167
169class CharArrayBoxValue : public CharBoxValue, public AbstractArrayBox {
170public:
171 CharArrayBoxValue(mlir::Value addr, mlir::Value len,
173 llvm::ArrayRef<mlir::Value> lbounds = {})
174 : CharBoxValue{addr, len}, AbstractArrayBox{extents, lbounds} {}
175
176 CharArrayBoxValue clone(mlir::Value newBase) const {
177 return {newBase, len, extents, lbounds};
178 }
179
180 CharBoxValue cloneElement(mlir::Value newBase) const {
181 return {newBase, len};
182 }
183
184 friend llvm::raw_ostream &operator<<(llvm::raw_ostream &,
185 const CharArrayBoxValue &);
186 LLVM_DUMP_METHOD void dump() const { llvm::errs() << *this; }
187};
188
191class ProcBoxValue : public AbstractBox {
192public:
193 ProcBoxValue(mlir::Value addr, mlir::Value context)
194 : AbstractBox{addr}, hostContext{context} {}
195
196 ProcBoxValue clone(mlir::Value newBase) const {
197 return {newBase, hostContext};
198 }
199
200 mlir::Value getHostContext() const { return hostContext; }
201
202 friend llvm::raw_ostream &operator<<(llvm::raw_ostream &,
203 const ProcBoxValue &);
204 LLVM_DUMP_METHOD void dump() const { llvm::errs() << *this; }
205
206protected:
207 mlir::Value hostContext;
208};
209
211class AbstractIrBox : public AbstractBox, public AbstractArrayBox {
212public:
213 AbstractIrBox(mlir::Value addr) : AbstractBox{addr} {}
214 AbstractIrBox(mlir::Value addr, llvm::ArrayRef<mlir::Value> lbounds,
216 : AbstractBox{addr}, AbstractArrayBox(extents, lbounds) {}
219 auto type = getAddr().getType();
220 if (auto pointedTy = fir::dyn_cast_ptrEleTy(type))
221 type = pointedTy;
222 return mlir::cast<fir::BaseBoxType>(type);
223 }
224
226 mlir::Type getBaseTy() const {
228 }
229
234 mlir::Type getMemTy() const {
235 auto ty = getBoxTy().getEleTy();
236 if (fir::isa_ref_type(ty))
237 return ty;
238 return fir::ReferenceType::get(ty, fir::isa_volatile_type(getBoxTy()));
239 }
240
242 mlir::Type getEleTy() const {
243 auto type = getBaseTy();
244 if (auto seqTy = mlir::dyn_cast<fir::SequenceType>(type))
245 return seqTy.getEleTy();
246 return type;
247 }
248
250 bool hasRank() const { return mlir::isa<fir::SequenceType>(getBaseTy()); }
252 bool hasAssumedRank() const {
253 auto seqTy = mlir::dyn_cast<fir::SequenceType>(getBaseTy());
254 return seqTy && seqTy.hasUnknownShape();
255 }
256
258 unsigned rank() const {
259 if (auto seqTy = mlir::dyn_cast<fir::SequenceType>(getBaseTy()))
260 return seqTy.getDimension();
261 return 0;
262 }
263
265 bool isCharacter() const { return fir::isa_char(getEleTy()); }
266
268 bool isDerived() const { return mlir::isa<fir::RecordType>(getEleTy()); }
269
270 bool isDerivedWithLenParameters() const {
272 }
273
276
281
282 unsigned corank() const { return fir::getBoxCorank(getBoxTy()); }
283};
284
292class BoxValue : public AbstractIrBox {
293public:
294 BoxValue(mlir::Value addr) : AbstractIrBox{addr} { assert(verify()); }
295 BoxValue(mlir::Value addr, llvm::ArrayRef<mlir::Value> lbounds,
296 llvm::ArrayRef<mlir::Value> explicitParams,
297 llvm::ArrayRef<mlir::Value> explicitExtents = {})
298 : AbstractIrBox{addr, lbounds, explicitExtents},
299 explicitParams{explicitParams} {
300 assert(verify());
301 }
302 // TODO: check contiguous attribute of addr
303 bool isContiguous() const { return false; }
304
305 // Replace the fir.box, keeping any non-deferred parameters.
306 BoxValue clone(mlir::Value newBox) const {
307 return {newBox, lbounds, explicitParams, extents};
308 }
309
310 friend llvm::raw_ostream &operator<<(llvm::raw_ostream &, const BoxValue &);
311 LLVM_DUMP_METHOD void dump() const { llvm::errs() << *this; }
312
313 llvm::ArrayRef<mlir::Value> getLBounds() const { return lbounds; }
314
315 // The extents member is not guaranteed to be field for arrays. It is only
316 // guaranteed to be field for explicit shape arrays. In general,
317 // explicit-shape will not come as descriptors, so this field will be empty in
318 // most cases. The exception are derived types with LEN parameters and
319 // polymorphic dummy argument arrays. It may be possible for the explicit
320 // extents to conflict with the shape information that is in the box according
321 // to 15.5.2.11 sequence association rules.
322 llvm::ArrayRef<mlir::Value> getExplicitExtents() const { return extents; }
323
324 llvm::ArrayRef<mlir::Value> getExplicitParameters() const {
325 return explicitParams;
326 }
327
328protected:
329 // Verify constructor invariants.
330 bool verify() const;
331
332 // Only field when the BoxValue has explicit LEN parameters.
333 // Otherwise, the LEN parameters are in the fir.box.
335};
336
344public:
345 bool isEmpty() const { return !addr; }
346 mlir::Value addr;
355};
356
361class MutableBoxValue : public AbstractIrBox {
362public:
367 MutableBoxValue(mlir::Value addr, mlir::ValueRange lenParameters,
369 : AbstractIrBox(addr), lenParams{lenParameters.begin(),
370 lenParameters.end()},
372 // Currently only accepts fir.(ref/ptr/heap)<fir.box<type>> mlir::Value for
373 // the address. This may change if we accept
374 // fir.(ref/ptr/heap)<fir.heap<type>> for scalar without LEN parameters.
375 assert(verify() &&
376 "MutableBoxValue requires mem ref to fir.box<fir.[heap|ptr]<type>>");
377 }
378
379 bool isPointer() const {
380 return mlir::isa<fir::PointerType>(getBoxTy().getEleTy());
381 }
382
383 bool isAllocatable() const {
384 return mlir::isa<fir::HeapType>(getBoxTy().getEleTy());
385 }
386 // Replace the fir.ref<fir.box>, keeping any non-deferred parameters.
387 MutableBoxValue clone(mlir::Value newBox) const {
388 return {newBox, lenParams, mutableProperties};
389 }
391 bool hasNonDeferredLenParams() const { return !lenParams.empty(); }
394 friend llvm::raw_ostream &operator<<(llvm::raw_ostream &,
395 const MutableBoxValue &);
396 LLVM_DUMP_METHOD void dump() const { llvm::errs() << *this; }
397
400 bool isDescribedByVariables() const { return !mutableProperties.isEmpty(); }
401
402 const MutableProperties &getMutableProperties() const {
403 return mutableProperties;
404 }
405
406protected:
408 bool verify() const;
417};
418
419class ExtendedValue;
420
423mlir::Value getBase(const ExtendedValue &exv);
424
427mlir::Value getLen(const ExtendedValue &exv);
428
430llvm::raw_ostream &operator<<(llvm::raw_ostream &, const ExtendedValue &);
431
434ExtendedValue substBase(const ExtendedValue &exv, mlir::Value base);
435
438bool isArray(const ExtendedValue &exv);
439
442
443//===----------------------------------------------------------------------===//
444// Functions that may generate IR to recover properties from extended values.
445//===----------------------------------------------------------------------===//
446namespace factory {
447
453 FirOpBuilder &builder,
454 const ExtendedValue &exv);
455
456// The generalized function to get a vector of extents is
460getExtents(mlir::Location loc, FirOpBuilder &builder, const ExtendedValue &box);
461
462} // namespace factory
463
469class ExtendedValue : public details::matcher<ExtendedValue> {
470public:
471 using VT =
474
475 ExtendedValue() : box{UnboxedValue{}} {}
476 template <typename A, typename = std::enable_if_t<
477 !std::is_same_v<std::decay_t<A>, ExtendedValue>>>
478 constexpr ExtendedValue(A &&a) : box{std::forward<A>(a)} {
479 if (const auto *b = getUnboxed()) {
480 if (*b) {
481 auto type = b->getType();
482 if (mlir::isa<fir::BoxCharType>(type))
483 fir::emitFatalError(b->getLoc(), "BoxChar should be unboxed");
484 type = fir::unwrapSequenceType(fir::unwrapRefType(type));
485 if (fir::isa_char(type))
486 fir::emitFatalError(b->getLoc(),
487 "character buffer should be in CharBoxValue");
488 }
489 }
490 }
491
492 template <typename A>
493 constexpr const A *getBoxOf() const {
494 return std::get_if<A>(&box);
495 }
496
497 constexpr const CharBoxValue *getCharBox() const {
498 return getBoxOf<CharBoxValue>();
499 }
500
501 constexpr const UnboxedValue *getUnboxed() const {
502 return getBoxOf<UnboxedValue>();
503 }
504
505 unsigned rank() const {
506 return match([](const fir::UnboxedValue &box) -> unsigned { return 0; },
507 [](const fir::CharBoxValue &box) -> unsigned { return 0; },
508 [](const fir::ProcBoxValue &box) -> unsigned { return 0; },
509 [](const fir::PolymorphicValue &box) -> unsigned { return 0; },
510 [](const auto &box) -> unsigned { return box.rank(); });
511 }
512
513 bool isPolymorphic() const {
514 return match([](const fir::PolymorphicValue &box) -> bool { return true; },
515 [](const fir::ArrayBoxValue &box) -> bool {
516 return box.getSourceBox() ? true : false;
517 },
518 [](const auto &box) -> bool { return false; });
519 }
520
521 bool hasAssumedRank() const {
522 return match(
523 [](const fir::BoxValue &box) -> bool { return box.hasAssumedRank(); },
524 [](const fir::MutableBoxValue &box) -> bool {
525 return box.hasAssumedRank();
526 },
527 [](const auto &box) -> bool { return false; });
528 }
529
531 LLVM_DUMP_METHOD void dump() const { llvm::errs() << *this << '\n'; }
532
533 friend llvm::raw_ostream &operator<<(llvm::raw_ostream &,
534 const ExtendedValue &);
535
536 const VT &matchee() const { return box; }
537
538private:
539 VT box;
540};
541
543inline bool isUnboxedValue(const ExtendedValue &exv) {
544 return exv.match(
545 [](const fir::UnboxedValue &box) { return box ? true : false; },
546 [](const auto &) { return false; });
547}
548
551inline mlir::Type getBaseTypeOf(const ExtendedValue &exv) {
552 return exv.match(
553 [](const fir::MutableBoxValue &box) { return box.getBaseTy(); },
554 [](const fir::BoxValue &box) { return box.getBaseTy(); },
555 [&](const auto &) {
556 return fir::unwrapRefType(fir::getBase(exv).getType());
557 });
558}
559
562inline mlir::Type getElementTypeOf(const ExtendedValue &exv) {
564}
565
570
571} // namespace fir
572
573#endif // FORTRAN_OPTIMIZER_BUILDER_BOXVALUE_H
mlir::Value getAddr() const
Definition BoxValue.h:68
fir::BaseBoxType getBoxTy() const
Get the fir.box<type> part of the address type.
Definition BoxValue.h:218
bool isUnlimitedPolymorphic() const
Is this a CLASS(*)/TYPE(*)?
Definition BoxValue.h:278
bool isDerived() const
Is this a derived type entity ?
Definition BoxValue.h:268
mlir::Type getBaseTy() const
Definition BoxValue.h:226
mlir::Type getEleTy() const
Get the scalar type related to the described entity.
Definition BoxValue.h:242
bool isCharacter() const
Is this a character entity ?
Definition BoxValue.h:265
bool hasRank() const
Is the entity an array or an assumed rank ?
Definition BoxValue.h:250
bool hasAssumedRank() const
Is this an assumed rank ?
Definition BoxValue.h:252
unsigned rank() const
Definition BoxValue.h:258
mlir::Type getMemTy() const
Definition BoxValue.h:234
bool isPolymorphic() const
Is this a polymorphic entity?
Definition BoxValue.h:275
Definition BoxValue.h:152
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:1482
Definition BoxValue.h:292
bool verify() const
Definition BoxValue.cpp:212
Expressions of type CHARACTER and with rank > 0.
Definition BoxValue.h:169
Definition BoxValue.h:76
mlir::Value getBuffer() const
Convenience alias to get the memory reference to the buffer.
Definition BoxValue.h:88
Definition BoxValue.h:469
LLVM_DUMP_METHOD void dump() const
LLVM style debugging of extended values.
Definition BoxValue.h:531
friend llvm::raw_ostream & operator<<(llvm::raw_ostream &, const ExtendedValue &)
Pretty-print an extended value.
Definition FIRBuilder.h:59
Definition BoxValue.h:361
MutableBoxValue(mlir::Value addr, mlir::ValueRange lenParameters, MutableProperties mutableProperties)
Definition BoxValue.h:367
bool hasNonDeferredLenParams() const
Does this entity has any non deferred LEN parameters?
Definition BoxValue.h:391
bool isAllocatable() const
Is this an allocatable ?
Definition BoxValue.h:383
llvm::SmallVector< mlir::Value, 2 > lenParams
Definition BoxValue.h:412
bool isDescribedByVariables() const
Definition BoxValue.h:400
bool isPointer() const
Is this a Fortran pointer ?
Definition BoxValue.h:379
MutableProperties mutableProperties
Definition BoxValue.h:416
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:393
Definition BoxValue.h:343
llvm::SmallVector< mlir::Value, 2 > deferredParams
Definition BoxValue.h:354
Polymorphic value associated with a dynamic type descriptor.
Definition BoxValue.h:101
Definition BoxValue.h:191
Definition FIRType.h:106
Definition OpenACC.h:20
Definition BoxValue.h:446
llvm::SmallVector< mlir::Value > getTypeParams(mlir::Location loc, FirOpBuilder &builder, const ExtendedValue &exv)
Definition FIRBuilder.cpp:1155
llvm::SmallVector< mlir::Value > getExtents(mlir::Location loc, FirOpBuilder &builder, const ExtendedValue &box)
Definition FIRBuilder.cpp:1081
Definition AbstractConverter.h:37
bool isa_ref_type(mlir::Type t)
Is t a FIR dialect type that implies a memory (de)reference?
Definition FIRType.h:135
bool isa_volatile_type(mlir::Type t)
Definition FIRType.cpp:766
bool isUnlimitedPolymorphicType(mlir::Type ty)
Definition FIRType.cpp:418
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:228
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:543
mlir::Value UnboxedValue
Definition BoxValue.h:57
mlir::Type dyn_cast_ptrEleTy(mlir::Type t)
Definition FIRType.cpp:257
mlir::Type getElementTypeOf(const ExtendedValue &exv)
Definition BoxValue.h:562
mlir::Value getBase(const ExtendedValue &exv)
Definition BoxValue.cpp:21
mlir::Type dyn_cast_ptrOrBoxEleTy(mlir::Type t)
Definition FIRType.cpp:264
bool isPolymorphicType(mlir::Type ty)
Definition FIRType.cpp:410
unsigned getBoxCorank(mlir::Type boxTy)
Get the corank from a !fir.box type.
Definition FIRType.cpp:488
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:445
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:551
mlir::Type unwrapSequenceType(mlir::Type t)
If t is a SequenceType return its element type, otherwise return t.
Definition FIRType.h:290
bool isDerivedWithLenParameters(const ExtendedValue &exv)
Is the extended value exv a derived type with LEN parameters?
Definition BoxValue.h:567
Definition Matcher.h:25