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;
34class MutableBoxValue;
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
61class AbstractBox {
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
102class PolymorphicValue : public AbstractBox {
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
125class AbstractArrayBox {
126public:
127 AbstractArrayBox() = default;
128 AbstractArrayBox(llvm::ArrayRef<mlir::Value> extents,
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
153class ArrayBoxValue : public PolymorphicValue, public AbstractArrayBox {
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
170class CharArrayBoxValue : public CharBoxValue, public AbstractArrayBox {
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
212class AbstractIrBox : public AbstractBox, public AbstractArrayBox {
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 }
225
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, fir::isa_volatile_type(getBoxTy()));
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 }
257
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
282
283 unsigned corank() const { return fir::getBoxCorank(getBoxTy()); }
284};
285
293class BoxValue : public AbstractIrBox {
294public:
295 BoxValue(mlir::Value addr) : AbstractIrBox{addr} { assert(verify()); }
296 BoxValue(mlir::Value addr, llvm::ArrayRef<mlir::Value> lbounds,
297 llvm::ArrayRef<mlir::Value> explicitParams,
298 llvm::ArrayRef<mlir::Value> explicitExtents = {})
299 : AbstractIrBox{addr, lbounds, explicitExtents},
300 explicitParams{explicitParams} {
301 assert(verify());
302 }
303 // TODO: check contiguous attribute of addr
304 bool isContiguous() const { return false; }
305
306 // Replace the fir.box, keeping any non-deferred parameters.
307 BoxValue clone(mlir::Value newBox) const {
308 return {newBox, lbounds, explicitParams, extents};
309 }
310
311 friend llvm::raw_ostream &operator<<(llvm::raw_ostream &, const BoxValue &);
312 LLVM_DUMP_METHOD void dump() const { llvm::errs() << *this; }
313
314 llvm::ArrayRef<mlir::Value> getLBounds() const { return lbounds; }
315
316 // The extents member is not guaranteed to be field for arrays. It is only
317 // guaranteed to be field for explicit shape arrays. In general,
318 // explicit-shape will not come as descriptors, so this field will be empty in
319 // most cases. The exception are derived types with LEN parameters and
320 // polymorphic dummy argument arrays. It may be possible for the explicit
321 // extents to conflict with the shape information that is in the box according
322 // to 15.5.2.11 sequence association rules.
323 llvm::ArrayRef<mlir::Value> getExplicitExtents() const { return extents; }
324
325 llvm::ArrayRef<mlir::Value> getExplicitParameters() const {
326 return explicitParams;
327 }
328
329protected:
330 // Verify constructor invariants.
331 bool verify() const;
332
333 // Only field when the BoxValue has explicit LEN parameters.
334 // Otherwise, the LEN parameters are in the fir.box.
336};
337
345public:
346 bool isEmpty() const { return !addr; }
347 mlir::Value addr;
356};
357
362class MutableBoxValue : public AbstractIrBox {
363public:
368 MutableBoxValue(mlir::Value addr, mlir::ValueRange lenParameters,
370 : AbstractIrBox(addr), lenParams{lenParameters.begin(),
371 lenParameters.end()},
373 // Currently only accepts fir.(ref/ptr/heap)<fir.box<type>> mlir::Value for
374 // the address. This may change if we accept
375 // fir.(ref/ptr/heap)<fir.heap<type>> for scalar without LEN parameters.
376 assert(verify() &&
377 "MutableBoxValue requires mem ref to fir.box<fir.[heap|ptr]<type>>");
378 }
379
380 bool isPointer() const {
381 return mlir::isa<fir::PointerType>(getBoxTy().getEleTy());
382 }
383
384 bool isAllocatable() const {
385 return mlir::isa<fir::HeapType>(getBoxTy().getEleTy());
386 }
387 // Replace the fir.ref<fir.box>, keeping any non-deferred parameters.
388 MutableBoxValue clone(mlir::Value newBox) const {
389 return {newBox, lenParams, mutableProperties};
390 }
392 bool hasNonDeferredLenParams() const { return !lenParams.empty(); }
395 friend llvm::raw_ostream &operator<<(llvm::raw_ostream &,
396 const MutableBoxValue &);
397 LLVM_DUMP_METHOD void dump() const { llvm::errs() << *this; }
398
401 bool isDescribedByVariables() const { return !mutableProperties.isEmpty(); }
402
403 const MutableProperties &getMutableProperties() const {
404 return mutableProperties;
405 }
406
407protected:
409 bool verify() const;
418};
419
420class ExtendedValue;
421
424mlir::Value getBase(const ExtendedValue &exv);
425
428mlir::Value getLen(const ExtendedValue &exv);
429
431llvm::raw_ostream &operator<<(llvm::raw_ostream &, const ExtendedValue &);
432
435ExtendedValue substBase(const ExtendedValue &exv, mlir::Value base);
436
439bool isArray(const ExtendedValue &exv);
440
443
444//===----------------------------------------------------------------------===//
445// Functions that may generate IR to recover properties from extended values.
446//===----------------------------------------------------------------------===//
447namespace factory {
448
454 FirOpBuilder &builder,
455 const ExtendedValue &exv);
456
460getTypeParams(mlir::Location loc, FirOpBuilder &builder, ArrayLoadOp load);
461
462// The generalized function to get a vector of extents is
466getExtents(mlir::Location loc, FirOpBuilder &builder, const ExtendedValue &box);
467
470mlir::Value getExtentAtDimension(mlir::Location loc, FirOpBuilder &builder,
471 const ExtendedValue &exv, unsigned dim);
472
473} // namespace factory
474
480class ExtendedValue : public details::matcher<ExtendedValue> {
481public:
482 using VT =
485
486 ExtendedValue() : box{UnboxedValue{}} {}
487 template <typename A, typename = std::enable_if_t<
488 !std::is_same_v<std::decay_t<A>, ExtendedValue>>>
489 constexpr ExtendedValue(A &&a) : box{std::forward<A>(a)} {
490 if (const auto *b = getUnboxed()) {
491 if (*b) {
492 auto type = b->getType();
493 if (mlir::isa<fir::BoxCharType>(type))
494 fir::emitFatalError(b->getLoc(), "BoxChar should be unboxed");
495 type = fir::unwrapSequenceType(fir::unwrapRefType(type));
496 if (fir::isa_char(type))
497 fir::emitFatalError(b->getLoc(),
498 "character buffer should be in CharBoxValue");
499 }
500 }
501 }
502
503 template <typename A>
504 constexpr const A *getBoxOf() const {
505 return std::get_if<A>(&box);
506 }
507
508 constexpr const CharBoxValue *getCharBox() const {
509 return getBoxOf<CharBoxValue>();
510 }
511
512 constexpr const UnboxedValue *getUnboxed() const {
513 return getBoxOf<UnboxedValue>();
514 }
515
516 unsigned rank() const {
517 return match([](const fir::UnboxedValue &box) -> unsigned { return 0; },
518 [](const fir::CharBoxValue &box) -> unsigned { return 0; },
519 [](const fir::ProcBoxValue &box) -> unsigned { return 0; },
520 [](const fir::PolymorphicValue &box) -> unsigned { return 0; },
521 [](const auto &box) -> unsigned { return box.rank(); });
522 }
523
524 bool isPolymorphic() const {
525 return match([](const fir::PolymorphicValue &box) -> bool { return true; },
526 [](const fir::ArrayBoxValue &box) -> bool {
527 return box.getSourceBox() ? true : false;
528 },
529 [](const auto &box) -> bool { return false; });
530 }
531
532 bool hasAssumedRank() const {
533 return match(
534 [](const fir::BoxValue &box) -> bool { return box.hasAssumedRank(); },
535 [](const fir::MutableBoxValue &box) -> bool {
536 return box.hasAssumedRank();
537 },
538 [](const auto &box) -> bool { return false; });
539 }
540
542 LLVM_DUMP_METHOD void dump() const { llvm::errs() << *this << '\n'; }
543
544 friend llvm::raw_ostream &operator<<(llvm::raw_ostream &,
545 const ExtendedValue &);
546
547 const VT &matchee() const { return box; }
548
549private:
550 VT box;
551};
552
554inline bool isUnboxedValue(const ExtendedValue &exv) {
555 return exv.match(
556 [](const fir::UnboxedValue &box) { return box ? true : false; },
557 [](const auto &) { return false; });
558}
559
562inline mlir::Type getBaseTypeOf(const ExtendedValue &exv) {
563 return exv.match(
564 [](const fir::MutableBoxValue &box) { return box.getBaseTy(); },
565 [](const fir::BoxValue &box) { return box.getBaseTy(); },
566 [&](const auto &) {
567 return fir::unwrapRefType(fir::getBase(exv).getType());
568 });
569}
570
573inline mlir::Type getElementTypeOf(const ExtendedValue &exv) {
575}
576
581
582} // namespace fir
583
584#endif // FORTRAN_OPTIMIZER_BUILDER_BOXVALUE_H
mlir::Value getAddr() const
Definition BoxValue.h:69
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:1464
Definition BoxValue.h:293
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:480
LLVM_DUMP_METHOD void dump() const
LLVM style debugging of extended values.
Definition BoxValue.h:542
friend llvm::raw_ostream & operator<<(llvm::raw_ostream &, const ExtendedValue &)
Pretty-print an extended value.
Definition FIRBuilder.h:59
Definition BoxValue.h:362
MutableBoxValue(mlir::Value addr, mlir::ValueRange lenParameters, MutableProperties mutableProperties)
Definition BoxValue.h:368
bool hasNonDeferredLenParams() const
Does this entity has any non deferred LEN parameters?
Definition BoxValue.h:392
bool isAllocatable() const
Is this an allocatable ?
Definition BoxValue.h:384
llvm::SmallVector< mlir::Value, 2 > lenParams
Definition BoxValue.h:413
bool isDescribedByVariables() const
Definition BoxValue.h:401
bool isPointer() const
Is this a Fortran pointer ?
Definition BoxValue.h:380
MutableProperties mutableProperties
Definition BoxValue.h:417
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:394
Definition BoxValue.h:344
llvm::SmallVector< mlir::Value, 2 > deferredParams
Definition BoxValue.h:355
Polymorphic value associated with a dynamic type descriptor.
Definition BoxValue.h:102
Definition BoxValue.h:192
Definition FIRType.h:106
Definition OpenACC.h:20
Definition BoxValue.h:447
llvm::SmallVector< mlir::Value > getTypeParams(mlir::Location loc, FirOpBuilder &builder, const ExtendedValue &exv)
Definition FIRBuilder.cpp:1200
mlir::Value getExtentAtDimension(mlir::Location loc, FirOpBuilder &builder, const ExtendedValue &exv, unsigned dim)
Definition BoxValue.cpp:226
llvm::SmallVector< mlir::Value > getExtents(mlir::Location loc, FirOpBuilder &builder, const ExtendedValue &box)
Definition FIRBuilder.cpp:1078
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:760
bool isUnlimitedPolymorphicType(mlir::Type ty)
Definition FIRType.cpp:412
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:554
mlir::Value UnboxedValue
Definition BoxValue.h:58
mlir::Type dyn_cast_ptrEleTy(mlir::Type t)
Definition FIRType.cpp:251
mlir::Type getElementTypeOf(const ExtendedValue &exv)
Definition BoxValue.h:573
mlir::Value getBase(const ExtendedValue &exv)
Definition BoxValue.cpp:21
mlir::Type dyn_cast_ptrOrBoxEleTy(mlir::Type t)
Definition FIRType.cpp:258
bool isPolymorphicType(mlir::Type ty)
Definition FIRType.cpp:404
unsigned getBoxCorank(mlir::Type boxTy)
Get the corank from a !fir.box type.
Definition FIRType.cpp:482
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:562
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:578
Definition Matcher.h:25